diff options
378 files changed, 6325 insertions, 2456 deletions
diff --git a/Android.mk b/Android.mk index f1e16b841585..9029f4ef1f53 100644 --- a/Android.mk +++ b/Android.mk @@ -483,6 +483,7 @@ aidl_files := \ frameworks/base/wifi/java/android/net/wifi/p2p/nsd/WifiP2pServiceInfo.aidl \ frameworks/base/wifi/java/android/net/wifi/WpsInfo.aidl \ frameworks/base/wifi/java/android/net/wifi/ScanResult.aidl \ + frameworks/base/wifi/java/android/net/wifi/ScanInfo.aidl \ frameworks/base/wifi/java/android/net/wifi/WifiEnterpriseConfig.aidl \ frameworks/base/wifi/java/android/net/wifi/WifiConfiguration.aidl \ frameworks/base/wifi/java/android/net/wifi/WifiInfo.aidl \ diff --git a/api/current.txt b/api/current.txt index 00b5ec02891f..758851c79abe 100644 --- a/api/current.txt +++ b/api/current.txt @@ -779,6 +779,7 @@ package android { field public static final int layout_y = 16843136; // 0x1010180 field public static final int left = 16843181; // 0x10101ad field public static final int letterSpacing = 16843958; // 0x10104b6 + field public static final int level = 16844031; // 0x10104ff field public static final int lineSpacingExtra = 16843287; // 0x1010217 field public static final int lineSpacingMultiplier = 16843288; // 0x1010218 field public static final int lines = 16843092; // 0x1010154 @@ -18250,6 +18251,7 @@ package android.net { field public static final java.lang.String CONNECTIVITY_ACTION = "android.net.conn.CONNECTIVITY_CHANGE"; field public static final deprecated int DEFAULT_NETWORK_PREFERENCE = 1; // 0x1 field public static final java.lang.String EXTRA_CAPTIVE_PORTAL = "android.net.extra.CAPTIVE_PORTAL"; + field public static final java.lang.String EXTRA_CAPTIVE_PORTAL_URL = "android.net.extra.CAPTIVE_PORTAL_URL"; field public static final java.lang.String EXTRA_EXTRA_INFO = "extraInfo"; field public static final java.lang.String EXTRA_IS_FAILOVER = "isFailover"; field public static final java.lang.String EXTRA_NETWORK = "android.net.extra.NETWORK"; @@ -19156,6 +19158,22 @@ package android.net.sip { package android.net.wifi { + public class ScanInfo implements android.os.Parcelable { + ctor public ScanInfo(android.net.wifi.ScanResult); + ctor public ScanInfo(long, int, java.lang.String, java.lang.String, java.lang.String, java.lang.String, byte[], int); + method public int describeContents(); + method public long getBssid(); + method public byte[] getIconData(); + method public java.lang.String getIconType(); + method public java.lang.String getName(); + method public int getOsuIdentity(); + method public int getRssi(); + method public android.net.wifi.ScanResult getScanResult(); + method public java.lang.String getServiceDescription(); + method public java.lang.String getSsid(); + method public void writeToParcel(android.os.Parcel, int); + } + public class ScanResult implements android.os.Parcelable { method public int describeContents(); method public boolean is80211mcResponder(); @@ -19356,6 +19374,7 @@ package android.net.wifi { method public java.util.List<android.net.wifi.WifiConfiguration> getConfiguredNetworks(); method public android.net.wifi.WifiInfo getConnectionInfo(); method public android.net.DhcpInfo getDhcpInfo(); + method public java.util.List<android.net.wifi.ScanInfo> getScanInfos(); method public java.util.List<android.net.wifi.ScanResult> getScanResults(); method public int getWifiState(); method public boolean is5GHzBandSupported(); @@ -19371,6 +19390,7 @@ package android.net.wifi { method public boolean reconnect(); method public boolean removeNetwork(int); method public boolean saveConfiguration(); + method public void setOsuSelection(int); method public void setTdlsEnabled(java.net.InetAddress, boolean); method public void setTdlsEnabledWithMacAddress(java.lang.String, boolean); method public boolean setWifiEnabled(boolean); @@ -40972,6 +40992,7 @@ package android.widget { method public void setInterpolator(android.view.animation.Interpolator); method public synchronized void setMax(int); method public synchronized void setProgress(int); + method public void setProgress(int, boolean); method public void setProgressBackgroundTintList(android.content.res.ColorStateList); method public void setProgressBackgroundTintMode(android.graphics.PorterDuff.Mode); method public void setProgressDrawable(android.graphics.drawable.Drawable); @@ -45328,7 +45349,10 @@ package java.lang.reflect { } public final class Constructor extends java.lang.reflect.AccessibleObject implements java.lang.reflect.GenericDeclaration java.lang.reflect.Member { + method public boolean equals(java.lang.Object); method public A getAnnotation(java.lang.Class<A>); + method public java.lang.annotation.Annotation[] getAnnotations(); + method public java.lang.annotation.Annotation[] getDeclaredAnnotations(); method public java.lang.Class<T> getDeclaringClass(); method public java.lang.Class<?>[] getExceptionTypes(); method public java.lang.reflect.Type[] getGenericExceptionTypes(); @@ -45338,6 +45362,7 @@ package java.lang.reflect { method public java.lang.annotation.Annotation[][] getParameterAnnotations(); method public java.lang.Class<?>[] getParameterTypes(); method public java.lang.reflect.TypeVariable<java.lang.reflect.Constructor<T>>[] getTypeParameters(); + method public boolean isAnnotationPresent(java.lang.Class<? extends java.lang.annotation.Annotation>); method public boolean isSynthetic(); method public boolean isVarArgs(); method public T newInstance(java.lang.Object...) throws java.lang.IllegalAccessException, java.lang.IllegalArgumentException, java.lang.InstantiationException, java.lang.reflect.InvocationTargetException; @@ -45411,7 +45436,10 @@ package java.lang.reflect { } public final class Method extends java.lang.reflect.AccessibleObject implements java.lang.reflect.GenericDeclaration java.lang.reflect.Member { + method public boolean equals(java.lang.Object); method public A getAnnotation(java.lang.Class<A>); + method public java.lang.annotation.Annotation[] getAnnotations(); + method public java.lang.annotation.Annotation[] getDeclaredAnnotations(); method public java.lang.Class<?> getDeclaringClass(); method public java.lang.Object getDefaultValue(); method public java.lang.Class<?>[] getExceptionTypes(); @@ -45425,6 +45453,7 @@ package java.lang.reflect { method public java.lang.Class<?> getReturnType(); method public java.lang.reflect.TypeVariable<java.lang.reflect.Method>[] getTypeParameters(); method public java.lang.Object invoke(java.lang.Object, java.lang.Object...) throws java.lang.IllegalAccessException, java.lang.IllegalArgumentException, java.lang.reflect.InvocationTargetException; + method public boolean isAnnotationPresent(java.lang.Class<? extends java.lang.annotation.Annotation>); method public boolean isBridge(); method public boolean isSynthetic(); method public boolean isVarArgs(); diff --git a/api/system-current.txt b/api/system-current.txt index b2803b7ffafc..256824010308 100644 --- a/api/system-current.txt +++ b/api/system-current.txt @@ -871,6 +871,7 @@ package android { field public static final int layout_y = 16843136; // 0x1010180 field public static final int left = 16843181; // 0x10101ad field public static final int letterSpacing = 16843958; // 0x10104b6 + field public static final int level = 16844031; // 0x10104ff field public static final int lineSpacingExtra = 16843287; // 0x1010217 field public static final int lineSpacingMultiplier = 16843288; // 0x1010218 field public static final int lines = 16843092; // 0x1010154 @@ -19762,6 +19763,7 @@ package android.net { field public static final java.lang.String CONNECTIVITY_ACTION = "android.net.conn.CONNECTIVITY_CHANGE"; field public static final deprecated int DEFAULT_NETWORK_PREFERENCE = 1; // 0x1 field public static final java.lang.String EXTRA_CAPTIVE_PORTAL = "android.net.extra.CAPTIVE_PORTAL"; + field public static final java.lang.String EXTRA_CAPTIVE_PORTAL_URL = "android.net.extra.CAPTIVE_PORTAL_URL"; field public static final java.lang.String EXTRA_EXTRA_INFO = "extraInfo"; field public static final java.lang.String EXTRA_IS_FAILOVER = "isFailover"; field public static final java.lang.String EXTRA_NETWORK = "android.net.extra.NETWORK"; @@ -20909,6 +20911,22 @@ package android.net.wifi { field public byte id; } + public class ScanInfo implements android.os.Parcelable { + ctor public ScanInfo(android.net.wifi.ScanResult); + ctor public ScanInfo(long, int, java.lang.String, java.lang.String, java.lang.String, java.lang.String, byte[], int); + method public int describeContents(); + method public long getBssid(); + method public byte[] getIconData(); + method public java.lang.String getIconType(); + method public java.lang.String getName(); + method public int getOsuIdentity(); + method public int getRssi(); + method public android.net.wifi.ScanResult getScanResult(); + method public java.lang.String getServiceDescription(); + method public java.lang.String getSsid(); + method public void writeToParcel(android.os.Parcel, int); + } + public class ScanResult implements android.os.Parcelable { method public int describeContents(); method public boolean is80211mcResponder(); @@ -21134,6 +21152,7 @@ package android.net.wifi { method public android.net.wifi.WifiConnectionStatistics getConnectionStatistics(); method public android.net.DhcpInfo getDhcpInfo(); method public java.util.List<android.net.wifi.WifiConfiguration> getPrivilegedConfiguredNetworks(); + method public java.util.List<android.net.wifi.ScanInfo> getScanInfos(); method public java.util.List<android.net.wifi.ScanResult> getScanResults(); method public int getWifiState(); method public boolean is5GHzBandSupported(); @@ -21153,6 +21172,7 @@ package android.net.wifi { method public boolean reconnect(); method public boolean removeNetwork(int); method public boolean saveConfiguration(); + method public void setOsuSelection(int); method public void setTdlsEnabled(java.net.InetAddress, boolean); method public void setTdlsEnabledWithMacAddress(java.lang.String, boolean); method public boolean setWifiEnabled(boolean); @@ -25667,8 +25687,8 @@ package android.os { ctor public UserHandle(android.os.Parcel); method public int describeContents(); method public int getIdentifier(); - method public final boolean isOwner(); - method public static final int myUserId(); + method public boolean isOwner(); + method public static int myUserId(); method public static android.os.UserHandle readFromParcel(android.os.Parcel); method public void writeToParcel(android.os.Parcel, int); method public static void writeToParcel(android.os.UserHandle, android.os.Parcel); @@ -43580,6 +43600,7 @@ package android.widget { method public void setInterpolator(android.view.animation.Interpolator); method public synchronized void setMax(int); method public synchronized void setProgress(int); + method public void setProgress(int, boolean); method public void setProgressBackgroundTintList(android.content.res.ColorStateList); method public void setProgressBackgroundTintMode(android.graphics.PorterDuff.Mode); method public void setProgressDrawable(android.graphics.drawable.Drawable); @@ -47936,7 +47957,10 @@ package java.lang.reflect { } public final class Constructor extends java.lang.reflect.AccessibleObject implements java.lang.reflect.GenericDeclaration java.lang.reflect.Member { + method public boolean equals(java.lang.Object); method public A getAnnotation(java.lang.Class<A>); + method public java.lang.annotation.Annotation[] getAnnotations(); + method public java.lang.annotation.Annotation[] getDeclaredAnnotations(); method public java.lang.Class<T> getDeclaringClass(); method public java.lang.Class<?>[] getExceptionTypes(); method public java.lang.reflect.Type[] getGenericExceptionTypes(); @@ -47946,6 +47970,7 @@ package java.lang.reflect { method public java.lang.annotation.Annotation[][] getParameterAnnotations(); method public java.lang.Class<?>[] getParameterTypes(); method public java.lang.reflect.TypeVariable<java.lang.reflect.Constructor<T>>[] getTypeParameters(); + method public boolean isAnnotationPresent(java.lang.Class<? extends java.lang.annotation.Annotation>); method public boolean isSynthetic(); method public boolean isVarArgs(); method public T newInstance(java.lang.Object...) throws java.lang.IllegalAccessException, java.lang.IllegalArgumentException, java.lang.InstantiationException, java.lang.reflect.InvocationTargetException; @@ -48019,7 +48044,10 @@ package java.lang.reflect { } public final class Method extends java.lang.reflect.AccessibleObject implements java.lang.reflect.GenericDeclaration java.lang.reflect.Member { + method public boolean equals(java.lang.Object); method public A getAnnotation(java.lang.Class<A>); + method public java.lang.annotation.Annotation[] getAnnotations(); + method public java.lang.annotation.Annotation[] getDeclaredAnnotations(); method public java.lang.Class<?> getDeclaringClass(); method public java.lang.Object getDefaultValue(); method public java.lang.Class<?>[] getExceptionTypes(); @@ -48033,6 +48061,7 @@ package java.lang.reflect { method public java.lang.Class<?> getReturnType(); method public java.lang.reflect.TypeVariable<java.lang.reflect.Method>[] getTypeParameters(); method public java.lang.Object invoke(java.lang.Object, java.lang.Object...) throws java.lang.IllegalAccessException, java.lang.IllegalArgumentException, java.lang.reflect.InvocationTargetException; + method public boolean isAnnotationPresent(java.lang.Class<? extends java.lang.annotation.Annotation>); method public boolean isBridge(); method public boolean isSynthetic(); method public boolean isVarArgs(); diff --git a/cmds/am/src/com/android/commands/am/Am.java b/cmds/am/src/com/android/commands/am/Am.java index 9185d7ac127a..20ac8d83ebad 100644 --- a/cmds/am/src/com/android/commands/am/Am.java +++ b/cmds/am/src/com/android/commands/am/Am.java @@ -19,6 +19,8 @@ package com.android.commands.am; import static android.app.ActivityManager.DOCKED_STACK_ID; +import static android.app.ActivityManager.RESIZE_MODE_SYSTEM; +import static android.app.ActivityManager.RESIZE_MODE_USER; import android.app.ActivityManager; import android.app.ActivityManager.StackInfo; @@ -2271,7 +2273,8 @@ public class Am extends BaseCommand { private void taskResize(int taskId, Rect bounds, int delay_ms, boolean pretendUserResize) { try { - mAm.resizeTask(taskId, bounds, pretendUserResize); + final int resizeMode = pretendUserResize ? RESIZE_MODE_USER : RESIZE_MODE_SYSTEM; + mAm.resizeTask(taskId, bounds, resizeMode); Thread.sleep(delay_ms); } catch (RemoteException e) { System.err.println("Error changing task bounds: " + e); diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java index 9ef51c8554d3..4191dce79be8 100644 --- a/core/java/android/app/ActivityManager.java +++ b/core/java/android/app/ActivityManager.java @@ -468,6 +468,29 @@ public class ActivityManager { */ public static final int DOCKED_STACK_CREATE_MODE_BOTTOM_OR_RIGHT = 1; + + /** + * Input parameter to {@link android.app.IActivityManager#resizeTask} which indicates + * that the resize is from the window manager (instead of the user). + * @hide + */ + public static final int RESIZE_MODE_SYSTEM = 0; + + /** + * Input parameter to {@link android.app.IActivityManager#resizeTask} which indicates + * that the resize is initiated by the user (most likely via a drag action on the + * window's edge or corner). + * @hide + */ + public static final int RESIZE_MODE_USER = 1; + + /** + * Input parameter to {@link android.app.IActivityManager#resizeTask} which indicates + * that the resize should be performed even if the bounds appears unchanged. + * @hide + */ + public static final int RESIZE_MODE_FORCED = 2; + /** @hide */ public int getFrontActivityScreenCompatMode() { try { diff --git a/core/java/android/app/ActivityManagerNative.java b/core/java/android/app/ActivityManagerNative.java index da6fc592e69a..3864a4bba1f9 100644 --- a/core/java/android/app/ActivityManagerNative.java +++ b/core/java/android/app/ActivityManagerNative.java @@ -2452,9 +2452,9 @@ public abstract class ActivityManagerNative extends Binder implements IActivityM case RESIZE_TASK_TRANSACTION: { data.enforceInterface(IActivityManager.descriptor); int taskId = data.readInt(); - final boolean resizedByUser = data.readInt() == 1; + int resizeMode = data.readInt(); Rect r = Rect.CREATOR.createFromParcel(data); - resizeTask(taskId, r, resizedByUser); + resizeTask(taskId, r, resizeMode); reply.writeNoException(); return true; } @@ -5900,13 +5900,13 @@ class ActivityManagerProxy implements IActivityManager } @Override - public void resizeTask(int taskId, Rect r, boolean resizedByUser) throws RemoteException + public void resizeTask(int taskId, Rect r, int resizeMode) throws RemoteException { Parcel data = Parcel.obtain(); Parcel reply = Parcel.obtain(); data.writeInterfaceToken(IActivityManager.descriptor); data.writeInt(taskId); - data.writeInt(resizedByUser ? 1 : 0); + data.writeInt(resizeMode); r.writeToParcel(data, 0); mRemote.transact(RESIZE_TASK_TRANSACTION, data, reply, 0); reply.readException(); diff --git a/core/java/android/app/ApplicationPackageManager.java b/core/java/android/app/ApplicationPackageManager.java index 0cd02dd397c1..5544a7150625 100644 --- a/core/java/android/app/ApplicationPackageManager.java +++ b/core/java/android/app/ApplicationPackageManager.java @@ -93,8 +93,8 @@ import java.util.List; import java.util.Map; import java.util.Objects; -/*package*/ -final class ApplicationPackageManager extends PackageManager { +/** @hide */ +public class ApplicationPackageManager extends PackageManager { private static final String TAG = "ApplicationPackageManager"; private final static boolean DEBUG_ICONS = false; diff --git a/core/java/android/app/Fragment.java b/core/java/android/app/Fragment.java index f70423fbbc9a..b44aab717174 100644 --- a/core/java/android/app/Fragment.java +++ b/core/java/android/app/Fragment.java @@ -63,6 +63,7 @@ final class FragmentState implements Parcelable { final boolean mRetainInstance; final boolean mDetached; final Bundle mArguments; + final boolean mHidden; Bundle mSavedFragmentState; @@ -78,6 +79,7 @@ final class FragmentState implements Parcelable { mRetainInstance = frag.mRetainInstance; mDetached = frag.mDetached; mArguments = frag.mArguments; + mHidden = frag.mHidden; } public FragmentState(Parcel in) { @@ -90,6 +92,7 @@ final class FragmentState implements Parcelable { mRetainInstance = in.readInt() != 0; mDetached = in.readInt() != 0; mArguments = in.readBundle(); + mHidden = in.readInt() != 0; mSavedFragmentState = in.readBundle(); } @@ -117,6 +120,7 @@ final class FragmentState implements Parcelable { mInstance.mTag = mTag; mInstance.mRetainInstance = mRetainInstance; mInstance.mDetached = mDetached; + mInstance.mHidden = mHidden; mInstance.mFragmentManager = host.mFragmentManager; if (FragmentManagerImpl.DEBUG) Log.v(FragmentManagerImpl.TAG, "Instantiated fragment " + mInstance); @@ -138,6 +142,7 @@ final class FragmentState implements Parcelable { dest.writeInt(mRetainInstance ? 1 : 0); dest.writeInt(mDetached ? 1 : 0); dest.writeBundle(mArguments); + dest.writeInt(mHidden ? 1 : 0); dest.writeBundle(mSavedFragmentState); } @@ -460,6 +465,9 @@ public class Fragment implements ComponentCallbacks2, OnCreateContextMenuListene // If set this fragment is being retained across the current config change. boolean mRetaining; + // If set this fragment's loaders are being retained across the current config change. + boolean mRetainLoader; + // If set this fragment has menu items to contribute. boolean mHasMenu; @@ -2407,7 +2415,7 @@ public class Fragment implements ComponentCallbacks2, OnCreateContextMenuListene mLoaderManager = mHost.getLoaderManager(mWho, mLoadersStarted, false); } if (mLoaderManager != null) { - if (mRetaining) { + if (mRetainLoader) { mLoaderManager.doRetain(); } else { mLoaderManager.doStop(); diff --git a/core/java/android/app/FragmentController.java b/core/java/android/app/FragmentController.java index 28dadfa78b32..1b45137fb7c9 100644 --- a/core/java/android/app/FragmentController.java +++ b/core/java/android/app/FragmentController.java @@ -341,6 +341,7 @@ public class FragmentController { */ public void doLoaderStop(boolean retain) { mHost.doLoaderStop(retain); + mHost.mFragmentManager.setRetainLoader(retain); } /** diff --git a/core/java/android/app/FragmentManager.java b/core/java/android/app/FragmentManager.java index 132ffef861e6..51d613247c87 100644 --- a/core/java/android/app/FragmentManager.java +++ b/core/java/android/app/FragmentManager.java @@ -869,6 +869,17 @@ final class FragmentManagerImpl extends FragmentManager implements LayoutInflate } } + void setRetainLoader(boolean retain) { + if (mActive != null) { + for (int i=0; i<mActive.size(); i++) { + Fragment f = mActive.get(i); + if (f != null) { + f.mRetainLoader = retain; + } + } + } + } + void moveToState(Fragment f, int newState, int transit, int transitionStyle, boolean keepActive) { if (DEBUG && false) Log.v(TAG, "moveToState: " + f diff --git a/core/java/android/app/IActivityManager.java b/core/java/android/app/IActivityManager.java index 7bd832bf5f95..2180bcc1e4b9 100644 --- a/core/java/android/app/IActivityManager.java +++ b/core/java/android/app/IActivityManager.java @@ -491,7 +491,7 @@ public interface IActivityManager extends IInterface { public void setTaskDescription(IBinder token, ActivityManager.TaskDescription values) throws RemoteException; public void setTaskResizeable(int taskId, boolean resizeable) throws RemoteException; - public void resizeTask(int taskId, Rect bounds, boolean resizedByUser) throws RemoteException; + public void resizeTask(int taskId, Rect bounds, int resizeMode) throws RemoteException; public Rect getTaskBounds(int taskId) throws RemoteException; public Bitmap getTaskDescriptionIcon(String filename) throws RemoteException; diff --git a/core/java/android/app/SystemServiceRegistry.java b/core/java/android/app/SystemServiceRegistry.java index 3d264c6f2cba..288a2cb5fa4f 100644 --- a/core/java/android/app/SystemServiceRegistry.java +++ b/core/java/android/app/SystemServiceRegistry.java @@ -240,7 +240,7 @@ final class SystemServiceRegistry { new CachedServiceFetcher<DevicePolicyManager>() { @Override public DevicePolicyManager createService(ContextImpl ctx) { - return DevicePolicyManager.create(ctx, ctx.mMainThread.getHandler()); + return DevicePolicyManager.create(ctx); }}); registerService(Context.DOWNLOAD_SERVICE, DownloadManager.class, diff --git a/core/java/android/app/admin/DeviceAdminInfo.java b/core/java/android/app/admin/DeviceAdminInfo.java index d1e40ae9bd5e..4e9adf09c351 100644 --- a/core/java/android/app/admin/DeviceAdminInfo.java +++ b/core/java/android/app/admin/DeviceAdminInfo.java @@ -20,6 +20,7 @@ import org.xmlpull.v1.XmlPullParser; import org.xmlpull.v1.XmlPullParserException; import org.xmlpull.v1.XmlSerializer; +import android.annotation.NonNull; import android.content.ComponentName; import android.content.Context; import android.content.pm.ActivityInfo; @@ -360,6 +361,7 @@ public final class DeviceAdminInfo implements Parcelable { /** * Return the component of the receiver that implements this device admin. */ + @NonNull public ComponentName getComponent() { return new ComponentName(mReceiver.activityInfo.packageName, mReceiver.activityInfo.name); diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java index ac50699ca110..e6484e965ee0 100644 --- a/core/java/android/app/admin/DevicePolicyManager.java +++ b/core/java/android/app/admin/DevicePolicyManager.java @@ -32,7 +32,6 @@ import android.content.pm.ResolveInfo; import android.graphics.Bitmap; import android.net.ProxyInfo; import android.os.Bundle; -import android.os.Handler; import android.os.PersistableBundle; import android.os.Process; import android.os.RemoteCallback; @@ -45,6 +44,7 @@ import android.security.Credentials; import android.service.restrictions.RestrictionsReceiver; import android.util.Log; +import com.android.internal.annotations.VisibleForTesting; import com.android.org.conscrypt.TrustedCertificateStore; import org.xmlpull.v1.XmlPullParserException; @@ -87,18 +87,30 @@ public class DevicePolicyManager { private final Context mContext; private final IDevicePolicyManager mService; - private DevicePolicyManager(Context context, Handler handler) { + private DevicePolicyManager(Context context) { + this(context, IDevicePolicyManager.Stub.asInterface( + ServiceManager.getService(Context.DEVICE_POLICY_SERVICE))); + } + + /** @hide */ + @VisibleForTesting + protected DevicePolicyManager(Context context, IDevicePolicyManager service) { mContext = context; - mService = IDevicePolicyManager.Stub.asInterface( - ServiceManager.getService(Context.DEVICE_POLICY_SERVICE)); + mService = service; } /** @hide */ - public static DevicePolicyManager create(Context context, Handler handler) { - DevicePolicyManager me = new DevicePolicyManager(context, handler); + public static DevicePolicyManager create(Context context) { + DevicePolicyManager me = new DevicePolicyManager(context); return me.mService != null ? me : null; } + /** @hide test will override it. */ + @VisibleForTesting + protected int myUserId() { + return UserHandle.myUserId(); + } + /** * Activity action: Starts the provisioning flow which sets up a managed profile. * @@ -823,7 +835,7 @@ public class DevicePolicyManager { * active (enabled) in the system. */ public boolean isAdminActive(@NonNull ComponentName admin) { - return isAdminActiveAsUser(admin, UserHandle.myUserId()); + return isAdminActiveAsUser(admin, myUserId()); } /** @@ -863,7 +875,7 @@ public class DevicePolicyManager { * returned. */ public List<ComponentName> getActiveAdmins() { - return getActiveAdminsAsUser(UserHandle.myUserId()); + return getActiveAdminsAsUser(myUserId()); } /** @@ -889,7 +901,7 @@ public class DevicePolicyManager { public boolean packageHasActiveAdmins(String packageName) { if (mService != null) { try { - return mService.packageHasActiveAdmins(packageName, UserHandle.myUserId()); + return mService.packageHasActiveAdmins(packageName, myUserId()); } catch (RemoteException e) { Log.w(TAG, "Failed talking with device policy service", e); } @@ -906,7 +918,7 @@ public class DevicePolicyManager { public void removeActiveAdmin(@NonNull ComponentName admin) { if (mService != null) { try { - mService.removeActiveAdmin(admin, UserHandle.myUserId()); + mService.removeActiveAdmin(admin, myUserId()); } catch (RemoteException e) { Log.w(TAG, "Failed talking with device policy service", e); } @@ -925,7 +937,7 @@ public class DevicePolicyManager { public boolean hasGrantedPolicy(@NonNull ComponentName admin, int usesPolicy) { if (mService != null) { try { - return mService.hasGrantedPolicy(admin, usesPolicy, UserHandle.myUserId()); + return mService.hasGrantedPolicy(admin, usesPolicy, myUserId()); } catch (RemoteException e) { Log.w(TAG, "Failed talking with device policy service", e); } @@ -1040,7 +1052,7 @@ public class DevicePolicyManager { * all admins. */ public int getPasswordQuality(@Nullable ComponentName admin) { - return getPasswordQuality(admin, UserHandle.myUserId()); + return getPasswordQuality(admin, myUserId()); } /** @hide per-user version */ @@ -1093,7 +1105,7 @@ public class DevicePolicyManager { * all admins. */ public int getPasswordMinimumLength(@Nullable ComponentName admin) { - return getPasswordMinimumLength(admin, UserHandle.myUserId()); + return getPasswordMinimumLength(admin, myUserId()); } /** @hide per-user version */ @@ -1154,7 +1166,7 @@ public class DevicePolicyManager { * password. */ public int getPasswordMinimumUpperCase(@Nullable ComponentName admin) { - return getPasswordMinimumUpperCase(admin, UserHandle.myUserId()); + return getPasswordMinimumUpperCase(admin, myUserId()); } /** @hide per-user version */ @@ -1215,7 +1227,7 @@ public class DevicePolicyManager { * password. */ public int getPasswordMinimumLowerCase(@Nullable ComponentName admin) { - return getPasswordMinimumLowerCase(admin, UserHandle.myUserId()); + return getPasswordMinimumLowerCase(admin, myUserId()); } /** @hide per-user version */ @@ -1273,7 +1285,7 @@ public class DevicePolicyManager { * @return The minimum number of letters required in the password. */ public int getPasswordMinimumLetters(@Nullable ComponentName admin) { - return getPasswordMinimumLetters(admin, UserHandle.myUserId()); + return getPasswordMinimumLetters(admin, myUserId()); } /** @hide per-user version */ @@ -1332,7 +1344,7 @@ public class DevicePolicyManager { * @return The minimum number of numerical digits required in the password. */ public int getPasswordMinimumNumeric(@Nullable ComponentName admin) { - return getPasswordMinimumNumeric(admin, UserHandle.myUserId()); + return getPasswordMinimumNumeric(admin, myUserId()); } /** @hide per-user version */ @@ -1390,7 +1402,7 @@ public class DevicePolicyManager { * @return The minimum number of symbols required in the password. */ public int getPasswordMinimumSymbols(@Nullable ComponentName admin) { - return getPasswordMinimumSymbols(admin, UserHandle.myUserId()); + return getPasswordMinimumSymbols(admin, myUserId()); } /** @hide per-user version */ @@ -1449,7 +1461,7 @@ public class DevicePolicyManager { * @return The minimum number of letters required in the password. */ public int getPasswordMinimumNonLetter(@Nullable ComponentName admin) { - return getPasswordMinimumNonLetter(admin, UserHandle.myUserId()); + return getPasswordMinimumNonLetter(admin, myUserId()); } /** @hide per-user version */ @@ -1540,7 +1552,7 @@ public class DevicePolicyManager { public long getPasswordExpirationTimeout(@Nullable ComponentName admin) { if (mService != null) { try { - return mService.getPasswordExpirationTimeout(admin, UserHandle.myUserId()); + return mService.getPasswordExpirationTimeout(admin, myUserId()); } catch (RemoteException e) { Log.w(TAG, "Failed talking with device policy service", e); } @@ -1561,7 +1573,7 @@ public class DevicePolicyManager { public long getPasswordExpiration(@Nullable ComponentName admin) { if (mService != null) { try { - return mService.getPasswordExpiration(admin, UserHandle.myUserId()); + return mService.getPasswordExpiration(admin, myUserId()); } catch (RemoteException e) { Log.w(TAG, "Failed talking with device policy service", e); } @@ -1577,7 +1589,7 @@ public class DevicePolicyManager { * @return The length of the password history */ public int getPasswordHistoryLength(@Nullable ComponentName admin) { - return getPasswordHistoryLength(admin, UserHandle.myUserId()); + return getPasswordHistoryLength(admin, myUserId()); } /** @hide per-user version */ @@ -1617,7 +1629,7 @@ public class DevicePolicyManager { public boolean isActivePasswordSufficient() { if (mService != null) { try { - return mService.isActivePasswordSufficient(UserHandle.myUserId()); + return mService.isActivePasswordSufficient(myUserId()); } catch (RemoteException e) { Log.w(TAG, "Failed talking with device policy service", e); } @@ -1636,7 +1648,7 @@ public class DevicePolicyManager { public int getCurrentFailedPasswordAttempts() { if (mService != null) { try { - return mService.getCurrentFailedPasswordAttempts(UserHandle.myUserId()); + return mService.getCurrentFailedPasswordAttempts(myUserId()); } catch (RemoteException e) { Log.w(TAG, "Failed talking with device policy service", e); } @@ -1698,7 +1710,7 @@ public class DevicePolicyManager { * all admins. */ public int getMaximumFailedPasswordsForWipe(@Nullable ComponentName admin) { - return getMaximumFailedPasswordsForWipe(admin, UserHandle.myUserId()); + return getMaximumFailedPasswordsForWipe(admin, myUserId()); } /** @hide per-user version */ @@ -1818,7 +1830,7 @@ public class DevicePolicyManager { * all admins if admin is null. Returns 0 if there are no restrictions. */ public long getMaximumTimeToLock(@Nullable ComponentName admin) { - return getMaximumTimeToLock(admin, UserHandle.myUserId()); + return getMaximumTimeToLock(admin, myUserId()); } /** @hide per-user version */ @@ -1881,7 +1893,7 @@ public class DevicePolicyManager { public void wipeData(int flags) { if (mService != null) { try { - mService.wipeData(flags, UserHandle.myUserId()); + mService.wipeData(flags, myUserId()); } catch (RemoteException e) { Log.w(TAG, "Failed talking with device policy service", e); } @@ -1995,7 +2007,7 @@ public class DevicePolicyManager { public ComponentName getGlobalProxyAdmin() { if (mService != null) { try { - return mService.getGlobalProxyAdmin(UserHandle.myUserId()); + return mService.getGlobalProxyAdmin(myUserId()); } catch (RemoteException e) { Log.w(TAG, "Failed talking with device policy service", e); } @@ -2145,7 +2157,7 @@ public class DevicePolicyManager { public boolean getStorageEncryption(@Nullable ComponentName admin) { if (mService != null) { try { - return mService.getStorageEncryption(admin, UserHandle.myUserId()); + return mService.getStorageEncryption(admin, myUserId()); } catch (RemoteException e) { Log.w(TAG, "Failed talking with device policy service", e); } @@ -2173,7 +2185,7 @@ public class DevicePolicyManager { * or {@link #ENCRYPTION_STATUS_ACTIVE}. */ public int getStorageEncryptionStatus() { - return getStorageEncryptionStatus(UserHandle.myUserId()); + return getStorageEncryptionStatus(myUserId()); } /** @hide per-user version */ @@ -2410,7 +2422,7 @@ public class DevicePolicyManager { * have disabled the camera */ public boolean getCameraDisabled(@Nullable ComponentName admin) { - return getCameraDisabled(admin, UserHandle.myUserId()); + return getCameraDisabled(admin, myUserId()); } /** @hide per-user version */ @@ -2457,7 +2469,7 @@ public class DevicePolicyManager { * have disabled screen capture. */ public boolean getScreenCaptureDisabled(@Nullable ComponentName admin) { - return getScreenCaptureDisabled(admin, UserHandle.myUserId()); + return getScreenCaptureDisabled(admin, myUserId()); } /** @hide per-user version */ @@ -2557,7 +2569,7 @@ public class DevicePolicyManager { * for a list. */ public int getKeyguardDisabledFeatures(@Nullable ComponentName admin) { - return getKeyguardDisabledFeatures(admin, UserHandle.myUserId()); + return getKeyguardDisabledFeatures(admin, myUserId()); } /** @hide per-user version */ @@ -2590,7 +2602,7 @@ public class DevicePolicyManager { * @hide */ public void setActiveAdmin(@NonNull ComponentName policyReceiver, boolean refreshing) { - setActiveAdmin(policyReceiver, refreshing, UserHandle.myUserId()); + setActiveAdmin(policyReceiver, refreshing, myUserId()); } /** @@ -2627,7 +2639,7 @@ public class DevicePolicyManager { public void getRemoveWarning(@Nullable ComponentName admin, RemoteCallback result) { if (mService != null) { try { - mService.getRemoveWarning(admin, result, UserHandle.myUserId()); + mService.getRemoveWarning(admin, result, myUserId()); } catch (RemoteException e) { Log.w(TAG, "Failed talking with device policy service", e); } @@ -2956,7 +2968,7 @@ public class DevicePolicyManager { throws IllegalArgumentException { if (mService != null) { try { - final int myUserId = UserHandle.myUserId(); + final int myUserId = myUserId(); mService.setActiveAdmin(admin, false, myUserId); return mService.setProfileOwner(admin, ownerName, myUserId); } catch (RemoteException re) { @@ -3301,7 +3313,7 @@ public class DevicePolicyManager { */ public List<PersistableBundle> getTrustAgentConfiguration(@Nullable ComponentName admin, @NonNull ComponentName agent) { - return getTrustAgentConfiguration(admin, agent, UserHandle.myUserId()); + return getTrustAgentConfiguration(admin, agent, myUserId()); } /** @hide per-user version */ @@ -3927,7 +3939,7 @@ public class DevicePolicyManager { * @see #setAccountManagementDisabled */ public String[] getAccountTypesWithManagementDisabled() { - return getAccountTypesWithManagementDisabledAsUser(UserHandle.myUserId()); + return getAccountTypesWithManagementDisabledAsUser(myUserId()); } /** diff --git a/core/java/android/content/pm/UserInfo.java b/core/java/android/content/pm/UserInfo.java index 73925633f741..d7c221510942 100644 --- a/core/java/android/content/pm/UserInfo.java +++ b/core/java/android/content/pm/UserInfo.java @@ -136,7 +136,16 @@ public class UserInfo implements Parcelable { * the method always returns false. */ public boolean isSystemOnly() { - return id == UserHandle.USER_SYSTEM && UserManager.isSplitSystemUser(); + return isSystemOnly(id); + } + + /** + * Returns true if the given user is a split system user. + * <p>If {@link UserManager#isSplitSystemUser split system user mode} is not enabled, + * the method always returns false. + */ + public static boolean isSystemOnly(int userId) { + return userId == UserHandle.USER_SYSTEM && UserManager.isSplitSystemUser(); } /** diff --git a/core/java/android/content/res/Configuration.java b/core/java/android/content/res/Configuration.java index 927c02f9ecfd..477b62cd86fa 100644 --- a/core/java/android/content/res/Configuration.java +++ b/core/java/android/content/res/Configuration.java @@ -61,7 +61,7 @@ public final class Configuration implements Parcelable, Comparable<Configuration * resource qualifier. 0 if undefined. */ public int mcc; - + /** * IMSI MNC (Mobile Network Code), corresponding to * <a href="{@docRoot}guide/topics/resources/providing-resources.html#MccQualifier">mnc</a> @@ -199,7 +199,7 @@ public final class Configuration implements Parcelable, Comparable<Configuration * @hide */ public static final int SCREENLAYOUT_COMPAT_NEEDED = 0x10000000; - + /** * Bit mask of overall layout of the screen. Currently there are two * fields: @@ -207,11 +207,11 @@ public final class Configuration implements Parcelable, Comparable<Configuration * of the screen. They may be one of * {@link #SCREENLAYOUT_SIZE_SMALL}, {@link #SCREENLAYOUT_SIZE_NORMAL}, * {@link #SCREENLAYOUT_SIZE_LARGE}, or {@link #SCREENLAYOUT_SIZE_XLARGE}.</p> - * + * * <p>The {@link #SCREENLAYOUT_LONG_MASK} defines whether the screen * is wider/taller than normal. They may be one of * {@link #SCREENLAYOUT_LONG_NO} or {@link #SCREENLAYOUT_LONG_YES}.</p> - * + * * <p>The {@link #SCREENLAYOUT_LAYOUTDIR_MASK} defines whether the screen layout * is either LTR or RTL. They may be one of * {@link #SCREENLAYOUT_LAYOUTDIR_LTR} or {@link #SCREENLAYOUT_LAYOUTDIR_RTL}.</p> @@ -295,6 +295,62 @@ public final class Configuration implements Parcelable, Comparable<Configuration return curLayout; } + /** @hide */ + public static String configurationDiffToString(int diff) { + ArrayList<String> list = new ArrayList<>(); + if ((diff & ActivityInfo.CONFIG_MCC) != 0) { + list.add("CONFIG_MCC"); + } + if ((diff & ActivityInfo.CONFIG_MNC) != 0) { + list.add("CONFIG_MNC"); + } + if ((diff & ActivityInfo.CONFIG_LOCALE) != 0) { + list.add("CONFIG_LOCALE"); + } + if ((diff & ActivityInfo.CONFIG_TOUCHSCREEN) != 0) { + list.add("CONFIG_TOUCHSCREEN"); + } + if ((diff & ActivityInfo.CONFIG_KEYBOARD) != 0) { + list.add("CONFIG_KEYBOARD"); + } + if ((diff & ActivityInfo.CONFIG_KEYBOARD_HIDDEN) != 0) { + list.add("CONFIG_KEYBOARD_HIDDEN"); + } + if ((diff & ActivityInfo.CONFIG_NAVIGATION) != 0) { + list.add("CONFIG_NAVIGATION"); + } + if ((diff & ActivityInfo.CONFIG_ORIENTATION) != 0) { + list.add("CONFIG_ORIENTATION"); + } + if ((diff & ActivityInfo.CONFIG_SCREEN_LAYOUT) != 0) { + list.add("CONFIG_SCREEN_LAYOUT"); + } + if ((diff & ActivityInfo.CONFIG_UI_MODE) != 0) { + list.add("CONFIG_UI_MODE"); + } + if ((diff & ActivityInfo.CONFIG_SCREEN_SIZE) != 0) { + list.add("CONFIG_SCREEN_SIZE"); + } + if ((diff & ActivityInfo.CONFIG_SMALLEST_SCREEN_SIZE) != 0) { + list.add("CONFIG_SMALLEST_SCREEN_SIZE"); + } + if ((diff & ActivityInfo.CONFIG_LAYOUT_DIRECTION) != 0) { + list.add("CONFIG_LAYOUT_DIRECTION"); + } + if ((diff & ActivityInfo.CONFIG_FONT_SCALE) != 0) { + list.add("CONFIG_FONT_SCALE"); + } + StringBuilder builder = new StringBuilder("{"); + for (int i = 0, n = list.size(); i < n; i++) { + builder.append(list.get(i)); + if (i != n - 1) { + builder.append(", "); + } + } + builder.append("}"); + return builder.toString(); + } + /** * Check if the Configuration's current {@link #screenLayout} is at * least the given size. @@ -323,7 +379,7 @@ public final class Configuration implements Parcelable, Comparable<Configuration * <a href="{@docRoot}guide/topics/resources/providing-resources.html#TouchscreenQualifier">finger</a> * resource qualifier. */ public static final int TOUCHSCREEN_FINGER = 3; - + /** * The kind of touch screen attached to the device. * One of: {@link #TOUCHSCREEN_NOTOUCH}, {@link #TOUCHSCREEN_FINGER}. @@ -344,7 +400,7 @@ public final class Configuration implements Parcelable, Comparable<Configuration * <a href="{@docRoot}guide/topics/resources/providing-resources.html#ImeQualifier">12key</a> * resource qualifier. */ public static final int KEYBOARD_12KEY = 3; - + /** * The kind of keyboard attached to the device. * One of: {@link #KEYBOARD_NOKEYS}, {@link #KEYBOARD_QWERTY}, @@ -364,7 +420,7 @@ public final class Configuration implements Parcelable, Comparable<Configuration public static final int KEYBOARDHIDDEN_YES = 2; /** Constant matching actual resource implementation. {@hide} */ public static final int KEYBOARDHIDDEN_SOFT = 3; - + /** * A flag indicating whether any keyboard is available. Unlike * {@link #hardKeyboardHidden}, this also takes into account a soft @@ -373,7 +429,7 @@ public final class Configuration implements Parcelable, Comparable<Configuration * {@link #KEYBOARDHIDDEN_NO}, {@link #KEYBOARDHIDDEN_YES}. */ public int keyboardHidden; - + /** Constant for {@link #hardKeyboardHidden}: a value indicating that no value has been set. */ public static final int HARDKEYBOARDHIDDEN_UNDEFINED = 0; /** Constant for {@link #hardKeyboardHidden}, value corresponding to the @@ -382,7 +438,7 @@ public final class Configuration implements Parcelable, Comparable<Configuration /** Constant for {@link #hardKeyboardHidden}, value corresponding to the * physical keyboard being hidden. */ public static final int HARDKEYBOARDHIDDEN_YES = 2; - + /** * A flag indicating whether the hard keyboard has been hidden. This will * be set on a device with a mechanism to hide the keyboard from the @@ -390,7 +446,7 @@ public final class Configuration implements Parcelable, Comparable<Configuration * {@link #HARDKEYBOARDHIDDEN_NO}, {@link #HARDKEYBOARDHIDDEN_YES}. */ public int hardKeyboardHidden; - + /** Constant for {@link #navigation}: a value indicating that no value has been set. */ public static final int NAVIGATION_UNDEFINED = 0; /** Constant for {@link #navigation}, value corresponding to the @@ -409,14 +465,14 @@ public final class Configuration implements Parcelable, Comparable<Configuration * <a href="{@docRoot}guide/topics/resources/providing-resources.html#NavigationQualifier">wheel</a> * resource qualifier. */ public static final int NAVIGATION_WHEEL = 4; - + /** * The kind of navigation method available on the device. * One of: {@link #NAVIGATION_NONAV}, {@link #NAVIGATION_DPAD}, * {@link #NAVIGATION_TRACKBALL}, {@link #NAVIGATION_WHEEL}. */ public int navigation; - + /** Constant for {@link #navigationHidden}: a value indicating that no value has been set. */ public static final int NAVIGATIONHIDDEN_UNDEFINED = 0; /** Constant for {@link #navigationHidden}, value corresponding to the @@ -427,7 +483,7 @@ public final class Configuration implements Parcelable, Comparable<Configuration * <a href="{@docRoot}guide/topics/resources/providing-resources.html#NavAvailQualifier">navhidden</a> * resource qualifier. */ public static final int NAVIGATIONHIDDEN_YES = 2; - + /** * A flag indicating whether any 5-way or DPAD navigation available. * This will be set on a device with a mechanism to hide the navigation @@ -435,7 +491,7 @@ public final class Configuration implements Parcelable, Comparable<Configuration * {@link #NAVIGATIONHIDDEN_NO}, {@link #NAVIGATIONHIDDEN_YES}. */ public int navigationHidden; - + /** Constant for {@link #orientation}: a value indicating that no value has been set. */ public static final int ORIENTATION_UNDEFINED = 0; /** Constant for {@link #orientation}, value corresponding to the @@ -448,7 +504,7 @@ public final class Configuration implements Parcelable, Comparable<Configuration public static final int ORIENTATION_LANDSCAPE = 2; /** @deprecated Not currently supported or used. */ @Deprecated public static final int ORIENTATION_SQUARE = 3; - + /** * Overall orientation of the screen. May be one of * {@link #ORIENTATION_LANDSCAPE}, {@link #ORIENTATION_PORTRAIT}. @@ -692,7 +748,7 @@ public final class Configuration implements Parcelable, Comparable<Configuration compatSmallestScreenWidthDp = o.compatSmallestScreenWidthDp; seq = o.seq; } - + public String toString() { StringBuilder sb = new StringBuilder(128); sb.append("{"); @@ -861,7 +917,7 @@ public final class Configuration implements Parcelable, Comparable<Configuration @Deprecated public void makeDefault() { setToDefaults(); } - + /** * Copy the fields from delta into this Configuration object, keeping * track of which ones have changed. Any undefined fields in @@ -1001,7 +1057,7 @@ public final class Configuration implements Parcelable, Comparable<Configuration if (delta.seq != 0) { seq = delta.seq; } - + return changed; } @@ -1119,12 +1175,12 @@ public final class Configuration implements Parcelable, Comparable<Configuration /** * Determine if a new resource needs to be loaded from the bit set of * configuration changes returned by {@link #updateFrom(Configuration)}. - * + * * @param configChanges The mask of changes configurations as returned by * {@link #updateFrom(Configuration)}. * @param interestingChanges The configuration changes that the resource * can handled, as given in {@link android.util.TypedValue#changingConfigurations}. - * + * * @return Return true if the resource needs to be loaded, else false. */ public static boolean needNewResources(int configChanges, int interestingChanges) { @@ -1159,7 +1215,7 @@ public final class Configuration implements Parcelable, Comparable<Configuration } return diff > 0; } - + /** * Parcelable methods */ @@ -1236,7 +1292,7 @@ public final class Configuration implements Parcelable, Comparable<Configuration compatSmallestScreenWidthDp = source.readInt(); seq = source.readInt(); } - + public static final Parcelable.Creator<Configuration> CREATOR = new Parcelable.Creator<Configuration>() { public Configuration createFromParcel(Parcel source) { diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java index 9a2a24128b92..444548faad42 100644 --- a/core/java/android/net/ConnectivityManager.java +++ b/core/java/android/net/ConnectivityManager.java @@ -208,6 +208,12 @@ public class ConnectivityManager { * {@link android.content.Intent#getParcelableExtra(String)}. */ public static final String EXTRA_CAPTIVE_PORTAL = "android.net.extra.CAPTIVE_PORTAL"; + + /** + * Key for passing a URL to the captive portal login activity. + */ + public static final String EXTRA_CAPTIVE_PORTAL_URL = "android.net.extra.CAPTIVE_PORTAL_URL"; + /** * Broadcast action to indicate the change of data activity status * (idle or active) on a network in a recent period. diff --git a/core/java/android/net/NetworkScoreManager.java b/core/java/android/net/NetworkScoreManager.java index a939ccee4ca7..3f36d65e577c 100644 --- a/core/java/android/net/NetworkScoreManager.java +++ b/core/java/android/net/NetworkScoreManager.java @@ -245,7 +245,8 @@ public class NetworkScoreManager { intent.putExtra(EXTRA_NETWORKS_TO_SCORE, networks); // A scorer should never become active if its package doesn't hold SCORE_NETWORKS, but // ensure the package still holds it to be extra safe. - mContext.sendBroadcastAsUser(intent, UserHandle.OWNER, Manifest.permission.SCORE_NETWORKS); + // TODO: http://b/23422763 + mContext.sendBroadcastAsUser(intent, UserHandle.SYSTEM, Manifest.permission.SCORE_NETWORKS); return true; } diff --git a/core/java/android/os/RecoverySystem.java b/core/java/android/os/RecoverySystem.java index 8c544f44f244..41de579201a5 100644 --- a/core/java/android/os/RecoverySystem.java +++ b/core/java/android/os/RecoverySystem.java @@ -410,7 +410,7 @@ public class RecoverySystem { Intent intent = new Intent("android.intent.action.MASTER_CLEAR_NOTIFICATION"); intent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND); - context.sendOrderedBroadcastAsUser(intent, UserHandle.OWNER, + context.sendOrderedBroadcastAsUser(intent, UserHandle.SYSTEM, android.Manifest.permission.MASTER_CLEAR, new BroadcastReceiver() { @Override diff --git a/core/java/android/os/StrictMode.java b/core/java/android/os/StrictMode.java index 87ce12cbe37c..8b2c74f07598 100644 --- a/core/java/android/os/StrictMode.java +++ b/core/java/android/os/StrictMode.java @@ -1923,7 +1923,7 @@ public final class StrictMode { if (LOG_V) Log.d(TAG, "strict mode violation stacks read from binder call. i=" + i); ViolationInfo info = new ViolationInfo(p, !currentlyGathering); if (info.crashInfo.stackTrace != null && info.crashInfo.stackTrace.length() > 30000) { - String front = info.crashInfo.stackTrace.substring(256); + String front = info.crashInfo.stackTrace.substring(0, 256); // 30000 characters is way too large for this to be any sane kind of // strict mode collection of stacks. We've had a problem where we leave // strict mode violations associated with the thread, and it keeps tacking diff --git a/core/java/android/os/storage/VolumeInfo.java b/core/java/android/os/storage/VolumeInfo.java index 688859479713..c368e5a24a1b 100644 --- a/core/java/android/os/storage/VolumeInfo.java +++ b/core/java/android/os/storage/VolumeInfo.java @@ -438,6 +438,8 @@ public class VolumeInfo implements Parcelable { final Intent intent = new Intent(DocumentsContract.ACTION_BROWSE_DOCUMENT_ROOT); intent.addCategory(Intent.CATEGORY_DEFAULT); intent.setData(uri); + intent.putExtra(DocumentsContract.EXTRA_SHOW_FILESIZE, true); + intent.putExtra(DocumentsContract.EXTRA_SHOW_ADVANCED, true); return intent; } diff --git a/core/java/android/provider/DocumentsContract.java b/core/java/android/provider/DocumentsContract.java index 59609f94546a..1a83cd567dc0 100644 --- a/core/java/android/provider/DocumentsContract.java +++ b/core/java/android/provider/DocumentsContract.java @@ -93,6 +93,9 @@ public final class DocumentsContract { public static final String EXTRA_SHOW_ADVANCED = "android.content.extra.SHOW_ADVANCED"; /** {@hide} */ + public static final String EXTRA_SHOW_FILESIZE = "android.content.extra.SHOW_FILESIZE"; + + /** {@hide} */ public static final String EXTRA_TARGET_URI = "android.content.extra.TARGET_URI"; /** @@ -266,7 +269,7 @@ public final class DocumentsContract { * writability of a document may change over time, for example due to * remote access changes. This flag indicates that a document client can * expect {@link ContentResolver#openOutputStream(Uri)} to succeed. - * + * * @see #COLUMN_FLAGS */ public static final int FLAG_SUPPORTS_WRITE = 1 << 1; diff --git a/core/java/android/view/ThreadedRenderer.java b/core/java/android/view/ThreadedRenderer.java index 420f7a174d53..dcef14267b7f 100644 --- a/core/java/android/view/ThreadedRenderer.java +++ b/core/java/android/view/ThreadedRenderer.java @@ -108,6 +108,11 @@ public class ThreadedRenderer extends HardwareRenderer { private Choreographer mChoreographer; private boolean mRootNodeNeedsUpdate; + // In case of multi threaded render nodes, these bounds indicate the content bounds against + // which the backdrop needs to be cropped against. + private final Rect mCurrentContentBounds = new Rect(); + private final Rect mStagedContentBounds = new Rect(); + ThreadedRenderer(Context context, boolean translucent) { final TypedArray a = context.obtainStyledAttributes(null, R.styleable.Lighting, 0, 0); mLightY = a.getDimension(R.styleable.Lighting_lightY, 0); @@ -307,6 +312,47 @@ public class ThreadedRenderer extends HardwareRenderer { Trace.traceEnd(Trace.TRACE_TAG_VIEW); } + /** + * Adds a rendernode to the renderer which can be drawn and changed asynchronously to the + * rendernode of the UI thread. + * @param node The node to add. + * @param placeFront If true, the render node will be placed in front of the content node, + * otherwise behind the content node. + */ + public void addRenderNode(RenderNode node, boolean placeFront) { + nAddRenderNode(mNativeProxy, node.mNativeRenderNode, placeFront); + } + + /** + * Only especially added render nodes can be removed. + * @param node The node which was added via addRenderNode which should get removed again. + */ + public void removeRenderNode(RenderNode node) { + nRemoveRenderNode(mNativeProxy, node.mNativeRenderNode); + } + + /** + * Draws a particular render node. If the node is not the content node, only the additional + * nodes will get drawn and the content remains untouched. + * @param node The node to be drawn. + */ + public void drawRenderNode(RenderNode node) { + nDrawRenderNode(mNativeProxy, node.mNativeRenderNode); + } + + /** + * To avoid unnecessary overdrawing of the main content all additionally passed render nodes + * will be prevented to overdraw this area. It will be synchronized with the draw call. + * This should be updated in the content view's draw call. + * @param left The left side of the protected bounds. + * @param top The top side of the protected bounds. + * @param right The right side of the protected bounds. + * @param bottom The bottom side of the protected bounds. + */ + public void setContentOverdrawProtectionBounds(int left, int top, int right, int bottom) { + mStagedContentBounds.set(left, top, right, bottom); + } + @Override void invalidateRoot() { mRootNodeNeedsUpdate = true; @@ -320,6 +366,14 @@ public class ThreadedRenderer extends HardwareRenderer { choreographer.mFrameInfo.markDrawStart(); updateRootDisplayList(view, callbacks); + // The main content view was updating the content bounds and we transfer them to the + // renderer. + if (!mCurrentContentBounds.equals(mStagedContentBounds)) { + mCurrentContentBounds.set(mStagedContentBounds); + nSetContentOverdrawProtectionBounds(mNativeProxy, mCurrentContentBounds.left, + mCurrentContentBounds.top, mCurrentContentBounds.right, + mCurrentContentBounds.bottom); + } attachInfo.mIgnoreDirtyState = false; @@ -541,4 +595,11 @@ public class ThreadedRenderer extends HardwareRenderer { private static native void nDumpProfileInfo(long nativeProxy, FileDescriptor fd, @DumpFlags int dumpFlags); private static native void nDumpProfileData(byte[] data, FileDescriptor fd); + + private static native void nAddRenderNode(long nativeProxy, long rootRenderNode, + boolean placeFront); + private static native void nRemoveRenderNode(long nativeProxy, long rootRenderNode); + private static native void nDrawRenderNode(long nativeProxy, long rootRenderNode); + private static native void nSetContentOverdrawProtectionBounds(long nativeProxy, int left, + int top, int right, int bottom); } diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java index 4d95294453ac..2a1d757feb7b 100644 --- a/core/java/android/view/View.java +++ b/core/java/android/view/View.java @@ -7373,6 +7373,23 @@ public class View implements Drawable.Callback, KeyEvent.Callback, } /** + * Compute the view's coordinate within the surface. + * + * <p>Computes the coordinates of this view in its surface. The argument + * must be an array of two integers. After the method returns, the array + * contains the x and y location in that order.</p> + * @hide + * @param location an array of two integers in which to hold the coordinates + */ + public void getLocationInSurface(@Size(2) int[] location) { + getLocationInWindow(location); + if (mAttachInfo != null && mAttachInfo.mViewRootImpl != null) { + location[0] += mAttachInfo.mViewRootImpl.mWindowAttributes.surfaceInsets.left; + location[1] += mAttachInfo.mViewRootImpl.mWindowAttributes.surfaceInsets.top; + } + } + + /** * Provide original WindowInsets that are dispatched to the view hierarchy. The insets are * only available if the view is attached. * diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java index 85b6a096bba9..8403c46e85bc 100644 --- a/core/java/android/view/ViewRootImpl.java +++ b/core/java/android/view/ViewRootImpl.java @@ -1787,10 +1787,6 @@ public final class ViewRootImpl implements ViewParent, || mHeight != hardwareRenderer.getHeight()) { hardwareRenderer.setup(mWidth, mHeight, mAttachInfo, mWindowAttributes.surfaceInsets); - if (!hwInitialized) { - hardwareRenderer.invalidate(mSurface); - mFullRedrawNeeded = true; - } } } diff --git a/core/java/android/view/WindowManager.java b/core/java/android/view/WindowManager.java index 45bc1df33469..92e473db556f 100644 --- a/core/java/android/view/WindowManager.java +++ b/core/java/android/view/WindowManager.java @@ -226,6 +226,7 @@ public interface WindowManager extends ViewManager { @ViewDebug.IntToString(from = TYPE_PRIVATE_PRESENTATION, to = "TYPE_PRIVATE_PRESENTATION"), @ViewDebug.IntToString(from = TYPE_VOICE_INTERACTION, to = "TYPE_VOICE_INTERACTION"), @ViewDebug.IntToString(from = TYPE_VOICE_INTERACTION_STARTING, to = "TYPE_VOICE_INTERACTION_STARTING"), + @ViewDebug.IntToString(from = TYPE_DOCK_DIVIDER, to = "TYPE_DOCK_DIVIDER"), }) public int type; @@ -565,6 +566,13 @@ public interface WindowManager extends ViewManager { public static final int TYPE_VOICE_INTERACTION_STARTING = FIRST_SYSTEM_WINDOW+33; /** + * Window for displaying a handle used for resizing docked stacks. This window is owned + * by the system process. + * @hide + */ + public static final int TYPE_DOCK_DIVIDER = FIRST_SYSTEM_WINDOW+34; + + /** * End of types of system windows. */ public static final int LAST_SYSTEM_WINDOW = 2999; diff --git a/core/java/android/widget/AbsSeekBar.java b/core/java/android/widget/AbsSeekBar.java index 6883db266e99..68855ff72531 100644 --- a/core/java/android/widget/AbsSeekBar.java +++ b/core/java/android/widget/AbsSeekBar.java @@ -385,17 +385,19 @@ public abstract class AbsSeekBar extends ProgressBar { } @Override - void onProgressRefresh(float scale, boolean fromUser, int progress) { - super.onProgressRefresh(scale, fromUser, progress); + void onVisualProgressChanged(int id, float scale) { + super.onVisualProgressChanged(id, scale); - final Drawable thumb = mThumb; - if (thumb != null) { - setThumbPos(getWidth(), thumb, scale, Integer.MIN_VALUE); + if (id == R.id.progress) { + final Drawable thumb = mThumb; + if (thumb != null) { + setThumbPos(getWidth(), thumb, scale, Integer.MIN_VALUE); - // Since we draw translated, the drawable's bounds that it signals - // for invalidation won't be the actual bounds we want invalidated, - // so just invalidate this whole view. - invalidate(); + // Since we draw translated, the drawable's bounds that it signals + // for invalidation won't be the actual bounds we want invalidated, + // so just invalidate this whole view. + invalidate(); + } } } @@ -709,8 +711,7 @@ public abstract class AbsSeekBar extends ProgressBar { case KeyEvent.KEYCODE_DPAD_RIGHT: increment = isLayoutRtl() ? -increment : increment; - // Let progress bar handle clamping values. - if (setProgress(getProgress() + increment, true)) { + if (setProgressInternal(getProgress() + increment, true, true)) { onKeyChange(); return true; } @@ -764,7 +765,7 @@ public abstract class AbsSeekBar extends ProgressBar { } float value = arguments.getFloat( AccessibilityNodeInfo.ACTION_ARGUMENT_PROGRESS_VALUE); - return setProgress((int) value, true); + return setProgressInternal((int) value, true, true); } case AccessibilityNodeInfo.ACTION_SCROLL_FORWARD: case AccessibilityNodeInfo.ACTION_SCROLL_BACKWARD: { @@ -777,7 +778,7 @@ public abstract class AbsSeekBar extends ProgressBar { } // Let progress bar handle clamping values. - if (setProgress(getProgress() + increment, true)) { + if (setProgressInternal(getProgress() + increment, true, true)) { onKeyChange(); return true; } diff --git a/core/java/android/widget/ProgressBar.java b/core/java/android/widget/ProgressBar.java index fce3754749ef..04c68ae600ea 100644 --- a/core/java/android/widget/ProgressBar.java +++ b/core/java/android/widget/ProgressBar.java @@ -16,10 +16,13 @@ package android.widget; +import android.animation.ObjectAnimator; import android.annotation.NonNull; import android.annotation.Nullable; import android.graphics.PorterDuff; +import android.util.FloatProperty; +import android.util.IntProperty; import android.view.accessibility.AccessibilityNodeInfo; import com.android.internal.R; @@ -28,7 +31,6 @@ import android.content.Context; import android.content.res.ColorStateList; import android.content.res.TypedArray; import android.graphics.Bitmap; -import android.graphics.BitmapShader; import android.graphics.Canvas; import android.graphics.Rect; import android.graphics.Shader; @@ -38,7 +40,6 @@ import android.graphics.drawable.BitmapDrawable; import android.graphics.drawable.ClipDrawable; import android.graphics.drawable.Drawable; import android.graphics.drawable.LayerDrawable; -import android.graphics.drawable.ShapeDrawable; import android.graphics.drawable.StateListDrawable; import android.graphics.drawable.shapes.RoundRectShape; import android.graphics.drawable.shapes.Shape; @@ -57,6 +58,7 @@ import android.view.accessibility.AccessibilityManager; import android.view.animation.AlphaAnimation; import android.view.animation.Animation; import android.view.animation.AnimationUtils; +import android.view.animation.DecelerateInterpolator; import android.view.animation.Interpolator; import android.view.animation.LinearInterpolator; import android.view.animation.Transformation; @@ -198,9 +200,17 @@ import java.util.ArrayList; */ @RemoteView public class ProgressBar extends View { + private static final int MAX_LEVEL = 10000; private static final int TIMEOUT_SEND_ACCESSIBILITY_EVENT = 200; + /** Interpolator used for smooth progress animations. */ + private static final DecelerateInterpolator PROGRESS_ANIM_INTERPOLATOR = + new DecelerateInterpolator(); + + /** Duration of smooth progress animations. */ + private static final int PROGRESS_ANIM_DURATION = 80; + int mMinWidth; int mMaxWidth; int mMinHeight; @@ -234,6 +244,9 @@ public class ProgressBar extends View { private boolean mAttached; private boolean mRefreshIsPosted; + /** Value used to track progress animation, in the range [0...1]. */ + private float mVisualProgress; + boolean mMirrorForRtl = false; private final ArrayList<RefreshData> mRefreshData = new ArrayList<RefreshData>(); @@ -814,8 +827,8 @@ public class ProgressBar extends View { updateDrawableBounds(getWidth(), getHeight()); updateDrawableState(); - doRefreshProgress(R.id.progress, mProgress, false, false); - doRefreshProgress(R.id.secondaryProgress, mSecondaryProgress, false, false); + doRefreshProgress(R.id.progress, mProgress, false, false, false); + doRefreshProgress(R.id.secondaryProgress, mSecondaryProgress, false, false, false); } } @@ -1246,7 +1259,7 @@ public class ProgressBar extends View { final int count = mRefreshData.size(); for (int i = 0; i < count; i++) { final RefreshData rd = mRefreshData.get(i); - doRefreshProgress(rd.id, rd.progress, rd.fromUser, true); + doRefreshProgress(rd.id, rd.progress, rd.fromUser, true, rd.animate); rd.recycle(); } mRefreshData.clear(); @@ -1263,8 +1276,9 @@ public class ProgressBar extends View { public int id; public int progress; public boolean fromUser; + public boolean animate; - public static RefreshData obtain(int id, int progress, boolean fromUser) { + public static RefreshData obtain(int id, int progress, boolean fromUser, boolean animate) { RefreshData rd = sPool.acquire(); if (rd == null) { rd = new RefreshData(); @@ -1272,6 +1286,7 @@ public class ProgressBar extends View { rd.id = id; rd.progress = progress; rd.fromUser = fromUser; + rd.animate = animate; return rd; } @@ -1281,26 +1296,21 @@ public class ProgressBar extends View { } private synchronized void doRefreshProgress(int id, int progress, boolean fromUser, - boolean callBackToApp) { - float scale = mMax > 0 ? (float) progress / (float) mMax : 0; - final Drawable d = mCurrentDrawable; - if (d != null) { - Drawable progressDrawable = null; - - if (d instanceof LayerDrawable) { - progressDrawable = ((LayerDrawable) d).findDrawableByLayerId(id); - if (progressDrawable != null && canResolveLayoutDirection()) { - progressDrawable.setLayoutDirection(getLayoutDirection()); - } - } - - final int level = (int) (scale * MAX_LEVEL); - (progressDrawable != null ? progressDrawable : d).setLevel(level); + boolean callBackToApp, boolean animate) { + final float scale = mMax > 0 ? progress / (float) mMax : 0; + final boolean isPrimary = id == R.id.progress; + + if (isPrimary && animate) { + final ObjectAnimator animator = ObjectAnimator.ofFloat(this, VISUAL_PROGRESS, scale); + animator.setAutoCancel(true); + animator.setDuration(PROGRESS_ANIM_DURATION); + animator.setInterpolator(PROGRESS_ANIM_INTERPOLATOR); + animator.start(); } else { - invalidate(); + setVisualProgress(id, scale); } - if (callBackToApp && id == R.id.progress) { + if (isPrimary && callBackToApp) { onProgressRefresh(scale, fromUser, progress); } } @@ -1311,15 +1321,51 @@ public class ProgressBar extends View { } } - private synchronized void refreshProgress(int id, int progress, boolean fromUser) { + /** + * Sets the visual state of a progress indicator. + * + * @param id the identifier of the progress indicator + * @param progress the visual progress in the range [0...1] + */ + private void setVisualProgress(int id, float progress) { + mVisualProgress = progress; + + Drawable d = mCurrentDrawable; + + if (d instanceof LayerDrawable) { + d = ((LayerDrawable) d).findDrawableByLayerId(id); + } + + if (d != null) { + final int level = (int) (progress * MAX_LEVEL); + d.setLevel(level); + } else { + invalidate(); + } + + onVisualProgressChanged(id, progress); + } + + /** + * Called when the visual state of a progress indicator changes. + * + * @param id the identifier of the progress indicator + * @param progress the visual progress in the range [0...1] + */ + void onVisualProgressChanged(int id, float progress) { + // Stub method. + } + + private synchronized void refreshProgress(int id, int progress, boolean fromUser, + boolean animate) { if (mUiThreadId == Thread.currentThread().getId()) { - doRefreshProgress(id, progress, fromUser, true); + doRefreshProgress(id, progress, fromUser, true, animate); } else { if (mRefreshProgressRunnable == null) { mRefreshProgressRunnable = new RefreshProgressRunnable(); } - final RefreshData rd = RefreshData.obtain(id, progress, fromUser); + final RefreshData rd = RefreshData.obtain(id, progress, fromUser, animate); mRefreshData.add(rd); if (mAttached && !mRefreshIsPosted) { post(mRefreshProgressRunnable); @@ -1329,8 +1375,8 @@ public class ProgressBar extends View { } /** - * <p>Set the current progress to the specified value. Does not do anything - * if the progress bar is in indeterminate mode.</p> + * Sets the current progress to the specified value. Does not do anything + * if the progress bar is in indeterminate mode. * * @param progress the new progress, between 0 and {@link #getMax()} * @@ -1341,11 +1387,26 @@ public class ProgressBar extends View { */ @android.view.RemotableViewMethod public synchronized void setProgress(int progress) { - setProgress(progress, false); + setProgressInternal(progress, false, false); + } + + /** + * Sets the current progress to the specified value, optionally animating + * between the current and target values. + * <p> + * Animation does not affect the result of {@link #getProgress()}, which + * will return the target value immediately after this method is called. + * + * @param progress the new progress value, between 0 and {@link #getMax()} + * @param animate {@code true} to animate between the current and target + * values or {@code false} to not animate + */ + public void setProgress(int progress, boolean animate) { + setProgressInternal(progress, false, animate); } @android.view.RemotableViewMethod - synchronized boolean setProgress(int progress, boolean fromUser) { + synchronized boolean setProgressInternal(int progress, boolean fromUser, boolean animate) { if (mIndeterminate) { // Not applicable. return false; @@ -1359,7 +1420,7 @@ public class ProgressBar extends View { } mProgress = progress; - refreshProgress(R.id.progress, mProgress, fromUser); + refreshProgress(R.id.progress, mProgress, fromUser, animate); return true; } @@ -1391,7 +1452,7 @@ public class ProgressBar extends View { if (secondaryProgress != mSecondaryProgress) { mSecondaryProgress = secondaryProgress; - refreshProgress(R.id.secondaryProgress, mSecondaryProgress, false); + refreshProgress(R.id.secondaryProgress, mSecondaryProgress, false, false); } } @@ -1464,7 +1525,7 @@ public class ProgressBar extends View { if (mProgress > max) { mProgress = max; } - refreshProgress(R.id.progress, mProgress, false); + refreshProgress(R.id.progress, mProgress, false, false); } } @@ -1847,7 +1908,7 @@ public class ProgressBar extends View { final int count = mRefreshData.size(); for (int i = 0; i < count; i++) { final RefreshData rd = mRefreshData.get(i); - doRefreshProgress(rd.id, rd.progress, rd.fromUser, true); + doRefreshProgress(rd.id, rd.progress, rd.fromUser, true, rd.animate); rd.recycle(); } mRefreshData.clear(); @@ -1956,4 +2017,23 @@ public class ProgressBar extends View { boolean mHasSecondaryProgressTint; boolean mHasSecondaryProgressTintMode; } + + /** + * Property wrapper around the visual state of the {@code progress} functionality + * handled by the {@link ProgressBar#setProgress(int, boolean)} method. This does + * not correspond directly to the actual progress -- only the visual state. + */ + private final FloatProperty<ProgressBar> VISUAL_PROGRESS = + new FloatProperty<ProgressBar>("visual_progress") { + @Override + public void setValue(ProgressBar object, float value) { + object.setVisualProgress(R.id.progress, value); + object.mVisualProgress = value; + } + + @Override + public Float get(ProgressBar object) { + return object.mVisualProgress; + } + }; } diff --git a/core/java/android/widget/Switch.java b/core/java/android/widget/Switch.java index 6f3a711c8aff..434516da1346 100644 --- a/core/java/android/widget/Switch.java +++ b/core/java/android/widget/Switch.java @@ -1387,7 +1387,7 @@ public class Switch extends CompoundButton { mTrackDrawable.jumpToCurrentState(); } - if (mPositionAnimator != null && mPositionAnimator.isRunning()) { + if (mPositionAnimator != null && mPositionAnimator.isStarted()) { mPositionAnimator.end(); mPositionAnimator = null; } diff --git a/core/java/com/android/internal/os/BatteryStatsImpl.java b/core/java/com/android/internal/os/BatteryStatsImpl.java index 6ccdd08498ce..e39bf607e53e 100644 --- a/core/java/com/android/internal/os/BatteryStatsImpl.java +++ b/core/java/com/android/internal/os/BatteryStatsImpl.java @@ -8044,6 +8044,10 @@ public final class BatteryStatsImpl extends BatteryStats { * wakelocks. If the screen is on, we just assign the actual cpu time an app used. */ public void updateCpuTimeLocked() { + if (mPowerProfile == null) { + return; + } + if (DEBUG_ENERGY_CPU) { Slog.d(TAG, "!Cpu updating!"); } @@ -8131,14 +8135,19 @@ public final class BatteryStatsImpl extends BatteryStats { // Add the cpu speeds to this UID. These are used as a ratio // for computing the power this UID used. - if (u.mCpuClusterSpeed == null) { - u.mCpuClusterSpeed = new LongSamplingCounter[clusterSpeeds.length][]; + final int numClusters = mPowerProfile.getNumCpuClusters(); + if (u.mCpuClusterSpeed == null || u.mCpuClusterSpeed.length != + numClusters) { + u.mCpuClusterSpeed = new LongSamplingCounter[numClusters][]; } for (int cluster = 0; cluster < clusterSpeeds.length; cluster++) { - if (u.mCpuClusterSpeed[cluster] == null) { + final int speedsInCluster = mPowerProfile.getNumSpeedStepsInCpuCluster( + cluster); + if (u.mCpuClusterSpeed[cluster] == null || speedsInCluster != + u.mCpuClusterSpeed[cluster].length) { u.mCpuClusterSpeed[cluster] = - new LongSamplingCounter[clusterSpeeds[cluster].length]; + new LongSamplingCounter[speedsInCluster]; } final LongSamplingCounter[] cpuSpeeds = u.mCpuClusterSpeed[cluster]; diff --git a/core/java/com/android/internal/os/InstallerConnection.java b/core/java/com/android/internal/os/InstallerConnection.java index dcc6a5e8cb33..db2b41f52b8c 100644 --- a/core/java/com/android/internal/os/InstallerConnection.java +++ b/core/java/com/android/internal/os/InstallerConnection.java @@ -92,14 +92,14 @@ public class InstallerConnection { } public int dexopt(String apkPath, int uid, boolean isPublic, - String instructionSet, int dexoptNeeded) { + String instructionSet, int dexoptNeeded, boolean bootComplete) { return dexopt(apkPath, uid, isPublic, "*", instructionSet, dexoptNeeded, - false, false, null); + false, false, null, bootComplete); } public int dexopt(String apkPath, int uid, boolean isPublic, String pkgName, String instructionSet, int dexoptNeeded, boolean vmSafeMode, - boolean debuggable, String outputPath) { + boolean debuggable, String outputPath, boolean bootComplete) { StringBuilder builder = new StringBuilder("dexopt"); builder.append(' '); builder.append(apkPath); @@ -116,6 +116,7 @@ public class InstallerConnection { builder.append(debuggable ? " 1" : " 0"); builder.append(' '); builder.append(outputPath != null ? outputPath : "!"); + builder.append(bootComplete ? " 1" : " 0"); return execute(builder.toString()); } diff --git a/core/java/com/android/internal/os/WrapperInit.java b/core/java/com/android/internal/os/WrapperInit.java index 34ae58a287b2..c558cf8d1ee7 100644 --- a/core/java/com/android/internal/os/WrapperInit.java +++ b/core/java/com/android/internal/os/WrapperInit.java @@ -121,22 +121,4 @@ public class WrapperInit { Zygote.appendQuotedShellArgs(command, args); Zygote.execShell(command.toString()); } - - /** - * Executes a standalone application with a wrapper command. - * This method never returns. - * - * @param invokeWith The wrapper command. - * @param classPath The class path. - * @param className The class name to invoke. - * @param args Arguments for the main() method of the specified class. - */ - public static void execStandalone(String invokeWith, String classPath, String className, - String[] args) { - StringBuilder command = new StringBuilder(invokeWith); - command.append(" /system/bin/dalvikvm -classpath '").append(classPath); - command.append("' ").append(className); - Zygote.appendQuotedShellArgs(command, args); - Zygote.execShell(command.toString()); - } } diff --git a/core/java/com/android/internal/os/ZygoteInit.java b/core/java/com/android/internal/os/ZygoteInit.java index af730978fd13..eee8b0812ea0 100644 --- a/core/java/com/android/internal/os/ZygoteInit.java +++ b/core/java/com/android/internal/os/ZygoteInit.java @@ -487,7 +487,7 @@ public class ZygoteInit { classPathElement, "*", instructionSet, false /* defer */); if (dexoptNeeded != DexFile.NO_DEXOPT_NEEDED) { installer.dexopt(classPathElement, Process.SYSTEM_UID, false, - instructionSet, dexoptNeeded); + instructionSet, dexoptNeeded, false /* boot complete */); } } } catch (IOException ioe) { diff --git a/core/java/com/android/internal/view/FloatingActionMode.java b/core/java/com/android/internal/view/FloatingActionMode.java index 44df0ce89133..b44baa2b8422 100644 --- a/core/java/com/android/internal/view/FloatingActionMode.java +++ b/core/java/com/android/internal/view/FloatingActionMode.java @@ -35,7 +35,7 @@ import java.util.Arrays; public class FloatingActionMode extends ActionMode { private static final int MAX_HIDE_DURATION = 3000; - private static final int MOVING_HIDE_DELAY = 300; + private static final int MOVING_HIDE_DELAY = 50; private final Context mContext; private final ActionMode.Callback2 mCallback; @@ -181,7 +181,6 @@ public class FloatingActionMode extends ActionMode { // Content rect is moving. mOriginatingView.removeCallbacks(mMovingOff); mFloatingToolbarVisibilityHelper.setMoving(true); - mFloatingToolbarVisibilityHelper.updateToolbarVisibility(); mOriginatingView.postDelayed(mMovingOff, MOVING_HIDE_DELAY); mFloatingToolbar.setContentRect(mContentRectOnScreen); @@ -189,9 +188,9 @@ public class FloatingActionMode extends ActionMode { } } else { mFloatingToolbarVisibilityHelper.setOutOfBounds(true); - mFloatingToolbarVisibilityHelper.updateToolbarVisibility(); mContentRectOnScreen.setEmpty(); } + mFloatingToolbarVisibilityHelper.updateToolbarVisibility(); mPreviousContentRectOnScreen.set(mContentRectOnScreen); } diff --git a/core/java/com/android/internal/view/menu/MenuItemImpl.java b/core/java/com/android/internal/view/menu/MenuItemImpl.java index 08d4e8616795..624c9e24e945 100644 --- a/core/java/com/android/internal/view/menu/MenuItemImpl.java +++ b/core/java/com/android/internal/view/menu/MenuItemImpl.java @@ -149,7 +149,7 @@ public final class MenuItemImpl implements MenuItem { return true; } - if (mMenu.dispatchMenuItemSelected(mMenu.getRootMenu(), this)) { + if (mMenu.dispatchMenuItemSelected(mMenu, this)) { return true; } diff --git a/core/java/com/android/internal/view/menu/SubMenuBuilder.java b/core/java/com/android/internal/view/menu/SubMenuBuilder.java index 92acf8cda8f5..cf741bf5bb02 100644 --- a/core/java/com/android/internal/view/menu/SubMenuBuilder.java +++ b/core/java/com/android/internal/view/menu/SubMenuBuilder.java @@ -73,7 +73,7 @@ public class SubMenuBuilder extends MenuBuilder implements SubMenu { @Override public MenuBuilder getRootMenu() { - return mParentMenu; + return mParentMenu.getRootMenu(); } @Override diff --git a/core/java/com/android/internal/widget/FloatingToolbar.java b/core/java/com/android/internal/widget/FloatingToolbar.java index ca6fe619f528..2a25db6b64c4 100644 --- a/core/java/com/android/internal/widget/FloatingToolbar.java +++ b/core/java/com/android/internal/widget/FloatingToolbar.java @@ -1488,10 +1488,9 @@ public final class FloatingToolbar { private static AnimatorSet createEnterAnimation(View view) { AnimatorSet animation = new AnimatorSet(); animation.playTogether( - ObjectAnimator.ofFloat(view, View.ALPHA, 0, 1).setDuration(200), + ObjectAnimator.ofFloat(view, View.ALPHA, 0, 1).setDuration(150), // Make sure that view.x is always fixed throughout the duration of this animation. ObjectAnimator.ofFloat(view, View.X, view.getX(), view.getX())); - animation.setStartDelay(50); return animation; } @@ -1506,7 +1505,7 @@ public final class FloatingToolbar { View view, int startDelay, Animator.AnimatorListener listener) { AnimatorSet animation = new AnimatorSet(); animation.playTogether( - ObjectAnimator.ofFloat(view, View.ALPHA, 1, 0).setDuration(200)); + ObjectAnimator.ofFloat(view, View.ALPHA, 1, 0).setDuration(100)); animation.setStartDelay(startDelay); animation.addListener(listener); return animation; diff --git a/core/java/com/android/server/LocalServices.java b/core/java/com/android/server/LocalServices.java index 25dcb308b55a..9c632ea725a9 100644 --- a/core/java/com/android/server/LocalServices.java +++ b/core/java/com/android/server/LocalServices.java @@ -16,6 +16,8 @@ package com.android.server; +import com.android.internal.annotations.VisibleForTesting; + import android.util.ArrayMap; /** @@ -57,4 +59,14 @@ public final class LocalServices { sLocalServiceObjects.put(type, service); } } + + /** + * Remove a service instance, must be only used in tests. + */ + @VisibleForTesting + public static <T> void removeServiceForTest(Class<T> type) { + synchronized (sLocalServiceObjects) { + sLocalServiceObjects.remove(type); + } + } } diff --git a/core/jni/AndroidRuntime.cpp b/core/jni/AndroidRuntime.cpp index e4bc80013b9c..ffc69a93f106 100644 --- a/core/jni/AndroidRuntime.cpp +++ b/core/jni/AndroidRuntime.cpp @@ -217,7 +217,7 @@ static void com_android_internal_os_RuntimeInit_nativeSetExitWithoutCleanup(JNIE /* * JNI registration. */ -static JNINativeMethod gMethods[] = { +static const JNINativeMethod gMethods[] = { { "nativeFinishInit", "()V", (void*) com_android_internal_os_RuntimeInit_nativeFinishInit }, { "nativeZygoteInit", "()V", diff --git a/core/jni/android/graphics/Bitmap.cpp b/core/jni/android/graphics/Bitmap.cpp index fbe3ececc348..e6c7c2bcf9d7 100755 --- a/core/jni/android/graphics/Bitmap.cpp +++ b/core/jni/android/graphics/Bitmap.cpp @@ -1348,7 +1348,7 @@ static jlong Bitmap_refPixelRef(JNIEnv* env, jobject, jlong bitmapHandle) { /////////////////////////////////////////////////////////////////////////////// -static JNINativeMethod gBitmapMethods[] = { +static const JNINativeMethod gBitmapMethods[] = { { "nativeCreate", "([IIIIIIZ)Landroid/graphics/Bitmap;", (void*)Bitmap_creator }, { "nativeCopy", "(JIZ)Landroid/graphics/Bitmap;", diff --git a/core/jni/android/graphics/BitmapFactory.cpp b/core/jni/android/graphics/BitmapFactory.cpp index 20a54e538ea8..28bc7fe47dd2 100644 --- a/core/jni/android/graphics/BitmapFactory.cpp +++ b/core/jni/android/graphics/BitmapFactory.cpp @@ -542,7 +542,7 @@ jobject decodeBitmap(JNIEnv* env, void* data, size_t size) { /////////////////////////////////////////////////////////////////////////////// -static JNINativeMethod gMethods[] = { +static const JNINativeMethod gMethods[] = { { "nativeDecodeStream", "(Ljava/io/InputStream;[BLandroid/graphics/Rect;Landroid/graphics/BitmapFactory$Options;)Landroid/graphics/Bitmap;", (void*)nativeDecodeStream @@ -569,7 +569,7 @@ static JNINativeMethod gMethods[] = { }, }; -static JNINativeMethod gOptionsMethods[] = { +static const JNINativeMethod gOptionsMethods[] = { { "requestCancel", "()V", (void*)nativeRequestCancel } }; diff --git a/core/jni/android/graphics/BitmapRegionDecoder.cpp b/core/jni/android/graphics/BitmapRegionDecoder.cpp index 1bbbb08990ce..2df3a4641aeb 100644 --- a/core/jni/android/graphics/BitmapRegionDecoder.cpp +++ b/core/jni/android/graphics/BitmapRegionDecoder.cpp @@ -261,7 +261,7 @@ static void nativeClean(JNIEnv* env, jobject, jlong brdHandle) { /////////////////////////////////////////////////////////////////////////////// -static JNINativeMethod gBitmapRegionDecoderMethods[] = { +static const JNINativeMethod gBitmapRegionDecoderMethods[] = { { "nativeDecodeRegion", "(JIIIILandroid/graphics/BitmapFactory$Options;)Landroid/graphics/Bitmap;", (void*)nativeDecodeRegion}, diff --git a/core/jni/android/graphics/Camera.cpp b/core/jni/android/graphics/Camera.cpp index 036ece1cec28..6fcf6892d490 100644 --- a/core/jni/android/graphics/Camera.cpp +++ b/core/jni/android/graphics/Camera.cpp @@ -115,7 +115,7 @@ static jfloat Camera_dotWithNormal(JNIEnv* env, jobject obj, /* * JNI registration. */ -static JNINativeMethod gCameraMethods[] = { +static const JNINativeMethod gCameraMethods[] = { /* name, signature, funcPtr */ { "nativeConstructor", "()V", (void*)Camera_constructor }, diff --git a/core/jni/android/graphics/CanvasProperty.cpp b/core/jni/android/graphics/CanvasProperty.cpp index deb4971a8a01..728bc1c3677e 100644 --- a/core/jni/android/graphics/CanvasProperty.cpp +++ b/core/jni/android/graphics/CanvasProperty.cpp @@ -39,7 +39,7 @@ static jlong createPaint(JNIEnv* env, jobject clazz, jlong paintPtr) { // JNI Glue // ---------------------------------------------------------------------------- -static JNINativeMethod gMethods[] = { +static const JNINativeMethod gMethods[] = { { "nCreateFloat", "(F)J", (void*) createFloat }, { "nCreatePaint", "(J)J", (void*) createPaint }, }; diff --git a/core/jni/android/graphics/ColorFilter.cpp b/core/jni/android/graphics/ColorFilter.cpp index d03bcf0fe3ac..83fd07382fe0 100644 --- a/core/jni/android/graphics/ColorFilter.cpp +++ b/core/jni/android/graphics/ColorFilter.cpp @@ -57,19 +57,19 @@ public: } }; -static JNINativeMethod colorfilter_methods[] = { +static const JNINativeMethod colorfilter_methods[] = { {"destroyFilter", "(J)V", (void*) SkColorFilterGlue::finalizer} }; -static JNINativeMethod porterduff_methods[] = { +static const JNINativeMethod porterduff_methods[] = { { "native_CreatePorterDuffFilter", "(II)J", (void*) SkColorFilterGlue::CreatePorterDuffFilter }, }; -static JNINativeMethod lighting_methods[] = { +static const JNINativeMethod lighting_methods[] = { { "native_CreateLightingFilter", "(II)J", (void*) SkColorFilterGlue::CreateLightingFilter }, }; -static JNINativeMethod colormatrix_methods[] = { +static const JNINativeMethod colormatrix_methods[] = { { "nativeColorMatrixFilter", "([F)J", (void*) SkColorFilterGlue::CreateColorMatrixFilter }, }; diff --git a/core/jni/android/graphics/DrawFilter.cpp b/core/jni/android/graphics/DrawFilter.cpp index 90ef6c0745cd..c1dc0dd025b6 100644 --- a/core/jni/android/graphics/DrawFilter.cpp +++ b/core/jni/android/graphics/DrawFilter.cpp @@ -97,11 +97,11 @@ public: } }; -static JNINativeMethod drawfilter_methods[] = { +static const JNINativeMethod drawfilter_methods[] = { {"nativeDestructor", "(J)V", (void*) SkDrawFilterGlue::finalizer} }; -static JNINativeMethod paintflags_methods[] = { +static const JNINativeMethod paintflags_methods[] = { {"nativeConstructor","(II)J", (void*) SkDrawFilterGlue::CreatePaintFlagsDF} }; diff --git a/core/jni/android/graphics/FontFamily.cpp b/core/jni/android/graphics/FontFamily.cpp index 38db76b0b183..dac6d96eb7df 100644 --- a/core/jni/android/graphics/FontFamily.cpp +++ b/core/jni/android/graphics/FontFamily.cpp @@ -124,7 +124,7 @@ static jboolean FontFamily_addFontFromAsset(JNIEnv* env, jobject, jlong familyPt /////////////////////////////////////////////////////////////////////////////// -static JNINativeMethod gFontFamilyMethods[] = { +static const JNINativeMethod gFontFamilyMethods[] = { { "nCreateFamily", "(Ljava/lang/String;I)J", (void*)FontFamily_create }, { "nUnrefFamily", "(J)V", (void*)FontFamily_unref }, { "nAddFont", "(JLjava/lang/String;)Z", (void*)FontFamily_addFont }, diff --git a/core/jni/android/graphics/Interpolator.cpp b/core/jni/android/graphics/Interpolator.cpp index 3593d1a4ab32..fa28359281db 100644 --- a/core/jni/android/graphics/Interpolator.cpp +++ b/core/jni/android/graphics/Interpolator.cpp @@ -71,7 +71,7 @@ static jint Interpolator_timeToValues(JNIEnv* env, jobject clazz, jlong interpHa /* * JNI registration. */ -static JNINativeMethod gInterpolatorMethods[] = { +static const JNINativeMethod gInterpolatorMethods[] = { { "nativeConstructor", "(II)J", (void*)Interpolator_constructor }, { "nativeDestructor", "(J)V", (void*)Interpolator_destructor }, { "nativeReset", "(JII)V", (void*)Interpolator_reset }, diff --git a/core/jni/android/graphics/MaskFilter.cpp b/core/jni/android/graphics/MaskFilter.cpp index d65864312196..2b4a1abbd673 100644 --- a/core/jni/android/graphics/MaskFilter.cpp +++ b/core/jni/android/graphics/MaskFilter.cpp @@ -61,19 +61,19 @@ public: } }; -static JNINativeMethod gMaskFilterMethods[] = { +static const JNINativeMethod gMaskFilterMethods[] = { { "nativeDestructor", "(J)V", (void*)SkMaskFilterGlue::destructor } }; -static JNINativeMethod gBlurMaskFilterMethods[] = { +static const JNINativeMethod gBlurMaskFilterMethods[] = { { "nativeConstructor", "(FI)J", (void*)SkMaskFilterGlue::createBlur } }; -static JNINativeMethod gEmbossMaskFilterMethods[] = { +static const JNINativeMethod gEmbossMaskFilterMethods[] = { { "nativeConstructor", "([FFFF)J", (void*)SkMaskFilterGlue::createEmboss } }; -static JNINativeMethod gTableMaskFilterMethods[] = { +static const JNINativeMethod gTableMaskFilterMethods[] = { { "nativeNewTable", "([B)J", (void*)SkMaskFilterGlue::createTable }, { "nativeNewClip", "(II)J", (void*)SkMaskFilterGlue::createClipTable }, { "nativeNewGamma", "(F)J", (void*)SkMaskFilterGlue::createGammaTable } diff --git a/core/jni/android/graphics/Matrix.cpp b/core/jni/android/graphics/Matrix.cpp index 101e2ba603e6..b0f3bb4b965a 100644 --- a/core/jni/android/graphics/Matrix.cpp +++ b/core/jni/android/graphics/Matrix.cpp @@ -302,7 +302,7 @@ public: } }; -static JNINativeMethod methods[] = { +static const JNINativeMethod methods[] = { {"finalizer", "(J)V", (void*) SkMatrixGlue::finalizer}, {"native_create","(J)J", (void*) SkMatrixGlue::create}, diff --git a/core/jni/android/graphics/Movie.cpp b/core/jni/android/graphics/Movie.cpp index d67ed10e9ef1..498c5902e5fd 100644 --- a/core/jni/android/graphics/Movie.cpp +++ b/core/jni/android/graphics/Movie.cpp @@ -135,7 +135,7 @@ static void movie_destructor(JNIEnv* env, jobject, jlong movieHandle) { ////////////////////////////////////////////////////////////////////////////////////////////// -static JNINativeMethod gMethods[] = { +static const JNINativeMethod gMethods[] = { { "width", "()I", (void*)movie_width }, { "height", "()I", (void*)movie_height }, { "isOpaque", "()Z", (void*)movie_isOpaque }, diff --git a/core/jni/android/graphics/NinePatch.cpp b/core/jni/android/graphics/NinePatch.cpp index 1c282623f455..3ccbb35cc960 100644 --- a/core/jni/android/graphics/NinePatch.cpp +++ b/core/jni/android/graphics/NinePatch.cpp @@ -108,7 +108,7 @@ public: ///////////////////////////////////////////////////////////////////////////////////////// -static JNINativeMethod gNinePatchMethods[] = { +static const JNINativeMethod gNinePatchMethods[] = { { "isNinePatchChunk", "([B)Z", (void*) SkNinePatchGlue::isNinePatchChunk }, { "validateNinePatchChunk", "([B)J", (void*) SkNinePatchGlue::validateNinePatchChunk }, diff --git a/core/jni/android/graphics/Paint.cpp b/core/jni/android/graphics/Paint.cpp index 988d13aa7ea8..520dc4fdb496 100644 --- a/core/jni/android/graphics/Paint.cpp +++ b/core/jni/android/graphics/Paint.cpp @@ -1095,7 +1095,7 @@ public: }; -static JNINativeMethod methods[] = { +static const JNINativeMethod methods[] = { {"finalizer", "(J)V", (void*) PaintGlue::finalizer}, {"native_init","()J", (void*) PaintGlue::init}, {"native_initWithPaint","(J)J", (void*) PaintGlue::initWithPaint}, diff --git a/core/jni/android/graphics/Path.cpp b/core/jni/android/graphics/Path.cpp index dbd7c89805ab..2998c99a273e 100644 --- a/core/jni/android/graphics/Path.cpp +++ b/core/jni/android/graphics/Path.cpp @@ -475,7 +475,7 @@ public: } }; -static JNINativeMethod methods[] = { +static const JNINativeMethod methods[] = { {"finalizer", "(J)V", (void*) SkPathGlue::finalizer}, {"init1","()J", (void*) SkPathGlue::init1}, {"init2","(J)J", (void*) SkPathGlue::init2}, diff --git a/core/jni/android/graphics/PathEffect.cpp b/core/jni/android/graphics/PathEffect.cpp index 265944e216e2..b289b21a3d8b 100644 --- a/core/jni/android/graphics/PathEffect.cpp +++ b/core/jni/android/graphics/PathEffect.cpp @@ -69,31 +69,31 @@ public: //////////////////////////////////////////////////////////////////////////////////////////////////////// -static JNINativeMethod gPathEffectMethods[] = { +static const JNINativeMethod gPathEffectMethods[] = { { "nativeDestructor", "(J)V", (void*)SkPathEffectGlue::destructor } }; -static JNINativeMethod gComposePathEffectMethods[] = { +static const JNINativeMethod gComposePathEffectMethods[] = { { "nativeCreate", "(JJ)J", (void*)SkPathEffectGlue::Compose_constructor } }; -static JNINativeMethod gSumPathEffectMethods[] = { +static const JNINativeMethod gSumPathEffectMethods[] = { { "nativeCreate", "(JJ)J", (void*)SkPathEffectGlue::Sum_constructor } }; -static JNINativeMethod gDashPathEffectMethods[] = { +static const JNINativeMethod gDashPathEffectMethods[] = { { "nativeCreate", "([FF)J", (void*)SkPathEffectGlue::Dash_constructor } }; -static JNINativeMethod gPathDashPathEffectMethods[] = { +static const JNINativeMethod gPathDashPathEffectMethods[] = { { "nativeCreate", "(JFFI)J", (void*)SkPathEffectGlue::OneD_constructor } }; -static JNINativeMethod gCornerPathEffectMethods[] = { +static const JNINativeMethod gCornerPathEffectMethods[] = { { "nativeCreate", "(F)J", (void*)SkPathEffectGlue::Corner_constructor } }; -static JNINativeMethod gDiscretePathEffectMethods[] = { +static const JNINativeMethod gDiscretePathEffectMethods[] = { { "nativeCreate", "(FF)J", (void*)SkPathEffectGlue::Discrete_constructor } }; diff --git a/core/jni/android/graphics/PathMeasure.cpp b/core/jni/android/graphics/PathMeasure.cpp index fec5d9db3a6a..70e528d4be6f 100644 --- a/core/jni/android/graphics/PathMeasure.cpp +++ b/core/jni/android/graphics/PathMeasure.cpp @@ -143,7 +143,7 @@ public: } }; -static JNINativeMethod methods[] = { +static const JNINativeMethod methods[] = { {"native_create", "(JZ)J", (void*) SkPathMeasureGlue::create }, {"native_setPath", "(JJZ)V", (void*) SkPathMeasureGlue::setPath }, {"native_getLength", "(J)F", (void*) SkPathMeasureGlue::getLength }, diff --git a/core/jni/android/graphics/PorterDuff.cpp b/core/jni/android/graphics/PorterDuff.cpp index fed90a5d2f83..dfc3c9d7ed13 100644 --- a/core/jni/android/graphics/PorterDuff.cpp +++ b/core/jni/android/graphics/PorterDuff.cpp @@ -58,7 +58,7 @@ public: }; -static JNINativeMethod methods[] = { +static const JNINativeMethod methods[] = { {"nativeCreateXfermode","(I)J", (void*) SkPorterDuffGlue::CreateXfermode}, }; diff --git a/core/jni/android/graphics/Rasterizer.cpp b/core/jni/android/graphics/Rasterizer.cpp index cfc23ac8ecb3..a106ecfeb65f 100644 --- a/core/jni/android/graphics/Rasterizer.cpp +++ b/core/jni/android/graphics/Rasterizer.cpp @@ -61,7 +61,7 @@ public: } }; -static JNINativeMethod gRasterizerMethods[] = { +static const JNINativeMethod gRasterizerMethods[] = { {"finalizer", "(J)V", (void*) SkRasterizerGlue::finalizer} }; @@ -85,7 +85,7 @@ public: } }; -static JNINativeMethod gLayerRasterizerMethods[] = { +static const JNINativeMethod gLayerRasterizerMethods[] = { { "nativeConstructor", "()J", (void*)SkLayerRasterizerGlue::create }, { "nativeAddLayer", "(JJFF)V", (void*)SkLayerRasterizerGlue::addLayer } }; diff --git a/core/jni/android/graphics/Region.cpp b/core/jni/android/graphics/Region.cpp index e99bdfcc63fa..bcd0b60308bb 100644 --- a/core/jni/android/graphics/Region.cpp +++ b/core/jni/android/graphics/Region.cpp @@ -306,13 +306,13 @@ static jboolean RegionIter_next(JNIEnv* env, jobject, jlong pairHandle, jobject //////////////////////////////////////////////////////////////////////////////////////////////////////////// -static JNINativeMethod gRegionIterMethods[] = { +static const JNINativeMethod gRegionIterMethods[] = { { "nativeConstructor", "(J)J", (void*)RegionIter_constructor }, { "nativeDestructor", "(J)V", (void*)RegionIter_destructor }, { "nativeNext", "(JLandroid/graphics/Rect;)Z", (void*)RegionIter_next } }; -static JNINativeMethod gRegionMethods[] = { +static const JNINativeMethod gRegionMethods[] = { // these are static methods { "nativeConstructor", "()J", (void*)Region_constructor }, { "nativeDestructor", "(J)V", (void*)Region_destructor }, diff --git a/core/jni/android/graphics/Shader.cpp b/core/jni/android/graphics/Shader.cpp index 49c377e9c97f..799ed835197d 100644 --- a/core/jni/android/graphics/Shader.cpp +++ b/core/jni/android/graphics/Shader.cpp @@ -240,36 +240,36 @@ static jlong ComposeShader_create2(JNIEnv* env, jobject o, /////////////////////////////////////////////////////////////////////////////////////////////// -static JNINativeMethod gColorMethods[] = { +static const JNINativeMethod gColorMethods[] = { { "nativeRGBToHSV", "(III[F)V", (void*)Color_RGBToHSV }, { "nativeHSVToColor", "(I[F)I", (void*)Color_HSVToColor } }; -static JNINativeMethod gShaderMethods[] = { +static const JNINativeMethod gShaderMethods[] = { { "nativeDestructor", "(J)V", (void*)Shader_destructor }, { "nativeSetLocalMatrix", "(JJ)J", (void*)Shader_setLocalMatrix } }; -static JNINativeMethod gBitmapShaderMethods[] = { +static const JNINativeMethod gBitmapShaderMethods[] = { { "nativeCreate", "(Landroid/graphics/Bitmap;II)J", (void*)BitmapShader_constructor }, }; -static JNINativeMethod gLinearGradientMethods[] = { +static const JNINativeMethod gLinearGradientMethods[] = { { "nativeCreate1", "(FFFF[I[FI)J", (void*)LinearGradient_create1 }, { "nativeCreate2", "(FFFFIII)J", (void*)LinearGradient_create2 }, }; -static JNINativeMethod gRadialGradientMethods[] = { +static const JNINativeMethod gRadialGradientMethods[] = { { "nativeCreate1", "(FFF[I[FI)J", (void*)RadialGradient_create1 }, { "nativeCreate2", "(FFFIII)J", (void*)RadialGradient_create2 }, }; -static JNINativeMethod gSweepGradientMethods[] = { +static const JNINativeMethod gSweepGradientMethods[] = { { "nativeCreate1", "(FF[I[F)J", (void*)SweepGradient_create1 }, { "nativeCreate2", "(FFII)J", (void*)SweepGradient_create2 }, }; -static JNINativeMethod gComposeShaderMethods[] = { +static const JNINativeMethod gComposeShaderMethods[] = { { "nativeCreate1", "(JJJ)J", (void*)ComposeShader_create1 }, { "nativeCreate2", "(JJI)J", (void*)ComposeShader_create2 }, }; diff --git a/core/jni/android/graphics/SurfaceTexture.cpp b/core/jni/android/graphics/SurfaceTexture.cpp index 80de52611735..61dc6e425ddf 100644 --- a/core/jni/android/graphics/SurfaceTexture.cpp +++ b/core/jni/android/graphics/SurfaceTexture.cpp @@ -359,7 +359,7 @@ static jboolean SurfaceTexture_isReleased(JNIEnv* env, jobject thiz) // ---------------------------------------------------------------------------- -static JNINativeMethod gSurfaceTextureMethods[] = { +static const JNINativeMethod gSurfaceTextureMethods[] = { {"nativeClassInit", "()V", (void*)SurfaceTexture_classInit }, {"nativeInit", "(ZIZLjava/lang/ref/WeakReference;)V", (void*)SurfaceTexture_init }, {"nativeFinalize", "()V", (void*)SurfaceTexture_finalize }, diff --git a/core/jni/android/graphics/Typeface.cpp b/core/jni/android/graphics/Typeface.cpp index e0cbc9efbd18..e97b768dd0cc 100644 --- a/core/jni/android/graphics/Typeface.cpp +++ b/core/jni/android/graphics/Typeface.cpp @@ -68,7 +68,7 @@ static void Typeface_setDefault(JNIEnv *env, jobject, jlong faceHandle) { /////////////////////////////////////////////////////////////////////////////// -static JNINativeMethod gTypefaceMethods[] = { +static const JNINativeMethod gTypefaceMethods[] = { { "nativeCreateFromTypeface", "(JI)J", (void*)Typeface_createFromTypeface }, { "nativeCreateWeightAlias", "(JI)J", (void*)Typeface_createWeightAlias }, { "nativeUnref", "(J)V", (void*)Typeface_unref }, diff --git a/core/jni/android/graphics/Xfermode.cpp b/core/jni/android/graphics/Xfermode.cpp index 4a424aeb09a3..7441acc95cea 100644 --- a/core/jni/android/graphics/Xfermode.cpp +++ b/core/jni/android/graphics/Xfermode.cpp @@ -47,15 +47,15 @@ public: /////////////////////////////////////////////////////////////////////////////// -static JNINativeMethod gXfermodeMethods[] = { +static const JNINativeMethod gXfermodeMethods[] = { {"finalizer", "(J)V", (void*) SkXfermodeGlue::finalizer} }; -static JNINativeMethod gAvoidMethods[] = { +static const JNINativeMethod gAvoidMethods[] = { {"nativeCreate", "(III)J", (void*) SkXfermodeGlue::avoid_create} }; -static JNINativeMethod gPixelXorMethods[] = { +static const JNINativeMethod gPixelXorMethods[] = { {"nativeCreate", "(I)J", (void*) SkXfermodeGlue::pixelxor_create} }; diff --git a/core/jni/android/graphics/YuvToJpegEncoder.cpp b/core/jni/android/graphics/YuvToJpegEncoder.cpp index 5eede2aee286..7d0c39cca018 100644 --- a/core/jni/android/graphics/YuvToJpegEncoder.cpp +++ b/core/jni/android/graphics/YuvToJpegEncoder.cpp @@ -243,7 +243,7 @@ static jboolean YuvImage_compressToJpeg(JNIEnv* env, jobject, jbyteArray inYuv, } /////////////////////////////////////////////////////////////////////////////// -static JNINativeMethod gYuvImageMethods[] = { +static const JNINativeMethod gYuvImageMethods[] = { { "nativeCompressToJpeg", "([BIII[I[IILjava/io/OutputStream;[B)Z", (void*)YuvImage_compressToJpeg } }; diff --git a/core/jni/android/graphics/pdf/PdfDocument.cpp b/core/jni/android/graphics/pdf/PdfDocument.cpp index a91b15b7fa41..7a13fe427b00 100644 --- a/core/jni/android/graphics/pdf/PdfDocument.cpp +++ b/core/jni/android/graphics/pdf/PdfDocument.cpp @@ -150,7 +150,7 @@ static void nativeClose(JNIEnv* env, jobject thiz, jlong documentPtr) { document->close(); } -static JNINativeMethod gPdfDocument_Methods[] = { +static const JNINativeMethod gPdfDocument_Methods[] = { {"nativeCreateDocument", "()J", (void*) nativeCreateDocument}, {"nativeStartPage", "(JIIIIII)J", (void*) nativeStartPage}, {"nativeFinishPage", "(J)V", (void*) nativeFinishPage}, diff --git a/core/jni/android/graphics/pdf/PdfEditor.cpp b/core/jni/android/graphics/pdf/PdfEditor.cpp index 52b69e02e894..0177635f26b0 100644 --- a/core/jni/android/graphics/pdf/PdfEditor.cpp +++ b/core/jni/android/graphics/pdf/PdfEditor.cpp @@ -343,7 +343,7 @@ static void nativeSetPageCropBox(JNIEnv* env, jclass thiz, jlong documentPtr, ji nativeSetPageBox(env, thiz, documentPtr, pageIndex, PAGE_BOX_CROP, mediaBox); } -static JNINativeMethod gPdfEditor_Methods[] = { +static const JNINativeMethod gPdfEditor_Methods[] = { {"nativeOpen", "(IJ)J", (void*) nativeOpen}, {"nativeClose", "(J)V", (void*) nativeClose}, {"nativeGetPageCount", "(J)I", (void*) nativeGetPageCount}, diff --git a/core/jni/android/graphics/pdf/PdfRenderer.cpp b/core/jni/android/graphics/pdf/PdfRenderer.cpp index 006eef847a12..6ddfacf442e8 100644 --- a/core/jni/android/graphics/pdf/PdfRenderer.cpp +++ b/core/jni/android/graphics/pdf/PdfRenderer.cpp @@ -283,7 +283,7 @@ static void nativeRenderPage(JNIEnv* env, jclass thiz, jlong documentPtr, jlong skBitmap.notifyPixelsChanged(); } -static JNINativeMethod gPdfRenderer_Methods[] = { +static const JNINativeMethod gPdfRenderer_Methods[] = { {"nativeCreate", "(IJ)J", (void*) nativeCreate}, {"nativeClose", "(J)V", (void*) nativeClose}, {"nativeGetPageCount", "(J)I", (void*) nativeGetPageCount}, diff --git a/core/jni/android/opengl/util.cpp b/core/jni/android/opengl/util.cpp index 40029bbe0aee..e045f5f36ada 100644 --- a/core/jni/android/opengl/util.cpp +++ b/core/jni/android/opengl/util.cpp @@ -1087,18 +1087,18 @@ static jint etc1_getHeight(JNIEnv *env, jclass clazz, * JNI registration */ -static JNINativeMethod gMatrixMethods[] = { +static const JNINativeMethod gMatrixMethods[] = { { "multiplyMM", "([FI[FI[FI)V", (void*)util_multiplyMM }, { "multiplyMV", "([FI[FI[FI)V", (void*)util_multiplyMV }, }; -static JNINativeMethod gVisibilityMethods[] = { +static const JNINativeMethod gVisibilityMethods[] = { { "computeBoundingSphere", "([FII[FI)V", (void*)util_computeBoundingSphere }, { "frustumCullSpheres", "([FI[FII[III)I", (void*)util_frustumCullSpheres }, { "visibilityTest", "([FI[FI[CII)I", (void*)util_visibilityTest }, }; -static JNINativeMethod gUtilsMethods[] = { +static const JNINativeMethod gUtilsMethods[] = { { "native_getInternalFormat", "(Landroid/graphics/Bitmap;)I", (void*) util_getInternalFormat }, { "native_getType", "(Landroid/graphics/Bitmap;)I", (void*) util_getType }, { "native_texImage2D", "(IIILandroid/graphics/Bitmap;II)I", (void*)util_texImage2D }, @@ -1106,7 +1106,7 @@ static JNINativeMethod gUtilsMethods[] = { { "setTracingLevel", "(I)V", (void*)setTracingLevel }, }; -static JNINativeMethod gEtc1Methods[] = { +static const JNINativeMethod gEtc1Methods[] = { { "encodeBlock", "(Ljava/nio/Buffer;ILjava/nio/Buffer;)V", (void*) etc1_encodeBlock }, { "decodeBlock", "(Ljava/nio/Buffer;Ljava/nio/Buffer;)V", (void*) etc1_decodeBlock }, { "getEncodedDataSize", "(II)I", (void*) etc1_getEncodedDataSize }, @@ -1120,11 +1120,11 @@ static JNINativeMethod gEtc1Methods[] = { typedef struct _ClassRegistrationInfo { const char* classPath; - JNINativeMethod* methods; + const JNINativeMethod* methods; size_t methodCount; } ClassRegistrationInfo; -static ClassRegistrationInfo gClasses[] = { +static const ClassRegistrationInfo gClasses[] = { {"android/opengl/Matrix", gMatrixMethods, NELEM(gMatrixMethods)}, {"android/opengl/Visibility", gVisibilityMethods, NELEM(gVisibilityMethods)}, {"android/opengl/GLUtils", gUtilsMethods, NELEM(gUtilsMethods)}, @@ -1136,7 +1136,7 @@ int register_android_opengl_classes(JNIEnv* env) nativeClassInitBuffer(env); int result = 0; for (int i = 0; i < NELEM(gClasses); i++) { - ClassRegistrationInfo* cri = &gClasses[i]; + const ClassRegistrationInfo* cri = &gClasses[i]; result = RegisterMethodsOrDie(env, cri->classPath, cri->methods, cri->methodCount); } return result; diff --git a/core/jni/android_animation_PropertyValuesHolder.cpp b/core/jni/android_animation_PropertyValuesHolder.cpp index d11774189901..6065c2473978 100644 --- a/core/jni/android_animation_PropertyValuesHolder.cpp +++ b/core/jni/android_animation_PropertyValuesHolder.cpp @@ -139,7 +139,7 @@ static void android_animation_PropertyValuesHolder_callMultipleIntMethod( env->ReleaseIntArrayElements(arg, intValues, JNI_ABORT); } -static JNINativeMethod gMethods[] = { +static const JNINativeMethod gMethods[] = { { "nGetIntMethod", "(Ljava/lang/Class;Ljava/lang/String;)J", (void*)android_animation_PropertyValuesHolder_getIntMethod }, { "nGetFloatMethod", "(Ljava/lang/Class;Ljava/lang/String;)J", diff --git a/core/jni/android_content_res_ObbScanner.cpp b/core/jni/android_content_res_ObbScanner.cpp index ef17db6b0fdf..36d78cf3aca0 100644 --- a/core/jni/android_content_res_ObbScanner.cpp +++ b/core/jni/android_content_res_ObbScanner.cpp @@ -76,7 +76,7 @@ static void android_content_res_ObbScanner_getObbInfo(JNIEnv* env, jobject clazz /* * JNI registration. */ -static JNINativeMethod gMethods[] = { +static const JNINativeMethod gMethods[] = { /* name, signature, funcPtr */ { "getObbInfo_native", "(Ljava/lang/String;Landroid/content/res/ObbInfo;)V", (void*) android_content_res_ObbScanner_getObbInfo }, diff --git a/core/jni/android_database_CursorWindow.cpp b/core/jni/android_database_CursorWindow.cpp index 580ac02789c5..bb09d001037d 100644 --- a/core/jni/android_database_CursorWindow.cpp +++ b/core/jni/android_database_CursorWindow.cpp @@ -477,7 +477,7 @@ static jboolean nativePutNull(JNIEnv* env, jclass clazz, jlong windowPtr, return true; } -static JNINativeMethod sMethods[] = +static const JNINativeMethod sMethods[] = { /* name, signature, funcPtr */ { "nativeCreate", "(Ljava/lang/String;I)J", diff --git a/core/jni/android_database_SQLiteConnection.cpp b/core/jni/android_database_SQLiteConnection.cpp index 7a3cdf68fb18..bcc3bb09b69d 100644 --- a/core/jni/android_database_SQLiteConnection.cpp +++ b/core/jni/android_database_SQLiteConnection.cpp @@ -786,7 +786,7 @@ static void nativeResetCancel(JNIEnv* env, jobject clazz, jlong connectionPtr, } -static JNINativeMethod sMethods[] = +static const JNINativeMethod sMethods[] = { /* name, signature, funcPtr */ { "nativeOpen", "(Ljava/lang/String;ILjava/lang/String;ZZ)J", diff --git a/core/jni/android_database_SQLiteDebug.cpp b/core/jni/android_database_SQLiteDebug.cpp index 26e13cf10e71..4e4c36cbb7e1 100644 --- a/core/jni/android_database_SQLiteDebug.cpp +++ b/core/jni/android_database_SQLiteDebug.cpp @@ -58,7 +58,7 @@ static void nativeGetPagerStats(JNIEnv *env, jobject clazz, jobject statsObj) * JNI registration. */ -static JNINativeMethod gMethods[] = +static const JNINativeMethod gMethods[] = { { "nativeGetPagerStats", "(Landroid/database/sqlite/SQLiteDebug$PagerStats;)V", (void*) nativeGetPagerStats }, diff --git a/core/jni/android_database_SQLiteGlobal.cpp b/core/jni/android_database_SQLiteGlobal.cpp index 0a1c9f75edec..03e2387f24bc 100644 --- a/core/jni/android_database_SQLiteGlobal.cpp +++ b/core/jni/android_database_SQLiteGlobal.cpp @@ -75,7 +75,7 @@ static jint nativeReleaseMemory(JNIEnv* env, jclass clazz) { return sqlite3_release_memory(SOFT_HEAP_LIMIT); } -static JNINativeMethod sMethods[] = +static const JNINativeMethod sMethods[] = { /* name, signature, funcPtr */ { "nativeReleaseMemory", "()I", (void*)nativeReleaseMemory }, diff --git a/core/jni/android_ddm_DdmHandleNativeHeap.cpp b/core/jni/android_ddm_DdmHandleNativeHeap.cpp index ae96936ecba5..3e7a04efc536 100644 --- a/core/jni/android_ddm_DdmHandleNativeHeap.cpp +++ b/core/jni/android_ddm_DdmHandleNativeHeap.cpp @@ -105,7 +105,7 @@ static jbyteArray DdmHandleNativeHeap_getLeakInfo(JNIEnv* env, jobject) { return array; } -static JNINativeMethod method_table[] = { +static const JNINativeMethod method_table[] = { { "getLeakInfo", "()[B", (void*) DdmHandleNativeHeap_getLeakInfo }, }; diff --git a/core/jni/android_graphics_Canvas.cpp b/core/jni/android_graphics_Canvas.cpp index 5ddf2350d278..32a877ae3398 100644 --- a/core/jni/android_graphics_Canvas.cpp +++ b/core/jni/android_graphics_Canvas.cpp @@ -746,7 +746,7 @@ static void freeTextLayoutCaches(JNIEnv* env, jobject) { }; // namespace CanvasJNI -static JNINativeMethod gMethods[] = { +static const JNINativeMethod gMethods[] = { {"finalizer", "(J)V", (void*) CanvasJNI::finalizer}, {"initRaster", "(Landroid/graphics/Bitmap;)J", (void*) CanvasJNI::initRaster}, {"native_setBitmap", "(JLandroid/graphics/Bitmap;)V", (void*) CanvasJNI::setBitmap}, diff --git a/core/jni/android_graphics_Picture.cpp b/core/jni/android_graphics_Picture.cpp index fd42ddb9226e..03fcdef8fbfe 100644 --- a/core/jni/android_graphics_Picture.cpp +++ b/core/jni/android_graphics_Picture.cpp @@ -91,7 +91,7 @@ static void android_graphics_Picture_endRecording(JNIEnv* env, jobject, jlong pi pict->endRecording(); } -static JNINativeMethod gMethods[] = { +static const JNINativeMethod gMethods[] = { {"nativeGetWidth", "(J)I", (void*) android_graphics_Picture_getWidth}, {"nativeGetHeight", "(J)I", (void*) android_graphics_Picture_getHeight}, {"nativeConstructor", "(J)J", (void*) android_graphics_Picture_newPicture}, diff --git a/core/jni/android_hardware_Camera.cpp b/core/jni/android_hardware_Camera.cpp index 4f44c262f261..414eba79f22d 100644 --- a/core/jni/android_hardware_Camera.cpp +++ b/core/jni/android_hardware_Camera.cpp @@ -949,7 +949,7 @@ static void android_hardware_Camera_enableFocusMoveCallback(JNIEnv *env, jobject //------------------------------------------------- -static JNINativeMethod camMethods[] = { +static const JNINativeMethod camMethods[] = { { "getNumberOfCameras", "()I", (void *)android_hardware_Camera_getNumberOfCameras }, diff --git a/core/jni/android_hardware_SensorManager.cpp b/core/jni/android_hardware_SensorManager.cpp index 7d0afdcdd109..2e5cda069538 100644 --- a/core/jni/android_hardware_SensorManager.cpp +++ b/core/jni/android_hardware_SensorManager.cpp @@ -343,7 +343,7 @@ static jint nativeInjectSensorData(JNIEnv *env, jclass clazz, jlong eventQ, jint } //---------------------------------------------------------------------------- -static JNINativeMethod gSystemSensorManagerMethods[] = { +static const JNINativeMethod gSystemSensorManagerMethods[] = { {"nativeClassInit", "()V", (void*)nativeClassInit }, @@ -360,7 +360,7 @@ static JNINativeMethod gSystemSensorManagerMethods[] = { (void*)nativeIsDataInjectionEnabled}, }; -static JNINativeMethod gBaseEventQueueMethods[] = { +static const JNINativeMethod gBaseEventQueueMethods[] = { {"nativeInitBaseEventQueue", "(JLjava/lang/ref/WeakReference;Landroid/os/MessageQueue;[FLjava/lang/String;ILjava/lang/String;)J", (void*)nativeInitSensorEventQueue }, diff --git a/core/jni/android_hardware_SerialPort.cpp b/core/jni/android_hardware_SerialPort.cpp index 2d2ff4d97cb9..393dc7b9f4fd 100644 --- a/core/jni/android_hardware_SerialPort.cpp +++ b/core/jni/android_hardware_SerialPort.cpp @@ -243,7 +243,7 @@ android_hardware_SerialPort_send_break(JNIEnv *env, jobject thiz) tcsendbreak(fd, 0); } -static JNINativeMethod method_table[] = { +static const JNINativeMethod method_table[] = { {"native_open", "(Ljava/io/FileDescriptor;I)V", (void *)android_hardware_SerialPort_open}, {"native_close", "()V", (void *)android_hardware_SerialPort_close}, diff --git a/core/jni/android_hardware_SoundTrigger.cpp b/core/jni/android_hardware_SoundTrigger.cpp index 1c4c9ecc8a09..048b3c71c2c3 100644 --- a/core/jni/android_hardware_SoundTrigger.cpp +++ b/core/jni/android_hardware_SoundTrigger.cpp @@ -768,14 +768,14 @@ android_hardware_SoundTrigger_stopRecognition(JNIEnv *env, jobject thiz, return status; } -static JNINativeMethod gMethods[] = { +static const JNINativeMethod gMethods[] = { {"listModules", "(Ljava/util/ArrayList;)I", (void *)android_hardware_SoundTrigger_listModules}, }; -static JNINativeMethod gModuleMethods[] = { +static const JNINativeMethod gModuleMethods[] = { {"native_setup", "(Ljava/lang/Object;)V", (void *)android_hardware_SoundTrigger_setup}, diff --git a/core/jni/android_hardware_UsbDevice.cpp b/core/jni/android_hardware_UsbDevice.cpp index ef3b6463cd97..89d33e2ace1c 100644 --- a/core/jni/android_hardware_UsbDevice.cpp +++ b/core/jni/android_hardware_UsbDevice.cpp @@ -44,7 +44,7 @@ android_hardware_UsbDevice_get_device_name(JNIEnv *env, jobject clazz, jint id) return result; } -static JNINativeMethod method_table[] = { +static const JNINativeMethod method_table[] = { // static methods { "native_get_device_id", "(Ljava/lang/String;)I", (void*)android_hardware_UsbDevice_get_device_id }, diff --git a/core/jni/android_hardware_UsbDeviceConnection.cpp b/core/jni/android_hardware_UsbDeviceConnection.cpp index e0cae6f3136f..1ba9fc58800c 100644 --- a/core/jni/android_hardware_UsbDeviceConnection.cpp +++ b/core/jni/android_hardware_UsbDeviceConnection.cpp @@ -246,7 +246,7 @@ android_hardware_UsbDeviceConnection_get_serial(JNIEnv *env, jobject thiz) return result; } -static JNINativeMethod method_table[] = { +static const JNINativeMethod method_table[] = { {"native_open", "(Ljava/lang/String;Ljava/io/FileDescriptor;)Z", (void *)android_hardware_UsbDeviceConnection_open}, {"native_close", "()V", (void *)android_hardware_UsbDeviceConnection_close}, diff --git a/core/jni/android_hardware_UsbRequest.cpp b/core/jni/android_hardware_UsbRequest.cpp index ce99e15bffc0..399e7b16f073 100644 --- a/core/jni/android_hardware_UsbRequest.cpp +++ b/core/jni/android_hardware_UsbRequest.cpp @@ -190,7 +190,7 @@ android_hardware_UsbRequest_cancel(JNIEnv *env, jobject thiz) return (usb_request_cancel(request) == 0); } -static JNINativeMethod method_table[] = { +static const JNINativeMethod method_table[] = { {"native_init", "(Landroid/hardware/usb/UsbDeviceConnection;IIII)Z", (void *)android_hardware_UsbRequest_init}, {"native_close", "()V", (void *)android_hardware_UsbRequest_close}, diff --git a/core/jni/android_hardware_camera2_CameraMetadata.cpp b/core/jni/android_hardware_camera2_CameraMetadata.cpp index fb2268911be3..793002734111 100644 --- a/core/jni/android_hardware_camera2_CameraMetadata.cpp +++ b/core/jni/android_hardware_camera2_CameraMetadata.cpp @@ -529,7 +529,7 @@ static void CameraMetadata_writeToParcel(JNIEnv *env, jobject thiz, jobject parc //------------------------------------------------- -static JNINativeMethod gCameraMetadataMethods[] = { +static const JNINativeMethod gCameraMetadataMethods[] = { // static methods { "nativeClassInit", "()V", diff --git a/core/jni/android_hardware_camera2_DngCreator.cpp b/core/jni/android_hardware_camera2_DngCreator.cpp index 8b69bbd084b5..738a62ad5772 100644 --- a/core/jni/android_hardware_camera2_DngCreator.cpp +++ b/core/jni/android_hardware_camera2_DngCreator.cpp @@ -2280,7 +2280,7 @@ static void DngCreator_nativeWriteInputStream(JNIEnv* env, jobject thiz, jobject } /*extern "C" */ -static JNINativeMethod gDngCreatorMethods[] = { +static const JNINativeMethod gDngCreatorMethods[] = { {"nativeClassInit", "()V", (void*) DngCreator_nativeClassInit}, {"nativeInit", "(Landroid/hardware/camera2/impl/CameraMetadataNative;" "Landroid/hardware/camera2/impl/CameraMetadataNative;Ljava/lang/String;)V", diff --git a/core/jni/android_hardware_camera2_legacy_LegacyCameraDevice.cpp b/core/jni/android_hardware_camera2_legacy_LegacyCameraDevice.cpp index 63915ed1c134..f1ea7ec7e8a2 100644 --- a/core/jni/android_hardware_camera2_legacy_LegacyCameraDevice.cpp +++ b/core/jni/android_hardware_camera2_legacy_LegacyCameraDevice.cpp @@ -730,7 +730,7 @@ static jint LegacyCameraDevice_nativeGetJpegFooterSize(JNIEnv* env, jobject thiz } // extern "C" -static JNINativeMethod gCameraDeviceMethods[] = { +static const JNINativeMethod gCameraDeviceMethods[] = { { "nativeDetectSurfaceType", "(Landroid/view/Surface;)I", (void *)LegacyCameraDevice_nativeDetectSurfaceType }, diff --git a/core/jni/android_hardware_camera2_legacy_PerfMeasurement.cpp b/core/jni/android_hardware_camera2_legacy_PerfMeasurement.cpp index 7257597ca6cf..f0420585bfa4 100644 --- a/core/jni/android_hardware_camera2_legacy_PerfMeasurement.cpp +++ b/core/jni/android_hardware_camera2_legacy_PerfMeasurement.cpp @@ -302,7 +302,7 @@ static jlong PerfMeasurement_nativeGetNextGlDuration(JNIEnv* env, } // extern "C" -static JNINativeMethod gPerfMeasurementMethods[] = { +static const JNINativeMethod gPerfMeasurementMethods[] = { { "nativeCreateContext", "(I)J", (jlong *)PerfMeasurement_nativeCreateContext }, diff --git a/core/jni/android_hardware_location_ActivityRecognitionHardware.cpp b/core/jni/android_hardware_location_ActivityRecognitionHardware.cpp index 470c5ba8e2a3..4b279f63c99f 100644 --- a/core/jni/android_hardware_location_ActivityRecognitionHardware.cpp +++ b/core/jni/android_hardware_location_ActivityRecognitionHardware.cpp @@ -275,7 +275,7 @@ static int flush(JNIEnv* env, jobject obj) { } -static JNINativeMethod sMethods[] = { +static const JNINativeMethod sMethods[] = { // {"name", "signature", (void*) functionPointer }, { "nativeClassInit", "()V", (void*) class_init }, { "nativeInitialize", "()V", (void*) initialize }, diff --git a/core/jni/android_media_AudioRecord.cpp b/core/jni/android_media_AudioRecord.cpp index 6c2bbd45ea51..b977e377f2f3 100644 --- a/core/jni/android_media_AudioRecord.cpp +++ b/core/jni/android_media_AudioRecord.cpp @@ -682,7 +682,7 @@ static void android_media_AudioRecord_disableDeviceCallback( // ---------------------------------------------------------------------------- // ---------------------------------------------------------------------------- -static JNINativeMethod gMethods[] = { +static const JNINativeMethod gMethods[] = { // name, signature, funcPtr {"native_start", "(II)I", (void *)android_media_AudioRecord_start}, {"native_stop", "()V", (void *)android_media_AudioRecord_stop}, diff --git a/core/jni/android_media_AudioSystem.cpp b/core/jni/android_media_AudioSystem.cpp index 91b3278c2e2b..6d3c7d7363c6 100644 --- a/core/jni/android_media_AudioSystem.cpp +++ b/core/jni/android_media_AudioSystem.cpp @@ -1616,7 +1616,7 @@ android_media_AudioSystem_systemReady(JNIEnv *env, jobject thiz) // ---------------------------------------------------------------------------- -static JNINativeMethod gMethods[] = { +static const JNINativeMethod gMethods[] = { {"setParameters", "(Ljava/lang/String;)I", (void *)android_media_AudioSystem_setParameters}, {"getParameters", "(Ljava/lang/String;)Ljava/lang/String;", (void *)android_media_AudioSystem_getParameters}, {"muteMicrophone", "(Z)I", (void *)android_media_AudioSystem_muteMicrophone}, @@ -1663,7 +1663,7 @@ static JNINativeMethod gMethods[] = { }; -static JNINativeMethod gEventHandlerMethods[] = { +static const JNINativeMethod gEventHandlerMethods[] = { {"native_setup", "(Ljava/lang/Object;)V", (void *)android_media_AudioSystem_eventHandlerSetup}, diff --git a/core/jni/android_media_AudioTrack.cpp b/core/jni/android_media_AudioTrack.cpp index 5faa15008359..7860b74cc804 100644 --- a/core/jni/android_media_AudioTrack.cpp +++ b/core/jni/android_media_AudioTrack.cpp @@ -1052,7 +1052,7 @@ static void android_media_AudioTrack_disableDeviceCallback( // ---------------------------------------------------------------------------- // ---------------------------------------------------------------------------- -static JNINativeMethod gMethods[] = { +static const JNINativeMethod gMethods[] = { // name, signature, funcPtr {"native_start", "()V", (void *)android_media_AudioTrack_start}, {"native_stop", "()V", (void *)android_media_AudioTrack_stop}, diff --git a/core/jni/android_media_JetPlayer.cpp b/core/jni/android_media_JetPlayer.cpp index d441f1015dfc..873c3f2e07e1 100644 --- a/core/jni/android_media_JetPlayer.cpp +++ b/core/jni/android_media_JetPlayer.cpp @@ -488,7 +488,7 @@ android_media_JetPlayer_clearQueue(JNIEnv *env, jobject thiz) // ---------------------------------------------------------------------------- // ---------------------------------------------------------------------------- -static JNINativeMethod gMethods[] = { +static const JNINativeMethod gMethods[] = { // name, signature, funcPtr {"native_setup", "(Ljava/lang/Object;II)Z", (void *)android_media_JetPlayer_setup}, {"native_finalize", "()V", (void *)android_media_JetPlayer_finalize}, diff --git a/core/jni/android_media_RemoteDisplay.cpp b/core/jni/android_media_RemoteDisplay.cpp index 9bc223b57a42..bd1a6ecaf95c 100644 --- a/core/jni/android_media_RemoteDisplay.cpp +++ b/core/jni/android_media_RemoteDisplay.cpp @@ -177,7 +177,7 @@ static void nativeDispose(JNIEnv* env, jobject remoteDisplayObj, jlong ptr) { // ---------------------------------------------------------------------------- -static JNINativeMethod gMethods[] = { +static const JNINativeMethod gMethods[] = { {"nativeListen", "(Ljava/lang/String;Ljava/lang/String;)J", (void*)nativeListen }, {"nativeDispose", "(J)V", diff --git a/core/jni/android_media_ToneGenerator.cpp b/core/jni/android_media_ToneGenerator.cpp index 243f0400775e..aec62631c559 100644 --- a/core/jni/android_media_ToneGenerator.cpp +++ b/core/jni/android_media_ToneGenerator.cpp @@ -123,7 +123,7 @@ static void android_media_ToneGenerator_native_finalize(JNIEnv *env, // ---------------------------------------------------------------------------- -static JNINativeMethod gMethods[] = { +static const JNINativeMethod gMethods[] = { { "startTone", "(II)Z", (void *)android_media_ToneGenerator_startTone }, { "stopTone", "()V", (void *)android_media_ToneGenerator_stopTone }, { "getAudioSessionId", "()I", (void *)android_media_ToneGenerator_getAudioSessionId}, diff --git a/core/jni/android_net_LocalSocketImpl.cpp b/core/jni/android_net_LocalSocketImpl.cpp index c137b17426e0..d6d431019a6d 100644 --- a/core/jni/android_net_LocalSocketImpl.cpp +++ b/core/jni/android_net_LocalSocketImpl.cpp @@ -495,7 +495,7 @@ static jobject socket_get_peer_credentials(JNIEnv *env, /* * JNI registration. */ -static JNINativeMethod gMethods[] = { +static const JNINativeMethod gMethods[] = { /* name, signature, funcPtr */ {"connectLocal", "(Ljava/io/FileDescriptor;Ljava/lang/String;I)V", (void*)socket_connect_local}, diff --git a/core/jni/android_net_NetUtils.cpp b/core/jni/android_net_NetUtils.cpp index fada7ac21b1d..ba0876d74b17 100644 --- a/core/jni/android_net_NetUtils.cpp +++ b/core/jni/android_net_NetUtils.cpp @@ -302,7 +302,7 @@ static jboolean android_net_utils_queryUserAccess(JNIEnv *env, jobject thiz, jin /* * JNI registration. */ -static JNINativeMethod gNetworkUtilMethods[] = { +static const JNINativeMethod gNetworkUtilMethods[] = { /* name, signature, funcPtr */ { "resetConnections", "(Ljava/lang/String;I)I", (void *)android_net_utils_resetConnections }, { "startDhcp", "(Ljava/lang/String;)Z", (void *)android_net_utils_startDhcp }, diff --git a/core/jni/android_net_TrafficStats.cpp b/core/jni/android_net_TrafficStats.cpp index 735441743516..7b7d0cf498c3 100644 --- a/core/jni/android_net_TrafficStats.cpp +++ b/core/jni/android_net_TrafficStats.cpp @@ -185,7 +185,7 @@ static jlong getUidStat(JNIEnv* env, jclass clazz, jint uid, jint type) { } } -static JNINativeMethod gMethods[] = { +static const JNINativeMethod gMethods[] = { {"nativeGetTotalStat", "(I)J", (void*) getTotalStat}, {"nativeGetIfaceStat", "(Ljava/lang/String;I)J", (void*) getIfaceStat}, {"nativeGetUidStat", "(II)J", (void*) getUidStat}, diff --git a/core/jni/android_opengl_EGL14.cpp b/core/jni/android_opengl_EGL14.cpp index 9f5b3bc3f5b2..568473c14dc5 100644 --- a/core/jni/android_opengl_EGL14.cpp +++ b/core/jni/android_opengl_EGL14.cpp @@ -1231,7 +1231,7 @@ android_eglCopyBuffers static const char *classPathName = "android/opengl/EGL14"; -static JNINativeMethod methods[] = { +static const JNINativeMethod methods[] = { {"_nativeClassInit", "()V", (void*)nativeClassInit }, {"eglGetError", "()I", (void *) android_eglGetError }, {"eglGetDisplay", "(I)Landroid/opengl/EGLDisplay;", (void *) android_eglGetDisplayInt }, diff --git a/core/jni/android_opengl_EGLExt.cpp b/core/jni/android_opengl_EGLExt.cpp index 60a3bf642915..62ccad4d85f0 100644 --- a/core/jni/android_opengl_EGLExt.cpp +++ b/core/jni/android_opengl_EGLExt.cpp @@ -149,7 +149,7 @@ android_eglPresentationTimeANDROID static const char *classPathName = "android/opengl/EGLExt"; -static JNINativeMethod methods[] = { +static const JNINativeMethod methods[] = { {"_nativeClassInit", "()V", (void*)nativeClassInit }, {"eglPresentationTimeANDROID", "(Landroid/opengl/EGLDisplay;Landroid/opengl/EGLSurface;J)Z", (void *) android_eglPresentationTimeANDROID }, }; diff --git a/core/jni/android_opengl_GLES10.cpp b/core/jni/android_opengl_GLES10.cpp index dac98defbc79..f4135c213e36 100644 --- a/core/jni/android_opengl_GLES10.cpp +++ b/core/jni/android_opengl_GLES10.cpp @@ -3184,7 +3184,7 @@ android_glViewport__IIII static const char *classPathName = "android/opengl/GLES10"; -static JNINativeMethod methods[] = { +static const JNINativeMethod methods[] = { {"_nativeClassInit", "()V", (void*)nativeClassInit }, {"glActiveTexture", "(I)V", (void *) android_glActiveTexture__I }, {"glAlphaFunc", "(IF)V", (void *) android_glAlphaFunc__IF }, diff --git a/core/jni/android_opengl_GLES10Ext.cpp b/core/jni/android_opengl_GLES10Ext.cpp index 95be11bde598..4dc42339b6e5 100644 --- a/core/jni/android_opengl_GLES10Ext.cpp +++ b/core/jni/android_opengl_GLES10Ext.cpp @@ -582,7 +582,7 @@ exit: static const char *classPathName = "android/opengl/GLES10Ext"; -static JNINativeMethod methods[] = { +static const JNINativeMethod methods[] = { {"_nativeClassInit", "()V", (void*)nativeClassInit }, {"glQueryMatrixxOES", "([II[II)I", (void *) android_glQueryMatrixxOES___3II_3II }, {"glQueryMatrixxOES", "(Ljava/nio/IntBuffer;Ljava/nio/IntBuffer;)I", (void *) android_glQueryMatrixxOES__Ljava_nio_IntBuffer_2Ljava_nio_IntBuffer_2 }, diff --git a/core/jni/android_opengl_GLES11.cpp b/core/jni/android_opengl_GLES11.cpp index 6970a3c7e180..2625e03c962e 100644 --- a/core/jni/android_opengl_GLES11.cpp +++ b/core/jni/android_opengl_GLES11.cpp @@ -3065,7 +3065,7 @@ android_glVertexPointer__IIII static const char *classPathName = "android/opengl/GLES11"; -static JNINativeMethod methods[] = { +static const JNINativeMethod methods[] = { {"_nativeClassInit", "()V", (void*)nativeClassInit }, {"glBindBuffer", "(II)V", (void *) android_glBindBuffer__II }, {"glBufferData", "(IILjava/nio/Buffer;I)V", (void *) android_glBufferData__IILjava_nio_Buffer_2I }, diff --git a/core/jni/android_opengl_GLES11Ext.cpp b/core/jni/android_opengl_GLES11Ext.cpp index 6422ff28e190..fb85cb0f8d95 100644 --- a/core/jni/android_opengl_GLES11Ext.cpp +++ b/core/jni/android_opengl_GLES11Ext.cpp @@ -3573,7 +3573,7 @@ android_glGetTexGenxvOES__IILjava_nio_IntBuffer_2 static const char *classPathName = "android/opengl/GLES11Ext"; -static JNINativeMethod methods[] = { +static const JNINativeMethod methods[] = { {"_nativeClassInit", "()V", (void*)nativeClassInit }, {"glBlendEquationSeparateOES", "(II)V", (void *) android_glBlendEquationSeparateOES__II }, {"glBlendFuncSeparateOES", "(IIII)V", (void *) android_glBlendFuncSeparateOES__IIII }, diff --git a/core/jni/android_opengl_GLES20.cpp b/core/jni/android_opengl_GLES20.cpp index f9a0dfeb444c..b9f61a91ec90 100644 --- a/core/jni/android_opengl_GLES20.cpp +++ b/core/jni/android_opengl_GLES20.cpp @@ -6152,7 +6152,7 @@ android_glViewport__IIII static const char *classPathName = "android/opengl/GLES20"; -static JNINativeMethod methods[] = { +static const JNINativeMethod methods[] = { {"_nativeClassInit", "()V", (void*)nativeClassInit }, {"glActiveTexture", "(I)V", (void *) android_glActiveTexture__I }, {"glAttachShader", "(II)V", (void *) android_glAttachShader__II }, diff --git a/core/jni/android_opengl_GLES30.cpp b/core/jni/android_opengl_GLES30.cpp index 1d92cd46527a..8eb50444762c 100644 --- a/core/jni/android_opengl_GLES30.cpp +++ b/core/jni/android_opengl_GLES30.cpp @@ -5167,7 +5167,7 @@ android_glGetInternalformativ__IIIILjava_nio_IntBuffer_2 static const char *classPathName = "android/opengl/GLES30"; -static JNINativeMethod methods[] = { +static const JNINativeMethod methods[] = { {"_nativeClassInit", "()V", (void*)nativeClassInit }, {"glReadBuffer", "(I)V", (void *) android_glReadBuffer__I }, {"glDrawRangeElements", "(IIIIILjava/nio/Buffer;)V", (void *) android_glDrawRangeElements__IIIIILjava_nio_Buffer_2 }, diff --git a/core/jni/android_opengl_GLES31.cpp b/core/jni/android_opengl_GLES31.cpp index 92ecbe0b99df..e427388a10e9 100644 --- a/core/jni/android_opengl_GLES31.cpp +++ b/core/jni/android_opengl_GLES31.cpp @@ -3175,7 +3175,7 @@ android_glVertexBindingDivisor__II static const char *classPathName = "android/opengl/GLES31"; -static JNINativeMethod methods[] = { +static const JNINativeMethod methods[] = { {"_nativeClassInit", "()V", (void*)nativeClassInit }, {"glDispatchCompute", "(III)V", (void *) android_glDispatchCompute__III }, {"glDispatchComputeIndirect", "(J)V", (void *) android_glDispatchComputeIndirect }, diff --git a/core/jni/android_opengl_GLES31Ext.cpp b/core/jni/android_opengl_GLES31Ext.cpp index 28563089e85a..180c69348853 100644 --- a/core/jni/android_opengl_GLES31Ext.cpp +++ b/core/jni/android_opengl_GLES31Ext.cpp @@ -1443,7 +1443,7 @@ android_glTexBufferRangeEXT__IIIII static const char *classPathName = "android/opengl/GLES31Ext"; -static JNINativeMethod methods[] = { +static const JNINativeMethod methods[] = { {"_nativeClassInit", "()V", (void*)nativeClassInit }, {"glBlendBarrierKHR", "()V", (void *) android_glBlendBarrierKHR__ }, {"glDebugMessageControlKHR", "(IIII[IIZ)V", (void *) android_glDebugMessageControlKHR__IIII_3IIZ }, diff --git a/core/jni/android_os_Debug.cpp b/core/jni/android_os_Debug.cpp index b969477bf258..097bbac84e3f 100644 --- a/core/jni/android_os_Debug.cpp +++ b/core/jni/android_os_Debug.cpp @@ -973,7 +973,7 @@ static void android_os_Debug_dumpNativeBacktraceToFile(JNIEnv* env, jobject claz * JNI registration. */ -static JNINativeMethod gMethods[] = { +static const JNINativeMethod gMethods[] = { { "getNativeHeapSize", "()J", (void*) android_os_Debug_getNativeHeapSize }, { "getNativeHeapAllocatedSize", "()J", diff --git a/core/jni/android_os_MessageQueue.cpp b/core/jni/android_os_MessageQueue.cpp index d2db3c9ab5b3..e57a7190cfce 100644 --- a/core/jni/android_os_MessageQueue.cpp +++ b/core/jni/android_os_MessageQueue.cpp @@ -209,7 +209,7 @@ static void android_os_MessageQueue_nativeSetFileDescriptorEvents(JNIEnv* env, j // ---------------------------------------------------------------------------- -static JNINativeMethod gMessageQueueMethods[] = { +static const JNINativeMethod gMessageQueueMethods[] = { /* name, signature, funcPtr */ { "nativeInit", "()J", (void*)android_os_MessageQueue_nativeInit }, { "nativeDestroy", "(J)V", (void*)android_os_MessageQueue_nativeDestroy }, diff --git a/core/jni/android_os_SELinux.cpp b/core/jni/android_os_SELinux.cpp index 762b88f5dbee..8ba77aed1d04 100644 --- a/core/jni/android_os_SELinux.cpp +++ b/core/jni/android_os_SELinux.cpp @@ -320,7 +320,7 @@ static jboolean native_restorecon(JNIEnv *env, jobject, jstring pathnameStr, jin /* * JNI registration. */ -static JNINativeMethod method_table[] = { +static const JNINativeMethod method_table[] = { /* name, signature, funcPtr */ { "checkSELinuxAccess" , "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)Z" , (void*)checkSELinuxAccess }, { "getContext" , "()Ljava/lang/String;" , (void*)getCon }, diff --git a/core/jni/android_os_SystemClock.cpp b/core/jni/android_os_SystemClock.cpp index dfe024e8a473..d98407deb7e7 100644 --- a/core/jni/android_os_SystemClock.cpp +++ b/core/jni/android_os_SystemClock.cpp @@ -104,7 +104,7 @@ static jlong android_os_SystemClock_elapsedRealtimeNano(JNIEnv* env, /* * JNI registration. */ -static JNINativeMethod gMethods[] = { +static const JNINativeMethod gMethods[] = { /* name, signature, funcPtr */ { "uptimeMillis", "()J", (void*) android_os_SystemClock_uptimeMillis }, diff --git a/core/jni/android_os_SystemProperties.cpp b/core/jni/android_os_SystemProperties.cpp index 554d304290cf..5dace6b7e536 100644 --- a/core/jni/android_os_SystemProperties.cpp +++ b/core/jni/android_os_SystemProperties.cpp @@ -220,7 +220,7 @@ static void SystemProperties_add_change_callback(JNIEnv *env, jobject clazz) } } -static JNINativeMethod method_table[] = { +static const JNINativeMethod method_table[] = { { "native_get", "(Ljava/lang/String;)Ljava/lang/String;", (void*) SystemProperties_getS }, { "native_get", "(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;", diff --git a/core/jni/android_os_Trace.cpp b/core/jni/android_os_Trace.cpp index 3fd3b3c9ae15..30fc47bba751 100644 --- a/core/jni/android_os_Trace.cpp +++ b/core/jni/android_os_Trace.cpp @@ -105,7 +105,7 @@ static void android_os_Trace_nativeSetTracingEnabled(JNIEnv* env, atrace_set_tracing_enabled(enabled); } -static JNINativeMethod gTraceMethods[] = { +static const JNINativeMethod gTraceMethods[] = { /* name, signature, funcPtr */ { "nativeGetEnabledTags", "()J", diff --git a/core/jni/android_os_UEventObserver.cpp b/core/jni/android_os_UEventObserver.cpp index eb36f8549cfa..30d40a2a08ad 100644 --- a/core/jni/android_os_UEventObserver.cpp +++ b/core/jni/android_os_UEventObserver.cpp @@ -103,7 +103,7 @@ static void nativeRemoveMatch(JNIEnv* env, jclass clazz, jstring matchStr) { } } -static JNINativeMethod gMethods[] = { +static const JNINativeMethod gMethods[] = { { "nativeSetup", "()V", (void *)nativeSetup }, { "nativeWaitForNextEvent", "()Ljava/lang/String;", diff --git a/core/jni/android_server_NetworkManagementSocketTagger.cpp b/core/jni/android_server_NetworkManagementSocketTagger.cpp index ca21fd716a5f..818bf53d97a4 100644 --- a/core/jni/android_server_NetworkManagementSocketTagger.cpp +++ b/core/jni/android_server_NetworkManagementSocketTagger.cpp @@ -83,7 +83,7 @@ static jint QTagUid_deleteTagData(JNIEnv* env, jclass, return (jint)res; } -static JNINativeMethod gQTagUidMethods[] = { +static const JNINativeMethod gQTagUidMethods[] = { { "native_tagSocketFd", "(Ljava/io/FileDescriptor;II)I", (void*)QTagUid_tagSocketFd}, { "native_untagSocketFd", "(Ljava/io/FileDescriptor;)I", (void*)QTagUid_untagSocketFd}, { "native_setCounterSet", "(II)I", (void*)QTagUid_setCounterSet}, diff --git a/core/jni/android_text_AndroidBidi.cpp b/core/jni/android_text_AndroidBidi.cpp index 328542954efa..2a3f0361a9cd 100644 --- a/core/jni/android_text_AndroidBidi.cpp +++ b/core/jni/android_text_AndroidBidi.cpp @@ -56,7 +56,7 @@ static jint runBidi(JNIEnv* env, jobject obj, jint dir, jcharArray chsArray, return result; } -static JNINativeMethod gMethods[] = { +static const JNINativeMethod gMethods[] = { { "runBidi", "(I[C[BIZ)I", (void*) runBidi } }; diff --git a/core/jni/android_text_AndroidCharacter.cpp b/core/jni/android_text_AndroidCharacter.cpp index 9258248083d0..474a74e8776c 100644 --- a/core/jni/android_text_AndroidCharacter.cpp +++ b/core/jni/android_text_AndroidCharacter.cpp @@ -178,7 +178,7 @@ static jchar getMirror(JNIEnv* env, jobject obj, jchar c) return u_charMirror(c); } -static JNINativeMethod gMethods[] = { +static const JNINativeMethod gMethods[] = { { "getDirectionalities", "([C[BI)V", (void*) getDirectionalities }, { "getEastAsianWidth", "(C)I", diff --git a/core/jni/android_text_StaticLayout.cpp b/core/jni/android_text_StaticLayout.cpp index 90e4bb64133e..a151e004922d 100644 --- a/core/jni/android_text_StaticLayout.cpp +++ b/core/jni/android_text_StaticLayout.cpp @@ -172,7 +172,7 @@ static void nGetWidths(JNIEnv* env, jclass, jlong nativePtr, jfloatArray widths) env->SetFloatArrayRegion(widths, 0, b->size(), b->charWidths()); } -static JNINativeMethod gMethods[] = { +static const JNINativeMethod gMethods[] = { // TODO performance: many of these are candidates for fast jni, awaiting guidance {"nNewBuilder", "()J", (void*) nNewBuilder}, {"nFreeBuilder", "(J)V", (void*) nFreeBuilder}, diff --git a/core/jni/android_util_AssetManager.cpp b/core/jni/android_util_AssetManager.cpp index 7ca0654f9656..614e82f803ff 100644 --- a/core/jni/android_util_AssetManager.cpp +++ b/core/jni/android_util_AssetManager.cpp @@ -2112,7 +2112,7 @@ static jint android_content_AssetManager_getGlobalAssetManagerCount(JNIEnv* env, /* * JNI registration. */ -static JNINativeMethod gAssetManagerMethods[] = { +static const JNINativeMethod gAssetManagerMethods[] = { /* name, signature, funcPtr */ // Basic asset stuff. diff --git a/core/jni/android_util_EventLog.cpp b/core/jni/android_util_EventLog.cpp index 05bc12563b6c..4f8a2cb91506 100644 --- a/core/jni/android_util_EventLog.cpp +++ b/core/jni/android_util_EventLog.cpp @@ -249,7 +249,7 @@ static void android_util_EventLog_readEvents(JNIEnv* env, jobject clazz UNUSED, /* * JNI registration. */ -static JNINativeMethod gRegisterMethods[] = { +static const JNINativeMethod gRegisterMethods[] = { /* name, signature, funcPtr */ { "writeEvent", "(II)I", (void*) android_util_EventLog_writeEvent_Integer }, { "writeEvent", "(IJ)I", (void*) android_util_EventLog_writeEvent_Long }, diff --git a/core/jni/android_util_FileObserver.cpp b/core/jni/android_util_FileObserver.cpp index 067d298580bc..2b93b6d61905 100644 --- a/core/jni/android_util_FileObserver.cpp +++ b/core/jni/android_util_FileObserver.cpp @@ -127,7 +127,7 @@ static void android_os_fileobserver_stopWatching(JNIEnv* env, jobject object, ji #endif } -static JNINativeMethod sMethods[] = { +static const JNINativeMethod sMethods[] = { /* name, signature, funcPtr */ { "init", "()I", (void*)android_os_fileobserver_init }, { "observe", "(I)V", (void*)android_os_fileobserver_observe }, diff --git a/core/jni/android_util_Log.cpp b/core/jni/android_util_Log.cpp index 2b1067bede5d..2d23cda5ff15 100644 --- a/core/jni/android_util_Log.cpp +++ b/core/jni/android_util_Log.cpp @@ -111,7 +111,7 @@ static jint android_util_Log_println_native(JNIEnv* env, jobject clazz, /* * JNI registration. */ -static JNINativeMethod gMethods[] = { +static const JNINativeMethod gMethods[] = { /* name, signature, funcPtr */ { "isLoggable", "(Ljava/lang/String;I)Z", (void*) android_util_Log_isLoggable }, { "println_native", "(IILjava/lang/String;Ljava/lang/String;)I", (void*) android_util_Log_println_native }, diff --git a/core/jni/android_util_StringBlock.cpp b/core/jni/android_util_StringBlock.cpp index f83eaec409d5..b396afe62dff 100644 --- a/core/jni/android_util_StringBlock.cpp +++ b/core/jni/android_util_StringBlock.cpp @@ -155,7 +155,7 @@ static void android_content_StringBlock_nativeDestroy(JNIEnv* env, jobject clazz /* * JNI registration. */ -static JNINativeMethod gStringBlockMethods[] = { +static const JNINativeMethod gStringBlockMethods[] = { /* name, signature, funcPtr */ { "nativeCreate", "([BII)J", (void*) android_content_StringBlock_nativeCreate }, diff --git a/core/jni/android_util_XmlBlock.cpp b/core/jni/android_util_XmlBlock.cpp index 375710e6faca..7ae51c89fab7 100644 --- a/core/jni/android_util_XmlBlock.cpp +++ b/core/jni/android_util_XmlBlock.cpp @@ -364,7 +364,7 @@ static void android_content_XmlBlock_nativeDestroy(JNIEnv* env, jobject clazz, /* * JNI registration. */ -static JNINativeMethod gXmlBlockMethods[] = { +static const JNINativeMethod gXmlBlockMethods[] = { /* name, signature, funcPtr */ { "nativeCreate", "([BII)J", (void*) android_content_XmlBlock_nativeCreate }, diff --git a/core/jni/android_view_DisplayEventReceiver.cpp b/core/jni/android_view_DisplayEventReceiver.cpp index 0e2ec6b85209..437bd192b70a 100644 --- a/core/jni/android_view_DisplayEventReceiver.cpp +++ b/core/jni/android_view_DisplayEventReceiver.cpp @@ -259,7 +259,7 @@ static void nativeScheduleVsync(JNIEnv* env, jclass clazz, jlong receiverPtr) { } -static JNINativeMethod gMethods[] = { +static const JNINativeMethod gMethods[] = { /* name, signature, funcPtr */ { "nativeInit", "(Ljava/lang/ref/WeakReference;Landroid/os/MessageQueue;)J", diff --git a/core/jni/android_view_GraphicBuffer.cpp b/core/jni/android_view_GraphicBuffer.cpp index 17d2a5eddbf8..7682dd6ca8e3 100644 --- a/core/jni/android_view_GraphicBuffer.cpp +++ b/core/jni/android_view_GraphicBuffer.cpp @@ -268,7 +268,7 @@ sp<GraphicBuffer> graphicBufferForJavaObject(JNIEnv* env, jobject obj) { const char* const kClassPathName = "android/view/GraphicBuffer"; -static JNINativeMethod gMethods[] = { +static const JNINativeMethod gMethods[] = { { "nCreateGraphicBuffer", "(IIII)J", (void*) android_view_GraphiceBuffer_create }, { "nDestroyGraphicBuffer", "(J)V", (void*) android_view_GraphiceBuffer_destroy }, diff --git a/core/jni/android_view_HardwareLayer.cpp b/core/jni/android_view_HardwareLayer.cpp index 36ba892b51c4..3a0ddc9fa825 100644 --- a/core/jni/android_view_HardwareLayer.cpp +++ b/core/jni/android_view_HardwareLayer.cpp @@ -85,7 +85,7 @@ static void android_view_HardwareLayer_updateSurfaceTexture(JNIEnv* env, jobject const char* const kClassPathName = "android/view/HardwareLayer"; -static JNINativeMethod gMethods[] = { +static const JNINativeMethod gMethods[] = { { "nPrepare", "(JIIZ)Z", (void*) android_view_HardwareLayer_prepare }, { "nSetLayerPaint", "(JJ)V", (void*) android_view_HardwareLayer_setLayerPaint }, { "nSetTransform", "(JJ)V", (void*) android_view_HardwareLayer_setTransform }, diff --git a/core/jni/android_view_InputChannel.cpp b/core/jni/android_view_InputChannel.cpp index 4b42ab5d213a..092ac27176cc 100644 --- a/core/jni/android_view_InputChannel.cpp +++ b/core/jni/android_view_InputChannel.cpp @@ -259,7 +259,7 @@ static void android_view_InputChannel_nativeDup(JNIEnv* env, jobject obj, jobjec // ---------------------------------------------------------------------------- -static JNINativeMethod gInputChannelMethods[] = { +static const JNINativeMethod gInputChannelMethods[] = { /* name, signature, funcPtr */ { "nativeOpenInputChannelPair", "(Ljava/lang/String;)[Landroid/view/InputChannel;", (void*)android_view_InputChannel_nativeOpenInputChannelPair }, diff --git a/core/jni/android_view_InputEventReceiver.cpp b/core/jni/android_view_InputEventReceiver.cpp index 43b847108a20..8293cd8ff88d 100644 --- a/core/jni/android_view_InputEventReceiver.cpp +++ b/core/jni/android_view_InputEventReceiver.cpp @@ -395,7 +395,7 @@ static jboolean nativeConsumeBatchedInputEvents(JNIEnv* env, jclass clazz, jlong } -static JNINativeMethod gMethods[] = { +static const JNINativeMethod gMethods[] = { /* name, signature, funcPtr */ { "nativeInit", "(Ljava/lang/ref/WeakReference;Landroid/view/InputChannel;Landroid/os/MessageQueue;)J", diff --git a/core/jni/android_view_InputEventSender.cpp b/core/jni/android_view_InputEventSender.cpp index d61dee7a7673..3bd6917aedfa 100644 --- a/core/jni/android_view_InputEventSender.cpp +++ b/core/jni/android_view_InputEventSender.cpp @@ -289,7 +289,7 @@ static jboolean nativeSendMotionEvent(JNIEnv* env, jclass clazz, jlong senderPtr } -static JNINativeMethod gMethods[] = { +static const JNINativeMethod gMethods[] = { /* name, signature, funcPtr */ { "nativeInit", "(Ljava/lang/ref/WeakReference;Landroid/view/InputChannel;Landroid/os/MessageQueue;)J", diff --git a/core/jni/android_view_KeyCharacterMap.cpp b/core/jni/android_view_KeyCharacterMap.cpp index 7653f58778dd..e5519a752c39 100644 --- a/core/jni/android_view_KeyCharacterMap.cpp +++ b/core/jni/android_view_KeyCharacterMap.cpp @@ -203,7 +203,7 @@ static jobjectArray nativeGetEvents(JNIEnv *env, jobject clazz, jlong ptr, * JNI registration. */ -static JNINativeMethod g_methods[] = { +static const JNINativeMethod g_methods[] = { /* name, signature, funcPtr */ { "nativeReadFromParcel", "(Landroid/os/Parcel;)J", (void*)nativeReadFromParcel }, diff --git a/core/jni/android_view_MotionEvent.cpp b/core/jni/android_view_MotionEvent.cpp index 98c17c03b1a7..81d46c3d6988 100644 --- a/core/jni/android_view_MotionEvent.cpp +++ b/core/jni/android_view_MotionEvent.cpp @@ -752,7 +752,7 @@ static jint android_view_MotionEvent_nativeAxisFromString(JNIEnv* env, jclass cl // ---------------------------------------------------------------------------- -static JNINativeMethod gMotionEventMethods[] = { +static const JNINativeMethod gMotionEventMethods[] = { /* name, signature, funcPtr */ { "nativeInitialize", "(JIIIIIIIFFFFJJI[Landroid/view/MotionEvent$PointerProperties;" diff --git a/core/jni/android_view_RenderNode.cpp b/core/jni/android_view_RenderNode.cpp index a3b370017a8e..388d36541eb8 100644 --- a/core/jni/android_view_RenderNode.cpp +++ b/core/jni/android_view_RenderNode.cpp @@ -467,7 +467,7 @@ static void android_view_RenderNode_endAllAnimators(JNIEnv* env, jobject clazz, const char* const kClassPathName = "android/view/RenderNode"; -static JNINativeMethod gMethods[] = { +static const JNINativeMethod gMethods[] = { { "nCreate", "(Ljava/lang/String;)J", (void*) android_view_RenderNode_create }, { "nDestroyRenderNode", "(J)V", (void*) android_view_RenderNode_destroyRenderNode }, { "nSetDisplayListData", "(JJ)V", (void*) android_view_RenderNode_setDisplayListData }, diff --git a/core/jni/android_view_RenderNodeAnimator.cpp b/core/jni/android_view_RenderNodeAnimator.cpp index 4177ee2f7fe8..0926e9b76691 100644 --- a/core/jni/android_view_RenderNodeAnimator.cpp +++ b/core/jni/android_view_RenderNodeAnimator.cpp @@ -193,7 +193,7 @@ static void end(JNIEnv* env, jobject clazz, jlong animatorPtr) { const char* const kClassPathName = "android/view/RenderNodeAnimator"; -static JNINativeMethod gMethods[] = { +static const JNINativeMethod gMethods[] = { { "nCreateAnimator", "(IF)J", (void*) createAnimator }, { "nCreateCanvasPropertyFloatAnimator", "(JF)J", (void*) createCanvasPropertyFloatAnimator }, { "nCreateCanvasPropertyPaintAnimator", "(JIF)J", (void*) createCanvasPropertyPaintAnimator }, diff --git a/core/jni/android_view_Surface.cpp b/core/jni/android_view_Surface.cpp index 4a311d31bd82..24055e76234e 100644 --- a/core/jni/android_view_Surface.cpp +++ b/core/jni/android_view_Surface.cpp @@ -514,7 +514,7 @@ static void destroy(JNIEnv* env, jclass clazz, jlong rendererPtr) { namespace hwui = android::uirenderer; -static JNINativeMethod gSurfaceMethods[] = { +static const JNINativeMethod gSurfaceMethods[] = { {"nativeCreateFromSurfaceTexture", "(Landroid/graphics/SurfaceTexture;)J", (void*)nativeCreateFromSurfaceTexture }, {"nativeRelease", "(J)V", diff --git a/core/jni/android_view_SurfaceControl.cpp b/core/jni/android_view_SurfaceControl.cpp index d1acb59a6411..65ebb6633a8f 100644 --- a/core/jni/android_view_SurfaceControl.cpp +++ b/core/jni/android_view_SurfaceControl.cpp @@ -572,7 +572,7 @@ static jboolean nativeGetAnimationFrameStats(JNIEnv* env, jclass clazz, jobject // ---------------------------------------------------------------------------- -static JNINativeMethod sSurfaceControlMethods[] = { +static const JNINativeMethod sSurfaceControlMethods[] = { {"nativeCreate", "(Landroid/view/SurfaceSession;Ljava/lang/String;IIII)J", (void*)nativeCreate }, {"nativeRelease", "(J)V", diff --git a/core/jni/android_view_SurfaceSession.cpp b/core/jni/android_view_SurfaceSession.cpp index 609c565678f2..dad6958560c0 100644 --- a/core/jni/android_view_SurfaceSession.cpp +++ b/core/jni/android_view_SurfaceSession.cpp @@ -56,7 +56,7 @@ static void nativeKill(JNIEnv* env, jclass clazz, jlong ptr) { } -static JNINativeMethod gMethods[] = { +static const JNINativeMethod gMethods[] = { /* name, signature, funcPtr */ { "nativeCreate", "()J", (void*)nativeCreate }, diff --git a/core/jni/android_view_TextureView.cpp b/core/jni/android_view_TextureView.cpp index beb83b1e01fa..b736a17c1199 100644 --- a/core/jni/android_view_TextureView.cpp +++ b/core/jni/android_view_TextureView.cpp @@ -197,7 +197,7 @@ static void android_view_TextureView_unlockCanvasAndPost(JNIEnv* env, jobject, const char* const kClassPathName = "android/view/TextureView"; -static JNINativeMethod gMethods[] = { +static const JNINativeMethod gMethods[] = { { "nCreateNativeWindow", "(Landroid/graphics/SurfaceTexture;)V", (void*) android_view_TextureView_createNativeWindow }, { "nDestroyNativeWindow", "()V", diff --git a/core/jni/android_view_ThreadedRenderer.cpp b/core/jni/android_view_ThreadedRenderer.cpp index 6c3676b5ef05..c79f833b54a9 100644 --- a/core/jni/android_view_ThreadedRenderer.cpp +++ b/core/jni/android_view_ThreadedRenderer.cpp @@ -440,6 +440,32 @@ static void android_view_ThreadedRenderer_dumpProfileData(JNIEnv* env, jobject c } } +static void android_view_ThreadedRenderer_addRenderNode(JNIEnv* env, jobject clazz, + jlong proxyPtr, jlong renderNodePtr, jboolean placeFront) { + RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr); + RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr); + proxy->addRenderNode(renderNode, placeFront); +} + +static void android_view_ThreadedRenderer_removeRenderNode(JNIEnv* env, jobject clazz, + jlong proxyPtr, jlong renderNodePtr) { + RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr); + RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr); + proxy->removeRenderNode(renderNode); +} + +static void android_view_ThreadedRendererd_drawRenderNode(JNIEnv* env, jobject clazz, + jlong proxyPtr, jlong renderNodePtr) { + RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr); + RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr); + proxy->drawRenderNode(renderNode); +} + +static void android_view_ThreadedRenderer_setContentOverdrawProtectionBounds(JNIEnv* env, + jobject clazz, jlong proxyPtr, jint left, jint top, jint right, jint bottom) { + RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr); + proxy->setContentOverdrawProtectionBounds(left, top, right, bottom); +} // ---------------------------------------------------------------------------- // Shaders @@ -447,7 +473,6 @@ static void android_view_ThreadedRenderer_dumpProfileData(JNIEnv* env, jobject c static void android_view_ThreadedRenderer_setupShadersDiskCache(JNIEnv* env, jobject clazz, jstring diskCachePath) { - const char* cacheArray = env->GetStringUTFChars(diskCachePath, NULL); egl_cache_t::get()->setCacheFilename(cacheArray); env->ReleaseStringUTFChars(diskCachePath, cacheArray); @@ -459,7 +484,7 @@ static void android_view_ThreadedRenderer_setupShadersDiskCache(JNIEnv* env, job const char* const kClassPathName = "android/view/ThreadedRenderer"; -static JNINativeMethod gMethods[] = { +static const JNINativeMethod gMethods[] = { { "nSetAtlas", "(JLandroid/view/GraphicBuffer;[J)V", (void*) android_view_ThreadedRenderer_setAtlas }, { "nSetProcessStatsBuffer", "(JI)V", (void*) android_view_ThreadedRenderer_setProcessStatsBuffer }, { "nCreateRootRenderNode", "()J", (void*) android_view_ThreadedRenderer_createRootRenderNode }, @@ -494,6 +519,11 @@ static JNINativeMethod gMethods[] = { { "nDumpProfileData", "([BLjava/io/FileDescriptor;)V", (void*) android_view_ThreadedRenderer_dumpProfileData }, { "setupShadersDiskCache", "(Ljava/lang/String;)V", (void*) android_view_ThreadedRenderer_setupShadersDiskCache }, + { "nAddRenderNode", "(JJZ)V", (void*) android_view_ThreadedRenderer_addRenderNode}, + { "nRemoveRenderNode", "(JJ)V", (void*) android_view_ThreadedRenderer_removeRenderNode}, + { "nDrawRenderNode", "(JJ)V", (void*) android_view_ThreadedRendererd_drawRenderNode}, + { "nSetContentOverdrawProtectionBounds", "(JIIII)V", + (void*)android_view_ThreadedRenderer_setContentOverdrawProtectionBounds}, }; int register_android_view_ThreadedRenderer(JNIEnv* env) { diff --git a/core/jni/android_view_VelocityTracker.cpp b/core/jni/android_view_VelocityTracker.cpp index ddd5fc853d25..04ec7059365e 100644 --- a/core/jni/android_view_VelocityTracker.cpp +++ b/core/jni/android_view_VelocityTracker.cpp @@ -215,7 +215,7 @@ static jboolean android_view_VelocityTracker_nativeGetEstimator(JNIEnv* env, jcl // --- JNI Registration --- -static JNINativeMethod gVelocityTrackerMethods[] = { +static const JNINativeMethod gVelocityTrackerMethods[] = { /* name, signature, funcPtr */ { "nativeInitialize", "(Ljava/lang/String;)J", diff --git a/core/jni/com_android_internal_content_NativeLibraryHelper.cpp b/core/jni/com_android_internal_content_NativeLibraryHelper.cpp index daa6f82ea122..364ac44ee0f6 100644 --- a/core/jni/com_android_internal_content_NativeLibraryHelper.cpp +++ b/core/jni/com_android_internal_content_NativeLibraryHelper.cpp @@ -561,7 +561,7 @@ com_android_internal_content_NativeLibraryHelper_close(JNIEnv *env, jclass, jlon delete reinterpret_cast<ZipFileRO*>(apkHandle); } -static JNINativeMethod gMethods[] = { +static const JNINativeMethod gMethods[] = { {"nativeOpenApk", "(Ljava/lang/String;)J", (void *)com_android_internal_content_NativeLibraryHelper_openApk}, diff --git a/core/jni/com_android_internal_net_NetworkStatsFactory.cpp b/core/jni/com_android_internal_net_NetworkStatsFactory.cpp index 6c0b756591f7..70134ab04a2a 100644 --- a/core/jni/com_android_internal_net_NetworkStatsFactory.cpp +++ b/core/jni/com_android_internal_net_NetworkStatsFactory.cpp @@ -284,7 +284,7 @@ static int readNetworkStatsDetail(JNIEnv* env, jclass clazz, jobject stats, return 0; } -static JNINativeMethod gMethods[] = { +static const JNINativeMethod gMethods[] = { { "nativeReadNetworkStatsDetail", "(Landroid/net/NetworkStats;Ljava/lang/String;I[Ljava/lang/String;I)I", (void*) readNetworkStatsDetail } diff --git a/core/jni/com_android_internal_os_Zygote.cpp b/core/jni/com_android_internal_os_Zygote.cpp index aef70be4922a..3f1be456c199 100644 --- a/core/jni/com_android_internal_os_Zygote.cpp +++ b/core/jni/com_android_internal_os_Zygote.cpp @@ -647,7 +647,7 @@ static jint com_android_internal_os_Zygote_nativeForkSystemServer( return pid; } -static JNINativeMethod gMethods[] = { +static const JNINativeMethod gMethods[] = { { "nativeForkAndSpecialize", "(II[II[[IILjava/lang/String;Ljava/lang/String;[ILjava/lang/String;Ljava/lang/String;)I", (void *) com_android_internal_os_Zygote_nativeForkAndSpecialize }, diff --git a/core/jni/com_android_internal_util_VirtualRefBasePtr.cpp b/core/jni/com_android_internal_util_VirtualRefBasePtr.cpp index 7a18c2d380ce..d20bae232656 100644 --- a/core/jni/com_android_internal_util_VirtualRefBasePtr.cpp +++ b/core/jni/com_android_internal_util_VirtualRefBasePtr.cpp @@ -36,7 +36,7 @@ static void decStrong(JNIEnv* env, jobject clazz, jlong objPtr) { const char* const kClassPathName = "com/android/internal/util/VirtualRefBasePtr"; -static JNINativeMethod gMethods[] = { +static const JNINativeMethod gMethods[] = { { "nIncStrong", "(J)V", (void*) incStrong }, { "nDecStrong", "(J)V", (void*) decStrong }, }; diff --git a/core/jni/com_android_internal_view_animation_NativeInterpolatorFactoryHelper.cpp b/core/jni/com_android_internal_view_animation_NativeInterpolatorFactoryHelper.cpp index 2c65d6210c2e..6781e130c860 100644 --- a/core/jni/com_android_internal_view_animation_NativeInterpolatorFactoryHelper.cpp +++ b/core/jni/com_android_internal_view_animation_NativeInterpolatorFactoryHelper.cpp @@ -78,7 +78,7 @@ static jlong createLutInterpolator(JNIEnv* env, jobject clazz, jfloatArray jlut) const char* const kClassPathName = "com/android/internal/view/animation/NativeInterpolatorFactoryHelper"; -static JNINativeMethod gMethods[] = { +static const JNINativeMethod gMethods[] = { { "createAccelerateDecelerateInterpolator", "()J", (void*) createAccelerateDecelerateInterpolator }, { "createAccelerateInterpolator", "(F)J", (void*) createAccelerateInterpolator }, { "createAnticipateInterpolator", "(F)J", (void*) createAnticipateInterpolator }, diff --git a/core/jni/com_google_android_gles_jni_EGLImpl.cpp b/core/jni/com_google_android_gles_jni_EGLImpl.cpp index baeb7dd98bc4..3d63b013e9f1 100644 --- a/core/jni/com_google_android_gles_jni_EGLImpl.cpp +++ b/core/jni/com_google_android_gles_jni_EGLImpl.cpp @@ -532,7 +532,7 @@ static const char *classPathName = "com/google/android/gles_jni/EGLImpl"; #define OBJECT "Ljava/lang/Object;" #define STRING "Ljava/lang/String;" -static JNINativeMethod methods[] = { +static const JNINativeMethod methods[] = { {"_nativeClassInit","()V", (void*)nativeClassInit }, {"eglWaitGL", "()Z", (void*)jni_eglWaitGL }, {"eglInitialize", "(" DISPLAY "[I)Z", (void*)jni_eglInitialize }, diff --git a/core/jni/com_google_android_gles_jni_GLImpl.cpp b/core/jni/com_google_android_gles_jni_GLImpl.cpp index f15f957d21c7..ad7d744cb693 100644 --- a/core/jni/com_google_android_gles_jni_GLImpl.cpp +++ b/core/jni/com_google_android_gles_jni_GLImpl.cpp @@ -8490,7 +8490,7 @@ android_glTexGenxv__IILjava_nio_IntBuffer_2 static const char *classPathName = "com/google/android/gles_jni/GLImpl"; -static JNINativeMethod methods[] = { +static const JNINativeMethod methods[] = { {"_nativeClassInit", "()V", (void*)nativeClassInit }, {"glActiveTexture", "(I)V", (void *) android_glActiveTexture__I }, {"glAlphaFunc", "(IF)V", (void *) android_glAlphaFunc__IF }, diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml index 664e62121d1b..28dac39d7022 100644 --- a/core/res/AndroidManifest.xml +++ b/core/res/AndroidManifest.xml @@ -188,7 +188,7 @@ <protected-broadcast android:name="android.hardware.usb.action.USB_STATE" /> <protected-broadcast android:name="android.hardware.usb.action.USB_PORT_CHANGED" /> <protected-broadcast android:name="android.hardware.usb.action.USB_ACCESSORY_ATTACHED" /> - <protected-broadcast android:name="android.hardware.usb.action.USB_ACCESSORY_ATTACHED" /> + <protected-broadcast android:name="android.hardware.usb.action.USB_ACCESSORY_DETACHED" /> <protected-broadcast android:name="android.hardware.usb.action.USB_DEVICE_ATTACHED" /> <protected-broadcast android:name="android.hardware.usb.action.USB_DEVICE_DETACHED" /> diff --git a/core/res/res/layout/docked_stack_divider.xml b/core/res/res/layout/docked_stack_divider.xml new file mode 100644 index 000000000000..aa6e68d57af9 --- /dev/null +++ b/core/res/res/layout/docked_stack_divider.xml @@ -0,0 +1,21 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Copyright (C) 2015 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> + +<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" + android:layout_width="@dimen/docked_stack_divider_thickness" + android:layout_height="match_parent" + android:background="@android:color/black" + /> diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml index 902d40dad64f..dc96df4e9d7c 100644 --- a/core/res/res/values/attrs.xml +++ b/core/res/res/values/attrs.xml @@ -5550,6 +5550,8 @@ i <!-- Push object to the end of its container, not changing its size. --> <flag name="end" value="0x00800005" /> </attr> + <!-- Specifies the initial drawable level in the range 0 to 10000. --> + <attr name="level" format="integer" /> <!-- Reference to a drawable resource to draw with the specified scale. --> <attr name="drawable" /> <!-- Use the drawable's intrinsic width and height as minimum size values. diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml index a19bc202c74d..9b1a613894d9 100644 --- a/core/res/res/values/config.xml +++ b/core/res/res/values/config.xml @@ -410,6 +410,9 @@ radio is unable to find any MCC information to infer wifi country code from --> <bool translatable="false" name="config_wifi_revert_country_code_on_cellular_loss">false</bool> + <!-- Boolean indicating whether or not wifi firmware debugging is enabled --> + <bool translatable="false" name="config_wifi_enable_wifi_firmware_debugging">false</bool> + <!-- Integer specifying the basic autojoin parameters --> <integer translatable="false" name="config_wifi_framework_5GHz_preference_boost_threshold">-65</integer> <integer translatable="false" name="config_wifi_framework_5GHz_preference_boost_factor">5</integer> diff --git a/core/res/res/values/dimens.xml b/core/res/res/values/dimens.xml index 8635a4fac7bc..2621bc9cf219 100644 --- a/core/res/res/values/dimens.xml +++ b/core/res/res/values/dimens.xml @@ -45,6 +45,9 @@ <!-- Margin at the edge of the screen to ignore touch events for in the windowshade. --> <dimen name="status_bar_edge_ignore">5dp</dimen> + <!-- Width of a divider bar used to resize docked stacks. --> + <dimen name="docked_stack_divider_thickness">24dp</dimen> + <!-- Min width for a tablet device --> <dimen name="min_xlarge_screen_width">800dp</dimen> diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml index b6284c93faab..89d9babbbc1e 100644 --- a/core/res/res/values/public.xml +++ b/core/res/res/values/public.xml @@ -2673,6 +2673,7 @@ <public type="attr" name="maxButtonHeight" /> <public type="attr" name="buttonGravity" /> <public type="attr" name="collapseIcon" /> + <public type="attr" name="level" /> <public type="style" name="Theme.Material.DayNight" /> <public type="style" name="Theme.Material.DayNight.DarkActionBar" /> diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml index 4edc847156c3..b5efbfd2462a 100644 --- a/core/res/res/values/symbols.xml +++ b/core/res/res/values/symbols.xml @@ -307,6 +307,7 @@ <java-symbol type="bool" name="config_wifi_enable_disconnection_debounce" /> <java-symbol type="bool" name="config_wifi_enable_5GHz_preference" /> <java-symbol type="bool" name="config_wifi_revert_country_code_on_cellular_loss" /> + <java-symbol type="bool" name="config_wifi_enable_wifi_firmware_debugging" /> <java-symbol type="bool" name="config_supportMicNearUltrasound" /> <java-symbol type="bool" name="config_supportSpeakerNearUltrasound" /> <java-symbol type="integer" name="config_wifi_framework_5GHz_preference_boost_threshold" /> @@ -1477,6 +1478,7 @@ <java-symbol type="bool" name="config_showNavigationBar" /> <java-symbol type="bool" name="config_supportAutoRotation" /> <java-symbol type="bool" name="target_honeycomb_needs_options_menu" /> + <java-symbol type="dimen" name="docked_stack_divider_thickness" /> <java-symbol type="dimen" name="navigation_bar_height" /> <java-symbol type="dimen" name="navigation_bar_height_landscape" /> <java-symbol type="dimen" name="navigation_bar_width" /> @@ -1719,6 +1721,7 @@ <java-symbol type="integer" name="config_undockedHdmiRotation" /> <java-symbol type="integer" name="config_virtualKeyQuietTimeMillis" /> <java-symbol type="layout" name="am_compat_mode_dialog" /> + <java-symbol type="layout" name="docked_stack_divider" /> <java-symbol type="layout" name="launch_warning" /> <java-symbol type="layout" name="safe_mode" /> <java-symbol type="layout" name="simple_list_item_2_single_choice" /> diff --git a/core/tests/coretests/apks/install_jni_lib/com_android_frameworks_coretests_JNITest.cpp b/core/tests/coretests/apks/install_jni_lib/com_android_frameworks_coretests_JNITest.cpp index e0b616c16184..3e8301038359 100644 --- a/core/tests/coretests/apks/install_jni_lib/com_android_frameworks_coretests_JNITest.cpp +++ b/core/tests/coretests/apks/install_jni_lib/com_android_frameworks_coretests_JNITest.cpp @@ -22,7 +22,7 @@ static jint checkFunction(JNIEnv*, jclass) { return 1; } -static JNINativeMethod sMethods[] = { +static const JNINativeMethod sMethods[] = { /* name, signature, funcPtr */ { "checkFunction", "()I", (void*) checkFunction }, }; diff --git a/core/tests/hosttests/test-apps/SharedUid/32/jni/native.cpp b/core/tests/hosttests/test-apps/SharedUid/32/jni/native.cpp index 4c1615453289..67b12d775828 100644 --- a/core/tests/hosttests/test-apps/SharedUid/32/jni/native.cpp +++ b/core/tests/hosttests/test-apps/SharedUid/32/jni/native.cpp @@ -30,7 +30,7 @@ int result = a + b; static const char *classPathName = "com/framework/shareduid/bit32/Native"; -static JNINativeMethod methods[] = { +static const JNINativeMethod methods[] = { {"add", "(II)I", (void*)add }, }; @@ -38,7 +38,7 @@ static JNINativeMethod methods[] = { * Register several native methods for one class. */ static int registerNativeMethods(JNIEnv* env, const char* className, - JNINativeMethod* gMethods, int numMethods) + const JNINativeMethod* gMethods, int numMethods) { jclass clazz; diff --git a/core/tests/hosttests/test-apps/SharedUid/64/jni/native.cpp b/core/tests/hosttests/test-apps/SharedUid/64/jni/native.cpp index c2f9f529ee63..342b3bc0ac9a 100644 --- a/core/tests/hosttests/test-apps/SharedUid/64/jni/native.cpp +++ b/core/tests/hosttests/test-apps/SharedUid/64/jni/native.cpp @@ -30,7 +30,7 @@ int result = a + b; static const char *classPathName = "com/framework/shareduid/bit64/Native"; -static JNINativeMethod methods[] = { +static const JNINativeMethod methods[] = { {"add", "(II)I", (void*)add }, }; @@ -38,7 +38,7 @@ static JNINativeMethod methods[] = { * Register several native methods for one class. */ static int registerNativeMethods(JNIEnv* env, const char* className, - JNINativeMethod* gMethods, int numMethods) + const JNINativeMethod* gMethods, int numMethods) { jclass clazz; diff --git a/core/tests/hosttests/test-apps/SharedUid/dual/jni/native.cpp b/core/tests/hosttests/test-apps/SharedUid/dual/jni/native.cpp index 5d3ca06968eb..9b38e3e4c437 100644 --- a/core/tests/hosttests/test-apps/SharedUid/dual/jni/native.cpp +++ b/core/tests/hosttests/test-apps/SharedUid/dual/jni/native.cpp @@ -30,7 +30,7 @@ int result = a + b; static const char *classPathName = "com/framework/shareduid/dual/Native"; -static JNINativeMethod methods[] = { +static const JNINativeMethod methods[] = { {"add", "(II)I", (void*)add }, }; @@ -38,7 +38,7 @@ static JNINativeMethod methods[] = { * Register several native methods for one class. */ static int registerNativeMethods(JNIEnv* env, const char* className, - JNINativeMethod* gMethods, int numMethods) + const JNINativeMethod* gMethods, int numMethods) { jclass clazz; diff --git a/docs/html/training/location/geofencing.jd b/docs/html/training/location/geofencing.jd index 59fc4c665a53..556329cb1f7e 100644 --- a/docs/html/training/location/geofencing.jd +++ b/docs/html/training/location/geofencing.jd @@ -100,8 +100,8 @@ srcset="{@docRoot}images/training/geofence.png 1x, {@docRoot}images/training/geo <h3>Create geofence objects</h3> <p> - First, use <code><a href="{@docRoot}reference/com/google/android/gms/location/Geofence.Builder. - html">Geofence.Builder</a></code> to create a geofence, setting the desired radius, duration, and + First, use <code><a href="{@docRoot}reference/com/google/android/gms/location/Geofence.Builder.html"> + Geofence.Builder</a></code> to create a geofence, setting the desired radius, duration, and transition types for the geofence. For example, to populate a list object named {@code mGeofenceList}: </p> diff --git a/drm/jni/android_drm_DrmManagerClient.cpp b/drm/jni/android_drm_DrmManagerClient.cpp index 52597e10609a..63fe8acedd54 100644 --- a/drm/jni/android_drm_DrmManagerClient.cpp +++ b/drm/jni/android_drm_DrmManagerClient.cpp @@ -702,7 +702,7 @@ static jobject android_drm_DrmManagerClient_closeConvertSession( return status; } -static JNINativeMethod nativeMethods[] = { +static const JNINativeMethod nativeMethods[] = { {"_initialize", "()I", (void*)android_drm_DrmManagerClient_initialize}, diff --git a/graphics/java/android/graphics/drawable/ScaleDrawable.java b/graphics/java/android/graphics/drawable/ScaleDrawable.java index 0acbeda1979e..f9206b7d3c26 100644 --- a/graphics/java/android/graphics/drawable/ScaleDrawable.java +++ b/graphics/java/android/graphics/drawable/ScaleDrawable.java @@ -35,19 +35,29 @@ import java.io.IOException; /** * A Drawable that changes the size of another Drawable based on its current - * level value. You can control how much the child Drawable changes in width + * level value. You can control how much the child Drawable changes in width * and height based on the level, as well as a gravity to control where it is - * placed in its overall container. Most often used to implement things like + * placed in its overall container. Most often used to implement things like * progress bars. - * - * <p>It can be defined in an XML file with the <code><scale></code> element. For more - * information, see the guide to <a - * href="{@docRoot}guide/topics/resources/drawable-resource.html">Drawable Resources</a>.</p> + * <p> + * The default level may be specified from XML using the + * {@link android.R.styleable#ScaleDrawable_level android:level} property. When + * this property is not specified, the default level is 0, which corresponds to + * zero height and/or width depending on the values specified for + * {@code android.R.styleable#ScaleDrawable_scaleWidth scaleWidth} and + * {@code android.R.styleable#ScaleDrawable_scaleHeight scaleHeight}. At run + * time, the level may be set via {@link #setLevel(int)}. + * <p> + * A scale drawable may be defined in an XML file with the {@code <scale>} + * element. For more information, see the guide to + * <a href="{@docRoot}guide/topics/resources/drawable-resource.html">Drawable + * Resources</a>. * * @attr ref android.R.styleable#ScaleDrawable_scaleWidth * @attr ref android.R.styleable#ScaleDrawable_scaleHeight * @attr ref android.R.styleable#ScaleDrawable_scaleGravity * @attr ref android.R.styleable#ScaleDrawable_drawable + * @attr ref android.R.styleable#ScaleDrawable_level */ public class ScaleDrawable extends DrawableWrapper { private static final int MAX_LEVEL = 10000; @@ -92,6 +102,8 @@ public class ScaleDrawable extends DrawableWrapper { inflateChildDrawable(r, parser, attrs, theme); verifyRequiredAttributes(a); a.recycle(); + + updateLocalState(); } private void verifyRequiredAttributes(TypedArray a) throws XmlPullParserException { @@ -117,6 +129,8 @@ public class ScaleDrawable extends DrawableWrapper { R.styleable.ScaleDrawable_scaleGravity, state.mGravity); state.mUseIntrinsicSizeAsMin = a.getBoolean( R.styleable.ScaleDrawable_useIntrinsicSizeAsMinimum, state.mUseIntrinsicSizeAsMin); + state.mInitialLevel = a.getInt( + R.styleable.ScaleDrawable_level, state.mInitialLevel); final Drawable dr = a.getDrawable(R.styleable.ScaleDrawable_drawable); if (dr != null) { @@ -165,6 +179,8 @@ public class ScaleDrawable extends DrawableWrapper { // The drawable may have changed as a result of applying the theme, so // apply the theme to the wrapped drawable last. super.applyTheme(t); + + updateLocalState(); } @Override @@ -239,6 +255,7 @@ public class ScaleDrawable extends DrawableWrapper { float mScaleHeight = DO_NOT_SCALE; int mGravity = Gravity.LEFT; boolean mUseIntrinsicSizeAsMin = false; + int mInitialLevel = 0; ScaleState(ScaleState orig) { super(orig); @@ -248,6 +265,7 @@ public class ScaleDrawable extends DrawableWrapper { mScaleHeight = orig.mScaleHeight; mGravity = orig.mGravity; mUseIntrinsicSizeAsMin = orig.mUseIntrinsicSizeAsMin; + mInitialLevel = orig.mInitialLevel; } } @@ -257,10 +275,23 @@ public class ScaleDrawable extends DrawableWrapper { } } + /** + * Creates a new ScaleDrawable based on the specified constant state. + * <p> + * The resulting drawable is guaranteed to have a new constant state. + * + * @param state constant state from which the drawable inherits + */ private ScaleDrawable(ScaleState state, Resources res) { super(state, res); mState = state; + + updateLocalState(); + } + + private void updateLocalState() { + setLevel(mState.mInitialLevel); } } diff --git a/graphics/java/android/graphics/drawable/VectorDrawable.java b/graphics/java/android/graphics/drawable/VectorDrawable.java index 174722538014..1105ca4b6cbc 100644 --- a/graphics/java/android/graphics/drawable/VectorDrawable.java +++ b/graphics/java/android/graphics/drawable/VectorDrawable.java @@ -126,9 +126,13 @@ import java.util.Stack; * <dd>Defines path data using exactly same format as "d" attribute * in the SVG's path data. This is defined in the viewport space.</dd> * <dt><code>android:fillColor</code></dt> - * <dd>Defines the color to fill the path (none if not present).</dd> + * <dd>Specifies the color used to fill the path. May be a color or (SDK 24+ only) a color state + * list. If this property is animated, any value set by the animation will override the original + * value. No path fill is drawn if this property is not specified.</dd> * <dt><code>android:strokeColor</code></dt> - * <dd>Defines the color to draw the path outline (none if not present).</dd> + * <dd>Specifies the color used to draw the path outline. May be a color or (SDK 24+ only) a color + * state list. If this property is animated, any value set by the animation will override the + * original value. No path outline is drawn if this property is not specified.</dd> * <dt><code>android:strokeWidth</code></dt> * <dd>The width a path stroke.</dd> * <dt><code>android:strokeAlpha</code></dt> @@ -374,19 +378,24 @@ public class VectorDrawable extends Drawable { @Override public boolean isStateful() { - return super.isStateful() || (mVectorState != null && mVectorState.mTint != null - && mVectorState.mTint.isStateful()); + return super.isStateful() || (mVectorState != null && mVectorState.isStateful()); } @Override protected boolean onStateChange(int[] stateSet) { + boolean changed = false; + final VectorDrawableState state = mVectorState; + if (state.mVPathRenderer != null && state.mVPathRenderer.onStateChange(stateSet)) { + changed = true; + state.mCacheDirty = true; + } if (state.mTint != null && state.mTintMode != null) { mTintFilter = updateTintFilter(mTintFilter, state.mTint, state.mTintMode); - invalidateSelf(); - return true; + changed = true; } - return false; + + return changed; } @Override @@ -664,7 +673,7 @@ public class VectorDrawable extends Drawable { if (SHAPE_PATH.equals(tagName)) { final VFullPath path = new VFullPath(); path.inflate(res, attrs, theme); - currentGroup.mChildren.add(path); + currentGroup.addChild(path); if (path.getPathName() != null) { pathRenderer.mVGTargetsMap.put(path.getPathName(), path); } @@ -673,7 +682,7 @@ public class VectorDrawable extends Drawable { } else if (SHAPE_CLIP_PATH.equals(tagName)) { final VClipPath path = new VClipPath(); path.inflate(res, attrs, theme); - currentGroup.mChildren.add(path); + currentGroup.addChild(path); if (path.getPathName() != null) { pathRenderer.mVGTargetsMap.put(path.getPathName(), path); } @@ -681,7 +690,7 @@ public class VectorDrawable extends Drawable { } else if (SHAPE_GROUP.equals(tagName)) { VGroup newChildGroup = new VGroup(); newChildGroup.inflate(res, attrs, theme); - currentGroup.mChildren.add(newChildGroup); + currentGroup.addChild(newChildGroup); groupStack.push(newChildGroup); if (newChildGroup.getGroupName() != null) { pathRenderer.mVGTargetsMap.put(newChildGroup.getGroupName(), @@ -700,7 +709,7 @@ public class VectorDrawable extends Drawable { // Print the tree out for debug. if (DBG_VECTOR_DRAWABLE) { - printGroupTree(pathRenderer.mRootGroup, 0); + pathRenderer.printGroupTree(); } if (noPathTag) { @@ -715,24 +724,6 @@ public class VectorDrawable extends Drawable { } } - private void printGroupTree(VGroup currentGroup, int level) { - String indent = ""; - for (int i = 0; i < level; i++) { - indent += " "; - } - // Print the current node - Log.v(LOGTAG, indent + "current group is :" + currentGroup.getGroupName() - + " rotation is " + currentGroup.mRotate); - Log.v(LOGTAG, indent + "matrix is :" + currentGroup.getLocalMatrix().toString()); - // Then print all the children groups - for (int i = 0; i < currentGroup.mChildren.size(); i++) { - final VObject child = currentGroup.mChildren.get(i); - if (child instanceof VGroup) { - printGroupTree((VGroup) child, level + 1); - } - } - } - @Override public int getChangingConfigurations() { return super.getChangingConfigurations() | mVectorState.getChangingConfigurations(); @@ -890,6 +881,11 @@ public class VectorDrawable extends Drawable { return mChangingConfigurations | (mTint != null ? mTint.getChangingConfigurations() : 0); } + + public boolean isStateful() { + return (mTint != null && mTint.isStateful()) + || (mVPathRenderer != null && mVPathRenderer.isStateful()); + } } private static class VPathRenderer { @@ -972,21 +968,35 @@ public class VectorDrawable extends Drawable { mRootGroup.applyTheme(t); } + public boolean onStateChange(int[] stateSet) { + return mRootGroup.onStateChange(stateSet); + } + + public boolean isStateful() { + return mRootGroup.isStateful(); + } + public void draw(Canvas canvas, int w, int h, ColorFilter filter) { final float scaleX = w / mViewportWidth; final float scaleY = h / mViewportHeight; mRootGroup.draw(canvas, mTempState, Matrix.IDENTITY_MATRIX, filter, scaleX, scaleY); } + + public void printGroupTree() { + mRootGroup.printGroupTree(""); + } } private static class VGroup implements VObject { + private static final String GROUP_INDENT = " "; + // mStackedMatrix is only used temporarily when drawing, it combines all // the parents' local matrices with the current one. private final Matrix mStackedMatrix = new Matrix(); ///////////////////////////////////////////////////// // Variables below need to be copied (deep copy if applicable) for mutation. - final ArrayList<VObject> mChildren = new ArrayList<>(); + private final ArrayList<VObject> mChildren = new ArrayList<>(); private float mRotate = 0; private float mPivotX = 0; @@ -995,6 +1005,7 @@ public class VectorDrawable extends Drawable { private float mScaleY = 1; private float mTranslateX = 0; private float mTranslateY = 0; + private boolean mIsStateful; // mLocalMatrix is updated based on the update of transformation information, // either parsed from the XML or by animation. @@ -1011,6 +1022,7 @@ public class VectorDrawable extends Drawable { mScaleY = copy.mScaleY; mTranslateX = copy.mTranslateX; mTranslateY = copy.mTranslateY; + mIsStateful = copy.mIsStateful; mThemeAttrs = copy.mThemeAttrs; mGroupName = copy.mGroupName; mChangingConfigurations = copy.mChangingConfigurations; @@ -1054,6 +1066,12 @@ public class VectorDrawable extends Drawable { return mLocalMatrix; } + public void addChild(VObject child) { + mChildren.add(child); + + mIsStateful |= child.isStateful(); + } + @Override public void draw(Canvas canvas, TempState temp, Matrix currentMatrix, ColorFilter filter, float scaleX, float scaleY) { @@ -1109,6 +1127,26 @@ public class VectorDrawable extends Drawable { } @Override + public boolean onStateChange(int[] stateSet) { + boolean changed = false; + + final ArrayList<VObject> children = mChildren; + for (int i = 0, count = children.size(); i < count; i++) { + final VObject child = children.get(i); + if (child.isStateful()) { + changed |= child.onStateChange(stateSet); + } + } + + return changed; + } + + @Override + public boolean isStateful() { + return mIsStateful; + } + + @Override public boolean canApplyTheme() { if (mThemeAttrs != null) { return true; @@ -1139,6 +1177,9 @@ public class VectorDrawable extends Drawable { final VObject child = children.get(i); if (child.canApplyTheme()) { child.applyTheme(t); + + // Applying a theme may have made the child stateful. + mIsStateful |= child.isStateful(); } } } @@ -1153,6 +1194,24 @@ public class VectorDrawable extends Drawable { mLocalMatrix.postTranslate(mTranslateX + mPivotX, mTranslateY + mPivotY); } + public void printGroupTree(String indent) { + Log.v(LOGTAG, indent + "group:" + getGroupName() + " rotation is " + mRotate); + Log.v(LOGTAG, indent + "matrix:" + getLocalMatrix().toString()); + + final int count = mChildren.size(); + if (count > 0) { + indent += GROUP_INDENT; + } + + // Then print all the children groups. + for (int i = 0; i < count; i++) { + final VObject child = mChildren.get(i); + if (child instanceof VGroup) { + ((VGroup) child).printGroupTree(indent); + } + } + } + /* Setters and Getters, used by animator from AnimatedVectorDrawable. */ @SuppressWarnings("unused") public float getRotation() { @@ -1398,6 +1457,16 @@ public class VectorDrawable extends Drawable { // No-op. } + @Override + public boolean onStateChange(int[] stateSet) { + return false; + } + + @Override + public boolean isStateful() { + return false; + } + private void updateStateFromTypedArray(TypedArray a) { // Account for any configuration changes. mChangingConfigurations |= a.getChangingConfigurations(); @@ -1427,9 +1496,11 @@ public class VectorDrawable extends Drawable { // Variables below need to be copied (deep copy if applicable) for mutation. private int[] mThemeAttrs; + ColorStateList mStrokeColors = null; int mStrokeColor = Color.TRANSPARENT; float mStrokeWidth = 0; + ColorStateList mFillColors = null; int mFillColor = Color.TRANSPARENT; float mStrokeAlpha = 1.0f; int mFillRule; @@ -1448,11 +1519,14 @@ public class VectorDrawable extends Drawable { public VFullPath(VFullPath copy) { super(copy); + mThemeAttrs = copy.mThemeAttrs; + mStrokeColors = copy.mStrokeColors; mStrokeColor = copy.mStrokeColor; mStrokeWidth = copy.mStrokeWidth; mStrokeAlpha = copy.mStrokeAlpha; + mFillColors = copy.mFillColors; mFillColor = copy.mFillColor; mFillRule = copy.mFillRule; mFillAlpha = copy.mFillAlpha; @@ -1492,6 +1566,31 @@ public class VectorDrawable extends Drawable { } @Override + public boolean onStateChange(int[] stateSet) { + boolean changed = false; + + if (mStrokeColors != null && mStrokeColors.isStateful()) { + final int strokeColor = mStrokeColor; + mStrokeColor = mStrokeColors.getColorForState(stateSet, strokeColor); + changed |= strokeColor != mStrokeColor; + } + + if (mFillColors != null && mFillColors.isStateful()) { + final int fillColor = mFillColor; + mFillColor = mFillColors.getColorForState(stateSet, fillColor); + changed |= fillColor != mFillColor; + } + + return changed; + } + + @Override + public boolean isStateful() { + return mStrokeColors != null && mStrokeColors.isStateful() + || mFillColors != null && mFillColors.isStateful(); + } + + @Override public void toPath(TempState temp, Path path) { super.toPath(temp, path); @@ -1614,8 +1713,20 @@ public class VectorDrawable extends Drawable { mNodes = PathParser.createNodesFromPathData(pathData); } - mFillColor = a.getColor(R.styleable.VectorDrawablePath_fillColor, - mFillColor); + final ColorStateList fillColors = a.getColorStateList( + R.styleable.VectorDrawablePath_fillColor); + if (fillColors != null) { + mFillColors = fillColors; + mFillColor = fillColors.getDefaultColor(); + } + + final ColorStateList strokeColors = a.getColorStateList( + R.styleable.VectorDrawablePath_strokeColor); + if (strokeColors != null) { + mStrokeColors = strokeColors; + mStrokeColor = strokeColors.getDefaultColor(); + } + mFillAlpha = a.getFloat(R.styleable.VectorDrawablePath_fillAlpha, mFillAlpha); mStrokeLineCap = getStrokeLineCap(a.getInt( @@ -1624,8 +1735,6 @@ public class VectorDrawable extends Drawable { R.styleable.VectorDrawablePath_strokeLineJoin, -1), mStrokeLineJoin); mStrokeMiterlimit = a.getFloat( R.styleable.VectorDrawablePath_strokeMiterLimit, mStrokeMiterlimit); - mStrokeColor = a.getColor(R.styleable.VectorDrawablePath_strokeColor, - mStrokeColor); mStrokeAlpha = a.getFloat(R.styleable.VectorDrawablePath_strokeAlpha, mStrokeAlpha); mStrokeWidth = a.getFloat(R.styleable.VectorDrawablePath_strokeWidth, @@ -1662,6 +1771,7 @@ public class VectorDrawable extends Drawable { @SuppressWarnings("unused") void setStrokeColor(int strokeColor) { + mStrokeColors = null; mStrokeColor = strokeColor; } @@ -1692,6 +1802,7 @@ public class VectorDrawable extends Drawable { @SuppressWarnings("unused") void setFillColor(int fillColor) { + mFillColors = null; mFillColor = fillColor; } @@ -1752,5 +1863,7 @@ public class VectorDrawable extends Drawable { void inflate(Resources r, AttributeSet attrs, Theme theme); boolean canApplyTheme(); void applyTheme(Theme t); + boolean onStateChange(int[] state); + boolean isStateful(); } } diff --git a/libs/hwui/Android.mk b/libs/hwui/Android.mk index 3eb13ab9a72d..cc0943f52fdb 100644 --- a/libs/hwui/Android.mk +++ b/libs/hwui/Android.mk @@ -24,6 +24,7 @@ hwui_src_files := \ utils/GLUtils.cpp \ utils/LinearAllocator.cpp \ utils/NinePatchImpl.cpp \ + utils/StringUtils.cpp \ AmbientShadow.cpp \ AnimationContext.cpp \ Animator.cpp \ @@ -168,7 +169,8 @@ LOCAL_SRC_FILES += \ unit_tests/CanvasStateTests.cpp \ unit_tests/ClipAreaTests.cpp \ unit_tests/DamageAccumulatorTests.cpp \ - unit_tests/LinearAllocatorTests.cpp + unit_tests/LinearAllocatorTests.cpp \ + unit_tests/StringUtilsTests.cpp include $(BUILD_NATIVE_TEST) diff --git a/libs/hwui/Caches.cpp b/libs/hwui/Caches.cpp index ff713133e389..7c63e316ba38 100644 --- a/libs/hwui/Caches.cpp +++ b/libs/hwui/Caches.cpp @@ -54,7 +54,6 @@ Caches::Caches(RenderState& renderState) , mInitialized(false) { INIT_LOGD("Creating OpenGL renderer caches"); init(); - initFont(); initConstraints(); initStaticProperties(); initExtensions(); @@ -78,10 +77,6 @@ bool Caches::init() { return true; } -void Caches::initFont() { - fontRenderer = GammaFontRenderer::createRenderer(); -} - void Caches::initExtensions() { if (mExtensions.hasDebugMarker()) { eventMark = glInsertEventMarkerEXT; @@ -100,15 +95,9 @@ void Caches::initConstraints() { } void Caches::initStaticProperties() { - gpuPixelBuffersEnabled = false; - // OpenGL ES 3.0+ specific features - if (mExtensions.hasPixelBufferObjects()) { - char property[PROPERTY_VALUE_MAX]; - if (property_get(PROPERTY_ENABLE_GPU_PIXEL_BUFFERS, property, "true") > 0) { - gpuPixelBuffersEnabled = !strcmp(property, "true"); - } - } + gpuPixelBuffersEnabled = mExtensions.hasPixelBufferObjects() + && property_get_bool(PROPERTY_ENABLE_GPU_PIXEL_BUFFERS, true); } void Caches::terminate() { @@ -203,14 +192,14 @@ void Caches::dumpMemoryUsage(String8 &log) { dropShadowCache.getMaxSize()); log.appendFormat(" PatchCache %8d / %8d\n", patchCache.getSize(), patchCache.getMaxSize()); - for (uint32_t i = 0; i < fontRenderer->getFontRendererCount(); i++) { - const uint32_t sizeA8 = fontRenderer->getFontRendererSize(i, GL_ALPHA); - const uint32_t sizeRGBA = fontRenderer->getFontRendererSize(i, GL_RGBA); - log.appendFormat(" FontRenderer %d A8 %8d / %8d\n", i, sizeA8, sizeA8); - log.appendFormat(" FontRenderer %d RGBA %8d / %8d\n", i, sizeRGBA, sizeRGBA); - log.appendFormat(" FontRenderer %d total %8d / %8d\n", i, sizeA8 + sizeRGBA, - sizeA8 + sizeRGBA); - } + + const uint32_t sizeA8 = fontRenderer.getFontRendererSize(GL_ALPHA); + const uint32_t sizeRGBA = fontRenderer.getFontRendererSize(GL_RGBA); + log.appendFormat(" FontRenderer A8 %8d / %8d\n", sizeA8, sizeA8); + log.appendFormat(" FontRenderer RGBA %8d / %8d\n", sizeRGBA, sizeRGBA); + log.appendFormat(" FontRenderer total %8d / %8d\n", sizeA8 + sizeRGBA, + sizeA8 + sizeRGBA); + log.appendFormat("Other:\n"); log.appendFormat(" FboCache %8d / %8d\n", fboCache.getSize(), fboCache.getMaxSize()); @@ -222,10 +211,8 @@ void Caches::dumpMemoryUsage(String8 &log) { total += tessellationCache.getSize(); total += dropShadowCache.getSize(); total += patchCache.getSize(); - for (uint32_t i = 0; i < fontRenderer->getFontRendererCount(); i++) { - total += fontRenderer->getFontRendererSize(i, GL_ALPHA); - total += fontRenderer->getFontRendererSize(i, GL_RGBA); - } + total += fontRenderer.getFontRendererSize(GL_ALPHA); + total += fontRenderer.getFontRendererSize(GL_RGBA); log.appendFormat("Total memory usage:\n"); log.appendFormat(" %d bytes, %.2f MB\n", total, total / 1024.0f / 1024.0f); @@ -250,12 +237,12 @@ void Caches::flush(FlushMode mode) { patchCache.clear(); dropShadowCache.clear(); gradientCache.clear(); - fontRenderer->clear(); + fontRenderer.clear(); fboCache.clear(); dither.clear(); // fall through case FlushMode::Moderate: - fontRenderer->flush(); + fontRenderer.flush(); textureCache.flush(); pathCache.clear(); tessellationCache.clear(); diff --git a/libs/hwui/Caches.h b/libs/hwui/Caches.h index 929db17a22a8..61e958d42148 100644 --- a/libs/hwui/Caches.h +++ b/libs/hwui/Caches.h @@ -21,6 +21,7 @@ #include "Dither.h" #include "Extensions.h" #include "FboCache.h" +#include "GammaFontRenderer.h" #include "GradientCache.h" #include "LayerCache.h" #include "PatchCache.h" @@ -53,8 +54,6 @@ namespace android { namespace uirenderer { -class GammaFontRenderer; - /////////////////////////////////////////////////////////////////////////////// // Caches /////////////////////////////////////////////////////////////////////////////// @@ -156,7 +155,7 @@ public: TextDropShadowCache dropShadowCache; FboCache fboCache; - GammaFontRenderer* fontRenderer; + GammaFontRenderer fontRenderer; TaskManager tasks; @@ -178,8 +177,6 @@ public: TextureState& textureState() { return *mTextureState; } private: - - void initFont(); void initExtensions(); void initConstraints(); void initStaticProperties(); diff --git a/libs/hwui/Debug.h b/libs/hwui/Debug.h index 5808aaca76be..e98fa0440591 100644 --- a/libs/hwui/Debug.h +++ b/libs/hwui/Debug.h @@ -20,9 +20,6 @@ // Turn on to check for OpenGL errors on each frame #define DEBUG_OPENGL 1 -// Turn on to display informations about the GPU -#define DEBUG_EXTENSIONS 0 - // Turn on to enable initialization information #define DEBUG_INIT 0 diff --git a/libs/hwui/DeferredDisplayList.cpp b/libs/hwui/DeferredDisplayList.cpp index 9fb1e756c00d..a81ffb9f59fa 100644 --- a/libs/hwui/DeferredDisplayList.cpp +++ b/libs/hwui/DeferredDisplayList.cpp @@ -631,7 +631,7 @@ static void replayBatchList(const std::vector<Batch*>& batchList, void DeferredDisplayList::flush(OpenGLRenderer& renderer, Rect& dirty) { ATRACE_NAME("flush drawing commands"); - Caches::getInstance().fontRenderer->endPrecaching(); + Caches::getInstance().fontRenderer.endPrecaching(); if (isEmpty()) return; // nothing to flush renderer.restoreToCount(1); diff --git a/libs/hwui/DisplayListOp.h b/libs/hwui/DisplayListOp.h index 14126a9e31a7..dc5cb8b349f1 100644 --- a/libs/hwui/DisplayListOp.h +++ b/libs/hwui/DisplayListOp.h @@ -1246,7 +1246,7 @@ public: virtual void onDefer(OpenGLRenderer& renderer, DeferInfo& deferInfo, const DeferredDisplayState& state) override { - FontRenderer& fontRenderer = renderer.getCaches().fontRenderer->getFontRenderer(mPaint); + FontRenderer& fontRenderer = renderer.getCaches().fontRenderer.getFontRenderer(); fontRenderer.precache(mPaint, mText, mCount, SkMatrix::I()); deferInfo.batchId = mPaint->getColor() == SK_ColorBLACK ? @@ -1311,7 +1311,7 @@ public: virtual void onDefer(OpenGLRenderer& renderer, DeferInfo& deferInfo, const DeferredDisplayState& state) override { - FontRenderer& fontRenderer = renderer.getCaches().fontRenderer->getFontRenderer(mPaint); + FontRenderer& fontRenderer = renderer.getCaches().fontRenderer.getFontRenderer(); SkMatrix transform; renderer.findBestFontTransform(state.mMatrix, &transform); if (mPrecacheTransform != transform) { diff --git a/libs/hwui/Extensions.cpp b/libs/hwui/Extensions.cpp index 3d350c98892b..06c8a21b019b 100644 --- a/libs/hwui/Extensions.cpp +++ b/libs/hwui/Extensions.cpp @@ -18,23 +18,14 @@ #include "Debug.h" #include "Properties.h" +#include "utils/StringUtils.h" -#include <EGL/egl.h> -#include <EGL/eglext.h> #include <GLES2/gl2ext.h> #include <utils/Log.h> namespace android { - -using namespace uirenderer; -ANDROID_SINGLETON_STATIC_INSTANCE(Extensions); - namespace uirenderer { -/////////////////////////////////////////////////////////////////////////////// -// Defines -/////////////////////////////////////////////////////////////////////////////// - // Debug #if DEBUG_EXTENSIONS #define EXT_LOGD(...) ALOGD(__VA_ARGS__) @@ -42,20 +33,16 @@ namespace uirenderer { #define EXT_LOGD(...) #endif -/////////////////////////////////////////////////////////////////////////////// -// Constructors -/////////////////////////////////////////////////////////////////////////////// Extensions::Extensions() { - // Query GL extensions - findExtensions((const char*) glGetString(GL_EXTENSIONS), mGlExtensionList); - mHasNPot = hasGlExtension("GL_OES_texture_npot"); - mHasFramebufferFetch = hasGlExtension("GL_NV_shader_framebuffer_fetch"); - mHasDiscardFramebuffer = hasGlExtension("GL_EXT_discard_framebuffer"); - mHasDebugMarker = hasGlExtension("GL_EXT_debug_marker"); - mHas1BitStencil = hasGlExtension("GL_OES_stencil1"); - mHas4BitStencil = hasGlExtension("GL_OES_stencil4"); - mHasUnpackSubImage = hasGlExtension("GL_EXT_unpack_subimage"); + StringCollection extensions((const char*) glGetString(GL_EXTENSIONS)); + mHasNPot = extensions.has("GL_OES_texture_npot"); + mHasFramebufferFetch = extensions.has("GL_NV_shader_framebuffer_fetch"); + mHasDiscardFramebuffer = extensions.has("GL_EXT_discard_framebuffer"); + mHasDebugMarker = extensions.has("GL_EXT_debug_marker"); + mHas1BitStencil = extensions.has("GL_OES_stencil1"); + mHas4BitStencil = extensions.has("GL_OES_stencil4"); + mHasUnpackSubImage = extensions.has("GL_EXT_unpack_subimage"); const char* version = (const char*) glGetString(GL_VERSION); @@ -78,40 +65,5 @@ Extensions::Extensions() { } } -/////////////////////////////////////////////////////////////////////////////// -// Methods -/////////////////////////////////////////////////////////////////////////////// - -bool Extensions::hasGlExtension(const char* extension) const { - const String8 s(extension); - return mGlExtensionList.indexOf(s) >= 0; -} - -bool Extensions::hasEglExtension(const char* extension) const { - const String8 s(extension); - return mEglExtensionList.indexOf(s) >= 0; -} - -void Extensions::findExtensions(const char* extensions, SortedVector<String8>& list) const { - const char* current = extensions; - const char* head = current; - EXT_LOGD("Available extensions:"); - do { - head = strchr(current, ' '); - String8 s(current, head ? head - current : strlen(current)); - if (s.length()) { - list.add(s); - EXT_LOGD(" %s", s.string()); - } - current = head + 1; - } while (head); -} - -void Extensions::dump() const { - ALOGD("%s", (const char*) glGetString(GL_VERSION)); - ALOGD("Supported GL extensions:\n%s", (const char*) glGetString(GL_EXTENSIONS)); - ALOGD("Supported EGL extensions:\n%s", eglQueryString(eglGetCurrentDisplay(), EGL_EXTENSIONS)); -} - }; // namespace uirenderer }; // namespace android diff --git a/libs/hwui/Extensions.h b/libs/hwui/Extensions.h index 636b631532bf..0a30d162f2e8 100644 --- a/libs/hwui/Extensions.h +++ b/libs/hwui/Extensions.h @@ -50,17 +50,7 @@ public: inline int getMajorGlVersion() const { return mVersionMajor; } inline int getMinorGlVersion() const { return mVersionMinor; } - bool hasGlExtension(const char* extension) const; - bool hasEglExtension(const char* extension) const; - - void dump() const; - private: - void findExtensions(const char* extensions, SortedVector<String8>& list) const; - - SortedVector<String8> mGlExtensionList; - SortedVector<String8> mEglExtensionList; - bool mHasNPot; bool mHasFramebufferFetch; bool mHasDiscardFramebuffer; diff --git a/libs/hwui/FontRenderer.cpp b/libs/hwui/FontRenderer.cpp index 75c3ead68f7b..4b9d4f90675c 100644 --- a/libs/hwui/FontRenderer.cpp +++ b/libs/hwui/FontRenderer.cpp @@ -75,8 +75,8 @@ void TextDrawFunctor::draw(CacheTexture& texture, bool linearFiltering) { static bool sLogFontRendererCreate = true; -FontRenderer::FontRenderer() - : mGammaTable(nullptr) +FontRenderer::FontRenderer(const uint8_t* gammaTable) + : mGammaTable(gammaTable) , mCurrentFont(nullptr) , mActiveFonts(LruCache<Font::FontDescription, Font*>::kUnlimitedCapacity) , mCurrentCacheTexture(nullptr) @@ -92,27 +92,15 @@ FontRenderer::FontRenderer() INIT_LOGD("Creating FontRenderer"); } - mSmallCacheWidth = DEFAULT_TEXT_SMALL_CACHE_WIDTH; - mSmallCacheHeight = DEFAULT_TEXT_SMALL_CACHE_HEIGHT; - mLargeCacheWidth = DEFAULT_TEXT_LARGE_CACHE_WIDTH; - mLargeCacheHeight = DEFAULT_TEXT_LARGE_CACHE_HEIGHT; + mSmallCacheWidth = property_get_int32(PROPERTY_TEXT_SMALL_CACHE_WIDTH, + DEFAULT_TEXT_SMALL_CACHE_WIDTH); + mSmallCacheHeight = property_get_int32(PROPERTY_TEXT_SMALL_CACHE_HEIGHT, + DEFAULT_TEXT_SMALL_CACHE_HEIGHT); - char property[PROPERTY_VALUE_MAX]; - if (property_get(PROPERTY_TEXT_SMALL_CACHE_WIDTH, property, nullptr) > 0) { - mSmallCacheWidth = atoi(property); - } - - if (property_get(PROPERTY_TEXT_SMALL_CACHE_HEIGHT, property, nullptr) > 0) { - mSmallCacheHeight = atoi(property); - } - - if (property_get(PROPERTY_TEXT_LARGE_CACHE_WIDTH, property, nullptr) > 0) { - mLargeCacheWidth = atoi(property); - } - - if (property_get(PROPERTY_TEXT_LARGE_CACHE_HEIGHT, property, nullptr) > 0) { - mLargeCacheHeight = atoi(property); - } + mLargeCacheWidth = property_get_int32(PROPERTY_TEXT_LARGE_CACHE_WIDTH, + DEFAULT_TEXT_LARGE_CACHE_WIDTH); + mLargeCacheHeight = property_get_int32(PROPERTY_TEXT_LARGE_CACHE_HEIGHT, + DEFAULT_TEXT_LARGE_CACHE_HEIGHT); uint32_t maxTextureSize = (uint32_t) Caches::getInstance().maxTextureSize; diff --git a/libs/hwui/FontRenderer.h b/libs/hwui/FontRenderer.h index 2954975b1413..936c838bd6e4 100644 --- a/libs/hwui/FontRenderer.h +++ b/libs/hwui/FontRenderer.h @@ -72,16 +72,12 @@ public: class FontRenderer { public: - FontRenderer(); + FontRenderer(const uint8_t* gammaTable); ~FontRenderer(); void flushLargeCaches(std::vector<CacheTexture*>& cacheTextures); void flushLargeCaches(); - void setGammaTable(const uint8_t* gammaTable) { - mGammaTable = gammaTable; - } - void setFont(const SkPaint* paint, const SkMatrix& matrix); void precache(const SkPaint* paint, const char* text, int numGlyphs, const SkMatrix& matrix); diff --git a/libs/hwui/GammaFontRenderer.cpp b/libs/hwui/GammaFontRenderer.cpp index 0bcd83a1a050..96cac86386b5 100644 --- a/libs/hwui/GammaFontRenderer.cpp +++ b/libs/hwui/GammaFontRenderer.cpp @@ -21,231 +21,22 @@ namespace android { namespace uirenderer { -/////////////////////////////////////////////////////////////////////////////// -// Utils -/////////////////////////////////////////////////////////////////////////////// - -static int luminance(const SkPaint* paint) { - uint32_t c = paint->getColor(); - const int r = (c >> 16) & 0xFF; - const int g = (c >> 8) & 0xFF; - const int b = (c ) & 0xFF; - return (r * 2 + g * 5 + b) >> 3; -} - -/////////////////////////////////////////////////////////////////////////////// -// Base class GammaFontRenderer -/////////////////////////////////////////////////////////////////////////////// - -GammaFontRenderer* GammaFontRenderer::createRenderer() { - // Choose the best renderer - char property[PROPERTY_VALUE_MAX]; - if (property_get(PROPERTY_TEXT_GAMMA_METHOD, property, DEFAULT_TEXT_GAMMA_METHOD) > 0) { - if (!strcasecmp(property, "lookup")) { - return new LookupGammaFontRenderer(); - } else if (!strcasecmp(property, "shader")) { - return new ShaderGammaFontRenderer(false); - } else if (!strcasecmp(property, "shader3")) { - return new ShaderGammaFontRenderer(true); - } - } - - return new Lookup3GammaFontRenderer(); -} - GammaFontRenderer::GammaFontRenderer() { - // Get the renderer properties - char property[PROPERTY_VALUE_MAX]; - - // Get the gamma - mGamma = DEFAULT_TEXT_GAMMA; - if (property_get(PROPERTY_TEXT_GAMMA, property, nullptr) > 0) { - INIT_LOGD(" Setting text gamma to %s", property); - mGamma = atof(property); - } else { - INIT_LOGD(" Using default text gamma of %.2f", DEFAULT_TEXT_GAMMA); - } - - // Get the black gamma threshold - mBlackThreshold = DEFAULT_TEXT_BLACK_GAMMA_THRESHOLD; - if (property_get(PROPERTY_TEXT_BLACK_GAMMA_THRESHOLD, property, nullptr) > 0) { - INIT_LOGD(" Setting text black gamma threshold to %s", property); - mBlackThreshold = atoi(property); - } else { - INIT_LOGD(" Using default text black gamma threshold of %d", - DEFAULT_TEXT_BLACK_GAMMA_THRESHOLD); - } - - // Get the white gamma threshold - mWhiteThreshold = DEFAULT_TEXT_WHITE_GAMMA_THRESHOLD; - if (property_get(PROPERTY_TEXT_WHITE_GAMMA_THRESHOLD, property, nullptr) > 0) { - INIT_LOGD(" Setting text white gamma threshold to %s", property); - mWhiteThreshold = atoi(property); - } else { - INIT_LOGD(" Using default white black gamma threshold of %d", - DEFAULT_TEXT_WHITE_GAMMA_THRESHOLD); - } -} - -GammaFontRenderer::~GammaFontRenderer() { -} - -/////////////////////////////////////////////////////////////////////////////// -// Shader-based renderer -/////////////////////////////////////////////////////////////////////////////// - -ShaderGammaFontRenderer::ShaderGammaFontRenderer(bool multiGamma) - : GammaFontRenderer() { - INIT_LOGD("Creating shader gamma font renderer"); - mRenderer = nullptr; - mMultiGamma = multiGamma; -} - -void ShaderGammaFontRenderer::describe(ProgramDescription& description, - const SkPaint* paint) const { - if (paint->getShader() == nullptr) { - if (mMultiGamma) { - const int l = luminance(paint); - - if (l <= mBlackThreshold) { - description.hasGammaCorrection = true; - description.gamma = mGamma; - } else if (l >= mWhiteThreshold) { - description.hasGammaCorrection = true; - description.gamma = 1.0f / mGamma; - } - } else { - description.hasGammaCorrection = true; - description.gamma = 1.0f / mGamma; - } - } -} - -void ShaderGammaFontRenderer::setupProgram(ProgramDescription& description, - Program& program) const { - if (description.hasGammaCorrection) { - glUniform1f(program.getUniform("gamma"), description.gamma); - } -} - -void ShaderGammaFontRenderer::endPrecaching() { - if (mRenderer) { - mRenderer->endPrecaching(); - } -} - -/////////////////////////////////////////////////////////////////////////////// -// Lookup-based renderer -/////////////////////////////////////////////////////////////////////////////// - -LookupGammaFontRenderer::LookupGammaFontRenderer() - : GammaFontRenderer() { INIT_LOGD("Creating lookup gamma font renderer"); // Compute the gamma tables - const float gamma = 1.0f / mGamma; + const float gamma = 1.0f / Properties::textGamma; for (uint32_t i = 0; i <= 255; i++) { mGammaTable[i] = uint8_t((float)::floor(pow(i / 255.0f, gamma) * 255.0f + 0.5f)); } - - mRenderer = nullptr; } -void LookupGammaFontRenderer::endPrecaching() { +void GammaFontRenderer::endPrecaching() { if (mRenderer) { mRenderer->endPrecaching(); } } -/////////////////////////////////////////////////////////////////////////////// -// Lookup-based renderer, using 3 different correction tables -/////////////////////////////////////////////////////////////////////////////// - -Lookup3GammaFontRenderer::Lookup3GammaFontRenderer() - : GammaFontRenderer() { - INIT_LOGD("Creating lookup3 gamma font renderer"); - - // Compute the gamma tables - const float blackGamma = mGamma; - const float whiteGamma = 1.0f / mGamma; - - for (uint32_t i = 0; i <= 255; i++) { - const float v = i / 255.0f; - const float black = pow(v, blackGamma); - const float white = pow(v, whiteGamma); - - mGammaTable[i] = i; - mGammaTable[256 + i] = uint8_t((float)::floor(black * 255.0f + 0.5f)); - mGammaTable[512 + i] = uint8_t((float)::floor(white * 255.0f + 0.5f)); - } - - memset(mRenderers, 0, sizeof(FontRenderer*) * kGammaCount); - memset(mRenderersUsageCount, 0, sizeof(uint32_t) * kGammaCount); -} - -void Lookup3GammaFontRenderer::endPrecaching() { - for (int i = 0; i < kGammaCount; i++) { - if (mRenderers[i]) { - mRenderers[i]->endPrecaching(); - } - } -} - -void Lookup3GammaFontRenderer::clear() { - for (int i = 0; i < kGammaCount; i++) { - mRenderers[i].release(); - } -} - -void Lookup3GammaFontRenderer::flush() { - int count = 0; - int min = -1; - uint32_t minCount = UINT_MAX; - - for (int i = 0; i < kGammaCount; i++) { - if (mRenderers[i]) { - count++; - if (mRenderersUsageCount[i] < minCount) { - minCount = mRenderersUsageCount[i]; - min = i; - } - } - } - - if (count <= 1 || min < 0) return; - - mRenderers[min].release(); - - // Also eliminate the caches for large glyphs, as they consume significant memory - for (int i = 0; i < kGammaCount; ++i) { - if (mRenderers[i]) { - mRenderers[i]->flushLargeCaches(); - } - } -} - -FontRenderer* Lookup3GammaFontRenderer::getRenderer(Gamma gamma) { - if (!mRenderers[gamma]) { - mRenderers[gamma].reset(new FontRenderer()); - mRenderers[gamma]->setGammaTable(&mGammaTable[gamma * 256]); - } - mRenderersUsageCount[gamma]++; - return mRenderers[gamma].get(); -} - -FontRenderer& Lookup3GammaFontRenderer::getFontRenderer(const SkPaint* paint) { - if (paint->getShader() == nullptr) { - const int l = luminance(paint); - - if (l <= mBlackThreshold) { - return *getRenderer(kGammaBlack); - } else if (l >= mWhiteThreshold) { - return *getRenderer(kGammaWhite); - } - } - return *getRenderer(kGammaDefault); -} - }; // namespace uirenderer }; // namespace android diff --git a/libs/hwui/GammaFontRenderer.h b/libs/hwui/GammaFontRenderer.h index ca55bf1e74e0..146d385e1173 100644 --- a/libs/hwui/GammaFontRenderer.h +++ b/libs/hwui/GammaFontRenderer.h @@ -17,183 +17,44 @@ #ifndef ANDROID_HWUI_GAMMA_FONT_RENDERER_H #define ANDROID_HWUI_GAMMA_FONT_RENDERER_H -#include <SkPaint.h> - #include "FontRenderer.h" #include "Program.h" +#include <SkPaint.h> + namespace android { namespace uirenderer { class GammaFontRenderer { public: - virtual ~GammaFontRenderer(); - - virtual void clear() = 0; - virtual void flush() = 0; - - virtual FontRenderer& getFontRenderer(const SkPaint* paint) = 0; - - virtual uint32_t getFontRendererCount() const = 0; - virtual uint32_t getFontRendererSize(uint32_t fontRenderer, GLenum format) const = 0; - - virtual void describe(ProgramDescription& description, const SkPaint* paint) const = 0; - virtual void setupProgram(ProgramDescription& description, Program& program) const = 0; - - virtual void endPrecaching() = 0; - - static GammaFontRenderer* createRenderer(); - -protected: GammaFontRenderer(); - int mBlackThreshold; - int mWhiteThreshold; - - float mGamma; -}; - -class ShaderGammaFontRenderer: public GammaFontRenderer { -public: - ~ShaderGammaFontRenderer() { - delete mRenderer; - } - - void clear() override { - delete mRenderer; - mRenderer = nullptr; - } - - void flush() override { - if (mRenderer) { - mRenderer->flushLargeCaches(); - } - } - - FontRenderer& getFontRenderer(const SkPaint* paint) override { - if (!mRenderer) { - mRenderer = new FontRenderer; - } - return *mRenderer; - } - - uint32_t getFontRendererCount() const override { - return 1; - } - - uint32_t getFontRendererSize(uint32_t fontRenderer, GLenum format) const override { - return mRenderer ? mRenderer->getCacheSize(format) : 0; - } - - void describe(ProgramDescription& description, const SkPaint* paint) const override; - void setupProgram(ProgramDescription& description, Program& program) const override; - - void endPrecaching() override; - -private: - ShaderGammaFontRenderer(bool multiGamma); - - FontRenderer* mRenderer; - bool mMultiGamma; - - friend class GammaFontRenderer; -}; - -class LookupGammaFontRenderer: public GammaFontRenderer { -public: - ~LookupGammaFontRenderer() { - delete mRenderer; - } - - void clear() override { - delete mRenderer; - mRenderer = nullptr; + void clear() { + mRenderer.release(); } - void flush() override { + void flush() { if (mRenderer) { mRenderer->flushLargeCaches(); } } - FontRenderer& getFontRenderer(const SkPaint* paint) override { + FontRenderer& getFontRenderer() { if (!mRenderer) { - mRenderer = new FontRenderer; - mRenderer->setGammaTable(&mGammaTable[0]); + mRenderer.reset(new FontRenderer(&mGammaTable[0])); } return *mRenderer; } - uint32_t getFontRendererCount() const override { - return 1; - } - - uint32_t getFontRendererSize(uint32_t fontRenderer, GLenum format) const override { + uint32_t getFontRendererSize(GLenum format) const { return mRenderer ? mRenderer->getCacheSize(format) : 0; } - void describe(ProgramDescription& description, const SkPaint* paint) const override { - } - - void setupProgram(ProgramDescription& description, Program& program) const override { - } - - void endPrecaching() override; + void endPrecaching(); private: - LookupGammaFontRenderer(); - - FontRenderer* mRenderer; + std::unique_ptr<FontRenderer> mRenderer; uint8_t mGammaTable[256]; - - friend class GammaFontRenderer; -}; - -class Lookup3GammaFontRenderer: public GammaFontRenderer { -public: - void clear() override; - void flush() override; - - FontRenderer& getFontRenderer(const SkPaint* paint) override; - - uint32_t getFontRendererCount() const override { - return kGammaCount; - } - - uint32_t getFontRendererSize(uint32_t fontRenderer, GLenum format) const override { - if (fontRenderer >= kGammaCount) return 0; - - if (!mRenderers[fontRenderer]) return 0; - - return mRenderers[fontRenderer]->getCacheSize(format); - } - - void describe(ProgramDescription& description, const SkPaint* paint) const override { - } - - void setupProgram(ProgramDescription& description, Program& program) const override { - } - - void endPrecaching() override; - -private: - Lookup3GammaFontRenderer(); - - enum Gamma { - kGammaDefault = 0, - kGammaBlack = 1, - kGammaWhite = 2, - kGammaCount = 3 - }; - - FontRenderer* getRenderer(Gamma gamma); - - uint32_t mRenderersUsageCount[kGammaCount]; - std::unique_ptr<FontRenderer> mRenderers[kGammaCount]; - - uint8_t mGammaTable[256 * kGammaCount]; - - friend class GammaFontRenderer; }; }; // namespace uirenderer diff --git a/libs/hwui/GlopBuilder.cpp b/libs/hwui/GlopBuilder.cpp index e27b26b1d091..69559a77c3a0 100644 --- a/libs/hwui/GlopBuilder.cpp +++ b/libs/hwui/GlopBuilder.cpp @@ -435,7 +435,6 @@ GlopBuilder& GlopBuilder::setFillLayer(Texture& texture, const SkColorFilter* co mOutGlop->fill.texture = { &texture, GL_TEXTURE_2D, GL_LINEAR, GL_CLAMP_TO_EDGE, nullptr }; - mOutGlop->fill.color = { alpha, alpha, alpha, alpha }; setFill(SK_ColorWHITE, alpha, mode, modeUsage, nullptr, colorFilter); @@ -449,7 +448,6 @@ GlopBuilder& GlopBuilder::setFillTextureLayer(Layer& layer, float alpha) { mOutGlop->fill.texture = { &(layer.getTexture()), layer.getRenderTarget(), GL_LINEAR, GL_CLAMP_TO_EDGE, &layer.getTexTransform() }; - mOutGlop->fill.color = { alpha, alpha, alpha, alpha }; setFill(SK_ColorWHITE, alpha, layer.getMode(), Blend::ModeOrderSwap::NoSwap, nullptr, layer.getColorFilter()); diff --git a/libs/hwui/OpenGLRenderer.cpp b/libs/hwui/OpenGLRenderer.cpp index e06e34849a91..a401ce119021 100644 --- a/libs/hwui/OpenGLRenderer.cpp +++ b/libs/hwui/OpenGLRenderer.cpp @@ -2014,7 +2014,7 @@ void OpenGLRenderer::drawPosText(const char* text, int bytesCount, int count, y = floorf(y + currentTransform()->getTranslateY() + 0.5f); } - FontRenderer& fontRenderer = mCaches.fontRenderer->getFontRenderer(paint); + FontRenderer& fontRenderer = mCaches.fontRenderer.getFontRenderer(); fontRenderer.setFont(paint, SkMatrix::I()); int alpha; @@ -2166,7 +2166,7 @@ void OpenGLRenderer::drawText(const char* text, int bytesCount, int count, float SkXfermode::Mode mode; getAlphaAndMode(paint, &alpha, &mode); - FontRenderer& fontRenderer = mCaches.fontRenderer->getFontRenderer(paint); + FontRenderer& fontRenderer = mCaches.fontRenderer.getFontRenderer(); if (CC_UNLIKELY(hasTextShadow(paint))) { fontRenderer.setFont(paint, SkMatrix::I()); @@ -2234,7 +2234,7 @@ void OpenGLRenderer::drawTextOnPath(const char* text, int bytesCount, int count, // TODO: avoid scissor by calculating maximum bounds using path bounds + font metrics mRenderState.scissor().setEnabled(true); - FontRenderer& fontRenderer = mCaches.fontRenderer->getFontRenderer(paint); + FontRenderer& fontRenderer = mCaches.fontRenderer.getFontRenderer(); fontRenderer.setFont(paint, SkMatrix::I()); fontRenderer.setTextureFiltering(true); diff --git a/libs/hwui/PathCache.cpp b/libs/hwui/PathCache.cpp index f503e5d6e8ba..4031f2e13f39 100644 --- a/libs/hwui/PathCache.cpp +++ b/libs/hwui/PathCache.cpp @@ -138,10 +138,10 @@ PathCache::PathCache(): mSize(0), mMaxSize(MB(DEFAULT_PATH_CACHE_SIZE)) { char property[PROPERTY_VALUE_MAX]; if (property_get(PROPERTY_PATH_CACHE_SIZE, property, nullptr) > 0) { - INIT_LOGD(" Setting %s cache size to %sMB", name, property); + INIT_LOGD(" Setting path cache size to %sMB", property); mMaxSize = MB(atof(property)); } else { - INIT_LOGD(" Using default %s cache size of %.2fMB", name, DEFAULT_PATH_CACHE_SIZE); + INIT_LOGD(" Using default path cache size of %.2fMB", DEFAULT_PATH_CACHE_SIZE); } mCache.setOnEntryRemovedListener(this); diff --git a/libs/hwui/Program.h b/libs/hwui/Program.h index b09c207f6e45..e5200a516777 100644 --- a/libs/hwui/Program.h +++ b/libs/hwui/Program.h @@ -78,14 +78,12 @@ namespace uirenderer { #define PROGRAM_HAS_EXTERNAL_TEXTURE_SHIFT 38 #define PROGRAM_HAS_TEXTURE_TRANSFORM_SHIFT 39 -#define PROGRAM_HAS_GAMMA_CORRECTION 40 +#define PROGRAM_IS_SIMPLE_GRADIENT 40 -#define PROGRAM_IS_SIMPLE_GRADIENT 41 +#define PROGRAM_HAS_COLORS 41 -#define PROGRAM_HAS_COLORS 42 - -#define PROGRAM_HAS_DEBUG_HIGHLIGHT 43 -#define PROGRAM_HAS_ROUND_RECT_CLIP 44 +#define PROGRAM_HAS_DEBUG_HIGHLIGHT 42 +#define PROGRAM_HAS_ROUND_RECT_CLIP 43 /////////////////////////////////////////////////////////////////////////////// // Types @@ -157,9 +155,6 @@ struct ProgramDescription { SkXfermode::Mode framebufferMode; bool swapSrcDst; - bool hasGammaCorrection; - float gamma; - bool hasDebugHighlight; bool hasRoundRectClip; @@ -199,9 +194,6 @@ struct ProgramDescription { framebufferMode = SkXfermode::kClear_Mode; swapSrcDst = false; - hasGammaCorrection = false; - gamma = 2.2f; - hasDebugHighlight = false; hasRoundRectClip = false; } @@ -266,7 +258,6 @@ struct ProgramDescription { if (useShadowAlphaInterp) key |= programid(0x1) << PROGRAM_USE_SHADOW_ALPHA_INTERP_SHIFT; if (hasExternalTexture) key |= programid(0x1) << PROGRAM_HAS_EXTERNAL_TEXTURE_SHIFT; if (hasTextureTransform) key |= programid(0x1) << PROGRAM_HAS_TEXTURE_TRANSFORM_SHIFT; - if (hasGammaCorrection) key |= programid(0x1) << PROGRAM_HAS_GAMMA_CORRECTION; if (isSimpleGradient) key |= programid(0x1) << PROGRAM_IS_SIMPLE_GRADIENT; if (hasColors) key |= programid(0x1) << PROGRAM_HAS_COLORS; if (hasDebugHighlight) key |= programid(0x1) << PROGRAM_HAS_DEBUG_HIGHLIGHT; diff --git a/libs/hwui/ProgramCache.cpp b/libs/hwui/ProgramCache.cpp index b25a4ac9558d..05be48822fb2 100644 --- a/libs/hwui/ProgramCache.cpp +++ b/libs/hwui/ProgramCache.cpp @@ -167,8 +167,6 @@ const char* gFS_Uniforms_ColorOp[3] = { // PorterDuff "uniform vec4 colorBlend;\n" }; -const char* gFS_Uniforms_Gamma = - "uniform float gamma;\n"; const char* gFS_Uniforms_HasRoundRectClip = "uniform vec4 roundRectInnerRectLTRB;\n" @@ -204,18 +202,10 @@ const char* gFS_Fast_SingleA8Texture = "\nvoid main(void) {\n" " gl_FragColor = texture2D(baseSampler, outTexCoords);\n" "}\n\n"; -const char* gFS_Fast_SingleA8Texture_ApplyGamma = - "\nvoid main(void) {\n" - " gl_FragColor = vec4(0.0, 0.0, 0.0, pow(texture2D(baseSampler, outTexCoords).a, gamma));\n" - "}\n\n"; const char* gFS_Fast_SingleModulateA8Texture = "\nvoid main(void) {\n" " gl_FragColor = color * texture2D(baseSampler, outTexCoords).a;\n" "}\n\n"; -const char* gFS_Fast_SingleModulateA8Texture_ApplyGamma = - "\nvoid main(void) {\n" - " gl_FragColor = color * pow(texture2D(baseSampler, outTexCoords).a, gamma);\n" - "}\n\n"; const char* gFS_Fast_SingleGradient[2] = { "\nvoid main(void) {\n" " gl_FragColor = %s + texture2D(gradientSampler, linear);\n" @@ -250,13 +240,11 @@ const char* gFS_Main_FetchTexture[2] = { // Modulate " fragColor = color * texture2D(baseSampler, outTexCoords);\n" }; -const char* gFS_Main_FetchA8Texture[4] = { +const char* gFS_Main_FetchA8Texture[2] = { // Don't modulate " fragColor = texture2D(baseSampler, outTexCoords);\n", - " fragColor = texture2D(baseSampler, outTexCoords);\n", // Modulate " fragColor = color * texture2D(baseSampler, outTexCoords).a;\n", - " fragColor = color * pow(texture2D(baseSampler, outTexCoords).a, gamma);\n" }; const char* gFS_Main_FetchGradient[6] = { // Linear @@ -284,38 +272,29 @@ const char* gFS_Main_BlendShadersBG = " fragColor = blendShaders(gradientColor, bitmapColor)"; const char* gFS_Main_BlendShadersGB = " fragColor = blendShaders(bitmapColor, gradientColor)"; -const char* gFS_Main_BlendShaders_Modulate[6] = { +const char* gFS_Main_BlendShaders_Modulate[3] = { // Don't modulate ";\n", - ";\n", // Modulate " * color.a;\n", - " * color.a;\n", // Modulate with alpha 8 texture " * texture2D(baseSampler, outTexCoords).a;\n", - " * pow(texture2D(baseSampler, outTexCoords).a, gamma);\n" }; -const char* gFS_Main_GradientShader_Modulate[6] = { +const char* gFS_Main_GradientShader_Modulate[3] = { // Don't modulate " fragColor = gradientColor;\n", - " fragColor = gradientColor;\n", // Modulate " fragColor = gradientColor * color.a;\n", - " fragColor = gradientColor * color.a;\n", // Modulate with alpha 8 texture " fragColor = gradientColor * texture2D(baseSampler, outTexCoords).a;\n", - " fragColor = gradientColor * pow(texture2D(baseSampler, outTexCoords).a, gamma);\n" }; -const char* gFS_Main_BitmapShader_Modulate[6] = { +const char* gFS_Main_BitmapShader_Modulate[3] = { // Don't modulate " fragColor = bitmapColor;\n", - " fragColor = bitmapColor;\n", // Modulate " fragColor = bitmapColor * color.a;\n", - " fragColor = bitmapColor * color.a;\n", // Modulate with alpha 8 texture " fragColor = bitmapColor * texture2D(baseSampler, outTexCoords).a;\n", - " fragColor = bitmapColor * pow(texture2D(baseSampler, outTexCoords).a, gamma);\n" }; const char* gFS_Main_FragColor = " gl_FragColor = fragColor;\n"; @@ -540,7 +519,6 @@ String8 ProgramCache::generateVertexShader(const ProgramDescription& description static bool shaderOp(const ProgramDescription& description, String8& shader, const int modulateOp, const char** snippets) { int op = description.hasAlpha8Texture ? MODULATE_OP_MODULATE_A8 : modulateOp; - op = op * 2 + description.hasGammaCorrection; shader.append(snippets[op]); return description.hasAlpha8Texture; } @@ -596,9 +574,6 @@ String8 ProgramCache::generateFragmentShader(const ProgramDescription& descripti shader.appendFormat(gFS_Uniforms_GradientSampler[description.isSimpleGradient], gFS_Uniforms_Dither); } - if (description.hasGammaCorrection) { - shader.append(gFS_Uniforms_Gamma); - } if (description.hasRoundRectClip) { shader.append(gFS_Uniforms_HasRoundRectClip); } @@ -633,17 +608,9 @@ String8 ProgramCache::generateFragmentShader(const ProgramDescription& descripti fast = true; } else if (singleA8Texture) { if (!description.modulate) { - if (description.hasGammaCorrection) { - shader.append(gFS_Fast_SingleA8Texture_ApplyGamma); - } else { - shader.append(gFS_Fast_SingleA8Texture); - } + shader.append(gFS_Fast_SingleA8Texture); } else { - if (description.hasGammaCorrection) { - shader.append(gFS_Fast_SingleModulateA8Texture_ApplyGamma); - } else { - shader.append(gFS_Fast_SingleModulateA8Texture); - } + shader.append(gFS_Fast_SingleModulateA8Texture); } fast = true; } else if (singleGradient) { @@ -693,8 +660,7 @@ String8 ProgramCache::generateFragmentShader(const ProgramDescription& descripti if (description.hasTexture || description.hasExternalTexture) { if (description.hasAlpha8Texture) { if (!description.hasGradient && !description.hasBitmap) { - shader.append(gFS_Main_FetchA8Texture[modulateOp * 2 + - description.hasGammaCorrection]); + shader.append(gFS_Main_FetchA8Texture[modulateOp]); } } else { shader.append(gFS_Main_FetchTexture[modulateOp]); diff --git a/libs/hwui/Properties.cpp b/libs/hwui/Properties.cpp index b8f8585e5af6..36a8dac9d0c1 100644 --- a/libs/hwui/Properties.cpp +++ b/libs/hwui/Properties.cpp @@ -33,6 +33,8 @@ bool Properties::swapBuffersWithDamage = true; bool Properties::useBufferAge = true; bool Properties::enablePartialUpdates = true; +float Properties::textGamma = DEFAULT_TEXT_GAMMA; + DebugLevel Properties::debugLevel = kDebugDisabled; OverdrawColorSet Properties::overdrawColorSet = OverdrawColorSet::Default; StencilClipDebug Properties::debugStencilClip = StencilClipDebug::Hide; @@ -47,6 +49,15 @@ int Properties::overrideSpotShadowStrength = -1; ProfileType Properties::sProfileType = ProfileType::None; bool Properties::sDisableProfileBars = false; +static float property_get_float(const char* key, float defaultValue) { + char buf[PROPERTY_VALUE_MAX] = {'\0',}; + + if (property_get(PROPERTY_PROFILE, buf, "") > 0) { + return atof(buf); + } + return defaultValue; +} + bool Properties::load() { char property[PROPERTY_VALUE_MAX]; bool prevDebugLayersUpdates = debugLayersUpdates; @@ -110,6 +121,8 @@ bool Properties::load() { useBufferAge = property_get_bool(PROPERTY_USE_BUFFER_AGE, true); enablePartialUpdates = property_get_bool(PROPERTY_ENABLE_PARTIAL_UPDATES, true); + textGamma = property_get_float(PROPERTY_TEXT_GAMMA, DEFAULT_TEXT_GAMMA); + return (prevDebugLayersUpdates != debugLayersUpdates) || (prevDebugOverdraw != debugOverdraw) || (prevDebugStencilClip != debugStencilClip); diff --git a/libs/hwui/Properties.h b/libs/hwui/Properties.h index 76028482ba86..3512c36417e1 100644 --- a/libs/hwui/Properties.h +++ b/libs/hwui/Properties.h @@ -208,30 +208,8 @@ enum DebugLevel { #define PROPERTY_TEXT_LARGE_CACHE_WIDTH "ro.hwui.text_large_cache_width" #define PROPERTY_TEXT_LARGE_CACHE_HEIGHT "ro.hwui.text_large_cache_height" -// Indicates whether gamma correction should be applied in the shaders -// or in lookup tables. Accepted values: -// -// - "lookup3", correction based on lookup tables. Gamma correction -// is different for black and white text (see thresholds below) -// -// - "lookup", correction based on a single lookup table -// -// - "shader3", correction applied by a GLSL shader. Gamma correction -// is different for black and white text (see thresholds below) -// -// - "shader", correction applied by a GLSL shader -// -// See PROPERTY_TEXT_GAMMA, PROPERTY_TEXT_BLACK_GAMMA_THRESHOLD and -// PROPERTY_TEXT_WHITE_GAMMA_THRESHOLD for more control. -#define PROPERTY_TEXT_GAMMA_METHOD "hwui.text_gamma_correction" -#define DEFAULT_TEXT_GAMMA_METHOD "lookup" - // Gamma (>= 1.0, <= 10.0) #define PROPERTY_TEXT_GAMMA "hwui.text_gamma" -// Luminance threshold below which black gamma correction is applied. Range: [0..255] -#define PROPERTY_TEXT_BLACK_GAMMA_THRESHOLD "hwui.text_gamma.black_threshold" -// Lumincance threshold above which white gamma correction is applied. Range: [0..255] -#define PROPERTY_TEXT_WHITE_GAMMA_THRESHOLD "hwui.text_gamma.white_threshold" /////////////////////////////////////////////////////////////////////////////// // Default property values @@ -242,7 +220,7 @@ enum DebugLevel { #define DEFAULT_RENDER_BUFFER_CACHE_SIZE 2.0f #define DEFAULT_PATH_CACHE_SIZE 4.0f #define DEFAULT_VERTEX_CACHE_SIZE 1.0f -#define DEFAULT_PATCH_CACHE_SIZE 128 // in kB +#define DEFAULT_PATCH_CACHE_SIZE 128.0f // in kB #define DEFAULT_GRADIENT_CACHE_SIZE 0.5f #define DEFAULT_DROP_SHADOW_CACHE_SIZE 2.0f #define DEFAULT_FBO_CACHE_SIZE 0 @@ -250,8 +228,6 @@ enum DebugLevel { #define DEFAULT_TEXTURE_CACHE_FLUSH_RATE 0.6f #define DEFAULT_TEXT_GAMMA 1.4f -#define DEFAULT_TEXT_BLACK_GAMMA_THRESHOLD 64 -#define DEFAULT_TEXT_WHITE_GAMMA_THRESHOLD 192 /////////////////////////////////////////////////////////////////////////////// // Misc @@ -300,6 +276,8 @@ public: static bool useBufferAge; static bool enablePartialUpdates; + static float textGamma; + static DebugLevel debugLevel; static OverdrawColorSet overdrawColorSet; static StencilClipDebug debugStencilClip; diff --git a/libs/hwui/TessellationCache.cpp b/libs/hwui/TessellationCache.cpp index 01f5e2dba214..12a3e76c9387 100644 --- a/libs/hwui/TessellationCache.cpp +++ b/libs/hwui/TessellationCache.cpp @@ -312,10 +312,10 @@ TessellationCache::TessellationCache() , mShadowCache(LruCache<ShadowDescription, Task<vertexBuffer_pair_t*>*>::kUnlimitedCapacity) { char property[PROPERTY_VALUE_MAX]; if (property_get(PROPERTY_VERTEX_CACHE_SIZE, property, nullptr) > 0) { - INIT_LOGD(" Setting %s cache size to %sMB", name, property); + INIT_LOGD(" Setting tessellation cache size to %sMB", property); setMaxSize(MB(atof(property))); } else { - INIT_LOGD(" Using default %s cache size of %.2fMB", name, DEFAULT_VERTEX_CACHE_SIZE); + INIT_LOGD(" Using default tessellation cache size of %.2fMB", DEFAULT_VERTEX_CACHE_SIZE); } mCache.setOnEntryRemovedListener(&mBufferRemovedListener); diff --git a/libs/hwui/TreeInfo.h b/libs/hwui/TreeInfo.h index ed853f72539d..98e61468ea70 100644 --- a/libs/hwui/TreeInfo.h +++ b/libs/hwui/TreeInfo.h @@ -77,7 +77,7 @@ public: , canvasContext(clone.canvasContext) {} - const TraversalMode mode; + TraversalMode mode; // TODO: Remove this? Currently this is used to signal to stop preparing // textures if we run out of cache space. bool prepareTextures; diff --git a/libs/hwui/renderstate/Blend.cpp b/libs/hwui/renderstate/Blend.cpp index b21e15e8fad9..93f787d31745 100644 --- a/libs/hwui/renderstate/Blend.cpp +++ b/libs/hwui/renderstate/Blend.cpp @@ -98,20 +98,6 @@ Blend::Blend() // gl blending off by default } -void Blend::enable(SkXfermode::Mode mode, ModeOrderSwap modeUsage) { - GLenum srcMode; - GLenum dstMode; - getFactors(mode, modeUsage, &srcMode, &dstMode); - setFactors(srcMode, dstMode); -} - -void Blend::disable() { - if (mEnabled) { - glDisable(GL_BLEND); - mEnabled = false; - } -} - void Blend::invalidate() { syncEnabled(); mSrcMode = mDstMode = GL_ZERO; @@ -132,8 +118,13 @@ void Blend::getFactors(SkXfermode::Mode mode, ModeOrderSwap modeUsage, GLenum* o void Blend::setFactors(GLenum srcMode, GLenum dstMode) { if (srcMode == GL_ZERO && dstMode == GL_ZERO) { - disable(); + // disable blending + if (mEnabled) { + glDisable(GL_BLEND); + mEnabled = false; + } } else { + // enable blending if (!mEnabled) { glEnable(GL_BLEND); mEnabled = true; diff --git a/libs/hwui/renderstate/Blend.h b/libs/hwui/renderstate/Blend.h index dcc681d4aa50..df9e5a8af879 100644 --- a/libs/hwui/renderstate/Blend.h +++ b/libs/hwui/renderstate/Blend.h @@ -34,9 +34,6 @@ public: NoSwap, Swap, }; - - void enable(SkXfermode::Mode mode, ModeOrderSwap modeUsage); - void disable(); void syncEnabled(); static void getFactors(SkXfermode::Mode mode, ModeOrderSwap modeUsage, diff --git a/libs/hwui/renderthread/CanvasContext.cpp b/libs/hwui/renderthread/CanvasContext.cpp index b74b5088c14f..9dc5b45a7738 100644 --- a/libs/hwui/renderthread/CanvasContext.cpp +++ b/libs/hwui/renderthread/CanvasContext.cpp @@ -60,9 +60,10 @@ CanvasContext::CanvasContext(RenderThread& thread, bool translucent, , mEglManager(thread.eglManager()) , mOpaque(!translucent) , mAnimationContext(contextFactory->createAnimationContext(mRenderThread.timeLord())) - , mRootRenderNode(rootRenderNode) , mJankTracker(thread.timeLord().frameIntervalNanos()) - , mProfiler(mFrames) { + , mProfiler(mFrames) + , mContentOverdrawProtectionBounds(0, 0, 0, 0) { + mRenderNodes.emplace_back(rootRenderNode); mRenderThread.renderState().registerCanvasContext(this); mProfiler.setDensity(mRenderThread.mainDisplayInfo().density); } @@ -172,7 +173,8 @@ static bool wasSkipped(FrameInfo* info) { return info && ((*info)[FrameInfoIndex::Flags] & FrameInfoFlags::SkippedFrame); } -void CanvasContext::prepareTree(TreeInfo& info, int64_t* uiFrameInfo, int64_t syncQueued) { +void CanvasContext::prepareTree(TreeInfo& info, int64_t* uiFrameInfo, + int64_t syncQueued, RenderNode* target) { mRenderThread.removeFrameCallback(this); // If the previous frame was dropped we don't need to hold onto it, so @@ -189,7 +191,13 @@ void CanvasContext::prepareTree(TreeInfo& info, int64_t* uiFrameInfo, int64_t sy info.canvasContext = this; mAnimationContext->startFrame(info.mode); - mRootRenderNode->prepareTree(info); + for (const sp<RenderNode>& node : mRenderNodes) { + // Only the primary target node will be drawn full - all other nodes would get drawn in + // real time mode. In case of a window, the primary node is the window content and the other + // node(s) are non client / filler nodes. + info.mode = (node.get() == target ? TreeInfo::MODE_FULL : TreeInfo::MODE_RT_ONLY); + node->prepareTree(info); + } mAnimationContext->runRemainingAnimations(info); freePrefetechedLayers(); @@ -299,7 +307,95 @@ void CanvasContext::draw() { dirty.fLeft, dirty.fTop, dirty.fRight, dirty.fBottom, mOpaque); Rect outBounds; - mCanvas->drawRenderNode(mRootRenderNode.get(), outBounds); + // It there are multiple render nodes, they are as follows: + // #0 - backdrop + // #1 - content (with - and clipped to - bounds mContentOverdrawProtectionBounds) + // #2 - frame + // Usually the backdrop cannot be seen since it will be entirely covered by the content. While + // resizing however it might become partially visible. The following render loop will crop the + // backdrop against the content and draw the remaining part of it. It will then crop the content + // against the backdrop (since that indicates a shrinking of the window) and then the frame + // around everything. + // The bounds of the backdrop against which the content should be clipped. + Rect backdropBounds = mContentOverdrawProtectionBounds; + // If there is no content bounds we ignore the layering as stated above and start with 2. + int layer = mContentOverdrawProtectionBounds.isEmpty() ? 2 : 0; + // Draw all render nodes. Note that + for (const sp<RenderNode>& node : mRenderNodes) { + if (layer == 0) { // Backdrop. + // Draw the backdrop clipped to the inverse content bounds. + const RenderProperties& properties = node->properties(); + Rect targetBounds(properties.getLeft(), properties.getTop(), + properties.getRight(), properties.getBottom()); + // Remember the intersection of the target bounds and the intersection bounds against + // which we have to crop the content. + backdropBounds.intersect(targetBounds); + // Check if we have to draw something on the left side ... + if (targetBounds.left < mContentOverdrawProtectionBounds.left) { + mCanvas->save(SkCanvas::kClip_SaveFlag); + if (mCanvas->clipRect(targetBounds.left, targetBounds.top, + mContentOverdrawProtectionBounds.left, targetBounds.bottom, + SkRegion::kIntersect_Op)) { + mCanvas->drawRenderNode(node.get(), outBounds); + } + // Reduce the target area by the area we have just painted. + targetBounds.left = std::min(mContentOverdrawProtectionBounds.left, + targetBounds.right); + mCanvas->restore(); + } + // ... or on the right side ... + if (targetBounds.right > mContentOverdrawProtectionBounds.right && + !targetBounds.isEmpty()) { + mCanvas->save(SkCanvas::kClip_SaveFlag); + if (mCanvas->clipRect(mContentOverdrawProtectionBounds.right, targetBounds.top, + targetBounds.right, targetBounds.bottom, + SkRegion::kIntersect_Op)) { + mCanvas->drawRenderNode(node.get(), outBounds); + } + // Reduce the target area by the area we have just painted. + targetBounds.right = std::max(targetBounds.left, + mContentOverdrawProtectionBounds.right); + mCanvas->restore(); + } + // ... or at the top ... + if (targetBounds.top < mContentOverdrawProtectionBounds.top && + !targetBounds.isEmpty()) { + mCanvas->save(SkCanvas::kClip_SaveFlag); + if (mCanvas->clipRect(targetBounds.left, targetBounds.top, targetBounds.right, + mContentOverdrawProtectionBounds.top, + SkRegion::kIntersect_Op)) { + mCanvas->drawRenderNode(node.get(), outBounds); + } + // Reduce the target area by the area we have just painted. + targetBounds.top = std::min(mContentOverdrawProtectionBounds.top, + targetBounds.bottom); + mCanvas->restore(); + } + // ... or at the bottom. + if (targetBounds.bottom > mContentOverdrawProtectionBounds.bottom && + !targetBounds.isEmpty()) { + mCanvas->save(SkCanvas::kClip_SaveFlag); + if (mCanvas->clipRect(targetBounds.left, + mContentOverdrawProtectionBounds.bottom, targetBounds.right, + targetBounds.bottom, SkRegion::kIntersect_Op)) { + mCanvas->drawRenderNode(node.get(), outBounds); + } + mCanvas->restore(); + } + } else if (layer == 1) { // Content + // It gets cropped against the bounds of the backdrop to stay inside. + mCanvas->save(SkCanvas::kClip_SaveFlag); + if (mCanvas->clipRect(backdropBounds.left, backdropBounds.top, + backdropBounds.right, backdropBounds.bottom, + SkRegion::kIntersect_Op)) { + mCanvas->drawRenderNode(node.get(), outBounds); + } + mCanvas->restore(); + } else { // draw the rest on top at will! + mCanvas->drawRenderNode(node.get(), outBounds); + } + layer++; + } profiler().draw(mCanvas); @@ -343,7 +439,10 @@ void CanvasContext::doFrame() { if (CC_UNLIKELY(!mCanvas || mEglSurface == EGL_NO_SURFACE)) { return; } + prepareAndDraw(nullptr); +} +void CanvasContext::prepareAndDraw(RenderNode* node) { ATRACE_CALL(); int64_t frameInfo[UI_THREAD_FRAME_INFO_SIZE]; @@ -353,7 +452,7 @@ void CanvasContext::doFrame() { mRenderThread.timeLord().latestVsync()); TreeInfo info(TreeInfo::MODE_RT_ONLY, mRenderThread.renderState()); - prepareTree(info, frameInfo, systemTime(CLOCK_MONOTONIC)); + prepareTree(info, frameInfo, systemTime(CLOCK_MONOTONIC), node); if (info.out.canDrawThisFrame) { draw(); } @@ -423,7 +522,9 @@ void CanvasContext::destroyHardwareResources() { stopDrawing(); if (mEglManager.hasEglContext()) { freePrefetechedLayers(); - mRootRenderNode->destroyHardwareResources(); + for (const sp<RenderNode>& node : mRenderNodes) { + node->destroyHardwareResources(); + } Caches& caches = Caches::getInstance(); // Make sure to release all the textures we were owning as there won't // be another draw diff --git a/libs/hwui/renderthread/CanvasContext.h b/libs/hwui/renderthread/CanvasContext.h index 6a793203e290..1c3845cac504 100644 --- a/libs/hwui/renderthread/CanvasContext.h +++ b/libs/hwui/renderthread/CanvasContext.h @@ -34,6 +34,7 @@ #include <set> #include <string> +#include <vector> namespace android { namespace uirenderer { @@ -77,12 +78,14 @@ public: void setOpaque(bool opaque); void makeCurrent(); void processLayerUpdate(DeferredLayerUpdater* layerUpdater); - void prepareTree(TreeInfo& info, int64_t* uiFrameInfo, int64_t syncQueued); + void prepareTree(TreeInfo& info, int64_t* uiFrameInfo, + int64_t syncQueued, RenderNode* target); void draw(); void destroy(); // IFrameCallback, Chroreographer-driven frame callback entry point virtual void doFrame() override; + void prepareAndDraw(RenderNode* node); void buildLayer(RenderNode* node); bool copyLayerInto(DeferredLayerUpdater* layer, SkBitmap* bitmap); @@ -113,6 +116,20 @@ public: void serializeDisplayListTree(); + void addRenderNode(RenderNode* node, bool placeFront) { + int pos = placeFront ? 0 : static_cast<int>(mRenderNodes.size()); + mRenderNodes.emplace( mRenderNodes.begin() + pos, node); + } + + void removeRenderNode(RenderNode* node) { + mRenderNodes.erase(std::remove(mRenderNodes.begin(), mRenderNodes.end(), node), + mRenderNodes.end()); + } + + void setContentOverdrawProtectionBounds(int left, int top, int right, int bottom) { + mContentOverdrawProtectionBounds.set(left, top, right, bottom); + } + private: friend class RegisterFrameCallbackTask; // TODO: Replace with something better for layer & other GL object @@ -138,7 +155,7 @@ private: DamageAccumulator mDamageAccumulator; std::unique_ptr<AnimationContext> mAnimationContext; - const sp<RenderNode> mRootRenderNode; + std::vector< sp<RenderNode> > mRenderNodes; FrameInfo* mCurrentFrameInfo = nullptr; // Ring buffer large enough for 2 seconds worth of frames @@ -148,6 +165,9 @@ private: FrameInfoVisualizer mProfiler; std::set<RenderNode*> mPrefetechedLayers; + + // Stores the bounds of the main content. + Rect mContentOverdrawProtectionBounds; }; } /* namespace renderthread */ diff --git a/libs/hwui/renderthread/DrawFrameTask.cpp b/libs/hwui/renderthread/DrawFrameTask.cpp index 198906ca845e..a47c9ecf8b31 100644 --- a/libs/hwui/renderthread/DrawFrameTask.cpp +++ b/libs/hwui/renderthread/DrawFrameTask.cpp @@ -38,9 +38,11 @@ DrawFrameTask::DrawFrameTask() DrawFrameTask::~DrawFrameTask() { } -void DrawFrameTask::setContext(RenderThread* thread, CanvasContext* context) { +void DrawFrameTask::setContext(RenderThread* thread, CanvasContext* context, + RenderNode* targetNode) { mRenderThread = thread; mContext = context; + mTargetNode = targetNode; } void DrawFrameTask::pushLayerUpdate(DeferredLayerUpdater* layer) { @@ -118,7 +120,7 @@ bool DrawFrameTask::syncFrameState(TreeInfo& info) { mContext->processLayerUpdate(mLayers[i].get()); } mLayers.clear(); - mContext->prepareTree(info, mFrameInfo, mSyncQueued); + mContext->prepareTree(info, mFrameInfo, mSyncQueued, mTargetNode); // This is after the prepareTree so that any pending operations // (RenderNode tree state, prefetched layers, etc...) will be flushed. diff --git a/libs/hwui/renderthread/DrawFrameTask.h b/libs/hwui/renderthread/DrawFrameTask.h index ebefcba9f6a5..68ee897e3b8e 100644 --- a/libs/hwui/renderthread/DrawFrameTask.h +++ b/libs/hwui/renderthread/DrawFrameTask.h @@ -57,7 +57,7 @@ public: DrawFrameTask(); virtual ~DrawFrameTask(); - void setContext(RenderThread* thread, CanvasContext* context); + void setContext(RenderThread* thread, CanvasContext* context, RenderNode* targetNode); void pushLayerUpdate(DeferredLayerUpdater* layer); void removeLayerUpdate(DeferredLayerUpdater* layer); @@ -78,6 +78,7 @@ private: RenderThread* mRenderThread; CanvasContext* mContext; + RenderNode* mTargetNode = nullptr; /********************************************* * Single frame data diff --git a/libs/hwui/renderthread/EglManager.cpp b/libs/hwui/renderthread/EglManager.cpp index d2ce49f800fc..c9b9637dd52e 100644 --- a/libs/hwui/renderthread/EglManager.cpp +++ b/libs/hwui/renderthread/EglManager.cpp @@ -20,6 +20,7 @@ #include "Properties.h" #include "RenderThread.h" #include "renderstate/RenderState.h" +#include "utils/StringUtils.h" #include <cutils/log.h> #include <cutils/properties.h> @@ -133,12 +134,9 @@ void EglManager::initialize() { } void EglManager::initExtensions() { - std::string extensions(eglQueryString(mEglDisplay, EGL_EXTENSIONS)); - auto has = [&](const char* ext) { - return extensions.find(ext) != std::string::npos; - }; - EglExtensions.bufferAge = has("EGL_EXT_buffer_age"); - EglExtensions.setDamage = has("EGL_KHR_partial_update"); + StringCollection extensions(eglQueryString(mEglDisplay, EGL_EXTENSIONS)); + EglExtensions.bufferAge = extensions.has("EGL_EXT_buffer_age"); + EglExtensions.setDamage = extensions.has("EGL_KHR_partial_update"); } bool EglManager::hasEglContext() { diff --git a/libs/hwui/renderthread/RenderProxy.cpp b/libs/hwui/renderthread/RenderProxy.cpp index b8388116ff80..f43a769890a4 100644 --- a/libs/hwui/renderthread/RenderProxy.cpp +++ b/libs/hwui/renderthread/RenderProxy.cpp @@ -74,7 +74,7 @@ RenderProxy::RenderProxy(bool translucent, RenderNode* rootRenderNode, IContextF args->thread = &mRenderThread; args->contextFactory = contextFactory; mContext = (CanvasContext*) postAndWait(task); - mDrawFrameTask.setContext(&mRenderThread, mContext); + mDrawFrameTask.setContext(&mRenderThread, mContext, rootRenderNode); } RenderProxy::~RenderProxy() { @@ -91,7 +91,7 @@ void RenderProxy::destroyContext() { SETUP_TASK(destroyContext); args->context = mContext; mContext = nullptr; - mDrawFrameTask.setContext(nullptr, nullptr); + mDrawFrameTask.setContext(nullptr, nullptr, nullptr); // This is also a fence as we need to be certain that there are no // outstanding mDrawFrame tasks posted before it is destroyed postAndWait(task); @@ -461,7 +461,8 @@ void RenderProxy::dumpGraphicsMemory(int fd) { staticPostAndWait(task); } -CREATE_BRIDGE4(setTextureAtlas, RenderThread* thread, GraphicBuffer* buffer, int64_t* map, size_t size) { +CREATE_BRIDGE4(setTextureAtlas, RenderThread* thread, GraphicBuffer* buffer, int64_t* map, + size_t size) { CanvasContext::setTextureAtlas(*args->thread, args->buffer, args->map, args->size); args->buffer->decStrong(nullptr); return nullptr; @@ -490,6 +491,61 @@ void RenderProxy::setProcessStatsBuffer(int fd) { post(task); } +CREATE_BRIDGE3(addRenderNode, CanvasContext* context, RenderNode* node, bool placeFront) { + args->context->addRenderNode(args->node, args->placeFront); + return nullptr; +} + +void RenderProxy::addRenderNode(RenderNode* node, bool placeFront) { + SETUP_TASK(addRenderNode); + args->context = mContext; + args->node = node; + args->placeFront = placeFront; + post(task); +} + +CREATE_BRIDGE2(removeRenderNode, CanvasContext* context, RenderNode* node) { + args->context->removeRenderNode(args->node); + return nullptr; +} + +void RenderProxy::removeRenderNode(RenderNode* node) { + SETUP_TASK(removeRenderNode); + args->context = mContext; + args->node = node; + post(task); +} + +CREATE_BRIDGE2(drawRenderNode, CanvasContext* context, RenderNode* node) { + args->context->prepareAndDraw(args->node); + return nullptr; +} + +void RenderProxy::drawRenderNode(RenderNode* node) { + SETUP_TASK(drawRenderNode); + args->context = mContext; + args->node = node; + // Be pseudo-thread-safe and don't use any member variables + staticPostAndWait(task); +} + +CREATE_BRIDGE5(setContentOverdrawProtectionBounds, CanvasContext* context, int left, int top, + int right, int bottom) { + args->context->setContentOverdrawProtectionBounds(args->left, args->top, args->right, + args->bottom); + return nullptr; +} + +void RenderProxy::setContentOverdrawProtectionBounds(int left, int top, int right, int bottom) { + SETUP_TASK(setContentOverdrawProtectionBounds); + args->context = mContext; + args->left = left; + args->top = top; + args->right = right; + args->bottom = bottom; + staticPostAndWait(task); +} + CREATE_BRIDGE1(serializeDisplayListTree, CanvasContext* context) { args->context->serializeDisplayListTree(); return nullptr; diff --git a/libs/hwui/renderthread/RenderProxy.h b/libs/hwui/renderthread/RenderProxy.h index e7356dbb0373..046f24ac3f81 100644 --- a/libs/hwui/renderthread/RenderProxy.h +++ b/libs/hwui/renderthread/RenderProxy.h @@ -106,6 +106,11 @@ public: ANDROID_API void serializeDisplayListTree(); + ANDROID_API void addRenderNode(RenderNode* node, bool placeFront); + ANDROID_API void removeRenderNode(RenderNode* node); + ANDROID_API void drawRenderNode(RenderNode* node); + ANDROID_API void setContentOverdrawProtectionBounds(int left, int top, int right, int bottom); + private: RenderThread& mRenderThread; CanvasContext* mContext; diff --git a/libs/hwui/unit_tests/StringUtilsTests.cpp b/libs/hwui/unit_tests/StringUtilsTests.cpp new file mode 100644 index 000000000000..5174ae99e71e --- /dev/null +++ b/libs/hwui/unit_tests/StringUtilsTests.cpp @@ -0,0 +1,41 @@ +/* + * Copyright (C) 2015 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <gtest/gtest.h> + +#include "utils/StringUtils.h" + +namespace android { +namespace uirenderer { + +TEST(StringUtils, simpleBuildSet) { + StringCollection collection("a b c"); + + EXPECT_TRUE(collection.has("a")); + EXPECT_TRUE(collection.has("b")); + EXPECT_TRUE(collection.has("c")); + EXPECT_FALSE(collection.has("d")); +} + +TEST(StringUtils, advancedBuildSet) { + StringCollection collection("GL_ext1 GL_ext2 GL_ext3"); + + EXPECT_TRUE(collection.has("GL_ext1")); + EXPECT_FALSE(collection.has("GL_ext")); // string present, but not in list +} + +}; +}; diff --git a/libs/hwui/utils/StringUtils.cpp b/libs/hwui/utils/StringUtils.cpp new file mode 100644 index 000000000000..a1df0e7966a9 --- /dev/null +++ b/libs/hwui/utils/StringUtils.cpp @@ -0,0 +1,40 @@ +/* + * Copyright (C) 2015 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "StringUtils.h" + +namespace android { +namespace uirenderer { + +StringCollection::StringCollection(const char* spacedList) { + const char* current = spacedList; + const char* head = current; + do { + head = strchr(current, ' '); + std::string s(current, head ? head - current : strlen(current)); + if (s.length()) { + mSet.insert(s); + } + current = head + 1; + } while (head); +} + +bool StringCollection::has(const char* s) { + return mSet.find(std::string(s)) != mSet.end(); +} + +}; // namespace uirenderer +}; // namespace android diff --git a/libs/hwui/utils/StringUtils.h b/libs/hwui/utils/StringUtils.h new file mode 100644 index 000000000000..ef2a6d5c031a --- /dev/null +++ b/libs/hwui/utils/StringUtils.h @@ -0,0 +1,36 @@ +/* + * Copyright (C) 2015 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#ifndef STRING_UTILS_H +#define STRING_UTILS_H + +#include <string> +#include <unordered_set> + +namespace android { +namespace uirenderer { + +class StringCollection { +public: + StringCollection(const char* spacedList); + bool has(const char* string); +private: + std::unordered_set<std::string> mSet; +}; + +} /* namespace uirenderer */ +} /* namespace android */ + +#endif /* GLUTILS_H */ diff --git a/media/java/android/media/midi/MidiManager.java b/media/java/android/media/midi/MidiManager.java index e72bdb446a65..266b0d97cb53 100644 --- a/media/java/android/media/midi/MidiManager.java +++ b/media/java/android/media/midi/MidiManager.java @@ -169,6 +169,13 @@ public final class MidiManager { /** * Registers a callback to receive notifications when MIDI devices are added and removed. * + * The {@link DeviceCallback#onDeviceStatusChanged} method will be called immediately + * for any devices that have open ports. This allows applications to know which input + * ports are already in use and, therefore, unavailable. + * + * Applications should call {@link #getDevices} before registering the callback + * to get a list of devices already added. + * * @param callback a {@link DeviceCallback} for MIDI device notifications * @param handler The {@link android.os.Handler Handler} that will be used for delivering the * device notifications. If handler is null, then the thread used for the diff --git a/media/jni/android_media_AmrInputStream.cpp b/media/jni/android_media_AmrInputStream.cpp index afb5d5cbba74..b56a3641ac9f 100644 --- a/media/jni/android_media_AmrInputStream.cpp +++ b/media/jni/android_media_AmrInputStream.cpp @@ -119,7 +119,7 @@ static void android_media_AmrInputStream_GsmAmrEncoderDelete // ---------------------------------------------------------------------------- -static JNINativeMethod gMethods[] = { +static const JNINativeMethod gMethods[] = { {"GsmAmrEncoderNew", "()J", (void*)android_media_AmrInputStream_GsmAmrEncoderNew}, {"GsmAmrEncoderInitialize", "(J)V", (void*)android_media_AmrInputStream_GsmAmrEncoderInitialize}, {"GsmAmrEncoderEncode", "(J[BI[BI)I", (void*)android_media_AmrInputStream_GsmAmrEncoderEncode}, diff --git a/media/jni/android_media_ImageReader.cpp b/media/jni/android_media_ImageReader.cpp index 0034b07762a8..3ffdb17f4ec0 100644 --- a/media/jni/android_media_ImageReader.cpp +++ b/media/jni/android_media_ImageReader.cpp @@ -1253,7 +1253,7 @@ static jint Image_getFormat(JNIEnv* env, jobject thiz, jint readerFormat) // ---------------------------------------------------------------------------- -static JNINativeMethod gImageReaderMethods[] = { +static const JNINativeMethod gImageReaderMethods[] = { {"nativeClassInit", "()V", (void*)ImageReader_classInit }, {"nativeInit", "(Ljava/lang/Object;IIII)V", (void*)ImageReader_init }, {"nativeClose", "()V", (void*)ImageReader_close }, @@ -1263,7 +1263,7 @@ static JNINativeMethod gImageReaderMethods[] = { {"nativeDetachImage", "(Landroid/media/Image;)I", (void*)ImageReader_detachImage }, }; -static JNINativeMethod gImageMethods[] = { +static const JNINativeMethod gImageMethods[] = { {"nativeImageGetBuffer", "(II)Ljava/nio/ByteBuffer;", (void*)Image_getByteBuffer }, {"nativeCreatePlane", "(II)Landroid/media/ImageReader$SurfaceImage$SurfacePlane;", (void*)Image_createSurfacePlane }, diff --git a/media/jni/android_media_MediaCodec.cpp b/media/jni/android_media_MediaCodec.cpp index 93a44261281b..e8f680f6a36c 100644 --- a/media/jni/android_media_MediaCodec.cpp +++ b/media/jni/android_media_MediaCodec.cpp @@ -1798,7 +1798,7 @@ static void android_media_MediaCodec_native_finalize( android_media_MediaCodec_release(env, thiz); } -static JNINativeMethod gMethods[] = { +static const JNINativeMethod gMethods[] = { { "native_release", "()V", (void *)android_media_MediaCodec_release }, { "native_reset", "()V", (void *)android_media_MediaCodec_reset }, diff --git a/media/jni/android_media_MediaCodecList.cpp b/media/jni/android_media_MediaCodecList.cpp index 82dd48dffeae..de9bf1f528af 100644 --- a/media/jni/android_media_MediaCodecList.cpp +++ b/media/jni/android_media_MediaCodecList.cpp @@ -286,7 +286,7 @@ static jobject android_media_MediaCodecList_getGlobalSettings(JNIEnv *env, jobje static void android_media_MediaCodecList_native_init(JNIEnv* /* env */) { } -static JNINativeMethod gMethods[] = { +static const JNINativeMethod gMethods[] = { { "native_getCodecCount", "()I", (void *)android_media_MediaCodecList_getCodecCount }, { "getCodecName", "(I)Ljava/lang/String;", (void *)android_media_MediaCodecList_getCodecName }, diff --git a/media/jni/android_media_MediaCrypto.cpp b/media/jni/android_media_MediaCrypto.cpp index d7968d225ab2..e414f4838583 100644 --- a/media/jni/android_media_MediaCrypto.cpp +++ b/media/jni/android_media_MediaCrypto.cpp @@ -316,7 +316,7 @@ static void android_media_MediaCrypto_setMediaDrmSession( } } -static JNINativeMethod gMethods[] = { +static const JNINativeMethod gMethods[] = { { "release", "()V", (void *)android_media_MediaCrypto_release }, { "native_init", "()V", (void *)android_media_MediaCrypto_native_init }, diff --git a/media/jni/android_media_MediaDrm.cpp b/media/jni/android_media_MediaDrm.cpp index 9ec0312d0f2a..275de1ad5ccb 100644 --- a/media/jni/android_media_MediaDrm.cpp +++ b/media/jni/android_media_MediaDrm.cpp @@ -1455,7 +1455,7 @@ static jbyteArray android_media_MediaDrm_signRSANative( } -static JNINativeMethod gMethods[] = { +static const JNINativeMethod gMethods[] = { { "release", "()V", (void *)android_media_MediaDrm_release }, { "native_init", "()V", (void *)android_media_MediaDrm_native_init }, diff --git a/media/jni/android_media_MediaExtractor.cpp b/media/jni/android_media_MediaExtractor.cpp index 4e9b72685223..96c12dd8665b 100644 --- a/media/jni/android_media_MediaExtractor.cpp +++ b/media/jni/android_media_MediaExtractor.cpp @@ -769,7 +769,7 @@ static void android_media_MediaExtractor_native_finalize( android_media_MediaExtractor_release(env, thiz); } -static JNINativeMethod gMethods[] = { +static const JNINativeMethod gMethods[] = { { "release", "()V", (void *)android_media_MediaExtractor_release }, { "getTrackCount", "()I", (void *)android_media_MediaExtractor_getTrackCount }, diff --git a/media/jni/android_media_MediaHTTPConnection.cpp b/media/jni/android_media_MediaHTTPConnection.cpp index 393003d98462..fa0b43fedcef 100644 --- a/media/jni/android_media_MediaHTTPConnection.cpp +++ b/media/jni/android_media_MediaHTTPConnection.cpp @@ -154,7 +154,7 @@ static jint android_media_MediaHTTPConnection_native_readAt( return n; } -static JNINativeMethod gMethods[] = { +static const JNINativeMethod gMethods[] = { { "native_getIMemory", "()Landroid/os/IBinder;", (void *)android_media_MediaHTTPConnection_native_getIMemory }, diff --git a/media/jni/android_media_MediaMetadataRetriever.cpp b/media/jni/android_media_MediaMetadataRetriever.cpp index 59fb6d6f6859..f4e940d6cb21 100644 --- a/media/jni/android_media_MediaMetadataRetriever.cpp +++ b/media/jni/android_media_MediaMetadataRetriever.cpp @@ -467,7 +467,7 @@ static void android_media_MediaMetadataRetriever_native_setup(JNIEnv *env, jobje } // JNI mapping between Java methods and native methods -static JNINativeMethod nativeMethods[] = { +static const JNINativeMethod nativeMethods[] = { { "_setDataSource", "(Landroid/os/IBinder;Ljava/lang/String;[Ljava/lang/String;[Ljava/lang/String;)V", diff --git a/media/jni/android_media_MediaMuxer.cpp b/media/jni/android_media_MediaMuxer.cpp index ecb2ac8a61e8..216624e96ad2 100644 --- a/media/jni/android_media_MediaMuxer.cpp +++ b/media/jni/android_media_MediaMuxer.cpp @@ -219,7 +219,7 @@ static void android_media_MediaMuxer_native_release( } } -static JNINativeMethod gMethods[] = { +static const JNINativeMethod gMethods[] = { { "nativeAddTrack", "(J[Ljava/lang/String;[Ljava/lang/Object;)I", (void *)android_media_MediaMuxer_addTrack }, diff --git a/media/jni/android_media_MediaPlayer.cpp b/media/jni/android_media_MediaPlayer.cpp index d8041f4bff04..be3672968398 100644 --- a/media/jni/android_media_MediaPlayer.cpp +++ b/media/jni/android_media_MediaPlayer.cpp @@ -1033,7 +1033,7 @@ android_media_MediaPlayer_setNextMediaPlayer(JNIEnv *env, jobject thiz, jobject // ---------------------------------------------------------------------------- -static JNINativeMethod gMethods[] = { +static const JNINativeMethod gMethods[] = { { "nativeSetDataSource", "(Landroid/os/IBinder;Ljava/lang/String;[Ljava/lang/String;" diff --git a/media/jni/android_media_MediaProfiles.cpp b/media/jni/android_media_MediaProfiles.cpp index ca9db91c5eed..580004304170 100644 --- a/media/jni/android_media_MediaProfiles.cpp +++ b/media/jni/android_media_MediaProfiles.cpp @@ -301,7 +301,7 @@ android_media_MediaProfiles_native_get_image_encoding_quality_level(JNIEnv *env, } return static_cast<jint>(levels[index]); } -static JNINativeMethod gMethodsForEncoderCapabilitiesClass[] = { +static const JNINativeMethod gMethodsForEncoderCapabilitiesClass[] = { {"native_init", "()V", (void *)android_media_MediaProfiles_native_init}, {"native_get_num_file_formats", "()I", (void *)android_media_MediaProfiles_native_get_num_file_formats}, {"native_get_file_format", "(I)I", (void *)android_media_MediaProfiles_native_get_file_format}, @@ -315,7 +315,7 @@ static JNINativeMethod gMethodsForEncoderCapabilitiesClass[] = { (void *)android_media_MediaProfiles_native_get_audio_encoder_cap}, }; -static JNINativeMethod gMethodsForCamcorderProfileClass[] = { +static const JNINativeMethod gMethodsForCamcorderProfileClass[] = { {"native_init", "()V", (void *)android_media_MediaProfiles_native_init}, {"native_get_camcorder_profile", "(II)Landroid/media/CamcorderProfile;", (void *)android_media_MediaProfiles_native_get_camcorder_profile}, @@ -323,7 +323,7 @@ static JNINativeMethod gMethodsForCamcorderProfileClass[] = { (void *)android_media_MediaProfiles_native_has_camcorder_profile}, }; -static JNINativeMethod gMethodsForDecoderCapabilitiesClass[] = { +static const JNINativeMethod gMethodsForDecoderCapabilitiesClass[] = { {"native_init", "()V", (void *)android_media_MediaProfiles_native_init}, {"native_get_num_video_decoders", "()I", (void *)android_media_MediaProfiles_native_get_num_video_decoders}, {"native_get_num_audio_decoders", "()I", (void *)android_media_MediaProfiles_native_get_num_audio_decoders}, @@ -331,7 +331,7 @@ static JNINativeMethod gMethodsForDecoderCapabilitiesClass[] = { {"native_get_audio_decoder_type", "(I)I", (void *)android_media_MediaProfiles_native_get_audio_decoder_type}, }; -static JNINativeMethod gMethodsForCameraProfileClass[] = { +static const JNINativeMethod gMethodsForCameraProfileClass[] = { {"native_init", "()V", (void *)android_media_MediaProfiles_native_init}, {"native_get_num_image_encoding_quality_levels", "(I)I", (void *)android_media_MediaProfiles_native_get_num_image_encoding_quality_levels}, diff --git a/media/jni/android_media_MediaRecorder.cpp b/media/jni/android_media_MediaRecorder.cpp index f60af63306ba..e05b3483aadc 100644 --- a/media/jni/android_media_MediaRecorder.cpp +++ b/media/jni/android_media_MediaRecorder.cpp @@ -510,7 +510,7 @@ void android_media_MediaRecorder_setInputSurface( // ---------------------------------------------------------------------------- -static JNINativeMethod gMethods[] = { +static const JNINativeMethod gMethods[] = { {"setCamera", "(Landroid/hardware/Camera;)V", (void *)android_media_MediaRecorder_setCamera}, {"setVideoSource", "(I)V", (void *)android_media_MediaRecorder_setVideoSource}, {"setAudioSource", "(I)V", (void *)android_media_MediaRecorder_setAudioSource}, diff --git a/media/jni/android_media_MediaScanner.cpp b/media/jni/android_media_MediaScanner.cpp index 1a9384e6b2c8..0f3c61f53a2c 100644 --- a/media/jni/android_media_MediaScanner.cpp +++ b/media/jni/android_media_MediaScanner.cpp @@ -412,7 +412,7 @@ android_media_MediaScanner_native_finalize(JNIEnv *env, jobject thiz) setNativeScanner_l(env, thiz, 0); } -static JNINativeMethod gMethods[] = { +static const JNINativeMethod gMethods[] = { { "processDirectory", "(Ljava/lang/String;Landroid/media/MediaScannerClient;)V", diff --git a/media/jni/android_media_ResampleInputStream.cpp b/media/jni/android_media_ResampleInputStream.cpp index 1549a301772a..d06baa57071d 100644 --- a/media/jni/android_media_ResampleInputStream.cpp +++ b/media/jni/android_media_ResampleInputStream.cpp @@ -107,7 +107,7 @@ static void android_media_ResampleInputStream_fir21(JNIEnv *env, jclass /* clazz // ---------------------------------------------------------------------------- -static JNINativeMethod gMethods[] = { +static const JNINativeMethod gMethods[] = { {"fir21", "([BI[BII)V", (void*)android_media_ResampleInputStream_fir21}, }; diff --git a/media/jni/android_mtp_MtpDatabase.cpp b/media/jni/android_mtp_MtpDatabase.cpp index 713f28ce5684..ec2f98a4c9b4 100644 --- a/media/jni/android_mtp_MtpDatabase.cpp +++ b/media/jni/android_mtp_MtpDatabase.cpp @@ -1173,12 +1173,12 @@ android_mtp_MtpPropertyGroup_format_date_time(JNIEnv *env, jobject /*thiz*/, jlo // ---------------------------------------------------------------------------- -static JNINativeMethod gMtpDatabaseMethods[] = { +static const JNINativeMethod gMtpDatabaseMethods[] = { {"native_setup", "()V", (void *)android_mtp_MtpDatabase_setup}, {"native_finalize", "()V", (void *)android_mtp_MtpDatabase_finalize}, }; -static JNINativeMethod gMtpPropertyGroupMethods[] = { +static const JNINativeMethod gMtpPropertyGroupMethods[] = { {"format_date_time", "(J)Ljava/lang/String;", (void *)android_mtp_MtpPropertyGroup_format_date_time}, }; diff --git a/media/jni/android_mtp_MtpDevice.cpp b/media/jni/android_mtp_MtpDevice.cpp index 2a46ee72e50c..f11329c7b258 100644 --- a/media/jni/android_mtp_MtpDevice.cpp +++ b/media/jni/android_mtp_MtpDevice.cpp @@ -490,7 +490,7 @@ android_mtp_MtpDevice_send_object_info(JNIEnv *env, jobject thiz, jobject info) // ---------------------------------------------------------------------------- -static JNINativeMethod gMethods[] = { +static const JNINativeMethod gMethods[] = { {"native_open", "(Ljava/lang/String;I)Z", (void *)android_mtp_MtpDevice_open}, {"native_close", "()V", (void *)android_mtp_MtpDevice_close}, diff --git a/media/jni/android_mtp_MtpServer.cpp b/media/jni/android_mtp_MtpServer.cpp index 2ce2a904e0f0..d13187c39846 100644 --- a/media/jni/android_mtp_MtpServer.cpp +++ b/media/jni/android_mtp_MtpServer.cpp @@ -179,7 +179,7 @@ android_mtp_MtpServer_remove_storage(JNIEnv *env, jobject thiz, jint storageId) // ---------------------------------------------------------------------------- -static JNINativeMethod gMethods[] = { +static const JNINativeMethod gMethods[] = { {"native_setup", "(Landroid/mtp/MtpDatabase;Z)V", (void *)android_mtp_MtpServer_setup}, {"native_run", "()V", (void *)android_mtp_MtpServer_run}, diff --git a/media/jni/audioeffect/android_media_AudioEffect.cpp b/media/jni/audioeffect/android_media_AudioEffect.cpp index aba4bbeb1e70..fa6913573add 100644 --- a/media/jni/audioeffect/android_media_AudioEffect.cpp +++ b/media/jni/audioeffect/android_media_AudioEffect.cpp @@ -879,7 +879,7 @@ android_media_AudioEffect_native_queryPreProcessings(JNIEnv *env, jclass clazz _ // ---------------------------------------------------------------------------- // Dalvik VM type signatures -static JNINativeMethod gMethods[] = { +static const JNINativeMethod gMethods[] = { {"native_init", "()V", (void *)android_media_AudioEffect_native_init}, {"native_setup", "(Ljava/lang/Object;Ljava/lang/String;Ljava/lang/String;II[I[Ljava/lang/Object;Ljava/lang/String;)I", (void *)android_media_AudioEffect_native_setup}, diff --git a/media/jni/audioeffect/android_media_Visualizer.cpp b/media/jni/audioeffect/android_media_Visualizer.cpp index 05570195752b..3d3adba609c0 100644 --- a/media/jni/audioeffect/android_media_Visualizer.cpp +++ b/media/jni/audioeffect/android_media_Visualizer.cpp @@ -677,7 +677,7 @@ android_media_setPeriodicCapture(JNIEnv *env, jobject thiz, jint rate, jboolean // ---------------------------------------------------------------------------- // Dalvik VM type signatures -static JNINativeMethod gMethods[] = { +static const JNINativeMethod gMethods[] = { {"native_init", "()V", (void *)android_media_visualizer_native_init}, {"native_setup", "(Ljava/lang/Object;I[ILjava/lang/String;)I", (void *)android_media_visualizer_native_setup}, diff --git a/media/packages/BluetoothMidiService/src/com/android/bluetoothmidiservice/BluetoothMidiDevice.java b/media/packages/BluetoothMidiService/src/com/android/bluetoothmidiservice/BluetoothMidiDevice.java index e6d59e4fb141..444705cfc79f 100644 --- a/media/packages/BluetoothMidiService/src/com/android/bluetoothmidiservice/BluetoothMidiDevice.java +++ b/media/packages/BluetoothMidiService/src/com/android/bluetoothmidiservice/BluetoothMidiDevice.java @@ -147,14 +147,22 @@ public final class BluetoothMidiDevice { // switch to receiving notifications after initial characteristic read mBluetoothGatt.setCharacteristicNotification(characteristic, true); + // Use writeType that requests acknowledgement. + // This improves compatibility with various BLE-MIDI devices. + int originalWriteType = characteristic.getWriteType(); + characteristic.setWriteType(BluetoothGattCharacteristic.WRITE_TYPE_DEFAULT); + BluetoothGattDescriptor descriptor = characteristic.getDescriptor( CLIENT_CHARACTERISTIC_CONFIG); if (descriptor != null) { descriptor.setValue(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE); - mBluetoothGatt.writeDescriptor(descriptor); + boolean result = mBluetoothGatt.writeDescriptor(descriptor); + Log.d(TAG, "writeDescriptor returned " + result); } else { Log.e(TAG, "No CLIENT_CHARACTERISTIC_CONFIG for device " + mBluetoothDevice); } + + characteristic.setWriteType(originalWriteType); } @Override diff --git a/packages/CaptivePortalLogin/src/com/android/captiveportallogin/CaptivePortalLoginActivity.java b/packages/CaptivePortalLogin/src/com/android/captiveportallogin/CaptivePortalLoginActivity.java index 0fe5509b95ce..abb464eb3a67 100644 --- a/packages/CaptivePortalLogin/src/com/android/captiveportallogin/CaptivePortalLoginActivity.java +++ b/packages/CaptivePortalLogin/src/com/android/captiveportallogin/CaptivePortalLoginActivity.java @@ -76,8 +76,9 @@ public class CaptivePortalLoginActivity extends Activity { String server = Settings.Global.getString(getContentResolver(), "captive_portal_server"); if (server == null) server = DEFAULT_SERVER; mCm = ConnectivityManager.from(this); + String url = getIntent().getStringExtra(ConnectivityManager.EXTRA_CAPTIVE_PORTAL_URL); try { - mURL = new URL("http", server, "/generate_204"); + mURL = url != null ? new URL(url) : new URL("http", server, "/generate_204"); } catch (MalformedURLException e) { // System misconfigured, bail out in a way that at least provides network access. Log.e(TAG, "Invalid captive portal URL, server=" + server); diff --git a/packages/DocumentsUI/AndroidManifest.xml b/packages/DocumentsUI/AndroidManifest.xml index 97bc8fd4d1f4..ac6f950a0a82 100644 --- a/packages/DocumentsUI/AndroidManifest.xml +++ b/packages/DocumentsUI/AndroidManifest.xml @@ -35,11 +35,6 @@ <action android:name="android.intent.action.OPEN_DOCUMENT_TREE" /> <category android:name="android.intent.category.DEFAULT" /> </intent-filter> - <intent-filter> - <action android:name="android.provider.action.BROWSE_DOCUMENT_ROOT" /> - <category android:name="android.intent.category.DEFAULT" /> - <data android:mimeType="vnd.android.document/root" /> - </intent-filter> </activity> <activity @@ -63,6 +58,11 @@ <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> + <intent-filter> + <action android:name="android.provider.action.BROWSE_DOCUMENT_ROOT" /> + <category android:name="android.intent.category.DEFAULT" /> + <data android:mimeType="vnd.android.document/root" /> + </intent-filter> </activity> <provider diff --git a/packages/DocumentsUI/res/drawable/progress_indeterminate_horizontal_material_trimmed.xml b/packages/DocumentsUI/res/drawable/progress_indeterminate_horizontal_material_trimmed.xml new file mode 100644 index 000000000000..070b9a10351c --- /dev/null +++ b/packages/DocumentsUI/res/drawable/progress_indeterminate_horizontal_material_trimmed.xml @@ -0,0 +1,28 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Copyright (C) 2015 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> + +<!-- Variant of progress_indeterminate_horizontal_material in frameworks/base/core/res, which + draws the whole height of the progress bar instead having blank space above and below the + bar. --> +<animated-vector xmlns:android="http://schemas.android.com/apk/res/android" + android:drawable="@drawable/vector_drawable_progress_indeterminate_horizontal_trimmed" > + <target + android:name="rect2_grp" + android:animation="@*android:anim/progress_indeterminate_horizontal_rect2" /> + <target + android:name="rect1_grp" + android:animation="@*android:anim/progress_indeterminate_horizontal_rect1" /> +</animated-vector> diff --git a/packages/DocumentsUI/res/drawable/vector_drawable_progress_indeterminate_horizontal_trimmed.xml b/packages/DocumentsUI/res/drawable/vector_drawable_progress_indeterminate_horizontal_trimmed.xml new file mode 100644 index 000000000000..39e3a3738e28 --- /dev/null +++ b/packages/DocumentsUI/res/drawable/vector_drawable_progress_indeterminate_horizontal_trimmed.xml @@ -0,0 +1,53 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Copyright (C) 2015 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> + +<!-- Variant of vector_drawable_progress_indeterminate_horizontal in frameworks/base/core/res, which + draws the whole height of the progress bar instead having blank space above and below the + bar. --> +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:height="10dp" + android:width="360dp" + android:viewportHeight="10" + android:viewportWidth="360" > + <group + android:name="progress_group" + android:translateX="180" + android:translateY="5" > + <path + android:name="background_track" + android:pathData="M -180.0,-5.0 l 360.0,0 l 0,10.0 l -360.0,0 Z" + android:fillColor="?android:attr/colorControlActivated" + android:fillAlpha="?android:attr/disabledAlpha"/> + <group + android:name="rect2_grp" + android:translateX="-197.60001" + android:scaleX="0.1" > + <path + android:name="rect2" + android:pathData="M -144.0,-5.0 l 288.0,0 l 0,10.0 l -288.0,0 Z" + android:fillColor="?android:attr/colorControlActivated" /> + </group> + <group + android:name="rect1_grp" + android:translateX="-522.59998" + android:scaleX="0.1" > + <path + android:name="rect1" + android:pathData="M -144.0,-5.0 l 288.0,0 l 0,10.0 l -288.0,0 Z" + android:fillColor="?android:attr/colorControlActivated" /> + </group> + </group> +</vector> diff --git a/packages/DocumentsUI/res/layout/fragment_directory.xml b/packages/DocumentsUI/res/layout/fragment_directory.xml index f5c73d5269c2..b02349a693f6 100644 --- a/packages/DocumentsUI/res/layout/fragment_directory.xml +++ b/packages/DocumentsUI/res/layout/fragment_directory.xml @@ -28,12 +28,6 @@ android:visibility="gone" style="@android:style/TextAppearance.Material.Subhead" /> - <!-- The 'list' view is still used for RecentsCreateFragment --> - <ListView - android:id="@+id/list" - android:layout_width="match_parent" - android:layout_height="match_parent" /> - <LinearLayout android:id="@+id/content" android:layout_width="match_parent" @@ -41,6 +35,14 @@ android:orientation="vertical" android:animateLayoutChanges="true"> + <ProgressBar + android:id="@+id/progressbar" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:indeterminate="true" + style="@style/TrimmedHorizontalProgressBar" + android:visibility="gone"/> + <FrameLayout android:id="@+id/container_message_bar" android:layout_width="match_parent" @@ -48,12 +50,12 @@ android:elevation="8dp" android:background="@color/material_grey_50" android:visibility="gone"/> - + <!-- This FrameLayout works around b/24189541 --> <FrameLayout android:layout_width="match_parent" android:layout_height="match_parent"> - + <android.support.v7.widget.RecyclerView android:id="@+id/recyclerView" android:scrollbars="vertical" @@ -67,9 +69,9 @@ android:scrollbarStyle="outsideOverlay" android:drawSelectorOnTop="true" android:background="@color/directory_background" /> - + </FrameLayout> - + </LinearLayout> </com.android.documentsui.DirectoryView> diff --git a/packages/DocumentsUI/res/values/styles.xml b/packages/DocumentsUI/res/values/styles.xml index 8301816edaea..c13f144d0717 100644 --- a/packages/DocumentsUI/res/values/styles.xml +++ b/packages/DocumentsUI/res/values/styles.xml @@ -77,14 +77,20 @@ <item name="android:colorPrimaryDark">@color/platform_blue_700</item> <item name="android:colorPrimary">@color/platform_blue_500</item> <item name="android:colorAccent">@color/platform_blue_700</item> + <item name="colorControlActivated">@color/platform_blue_a100</item> <item name="android:actionModeStyle">@style/FilesActionModeStyle</item> <item name="colorActionMode">@color/platform_blue_700</item> - <item name="android:alertDialogTheme">@style/AlertDialogTheme</item> </style> <style name="FilesActionModeStyle" parent="@android:style/Widget.Material.Light.ActionMode"> <item name="android:background">@color/platform_blue_100</item> </style> - + + <style name="TrimmedHorizontalProgressBar" parent="android:Widget.Material.ProgressBar.Horizontal"> + <item name="android:indeterminateDrawable">@drawable/progress_indeterminate_horizontal_material_trimmed</item> + <item name="android:minHeight">3dp</item> + <item name="android:maxHeight">3dp</item> + </style> + </resources> diff --git a/packages/DocumentsUI/src/com/android/documentsui/BaseActivity.java b/packages/DocumentsUI/src/com/android/documentsui/BaseActivity.java index 1e7a42fa7732..1585908e5639 100644 --- a/packages/DocumentsUI/src/com/android/documentsui/BaseActivity.java +++ b/packages/DocumentsUI/src/com/android/documentsui/BaseActivity.java @@ -16,13 +16,6 @@ package com.android.documentsui; -import static com.android.documentsui.BaseActivity.State.ACTION_BROWSE; -import static com.android.documentsui.BaseActivity.State.ACTION_CREATE; -import static com.android.documentsui.BaseActivity.State.ACTION_GET_CONTENT; -import static com.android.documentsui.BaseActivity.State.ACTION_MANAGE; -import static com.android.documentsui.BaseActivity.State.ACTION_OPEN; -import static com.android.documentsui.BaseActivity.State.ACTION_OPEN_COPY_DESTINATION; -import static com.android.documentsui.BaseActivity.State.ACTION_OPEN_TREE; import static com.android.documentsui.DirectoryFragment.ANIM_DOWN; import static com.android.documentsui.DirectoryFragment.ANIM_NONE; import static com.android.documentsui.DirectoryFragment.ANIM_SIDE; @@ -90,6 +83,7 @@ abstract class BaseActivity extends Activity { @LayoutRes private int mLayoutId; private final String mTag; + private DirectoryContainerView mDirectoryContainer; public abstract void onDocumentPicked(DocumentInfo doc, @Nullable DocumentContext siblings); public abstract void onDocumentsPicked(List<DocumentInfo> docs); @@ -116,6 +110,7 @@ abstract class BaseActivity extends Activity { setContentView(mLayoutId); mRoots = DocumentsApplication.getRootsCache(this); + mDirectoryContainer = (DirectoryContainerView) findViewById(R.id.container_directory); mSearchManager = new SearchManager(); // Base classes must update result in their onCreate. @@ -123,22 +118,6 @@ abstract class BaseActivity extends Activity { } @Override - public void onResume() { - super.onResume(); - - final State state = getDisplayState(); - final RootInfo root = getCurrentRoot(); - - // If we're browsing a specific root, and that root went away, then we - // have no reason to hang around - if (state.action == State.ACTION_BROWSE && root != null) { - if (mRoots.getRootBlocking(root.authority, root.rootId) == null) { - finish(); - } - } - } - - @Override public boolean onCreateOptionsMenu(Menu menu) { boolean showMenu = super.onCreateOptionsMenu(menu); @@ -176,8 +155,10 @@ abstract class BaseActivity extends Activity { State state = getDisplayState(); sortSize.setVisible(state.showSize); // Only sort by size when visible + fileSize.setVisible(!state.showSize); grid.setVisible(state.derivedMode != State.MODE_GRID); list.setVisible(state.derivedMode != State.MODE_LIST); + advanced.setVisible(!mState.showAdvanced); settings.setVisible((root.flags & Root.FLAG_HAS_SETTINGS) != 0); return shown; @@ -187,13 +168,17 @@ abstract class BaseActivity extends Activity { State state = new State(); final Intent intent = getIntent(); - final String action = intent.getAction(); state.localOnly = intent.getBooleanExtra(Intent.EXTRA_LOCAL_ONLY, false); + + state.forceSize = intent.getBooleanExtra(DocumentsContract.EXTRA_SHOW_FILESIZE, false); + state.showSize = state.forceSize || LocalPreferences.getDisplayFileSize(this); + state.forceAdvanced = intent.getBooleanExtra(DocumentsContract.EXTRA_SHOW_ADVANCED, false); - state.showAdvanced = state.forceAdvanced || - LocalPreferences.getDisplayAdvancedDevices(this); + state.showAdvanced = state.forceAdvanced + || LocalPreferences.getDisplayAdvancedDevices(this); + state.initAcceptMimes(intent); state.excludedAuthorities = getExcludedAuthorities(); return state; @@ -217,7 +202,7 @@ abstract class BaseActivity extends Activity { if (mRoots.isRecentsRoot(root)) { onCurrentDirectoryChanged(ANIM_SIDE); } else { - new PickRootTask(root).executeOnExecutor(getCurrentExecutor()); + new PickRootTask(root).executeOnExecutor(getExecutorForCurrentDirectory()); } } @@ -316,6 +301,7 @@ abstract class BaseActivity extends Activity { * @param anim */ final void onCurrentDirectoryChanged(int anim) { + mDirectoryContainer.setDrawDisappearingFirst(anim == ANIM_DOWN); onDirectoryChanged(anim); final RootsFragment roots = RootsFragment.get(getFragmentManager()); @@ -396,6 +382,7 @@ abstract class BaseActivity extends Activity { public int derivedSortOrder = SORT_ORDER_DISPLAY_NAME; public boolean allowMultiple; + public boolean forceSize ; public boolean showSize; public boolean localOnly ; public boolean forceAdvanced ; @@ -426,7 +413,6 @@ abstract class BaseActivity extends Activity { public static final int ACTION_OPEN_TREE = 4; public static final int ACTION_MANAGE = 5; public static final int ACTION_BROWSE = 6; - public static final int ACTION_BROWSE_ALL = 7; public static final int ACTION_OPEN_COPY_DESTINATION = 8; public static final int MODE_UNKNOWN = 0; @@ -438,6 +424,15 @@ abstract class BaseActivity extends Activity { public static final int SORT_ORDER_LAST_MODIFIED = 2; public static final int SORT_ORDER_SIZE = 3; + public void initAcceptMimes(Intent intent) { + if (intent.hasExtra(Intent.EXTRA_MIME_TYPES)) { + acceptMimes = intent.getStringArrayExtra(Intent.EXTRA_MIME_TYPES); + } else { + String glob = intent.getType(); + acceptMimes = new String[] { glob != null ? glob : "*/*" }; + } + } + @Override public int describeContents() { return 0; @@ -450,6 +445,7 @@ abstract class BaseActivity extends Activity { out.writeStringArray(acceptMimes); out.writeInt(userSortOrder); out.writeInt(allowMultiple ? 1 : 0); + out.writeInt(forceSize ? 1 : 0); out.writeInt(showSize ? 1 : 0); out.writeInt(localOnly ? 1 : 0); out.writeInt(forceAdvanced ? 1 : 0); @@ -472,6 +468,7 @@ abstract class BaseActivity extends Activity { state.acceptMimes = in.readStringArray(); state.userSortOrder = in.readInt(); state.allowMultiple = in.readInt() != 0; + state.forceSize = in.readInt() != 0; state.showSize = in.readInt() != 0; state.localOnly = in.readInt() != 0; state.forceAdvanced = in.readInt() != 0; @@ -559,7 +556,7 @@ abstract class BaseActivity extends Activity { return getDisplayState().stack.peek(); } - public Executor getCurrentExecutor() { + public Executor getExecutorForCurrentDirectory() { final DocumentInfo cwd = getCurrentDirectory(); if (cwd != null && cwd.authority != null) { return ProviderExecutor.forAuthority(cwd.authority); diff --git a/packages/DocumentsUI/src/com/android/documentsui/DirectoryFragment.java b/packages/DocumentsUI/src/com/android/documentsui/DirectoryFragment.java index c2821e13d7c3..ea8ecf54f31c 100644 --- a/packages/DocumentsUI/src/com/android/documentsui/DirectoryFragment.java +++ b/packages/DocumentsUI/src/com/android/documentsui/DirectoryFragment.java @@ -17,7 +17,6 @@ package com.android.documentsui; import static com.android.documentsui.BaseActivity.State.ACTION_BROWSE; -import static com.android.documentsui.BaseActivity.State.ACTION_BROWSE_ALL; import static com.android.documentsui.BaseActivity.State.ACTION_CREATE; import static com.android.documentsui.BaseActivity.State.ACTION_MANAGE; import static com.android.documentsui.BaseActivity.State.MODE_GRID; @@ -101,7 +100,7 @@ import com.android.documentsui.RecentsProvider.StateColumns; import com.android.documentsui.model.DocumentInfo; import com.android.documentsui.model.DocumentStack; import com.android.documentsui.model.RootInfo; -import com.android.internal.util.Preconditions; + import com.google.common.collect.Lists; import java.util.ArrayList; @@ -135,6 +134,7 @@ public class DirectoryFragment extends Fragment { private static final String EXTRA_IGNORE_STATE = "ignoreState"; private Model mModel; + private Model.UpdateListener mModelUpdateListener = new ModelUpdateListener(); private final Handler mHandler = new Handler(Looper.getMainLooper()); @@ -160,6 +160,7 @@ public class DirectoryFragment extends Fragment { private int mColumnCount = 1; // This will get updated when layout changes. private MessageBar mMessageBar; + private View mProgressBar; public static void showNormal(FragmentManager fm, RootInfo root, DocumentInfo doc, int anim) { show(fm, TYPE_NORMAL, root, doc, null, anim); @@ -223,6 +224,7 @@ public class DirectoryFragment extends Fragment { final View view = inflater.inflate(R.layout.fragment_directory, container, false); mMessageBar = MessageBar.create(getChildFragmentManager()); + mProgressBar = view.findViewById(R.id.progressbar); mEmptyView = view.findViewById(android.R.id.empty); @@ -311,9 +313,8 @@ public class DirectoryFragment extends Fragment { : MultiSelectManager.MODE_SINGLE); selMgr.addCallback(new SelectionModeListener()); - mModel = new Model(context, selMgr); - mModel.setSelectionManager(selMgr); - mModel.addUpdateListener(mAdapter); + mModel = new Model(context, selMgr, mAdapter); + mModel.addUpdateListener(mModelUpdateListener); mType = getArguments().getInt(EXTRA_TYPE); mStateKey = buildStateKey(root, doc); @@ -897,8 +898,7 @@ public class DirectoryFragment extends Fragment { } } - private final class DocumentsAdapter extends RecyclerView.Adapter<DocumentHolder> - implements Model.UpdateListener { + private final class DocumentsAdapter extends RecyclerView.Adapter<DocumentHolder> { private final Context mContext; private final LayoutInflater mInflater; @@ -909,30 +909,6 @@ public class DirectoryFragment extends Fragment { } @Override - public void onModelUpdate(Model model) { - if (model.info != null || model.error != null) { - mMessageBar.setInfo(model.info); - mMessageBar.setError(model.error); - mMessageBar.show(); - } - - if (model.isEmpty()) { - mEmptyView.setVisibility(View.VISIBLE); - } else { - mEmptyView.setVisibility(View.GONE); - } - - notifyDataSetChanged(); - } - - @Override - public void onModelUpdateFailed(Exception e) { - // TODO: deal with catastrophic update failures - String error = getString(R.string.query_error); - notifyDataSetChanged(); - } - - @Override public DocumentHolder onCreateViewHolder(ViewGroup parent, int viewType) { final State state = getDisplayState(DirectoryFragment.this); final LayoutInflater inflater = LayoutInflater.from(getContext()); @@ -1576,9 +1552,9 @@ public class DirectoryFragment extends Fragment { } private FragmentTuner pickFragmentTuner(final State state) { - return state.action == ACTION_BROWSE_ALL + return state.action == ACTION_BROWSE ? new FilesTuner() - : new DefaultTuner(state); + : new DefaultTuner(state.action); } /** @@ -1615,15 +1591,14 @@ public class DirectoryFragment extends Fragment { */ private static final class DefaultTuner implements FragmentTuner { - private final State mState; + private final boolean mManaging; - public DefaultTuner(State state) { - mState = state; + public DefaultTuner(int action) { + mManaging = (action == ACTION_MANAGE); } @Override public void updateActionMenu(Menu menu, int dirType, boolean canDelete) { - Preconditions.checkState(mState.action != ACTION_BROWSE_ALL); final MenuItem open = menu.findItem(R.id.menu_open); final MenuItem share = menu.findItem(R.id.menu_share); @@ -1632,14 +1607,11 @@ public class DirectoryFragment extends Fragment { final MenuItem moveTo = menu.findItem(R.id.menu_move_to); final MenuItem copyToClipboard = menu.findItem(R.id.menu_copy_to_clipboard); - final boolean manageOrBrowse = (mState.action == ACTION_MANAGE - || mState.action == ACTION_BROWSE); - - open.setVisible(!manageOrBrowse); - share.setVisible(manageOrBrowse); - delete.setVisible(manageOrBrowse && canDelete); + open.setVisible(!mManaging); + share.setVisible(mManaging); + delete.setVisible(mManaging && canDelete); // Disable copying from the Recents view. - copyTo.setVisible(manageOrBrowse && dirType != TYPE_RECENT_OPEN); + copyTo.setVisible(mManaging && dirType != TYPE_RECENT_OPEN); moveTo.setVisible(SystemProperties.getBoolean("debug.documentsui.enable_move", false)); // Only shown in files mode. @@ -1656,6 +1628,7 @@ public class DirectoryFragment extends Fragment { private static final class FilesTuner implements FragmentTuner { @Override public void updateActionMenu(Menu menu, int dirType, boolean canDelete) { + menu.findItem(R.id.menu_share).setVisible(true); menu.findItem(R.id.menu_delete).setVisible(canDelete); menu.findItem(R.id.menu_copy_to_clipboard).setVisible(true); @@ -1675,6 +1648,7 @@ public class DirectoryFragment extends Fragment { @VisibleForTesting public static final class Model implements DocumentContext { private MultiSelectManager mSelectionManager; + private RecyclerView.Adapter<?> mViewAdapter; private Context mContext; private int mCursorCount; private boolean mIsLoading; @@ -1684,17 +1658,11 @@ public class DirectoryFragment extends Fragment { @Nullable private String info; @Nullable private String error; - Model(Context context, MultiSelectManager selectionManager) { + Model(Context context, MultiSelectManager selectionManager, + RecyclerView.Adapter<?> viewAdapter) { mContext = context; mSelectionManager = selectionManager; - } - - /** - * Sets the selection manager used by the model. - * TODO: the model should instantiate the selection manager. See onActivityCreated. - */ - void setSelectionManager(MultiSelectManager mgr) { - mSelectionManager = mgr; + mViewAdapter = viewAdapter; } /** @@ -1859,7 +1827,7 @@ public class DirectoryFragment extends Fragment { int position = selected.get(i); if (DEBUG) Log.d(TAG, "Marked position " + position + " for deletion"); mMarkedForDeletion.append(position, true); - mUpdateListener.notifyItemRemoved(position); + mViewAdapter.notifyItemRemoved(position); } } @@ -1874,7 +1842,7 @@ public class DirectoryFragment extends Fragment { for (int i = 0; i < size; ++i) { final int position = mMarkedForDeletion.keyAt(i); mMarkedForDeletion.put(position, false); - mUpdateListener.notifyItemInserted(position); + mViewAdapter.notifyItemInserted(position); } // Then, clear the deletion list. @@ -1957,26 +1925,46 @@ public class DirectoryFragment extends Fragment { mUpdateListener = listener; } - interface UpdateListener { + static class UpdateListener { /** * Called when a successful update has occurred. */ - void onModelUpdate(Model model); + void onModelUpdate(Model model) {} /** * Called when an update has been attempted but failed. */ - void onModelUpdateFailed(Exception e); + void onModelUpdateFailed(Exception e) {} + } + } - /** - * Called when an item has been removed from the model. - */ - void notifyItemRemoved(int position); + private class ModelUpdateListener extends Model.UpdateListener { + @Override + public void onModelUpdate(Model model) { + if (model.info != null || model.error != null) { + mMessageBar.setInfo(model.info); + mMessageBar.setError(model.error); + mMessageBar.show(); + } - /** - * Called when an item has been added to the model. - */ - void notifyItemInserted(int position); + mProgressBar.setVisibility(model.isLoading() ? View.VISIBLE : View.GONE); + + if (model.isEmpty()) { + mEmptyView.setVisibility(View.VISIBLE); + mRecView.setVisibility(View.GONE); + } else { + mEmptyView.setVisibility(View.GONE); + mRecView.setVisibility(View.VISIBLE); + } + + mAdapter.notifyDataSetChanged(); + } + + @Override + public void onModelUpdateFailed(Exception e) { + // TODO: deal with catastrophic update failures + String error = getString(R.string.query_error); + mAdapter.notifyDataSetChanged(); } } } diff --git a/packages/DocumentsUI/src/com/android/documentsui/DocumentsActivity.java b/packages/DocumentsUI/src/com/android/documentsui/DocumentsActivity.java index 1de1c6a57028..dbfcf407e6bd 100644 --- a/packages/DocumentsUI/src/com/android/documentsui/DocumentsActivity.java +++ b/packages/DocumentsUI/src/com/android/documentsui/DocumentsActivity.java @@ -16,7 +16,6 @@ package com.android.documentsui; -import static com.android.documentsui.BaseActivity.State.ACTION_BROWSE; import static com.android.documentsui.BaseActivity.State.ACTION_CREATE; import static com.android.documentsui.BaseActivity.State.ACTION_GET_CONTENT; import static com.android.documentsui.BaseActivity.State.ACTION_OPEN; @@ -28,7 +27,6 @@ import static com.android.documentsui.DirectoryFragment.ANIM_NONE; import android.app.Activity; import android.app.Fragment; import android.app.FragmentManager; -import android.content.ActivityNotFoundException; import android.content.ClipData; import android.content.ComponentName; import android.content.ContentProviderClient; @@ -44,7 +42,6 @@ import android.os.AsyncTask; import android.os.Bundle; import android.os.Parcelable; import android.provider.DocumentsContract; -import android.provider.DocumentsContract.Root; import android.util.Log; import android.view.Menu; import android.view.MenuItem; @@ -75,8 +72,6 @@ public class DocumentsActivity extends BaseActivity { private Toolbar mRootsToolbar; - private DirectoryContainerView mDirectoryContainer; - private ItemSelectedListener mStackListener; private BaseAdapter mStackAdapter; @@ -89,7 +84,7 @@ public class DocumentsActivity extends BaseActivity { super.onCreate(icicle); final Resources res = getResources(); - mShowAsDialog = res.getBoolean(R.bool.show_as_dialog) && mState.action != ACTION_BROWSE; + mShowAsDialog = res.getBoolean(R.bool.show_as_dialog); if (!mShowAsDialog) { setTheme(R.style.DocumentsNonDialogTheme); @@ -114,8 +109,6 @@ public class DocumentsActivity extends BaseActivity { mDrawer = DrawerController.create(this); } - mDirectoryContainer = (DirectoryContainerView) findViewById(R.id.container_directory); - mToolbar = (Toolbar) findViewById(R.id.toolbar); mStackAdapter = new StackAdapter(); @@ -127,14 +120,6 @@ public class DocumentsActivity extends BaseActivity { setActionBar(mToolbar); - // Hide roots when we're managing a specific root - if (mState.action == ACTION_BROWSE) { - mDrawer.lockClosed(); - if (mShowAsDialog) { - findViewById(R.id.container_roots).setVisibility(View.GONE); - } - } - if (mState.action == ACTION_CREATE) { final String mimeType = getIntent().getType(); final String title = getIntent().getStringExtra(Intent.EXTRA_TITLE); @@ -160,12 +145,7 @@ public class DocumentsActivity extends BaseActivity { // In this case, we set the activity title in AsyncTask.onPostExecute(). To prevent // talkback from reading aloud the default title, we clear it here. setTitle(""); - if (mState.action == ACTION_BROWSE) { - final Uri rootUri = getIntent().getData(); - new RestoreRootTask(rootUri).executeOnExecutor(getCurrentExecutor()); - } else { - new RestoreStackTask().execute(); - } + new RestoreStackTask().execute(); } else { onCurrentDirectoryChanged(ANIM_NONE); } @@ -185,8 +165,6 @@ public class DocumentsActivity extends BaseActivity { state.action = ACTION_GET_CONTENT; } else if (Intent.ACTION_OPEN_DOCUMENT_TREE.equals(action)) { state.action = ACTION_OPEN_TREE; - } else if (DocumentsContract.ACTION_BROWSE_DOCUMENT_ROOT.equals(action)) { - state.action = ACTION_BROWSE; } else if (DocumentsIntent.ACTION_OPEN_COPY_DESTINATION.equals(action)) { state.action = ACTION_OPEN_COPY_DESTINATION; } @@ -196,20 +174,6 @@ public class DocumentsActivity extends BaseActivity { Intent.EXTRA_ALLOW_MULTIPLE, false); } - if (state.action == ACTION_BROWSE) { - state.acceptMimes = new String[] { "*/*" }; - state.allowMultiple = true; - } else if (intent.hasExtra(Intent.EXTRA_MIME_TYPES)) { - state.acceptMimes = intent.getStringArrayExtra(Intent.EXTRA_MIME_TYPES); - } else { - state.acceptMimes = new String[] { intent.getType() }; - } - - if (state.action == ACTION_BROWSE) { - state.showSize = true; - } else { - state.showSize = LocalPreferences.getDisplayFileSize(this); - } if (state.action == ACTION_OPEN_COPY_DESTINATION) { state.directoryCopy = intent.getBooleanExtra( BaseActivity.DocumentsIntent.EXTRA_DIRECTORY_COPY, false); @@ -361,11 +325,7 @@ public class DocumentsActivity extends BaseActivity { final MenuItem fileSize = menu.findItem(R.id.menu_file_size); final MenuItem settings = menu.findItem(R.id.menu_settings); - // File size is locked visible for browse because that is the action triggered by Settings, - // where the user is trying to find large files to clean up. - // TODO: instead of setting this according to the action, use a local preference, but - // provide a @hide extra to let callers like Settings force-enable size visibility. - boolean fileSizeVisible = mState.action != ACTION_BROWSE; + boolean fileSizeVisible = mState.showSize && !mState.forceSize; if (mState.action == ACTION_CREATE || mState.action == ACTION_OPEN_TREE || mState.action == ACTION_OPEN_COPY_DESTINATION) { @@ -387,11 +347,9 @@ public class DocumentsActivity extends BaseActivity { createDir.setVisible(false); } - advanced.setVisible(mState.action != ACTION_BROWSE && !mState.forceAdvanced); + advanced.setVisible(!mState.forceAdvanced); fileSize.setVisible(fileSizeVisible); - - settings.setVisible(mState.action == ACTION_BROWSE - && (root.flags & Root.FLAG_HAS_SETTINGS) != 0); + settings.setVisible(false); return true; } @@ -407,8 +365,6 @@ public class DocumentsActivity extends BaseActivity { final RootInfo root = getCurrentRoot(); final DocumentInfo cwd = getCurrentDirectory(); - mDirectoryContainer.setDrawDisappearingFirst(anim == ANIM_DOWN); - if (cwd == null) { // No directory means recents if (mState.action == ACTION_CREATE || @@ -452,11 +408,11 @@ public class DocumentsActivity extends BaseActivity { } void onSaveRequested(DocumentInfo replaceTarget) { - new ExistingFinishTask(replaceTarget.derivedUri).executeOnExecutor(getCurrentExecutor()); + new ExistingFinishTask(replaceTarget.derivedUri).executeOnExecutor(getExecutorForCurrentDirectory()); } void onSaveRequested(String mimeType, String displayName) { - new CreateFinishTask(mimeType, displayName).executeOnExecutor(getCurrentExecutor()); + new CreateFinishTask(mimeType, displayName).executeOnExecutor(getExecutorForCurrentDirectory()); } @Override @@ -472,21 +428,10 @@ public class DocumentsActivity extends BaseActivity { openDirectory(doc); } else if (mState.action == ACTION_OPEN || mState.action == ACTION_GET_CONTENT) { // Explicit file picked, return - new ExistingFinishTask(doc.derivedUri).executeOnExecutor(getCurrentExecutor()); + new ExistingFinishTask(doc.derivedUri).executeOnExecutor(getExecutorForCurrentDirectory()); } else if (mState.action == ACTION_CREATE) { // Replace selected file SaveFragment.get(fm).setReplaceTarget(doc); - } else if (mState.action == ACTION_BROWSE) { - // Go straight to viewing - final Intent view = new Intent(Intent.ACTION_VIEW); - view.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); - view.setData(doc.derivedUri); - - try { - startActivity(view); - } catch (ActivityNotFoundException ex) { - Toast.makeText(this, R.string.toast_no_application, Toast.LENGTH_SHORT).show(); - } } } @@ -498,7 +443,7 @@ public class DocumentsActivity extends BaseActivity { for (int i = 0; i < size; i++) { uris[i] = docs.get(i).derivedUri; } - new ExistingFinishTask(uris).executeOnExecutor(getCurrentExecutor()); + new ExistingFinishTask(uris).executeOnExecutor(getExecutorForCurrentDirectory()); } } @@ -513,7 +458,7 @@ public class DocumentsActivity extends BaseActivity { // Should not be reached. throw new IllegalStateException("Invalid mState.action."); } - new PickFinishTask(result).executeOnExecutor(getCurrentExecutor()); + new PickFinishTask(result).executeOnExecutor(getExecutorForCurrentDirectory()); } @Override diff --git a/packages/DocumentsUI/src/com/android/documentsui/FilesActivity.java b/packages/DocumentsUI/src/com/android/documentsui/FilesActivity.java index 450def799a1a..7e9531b777fa 100644 --- a/packages/DocumentsUI/src/com/android/documentsui/FilesActivity.java +++ b/packages/DocumentsUI/src/com/android/documentsui/FilesActivity.java @@ -16,8 +16,9 @@ package com.android.documentsui; -import static com.android.documentsui.DirectoryFragment.ANIM_DOWN; import static com.android.documentsui.DirectoryFragment.ANIM_NONE; +import static com.android.documentsui.Shared.DEBUG; +import static com.android.internal.util.Preconditions.checkArgument; import android.app.Activity; import android.app.FragmentManager; @@ -25,11 +26,9 @@ import android.content.ActivityNotFoundException; import android.content.ClipData; import android.content.ContentResolver; import android.content.ContentValues; -import android.content.Context; import android.content.Intent; import android.net.Uri; import android.os.Bundle; -import android.provider.DocumentsContract; import android.support.annotation.Nullable; import android.util.Log; import android.view.KeyEvent; @@ -46,7 +45,6 @@ import com.android.documentsui.model.DocumentInfo; import com.android.documentsui.model.DocumentStack; import com.android.documentsui.model.DurableUtils; import com.android.documentsui.model.RootInfo; -import com.android.internal.util.Preconditions; import java.util.ArrayList; import java.util.Arrays; @@ -58,11 +56,9 @@ import java.util.List; public class FilesActivity extends BaseActivity { public static final String TAG = "FilesActivity"; - static final boolean DEBUG = false; private Toolbar mToolbar; private Spinner mToolbarStack; - private DirectoryContainerView mDirectoryContainer; private ItemSelectedListener mStackListener; private BaseAdapter mStackAdapter; private DocumentClipper mClipper; @@ -75,10 +71,6 @@ public class FilesActivity extends BaseActivity { public void onCreate(Bundle icicle) { super.onCreate(icicle); - final Context context = this; - - mDirectoryContainer = (DirectoryContainerView) findViewById(R.id.container_directory); - mToolbar = (Toolbar) findViewById(R.id.toolbar); mStackAdapter = new StackAdapter(); @@ -93,7 +85,16 @@ public class FilesActivity extends BaseActivity { RootsFragment.show(getFragmentManager(), null); if (!mState.restored) { - new RestoreStackTask().execute(); + Uri rootUri = getIntent().getData(); + + // If we've got a specific root to display, restore that root using a dedicated + // authority. That way a misbehaving provider won't result in an ANR. + if (rootUri != null) { + new RestoreRootTask(rootUri).executeOnExecutor( + ProviderExecutor.forAuthority(rootUri.getAuthority())); + } else { + new RestoreStackTask().execute(); + } // Show a failure dialog if there was a failed operation. final Intent intent = getIntent(); @@ -118,22 +119,16 @@ public class FilesActivity extends BaseActivity { final Intent intent = getIntent(); - state.action = State.ACTION_BROWSE_ALL; - state.acceptMimes = new String[] { intent.getType() }; + state.action = State.ACTION_BROWSE; state.allowMultiple = true; - // These options are specific to the DocumentsActivity. - Preconditions.checkArgument( - !intent.hasExtra(Intent.EXTRA_LOCAL_ONLY)); - Preconditions.checkArgument( - !intent.hasExtra(DocumentsContract.EXTRA_SHOW_ADVANCED)); - - state.showAdvanced = LocalPreferences.getDisplayAdvancedDevices(this); - state.showSize = LocalPreferences.getDisplayFileSize(this); + // Options specific to the DocumentsActivity. + checkArgument(!intent.hasExtra(Intent.EXTRA_LOCAL_ONLY)); final DocumentStack stack = intent.getParcelableExtra(CopyService.EXTRA_STACK); - if (stack != null) + if (stack != null) { state.stack = stack; + } return state; } @@ -145,6 +140,21 @@ public class FilesActivity extends BaseActivity { } @Override + public void onResume() { + super.onResume(); + + final RootInfo root = getCurrentRoot(); + + // If we're browsing a specific root, and that root went away, then we + // have no reason to hang around. + // TODO: Rather than just disappearing, maybe we should inform + // the user what has happened, let them close us. Less surprising. + if (mRoots.getRootBlocking(root.authority, root.rootId) == null) { + finish(); + } + } + + @Override public void updateActionBar() { final RootInfo root = getCurrentRoot(); @@ -197,12 +207,8 @@ public class FilesActivity extends BaseActivity { public boolean onPrepareOptionsMenu(Menu menu) { boolean shown = super.onPrepareOptionsMenu(menu); - menu.findItem(R.id.menu_file_size).setVisible(true); - menu.findItem(R.id.menu_advanced).setVisible(true); - final MenuItem pasteFromCb = menu.findItem(R.id.menu_paste_from_clipboard); final MenuItem createDir = menu.findItem(R.id.menu_create_dir); - final MenuItem settings = menu.findItem(R.id.menu_settings); boolean canCreateDir = canCreateDirectory(); @@ -235,8 +241,6 @@ public class FilesActivity extends BaseActivity { final RootInfo root = getCurrentRoot(); final DocumentInfo cwd = getCurrentDirectory(); - mDirectoryContainer.setDrawDisappearingFirst(anim == ANIM_DOWN); - if (cwd == null) { DirectoryFragment.showRecentsOpen(fm, anim); diff --git a/packages/DocumentsUI/src/com/android/documentsui/ManageRootActivity.java b/packages/DocumentsUI/src/com/android/documentsui/ManageRootActivity.java index 740157829d3f..f5b1d8e67dd4 100644 --- a/packages/DocumentsUI/src/com/android/documentsui/ManageRootActivity.java +++ b/packages/DocumentsUI/src/com/android/documentsui/ManageRootActivity.java @@ -56,8 +56,6 @@ public class ManageRootActivity extends BaseActivity { private Toolbar mToolbar; private Spinner mToolbarStack; - private DirectoryContainerView mDirectoryContainer; - private ItemSelectedListener mStackListener; private BaseAdapter mStackAdapter; @@ -73,8 +71,6 @@ public class ManageRootActivity extends BaseActivity { mDrawer = DrawerController.createDummy(); - mDirectoryContainer = (DirectoryContainerView) findViewById(R.id.container_directory); - mToolbar = (Toolbar) findViewById(R.id.toolbar); mToolbar.setTitleTextAppearance(context, android.R.style.TextAppearance_DeviceDefault_Widget_ActionBar_Title); @@ -91,7 +87,7 @@ public class ManageRootActivity extends BaseActivity { // talkback from reading aloud the default title, we clear it here. setTitle(""); final Uri rootUri = getIntent().getData(); - new RestoreRootTask(rootUri).executeOnExecutor(getCurrentExecutor()); + new RestoreRootTask(rootUri).executeOnExecutor(getExecutorForCurrentDirectory()); } else { onCurrentDirectoryChanged(ANIM_NONE); } @@ -157,7 +153,6 @@ public class ManageRootActivity extends BaseActivity { // If started in manage roots mode, there has to be a cwd (i.e. the root dir of the managed // root). Preconditions.checkNotNull(cwd); - mDirectoryContainer.setDrawDisappearingFirst(anim == ANIM_DOWN); if (mState.currentSearch != null) { // Ongoing search diff --git a/packages/DocumentsUI/src/com/android/documentsui/MessageBar.java b/packages/DocumentsUI/src/com/android/documentsui/MessageBar.java index a48fd5c268b4..312d53b9dc1c 100644 --- a/packages/DocumentsUI/src/com/android/documentsui/MessageBar.java +++ b/packages/DocumentsUI/src/com/android/documentsui/MessageBar.java @@ -69,7 +69,7 @@ public class MessageBar extends Fragment { * message bar layout will be adjusted accordingly. */ public void setError(@Nullable String error) { - View errorView = mView.findViewById(R.id.container_message_bar); + View errorView = mView.findViewById(R.id.container_error); if (error != null) { TextView errorText = (TextView) mView.findViewById(R.id.textview_error); errorText.setText(error); diff --git a/packages/DocumentsUI/src/com/android/documentsui/MultiSelectManager.java b/packages/DocumentsUI/src/com/android/documentsui/MultiSelectManager.java index 5930056f111c..583994351a0c 100644 --- a/packages/DocumentsUI/src/com/android/documentsui/MultiSelectManager.java +++ b/packages/DocumentsUI/src/com/android/documentsui/MultiSelectManager.java @@ -45,6 +45,8 @@ import android.view.View; import com.android.documentsui.Events.InputEvent; import com.android.documentsui.Events.MotionInputEvent; +import com.google.android.collect.Lists; + import java.util.ArrayList; import java.util.Collections; import java.util.List; @@ -113,8 +115,11 @@ public final class MultiSelectManager { } }; - CompositeOnGestureListener<? extends Object> compositeListener = - new CompositeOnGestureListener<>(listener, gestureDelegate); + CompositeOnGestureListener compositeListener = + new CompositeOnGestureListener( + Lists.<OnGestureListener>newArrayList(listener, gestureDelegate), + Lists.<OnDoubleTapListener>newArrayList(listener, gestureDelegate)); + final GestureDetector detector = new GestureDetector(recyclerView.getContext(), compositeListener); @@ -1060,21 +1065,23 @@ public final class MultiSelectManager { * @template A gestureDelegate that implements both {@link OnGestureListener} * and {@link OnDoubleTapListener} */ - private static final class - CompositeOnGestureListener<L extends OnGestureListener & OnDoubleTapListener> + private static final class CompositeOnGestureListener implements OnGestureListener, OnDoubleTapListener { - private L[] mListeners; + private List<OnGestureListener> mGestureListeners; + private List<OnDoubleTapListener> mTapListeners; - @SafeVarargs - public CompositeOnGestureListener(L... listeners) { - mListeners = listeners; + public CompositeOnGestureListener( + List<OnGestureListener> gestureListeners, + List<OnDoubleTapListener> tapListeners) { + mGestureListeners = gestureListeners; + mTapListeners = tapListeners; } @Override public boolean onDown(MotionEvent e) { - for (int i = 0; i < mListeners.length; i++) { - if (mListeners[i].onDown(e)) { + for (OnGestureListener l : mGestureListeners) { + if (l.onDown(e)) { return true; } } @@ -1083,15 +1090,15 @@ public final class MultiSelectManager { @Override public void onShowPress(MotionEvent e) { - for (int i = 0; i < mListeners.length; i++) { - mListeners[i].onShowPress(e); + for (OnGestureListener l : mGestureListeners) { + l.onShowPress(e); } } @Override public boolean onSingleTapUp(MotionEvent e) { - for (int i = 0; i < mListeners.length; i++) { - if (mListeners[i].onSingleTapUp(e)) { + for (OnGestureListener l : mGestureListeners) { + if (l.onSingleTapUp(e)) { return true; } } @@ -1100,8 +1107,8 @@ public final class MultiSelectManager { @Override public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) { - for (int i = 0; i < mListeners.length; i++) { - if (mListeners[i].onScroll(e1, e2, distanceX, distanceY)) { + for (OnGestureListener l : mGestureListeners) { + if (l.onScroll(e1, e2, distanceX, distanceY)) { return true; } } @@ -1110,15 +1117,15 @@ public final class MultiSelectManager { @Override public void onLongPress(MotionEvent e) { - for (int i = 0; i < mListeners.length; i++) { - mListeners[i].onLongPress(e); + for (OnGestureListener l : mGestureListeners) { + l.onLongPress(e); } } @Override public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) { - for (int i = 0; i < mListeners.length; i++) { - if (mListeners[i].onFling(e1, e2, velocityX, velocityY)) { + for (OnGestureListener l : mGestureListeners) { + if (l.onFling(e1, e2, velocityX, velocityY)) { return true; } } @@ -1127,8 +1134,8 @@ public final class MultiSelectManager { @Override public boolean onSingleTapConfirmed(MotionEvent e) { - for (int i = 0; i < mListeners.length; i++) { - if (mListeners[i].onSingleTapConfirmed(e)) { + for (OnDoubleTapListener listener : mTapListeners) { + if (listener.onSingleTapConfirmed(e)) { return true; } } @@ -1137,8 +1144,8 @@ public final class MultiSelectManager { @Override public boolean onDoubleTap(MotionEvent e) { - for (int i = 0; i < mListeners.length; i++) { - if (mListeners[i].onDoubleTap(e)) { + for (OnDoubleTapListener listener : mTapListeners) { + if (listener.onDoubleTap(e)) { return true; } } @@ -1147,8 +1154,8 @@ public final class MultiSelectManager { @Override public boolean onDoubleTapEvent(MotionEvent e) { - for (int i = 0; i < mListeners.length; i++) { - if (mListeners[i].onDoubleTapEvent(e)) { + for (OnDoubleTapListener listener : mTapListeners) { + if (listener.onDoubleTapEvent(e)) { return true; } } diff --git a/packages/DocumentsUI/src/com/android/documentsui/RecentsCreateFragment.java b/packages/DocumentsUI/src/com/android/documentsui/RecentsCreateFragment.java index 662822ee35d3..681133156dca 100644 --- a/packages/DocumentsUI/src/com/android/documentsui/RecentsCreateFragment.java +++ b/packages/DocumentsUI/src/com/android/documentsui/RecentsCreateFragment.java @@ -30,19 +30,19 @@ import android.graphics.drawable.Drawable; import android.net.Uri; import android.os.Bundle; import android.os.CancellationSignal; +import android.support.annotation.Nullable; +import android.support.v7.widget.LinearLayoutManager; +import android.support.v7.widget.RecyclerView; import android.text.Spannable; import android.text.SpannableStringBuilder; import android.text.TextUtils.TruncateAt; import android.text.style.ImageSpan; import android.util.Log; import android.view.LayoutInflater; +import android.view.MotionEvent; import android.view.View; import android.view.ViewGroup; -import android.widget.AdapterView; -import android.widget.AdapterView.OnItemClickListener; -import android.widget.BaseAdapter; import android.widget.ImageView; -import android.widget.ListView; import android.widget.TextView; import com.android.documentsui.BaseActivity.State; @@ -64,8 +64,7 @@ import java.util.List; public class RecentsCreateFragment extends Fragment { private View mEmptyView; - private ListView mListView; - + private RecyclerView mRecView; private DocumentStackAdapter mAdapter; private LoaderCallbacks<List<DocumentStack>> mCallbacks; @@ -85,13 +84,14 @@ public class RecentsCreateFragment extends Fragment { final View view = inflater.inflate(R.layout.fragment_directory, container, false); - mEmptyView = view.findViewById(android.R.id.empty); + mRecView = (RecyclerView) view.findViewById(R.id.recyclerView); + mRecView.setLayoutManager(new LinearLayoutManager(getContext())); + mRecView.addOnItemTouchListener(mItemListener); - mListView = (ListView) view.findViewById(R.id.list); - mListView.setOnItemClickListener(mItemListener); + mEmptyView = view.findViewById(android.R.id.empty); mAdapter = new DocumentStackAdapter(); - mListView.setAdapter(mAdapter); + mRecView.setAdapter(mAdapter); final RootsCache roots = DocumentsApplication.getRootsCache(context); final State state = ((BaseActivity) getActivity()).getDisplayState(); @@ -105,7 +105,7 @@ public class RecentsCreateFragment extends Fragment { @Override public void onLoadFinished( Loader<List<DocumentStack>> loader, List<DocumentStack> data) { - mAdapter.swapStacks(data); + mAdapter.update(data); // When launched into empty recents, show drawer if (mAdapter.isEmpty() && !state.stackTouched && @@ -116,7 +116,7 @@ public class RecentsCreateFragment extends Fragment { @Override public void onLoaderReset(Loader<List<DocumentStack>> loader) { - mAdapter.swapStacks(null); + mAdapter.update(null); } }; @@ -135,13 +135,24 @@ public class RecentsCreateFragment extends Fragment { getLoaderManager().destroyLoader(LOADER_RECENTS); } - private OnItemClickListener mItemListener = new OnItemClickListener() { - @Override - public void onItemClick(AdapterView<?> parent, View view, int position, long id) { - final DocumentStack stack = mAdapter.getItem(position); - ((BaseActivity) getActivity()).onStackPicked(stack); - } - }; + private RecyclerView.OnItemTouchListener mItemListener = + new RecyclerView.OnItemTouchListener() { + @Override + public boolean onInterceptTouchEvent(RecyclerView rv, MotionEvent e) { + Events.MotionInputEvent event = new Events.MotionInputEvent(e, mRecView); + if (event.isOverItem() && event.isActionUp()) { + final DocumentStack stack = mAdapter.getItem(event.getItemPosition()); + ((BaseActivity) getActivity()).onStackPicked(stack); + return true; + } + return false; + } + + @Override + public void onTouchEvent(RecyclerView rv, MotionEvent e) {} + @Override + public void onRequestDisallowInterceptTouchEvent(boolean disallowIntercept) {} + }; public static class RecentsCreateLoader extends UriDerivativeLoader<Uri, List<DocumentStack>> { private final RootsCache mRoots; @@ -187,14 +198,32 @@ public class RecentsCreateFragment extends Fragment { } } - private class DocumentStackAdapter extends BaseAdapter { - private List<DocumentStack> mStacks; + private static final class StackHolder extends RecyclerView.ViewHolder { + public View view; + public StackHolder(View view) { + super(view); + this.view = view; + } + } + + private class DocumentStackAdapter extends RecyclerView.Adapter<StackHolder> { + @Nullable private List<DocumentStack> mItems; + + DocumentStack getItem(int position) { + return mItems.get(position); + } + + @Override + public int getItemCount() { + return mItems == null ? 0 : mItems.size(); + } - public DocumentStackAdapter() { + boolean isEmpty() { + return mItems == null ? true : mItems.isEmpty(); } - public void swapStacks(List<DocumentStack> stacks) { - mStacks = stacks; + void update(@Nullable List<DocumentStack> items) { + mItems = items; if (isEmpty()) { mEmptyView.setVisibility(View.VISIBLE); @@ -206,17 +235,22 @@ public class RecentsCreateFragment extends Fragment { } @Override - public View getView(int position, View convertView, ViewGroup parent) { - final Context context = parent.getContext(); + public StackHolder onCreateViewHolder(ViewGroup parent, int viewType) { + final Context context = parent.getContext(); - if (convertView == null) { - final LayoutInflater inflater = LayoutInflater.from(context); - convertView = inflater.inflate(R.layout.item_doc_list, parent, false); - } + final LayoutInflater inflater = LayoutInflater.from(context); + return new StackHolder( + (View) inflater.inflate(R.layout.item_doc_list, parent, false)); + } + + @Override + public void onBindViewHolder(StackHolder holder, int position) { + Context context = getContext(); + View view = holder.view; - final ImageView iconMime = (ImageView) convertView.findViewById(R.id.icon_mime); - final TextView title = (TextView) convertView.findViewById(android.R.id.title); - final View line2 = convertView.findViewById(R.id.line2); + final ImageView iconMime = (ImageView) view.findViewById(R.id.icon_mime); + final TextView title = (TextView) view.findViewById(android.R.id.title); + final View line2 = view.findViewById(R.id.line2); final DocumentStack stack = getItem(position); iconMime.setImageDrawable(stack.root.loadIcon(context)); @@ -234,23 +268,6 @@ public class RecentsCreateFragment extends Fragment { title.setEllipsize(TruncateAt.MIDDLE); if (line2 != null) line2.setVisibility(View.GONE); - - return convertView; - } - - @Override - public int getCount() { - return mStacks != null ? mStacks.size() : 0; - } - - @Override - public DocumentStack getItem(int position) { - return mStacks.get(position); - } - - @Override - public long getItemId(int position) { - return getItem(position).hashCode(); } } diff --git a/packages/DocumentsUI/src/com/android/documentsui/RootsCache.java b/packages/DocumentsUI/src/com/android/documentsui/RootsCache.java index 05f7d8dd11e3..cb46bca741a1 100644 --- a/packages/DocumentsUI/src/com/android/documentsui/RootsCache.java +++ b/packages/DocumentsUI/src/com/android/documentsui/RootsCache.java @@ -17,6 +17,7 @@ package com.android.documentsui; import static com.android.documentsui.Shared.TAG; +import static com.android.documentsui.Shared.DEBUG; import android.content.ContentProviderClient; import android.content.ContentResolver; @@ -58,8 +59,6 @@ import java.util.concurrent.TimeUnit; * Cache of known storage backends and their roots. */ public class RootsCache { - private static final boolean LOGD = false; - public static final Uri sNotificationUri = Uri.parse( "content://com.android.documentsui.roots/"); @@ -91,7 +90,7 @@ public class RootsCache { @Override public void onChange(boolean selfChange, Uri uri) { - if (LOGD) Log.d(TAG, "Updating roots due to change at " + uri); + if (DEBUG) Log.d(TAG, "Updating roots due to change at " + uri); updateAuthorityAsync(uri.getAuthority()); } } @@ -148,7 +147,7 @@ public class RootsCache { final ContentResolver resolver = mContext.getContentResolver(); synchronized (mLock) { for (String authority : mStoppedAuthorities) { - if (LOGD) Log.d(TAG, "Loading stopped authority " + authority); + if (DEBUG) Log.d(TAG, "Loading stopped authority " + authority); mRoots.putAll(authority, loadRootsForAuthority(resolver, authority)); } mStoppedAuthorities.clear(); @@ -199,7 +198,8 @@ public class RootsCache { } final long delta = SystemClock.elapsedRealtime() - start; - Log.d(TAG, "Update found " + mTaskRoots.size() + " roots in " + delta + "ms"); + if (DEBUG) + Log.d(TAG, "Update found " + mTaskRoots.size() + " roots in " + delta + "ms"); synchronized (mLock) { mRoots = mTaskRoots; mStoppedAuthorities = mTaskStoppedAuthorities; @@ -213,7 +213,7 @@ public class RootsCache { // Ignore stopped packages for now; we might query them // later during UI interaction. if ((info.applicationInfo.flags & ApplicationInfo.FLAG_STOPPED) != 0) { - if (LOGD) Log.d(TAG, "Ignoring stopped authority " + info.authority); + if (DEBUG) Log.d(TAG, "Ignoring stopped authority " + info.authority); mTaskStoppedAuthorities.add(info.authority); return; } @@ -223,7 +223,7 @@ public class RootsCache { if (mFilterPackage != null && !mFilterPackage.equals(info.packageName)) { synchronized (mLock) { if (mTaskRoots.putAll(info.authority, mRoots.get(info.authority))) { - if (LOGD) Log.d(TAG, "Used cached roots for " + info.authority); + if (DEBUG) Log.d(TAG, "Used cached roots for " + info.authority); cacheHit = true; } } @@ -241,7 +241,7 @@ public class RootsCache { * Bring up requested provider and query for all active roots. */ private Collection<RootInfo> loadRootsForAuthority(ContentResolver resolver, String authority) { - if (LOGD) Log.d(TAG, "Loading roots for " + authority); + if (DEBUG) Log.d(TAG, "Loading roots for " + authority); synchronized (mObservedAuthorities) { if (mObservedAuthorities.add(authority)) { @@ -370,10 +370,15 @@ public class RootsCache { // Exclude downloads roots that don't support directory creation // TODO: Add flag to check the root supports directory creation or not. if (state.directoryCopy && root.isDownloads()) continue; - // Only show empty roots when creating - if ((state.action != State.ACTION_CREATE || + + // Only show empty roots when creating, or in browse mode. + if (empty && (state.action != State.ACTION_BROWSE || + state.action != State.ACTION_CREATE || state.action != State.ACTION_OPEN_TREE || - state.action != State.ACTION_OPEN_COPY_DESTINATION) && empty) continue; + state.action != State.ACTION_OPEN_COPY_DESTINATION)) { + if (DEBUG) Log.i(TAG, "Skipping empty root: " + root); + continue; + } // Only include roots that serve requested content final boolean overlap = @@ -385,7 +390,7 @@ public class RootsCache { // Exclude roots from the calling package. if (state.excludedAuthorities.contains(root.authority)) { - if (LOGD) Log.d(TAG, "Excluding root " + root.authority + " from calling package."); + if (DEBUG) Log.d(TAG, "Excluding root " + root.authority + " from calling package."); continue; } diff --git a/packages/DocumentsUI/src/com/android/documentsui/Shared.java b/packages/DocumentsUI/src/com/android/documentsui/Shared.java index 0c1ebc16f1df..9c884d4ef8c6 100644 --- a/packages/DocumentsUI/src/com/android/documentsui/Shared.java +++ b/packages/DocumentsUI/src/com/android/documentsui/Shared.java @@ -22,7 +22,7 @@ import android.content.Context; * @hide */ public final class Shared { - public static final boolean DEBUG = false; + public static final boolean DEBUG = true; public static final String TAG = "Documents"; /** diff --git a/packages/DocumentsUI/tests/src/com/android/documentsui/DirectoryFragmentModelTest.java b/packages/DocumentsUI/tests/src/com/android/documentsui/DirectoryFragmentModelTest.java index 5505f3546e5d..1895a6e66450 100644 --- a/packages/DocumentsUI/tests/src/com/android/documentsui/DirectoryFragmentModelTest.java +++ b/packages/DocumentsUI/tests/src/com/android/documentsui/DirectoryFragmentModelTest.java @@ -22,9 +22,12 @@ import android.content.ContextWrapper; import android.database.Cursor; import android.database.MatrixCursor; import android.provider.DocumentsContract.Document; +import android.support.v7.widget.RecyclerView.ViewHolder; +import android.support.v7.widget.RecyclerView; import android.test.AndroidTestCase; import android.test.MoreAsserts; import android.test.mock.MockContentResolver; +import android.view.ViewGroup; import com.android.documentsui.DirectoryFragment.Model; import com.android.documentsui.MultiSelectManager.Selection; @@ -57,7 +60,8 @@ public class DirectoryFragmentModelTest extends AndroidTestCase { DirectoryResult r = new DirectoryResult(); r.cursor = cursor; - model = new Model(mContext, null); + // Instantiate the model with a dummy view adapter and listener that (for now) do nothing. + model = new Model(mContext, null, new DummyAdapter()); model.addUpdateListener(new DummyListener()); model.update(r); } @@ -160,11 +164,16 @@ public class DirectoryFragmentModelTest extends AndroidTestCase { return model.getDocuments(sel); } - private static class DummyListener implements Model.UpdateListener { + private static class DummyListener extends Model.UpdateListener { public void onModelUpdate(Model model) {} public void onModelUpdateFailed(Exception e) {} - public void notifyItemRemoved(int position) {} - public void notifyItemInserted(int position) {} } + private static class DummyAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> { + public int getItemCount() { return 0; } + public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {} + public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { + return null; + } + } } diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardSimPinView.java b/packages/Keyguard/src/com/android/keyguard/KeyguardSimPinView.java index aeac91215be6..2033159af720 100644 --- a/packages/Keyguard/src/com/android/keyguard/KeyguardSimPinView.java +++ b/packages/Keyguard/src/com/android/keyguard/KeyguardSimPinView.java @@ -23,6 +23,7 @@ import com.android.internal.telephony.PhoneConstants; import android.content.Context; import android.content.res.ColorStateList; +import android.content.res.Configuration; import android.content.res.Resources; import android.app.AlertDialog; import android.app.AlertDialog.Builder; @@ -96,6 +97,12 @@ public class KeyguardSimPinView extends KeyguardPinBasedInputView { } @Override + protected void onConfigurationChanged(Configuration newConfig) { + super.onConfigurationChanged(newConfig); + resetState(); + } + + @Override protected int getPromtReasonStringRes(int reason) { // No message on SIM Pin return 0; diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitor.java b/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitor.java index e34286572cb6..57ee319f8ff3 100644 --- a/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitor.java +++ b/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitor.java @@ -121,7 +121,6 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener { private static final int MSG_DEVICE_PROVISIONED = 308; private static final int MSG_DPM_STATE_CHANGED = 309; private static final int MSG_USER_SWITCHING = 310; - private static final int MSG_KEYGUARD_VISIBILITY_CHANGED = 311; private static final int MSG_KEYGUARD_RESET = 312; private static final int MSG_BOOT_COMPLETED = 313; private static final int MSG_USER_SWITCH_COMPLETE = 314; @@ -233,9 +232,6 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener { case MSG_USER_SWITCH_COMPLETE: handleUserSwitchComplete(msg.arg1); break; - case MSG_KEYGUARD_VISIBILITY_CHANGED: - handleKeyguardVisibilityChanged(msg.arg1); - break; case MSG_KEYGUARD_RESET: handleKeyguardReset(); break; @@ -1344,19 +1340,20 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener { } /** - * Handle {@link #MSG_KEYGUARD_VISIBILITY_CHANGED} + * Notifies that the visibility state of Keyguard has changed. + * + * <p>Needs to be called from the main thread. */ - private void handleKeyguardVisibilityChanged(int showing) { - if (DEBUG) Log.d(TAG, "handleKeyguardVisibilityChanged(" + showing + ")"); - boolean isShowing = (showing == 1); - mKeyguardIsVisible = isShowing; + public void onKeyguardVisibilityChanged(boolean showing) { + if (DEBUG) Log.d(TAG, "onKeyguardVisibilityChanged(" + showing + ")"); + mKeyguardIsVisible = showing; for (int i = 0; i < mCallbacks.size(); i++) { KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get(); if (cb != null) { - cb.onKeyguardVisibilityChangedRaw(isShowing); + cb.onKeyguardVisibilityChangedRaw(showing); } } - if (!isShowing) { + if (!showing) { mFingerprintAlreadyAuthenticated = false; } updateFingerprintListeningState(); @@ -1477,13 +1474,6 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener { } } - public void sendKeyguardVisibilityChanged(boolean showing) { - if (DEBUG) Log.d(TAG, "sendKeyguardVisibilityChanged(" + showing + ")"); - Message message = mHandler.obtainMessage(MSG_KEYGUARD_VISIBILITY_CHANGED); - message.arg1 = showing ? 1 : 0; - message.sendToTarget(); - } - public void sendKeyguardReset() { mHandler.obtainMessage(MSG_KEYGUARD_RESET).sendToTarget(); } diff --git a/packages/PrintSpooler/jni/com_android_printspooler_util_BitmapSerializeUtils.cpp b/packages/PrintSpooler/jni/com_android_printspooler_util_BitmapSerializeUtils.cpp index b5d91385abe5..1530a02c22fe 100644 --- a/packages/PrintSpooler/jni/com_android_printspooler_util_BitmapSerializeUtils.cpp +++ b/packages/PrintSpooler/jni/com_android_printspooler_util_BitmapSerializeUtils.cpp @@ -166,7 +166,7 @@ static void writeBitmapPixels(JNIEnv* env, jclass /* clazz */, jobject jbitmap, } } -static JNINativeMethod sMethods[] = { +static const JNINativeMethod sMethods[] = { {"nativeReadBitmapPixels", "(Landroid/graphics/Bitmap;I)V", (void *) readBitmapPixels}, {"nativeWriteBitmapPixels", "(Landroid/graphics/Bitmap;I)V", (void *) writeBitmapPixels}, }; diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsHelper.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsHelper.java index 1d71346b575b..e12e3a571880 100644 --- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsHelper.java +++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsHelper.java @@ -166,7 +166,7 @@ public class SettingsHelper { .putExtra(Intent.EXTRA_SETTING_NAME, name) .putExtra(Intent.EXTRA_SETTING_NEW_VALUE, value) .putExtra(Intent.EXTRA_SETTING_PREVIOUS_VALUE, oldValue); - context.sendBroadcastAsUser(intent, UserHandle.OWNER, null); + context.sendBroadcastAsUser(intent, UserHandle.SYSTEM, null); } } } diff --git a/packages/SystemUI/src/com/android/systemui/RecentsComponent.java b/packages/SystemUI/src/com/android/systemui/RecentsComponent.java index dd93389880b0..1d0bfe7dc6f1 100644 --- a/packages/SystemUI/src/com/android/systemui/RecentsComponent.java +++ b/packages/SystemUI/src/com/android/systemui/RecentsComponent.java @@ -20,10 +20,6 @@ import android.view.Display; import android.view.View; public interface RecentsComponent { - public interface Callbacks { - public void onVisibilityChanged(boolean visible); - } - void showRecents(boolean triggeredFromAltTab, View statusBarView); void hideRecents(boolean triggeredFromAltTab, boolean triggeredFromHomeKey); void toggleRecents(Display display, int layoutDirection, View statusBarView); @@ -31,5 +27,4 @@ public interface RecentsComponent { void cancelPreloadingRecents(); void showNextAffiliatedTask(); void showPrevAffiliatedTask(); - void setCallback(Callbacks cb); } diff --git a/packages/SystemUI/src/com/android/systemui/SystemUIApplication.java b/packages/SystemUI/src/com/android/systemui/SystemUIApplication.java index 33bd726c8d4e..5bf251b57af1 100644 --- a/packages/SystemUI/src/com/android/systemui/SystemUIApplication.java +++ b/packages/SystemUI/src/com/android/systemui/SystemUIApplication.java @@ -22,7 +22,9 @@ import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.content.res.Configuration; +import android.os.Process; import android.os.SystemProperties; +import android.os.UserHandle; import android.util.Log; import java.util.HashMap; @@ -51,12 +53,20 @@ public class SystemUIApplication extends Application { }; /** + * The classes of the stuff to start for each user. This is a subset of the services listed + * above. + */ + private final Class<?>[] SERVICES_PER_USER = new Class[] { + com.android.systemui.recents.Recents.class + }; + + /** * Hold a reference on the stuff we start. */ private final SystemUI[] mServices = new SystemUI[SERVICES.length]; private boolean mServicesStarted; private boolean mBootCompleted; - private final Map<Class<?>, Object> mComponents = new HashMap<Class<?>, Object>(); + private final Map<Class<?>, Object> mComponents = new HashMap<>(); @Override public void onCreate() { @@ -66,24 +76,32 @@ public class SystemUIApplication extends Application { // the theme set there. setTheme(R.style.systemui_theme); - IntentFilter filter = new IntentFilter(Intent.ACTION_BOOT_COMPLETED); - filter.setPriority(IntentFilter.SYSTEM_HIGH_PRIORITY); - registerReceiver(new BroadcastReceiver() { - @Override - public void onReceive(Context context, Intent intent) { - if (mBootCompleted) return; - - if (DEBUG) Log.v(TAG, "BOOT_COMPLETED received"); - unregisterReceiver(this); - mBootCompleted = true; - if (mServicesStarted) { - final int N = mServices.length; - for (int i = 0; i < N; i++) { - mServices[i].onBootCompleted(); + if (Process.myUserHandle().equals(UserHandle.SYSTEM)) { + IntentFilter filter = new IntentFilter(Intent.ACTION_BOOT_COMPLETED); + filter.setPriority(IntentFilter.SYSTEM_HIGH_PRIORITY); + registerReceiver(new BroadcastReceiver() { + @Override + public void onReceive(Context context, Intent intent) { + if (mBootCompleted) return; + + if (DEBUG) Log.v(TAG, "BOOT_COMPLETED received"); + unregisterReceiver(this); + mBootCompleted = true; + if (mServicesStarted) { + final int N = mServices.length; + for (int i = 0; i < N; i++) { + mServices[i].onBootCompleted(); + } } } - } - }, filter); + }, filter); + } else { + // For a secondary user, boot-completed will never be called because it has already + // been broadcasted on startup for the primary SystemUI process. Instead, for + // components which require the SystemUI component to be initialized per-user, we + // start those components now for the current non-system user. + startServicesIfNeeded(SERVICES_PER_USER); + } } /** @@ -94,6 +112,10 @@ public class SystemUIApplication extends Application { * <p>This method must only be called from the main thread.</p> */ public void startServicesIfNeeded() { + startServicesIfNeeded(SERVICES); + } + + private void startServicesIfNeeded(Class<?>[] services) { if (mServicesStarted) { return; } @@ -107,13 +129,14 @@ public class SystemUIApplication extends Application { } } - Log.v(TAG, "Starting SystemUI services."); - final int N = SERVICES.length; + Log.v(TAG, "Starting SystemUI services for user " + + Process.myUserHandle().getIdentifier() + "."); + final int N = services.length; for (int i=0; i<N; i++) { - Class<?> cl = SERVICES[i]; + Class<?> cl = services[i]; if (DEBUG) Log.d(TAG, "loading: " + cl); try { - mServices[i] = (SystemUI)cl.newInstance(); + mServices[i] = (SystemUI) cl.newInstance(); } catch (IllegalAccessException ex) { throw new RuntimeException(ex); } catch (InstantiationException ex) { @@ -136,7 +159,9 @@ public class SystemUIApplication extends Application { if (mServicesStarted) { int len = mServices.length; for (int i = 0; i < len; i++) { - mServices[i].onConfigurationChanged(newConfig); + if (mServices[i] != null) { + mServices[i].onConfigurationChanged(newConfig); + } } } } diff --git a/packages/SystemUI/src/com/android/systemui/classifier/AccelerationClassifier.java b/packages/SystemUI/src/com/android/systemui/classifier/AccelerationClassifier.java new file mode 100644 index 000000000000..86bea873b737 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/classifier/AccelerationClassifier.java @@ -0,0 +1,94 @@ +/* + * Copyright (C) 2015 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License + */ + +package com.android.systemui.classifier; + +import android.view.MotionEvent; + +import java.util.HashMap; + +/** + * A classifier which looks at the speed and distance between successive points of a Stroke. + * It looks at two consecutive speeds between two points and calculates the ratio between them. + * The final result is the maximum of these values. It does the same for distances. If some speed + * or distance is equal to zero then the ratio between this and the next part is not calculated. To + * the duration of each part there is added one nanosecond so that it is always possible to + * calculate the speed of a part. + */ +public class AccelerationClassifier extends StrokeClassifier { + private final HashMap<Stroke, Data> mStrokeMap = new HashMap<>(); + + public AccelerationClassifier(ClassifierData classifierData) { + mClassifierData = classifierData; + } + + @Override + public void onTouchEvent(MotionEvent event) { + int action = event.getActionMasked(); + + if (action == MotionEvent.ACTION_DOWN) { + mStrokeMap.clear(); + } + + for (int i = 0; i < event.getPointerCount(); i++) { + Stroke stroke = mClassifierData.getStroke(event.getPointerId(i)); + Point point = stroke.getPoints().get(stroke.getPoints().size() - 1); + if (mStrokeMap.get(stroke) == null) { + mStrokeMap.put(stroke, new Data(point)); + } else { + mStrokeMap.get(stroke).addPoint(point); + } + } + } + + @Override + public float getFalseTouchEvaluation(int type, Stroke stroke) { + Data data = mStrokeMap.get(stroke); + return SpeedRatioEvaluator.evaluate(data.maxSpeedRatio) + + DistanceRatioEvaluator.evaluate(data.maxDistanceRatio); + } + + private static class Data { + public Point previousPoint; + public float previousSpeed; + public float previousDistance; + public float maxSpeedRatio; + public float maxDistanceRatio; + + public Data(Point point) { + previousPoint = point; + previousSpeed = previousDistance = 0.0f; + maxDistanceRatio = maxSpeedRatio = 0.0f; + } + + public void addPoint(Point point) { + float distance = previousPoint.dist(point); + float duration = (float) (point.timeOffsetNano - previousPoint.timeOffsetNano + 1); + float speed = distance / duration; + if (previousDistance != 0.0f) { + maxDistanceRatio = Math.max(maxDistanceRatio, distance / previousDistance); + } + + if (previousSpeed != 0.0f) { + maxSpeedRatio = Math.max(maxSpeedRatio, speed / previousSpeed); + } + + previousDistance = distance; + previousSpeed = speed; + previousPoint = point; + } + } +}
\ No newline at end of file diff --git a/packages/SystemUI/src/com/android/systemui/classifier/AnglesVarianceClassifier.java b/packages/SystemUI/src/com/android/systemui/classifier/AnglesVarianceClassifier.java index 5cd914f06828..c74339b9082b 100644 --- a/packages/SystemUI/src/com/android/systemui/classifier/AnglesVarianceClassifier.java +++ b/packages/SystemUI/src/com/android/systemui/classifier/AnglesVarianceClassifier.java @@ -16,7 +16,6 @@ package com.android.systemui.classifier; -import android.hardware.SensorEvent; import android.view.MotionEvent; import java.lang.Math; @@ -27,27 +26,24 @@ import java.util.List; /** * A classifier which calculates the variance of differences between successive angles in a stroke. - * For each stroke it keeps its last three points. If some successive points are the same, it ignores - * the repetitions. If a new point is added, the classifier calculates the angle between the last - * three points. After that it calculates the difference between this angle and the previously - * calculated angle. The return value of the classifier is the variance of the differences - * from a stroke. If there are multiple strokes created at once, the classifier sums up the - * variances of all the strokes. Also the value is multiplied by HISTORY_FACTOR after each - * INTERVAL milliseconds. + * For each stroke it keeps its last three points. If some successive points are the same, it + * ignores the repetitions. If a new point is added, the classifier calculates the angle between + * the last three points. After that, it calculates the difference between this angle and the + * previously calculated angle. Then it calculates the variance of the differences from a stroke. + * To the differences there is artificially added value 0.0 and the difference between the first + * angle and PI (angles are in radians). It helps with strokes which have few points and punishes + * more strokes which are not smooth. This classifier also tries to split the stroke into two parts + * int the place in which the biggest angle is. It calculates the angle variance of the two parts + * and sums them up. The reason the classifier is doing this, is because some human swipes at the + * beginning go for a moment in one direction and then they rapidly change direction for the rest + * of the stroke (like a tick). The final result is the minimum of angle variance of the whole + * stroke and the sum of angle variances of the two parts split up. */ -public class AnglesVarianceClassifier extends Classifier { - private final float INTERVAL = 10.0f; - private final float CLEAR_HISTORY = 500f; - private final float HISTORY_FACTOR = 0.9f; - +public class AnglesVarianceClassifier extends StrokeClassifier { private HashMap<Stroke, Data> mStrokeMap = new HashMap<>(); - private float mValue; - private long mLastUpdate; public AnglesVarianceClassifier(ClassifierData classifierData) { mClassifierData = classifierData; - mValue = 0.0f; - mLastUpdate = System.currentTimeMillis(); } @Override @@ -65,54 +61,33 @@ public class AnglesVarianceClassifier extends Classifier { mStrokeMap.put(stroke, new Data()); } mStrokeMap.get(stroke).addPoint(stroke.getPoints().get(stroke.getPoints().size() - 1)); - - if (action == MotionEvent.ACTION_UP || action == MotionEvent.ACTION_CANCEL - || (action == MotionEvent.ACTION_POINTER_UP && i == event.getActionIndex())) { - decayValue(); - mValue += mStrokeMap.get(stroke).getAnglesVariance(); - } } } - /** - * Decreases mValue through time - */ - private void decayValue() { - long currentTimeMillis = System.currentTimeMillis(); - if (currentTimeMillis - mLastUpdate > CLEAR_HISTORY) { - mValue = 0.0f; - } else { - mValue *= Math.pow(HISTORY_FACTOR, (float) (currentTimeMillis - mLastUpdate) / INTERVAL); - } - mLastUpdate = currentTimeMillis; - } - @Override - public void onSensorChanged(SensorEvent event) { + public float getFalseTouchEvaluation(int type, Stroke stroke) { + return AnglesVarianceEvaluator.evaluate(mStrokeMap.get(stroke).getAnglesVariance()); } - @Override - public float getFalseTouchEvaluation(int type) { - decayValue(); - float currentValue = 0.0f; - for (Data data: mStrokeMap.values()) { - currentValue += data.getAnglesVariance(); - } - return (float) (mValue + currentValue); - } - - private class Data { + private static class Data { private List<Point> mLastThreePoints = new ArrayList<>(); + private float mFirstAngleVariance; private float mPreviousAngle; + private float mBiggestAngle; private float mSumSquares; + private float mSecondSumSquares; private float mSum; + private float mSecondSum; private float mCount; + private float mSecondCount; public Data() { + mFirstAngleVariance = 0.0f; mPreviousAngle = (float) Math.PI; - mSumSquares = 0.0f; - mSum = 0.0f; - mCount = 1.0f; + mBiggestAngle = 0.0f; + mSumSquares = mSecondSumSquares = 0.0f; + mSum = mSecondSum = 0.0f; + mCount = mSecondCount = 1.0f; } public void addPoint(Point point) { @@ -124,10 +99,26 @@ public class AnglesVarianceClassifier extends Classifier { if (mLastThreePoints.size() == 4) { mLastThreePoints.remove(0); - float angle = getAngle(mLastThreePoints.get(0), mLastThreePoints.get(1), + float angle = mLastThreePoints.get(1).getAngle(mLastThreePoints.get(0), mLastThreePoints.get(2)); float difference = angle - mPreviousAngle; + + // If this is the biggest angle of the stroke so then we save the value of + // the angle variance so far and start to count the values for the angle + // variance of the second part. + if (mBiggestAngle < angle) { + mBiggestAngle = angle; + mFirstAngleVariance = getAnglesVariance(mSumSquares, mSum, mCount); + mSecondSumSquares = 0.0f; + mSecondSum = 0.0f; + mSecondCount = 1.0f; + } else { + mSecondSum += difference; + mSecondSumSquares += difference * difference; + mSecondCount += 1.0; + } + mSum += difference; mSumSquares += difference * difference; mCount += 1.0; @@ -136,21 +127,14 @@ public class AnglesVarianceClassifier extends Classifier { } } - private float getAngle(Point a, Point b, Point c) { - float dist1 = a.dist(b); - float dist2 = b.dist(c); - float crossProduct = b.crossProduct(a, c); - float dotProduct = b.dotProduct(a, c); - float cos = Math.min(1.0f, Math.max(-1.0f, dotProduct / dist1 / dist2)); - float angle = (float) Math.acos(cos); - if (crossProduct < 0.0) { - angle = 2.0f * (float) Math.PI - angle; - } - return angle; + public float getAnglesVariance(float sumSquares, float sum, float count) { + return sumSquares / count - (sum / count) * (sum / count); } public float getAnglesVariance() { - return mSumSquares / mCount + (mSum / mCount) * (mSum / mCount); + return Math.min(getAnglesVariance(mSumSquares, mSum, mCount), + mFirstAngleVariance + getAnglesVariance(mSecondSumSquares, mSecondSum, + mSecondCount)); } } }
\ No newline at end of file diff --git a/packages/SystemUI/src/com/android/systemui/classifier/AnglesVarianceEvaluator.java b/packages/SystemUI/src/com/android/systemui/classifier/AnglesVarianceEvaluator.java new file mode 100644 index 000000000000..99cc1a6d14fe --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/classifier/AnglesVarianceEvaluator.java @@ -0,0 +1,30 @@ +/* + * Copyright (C) 2015 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License + */ + +package com.android.systemui.classifier; + +public class AnglesVarianceEvaluator { + public static float evaluate(float value) { + float evaluation = 0.0f; + if (value > 0.05) evaluation++; + if (value > 0.10) evaluation++; + if (value > 0.20) evaluation++; + if (value > 0.40) evaluation++; + if (value > 0.80) evaluation++; + if (value > 1.50) evaluation++; + return evaluation; + } +} diff --git a/packages/SystemUI/src/com/android/systemui/classifier/Classifier.java b/packages/SystemUI/src/com/android/systemui/classifier/Classifier.java index b76be1478bb4..89d20defc7db 100644 --- a/packages/SystemUI/src/com/android/systemui/classifier/Classifier.java +++ b/packages/SystemUI/src/com/android/systemui/classifier/Classifier.java @@ -20,7 +20,7 @@ import android.hardware.SensorEvent; import android.view.MotionEvent; /** - * An interface for classifiers for touch and sensor events. + * An abstract class for classifiers for touch and sensor events. */ public abstract class Classifier { public static final int QUICK_SETTINGS = 0; @@ -30,6 +30,7 @@ public abstract class Classifier { public static final int UNLOCK = 4; public static final int LEFT_AFFORDANCE = 5; public static final int RIGHT_AFFORDANCE = 6; + public static final int GENERIC = 7; /** * Contains all the information about touch events from which the classifier can query @@ -47,11 +48,4 @@ public abstract class Classifier { */ public void onSensorChanged(SensorEvent event) { } - - /** - * @param type the type of action for which this method is called - * @return a nonnegative value which is used to determine whether this a false touch. The - * bigger the value the greater the chance that this a false touch. - */ - public abstract float getFalseTouchEvaluation(int type); } diff --git a/packages/SystemUI/src/com/android/systemui/classifier/ClassifierData.java b/packages/SystemUI/src/com/android/systemui/classifier/ClassifierData.java index 77b81d2b68fa..649279dac285 100644 --- a/packages/SystemUI/src/com/android/systemui/classifier/ClassifierData.java +++ b/packages/SystemUI/src/com/android/systemui/classifier/ClassifierData.java @@ -19,32 +19,47 @@ package com.android.systemui.classifier; import android.util.SparseArray; import android.view.MotionEvent; +import java.util.ArrayList; + /** * Contains data which is used to classify interaction sequences on the lockscreen. It does, for * example, provide information on the current touch state. */ public class ClassifierData { private SparseArray<Stroke> mCurrentStrokes = new SparseArray<>(); + private ArrayList<Stroke> mEndingStrokes = new ArrayList<>(); + private float mXdpi; + private float mYdpi; - public ClassifierData() { + public ClassifierData(float xdpi, float ydpi) { + mXdpi = xdpi; + mYdpi = ydpi; } public void update(MotionEvent event) { + mEndingStrokes.clear(); int action = event.getActionMasked(); if (action == MotionEvent.ACTION_DOWN) { mCurrentStrokes.clear(); } + for (int i = 0; i < event.getPointerCount(); i++) { int id = event.getPointerId(i); if (mCurrentStrokes.get(id) == null) { - mCurrentStrokes.put(id, new Stroke(event.getEventTimeNano())); + mCurrentStrokes.put(id, new Stroke(event.getEventTimeNano(), mXdpi, mYdpi)); } mCurrentStrokes.get(id).addPoint(event.getX(i), event.getY(i), event.getEventTimeNano()); + + if (action == MotionEvent.ACTION_UP || action == MotionEvent.ACTION_CANCEL + || (action == MotionEvent.ACTION_POINTER_UP && i == event.getActionIndex())) { + mEndingStrokes.add(getStroke(id)); + } } } public void cleanUp(MotionEvent event) { + mEndingStrokes.clear(); int action = event.getActionMasked(); for (int i = 0; i < event.getPointerCount(); i++) { int id = event.getPointerId(i); @@ -56,6 +71,13 @@ public class ClassifierData { } /** + * @return the list of Strokes which are ending in the recently added MotionEvent + */ + public ArrayList<Stroke> getEndingStrokes() { + return mEndingStrokes; + } + + /** * @param id the id from MotionEvent * @return the Stroke assigned to the id */ diff --git a/packages/SystemUI/src/com/android/systemui/classifier/DistanceRatioEvaluator.java b/packages/SystemUI/src/com/android/systemui/classifier/DistanceRatioEvaluator.java new file mode 100644 index 000000000000..8acb009a230f --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/classifier/DistanceRatioEvaluator.java @@ -0,0 +1,29 @@ +/* + * Copyright (C) 2015 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License + */ + +package com.android.systemui.classifier; + +public class DistanceRatioEvaluator { + public static float evaluate(float value) { + float evaluation = 0.0f; + if (value <= 1.0) evaluation++; + if (value <= 0.5) evaluation++; + if (value > 4.0) evaluation++; + if (value > 7.0) evaluation++; + if (value > 14.0) evaluation++; + return evaluation; + } +} diff --git a/packages/SystemUI/src/com/android/systemui/classifier/DurationCountClassifier.java b/packages/SystemUI/src/com/android/systemui/classifier/DurationCountClassifier.java new file mode 100644 index 000000000000..892469428f4a --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/classifier/DurationCountClassifier.java @@ -0,0 +1,31 @@ +/* + * Copyright (C) 2015 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License + */ + +package com.android.systemui.classifier; + +/** + * A classifier which looks at the ratio between the duration of the stroke and its number of + * points. + */ +public class DurationCountClassifier extends StrokeClassifier { + public DurationCountClassifier(ClassifierData classifierData) { + } + + @Override + public float getFalseTouchEvaluation(int type, Stroke stroke) { + return DurationCountEvaluator.evaluate(stroke.getDurationSeconds() / stroke.getCount()); + } +}
\ No newline at end of file diff --git a/packages/SystemUI/src/com/android/systemui/classifier/DurationCountEvaluator.java b/packages/SystemUI/src/com/android/systemui/classifier/DurationCountEvaluator.java new file mode 100644 index 000000000000..5395983968f7 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/classifier/DurationCountEvaluator.java @@ -0,0 +1,30 @@ +/* + * Copyright (C) 2015 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License + */ + +package com.android.systemui.classifier; + + +public class DurationCountEvaluator { + public static float evaluate(float value) { + float evaluation = 0.0f; + if (value < 0.0105) evaluation++; + if (value < 0.00909) evaluation++; + if (value < 0.00667) evaluation++; + if (value > 0.0333) evaluation++; + if (value > 0.0500) evaluation++; + return evaluation; + } +} diff --git a/packages/SystemUI/src/com/android/systemui/classifier/EndPointLengthClassifier.java b/packages/SystemUI/src/com/android/systemui/classifier/EndPointLengthClassifier.java new file mode 100644 index 000000000000..78bc0ddf1942 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/classifier/EndPointLengthClassifier.java @@ -0,0 +1,30 @@ +/* + * Copyright (C) 2015 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License + */ + +package com.android.systemui.classifier; + +/** + * A classifier which looks at the distance between the first and the last point from the stroke. + */ +public class EndPointLengthClassifier extends StrokeClassifier { + public EndPointLengthClassifier(ClassifierData classifierData) { + } + + @Override + public float getFalseTouchEvaluation(int type, Stroke stroke) { + return EndPointLengthEvaluator.evaluate(stroke.getEndPointLength()); + } +}
\ No newline at end of file diff --git a/packages/SystemUI/src/com/android/systemui/classifier/EndPointLengthEvaluator.java b/packages/SystemUI/src/com/android/systemui/classifier/EndPointLengthEvaluator.java new file mode 100644 index 000000000000..bb2f1c4e355d --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/classifier/EndPointLengthEvaluator.java @@ -0,0 +1,30 @@ +/* + * Copyright (C) 2015 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License + */ + +package com.android.systemui.classifier; + +public class EndPointLengthEvaluator { + public static float evaluate(float value) { + float evaluation = 0.0f; + if (value < 0.05) evaluation += 2.0; + if (value < 0.1) evaluation += 2.0; + if (value < 0.2) evaluation += 2.0; + if (value < 0.3) evaluation += 2.0; + if (value < 0.4) evaluation += 2.0; + if (value < 0.5) evaluation += 2.0; + return evaluation; + } +} diff --git a/packages/SystemUI/src/com/android/systemui/classifier/EndPointRatioClassifier.java b/packages/SystemUI/src/com/android/systemui/classifier/EndPointRatioClassifier.java new file mode 100644 index 000000000000..c125e0093db5 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/classifier/EndPointRatioClassifier.java @@ -0,0 +1,36 @@ +/* + * Copyright (C) 2015 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License + */ + +package com.android.systemui.classifier; + +/** + * A classifier which looks at the ratio between the total length covered by the stroke and the + * distance between the first and last point from this stroke. + */ +public class EndPointRatioClassifier extends StrokeClassifier { + public EndPointRatioClassifier(ClassifierData classifierData) { + mClassifierData = classifierData; + } + + @Override + public float getFalseTouchEvaluation(int type, Stroke stroke) { + if (stroke.getTotalLength() == 0.0f) { + return 1.0f; + } + return EndPointRatioEvaluator.evaluate( + stroke.getEndPointLength() / stroke.getTotalLength()); + } +}
\ No newline at end of file diff --git a/packages/SystemUI/src/com/android/systemui/classifier/EndPointRatioEvaluator.java b/packages/SystemUI/src/com/android/systemui/classifier/EndPointRatioEvaluator.java new file mode 100644 index 000000000000..529fcec2710e --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/classifier/EndPointRatioEvaluator.java @@ -0,0 +1,30 @@ +/* + * Copyright (C) 2015 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License + */ + +package com.android.systemui.classifier; + +public class EndPointRatioEvaluator { + public static float evaluate(float value) { + float evaluation = 0.0f; + if (value < 0.85) evaluation++; + if (value < 0.75) evaluation++; + if (value < 0.65) evaluation++; + if (value < 0.55) evaluation++; + if (value < 0.45) evaluation++; + if (value < 0.35) evaluation++; + return evaluation; + } +} diff --git a/packages/SystemUI/src/com/android/systemui/classifier/FalsingManager.java b/packages/SystemUI/src/com/android/systemui/classifier/FalsingManager.java index 347273ac0f68..c68fff837c6f 100644 --- a/packages/SystemUI/src/com/android/systemui/classifier/FalsingManager.java +++ b/packages/SystemUI/src/com/android/systemui/classifier/FalsingManager.java @@ -126,11 +126,10 @@ public class FalsingManager implements SensorEventListener { } /** - * @param type the type of action for which this method is called * @return true if the classifier determined that this is not a human interacting with the phone */ - public boolean isFalseTouch(int type) { - return mHumanInteractionClassifier.getFalseTouchEvaluation(type) > 0.5; + public boolean isFalseTouch() { + return mHumanInteractionClassifier.isFalseTouch(); } @Override @@ -189,6 +188,7 @@ public class FalsingManager implements SensorEventListener { } public void onQsDown() { + mHumanInteractionClassifier.setType(Classifier.QUICK_SETTINGS); mDataCollector.onQsDown(); } @@ -197,6 +197,7 @@ public class FalsingManager implements SensorEventListener { } public void onTrackingStarted() { + mHumanInteractionClassifier.setType(Classifier.UNLOCK); mDataCollector.onTrackingStarted(); } @@ -217,6 +218,7 @@ public class FalsingManager implements SensorEventListener { } public void onNotificatonStartDraggingDown() { + mHumanInteractionClassifier.setType(Classifier.NOTIFICATION_DRAG_DOWN); mDataCollector.onNotificatonStartDraggingDown(); } @@ -229,6 +231,7 @@ public class FalsingManager implements SensorEventListener { } public void onNotificatonStartDismissing() { + mHumanInteractionClassifier.setType(Classifier.NOTIFICATION_DISMISS); mDataCollector.onNotificatonStartDismissing(); } @@ -245,6 +248,11 @@ public class FalsingManager implements SensorEventListener { } public void onAffordanceSwipingStarted(boolean rightCorner) { + if (rightCorner) { + mHumanInteractionClassifier.setType(Classifier.RIGHT_AFFORDANCE); + } else { + mHumanInteractionClassifier.setType(Classifier.LEFT_AFFORDANCE); + } mDataCollector.onAffordanceSwipingStarted(rightCorner); } diff --git a/packages/SystemUI/src/com/android/systemui/classifier/GestureClassifier.java b/packages/SystemUI/src/com/android/systemui/classifier/GestureClassifier.java new file mode 100644 index 000000000000..11388fc49594 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/classifier/GestureClassifier.java @@ -0,0 +1,32 @@ +/* + * Copyright (C) 2015 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License + */ + +package com.android.systemui.classifier; + +/** + * An abstract class for classifiers which classify the whole gesture (all the strokes which + * occurred from DOWN event to UP/CANCEL event) + */ +public abstract class GestureClassifier extends Classifier { + + /** + * @param type the type of action for which this method is called + * @return a non-negative value which is used to determine whether the most recent gesture is a + * false interaction; the bigger the value the greater the chance that this a false + * interaction. + */ + public abstract float getFalseTouchEvaluation(int type); +} diff --git a/packages/SystemUI/src/com/android/systemui/classifier/HistoryEvaluator.java b/packages/SystemUI/src/com/android/systemui/classifier/HistoryEvaluator.java new file mode 100644 index 000000000000..85a9bee8d977 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/classifier/HistoryEvaluator.java @@ -0,0 +1,112 @@ +/* + * Copyright (C) 2015 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License + */ + +package com.android.systemui.classifier; + +import java.util.ArrayList; + +/** + * Holds the evaluations for ended strokes and gestures. These values are decreased through time. + */ +public class HistoryEvaluator { + private static final float INTERVAL = 50.0f; + private static final float HISTORY_FACTOR = 0.9f; + private static final float EPSILON = 1e-5f; + + private final ArrayList<Data> mStrokes = new ArrayList<>(); + private final ArrayList<Data> mGestureWeights = new ArrayList<>(); + private long mLastUpdate; + + public HistoryEvaluator() { + mLastUpdate = System.currentTimeMillis(); + } + + public void addStroke(float evaluation) { + decayValue(); + mStrokes.add(new Data(evaluation)); + } + + public void addGesture(float evaluation) { + decayValue(); + mGestureWeights.add(new Data(evaluation)); + } + + /** + * Calculates the weighted average of strokes and adds to it the weighted average of gestures + */ + public float getEvaluation() { + return weightedAverage(mStrokes) + weightedAverage(mGestureWeights); + } + + private float weightedAverage(ArrayList<Data> list) { + float sumValue = 0.0f; + float sumWeight = 0.0f; + int size = list.size(); + for (int i = 0; i < size; i++) { + Data data = list.get(i); + sumValue += data.evaluation * data.weight; + sumWeight += data.weight; + } + + if (sumWeight == 0.0f) { + return 0.0f; + } + + return sumValue / sumWeight; + } + + private void decayValue() { + long currentTimeMillis = System.currentTimeMillis(); + + // All weights are multiplied by HISTORY_FACTOR after each INTERVAL milliseconds. + float factor = (float) Math.pow(HISTORY_FACTOR, + (float) (currentTimeMillis - mLastUpdate) / INTERVAL); + + decayValue(mStrokes, factor); + decayValue(mGestureWeights, factor); + mLastUpdate = currentTimeMillis; + } + + private void decayValue(ArrayList<Data> list, float factor) { + int size = list.size(); + for (int i = 0; i < size; i++) { + list.get(i).weight *= factor; + } + + // Removing evaluations with such small weights that they do not matter anymore + while (!list.isEmpty() && isZero(list.get(0).weight)) { + list.remove(0); + } + } + + private boolean isZero(float x) { + return x <= EPSILON && x >= -EPSILON; + } + + /** + * For each stroke it holds its initial value and the current weight. Initially the + * weight is set to 1.0 + */ + private static class Data { + public float evaluation; + public float weight; + + public Data(float evaluation) { + this.evaluation = evaluation; + weight = 1.0f; + } + } +} diff --git a/packages/SystemUI/src/com/android/systemui/classifier/HumanInteractionClassifier.java b/packages/SystemUI/src/com/android/systemui/classifier/HumanInteractionClassifier.java index a5f6df858d2c..6ef805c569dd 100644 --- a/packages/SystemUI/src/com/android/systemui/classifier/HumanInteractionClassifier.java +++ b/packages/SystemUI/src/com/android/systemui/classifier/HumanInteractionClassifier.java @@ -25,6 +25,8 @@ import android.os.UserHandle; import android.provider.Settings; import android.view.MotionEvent; +import java.util.ArrayList; + /** * An classifier trying to determine whether it is a human interacting with the phone or not. */ @@ -35,8 +37,14 @@ public class HumanInteractionClassifier extends Classifier { private final Handler mHandler = new Handler(); private final Context mContext; - private AnglesVarianceClassifier mAnglesVarianceClassifier; + private ArrayList<StrokeClassifier> mStrokeClassifiers = new ArrayList<>(); + private ArrayList<GestureClassifier> mGestureClassifiers = new ArrayList<>(); + private final int mStrokeClassifiersSize; + private final int mGestureClassifiersSize; + + private HistoryEvaluator mHistoryEvaluator; private boolean mEnableClassifier = false; + private int mCurrentType = Classifier.GENERIC; protected final ContentObserver mSettingsObserver = new ContentObserver(mHandler) { @Override @@ -47,8 +55,24 @@ public class HumanInteractionClassifier extends Classifier { private HumanInteractionClassifier(Context context) { mContext = context; - mClassifierData = new ClassifierData(); - mAnglesVarianceClassifier = new AnglesVarianceClassifier(mClassifierData); + mClassifierData = new ClassifierData(mContext.getResources().getDisplayMetrics().xdpi, + mContext.getResources().getDisplayMetrics().ydpi); + mHistoryEvaluator = new HistoryEvaluator(); + + mStrokeClassifiers.add(new AnglesVarianceClassifier(mClassifierData)); + mStrokeClassifiers.add(new SpeedClassifier(mClassifierData)); + mStrokeClassifiers.add(new DurationCountClassifier(mClassifierData)); + mStrokeClassifiers.add(new EndPointRatioClassifier(mClassifierData)); + mStrokeClassifiers.add(new EndPointLengthClassifier(mClassifierData)); + mStrokeClassifiers.add(new AccelerationClassifier(mClassifierData)); + mStrokeClassifiers.add(new SpeedVarianceClassifier(mClassifierData)); + mStrokeClassifiers.add(new LengthCountClassifier(mClassifierData)); + + mGestureClassifiers.add(new PointerCountClassifier(mClassifierData)); + mGestureClassifiers.add(new ProximityClassifier(mClassifierData)); + + mStrokeClassifiersSize = mStrokeClassifiers.size(); + mGestureClassifiersSize = mGestureClassifiers.size(); mContext.getContentResolver().registerContentObserver( Settings.Global.getUriFor(HIC_ENABLE), false, @@ -71,25 +95,61 @@ public class HumanInteractionClassifier extends Classifier { HIC_ENABLE, 0); } + public void setType(int type) { + mCurrentType = type; + } + @Override public void onTouchEvent(MotionEvent event) { if (mEnableClassifier) { mClassifierData.update(event); - mAnglesVarianceClassifier.onTouchEvent(event); + + for (int i = 0; i < mStrokeClassifiersSize; i++) { + mStrokeClassifiers.get(i).onTouchEvent(event); + } + + for (int i = 0; i < mGestureClassifiersSize; i++) { + mGestureClassifiers.get(i).onTouchEvent(event); + } + + int size = mClassifierData.getEndingStrokes().size(); + for (int i = 0; i < size; i++) { + Stroke stroke = mClassifierData.getEndingStrokes().get(i); + float evaluation = 0.0f; + for (int j = 0; j < mStrokeClassifiersSize; j++) { + evaluation += mStrokeClassifiers.get(j).getFalseTouchEvaluation( + mCurrentType, stroke); + } + mHistoryEvaluator.addStroke(evaluation); + } + + int action = event.getActionMasked(); + if (action == MotionEvent.ACTION_UP || action == MotionEvent.ACTION_CANCEL) { + float evaluation = 0.0f; + for (int i = 0; i < mGestureClassifiersSize; i++) { + evaluation += mGestureClassifiers.get(i).getFalseTouchEvaluation(mCurrentType); + } + mHistoryEvaluator.addGesture(evaluation); + setType(Classifier.GENERIC); + } + mClassifierData.cleanUp(event); } } @Override public void onSensorChanged(SensorEvent event) { - } + for (int i = 0; i < mStrokeClassifiers.size(); i++) { + mStrokeClassifiers.get(i).onSensorChanged(event); + } - @Override - public float getFalseTouchEvaluation(int type) { - if (mEnableClassifier) { - return mAnglesVarianceClassifier.getFalseTouchEvaluation(type); + for (int i = 0; i < mGestureClassifiers.size(); i++) { + mGestureClassifiers.get(i).onSensorChanged(event); } - return 0.0f; + } + + public boolean isFalseTouch() { + return mHistoryEvaluator.getEvaluation() >= 5.0f; } public boolean isEnabled() { diff --git a/packages/SystemUI/src/com/android/systemui/classifier/LengthCountClassifier.java b/packages/SystemUI/src/com/android/systemui/classifier/LengthCountClassifier.java new file mode 100644 index 000000000000..1ea467bfb857 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/classifier/LengthCountClassifier.java @@ -0,0 +1,31 @@ +/* + * Copyright (C) 2015 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License + */ + +package com.android.systemui.classifier; + +/** + * A classifier which looks at the ratio between the duration of the stroke and its number of + * points. + */ +public class LengthCountClassifier extends StrokeClassifier { + public LengthCountClassifier(ClassifierData classifierData) { + } + + @Override + public float getFalseTouchEvaluation(int type, Stroke stroke) { + return LengthCountEvaluator.evaluate(stroke.getTotalLength() / stroke.getCount()); + } +}
\ No newline at end of file diff --git a/packages/SystemUI/src/com/android/systemui/classifier/LengthCountEvaluator.java b/packages/SystemUI/src/com/android/systemui/classifier/LengthCountEvaluator.java new file mode 100644 index 000000000000..68f163d1916b --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/classifier/LengthCountEvaluator.java @@ -0,0 +1,33 @@ +/* + * Copyright (C) 2015 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License + */ + +package com.android.systemui.classifier; + +/** + * A classifier which looks at the ratio between the length of the stroke and its number of + * points. + */ +public class LengthCountEvaluator { + public static float evaluate(float value) { + float evaluation = 0.0f; + if (value < 0.07) evaluation++; + if (value < 0.05) evaluation++; + if (value < 0.02) evaluation++; + if (value > 0.6) evaluation++; + if (value > 1.2) evaluation++; + return evaluation; + } +} diff --git a/packages/SystemUI/src/com/android/systemui/classifier/Point.java b/packages/SystemUI/src/com/android/systemui/classifier/Point.java index e7dbae19eb31..f3dc2be4144b 100644 --- a/packages/SystemUI/src/com/android/systemui/classifier/Point.java +++ b/packages/SystemUI/src/com/android/systemui/classifier/Point.java @@ -56,4 +56,28 @@ public class Point { public float dotProduct(Point a, Point b) { return (a.x - x) * (b.x - x) + (a.y - y) * (b.y - y); } + + /** + * Calculates the angle in radians created by points (a, this, b). If any two of these points + * are the same, the method will return 0.0f + * + * @return the angle in radians + */ + public float getAngle(Point a, Point b) { + float dist1 = dist(a); + float dist2 = dist(b); + + if (dist1 == 0.0f || dist2 == 0.0f) { + return 0.0f; + } + + float crossProduct = crossProduct(a, b); + float dotProduct = dotProduct(a, b); + float cos = Math.min(1.0f, Math.max(-1.0f, dotProduct / dist1 / dist2)); + float angle = (float) Math.acos(cos); + if (crossProduct < 0.0) { + angle = 2.0f * (float) Math.PI - angle; + } + return angle; + } } diff --git a/packages/SystemUI/src/com/android/systemui/classifier/PointerCountClassifier.java b/packages/SystemUI/src/com/android/systemui/classifier/PointerCountClassifier.java new file mode 100644 index 000000000000..5097b635807e --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/classifier/PointerCountClassifier.java @@ -0,0 +1,48 @@ +/* + * Copyright (C) 2015 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License + */ + +package com.android.systemui.classifier; + +import android.view.MotionEvent; + +/** + * A classifier which looks at the total number of traces in the whole gesture. + */ +public class PointerCountClassifier extends GestureClassifier { + private int mCount; + + public PointerCountClassifier(ClassifierData classifierData) { + mCount = 0; + } + + @Override + public void onTouchEvent(MotionEvent event) { + int action = event.getActionMasked(); + + if (action == MotionEvent.ACTION_DOWN) { + mCount = 1; + } + + if (action == MotionEvent.ACTION_POINTER_DOWN) { + ++mCount; + } + } + + @Override + public float getFalseTouchEvaluation(int type) { + return PointerCountEvaluator.evaluate(mCount); + } +} diff --git a/packages/SystemUI/src/com/android/systemui/classifier/PointerCountEvaluator.java b/packages/SystemUI/src/com/android/systemui/classifier/PointerCountEvaluator.java new file mode 100644 index 000000000000..d7a3af0360af --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/classifier/PointerCountEvaluator.java @@ -0,0 +1,23 @@ +/* + * Copyright (C) 2015 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License + */ + +package com.android.systemui.classifier; + +public class PointerCountEvaluator { + public static float evaluate(int value) { + return (value - 1) * (value - 1); + } +} diff --git a/packages/SystemUI/src/com/android/systemui/classifier/ProximityClassifier.java b/packages/SystemUI/src/com/android/systemui/classifier/ProximityClassifier.java new file mode 100644 index 000000000000..69950640337f --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/classifier/ProximityClassifier.java @@ -0,0 +1,93 @@ +/* + * Copyright (C) 2015 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License + */ + +package com.android.systemui.classifier; + +import android.hardware.Sensor; +import android.hardware.SensorEvent; +import android.view.MotionEvent; + +/** + * A classifier which looks at the proximity sensor during the gesture. It calculates the percentage + * the proximity sensor showing the near state during the whole gesture + */ +public class ProximityClassifier extends GestureClassifier { + private long mGestureStartTimeNano; + private long mNearStartTimeNano; + private long mNearDuration; + private boolean mNear; + private float mAverageNear; + + public ProximityClassifier(ClassifierData classifierData) { + } + + @Override + public void onSensorChanged(SensorEvent event) { + if (event.sensor.getType() == Sensor.TYPE_PROXIMITY) { + update(event.values[0] < event.sensor.getMaximumRange(), event.timestamp); + } + } + + @Override + public void onTouchEvent(MotionEvent event) { + int action = event.getActionMasked(); + + if (action == MotionEvent.ACTION_DOWN) { + mGestureStartTimeNano = event.getEventTimeNano(); + mNearStartTimeNano = event.getEventTimeNano(); + mNearDuration = 0; + } + + if (action == MotionEvent.ACTION_UP || action == MotionEvent.ACTION_CANCEL) { + update(mNear, event.getEventTimeNano()); + long duration = event.getEventTimeNano() - mGestureStartTimeNano; + + if (duration == 0) { + mAverageNear = mNear ? 1.0f : 0.0f; + } else { + mAverageNear = (float) mNearDuration / (float) duration; + } + } + } + + + /** + * @param near is the sensor showing the near state right now + * @param timestampNano time of this event in nanoseconds + */ + private void update(boolean near, long timestampNano) { + // This if is necessary because MotionEvents and SensorEvents do not come in + // chronological order + if (timestampNano > mNearStartTimeNano) { + // if the state before was near then add the difference of the current time and + // mNearStartTimeNano to mNearDuration. + if (mNear) { + mNearDuration += timestampNano - mNearStartTimeNano; + } + + // if the new state is near, set mNearStartTimeNano equal to this moment. + if (near) { + mNearStartTimeNano = timestampNano; + } + } + mNear = near; + } + + @Override + public float getFalseTouchEvaluation(int type) { + return ProximityEvaluator.evaluate(mAverageNear, type); + } +} diff --git a/packages/SystemUI/src/com/android/systemui/classifier/ProximityEvaluator.java b/packages/SystemUI/src/com/android/systemui/classifier/ProximityEvaluator.java new file mode 100644 index 000000000000..91002bf1291c --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/classifier/ProximityEvaluator.java @@ -0,0 +1,29 @@ +/* + * Copyright (C) 2015 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License + */ + +package com.android.systemui.classifier; + +public class ProximityEvaluator { + public static float evaluate(float value, int type) { + float evaluation = 0.0f; + float threshold = 0.1f; + if (type == Classifier.QUICK_SETTINGS) { + threshold = 1.0f; + } + if (value >= threshold) evaluation += 2.0; + return evaluation; + } +} diff --git a/packages/SystemUI/src/com/android/systemui/classifier/SpeedClassifier.java b/packages/SystemUI/src/com/android/systemui/classifier/SpeedClassifier.java new file mode 100644 index 000000000000..81b78c7ecdfe --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/classifier/SpeedClassifier.java @@ -0,0 +1,37 @@ +/* + * Copyright (C) 2015 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License + */ + +package com.android.systemui.classifier; + +/** + * A classifier that looks at the speed of the stroke. It calculates the speed of a stroke in + * inches per second. + */ +public class SpeedClassifier extends StrokeClassifier { + private final float NANOS_TO_SECONDS = 1e9f; + + public SpeedClassifier(ClassifierData classifierData) { + } + + @Override + public float getFalseTouchEvaluation(int type, Stroke stroke) { + float duration = (float) stroke.getDurationNanos() / NANOS_TO_SECONDS; + if (duration == 0.0f) { + return SpeedEvaluator.evaluate(0.0f); + } + return SpeedEvaluator.evaluate(stroke.getTotalLength() / duration); + } +}
\ No newline at end of file diff --git a/packages/SystemUI/src/com/android/systemui/classifier/SpeedEvaluator.java b/packages/SystemUI/src/com/android/systemui/classifier/SpeedEvaluator.java new file mode 100644 index 000000000000..c0e4a2ddc89a --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/classifier/SpeedEvaluator.java @@ -0,0 +1,27 @@ +/* + * Copyright (C) 2015 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License + */ + +package com.android.systemui.classifier; + +public class SpeedEvaluator { + public static float evaluate(float value) { + float evaluation = 0.0f; + if (value < 4.0 || value > 35.0) evaluation += 1.0; + if (value < 2.2) evaluation += 1.0; + if (value > 50.0) evaluation += 1.0; + return evaluation; + } +} diff --git a/packages/SystemUI/src/com/android/systemui/classifier/SpeedRatioEvaluator.java b/packages/SystemUI/src/com/android/systemui/classifier/SpeedRatioEvaluator.java new file mode 100644 index 000000000000..349aa9ed49d6 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/classifier/SpeedRatioEvaluator.java @@ -0,0 +1,26 @@ +/* + * Copyright (C) 2015 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License + */ + +package com.android.systemui.classifier; + +public class SpeedRatioEvaluator { + public static float evaluate(float value) { + float evaluation = 0.0f; + if (value > 9.0) ++evaluation; + if (value > 18.0) ++evaluation; + return evaluation; + } +} diff --git a/packages/SystemUI/src/com/android/systemui/classifier/SpeedVarianceClassifier.java b/packages/SystemUI/src/com/android/systemui/classifier/SpeedVarianceClassifier.java new file mode 100644 index 000000000000..9a30fe1a425c --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/classifier/SpeedVarianceClassifier.java @@ -0,0 +1,124 @@ +/* + * Copyright (C) 2015 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License + */ + +package com.android.systemui.classifier; + +import android.view.MotionEvent; + +import java.lang.Math; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; + +/** + * A classifier which for each point from a stroke, it creates a point on plane with coordinates + * (timeOffsetNano, distanceCoveredUpToThisPoint) (scaled by DURATION_SCALE and LENGTH_SCALE) + * and then it calculates the angle variance of these points like the class + * {@link AnglesVarianceClassifier} (without splitting it into two parts). The classifier ignores + * the last point of a stroke because the UP event comes in with some delay and this ruins the + * smoothness of this curve + */ +public class SpeedVarianceClassifier extends StrokeClassifier { + private HashMap<Stroke, Data> mStrokeMap = new HashMap<>(); + + public SpeedVarianceClassifier(ClassifierData classifierData) { + mClassifierData = classifierData; + } + + @Override + public void onTouchEvent(MotionEvent event) { + int action = event.getActionMasked(); + + if (action == MotionEvent.ACTION_DOWN) { + mStrokeMap.clear(); + } + + for (int i = 0; i < event.getPointerCount(); i++) { + Stroke stroke = mClassifierData.getStroke(event.getPointerId(i)); + + if (mStrokeMap.get(stroke) == null) { + mStrokeMap.put(stroke, new Data()); + } + + if (action != MotionEvent.ACTION_UP && action != MotionEvent.ACTION_CANCEL + && !(action == MotionEvent.ACTION_POINTER_UP && i == event.getActionIndex())) { + mStrokeMap.get(stroke).addPoint( + stroke.getPoints().get(stroke.getPoints().size() - 1)); + } + } + } + + @Override + public float getFalseTouchEvaluation(int type, Stroke stroke) { + return SpeedVarianceEvaluator.evaluate(mStrokeMap.get(stroke).getAnglesVariance()); + } + + private static class Data { + private final float DURATION_SCALE = 1e8f; + private final float LENGTH_SCALE = 1.0f; + + private List<Point> mLastThreePoints = new ArrayList<>(); + private Point mPreviousPoint; + private float mPreviousAngle; + private float mSumSquares; + private float mSum; + private float mCount; + private float mDist; + + public Data() { + mPreviousPoint = null; + mPreviousAngle = (float) Math.PI; + mSumSquares = 0.0f; + mSum = 0.0f; + mCount = 1.0f; + mDist = 0.0f; + } + + public void addPoint(Point point) { + if (mPreviousPoint != null) { + mDist += mPreviousPoint.dist(point); + } + + mPreviousPoint = point; + Point speedPoint = new Point((float) point.timeOffsetNano / DURATION_SCALE, + mDist / LENGTH_SCALE); + + // Checking if the added point is different than the previously added point + // Repetitions are being ignored so that proper angles are calculated. + if (mLastThreePoints.isEmpty() + || !mLastThreePoints.get(mLastThreePoints.size() - 1).equals(speedPoint)) { + mLastThreePoints.add(speedPoint); + if (mLastThreePoints.size() == 4) { + mLastThreePoints.remove(0); + + float angle = mLastThreePoints.get(1).getAngle(mLastThreePoints.get(0), + mLastThreePoints.get(2)); + + float difference = angle - mPreviousAngle; + mSum += difference; + mSumSquares += difference * difference; + mCount += 1.0; + mPreviousAngle = angle; + } + } + } + + public float getAnglesVariance() { + return mSumSquares / mCount - (mSum / mCount) * (mSum / mCount); + } + } +}
\ No newline at end of file diff --git a/packages/SystemUI/src/com/android/systemui/classifier/SpeedVarianceEvaluator.java b/packages/SystemUI/src/com/android/systemui/classifier/SpeedVarianceEvaluator.java new file mode 100644 index 000000000000..8f9a7e159638 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/classifier/SpeedVarianceEvaluator.java @@ -0,0 +1,28 @@ +/* + * Copyright (C) 2015 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License + */ + +package com.android.systemui.classifier; + +public class SpeedVarianceEvaluator { + public static float evaluate(float value) { + float evaluation = 0.0f; + if (value > 0.06) evaluation += 1.0; + if (value > 0.15) evaluation += 1.0; + if (value > 0.3) evaluation += 1.0; + if (value > 0.6) evaluation += 1.0; + return evaluation; + } +} diff --git a/packages/SystemUI/src/com/android/systemui/classifier/Stroke.java b/packages/SystemUI/src/com/android/systemui/classifier/Stroke.java index f386cbe458e6..49e6fb8b62c9 100644 --- a/packages/SystemUI/src/com/android/systemui/classifier/Stroke.java +++ b/packages/SystemUI/src/com/android/systemui/classifier/Stroke.java @@ -19,20 +19,52 @@ package com.android.systemui.classifier; import java.util.ArrayList; /** - * Contains data about movement traces (pointers) + * Contains data about a stroke (a single trace, all the events from a given id from the + * DOWN/POINTER_DOWN event till the UP/POINTER_UP/CANCEL event.) */ public class Stroke { + private final float NANOS_TO_SECONDS = 1e9f; + private ArrayList<Point> mPoints = new ArrayList<>(); private long mStartTimeNano; private long mEndTimeNano; + private float mLength; + private float mXdpi; + private float mYdpi; - public Stroke(long eventTimeNano) { + public Stroke(long eventTimeNano, float xdpi, float ydpi) { + mXdpi = xdpi; + mYdpi = ydpi; mStartTimeNano = mEndTimeNano = eventTimeNano; } public void addPoint(float x, float y, long eventTimeNano) { mEndTimeNano = eventTimeNano; - mPoints.add(new Point(x, y, eventTimeNano - mStartTimeNano)); + Point point = new Point(x / mXdpi, y / mYdpi, eventTimeNano - mStartTimeNano); + if (!mPoints.isEmpty()) { + mLength += mPoints.get(mPoints.size() - 1).dist(point); + } + mPoints.add(point); + } + + public int getCount() { + return mPoints.size(); + } + + public float getTotalLength() { + return mLength; + } + + public float getEndPointLength() { + return mPoints.get(0).dist(mPoints.get(mPoints.size() - 1)); + } + + public long getDurationNanos() { + return mEndTimeNano - mStartTimeNano; + } + + public float getDurationSeconds() { + return (float) getDurationNanos() / NANOS_TO_SECONDS; } public ArrayList<Point> getPoints() { diff --git a/packages/SystemUI/src/com/android/systemui/classifier/StrokeClassifier.java b/packages/SystemUI/src/com/android/systemui/classifier/StrokeClassifier.java new file mode 100644 index 000000000000..5da392f31d63 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/classifier/StrokeClassifier.java @@ -0,0 +1,31 @@ +/* + * Copyright (C) 2015 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License + */ + +package com.android.systemui.classifier; + +/** + * An abstract class for classifiers which classify each stroke separately. + */ +public abstract class StrokeClassifier extends Classifier { + + /** + * @param type the type of action for which this method is called + * @param stroke the stroke for which the evaluation will be calculated + * @return a non-negative value which is used to determine whether this a false touch; the + * bigger the value the greater the chance that this a false touch + */ + public abstract float getFalseTouchEvaluation(int type, Stroke stroke); +} diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java index 3de500165185..2ea1e43b39a2 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java +++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java @@ -921,9 +921,27 @@ public class KeyguardViewMediator extends SystemUI { } catch (RemoteException e) { Slog.w(TAG, "Failed to call onKeyguardExitResult(false)", e); } + } else if (!isSecure()) { + + // Keyguard is not secure, no need to do anything, and we don't need to reshow + // the Keyguard after the client releases the Keyguard lock. + mExternallyEnabled = true; + mNeedToReshowWhenReenabled = false; + updateInputRestricted(); + try { + callback.onKeyguardExitResult(true); + } catch (RemoteException e) { + Slog.w(TAG, "Failed to call onKeyguardExitResult(false)", e); + } } else { - mExitSecureCallback = callback; - verifyUnlockLocked(); + + // Since we prevent apps from hiding the Keyguard if we are secure, this should be + // a no-op as well. + try { + callback.onKeyguardExitResult(false); + } catch (RemoteException e) { + Slog.w(TAG, "Failed to call onKeyguardExitResult(false)", e); + } } } } diff --git a/packages/SystemUI/src/com/android/systemui/media/RingtonePlayer.java b/packages/SystemUI/src/com/android/systemui/media/RingtonePlayer.java index 7f68e290f3a0..f39f3026f26b 100644 --- a/packages/SystemUI/src/com/android/systemui/media/RingtonePlayer.java +++ b/packages/SystemUI/src/com/android/systemui/media/RingtonePlayer.java @@ -160,7 +160,7 @@ public class RingtonePlayer extends SystemUI { throw new SecurityException("Async playback only available from system UID."); } if (UserHandle.ALL.equals(user)) { - user = UserHandle.OWNER; + user = UserHandle.SYSTEM; } mAsyncPlayer.play(getContextForUser(user), uri, looping, aa); } diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/QWifiTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/QWifiTile.java index 87194fb840d1..b1572754fb6b 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/QWifiTile.java +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/QWifiTile.java @@ -17,6 +17,7 @@ package com.android.systemui.qs.tiles; import com.android.systemui.qs.QSTileView; +import com.android.systemui.statusbar.policy.WifiIcons; /** Quick settings tile: Wifi **/ public class QWifiTile extends WifiTile { @@ -29,4 +30,23 @@ public class QWifiTile extends WifiTile { public int getTileType() { return QSTileView.QS_TYPE_QUICK; } + + @Override + protected void handleUpdateState(SignalState state, Object arg) { + super.handleUpdateState(state, arg); + + CallbackInfo cb = (CallbackInfo) arg; + if (cb == null) { + cb = mSignalCallback.mInfo; + } + boolean wifiConnected = cb.enabled && (cb.wifiSignalIconId > 0) && (cb.enabledDesc != null); + + if (state.enabled && wifiConnected) { + // Only show full signal here. + state.icon = ResourceIcon.get(WifiIcons.QS_WIFI_SIGNAL_STRENGTH[1][4]); + } + // No activity in the quick toggle. + state.activityIn = false; + state.activityOut = false; + } } diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/WifiTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/WifiTile.java index 3295e14e0ae5..91e02183818f 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/WifiTile.java +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/WifiTile.java @@ -48,7 +48,7 @@ public class WifiTile extends QSTile<QSTile.SignalState> { private final WifiDetailAdapter mDetailAdapter; private final QSTile.SignalState mStateBeforeClick = newTileState(); - private final WifiSignalCallback mSignalCallback = new WifiSignalCallback(); + protected final WifiSignalCallback mSignalCallback = new WifiSignalCallback(); private final boolean mAlwaysDetail; @@ -200,7 +200,7 @@ public class WifiTile extends QSTile<QSTile.SignalState> { return string; } - private static final class CallbackInfo { + protected static final class CallbackInfo { boolean enabled; boolean connected; int wifiSignalIconId; @@ -223,7 +223,7 @@ public class WifiTile extends QSTile<QSTile.SignalState> { } } - private final class WifiSignalCallback extends SignalCallbackAdapter { + protected final class WifiSignalCallback extends SignalCallbackAdapter { final CallbackInfo mInfo = new CallbackInfo(); @Override diff --git a/packages/SystemUI/src/com/android/systemui/recents/Recents.java b/packages/SystemUI/src/com/android/systemui/recents/Recents.java index 308e7cc9e012..cbccaf887d69 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/Recents.java +++ b/packages/SystemUI/src/com/android/systemui/recents/Recents.java @@ -151,7 +151,8 @@ public class Recents extends SystemUI public void onReceive(Context context, Intent intent) { switch (intent.getAction()) { case ACTION_PROXY_NOTIFY_RECENTS_VISIBLITY_TO_OWNER: - visibilityChanged(intent.getBooleanExtra(EXTRA_RECENTS_VISIBILITY, false)); + visibilityChanged(context, + intent.getBooleanExtra(EXTRA_RECENTS_VISIBILITY, false)); break; case ACTION_PROXY_SCREEN_PINNING_REQUEST_TO_OWNER: onStartScreenPinning(context); @@ -160,7 +161,6 @@ public class Recents extends SystemUI } } - static RecentsComponent.Callbacks sRecentsComponentCallbacks; static RecentsTaskLoadPlan sInstanceLoadPlan; static Recents sInstance; @@ -834,18 +834,12 @@ public class Recents extends SystemUI mCanReuseTaskStackViews = true; } - /** Sets the RecentsComponent callbacks. */ - @Override - public void setCallback(RecentsComponent.Callbacks cb) { - sRecentsComponentCallbacks = cb; - } - /** Notifies the callbacks that the visibility of Recents has changed. */ @ProxyFromAnyToSystemUser public static void notifyVisibilityChanged(Context context, SystemServicesProxy ssp, boolean visible) { if (ssp.isForegroundUserSystem()) { - visibilityChanged(visible); + visibilityChanged(context, visible); } else { Intent intent = createLocalBroadcastIntent(context, ACTION_PROXY_NOTIFY_RECENTS_VISIBLITY_TO_OWNER); @@ -853,9 +847,13 @@ public class Recents extends SystemUI context.sendBroadcastAsUser(intent, UserHandle.SYSTEM); } } - static void visibilityChanged(boolean visible) { - if (sRecentsComponentCallbacks != null) { - sRecentsComponentCallbacks.onVisibilityChanged(visible); + static void visibilityChanged(Context context, boolean visible) { + // For the primary user, the context for the SystemUI component is the SystemUIApplication + SystemUIApplication app = (SystemUIApplication) + getInstanceAndStartIfNeeded(context.getApplicationContext()).mContext; + PhoneStatusBar statusBar = app.getComponent(PhoneStatusBar.class); + if (statusBar != null) { + statusBar.updateRecentsVisibility(visible); } } @@ -873,7 +871,7 @@ public class Recents extends SystemUI static void onStartScreenPinning(Context context) { // For the primary user, the context for the SystemUI component is the SystemUIApplication SystemUIApplication app = (SystemUIApplication) - getInstanceAndStartIfNeeded(context).mContext; + getInstanceAndStartIfNeeded(context.getApplicationContext()).mContext; PhoneStatusBar statusBar = app.getComponent(PhoneStatusBar.class); if (statusBar != null) { statusBar.showScreenPinningRequest(false); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java index 2c964be44cac..e7a3c8a3fe72 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java @@ -115,8 +115,7 @@ import static com.android.keyguard.KeyguardHostView.OnDismissAction; public abstract class BaseStatusBar extends SystemUI implements CommandQueue.Callbacks, ActivatableNotificationView.OnActivatedListener, - RecentsComponent.Callbacks, ExpandableNotificationRow.ExpansionLogger, - NotificationData.Environment { + ExpandableNotificationRow.ExpansionLogger, NotificationData.Environment { public static final String TAG = "StatusBar"; public static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG); public static final boolean MULTIUSER_DEBUG = false; @@ -577,7 +576,6 @@ public abstract class BaseStatusBar extends SystemUI implements ServiceManager.getService(Context.STATUS_BAR_SERVICE)); mRecents = getComponent(Recents.class); - mRecents.setCallback(this); final Configuration currentConfig = mContext.getResources().getConfiguration(); mLocale = currentConfig.locale; @@ -1174,11 +1172,6 @@ public abstract class BaseStatusBar extends SystemUI implements } } - @Override - public void onVisibilityChanged(boolean visible) { - // Do nothing - } - /** * If there is an active heads-up notification and it has a fullscreen intent, fire it now. */ diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeParameters.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeParameters.java index 5a2fa3bad127..1d890d0dde6c 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeParameters.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeParameters.java @@ -33,7 +33,7 @@ public class DozeParameters { private static final String TAG = "DozeParameters"; private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG); - private static final int MAX_DURATION = 10 * 1000; + private static final int MAX_DURATION = 60 * 1000; private final Context mContext; diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java index 13d0e1e0fbc3..3feead8f36ad 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java @@ -610,7 +610,7 @@ public abstract class PanelView extends FrameLayout { if (!mStatusBar.isFalsingThresholdNeeded()) { return false; } - if (mFalsingManager.isFalseTouch(Classifier.UNLOCK)) { + if (mFalsingManager.isFalseTouch()) { return true; } if (!mTouchAboveFalsingThreshold) { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java index 7f4be65c946f..151fa3c5a033 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java @@ -4106,8 +4106,7 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode, super.toggleRecents(); } - @Override - public void onVisibilityChanged(boolean visible) { + public void updateRecentsVisibility(boolean visible) { // Update the recents visibility flag if (visible) { mSystemUiVisibility |= View.RECENT_APPS_VISIBLE; diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java index 394ff3f8245c..05f6e57d9199 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java @@ -466,7 +466,7 @@ public class StatusBarKeyguardViewManager { KeyguardUpdateMonitor updateMonitor = KeyguardUpdateMonitor.getInstance(mContext); if ((showing && !occluded) != (mLastShowing && !mLastOccluded) || mFirstUpdate) { - updateMonitor.sendKeyguardVisibilityChanged(showing && !occluded); + updateMonitor.onKeyguardVisibilityChanged(showing && !occluded); } if (bouncerShowing != mLastBouncerShowing || mFirstUpdate) { updateMonitor.sendKeyguardBouncerChanged(bouncerShowing); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/WifiIcons.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/WifiIcons.java index c56646fc7740..374408d3ec7a 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/WifiIcons.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/WifiIcons.java @@ -18,7 +18,7 @@ package com.android.systemui.statusbar.policy; import com.android.systemui.R; -class WifiIcons { +public class WifiIcons { static final int[][] WIFI_SIGNAL_STRENGTH = { { R.drawable.stat_sys_wifi_signal_0, R.drawable.stat_sys_wifi_signal_1, @@ -32,7 +32,7 @@ class WifiIcons { R.drawable.stat_sys_wifi_signal_4_fully } }; - static final int[][] QS_WIFI_SIGNAL_STRENGTH = { + public static final int[][] QS_WIFI_SIGNAL_STRENGTH = { { R.drawable.ic_qs_wifi_0, R.drawable.ic_qs_wifi_1, R.drawable.ic_qs_wifi_2, diff --git a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialog.java b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialog.java index b2f527e3bbb4..da19b06d2f40 100644 --- a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialog.java +++ b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialog.java @@ -89,7 +89,6 @@ public class VolumeDialog { private static final long USER_ATTEMPT_GRACE_PERIOD = 1000; private static final int WAIT_FOR_RIPPLE = 200; - private static final int UPDATE_ANIMATION_DURATION = 80; private final Context mContext; private final H mHandler = new H(); @@ -353,14 +352,6 @@ public class VolumeDialog { writer.println(mAccessibility.mFeedbackEnabled); } - private static int getImpliedLevel(SeekBar seekBar, int progress) { - final int m = seekBar.getMax(); - final int n = m / 100 - 1; - final int level = progress == 0 ? 0 - : progress == m ? (m / 100) : (1 + (int)((progress / (float) m) * n)); - return level; - } - @SuppressLint("InflateParams") private VolumeRow initRow(final int stream, int iconRes, int iconMuteRes, boolean important) { final VolumeRow row = new VolumeRow(); @@ -690,7 +681,7 @@ public class VolumeDialog { : false; // update slider max - final int max = ss.levelMax * 100; + final int max = ss.levelMax; if (max != row.slider.getMax()) { row.slider.setMax(max); } @@ -777,8 +768,7 @@ public class VolumeDialog { if (row.tracking) { return; // don't update if user is sliding } - final int progress = row.slider.getProgress(); - final int level = getImpliedLevel(row.slider, progress); + final int level = row.slider.getProgress(); final boolean rowVisible = row.view.getVisibility() == View.VISIBLE; final boolean inGracePeriod = (SystemClock.uptimeMillis() - row.userAttempt) < USER_ATTEMPT_GRACE_PERIOD; @@ -794,33 +784,7 @@ public class VolumeDialog { return; // don't clamp if visible } } - final int newProgress = vlevel * 100; - if (progress != newProgress) { - if (mShowing && rowVisible) { - // animate! - if (row.anim != null && row.anim.isRunning() - && row.animTargetProgress == newProgress) { - return; // already animating to the target progress - } - // start/update animation - if (row.anim == null) { - row.anim = ObjectAnimator.ofInt(row.slider, "progress", progress, newProgress); - row.anim.setInterpolator(new DecelerateInterpolator()); - } else { - row.anim.cancel(); - row.anim.setIntValues(progress, newProgress); - } - row.animTargetProgress = newProgress; - row.anim.setDuration(UPDATE_ANIMATION_DURATION); - row.anim.start(); - } else { - // update slider directly to clamped value - if (row.anim != null) { - row.anim.cancel(); - } - row.slider.setProgress(newProgress); - } - } + row.slider.setProgress(vlevel, true); } private void recheckH(VolumeRow row) { @@ -1025,20 +989,19 @@ public class VolumeDialog { + " onProgressChanged " + progress + " fromUser=" + fromUser); if (!fromUser) return; if (mRow.ss.levelMin > 0) { - final int minProgress = mRow.ss.levelMin * 100; + final int minProgress = mRow.ss.levelMin; if (progress < minProgress) { seekBar.setProgress(minProgress); progress = minProgress; } } - final int userLevel = getImpliedLevel(seekBar, progress); - if (mRow.ss.level != userLevel || mRow.ss.muted && userLevel > 0) { + if (mRow.ss.level != progress || mRow.ss.muted && progress > 0) { mRow.userAttempt = SystemClock.uptimeMillis(); - if (mRow.requestedLevel != userLevel) { - mController.setStreamVolume(mRow.stream, userLevel); - mRow.requestedLevel = userLevel; + if (mRow.requestedLevel != progress) { + mController.setStreamVolume(mRow.stream, progress); + mRow.requestedLevel = progress; Events.writeEvent(mContext, Events.EVENT_TOUCH_LEVEL_CHANGED, mRow.stream, - userLevel); + progress); } } } @@ -1055,7 +1018,7 @@ public class VolumeDialog { if (D.BUG) Log.d(TAG, "onStopTrackingTouch"+ " " + mRow.stream); mRow.tracking = false; mRow.userAttempt = SystemClock.uptimeMillis(); - int userLevel = getImpliedLevel(seekBar, seekBar.getProgress()); + final int userLevel = seekBar.getProgress(); Events.writeEvent(mContext, Events.EVENT_TOUCH_LEVEL_DONE, mRow.stream, userLevel); if (mRow.ss.level != userLevel) { mHandler.sendMessageDelayed(mHandler.obtainMessage(H.RECHECK, mRow), @@ -1137,8 +1100,6 @@ public class VolumeDialog { private int iconState; // from Events private boolean cachedShowHeaders = VolumePrefs.DEFAULT_SHOW_HEADERS; private int cachedExpandButtonRes; - private ObjectAnimator anim; // slider progress animation for non-touch-related updates - private int animTargetProgress; private int lastAudibleLevel = 1; } diff --git a/packages/services/PacProcessor/jni/com_android_pacprocessor_PacNative.cpp b/packages/services/PacProcessor/jni/com_android_pacprocessor_PacNative.cpp index 272733893280..990d7707cdfb 100644 --- a/packages/services/PacProcessor/jni/com_android_pacprocessor_PacNative.cpp +++ b/packages/services/PacProcessor/jni/com_android_pacprocessor_PacNative.cpp @@ -130,7 +130,7 @@ static jstring com_android_pacprocessor_PacNative_makeProxyRequestNativeLocked(J return jret; } -static JNINativeMethod gMethods[] = { +static const JNINativeMethod gMethods[] = { { "createV8ParserNativeLocked", "()Z", (void*)com_android_pacprocessor_PacNative_createV8ParserNativeLocked}, { "destroyV8ParserNativeLocked", "()Z", diff --git a/rs/jni/android_renderscript_RenderScript.cpp b/rs/jni/android_renderscript_RenderScript.cpp index 0419d33c686c..8c830e8d9257 100644 --- a/rs/jni/android_renderscript_RenderScript.cpp +++ b/rs/jni/android_renderscript_RenderScript.cpp @@ -2494,7 +2494,7 @@ nSystemGetPointerSize(JNIEnv *_env, jobject _this) { static const char *classPathName = "android/renderscript/RenderScript"; -static JNINativeMethod methods[] = { +static const JNINativeMethod methods[] = { {"_nInit", "()V", (void*)_nInit }, {"nDeviceCreate", "()J", (void*)nDeviceCreate }, diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java index 91c3d48d1274..ff2a2ee3ca26 100644 --- a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java +++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java @@ -967,8 +967,8 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub { List<ResolveInfo> installedServices = mPackageManager.queryIntentServicesAsUser( new Intent(AccessibilityService.SERVICE_INTERFACE), - PackageManager.GET_SERVICES - | PackageManager.GET_META_DATA + PackageManager.GET_SERVICES + | PackageManager.GET_META_DATA | PackageManager.GET_DISABLED_UNTIL_USED_COMPONENTS, mCurrentUserId); @@ -3217,7 +3217,8 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub { case WindowManager.LayoutParams.TYPE_SYSTEM_ALERT: case WindowManager.LayoutParams.TYPE_SYSTEM_DIALOG: case WindowManager.LayoutParams.TYPE_SYSTEM_ERROR: - case WindowManager.LayoutParams.TYPE_SYSTEM_OVERLAY: { + case WindowManager.LayoutParams.TYPE_SYSTEM_OVERLAY: + case WindowManager.LayoutParams.TYPE_DOCK_DIVIDER: { return AccessibilityWindowInfo.TYPE_SYSTEM; } diff --git a/services/accessibility/java/com/android/server/accessibility/AutoclickController.java b/services/accessibility/java/com/android/server/accessibility/AutoclickController.java index 2e6136fc111b..8989625f979a 100644 --- a/services/accessibility/java/com/android/server/accessibility/AutoclickController.java +++ b/services/accessibility/java/com/android/server/accessibility/AutoclickController.java @@ -16,9 +16,16 @@ package com.android.server.accessibility; +import android.annotation.NonNull; +import android.content.ContentResolver; import android.content.Context; +import android.database.ContentObserver; +import android.net.Uri; import android.os.Handler; import android.os.SystemClock; +import android.os.UserHandle; +import android.provider.Settings; +import android.util.Slog; import android.view.InputDevice; import android.view.KeyEvent; import android.view.MotionEvent; @@ -46,16 +53,17 @@ import android.view.accessibility.AccessibilityEvent; * the class should handle cases where multiple mouse devices are present. */ public class AutoclickController implements EventStreamTransformation { - private static final String LOG_TAG = AutoclickController.class.getSimpleName(); - // TODO: Control click delay via settings. - private static final int CLICK_DELAY_MS = 600; + public static final int DEFAULT_CLICK_DELAY_MS = 600; + + private static final String LOG_TAG = AutoclickController.class.getSimpleName(); private EventStreamTransformation mNext; - private Context mContext; + private final Context mContext; // Lazily created on the first mouse motion event. private ClickScheduler mClickScheduler; + private ClickDelayObserver mClickDelayObserver; public AutoclickController(Context context) { mContext = context; @@ -66,7 +74,9 @@ public class AutoclickController implements EventStreamTransformation { if (event.isFromSource(InputDevice.SOURCE_MOUSE)) { if (mClickScheduler == null) { Handler handler = new Handler(mContext.getMainLooper()); - mClickScheduler = new ClickScheduler(handler, CLICK_DELAY_MS); + mClickScheduler = new ClickScheduler(handler, DEFAULT_CLICK_DELAY_MS); + mClickDelayObserver = new ClickDelayObserver(handler); + mClickDelayObserver.start(mContext.getContentResolver(), mClickScheduler); } handleMouseMotion(event, policyFlags); @@ -119,8 +129,13 @@ public class AutoclickController implements EventStreamTransformation { @Override public void onDestroy() { + if (mClickDelayObserver != null) { + mClickDelayObserver.stop(); + mClickDelayObserver = null; + } if (mClickScheduler != null) { mClickScheduler.cancel(); + mClickScheduler = null; } } @@ -143,6 +158,80 @@ public class AutoclickController implements EventStreamTransformation { } /** + * Observes setting value for autoclick delay, and updates ClickScheduler delay whenever the + * setting value changes. + */ + final private static class ClickDelayObserver extends ContentObserver { + /** URI used to identify the autoclick delay setting with content resolver. */ + private final Uri mAutoclickDelaySettingUri = Settings.Secure.getUriFor( + Settings.Secure.ACCESSIBILITY_AUTOCLICK_DELAY); + + private ContentResolver mContentResolver; + private ClickScheduler mClickScheduler; + + public ClickDelayObserver(Handler handler) { + super(handler); + } + + /** + * Starts the observer. And makes sure up-to-date autoclick delay is propagated to + * |clickScheduler|. + * + * @param contentResolver Content resolver that should be observed for setting's value + * changes. + * @param clickScheduler ClickScheduler that should be updated when click delay changes. + * @throws IllegalStateException If internal state is already setup when the method is + * called. + * @throws NullPointerException If any of the arguments is a null pointer. + */ + public void start(@NonNull ContentResolver contentResolver, + @NonNull ClickScheduler clickScheduler) { + if (mContentResolver != null || mClickScheduler != null) { + throw new IllegalStateException("Observer already started."); + } + if (contentResolver == null) { + throw new NullPointerException("contentResolver not set."); + } + if (clickScheduler == null) { + throw new NullPointerException("clickScheduler not set."); + } + + mContentResolver = contentResolver; + mClickScheduler = clickScheduler; + mContentResolver.registerContentObserver(mAutoclickDelaySettingUri, false, this, + UserHandle.USER_ALL); + + // Initialize mClickScheduler's initial delay value. + onChange(true, mAutoclickDelaySettingUri); + } + + /** + * Stops the the observer. Should only be called if the observer has been started. + * + * @throws IllegalStateException If internal state hasn't yet been initialized by calling + * {@link #start}. + */ + public void stop() { + if (mContentResolver == null || mClickScheduler == null) { + throw new IllegalStateException("ClickDelayObserver not started."); + } + + mContentResolver.unregisterContentObserver(this); + } + + @Override + public void onChange(boolean selfChange, Uri uri) { + if (mAutoclickDelaySettingUri.equals(uri)) { + // TODO: Plumb current user id down to here and use getIntForUser. + int delay = Settings.Secure.getInt( + mContentResolver, Settings.Secure.ACCESSIBILITY_AUTOCLICK_DELAY, + DEFAULT_CLICK_DELAY_MS); + mClickScheduler.updateDelay(delay); + } + } + } + + /** * Schedules and performs click event sequence that should be initiated when mouse pointer stops * moving. The click is first scheduled when a mouse movement is detected, and then further * delayed on every sufficient mouse movement. @@ -242,6 +331,15 @@ public class AutoclickController implements EventStreamTransformation { } /** + * Updates delay that should be used when scheduling clicks. The delay will be used only for + * clicks scheduled after this point (pending click tasks are not affected). + * @param delay New delay value. + */ + public void updateDelay(int delay) { + mDelay = delay; + } + + /** * Updates the time at which click sequence should occur. * * @param delay Delay (from now) after which click should occur. diff --git a/services/core/java/com/android/server/DeviceIdleController.java b/services/core/java/com/android/server/DeviceIdleController.java index 2f4ad3ff0e29..0c6eb40f5b08 100644 --- a/services/core/java/com/android/server/DeviceIdleController.java +++ b/services/core/java/com/android/server/DeviceIdleController.java @@ -1523,13 +1523,13 @@ public class DeviceIdleController extends SystemService private void reportPowerSaveWhitelistChangedLocked() { Intent intent = new Intent(PowerManager.ACTION_POWER_SAVE_WHITELIST_CHANGED); intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY); - getContext().sendBroadcastAsUser(intent, UserHandle.OWNER); + getContext().sendBroadcastAsUser(intent, UserHandle.SYSTEM); } private void reportTempWhitelistChangedLocked() { Intent intent = new Intent(PowerManager.ACTION_POWER_SAVE_TEMP_WHITELIST_CHANGED); intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY); - getContext().sendBroadcastAsUser(intent, UserHandle.OWNER); + getContext().sendBroadcastAsUser(intent, UserHandle.SYSTEM); } void readConfigFileLocked() { diff --git a/services/core/java/com/android/server/DropBoxManagerService.java b/services/core/java/com/android/server/DropBoxManagerService.java index b9db89ecae64..245448748766 100644 --- a/services/core/java/com/android/server/DropBoxManagerService.java +++ b/services/core/java/com/android/server/DropBoxManagerService.java @@ -170,7 +170,7 @@ public final class DropBoxManagerService extends SystemService { @Override public void handleMessage(Message msg) { if (msg.what == MSG_SEND_BROADCAST) { - getContext().sendBroadcastAsUser((Intent)msg.obj, UserHandle.OWNER, + getContext().sendBroadcastAsUser((Intent)msg.obj, UserHandle.SYSTEM, android.Manifest.permission.READ_LOGS); } } @@ -488,7 +488,7 @@ public final class DropBoxManagerService extends SystemService { /////////////////////////////////////////////////////////////////////////// - /** Chronologically sorted list of {@link #EntryFile} */ + /** Chronologically sorted list of {@link EntryFile} */ private static final class FileList implements Comparable<FileList> { public int blocks = 0; public final TreeSet<EntryFile> contents = new TreeSet<EntryFile>(); @@ -613,7 +613,7 @@ public final class DropBoxManagerService extends SystemService { /** * Creates a EntryFile object with only a timestamp for comparison purposes. - * @param timestampMillis to compare with. + * @param millis to compare with. */ public EntryFile(long millis) { this.tag = null; diff --git a/services/core/java/com/android/server/EventLogTags.logtags b/services/core/java/com/android/server/EventLogTags.logtags index b826cfda0952..9bf2aaad597e 100644 --- a/services/core/java/com/android/server/EventLogTags.logtags +++ b/services/core/java/com/android/server/EventLogTags.logtags @@ -29,6 +29,9 @@ option java_package com.android.server # This is logged when the partial wake lock (keeping the device awake # regardless of whether the screen is off) is acquired or released. 2729 power_partial_wake_state (releasedorAcquired|1|5),(tag|3) +# The device is being asked to go into a soft sleep (typically by the ungaze gesture). +# It logs the time remaining before the device would've normally gone to sleep without the request. +2731 power_soft_sleep_requested (savedwaketimems|2) # # Leave IDs through 2739 for more power logs (2730 used by battery_discharge above) diff --git a/services/core/java/com/android/server/GestureLauncherService.java b/services/core/java/com/android/server/GestureLauncherService.java index bd7d4b27e02c..7c85001c9175 100644 --- a/services/core/java/com/android/server/GestureLauncherService.java +++ b/services/core/java/com/android/server/GestureLauncherService.java @@ -101,8 +101,7 @@ public class GestureLauncherService extends SystemService { * Whether camera double tap power button gesture is currently enabled; */ private boolean mCameraDoubleTapPowerEnabled; - private long mLastPowerDownWhileNonInteractive; - private long mLastPowerDownWhileInteractive; + private long mLastPowerDown; public GestureLauncherService(Context context) { super(context); @@ -252,35 +251,32 @@ public class GestureLauncherService extends SystemService { public boolean interceptPowerKeyDown(KeyEvent event, boolean interactive) { boolean launched = false; boolean intercept = false; + long doubleTapInterval; synchronized (this) { - if (!mCameraDoubleTapPowerEnabled) { - mLastPowerDownWhileNonInteractive = 0; - mLastPowerDownWhileInteractive = 0; - return false; - } - if (event.getEventTime() - mLastPowerDownWhileNonInteractive - < CAMERA_POWER_DOUBLE_TAP_TIME_MS) { - launched = true; - intercept = true; - } else if (event.getEventTime() - mLastPowerDownWhileInteractive - < CAMERA_POWER_DOUBLE_TAP_TIME_MS) { + doubleTapInterval = event.getEventTime() - mLastPowerDown; + if (mCameraDoubleTapPowerEnabled + && doubleTapInterval < CAMERA_POWER_DOUBLE_TAP_TIME_MS) { launched = true; + intercept = interactive; } - mLastPowerDownWhileNonInteractive = interactive ? 0 : event.getEventTime(); - mLastPowerDownWhileInteractive = interactive ? event.getEventTime() : 0; + mLastPowerDown = event.getEventTime(); } if (launched) { Slog.i(TAG, "Power button double tap gesture detected, launching camera."); - launched = handleCameraLaunchGesture(false /* useWakelock */, - MetricsLogger.ACTION_DOUBLE_TAP_POWER_CAMERA_GESTURE); + launched = handleCameraLaunchGesture(false /* useWakelock */); + if (launched) { + MetricsLogger.action(mContext, MetricsLogger.ACTION_DOUBLE_TAP_POWER_CAMERA_GESTURE, + (int) doubleTapInterval); + } } + MetricsLogger.histogram(mContext, "power_double_tap_interval", (int) doubleTapInterval); return intercept && launched; } /** * @return true if camera was launched, false otherwise. */ - private boolean handleCameraLaunchGesture(boolean useWakelock, int logCategory) { + private boolean handleCameraLaunchGesture(boolean useWakelock) { boolean userSetupComplete = Settings.Secure.getInt(mContext.getContentResolver(), Settings.Secure.USER_SETUP_COMPLETE, 0) != 0; if (!userSetupComplete) { @@ -300,7 +296,6 @@ public class GestureLauncherService extends SystemService { StatusBarManagerInternal service = LocalServices.getService( StatusBarManagerInternal.class); service.onCameraLaunchGestureDetected(); - MetricsLogger.action(mContext, logCategory); return true; } @@ -339,8 +334,8 @@ public class GestureLauncherService extends SystemService { Slog.d(TAG, String.format("Received a camera launch event: " + "values=[%.4f, %.4f, %.4f].", values[0], values[1], values[2])); } - if (handleCameraLaunchGesture(true /* useWakelock */, - MetricsLogger.ACTION_WIGGLE_CAMERA_GESTURE)) { + if (handleCameraLaunchGesture(true /* useWakelock */)) { + MetricsLogger.action(mContext, MetricsLogger.ACTION_WIGGLE_CAMERA_GESTURE); trackCameraLaunchEvent(event); } return; diff --git a/services/core/java/com/android/server/LocationManagerService.java b/services/core/java/com/android/server/LocationManagerService.java index 885c765f3f4b..087ddd6fd882 100644 --- a/services/core/java/com/android/server/LocationManagerService.java +++ b/services/core/java/com/android/server/LocationManagerService.java @@ -211,8 +211,8 @@ public class LocationManagerService extends ILocationManager.Stub { new ArrayList<LocationProviderProxy>(); // current active user on the device - other users are denied location data - private int mCurrentUserId = UserHandle.USER_OWNER; - private int[] mCurrentUserProfiles = new int[] { UserHandle.USER_OWNER }; + private int mCurrentUserId = UserHandle.USER_SYSTEM; + private int[] mCurrentUserProfiles = new int[] { UserHandle.USER_SYSTEM }; public LocationManagerService(Context context) { super(); @@ -1832,7 +1832,8 @@ public class LocationManagerService extends ILocationManager.Stub { // geo-fence manager uses the public location API, need to clear identity int uid = Binder.getCallingUid(); - if (UserHandle.getUserId(uid) != UserHandle.USER_OWNER) { + // TODO: http://b/23822629 + if (UserHandle.getUserId(uid) != UserHandle.USER_SYSTEM) { // temporary measure until geofences work for secondary users Log.w(TAG, "proximity alerts are currently available only to the primary user"); return; diff --git a/services/core/java/com/android/server/MountService.java b/services/core/java/com/android/server/MountService.java index 540f8cb8557c..c3d32c2a870b 100644 --- a/services/core/java/com/android/server/MountService.java +++ b/services/core/java/com/android/server/MountService.java @@ -2981,7 +2981,7 @@ class MountService extends IMountService.Stub Intent service = new Intent().setComponent(DEFAULT_CONTAINER_COMPONENT); if (mContext.bindServiceAsUser(service, mDefContainerConn, Context.BIND_AUTO_CREATE, - UserHandle.OWNER)) { + UserHandle.SYSTEM)) { mBound = true; return true; } @@ -3014,7 +3014,6 @@ class MountService extends IMountService.Stub Slog.w(TAG, "Failed to invoke remote methods on default container service. Giving up"); mObbActionHandler.sendEmptyMessage(OBB_MCS_UNBIND); handleError(); - return; } else { handleExecute(); if (DEBUG_OBB) @@ -3176,8 +3175,6 @@ class MountService extends IMountService.Stub waitForReady(); warnOnNotMounted(); - final ObbInfo obbInfo = getObbInfo(); - final ObbState existingState; synchronized (mObbMounts) { existingState = mObbPathToStateMap.get(mObbState.rawPath); diff --git a/services/core/java/com/android/server/NetworkScoreService.java b/services/core/java/com/android/server/NetworkScoreService.java index b05a6908aee5..b984e1938758 100644 --- a/services/core/java/com/android/server/NetworkScoreService.java +++ b/services/core/java/com/android/server/NetworkScoreService.java @@ -133,8 +133,8 @@ public class NetworkScoreService extends INetworkScoreService.Stub { filter.addDataSchemeSpecificPart(scorer.mPackageName, PatternMatcher.PATTERN_LITERAL); mReceiver = new ScorerChangedReceiver(scorer.mPackageName); - // TODO: Need to update when we support per-user scorers. - mContext.registerReceiverAsUser(mReceiver, UserHandle.OWNER, filter, null, null); + // TODO: Need to update when we support per-user scorers. http://b/23422763 + mContext.registerReceiverAsUser(mReceiver, UserHandle.SYSTEM, filter, null, null); if (Log.isLoggable(TAG, Log.VERBOSE)) { Log.v(TAG, "Registered receiver for " + scorer.mPackageName); } diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java index 372a5fad14c2..07a7af46e265 100644 --- a/services/core/java/com/android/server/am/ActivityManagerService.java +++ b/services/core/java/com/android/server/am/ActivityManagerService.java @@ -33,6 +33,7 @@ import static com.android.server.Watchdog.NATIVE_STACKS_OF_INTEREST; import static com.android.server.am.ActivityManagerDebugConfig.*; import static com.android.server.am.ActivityStackSupervisor.FORCE_FOCUS; import static com.android.server.am.ActivityStackSupervisor.ON_TOP; +import static com.android.server.am.ActivityStackSupervisor.PRESERVE_WINDOWS; import static com.android.server.am.TaskRecord.INVALID_TASK_ID; import static com.android.server.am.TaskRecord.LOCK_TASK_AUTH_DONT_LOCK; import static com.android.server.am.TaskRecord.LOCK_TASK_AUTH_LAUNCHABLE_PRIV; @@ -2020,7 +2021,7 @@ public final class ActivityManagerService extends ActivityManagerNative intent, PendingIntent.FLAG_CANCEL_CURRENT, null, new UserHandle(userId))) .setDeleteIntent(PendingIntent.getBroadcastAsUser(mContext, 0, - deleteIntent, 0, UserHandle.OWNER)) + deleteIntent, 0, UserHandle.SYSTEM)) .build(); try { @@ -2378,8 +2379,8 @@ public final class ActivityManagerService extends ActivityManagerNative mGrantFile = new AtomicFile(new File(systemDir, "urigrants.xml")); // User 0 is the first and only user that runs at boot. - mStartedUsers.put(UserHandle.USER_OWNER, new UserState(UserHandle.OWNER, true)); - mUserLru.add(UserHandle.USER_OWNER); + mStartedUsers.put(UserHandle.USER_SYSTEM, new UserState(UserHandle.SYSTEM, true)); + mUserLru.add(UserHandle.USER_SYSTEM); updateStartedUserArrayLocked(); GL_ES_VERSION = SystemProperties.getInt("ro.opengles.version", @@ -4626,7 +4627,7 @@ public final class ActivityManagerService extends ActivityManagerNative // is hosted by the process... then make sure all visible // activities are running, taking care of restarting this // process. - mStackSupervisor.ensureActivitiesVisibleLocked(null, 0); + mStackSupervisor.ensureActivitiesVisibleLocked(null, 0, !PRESERVE_WINDOWS); } } @@ -5646,7 +5647,7 @@ public final class ActivityManagerService extends ActivityManagerNative try { // Entire package setting changed enabled = pm.getApplicationEnabledSetting(packageName, - (userId != UserHandle.USER_ALL) ? userId : UserHandle.USER_OWNER); + (userId != UserHandle.USER_ALL) ? userId : UserHandle.USER_SYSTEM); } catch (Exception e) { // No such package/component; probably racing with uninstall. In any // event it means we have nothing further to do here. @@ -5664,7 +5665,7 @@ public final class ActivityManagerService extends ActivityManagerNative try { enabled = pm.getComponentEnabledSetting( new ComponentName(packageName, changedClass), - (userId != UserHandle.USER_ALL) ? userId : UserHandle.USER_OWNER); + (userId != UserHandle.USER_ALL) ? userId : UserHandle.USER_SYSTEM); } catch (Exception e) { // As above, probably racing with uninstall. return; @@ -8664,14 +8665,14 @@ public final class ActivityManagerService extends ActivityManagerNative } if (task.mResizeable != resizeable) { task.mResizeable = resizeable; - mStackSupervisor.ensureActivitiesVisibleLocked(null, 0); + mStackSupervisor.ensureActivitiesVisibleLocked(null, 0, !PRESERVE_WINDOWS); mStackSupervisor.resumeTopActivitiesLocked(); } } } @Override - public void resizeTask(int taskId, Rect bounds, boolean resizedByUser) { + public void resizeTask(int taskId, Rect bounds, int resizeMode) { enforceCallingPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS, "resizeTask()"); long ident = Binder.clearCallingIdentity(); @@ -8682,7 +8683,7 @@ public final class ActivityManagerService extends ActivityManagerNative Slog.w(TAG, "resizeTask: taskId=" + taskId + " not found"); return; } - mStackSupervisor.resizeTaskLocked(task, bounds, resizedByUser); + mStackSupervisor.resizeTaskLocked(task, bounds, resizeMode); } } finally { Binder.restoreCallingIdentity(ident); @@ -9108,7 +9109,7 @@ public final class ActivityManagerService extends ActivityManagerNative long ident = Binder.clearCallingIdentity(); try { synchronized (this) { - mStackSupervisor.resizeStackLocked(stackId, bounds); + mStackSupervisor.resizeStackLocked(stackId, bounds, !PRESERVE_WINDOWS); } } finally { Binder.restoreCallingIdentity(ident); @@ -9391,7 +9392,7 @@ public final class ActivityManagerService extends ActivityManagerNative (ProviderInfo)providers.get(i); boolean singleton = isSingleton(cpi.processName, cpi.applicationInfo, cpi.name, cpi.flags); - if (singleton && UserHandle.getUserId(app.uid) != UserHandle.USER_OWNER) { + if (singleton && UserHandle.getUserId(app.uid) != UserHandle.USER_SYSTEM) { // This is a singleton provider, but a user besides the // default user is asking to initialize a process it runs // in... well, no, it doesn't actually run in this process, @@ -9613,7 +9614,7 @@ public final class ActivityManagerService extends ActivityManagerNative } } - private final ContentProviderHolder getContentProviderImpl(IApplicationThread caller, + private ContentProviderHolder getContentProviderImpl(IApplicationThread caller, String name, IBinder token, boolean stable, int userId) { ContentProviderRecord cpr; ContentProviderConnection conn = null; @@ -9641,14 +9642,14 @@ public final class ActivityManagerService extends ActivityManagerNative cpr = mProviderMap.getProviderByName(name, userId); // If that didn't work, check if it exists for user 0 and then // verify that it's a singleton provider before using it. - if (cpr == null && userId != UserHandle.USER_OWNER) { - cpr = mProviderMap.getProviderByName(name, UserHandle.USER_OWNER); + if (cpr == null && userId != UserHandle.USER_SYSTEM) { + cpr = mProviderMap.getProviderByName(name, UserHandle.USER_SYSTEM); if (cpr != null) { cpi = cpr.info; if (isSingleton(cpi.processName, cpi.applicationInfo, cpi.name, cpi.flags) && isValidSingletonCall(r.uid, cpi.applicationInfo.uid)) { - userId = UserHandle.USER_OWNER; + userId = UserHandle.USER_SYSTEM; checkCrossUser = false; } else { cpr = null; @@ -9741,7 +9742,6 @@ public final class ActivityManagerService extends ActivityManagerNative Binder.restoreCallingIdentity(origId); } - boolean singleton; if (!providerRunning) { try { checkTime(startTime, "getContentProviderImpl: before resolveContentProvider"); @@ -9758,11 +9758,11 @@ public final class ActivityManagerService extends ActivityManagerNative // (it's a call within the same user || the provider is a // privileged app) // Then allow connecting to the singleton provider - singleton = isSingleton(cpi.processName, cpi.applicationInfo, + boolean singleton = isSingleton(cpi.processName, cpi.applicationInfo, cpi.name, cpi.flags) && isValidSingletonCall(r.uid, cpi.applicationInfo.uid); if (singleton) { - userId = UserHandle.USER_OWNER; + userId = UserHandle.USER_SYSTEM; } cpi.applicationInfo = getAppInfoForUser(cpi.applicationInfo, userId); checkTime(startTime, "getContentProviderImpl: got app info for user"); @@ -10365,7 +10365,7 @@ public final class ActivityManagerService extends ActivityManagerNative } final ProcessRecord r = new ProcessRecord(stats, info, proc, uid); if (!mBooted && !mBooting - && userId == UserHandle.USER_OWNER + && userId == UserHandle.USER_SYSTEM && (info.flags & PERSISTENT_MASK) == PERSISTENT_MASK) { r.persistent = true; } @@ -11188,7 +11188,7 @@ public final class ActivityManagerService extends ActivityManagerNative final boolean translucentChanged = r.changeWindowTranslucency(true); if (translucentChanged) { r.task.stack.releaseBackgroundResources(r); - mStackSupervisor.ensureActivitiesVisibleLocked(null, 0); + mStackSupervisor.ensureActivitiesVisibleLocked(null, 0, !PRESERVE_WINDOWS); } mWindowManager.setAppFullscreen(token, true); return translucentChanged; @@ -11216,7 +11216,7 @@ public final class ActivityManagerService extends ActivityManagerNative if (translucentChanged) { r.task.stack.convertActivityToTranslucent(r); } - mStackSupervisor.ensureActivitiesVisibleLocked(null, 0); + mStackSupervisor.ensureActivitiesVisibleLocked(null, 0, !PRESERVE_WINDOWS); mWindowManager.setAppFullscreen(token, false); return translucentChanged; } @@ -11822,12 +11822,12 @@ public final class ActivityManagerService extends ActivityManagerNative } private boolean deliverPreBootCompleted(final Runnable onFinishCallback, - ArrayList<ComponentName> doneReceivers, int userId) { + ArrayList<ComponentName> doneReceivers) { Intent intent = new Intent(Intent.ACTION_PRE_BOOT_COMPLETED); List<ResolveInfo> ris = null; try { ris = AppGlobals.getPackageManager().queryIntentReceivers( - intent, null, 0, userId); + intent, null, 0, UserHandle.USER_SYSTEM); } catch (RemoteException e) { } if (ris == null) { @@ -11841,22 +11841,18 @@ public final class ActivityManagerService extends ActivityManagerNative } intent.addFlags(Intent.FLAG_RECEIVER_BOOT_UPGRADE); - // For User 0, load the version number. When delivering to a new user, deliver - // to all receivers. - if (userId == UserHandle.USER_OWNER) { - ArrayList<ComponentName> lastDoneReceivers = readLastDonePreBootReceivers(); - for (int i=0; i<ris.size(); i++) { - ActivityInfo ai = ris.get(i).activityInfo; - ComponentName comp = new ComponentName(ai.packageName, ai.name); - if (lastDoneReceivers.contains(comp)) { - // We already did the pre boot receiver for this app with the current - // platform version, so don't do it again... - ris.remove(i); - i--; - // ...however, do keep it as one that has been done, so we don't - // forget about it when rewriting the file of last done receivers. - doneReceivers.add(comp); - } + ArrayList<ComponentName> lastDoneReceivers = readLastDonePreBootReceivers(); + for (int i=0; i<ris.size(); i++) { + ActivityInfo ai = ris.get(i).activityInfo; + ComponentName comp = new ComponentName(ai.packageName, ai.name); + if (lastDoneReceivers.contains(comp)) { + // We already did the pre boot receiver for this app with the current + // platform version, so don't do it again... + ris.remove(i); + i--; + // ...however, do keep it as one that has been done, so we don't + // forget about it when rewriting the file of last done receivers. + doneReceivers.add(comp); } } @@ -11864,9 +11860,8 @@ public final class ActivityManagerService extends ActivityManagerNative return false; } - // If primary user, send broadcast to all available users, else just to userId - final int[] users = userId == UserHandle.USER_OWNER ? getUsersLocked() - : new int[] { userId }; + // TODO: can we still do this with per user encryption? + final int[] users = getUsersLocked(); if (users.length <= 0) { return false; } @@ -11917,7 +11912,7 @@ public final class ActivityManagerService extends ActivityManagerNative writeLastDonePreBootReceivers(doneReceivers); systemReady(goingCallback); } - }, doneReceivers, UserHandle.USER_OWNER); + }, doneReceivers); if (mWaitingUpdate) { return; @@ -17699,7 +17694,8 @@ public final class ActivityManagerService extends ActivityManagerNative kept = mainStack.ensureActivityConfigurationLocked(starting, changes, false); // And we need to make sure at this point that all other activities // are made visible with the correct configuration. - mStackSupervisor.ensureActivitiesVisibleLocked(starting, changes); + mStackSupervisor.ensureActivitiesVisibleLocked(starting, changes, + !PRESERVE_WINDOWS); } } @@ -20170,7 +20166,7 @@ public final class ActivityManagerService extends ActivityManagerNative } if ((userInfo.flags&UserInfo.FLAG_INITIALIZED) == 0) { - if (userId != UserHandle.USER_OWNER) { + if (userId != UserHandle.USER_SYSTEM) { Intent intent = new Intent(Intent.ACTION_USER_INITIALIZE); intent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND); broadcastIntentLocked(null, null, intent, null, @@ -20408,7 +20404,7 @@ public final class ActivityManagerService extends ActivityManagerNative for (int i = 0; i < num; i++) { Integer oldUserId = mUserLru.get(i); UserState oldUss = mStartedUsers.get(oldUserId); - if (oldUserId == UserHandle.USER_OWNER || oldUserId == mCurrentUserId + if (oldUserId == UserHandle.USER_SYSTEM || oldUserId == mCurrentUserId || oldUss.mState == UserState.STATE_STOPPING || oldUss.mState == UserState.STATE_SHUTDOWN) { continue; @@ -20493,8 +20489,12 @@ public final class ActivityManagerService extends ActivityManagerNative i++; continue; } - if (oldUserId == UserHandle.USER_OWNER || oldUserId == mCurrentUserId) { - // Owner and current can't be stopped, but count as running. + if (oldUserId == UserHandle.USER_SYSTEM || oldUserId == mCurrentUserId) { + // Owner/System user and current user can't be stopped. We count it as running + // when it is not a pure system user. + if (UserInfo.isSystemOnly(oldUserId)) { + num--; + } i++; continue; } @@ -20517,8 +20517,8 @@ public final class ActivityManagerService extends ActivityManagerNative Slog.w(TAG, msg); throw new SecurityException(msg); } - if (userId < 0 || userId == UserHandle.USER_OWNER) { - throw new IllegalArgumentException("Can't stop primary user " + userId); + if (userId < 0 || userId == UserHandle.USER_SYSTEM) { + throw new IllegalArgumentException("Can't stop system user " + userId); } enforceShellRestriction(UserManager.DISALLOW_DEBUGGING_FEATURES, userId); synchronized (this) { diff --git a/services/core/java/com/android/server/am/ActivityStack.java b/services/core/java/com/android/server/am/ActivityStack.java index 3fcffd78d049..9809c2e4906c 100644 --- a/services/core/java/com/android/server/am/ActivityStack.java +++ b/services/core/java/com/android/server/am/ActivityStack.java @@ -30,6 +30,7 @@ import static com.android.server.am.ActivityRecord.HOME_ACTIVITY_TYPE; import static com.android.server.am.ActivityRecord.APPLICATION_ACTIVITY_TYPE; import static com.android.server.am.ActivityStackSupervisor.MOVING; +import static com.android.server.am.ActivityStackSupervisor.PRESERVE_WINDOWS; import android.graphics.Rect; import android.util.ArraySet; @@ -528,21 +529,15 @@ final class ActivityStack { * */ void moveToFront(String reason, TaskRecord task) { if (isAttached()) { - final boolean homeStack = isHomeStack() - || (mActivityContainer.mParentActivity != null - && mActivityContainer.mParentActivity.isHomeActivity()); - ActivityStack lastFocusStack = null; - if (!homeStack) { - // Need to move this stack to the front before calling - // {@link ActivityStackSupervisor#moveHomeStack} below. - lastFocusStack = mStacks.get(mStacks.size() - 1); - mStacks.remove(this); - mStacks.add(this); - } - // TODO(multi-display): Focus stack currently adjusted in call to move home stack. - // Needs to also work if focus is moving to the non-home display. + final ActivityStack lastFocusStack = mStacks.get(mStacks.size() - 1); + // Need to move this stack to the front before calling + // {@link ActivityStackSupervisor#setFocusStack} below. + mStacks.remove(this); + mStacks.add(this); + + // TODO(multi-display): Needs to also work if focus is moving to the non-home display. if (isOnHomeDisplay()) { - mStackSupervisor.moveHomeStack(homeStack, reason, lastFocusStack); + mStackSupervisor.setFocusStack(reason, lastFocusStack); } if (task != null) { insertTaskAtTop(task, null); @@ -815,7 +810,7 @@ final class ActivityStack { } void goToSleep() { - ensureActivitiesVisibleLocked(null, 0); + ensureActivitiesVisibleLocked(null, 0, !PRESERVE_WINDOWS); // Make sure any stopped but visible activities are now sleeping. // This ensures that the activity's onStop() is called. @@ -1335,17 +1330,28 @@ final class ActivityStack { return topHomeActivity == null || !topHomeActivity.isHomeActivity(); } - if (focusedStackId == DOCKED_STACK_ID - && stackIndex == (mStacks.indexOf(focusedStack) - 1)) { + final int belowFocusedIndex = mStacks.indexOf(focusedStack) - 1; + if (focusedStackId == DOCKED_STACK_ID && stackIndex == belowFocusedIndex) { // Stacks directly behind the docked stack are always visible. return true; } - if (mStackId == HOME_STACK_ID && focusedStackId == FULLSCREEN_WORKSPACE_STACK_ID) { - // Home stack is always visible behind the fullscreen stack with a translucent activity. - // This is done so that the home stack can act as a background to the translucent - // activity. - return hasTranslucentActivity(focusedStack); + if (focusedStackId == FULLSCREEN_WORKSPACE_STACK_ID + && hasTranslucentActivity(focusedStack)) { + // Stacks behind the fullscreen stack with a translucent activity are always + // visible so they can act as a backdrop to the translucent activity. + // For example, dialog activities + if (stackIndex == belowFocusedIndex) { + return true; + } + if (belowFocusedIndex >= 0) { + final ActivityStack stack = mStacks.get(belowFocusedIndex); + if (stack.mStackId == DOCKED_STACK_ID && stackIndex == (belowFocusedIndex - 1)) { + // The stack behind the docked stack is also visible so we can have a complete + // backdrop to the translucent activity when the docked stack is up. + return true; + } + } } if (mStackId >= FIRST_STATIC_STACK_ID && mStackId <= LAST_STATIC_STACK_ID) { @@ -1379,7 +1385,8 @@ final class ActivityStack { * Make sure that all activities that need to be visible (that is, they * currently can be seen by the user) actually are. */ - final void ensureActivitiesVisibleLocked(ActivityRecord starting, int configChanges) { + final void ensureActivitiesVisibleLocked(ActivityRecord starting, int configChanges, + boolean preserveWindows) { ActivityRecord top = topRunningActivityLocked(null); if (top == null) { return; @@ -1428,7 +1435,7 @@ final class ActivityStack { // First: if this is not the current activity being started, make // sure it matches the current configuration. if (r != starting) { - ensureActivityConfigurationLocked(r, 0, false); + ensureActivityConfigurationLocked(r, 0, preserveWindows); } if (r.app == null || r.app.thread == null) { @@ -2342,7 +2349,7 @@ final class ActivityStack { // Don't do a starting window for mLaunchTaskBehind. More importantly make sure we // tell WindowManager that r is visible even though it is at the back of the stack. mWindowManager.setAppVisibility(r.appToken, true); - ensureActivitiesVisibleLocked(null, 0); + ensureActivitiesVisibleLocked(null, 0, !PRESERVE_WINDOWS); } else if (SHOW_APP_STARTING_PREVIEW && doShow) { // Figure out if we are transitioning from another activity that is // "has the same starting icon" as the next one. This allows the @@ -4024,6 +4031,11 @@ final class ActivityStack { return true; } + if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Slog.v(TAG_CONFIGURATION, + "Configuration changes for " + r + " ; taskChanges=" + + Configuration.configurationDiffToString(taskChanges) + ", allChanges=" + + Configuration.configurationDiffToString(changes)); + // If the activity isn't currently running, just leave the new // configuration and it will pick that up next time it starts. if (r.app == null || r.app.thread == null) { @@ -4536,18 +4548,17 @@ final class ActivityStack { if (mTaskHistory.isEmpty()) { if (DEBUG_STACK) Slog.i(TAG_STACK, "removeTask: removing stack=" + this); - final boolean notHomeStack = !isHomeStack(); if (isOnHomeDisplay()) { String myReason = reason + " leftTaskHistoryEmpty"; if (mFullscreen || !adjustFocusToNextVisibleStackLocked(null, myReason)) { - mStackSupervisor.moveHomeStack(notHomeStack, myReason); + mStackSupervisor.moveHomeStackToFront(myReason); } } if (mStacks != null) { mStacks.remove(this); mStacks.add(0, this); } - if (notHomeStack) { + if (!isHomeStack()) { mActivityContainer.onTaskListEmptyLocked(); } } @@ -4564,6 +4575,8 @@ final class ActivityStack { addTask(task, toTop, false); if (mTaskPositioner != null) { mTaskPositioner.updateDefaultBounds(task, mTaskHistory, info.initialLayout); + } else if (mBounds != null && task.mResizeable) { + task.updateOverrideConfiguration(mBounds); } return task; } diff --git a/services/core/java/com/android/server/am/ActivityStackSupervisor.java b/services/core/java/com/android/server/am/ActivityStackSupervisor.java index d3cea8de1442..17a44720deaf 100644 --- a/services/core/java/com/android/server/am/ActivityStackSupervisor.java +++ b/services/core/java/com/android/server/am/ActivityStackSupervisor.java @@ -175,6 +175,9 @@ public final class ActivityStackSupervisor implements DisplayListener { // should be created if it doesn't exist already. private static final boolean CREATE_IF_NEEDED = true; + // Used to indicate that windows of activities should be preserved during the resize. + static final boolean PRESERVE_WINDOWS = true; + // Used to indicate if an object (e.g. task) should be moved/created // at the top of its container (e.g. stack). static final boolean ON_TOP = true; @@ -189,6 +192,7 @@ public final class ActivityStackSupervisor implements DisplayListener { // Activity actions an app cannot start if it uses a permission which is not granted. private static final ArrayMap<String, String> ACTION_TO_RUNTIME_PERMISSION = new ArrayMap<>(); + static { ACTION_TO_RUNTIME_PERMISSION.put(MediaStore.ACTION_IMAGE_CAPTURE, Manifest.permission.CAMERA); @@ -464,35 +468,22 @@ public final class ActivityStackSupervisor implements DisplayListener { return stack == mFocusedStack; } - void moveHomeStack(boolean toFront, String reason) { - moveHomeStack(toFront, reason, null); - } - - void moveHomeStack(boolean toFront, String reason, ActivityStack lastFocusedStack) { + void setFocusStack(String reason, ActivityStack lastFocusedStack) { ArrayList<ActivityStack> stacks = mHomeStack.mStacks; final int topNdx = stacks.size() - 1; if (topNdx <= 0) { return; } - // The home stack should either be at the top or bottom of the stack list. - if ((toFront && (stacks.get(topNdx) != mHomeStack)) - || (!toFront && (stacks.get(0) != mHomeStack))) { - if (DEBUG_STACK) Slog.d(TAG_STACK, "moveHomeTask: topStack old=" - + ((lastFocusedStack != null) ? lastFocusedStack : stacks.get(topNdx)) - + " new=" + mFocusedStack); - stacks.remove(mHomeStack); - stacks.add(toFront ? topNdx : 0, mHomeStack); - } - + final ActivityStack topStack = stacks.get(topNdx); + mFocusedStack = topStack; if (lastFocusedStack != null) { mLastFocusedStack = lastFocusedStack; } - mFocusedStack = stacks.get(topNdx); - EventLog.writeEvent(EventLogTags.AM_HOME_STACK_MOVED, - mCurrentUser, toFront ? 1 : 0, stacks.get(topNdx).getStackId(), - mFocusedStack == null ? -1 : mFocusedStack.getStackId(), reason); + EventLogTags.writeAmFocusedStack( + mCurrentUser, mFocusedStack == null ? -1 : mFocusedStack.getStackId(), + mLastFocusedStack == null ? -1 : mLastFocusedStack.getStackId(), reason); if (mService.mBooting || !mService.mBooted) { final ActivityRecord r = topRunningActivityLocked(); @@ -502,6 +493,10 @@ public final class ActivityStackSupervisor implements DisplayListener { } } + void moveHomeStackToFront(String reason) { + mHomeStack.moveToFront(reason); + } + /** Returns true if the focus activity was adjusted to the home stack top activity. */ boolean moveHomeStackTaskToTop(int homeStackTaskType, String reason) { if (homeStackTaskType == RECENTS_ACTIVITY_TYPE) { @@ -660,7 +655,7 @@ public final class ActivityStackSupervisor implements DisplayListener { } } if (!didSomething) { - ensureActivitiesVisibleLocked(null, 0); + ensureActivitiesVisibleLocked(null, 0, !PRESERVE_WINDOWS); } return didSomething; } @@ -1803,8 +1798,11 @@ public final class ActivityStackSupervisor implements DisplayListener { return container.mStack; } - if (mFocusedStack != mHomeStack && (!newTask || - mFocusedStack.mActivityContainer.isEligibleForNewTasks())) { + // The fullscreen stack is the only stack that can contain any task regardless of if + // the task is resizeable or not. So, we let the task go in the fullscreen task if it + // is the focus stack. + if (mFocusedStack.mStackId == FULLSCREEN_WORKSPACE_STACK_ID + && (!newTask || mFocusedStack.mActivityContainer.isEligibleForNewTasks())) { if (DEBUG_FOCUS || DEBUG_STACK) Slog.d(TAG_FOCUS, "computeStackFocus: Have a focused stack=" + mFocusedStack); return mFocusedStack; @@ -1823,7 +1821,7 @@ public final class ActivityStackSupervisor implements DisplayListener { } // If there is no suitable dynamic stack then we figure out which static stack to use. - int stackId = task != null ? task.getLaunchStackId() : + final int stackId = task != null ? task.getLaunchStackId() : bounds != null ? FREEFORM_WORKSPACE_STACK_ID : FULLSCREEN_WORKSPACE_STACK_ID; stack = getStack(stackId, CREATE_IF_NEEDED, ON_TOP); @@ -2629,7 +2627,7 @@ public final class ActivityStackSupervisor implements DisplayListener { } mLaunchingActivity.release(); } - ensureActivitiesVisibleLocked(null, 0); + ensureActivitiesVisibleLocked(null, 0, !PRESERVE_WINDOWS); } // Atomically retrieve all of the other things to do. @@ -2859,7 +2857,8 @@ public final class ActivityStackSupervisor implements DisplayListener { if (opts.hasBounds()) { Rect bounds = opts.getBounds(); task.updateOverrideConfiguration(bounds); - mWindowManager.resizeTask(task.taskId, bounds, task.mOverrideConfig, false); + mWindowManager.resizeTask(task.taskId, bounds, task.mOverrideConfig, + false /*relayout*/, false /*forced*/); stackId = task.getLaunchStackId(); } } @@ -2962,7 +2961,7 @@ public final class ActivityStackSupervisor implements DisplayListener { } } - void resizeStackLocked(int stackId, Rect bounds) { + void resizeStackLocked(int stackId, Rect bounds, boolean preserveWindows) { final ActivityStack stack = getStack(stackId); if (stack == null) { Slog.w(TAG, "resizeStack: stackId " + stackId + " not found."); @@ -2970,31 +2969,29 @@ public final class ActivityStackSupervisor implements DisplayListener { } ActivityRecord r = stack.topRunningActivityLocked(null); - final boolean resizeTasks = r != null && r.task.mResizeable; mTmpBounds.clear(); mTmpConfigs.clear(); - if (resizeTasks) { - ArrayList<TaskRecord> tasks = stack.getAllTasks(); - for (int i = tasks.size() - 1; i >= 0; i--) { - TaskRecord task = tasks.get(i); + ArrayList<TaskRecord> tasks = stack.getAllTasks(); + for (int i = tasks.size() - 1; i >= 0; i--) { + TaskRecord task = tasks.get(i); + if (task.mResizeable) { if (stack.mStackId == FREEFORM_WORKSPACE_STACK_ID) { - // For freeform stack we don't adjust the size of the tasks to match that of - // the stack, but we do try to make sure the tasks are still contained with the - // bounds of the stack. + // For freeform stack we don't adjust the size of the tasks to match that + // of the stack, but we do try to make sure the tasks are still contained + // with the bounds of the stack. tempRect2.set(task.mBounds); fitWithinBounds(tempRect2, bounds); task.updateOverrideConfiguration(tempRect2); } else { task.updateOverrideConfiguration(bounds); } - - mTmpConfigs.put(task.taskId, task.mOverrideConfig); - mTmpBounds.put(task.taskId, task.mBounds); } + + mTmpConfigs.put(task.taskId, task.mOverrideConfig); + mTmpBounds.put(task.taskId, task.mBounds); } - stack.mFullscreen = mWindowManager.resizeStack(stackId, bounds, resizeTasks, mTmpConfigs, - mTmpBounds); + stack.mFullscreen = mWindowManager.resizeStack(stackId, bounds, mTmpConfigs, mTmpBounds); if (stack.mStackId == DOCKED_STACK_ID) { // Dock stack funness...Yay! if (stack.mFullscreen) { @@ -3003,11 +3000,10 @@ public final class ActivityStackSupervisor implements DisplayListener { // docked stack tasks to the fullscreen stack. for (int i = FIRST_STATIC_STACK_ID; i <= LAST_STATIC_STACK_ID; i++) { if (i != DOCKED_STACK_ID) { - resizeStackLocked(i, null); + resizeStackLocked(i, null, preserveWindows); } } - final ArrayList<TaskRecord> tasks = stack.getAllTasks(); final int count = tasks.size(); for (int i = 0; i < count; i++) { moveTaskToStackLocked(tasks.get(i).taskId, @@ -3035,33 +3031,38 @@ public final class ActivityStackSupervisor implements DisplayListener { tempRect.right -= leftChange; tempRect.top -= bottomChange; tempRect.bottom -= topChange; - resizeStackLocked(i, tempRect); + resizeStackLocked(i, tempRect, PRESERVE_WINDOWS); } } } - } + // Since we are resizing the stack, all other operations should strive to preserve + // windows. + preserveWindows = true; } stack.setBounds(bounds); if (r != null) { - final boolean updated = stack.ensureActivityConfigurationLocked(r, 0, false); + final boolean updated = stack.ensureActivityConfigurationLocked(r, 0, preserveWindows); // And we need to make sure at this point that all other activities // are made visible with the correct configuration. - ensureActivitiesVisibleLocked(r, 0); + ensureActivitiesVisibleLocked(r, 0, preserveWindows); if (!updated) { resumeTopActivitiesLocked(stack, null, null); } } } - void resizeTaskLocked(TaskRecord task, Rect bounds, boolean resizedByUser) { + void resizeTaskLocked(TaskRecord task, Rect bounds, int resizeMode) { if (!task.mResizeable) { Slog.w(TAG, "resizeTask: task " + task + " not resizeable."); return; } - if (task.mBounds != null && task.mBounds.equals(bounds)) { + // If this is a forced resize, let it go through even if the bounds is not changing, + // as we might need a relayout due to surface size change (to/from fullscreen). + final boolean forced = (resizeMode == RESIZE_MODE_FORCED); + if (task.mBounds != null && task.mBounds.equals(bounds) && !forced) { // Nothing to do here... return; } @@ -3102,10 +3103,11 @@ public final class ActivityStackSupervisor implements DisplayListener { ActivityRecord r = task.topRunningActivityLocked(null); if (r != null) { final ActivityStack stack = task.stack; + final boolean resizedByUser = resizeMode == RESIZE_MODE_USER; final boolean preserveWindow = resizedByUser && !changedStacks; kept = stack.ensureActivityConfigurationLocked(r, 0, preserveWindow); // All other activities must be made visible with their correct configuration. - ensureActivitiesVisibleLocked(r, 0); + ensureActivitiesVisibleLocked(r, 0, !PRESERVE_WINDOWS); if (!kept) { resumeTopActivitiesLocked(stack, null, null); if (changedStacks && stackId == FULLSCREEN_WORKSPACE_STACK_ID) { @@ -3121,7 +3123,7 @@ public final class ActivityStackSupervisor implements DisplayListener { } } } - mWindowManager.resizeTask(task.taskId, bounds, task.mOverrideConfig, kept); + mWindowManager.resizeTask(task.taskId, bounds, task.mOverrideConfig, kept, forced); } ActivityStack createStackOnDisplay(int stackId, int displayId, boolean onTop) { @@ -3208,7 +3210,13 @@ public final class ActivityStackSupervisor implements DisplayListener { final boolean wasFocused = isFrontStack(task.stack) && (topRunningActivityLocked() == r); final boolean wasResumed = wasFocused && (task.stack.mResumedActivity == r); + final boolean resizeable = task.mResizeable; + // Temporarily disable resizeablility of task we are moving. We don't want it to be resized + // if a docked stack is created below which will lead to the stack we are moving from and + // its resizeable tasks being resized. + task.mResizeable = false; final ActivityStack stack = getStack(stackId, CREATE_IF_NEEDED, toTop); + task.mResizeable = resizeable; mWindowManager.moveTaskToStack(task.taskId, stack.mStackId, toTop); if (task.stack != null) { task.stack.removeTask(task, reason, MOVING); @@ -3243,17 +3251,17 @@ public final class ActivityStackSupervisor implements DisplayListener { // Make sure the task has the appropriate bounds/size for the stack it is in. if (stackId == FULLSCREEN_WORKSPACE_STACK_ID && task.mBounds != null) { - resizeTaskLocked(task, stack.mBounds, false); + resizeTaskLocked(task, stack.mBounds, RESIZE_MODE_SYSTEM); } else if (stackId == FREEFORM_WORKSPACE_STACK_ID && task.mBounds == null && task.mLastNonFullscreenBounds != null) { - resizeTaskLocked(task, task.mLastNonFullscreenBounds, false); + resizeTaskLocked(task, task.mLastNonFullscreenBounds, RESIZE_MODE_SYSTEM); } else if (stackId == DOCKED_STACK_ID) { - resizeTaskLocked(task, stack.mBounds, false); + resizeTaskLocked(task, stack.mBounds, RESIZE_MODE_SYSTEM); } // The task might have already been running and its visibility needs to be synchronized with // the visibility of the stack / windows. - ensureActivitiesVisibleLocked(null, 0); + ensureActivitiesVisibleLocked(null, 0, !PRESERVE_WINDOWS); resumeTopActivitiesLocked(); } @@ -3273,7 +3281,7 @@ public final class ActivityStackSupervisor implements DisplayListener { stack.positionTask(task, position, stackChanged); // The task might have already been running and its visibility needs to be synchronized with // the visibility of the stack / windows. - stack.ensureActivitiesVisibleLocked(null, 0); + stack.ensureActivitiesVisibleLocked(null, 0, !PRESERVE_WINDOWS); resumeTopActivitiesLocked(); } @@ -3448,7 +3456,7 @@ public final class ActivityStackSupervisor implements DisplayListener { mService.updateUsageStats(r, true); } if (allResumedActivitiesComplete()) { - ensureActivitiesVisibleLocked(null, 0); + ensureActivitiesVisibleLocked(null, 0, !PRESERVE_WINDOWS); mWindowManager.executeAppTransition(); return true; } @@ -3534,14 +3542,15 @@ public final class ActivityStackSupervisor implements DisplayListener { mHandler.obtainMessage(LAUNCH_TASK_BEHIND_COMPLETE, token).sendToTarget(); } - void ensureActivitiesVisibleLocked(ActivityRecord starting, int configChanges) { + void ensureActivitiesVisibleLocked(ActivityRecord starting, int configChanges, + boolean preserveWindows) { // First the front stacks. In case any are not fullscreen and are in front of home. for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) { final ArrayList<ActivityStack> stacks = mActivityDisplays.valueAt(displayNdx).mStacks; final int topStackNdx = stacks.size() - 1; for (int stackNdx = topStackNdx; stackNdx >= 0; --stackNdx) { final ActivityStack stack = stacks.get(stackNdx); - stack.ensureActivitiesVisibleLocked(starting, configChanges); + stack.ensureActivitiesVisibleLocked(starting, configChanges, preserveWindows); } } } @@ -3648,11 +3657,7 @@ public final class ActivityStackSupervisor implements DisplayListener { } final boolean homeInFront = stack.isHomeStack(); if (stack.isOnHomeDisplay()) { - moveHomeStack(homeInFront, "switchUserOnHomeDisplay"); - TaskRecord task = stack.topTask(); - if (task != null) { - mWindowManager.moveTaskToTop(task.taskId); - } + stack.moveToFront("switchUserOnHomeDisplay"); } else { // Stack was moved to another display while user was swapped out. resumeHomeStackTask(HOME_ACTIVITY_TYPE, null, "switchUserOnOtherDisplay"); diff --git a/services/core/java/com/android/server/am/CompatModePackages.java b/services/core/java/com/android/server/am/CompatModePackages.java index 424ceb1a457c..c36fd06f633b 100644 --- a/services/core/java/com/android/server/am/CompatModePackages.java +++ b/services/core/java/com/android/server/am/CompatModePackages.java @@ -17,6 +17,7 @@ package com.android.server.am; import static com.android.server.am.ActivityManagerDebugConfig.*; +import static com.android.server.am.ActivityStackSupervisor.PRESERVE_WINDOWS; import java.io.File; import java.io.FileInputStream; @@ -347,7 +348,7 @@ public final class CompatModePackages { stack.ensureActivityConfigurationLocked(starting, 0, false); // And we need to make sure at this point that all other activities // are made visible with the correct configuration. - stack.ensureActivitiesVisibleLocked(starting, 0); + stack.ensureActivitiesVisibleLocked(starting, 0, !PRESERVE_WINDOWS); } } } diff --git a/services/core/java/com/android/server/am/EventLogTags.logtags b/services/core/java/com/android/server/am/EventLogTags.logtags index 9a645dfc6985..78b5f3333b2c 100644 --- a/services/core/java/com/android/server/am/EventLogTags.logtags +++ b/services/core/java/com/android/server/am/EventLogTags.logtags @@ -93,8 +93,8 @@ option java_package com.android.server.am # Activity focused 30043 am_focused_activity (User|1|5),(Component Name|3) -# Home Stack brought to front or rear -30044 am_home_stack_moved (User|1|5),(To Front|1|5),(Top Stack Id|1|5),(Focused Stack Id|1|5),(Reason|3) +# Stack focus +30044 am_focused_stack (User|1|5),(Focused Stack Id|1|5),(Last Focused Stack Id|1|5),(Reason|3) # Running pre boot receiver 30045 am_pre_boot (User|1|5),(Package|3) diff --git a/services/core/java/com/android/server/am/TaskRecord.java b/services/core/java/com/android/server/am/TaskRecord.java index 8f10f083c0ff..43f5baab793f 100644 --- a/services/core/java/com/android/server/am/TaskRecord.java +++ b/services/core/java/com/android/server/am/TaskRecord.java @@ -1235,7 +1235,7 @@ final class TaskRecord { if (stack == null || stack.mStackId == HOME_STACK_ID || stack.mStackId == FULLSCREEN_WORKSPACE_STACK_ID) { - return null; + return (mResizeable && stack != null) ? stack.mBounds : null; } else if (stack.mStackId == DOCKED_STACK_ID) { return stack.mBounds; } diff --git a/services/core/java/com/android/server/display/DisplayPowerController.java b/services/core/java/com/android/server/display/DisplayPowerController.java index 452378ff1e45..533f425e33f7 100644 --- a/services/core/java/com/android/server/display/DisplayPowerController.java +++ b/services/core/java/com/android/server/display/DisplayPowerController.java @@ -837,6 +837,7 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call if (mPendingScreenOff && target != Display.STATE_OFF) { setScreenState(Display.STATE_OFF); mPendingScreenOff = false; + mPowerState.dismissColorFade(); } if (target == Display.STATE_ON) { @@ -910,6 +911,7 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call // A black surface is already hiding the contents of the screen. setScreenState(Display.STATE_OFF); mPendingScreenOff = false; + mPowerState.dismissColorFade(); } else if (performScreenOffTransition && mPowerState.prepareColorFade(mContext, mColorFadeFadesConfig ? diff --git a/services/core/java/com/android/server/location/GeofenceProxy.java b/services/core/java/com/android/server/location/GeofenceProxy.java index d1bb8db221f4..b3a001022556 100644 --- a/services/core/java/com/android/server/location/GeofenceProxy.java +++ b/services/core/java/com/android/server/location/GeofenceProxy.java @@ -94,7 +94,7 @@ public final class GeofenceProxy { private void bindHardwareGeofence() { mContext.bindServiceAsUser(new Intent(mContext, GeofenceHardwareService.class), - mServiceConnection, Context.BIND_AUTO_CREATE, UserHandle.OWNER); + mServiceConnection, Context.BIND_AUTO_CREATE, UserHandle.SYSTEM); } private ServiceConnection mServiceConnection = new ServiceConnection() { diff --git a/services/core/java/com/android/server/pm/Installer.java b/services/core/java/com/android/server/pm/Installer.java index b59b4b2586ee..f292c9c4c3d8 100644 --- a/services/core/java/com/android/server/pm/Installer.java +++ b/services/core/java/com/android/server/pm/Installer.java @@ -77,24 +77,37 @@ public final class Installer extends SystemService { public int dexopt(String apkPath, int uid, boolean isPublic, String instructionSet, int dexoptNeeded) { + return dexopt(apkPath, uid, isPublic, instructionSet, dexoptNeeded, true); + } + + public int dexopt(String apkPath, int uid, boolean isPublic, + String instructionSet, int dexoptNeeded, boolean bootComplete) { if (!isValidInstructionSet(instructionSet)) { Slog.e(TAG, "Invalid instruction set: " + instructionSet); return -1; } - return mInstaller.dexopt(apkPath, uid, isPublic, instructionSet, dexoptNeeded); + return mInstaller.dexopt(apkPath, uid, isPublic, instructionSet, dexoptNeeded, + bootComplete); } public int dexopt(String apkPath, int uid, boolean isPublic, String pkgName, String instructionSet, int dexoptNeeded, boolean vmSafeMode, boolean debuggable, @Nullable String outputPath) { + return dexopt(apkPath, uid, isPublic, pkgName, instructionSet, dexoptNeeded, vmSafeMode, + debuggable, outputPath, true); + } + + public int dexopt(String apkPath, int uid, boolean isPublic, String pkgName, + String instructionSet, int dexoptNeeded, boolean vmSafeMode, + boolean debuggable, @Nullable String outputPath, boolean bootComplete) { if (!isValidInstructionSet(instructionSet)) { Slog.e(TAG, "Invalid instruction set: " + instructionSet); return -1; } return mInstaller.dexopt(apkPath, uid, isPublic, pkgName, instructionSet, dexoptNeeded, vmSafeMode, - debuggable, outputPath); + debuggable, outputPath, bootComplete); } public int idmap(String targetApkPath, String overlayApkPath, int uid) { diff --git a/services/core/java/com/android/server/pm/PackageDexOptimizer.java b/services/core/java/com/android/server/pm/PackageDexOptimizer.java index 8c23648f0f0f..b692def44153 100644 --- a/services/core/java/com/android/server/pm/PackageDexOptimizer.java +++ b/services/core/java/com/android/server/pm/PackageDexOptimizer.java @@ -71,7 +71,7 @@ final class PackageDexOptimizer { * {@link PackageManagerService#mInstallLock}. */ int performDexOpt(PackageParser.Package pkg, String[] instructionSets, - boolean forceDex, boolean defer, boolean inclDependencies) { + boolean forceDex, boolean defer, boolean inclDependencies, boolean bootComplete) { ArraySet<String> done; if (inclDependencies && (pkg.usesLibraries != null || pkg.usesOptionalLibraries != null)) { done = new ArraySet<String>(); @@ -86,7 +86,7 @@ final class PackageDexOptimizer { mDexoptWakeLock.acquire(); } try { - return performDexOptLI(pkg, instructionSets, forceDex, defer, done); + return performDexOptLI(pkg, instructionSets, forceDex, defer, bootComplete, done); } finally { if (useLock) { mDexoptWakeLock.release(); @@ -96,18 +96,19 @@ final class PackageDexOptimizer { } private int performDexOptLI(PackageParser.Package pkg, String[] targetInstructionSets, - boolean forceDex, boolean defer, ArraySet<String> done) { + boolean forceDex, boolean defer, boolean bootComplete, ArraySet<String> done) { final String[] instructionSets = targetInstructionSets != null ? targetInstructionSets : getAppDexInstructionSets(pkg.applicationInfo); if (done != null) { done.add(pkg.packageName); if (pkg.usesLibraries != null) { - performDexOptLibsLI(pkg.usesLibraries, instructionSets, forceDex, defer, done); + performDexOptLibsLI(pkg.usesLibraries, instructionSets, forceDex, defer, + bootComplete, done); } if (pkg.usesOptionalLibraries != null) { performDexOptLibsLI(pkg.usesOptionalLibraries, instructionSets, forceDex, defer, - done); + bootComplete, done); } } @@ -174,11 +175,11 @@ final class PackageDexOptimizer { Log.i(TAG, "Running dexopt (" + dexoptType + ") on: " + path + " pkg=" + pkg.applicationInfo.packageName + " isa=" + dexCodeInstructionSet + " vmSafeMode=" + vmSafeMode + " debuggable=" + debuggable - + " oatDir = " + oatDir); + + " oatDir = " + oatDir + " bootComplete=" + bootComplete); final int sharedGid = UserHandle.getSharedAppGid(pkg.applicationInfo.uid); final int ret = mPackageManagerService.mInstaller.dexopt(path, sharedGid, !pkg.isForwardLocked(), pkg.packageName, dexCodeInstructionSet, - dexoptNeeded, vmSafeMode, debuggable, oatDir); + dexoptNeeded, vmSafeMode, debuggable, oatDir, bootComplete); // Dex2oat might fail due to compiler / verifier errors. We soldier on // regardless, and attempt to interpret the app as a safety net. @@ -235,12 +236,12 @@ final class PackageDexOptimizer { } private void performDexOptLibsLI(ArrayList<String> libs, String[] instructionSets, - boolean forceDex, boolean defer, ArraySet<String> done) { + boolean forceDex, boolean defer, boolean bootComplete, ArraySet<String> done) { for (String libName : libs) { PackageParser.Package libPkg = mPackageManagerService.findSharedNonSystemLibrary( libName); if (libPkg != null && !done.contains(libName)) { - performDexOptLI(libPkg, instructionSets, forceDex, defer, done); + performDexOptLI(libPkg, instructionSets, forceDex, defer, bootComplete, done); } } } diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java index e385ac5d32cb..17a3f56a1bf6 100644 --- a/services/core/java/com/android/server/pm/PackageManagerService.java +++ b/services/core/java/com/android/server/pm/PackageManagerService.java @@ -2015,7 +2015,7 @@ public class PackageManagerService extends IPackageManager.Stub { int dexoptNeeded = DexFile.getDexOptNeeded(lib, null, dexCodeInstructionSet, false); if (dexoptNeeded != DexFile.NO_DEXOPT_NEEDED) { alreadyDexOpted.add(lib); - mInstaller.dexopt(lib, Process.SYSTEM_UID, true, dexCodeInstructionSet, dexoptNeeded); + mInstaller.dexopt(lib, Process.SYSTEM_UID, true, dexCodeInstructionSet, dexoptNeeded, false); } } catch (FileNotFoundException e) { Slog.w(TAG, "Library not found: " + lib); @@ -2063,7 +2063,7 @@ public class PackageManagerService extends IPackageManager.Stub { try { int dexoptNeeded = DexFile.getDexOptNeeded(path, null, dexCodeInstructionSet, false); if (dexoptNeeded != DexFile.NO_DEXOPT_NEEDED) { - mInstaller.dexopt(path, Process.SYSTEM_UID, true, dexCodeInstructionSet, dexoptNeeded); + mInstaller.dexopt(path, Process.SYSTEM_UID, true, dexCodeInstructionSet, dexoptNeeded, false); } } catch (FileNotFoundException e) { Slog.w(TAG, "Jar not found: " + path); @@ -2292,7 +2292,8 @@ public class PackageManagerService extends IPackageManager.Stub { // the rest of the commands above) because there's precious little we // can do about it. A settings error is reported, though. adjustCpuAbisForSharedUserLPw(setting.packages, null /* scanned package */, - false /* force dexopt */, false /* defer dexopt */); + false /* force dexopt */, false /* defer dexopt */, + false /* boot complete */); } // Now that we know all the packages we are keeping, @@ -6155,41 +6156,6 @@ public class PackageManagerService extends IPackageManager.Stub { it.remove(); } } - // Give priority to system apps. - for (Iterator<PackageParser.Package> it = pkgs.iterator(); it.hasNext();) { - PackageParser.Package pkg = it.next(); - if (isSystemApp(pkg) && !pkg.isUpdatedSystemApp()) { - if (DEBUG_DEXOPT) { - Log.i(TAG, "Adding system app " + sortedPkgs.size() + ": " + pkg.packageName); - } - sortedPkgs.add(pkg); - it.remove(); - } - } - // Give priority to updated system apps. - for (Iterator<PackageParser.Package> it = pkgs.iterator(); it.hasNext();) { - PackageParser.Package pkg = it.next(); - if (pkg.isUpdatedSystemApp()) { - if (DEBUG_DEXOPT) { - Log.i(TAG, "Adding updated system app " + sortedPkgs.size() + ": " + pkg.packageName); - } - sortedPkgs.add(pkg); - it.remove(); - } - } - // Give priority to apps that listen for boot complete. - intent = new Intent(Intent.ACTION_BOOT_COMPLETED); - pkgNames = getPackageNamesForIntent(intent, UserHandle.USER_SYSTEM); - for (Iterator<PackageParser.Package> it = pkgs.iterator(); it.hasNext();) { - PackageParser.Package pkg = it.next(); - if (pkgNames.contains(pkg.packageName)) { - if (DEBUG_DEXOPT) { - Log.i(TAG, "Adding boot app " + sortedPkgs.size() + ": " + pkg.packageName); - } - sortedPkgs.add(pkg); - it.remove(); - } - } // Filter out packages that aren't recently used. filterRecentlyUsedApps(pkgs); // Add all remaining apps. @@ -6281,7 +6247,8 @@ public class PackageManagerService extends IPackageManager.Stub { PackageParser.Package p = pkg; synchronized (mInstallLock) { mPackageDexOptimizer.performDexOpt(p, null /* instruction sets */, - false /* force dex */, false /* defer */, true /* include dependencies */); + false /* force dex */, false /* defer */, true /* include dependencies */, + false /* boot complete */); } } @@ -6340,7 +6307,8 @@ public class PackageManagerService extends IPackageManager.Stub { synchronized (mInstallLock) { final String[] instructionSets = new String[] { targetInstructionSet }; int result = mPackageDexOptimizer.performDexOpt(p, instructionSets, - false /* forceDex */, false /* defer */, true /* inclDependencies */); + false /* forceDex */, false /* defer */, true /* inclDependencies */, + true /* boot complete */); return result == PackageDexOptimizer.DEX_OPT_PERFORMED; } } finally { @@ -6390,7 +6358,8 @@ public class PackageManagerService extends IPackageManager.Stub { Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "dexopt"); final int res = mPackageDexOptimizer.performDexOpt(pkg, instructionSets, - true /*forceDex*/, false /* defer */, true /* inclDependencies */); + true /*forceDex*/, false /* defer */, true /* inclDependencies */, + true /* boot complete */); Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER); if (res != PackageDexOptimizer.DEX_OPT_PERFORMED) { @@ -7199,14 +7168,15 @@ public class PackageManagerService extends IPackageManager.Stub { // we can avoid redundant dexopts, and also to make sure we've got the // code and package path correct. adjustCpuAbisForSharedUserLPw(pkgSetting.sharedUser.packages, - pkg, forceDex, (scanFlags & SCAN_DEFER_DEX) != 0); + pkg, forceDex, (scanFlags & SCAN_DEFER_DEX) != 0, true /* boot complete */); } if ((scanFlags & SCAN_NO_DEX) == 0) { Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "dexopt"); int result = mPackageDexOptimizer.performDexOpt(pkg, null /* instruction sets */, - forceDex, (scanFlags & SCAN_DEFER_DEX) != 0, false /* inclDependencies */); + forceDex, (scanFlags & SCAN_DEFER_DEX) != 0, false /* inclDependencies */, + (scanFlags & SCAN_BOOTING) == 0); Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER); if (result == PackageDexOptimizer.DEX_OPT_FAILED) { @@ -7286,7 +7256,8 @@ public class PackageManagerService extends IPackageManager.Stub { PackageParser.Package clientPkg = clientLibPkgs.get(i); int result = mPackageDexOptimizer.performDexOpt(clientPkg, null /* instruction sets */, forceDex, - (scanFlags & SCAN_DEFER_DEX) != 0, false); + (scanFlags & SCAN_DEFER_DEX) != 0, false, + (scanFlags & SCAN_BOOTING) == 0); if (result == PackageDexOptimizer.DEX_OPT_FAILED) { throw new PackageManagerException(INSTALL_FAILED_DEXOPT, "scanPackageLI failed to dexopt clientLibPkgs"); @@ -7842,7 +7813,8 @@ public class PackageManagerService extends IPackageManager.Stub { * adds unnecessary complexity. */ private void adjustCpuAbisForSharedUserLPw(Set<PackageSetting> packagesForUser, - PackageParser.Package scannedPackage, boolean forceDexOpt, boolean deferDexOpt) { + PackageParser.Package scannedPackage, boolean forceDexOpt, boolean deferDexOpt, + boolean bootComplete) { String requiredInstructionSet = null; if (scannedPackage != null && scannedPackage.applicationInfo.primaryCpuAbi != null) { requiredInstructionSet = VMRuntime.getInstructionSet( @@ -7908,7 +7880,8 @@ public class PackageManagerService extends IPackageManager.Stub { Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "dexopt"); int result = mPackageDexOptimizer.performDexOpt(ps.pkg, - null /* instruction sets */, forceDexOpt, deferDexOpt, true); + null /* instruction sets */, forceDexOpt, deferDexOpt, true, + bootComplete); Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER); if (result == PackageDexOptimizer.DEX_OPT_FAILED) { @@ -12598,7 +12571,8 @@ public class PackageManagerService extends IPackageManager.Stub { int result = mPackageDexOptimizer .performDexOpt(pkg, null /* instruction sets */, false /* forceDex */, - false /* defer */, false /* inclDependencies */); + false /* defer */, false /* inclDependencies */, + true /* boot complete */); Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER); if (result == PackageDexOptimizer.DEX_OPT_FAILED) { @@ -15902,14 +15876,28 @@ public class PackageManagerService extends IPackageManager.Stub { } } - private void loadPrivatePackages(VolumeInfo vol) { + private void loadPrivatePackages(final VolumeInfo vol) { + mHandler.post(new Runnable() { + @Override + public void run() { + loadPrivatePackagesInner(vol); + } + }); + } + + private void loadPrivatePackagesInner(VolumeInfo vol) { final ArrayList<ApplicationInfo> loaded = new ArrayList<>(); final int parseFlags = mDefParseFlags | PackageParser.PARSE_EXTERNAL_STORAGE; - synchronized (mInstallLock) { + + final VersionInfo ver; + final List<PackageSetting> packages; synchronized (mPackages) { - final VersionInfo ver = mSettings.findOrCreateVersion(vol.fsUuid); - final List<PackageSetting> packages = mSettings.getVolumePackagesLPr(vol.fsUuid); - for (PackageSetting ps : packages) { + ver = mSettings.findOrCreateVersion(vol.fsUuid); + packages = mSettings.getVolumePackagesLPr(vol.fsUuid); + } + + for (PackageSetting ps : packages) { + synchronized (mInstallLock) { final PackageParser.Package pkg; try { pkg = scanPackageTracedLI(ps.codePath, parseFlags, SCAN_INITIAL, 0L, null); @@ -15922,7 +15910,9 @@ public class PackageManagerService extends IPackageManager.Stub { deleteCodeCacheDirsLI(ps.volumeUuid, ps.name); } } + } + synchronized (mPackages) { int updateFlags = UPDATE_PERMISSIONS_ALL; if (ver.sdkVersion != mSdkVersion) { logCriticalInfo(Log.INFO, "Platform changed from " + ver.sdkVersion + " to " @@ -15936,13 +15926,21 @@ public class PackageManagerService extends IPackageManager.Stub { mSettings.writeLPr(); } - } if (DEBUG_INSTALL) Slog.d(TAG, "Loaded packages " + loaded); sendResourcesChangedBroadcast(true, false, loaded, null); } - private void unloadPrivatePackages(VolumeInfo vol) { + private void unloadPrivatePackages(final VolumeInfo vol) { + mHandler.post(new Runnable() { + @Override + public void run() { + unloadPrivatePackagesInner(vol); + } + }); + } + + private void unloadPrivatePackagesInner(VolumeInfo vol) { final ArrayList<ApplicationInfo> unloaded = new ArrayList<>(); synchronized (mInstallLock) { synchronized (mPackages) { diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java index 33ecd0944f25..dbc3970cf4cf 100644 --- a/services/core/java/com/android/server/policy/PhoneWindowManager.java +++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java @@ -2003,6 +2003,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { case TYPE_SYSTEM_DIALOG: case TYPE_VOLUME_OVERLAY: case TYPE_PRIVATE_PRESENTATION: + case TYPE_DOCK_DIVIDER: break; } @@ -2134,54 +2135,56 @@ public class PhoneWindowManager implements WindowManagerPolicy { case TYPE_INPUT_METHOD_DIALOG: // on-screen keyboards and other such input method user interfaces go here. return 13; + case TYPE_DOCK_DIVIDER: + return 14; case TYPE_KEYGUARD_SCRIM: // the safety window that shows behind keyguard while keyguard is starting - return 14; - case TYPE_STATUS_BAR_SUB_PANEL: return 15; - case TYPE_STATUS_BAR: + case TYPE_STATUS_BAR_SUB_PANEL: return 16; - case TYPE_STATUS_BAR_PANEL: + case TYPE_STATUS_BAR: return 17; - case TYPE_KEYGUARD_DIALOG: + case TYPE_STATUS_BAR_PANEL: return 18; + case TYPE_KEYGUARD_DIALOG: + return 19; case TYPE_VOLUME_OVERLAY: // the on-screen volume indicator and controller shown when the user // changes the device volume - return 19; + return 20; case TYPE_SYSTEM_OVERLAY: // the on-screen volume indicator and controller shown when the user // changes the device volume - return 20; + return 21; case TYPE_NAVIGATION_BAR: // the navigation bar, if available, shows atop most things - return 21; + return 22; case TYPE_NAVIGATION_BAR_PANEL: // some panels (e.g. search) need to show on top of the navigation bar - return 22; + return 23; case TYPE_SYSTEM_ERROR: // system-level error dialogs - return 23; + return 24; case TYPE_MAGNIFICATION_OVERLAY: // used to highlight the magnified portion of a display - return 24; + return 25; case TYPE_DISPLAY_OVERLAY: // used to simulate secondary display devices - return 25; + return 26; case TYPE_DRAG: // the drag layer: input for drag-and-drop is associated with this window, // which sits above all other focusable windows - return 26; + return 27; case TYPE_ACCESSIBILITY_OVERLAY: // overlay put by accessibility services to intercept user interaction - return 27; - case TYPE_SECURE_SYSTEM_OVERLAY: return 28; - case TYPE_BOOT_PROGRESS: + case TYPE_SECURE_SYSTEM_OVERLAY: return 29; + case TYPE_BOOT_PROGRESS: + return 30; case TYPE_POINTER: // the (mouse) pointer layer - return 30; + return 31; } Log.e(TAG, "Unknown window type: " + type); return 2; @@ -2271,6 +2274,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { case TYPE_WALLPAPER: case TYPE_DREAM: case TYPE_KEYGUARD_SCRIM: + case TYPE_DOCK_DIVIDER: return false; default: // Hide only windows below the keyguard host window. @@ -3577,7 +3581,6 @@ public class PhoneWindowManager implements WindowManagerPolicy { final Rect of = mTmpOverscanFrame; final Rect vf = mTmpVisibleFrame; final Rect dcf = mTmpDecorFrame; - final Rect osf = mTmpOutsetFrame; pf.left = df.left = of.left = vf.left = mDockLeft; pf.top = df.top = of.top = vf.top = mDockTop; pf.right = df.right = of.right = vf.right = mDockRight; @@ -3619,150 +3622,163 @@ public class PhoneWindowManager implements WindowManagerPolicy { // then take that into account. navVisible |= !canHideNavigationBar(); - boolean updateSysUiVisibility = false; - if (mNavigationBar != null) { - boolean transientNavBarShowing = mNavigationBarController.isTransientShowing(); - // Force the navigation bar to its appropriate place and - // size. We need to do this directly, instead of relying on - // it to bubble up from the nav bar, because this needs to - // change atomically with screen rotations. - mNavigationBarOnBottom = (!mNavigationBarCanMove || displayWidth < displayHeight); - if (mNavigationBarOnBottom) { - // It's a system nav bar or a portrait screen; nav bar goes on bottom. - int top = displayHeight - overscanBottom - - mNavigationBarHeightForRotation[displayRotation]; - mTmpNavigationFrame.set(0, top, displayWidth, displayHeight - overscanBottom); - mStableBottom = mStableFullscreenBottom = mTmpNavigationFrame.top; - if (transientNavBarShowing) { - mNavigationBarController.setBarShowingLw(true); - } else if (navVisible) { - mNavigationBarController.setBarShowingLw(true); - mDockBottom = mTmpNavigationFrame.top; - mRestrictedScreenHeight = mDockBottom - mRestrictedScreenTop; - mRestrictedOverscanScreenHeight = mDockBottom - mRestrictedOverscanScreenTop; - } else { - // We currently want to hide the navigation UI. - mNavigationBarController.setBarShowingLw(false); - } - if (navVisible && !navTranslucent && !navAllowedHidden - && !mNavigationBar.isAnimatingLw() - && !mNavigationBarController.wasRecentlyTranslucent()) { - // If the opaque nav bar is currently requested to be visible, - // and not in the process of animating on or off, then - // we can tell the app that it is covered by it. - mSystemBottom = mTmpNavigationFrame.top; - } - } else { - // Landscape screen; nav bar goes to the right. - int left = displayWidth - overscanRight - - mNavigationBarWidthForRotation[displayRotation]; - mTmpNavigationFrame.set(left, 0, displayWidth - overscanRight, displayHeight); - mStableRight = mStableFullscreenRight = mTmpNavigationFrame.left; - if (transientNavBarShowing) { - mNavigationBarController.setBarShowingLw(true); - } else if (navVisible) { - mNavigationBarController.setBarShowingLw(true); - mDockRight = mTmpNavigationFrame.left; - mRestrictedScreenWidth = mDockRight - mRestrictedScreenLeft; - mRestrictedOverscanScreenWidth = mDockRight - mRestrictedOverscanScreenLeft; - } else { - // We currently want to hide the navigation UI. - mNavigationBarController.setBarShowingLw(false); - } - if (navVisible && !navTranslucent && !navAllowedHidden - && !mNavigationBar.isAnimatingLw() - && !mNavigationBarController.wasRecentlyTranslucent()) { - // If the nav bar is currently requested to be visible, - // and not in the process of animating on or off, then - // we can tell the app that it is covered by it. - mSystemRight = mTmpNavigationFrame.left; - } - } - // Make sure the content and current rectangles are updated to - // account for the restrictions from the navigation bar. - mContentTop = mVoiceContentTop = mCurTop = mDockTop; - mContentBottom = mVoiceContentBottom = mCurBottom = mDockBottom; - mContentLeft = mVoiceContentLeft = mCurLeft = mDockLeft; - mContentRight = mVoiceContentRight = mCurRight = mDockRight; - mStatusBarLayer = mNavigationBar.getSurfaceLayer(); - // And compute the final frame. - mNavigationBar.computeFrameLw(mTmpNavigationFrame, mTmpNavigationFrame, - mTmpNavigationFrame, mTmpNavigationFrame, mTmpNavigationFrame, dcf, - mTmpNavigationFrame, mTmpNavigationFrame); - if (DEBUG_LAYOUT) Slog.i(TAG, "mNavigationBar frame: " + mTmpNavigationFrame); - if (mNavigationBarController.checkHiddenLw()) { - updateSysUiVisibility = true; - } - } + boolean updateSysUiVisibility = layoutNavigationBar(displayWidth, displayHeight, + displayRotation, overscanRight, overscanBottom, dcf, navVisible, navTranslucent, + navAllowedHidden); if (DEBUG_LAYOUT) Slog.i(TAG, String.format("mDock rect: (%d,%d - %d,%d)", mDockLeft, mDockTop, mDockRight, mDockBottom)); + updateSysUiVisibility |= layoutStatusBar(pf, df, of, vf, dcf, sysui, isKeyguardShowing); + if (updateSysUiVisibility) { + updateSystemUiVisibilityLw(); + } + } + } - // decide where the status bar goes ahead of time - if (mStatusBar != null) { - // apply any navigation bar insets - pf.left = df.left = of.left = mUnrestrictedScreenLeft; - pf.top = df.top = of.top = mUnrestrictedScreenTop; - pf.right = df.right = of.right = mUnrestrictedScreenWidth + mUnrestrictedScreenLeft; - pf.bottom = df.bottom = of.bottom = mUnrestrictedScreenHeight - + mUnrestrictedScreenTop; - vf.left = mStableLeft; - vf.top = mStableTop; - vf.right = mStableRight; - vf.bottom = mStableBottom; - - mStatusBarLayer = mStatusBar.getSurfaceLayer(); - - // Let the status bar determine its size. - mStatusBar.computeFrameLw(pf /* parentFrame */, df /* displayFrame */, - vf /* overlayFrame */, vf /* contentFrame */, vf /* visibleFrame */, - dcf /* decorFrame */, vf /* stableFrame */, vf /* outsetFrame */); - - // For layout, the status bar is always at the top with our fixed height. - mStableTop = mUnrestrictedScreenTop + mStatusBarHeight; - - boolean statusBarTransient = (sysui & View.STATUS_BAR_TRANSIENT) != 0; - boolean statusBarTranslucent = (sysui - & (View.STATUS_BAR_TRANSLUCENT | View.SYSTEM_UI_TRANSPARENT)) != 0; - if (!isKeyguardShowing) { - statusBarTranslucent &= areTranslucentBarsAllowed(); - } + private boolean layoutStatusBar(Rect pf, Rect df, Rect of, Rect vf, Rect dcf, int sysui, + boolean isKeyguardShowing) { + // decide where the status bar goes ahead of time + if (mStatusBar != null) { + // apply any navigation bar insets + pf.left = df.left = of.left = mUnrestrictedScreenLeft; + pf.top = df.top = of.top = mUnrestrictedScreenTop; + pf.right = df.right = of.right = mUnrestrictedScreenWidth + mUnrestrictedScreenLeft; + pf.bottom = df.bottom = of.bottom = mUnrestrictedScreenHeight + + mUnrestrictedScreenTop; + vf.left = mStableLeft; + vf.top = mStableTop; + vf.right = mStableRight; + vf.bottom = mStableBottom; + + mStatusBarLayer = mStatusBar.getSurfaceLayer(); + + // Let the status bar determine its size. + mStatusBar.computeFrameLw(pf /* parentFrame */, df /* displayFrame */, + vf /* overlayFrame */, vf /* contentFrame */, vf /* visibleFrame */, + dcf /* decorFrame */, vf /* stableFrame */, vf /* outsetFrame */); - // If the status bar is hidden, we don't want to cause - // windows behind it to scroll. - if (mStatusBar.isVisibleLw() && !statusBarTransient) { - // Status bar may go away, so the screen area it occupies - // is available to apps but just covering them when the - // status bar is visible. - mDockTop = mUnrestrictedScreenTop + mStatusBarHeight; + // For layout, the status bar is always at the top with our fixed height. + mStableTop = mUnrestrictedScreenTop + mStatusBarHeight; + + boolean statusBarTransient = (sysui & View.STATUS_BAR_TRANSIENT) != 0; + boolean statusBarTranslucent = (sysui + & (View.STATUS_BAR_TRANSLUCENT | View.SYSTEM_UI_TRANSPARENT)) != 0; + if (!isKeyguardShowing) { + statusBarTranslucent &= areTranslucentBarsAllowed(); + } - mContentTop = mVoiceContentTop = mCurTop = mDockTop; - mContentBottom = mVoiceContentBottom = mCurBottom = mDockBottom; - mContentLeft = mVoiceContentLeft = mCurLeft = mDockLeft; - mContentRight = mVoiceContentRight = mCurRight = mDockRight; + // If the status bar is hidden, we don't want to cause + // windows behind it to scroll. + if (mStatusBar.isVisibleLw() && !statusBarTransient) { + // Status bar may go away, so the screen area it occupies + // is available to apps but just covering them when the + // status bar is visible. + mDockTop = mUnrestrictedScreenTop + mStatusBarHeight; + + mContentTop = mVoiceContentTop = mCurTop = mDockTop; + mContentBottom = mVoiceContentBottom = mCurBottom = mDockBottom; + mContentLeft = mVoiceContentLeft = mCurLeft = mDockLeft; + mContentRight = mVoiceContentRight = mCurRight = mDockRight; - if (DEBUG_LAYOUT) Slog.v(TAG, "Status bar: " + + if (DEBUG_LAYOUT) Slog.v(TAG, "Status bar: " + String.format( - "dock=[%d,%d][%d,%d] content=[%d,%d][%d,%d] cur=[%d,%d][%d,%d]", - mDockLeft, mDockTop, mDockRight, mDockBottom, - mContentLeft, mContentTop, mContentRight, mContentBottom, - mCurLeft, mCurTop, mCurRight, mCurBottom)); + "dock=[%d,%d][%d,%d] content=[%d,%d][%d,%d] cur=[%d,%d][%d,%d]", + mDockLeft, mDockTop, mDockRight, mDockBottom, + mContentLeft, mContentTop, mContentRight, mContentBottom, + mCurLeft, mCurTop, mCurRight, mCurBottom)); + } + if (mStatusBar.isVisibleLw() && !mStatusBar.isAnimatingLw() + && !statusBarTransient && !statusBarTranslucent + && !mStatusBarController.wasRecentlyTranslucent()) { + // If the opaque status bar is currently requested to be visible, + // and not in the process of animating on or off, then + // we can tell the app that it is covered by it. + mSystemTop = mUnrestrictedScreenTop + mStatusBarHeight; + } + if (mStatusBarController.checkHiddenLw()) { + return true; + } + } + return false; + } + + private boolean layoutNavigationBar(int displayWidth, int displayHeight, int displayRotation, + int overscanRight, int overscanBottom, Rect dcf, boolean navVisible, + boolean navTranslucent, boolean navAllowedHidden) { + if (mNavigationBar != null) { + boolean transientNavBarShowing = mNavigationBarController.isTransientShowing(); + // Force the navigation bar to its appropriate place and + // size. We need to do this directly, instead of relying on + // it to bubble up from the nav bar, because this needs to + // change atomically with screen rotations. + mNavigationBarOnBottom = (!mNavigationBarCanMove || displayWidth < displayHeight); + if (mNavigationBarOnBottom) { + // It's a system nav bar or a portrait screen; nav bar goes on bottom. + int top = displayHeight - overscanBottom + - mNavigationBarHeightForRotation[displayRotation]; + mTmpNavigationFrame.set(0, top, displayWidth, displayHeight - overscanBottom); + mStableBottom = mStableFullscreenBottom = mTmpNavigationFrame.top; + if (transientNavBarShowing) { + mNavigationBarController.setBarShowingLw(true); + } else if (navVisible) { + mNavigationBarController.setBarShowingLw(true); + mDockBottom = mTmpNavigationFrame.top; + mRestrictedScreenHeight = mDockBottom - mRestrictedScreenTop; + mRestrictedOverscanScreenHeight = mDockBottom - mRestrictedOverscanScreenTop; + } else { + // We currently want to hide the navigation UI. + mNavigationBarController.setBarShowingLw(false); } - if (mStatusBar.isVisibleLw() && !mStatusBar.isAnimatingLw() - && !statusBarTransient && !statusBarTranslucent - && !mStatusBarController.wasRecentlyTranslucent()) { - // If the opaque status bar is currently requested to be visible, + if (navVisible && !navTranslucent && !navAllowedHidden + && !mNavigationBar.isAnimatingLw() + && !mNavigationBarController.wasRecentlyTranslucent()) { + // If the opaque nav bar is currently requested to be visible, // and not in the process of animating on or off, then // we can tell the app that it is covered by it. - mSystemTop = mUnrestrictedScreenTop + mStatusBarHeight; + mSystemBottom = mTmpNavigationFrame.top; + } + } else { + // Landscape screen; nav bar goes to the right. + int left = displayWidth - overscanRight + - mNavigationBarWidthForRotation[displayRotation]; + mTmpNavigationFrame.set(left, 0, displayWidth - overscanRight, displayHeight); + mStableRight = mStableFullscreenRight = mTmpNavigationFrame.left; + if (transientNavBarShowing) { + mNavigationBarController.setBarShowingLw(true); + } else if (navVisible) { + mNavigationBarController.setBarShowingLw(true); + mDockRight = mTmpNavigationFrame.left; + mRestrictedScreenWidth = mDockRight - mRestrictedScreenLeft; + mRestrictedOverscanScreenWidth = mDockRight - mRestrictedOverscanScreenLeft; + } else { + // We currently want to hide the navigation UI. + mNavigationBarController.setBarShowingLw(false); } - if (mStatusBarController.checkHiddenLw()) { - updateSysUiVisibility = true; + if (navVisible && !navTranslucent && !navAllowedHidden + && !mNavigationBar.isAnimatingLw() + && !mNavigationBarController.wasRecentlyTranslucent()) { + // If the nav bar is currently requested to be visible, + // and not in the process of animating on or off, then + // we can tell the app that it is covered by it. + mSystemRight = mTmpNavigationFrame.left; } } - if (updateSysUiVisibility) { - updateSystemUiVisibilityLw(); + // Make sure the content and current rectangles are updated to + // account for the restrictions from the navigation bar. + mContentTop = mVoiceContentTop = mCurTop = mDockTop; + mContentBottom = mVoiceContentBottom = mCurBottom = mDockBottom; + mContentLeft = mVoiceContentLeft = mCurLeft = mDockLeft; + mContentRight = mVoiceContentRight = mCurRight = mDockRight; + mStatusBarLayer = mNavigationBar.getSurfaceLayer(); + // And compute the final frame. + mNavigationBar.computeFrameLw(mTmpNavigationFrame, mTmpNavigationFrame, + mTmpNavigationFrame, mTmpNavigationFrame, mTmpNavigationFrame, dcf, + mTmpNavigationFrame, mTmpNavigationFrame); + if (DEBUG_LAYOUT) Slog.i(TAG, "mNavigationBar frame: " + mTmpNavigationFrame); + if (mNavigationBarController.checkHiddenLw()) { + return true; } } + return false; } /** {@inheritDoc} */ @@ -4416,6 +4432,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { if (attrs.type == TYPE_STATUS_BAR) { if ((attrs.privateFlags & PRIVATE_FLAG_KEYGUARD) != 0) { mForceStatusBarFromKeyguard = true; + mShowingLockscreen = true; } if ((attrs.privateFlags & PRIVATE_FLAG_FORCE_STATUS_BAR_VISIBLE_TRANSPARENT) != 0) { mForceStatusBarTransparent = true; @@ -4436,9 +4453,6 @@ public class PhoneWindowManager implements WindowManagerPolicy { mForceStatusBar = true; } } - if ((attrs.privateFlags & PRIVATE_FLAG_KEYGUARD) != 0) { - mShowingLockscreen = true; - } if (attrs.type == TYPE_DREAM) { // If the lockscreen was showing when the dream started then wait // for the dream to draw before hiding the lockscreen. diff --git a/services/core/java/com/android/server/policy/keyguard/KeyguardServiceDelegate.java b/services/core/java/com/android/server/policy/keyguard/KeyguardServiceDelegate.java index 7ae3c79e0fe5..c0dfbcbb01ab 100644 --- a/services/core/java/com/android/server/policy/keyguard/KeyguardServiceDelegate.java +++ b/services/core/java/com/android/server/policy/keyguard/KeyguardServiceDelegate.java @@ -129,7 +129,7 @@ public class KeyguardServiceDelegate { intent.setComponent(keyguardComponent); if (!context.bindServiceAsUser(intent, mKeyguardConnection, - Context.BIND_AUTO_CREATE, UserHandle.OWNER)) { + Context.BIND_AUTO_CREATE, UserHandle.SYSTEM)) { Log.v(TAG, "*** Keyguard: can't bind to " + keyguardComponent); mKeyguardState.showing = false; mKeyguardState.showingAndNotOccluded = false; diff --git a/services/core/java/com/android/server/power/PowerManagerService.java b/services/core/java/com/android/server/power/PowerManagerService.java index 513fd4e55d39..a0a31c0d8a0c 100644 --- a/services/core/java/com/android/server/power/PowerManagerService.java +++ b/services/core/java/com/android/server/power/PowerManagerService.java @@ -1577,6 +1577,13 @@ public final class PowerManagerService extends SystemService } if (mUserActivitySummary != USER_ACTIVITY_SCREEN_DREAM && userInactiveOverride) { + if ((mUserActivitySummary & + (USER_ACTIVITY_SCREEN_BRIGHT | USER_ACTIVITY_SCREEN_DIM)) != 0) { + // Device is being kept awake by recent user activity + long savedWakeTimeMs = now - nextTimeout; + EventLog.writeEvent( + EventLogTags.POWER_SOFT_SLEEP_REQUESTED, savedWakeTimeMs); + } mUserActivitySummary = USER_ACTIVITY_SCREEN_DREAM; nextTimeout = -1; } diff --git a/services/core/java/com/android/server/statusbar/StatusBarManagerService.java b/services/core/java/com/android/server/statusbar/StatusBarManagerService.java index 87dc6c4c3e72..11a16394a502 100644 --- a/services/core/java/com/android/server/statusbar/StatusBarManagerService.java +++ b/services/core/java/com/android/server/statusbar/StatusBarManagerService.java @@ -305,9 +305,8 @@ public class StatusBarManagerService extends IStatusBarService.Stub { throw new SecurityException("invalid status bar icon slot: " + slot); } - StatusBarIcon icon = new StatusBarIcon(iconPackage, UserHandle.OWNER, iconId, - iconLevel, 0, - contentDescription); + StatusBarIcon icon = new StatusBarIcon(iconPackage, UserHandle.SYSTEM, iconId, + iconLevel, 0, contentDescription); //Slog.d(TAG, "setIcon slot=" + slot + " index=" + index + " icon=" + icon); mIcons.setIcon(index, icon); diff --git a/services/core/java/com/android/server/telecom/TelecomLoaderService.java b/services/core/java/com/android/server/telecom/TelecomLoaderService.java index f4bd61fa39cd..6c5452a3cb2e 100644 --- a/services/core/java/com/android/server/telecom/TelecomLoaderService.java +++ b/services/core/java/com/android/server/telecom/TelecomLoaderService.java @@ -188,7 +188,7 @@ public class TelecomLoaderService extends SystemService { | Context.BIND_AUTO_CREATE; // Bind to Telecom and register the service - if (mContext.bindServiceAsUser(intent, serviceConnection, flags, UserHandle.OWNER)) { + if (mContext.bindServiceAsUser(intent, serviceConnection, flags, UserHandle.SYSTEM)) { mServiceConnection = serviceConnection; } } diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java index b503554ce15e..4392ab43579c 100644 --- a/services/core/java/com/android/server/wm/DisplayContent.java +++ b/services/core/java/com/android/server/wm/DisplayContent.java @@ -16,6 +16,7 @@ package com.android.server.wm; +import static android.app.ActivityManager.DOCKED_STACK_ID; import static android.app.ActivityManager.HOME_STACK_ID; import static com.android.server.wm.WindowManagerService.DEBUG_VISIBILITY; @@ -100,7 +101,8 @@ class DisplayContent { Region mTouchExcludeRegion = new Region(); /** Save allocating when calculating rects */ - Rect mTmpRect = new Rect(); + private Rect mTmpRect = new Rect(); + private Rect mTmpRect2 = new Rect(); /** For gathering Task objects in order. */ final ArrayList<Task> mTmpTaskHistory = new ArrayList<Task>(); @@ -110,6 +112,8 @@ class DisplayContent { /** Remove this display when animation on it has completed. */ boolean mDeferredRemoval; + final DockedStackDividerController mDividerControllerLocked; + /** * @param display May not be null. * @param service You know. @@ -121,6 +125,7 @@ class DisplayContent { display.getMetrics(mDisplayMetrics); isDefaultDisplay = mDisplayId == Display.DEFAULT_DISPLAY; mService = service; + mDividerControllerLocked = new DockedStackDividerController(service.mContext, this); } int getDisplayId() { @@ -442,6 +447,35 @@ class DisplayContent { } } + void rotateBounds(int oldRotation, int newRotation, Rect bounds) { + final int rotationDelta = DisplayContent.deltaRotation(oldRotation, newRotation); + getLogicalDisplayRect(mTmpRect); + switch (rotationDelta) { + case Surface.ROTATION_0: + mTmpRect2.set(bounds); + break; + case Surface.ROTATION_90: + mTmpRect2.top = mTmpRect.bottom - bounds.right; + mTmpRect2.left = bounds.top; + mTmpRect2.right = mTmpRect2.left + bounds.height(); + mTmpRect2.bottom = mTmpRect2.top + bounds.width(); + break; + case Surface.ROTATION_180: + mTmpRect2.top = mTmpRect.bottom - bounds.bottom; + mTmpRect2.left = mTmpRect.right - bounds.right; + mTmpRect2.right = mTmpRect2.left + bounds.width(); + mTmpRect2.bottom = mTmpRect2.top + bounds.height(); + break; + case Surface.ROTATION_270: + mTmpRect2.top = bounds.left; + mTmpRect2.left = mTmpRect.right - bounds.bottom; + mTmpRect2.right = mTmpRect2.left + bounds.height(); + mTmpRect2.bottom = mTmpRect2.top + bounds.width(); + break; + } + bounds.set(mTmpRect2); + } + static int deltaRotation(int oldRotation, int newRotation) { int delta = newRotation - oldRotation; if (delta < 0) delta += 4; @@ -522,4 +556,14 @@ class DisplayContent { public String toString() { return "Display " + mDisplayId + " info=" + mDisplayInfo + " stacks=" + mStacks; } + + TaskStack getDockedStack() { + for (int i = mStacks.size() - 1; i >= 0; i--) { + TaskStack stack = mStacks.get(i); + if (stack.mStackId == DOCKED_STACK_ID) { + return stack; + } + } + return null; + } } diff --git a/services/core/java/com/android/server/wm/DockedStackDividerController.java b/services/core/java/com/android/server/wm/DockedStackDividerController.java new file mode 100644 index 000000000000..ad207d4b8939 --- /dev/null +++ b/services/core/java/com/android/server/wm/DockedStackDividerController.java @@ -0,0 +1,117 @@ +/* + * Copyright (C) 2012 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server.wm; + +import static android.view.ViewGroup.LayoutParams.MATCH_PARENT; +import static android.view.WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE; +import static android.view.WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL; +import static android.view.WindowManager.LayoutParams.FLAG_SPLIT_TOUCH; +import static android.view.WindowManager.LayoutParams.FLAG_TOUCHABLE_WHEN_WAKING; +import static android.view.WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH; +import static android.view.WindowManager.LayoutParams.TYPE_DOCK_DIVIDER; + +import android.content.Context; +import android.graphics.PixelFormat; +import android.graphics.Rect; +import android.view.LayoutInflater; +import android.view.View; +import android.view.WindowManager; +import android.view.WindowManagerGlobal; + +/** + * Controls showing and hiding of a docked stack divider on the display. + */ +public class DockedStackDividerController { + private static final String TAG = "DockedStackDivider"; + private final Context mContext; + private final int mDividerWidth; + private final DisplayContent mDisplayContent; + private View mView; + private Rect mTmpRect = new Rect(); + + DockedStackDividerController(Context context, DisplayContent displayContent) { + mContext = context; + mDisplayContent = displayContent; + mDividerWidth = context.getResources().getDimensionPixelSize( + com.android.internal.R.dimen.docked_stack_divider_thickness); + } + + private void addDivider() { + View view = LayoutInflater.from(mContext).inflate( + com.android.internal.R.layout.docked_stack_divider, null); + WindowManagerGlobal manager = WindowManagerGlobal.getInstance(); + WindowManager.LayoutParams params = new WindowManager.LayoutParams( + mDividerWidth, MATCH_PARENT, TYPE_DOCK_DIVIDER, + FLAG_TOUCHABLE_WHEN_WAKING | FLAG_NOT_FOCUSABLE | FLAG_NOT_TOUCH_MODAL + | FLAG_WATCH_OUTSIDE_TOUCH | FLAG_SPLIT_TOUCH, + PixelFormat.OPAQUE); + params.setTitle(TAG); + manager.addView(view, params, mDisplayContent.getDisplay(), null); + mView = view; + } + + private void removeDivider() { + WindowManagerGlobal manager = WindowManagerGlobal.getInstance(); + manager.removeView(mView, true /* immediate */); + mView = null; + } + + boolean hasDivider() { + return mView != null; + } + + void update() { + TaskStack stack = mDisplayContent.getDockedStack(); + if (stack != null && mView == null) { + addDivider(); + } else if (stack == null && mView != null) { + removeDivider(); + } + } + + int getWidth() { + return mDividerWidth; + } + + + void positionDockedStackedDivider(Rect frame) { + TaskStack stack = mDisplayContent.getDockedStack(); + if (stack == null) { + // Unfortunately we might end up with still having a divider, even though the underlying + // stack was already removed. This is because we are on AM thread and the removal of the + // divider was deferred to WM thread and hasn't happened yet. + return; + } + final @TaskStack.DockSide int side = stack.getDockSide(); + stack.getBounds(mTmpRect); + switch (side) { + case TaskStack.DOCKED_LEFT: + frame.set(mTmpRect.right, frame.top, mTmpRect.right + frame.width(), frame.bottom); + break; + case TaskStack.DOCKED_TOP: + frame.set(frame.left, mTmpRect.bottom, mTmpRect.right, + mTmpRect.bottom + frame.height()); + break; + case TaskStack.DOCKED_RIGHT: + frame.set(mTmpRect.left - frame.width(), frame.top, mTmpRect.left, frame.bottom); + break; + case TaskStack.DOCKED_BOTTOM: + frame.set(frame.left, mTmpRect.top - frame.height(), frame.right, mTmpRect.top); + break; + } + } +} diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java index cc9efdbe90af..6ebff4212b16 100644 --- a/services/core/java/com/android/server/wm/Task.java +++ b/services/core/java/com/android/server/wm/Task.java @@ -16,6 +16,7 @@ package com.android.server.wm; +import static android.app.ActivityManager.DOCKED_STACK_ID; import static com.android.server.wm.WindowManagerService.TAG; import static com.android.server.wm.WindowManagerService.DEBUG_RESIZE; import static com.android.server.wm.WindowManagerService.DEBUG_STACK; @@ -72,6 +73,9 @@ class Task implements DimLayer.DimLayerUser { // For handling display rotations. private Rect mTmpRect2 = new Rect(); + // Whether the task is currently being drag-resized + private boolean mDragResizing; + // The particular window with FLAG_DIM_BEHIND set. If null, hide mDimLayer. WindowStateAnimator mDimWinAnimator; // Used to support {@link android.view.WindowManager.LayoutParams#FLAG_DIM_BEHIND} @@ -227,10 +231,32 @@ class Task implements DimLayer.DimLayerUser { return boundsChange; } + boolean resizeLocked(Rect bounds, Configuration configuration, boolean forced) { + int boundsChanged = setBounds(bounds, configuration); + if (forced) { + boundsChanged |= BOUNDS_CHANGE_SIZE; + } + if (boundsChanged == BOUNDS_CHANGE_NONE) { + return false; + } + if ((boundsChanged & BOUNDS_CHANGE_SIZE) == BOUNDS_CHANGE_SIZE) { + resizeWindows(); + } + return true; + } + void getBounds(Rect out) { out.set(mBounds); } + void setDragResizing(boolean dragResizing) { + mDragResizing = dragResizing; + } + + boolean isDragResizing() { + return mDragResizing; + } + void updateDisplayInfo(final DisplayContent displayContent) { if (displayContent == null) { return; @@ -246,31 +272,8 @@ class Task implements DimLayer.DimLayerUser { // Device rotation changed. We don't want the task to move around on the screen when // this happens, so update the task bounds so it stays in the same place. - final int rotationDelta = DisplayContent.deltaRotation(mRotation, newRotation); - displayContent.getLogicalDisplayRect(mTmpRect); - switch (rotationDelta) { - case Surface.ROTATION_0: - mTmpRect2.set(mBounds); - break; - case Surface.ROTATION_90: - mTmpRect2.top = mTmpRect.bottom - mBounds.right; - mTmpRect2.left = mBounds.top; - mTmpRect2.right = mTmpRect2.left + mBounds.height(); - mTmpRect2.bottom = mTmpRect2.top + mBounds.width(); - break; - case Surface.ROTATION_180: - mTmpRect2.top = mTmpRect.bottom - mBounds.bottom; - mTmpRect2.left = mTmpRect.right - mBounds.right; - mTmpRect2.right = mTmpRect2.left + mBounds.width(); - mTmpRect2.bottom = mTmpRect2.top + mBounds.height(); - break; - case Surface.ROTATION_270: - mTmpRect2.top = mBounds.left; - mTmpRect2.left = mTmpRect.right - mBounds.bottom; - mTmpRect2.right = mTmpRect2.left + mBounds.height(); - mTmpRect2.bottom = mTmpRect2.top + mBounds.width(); - break; - } + mTmpRect2.set(mBounds); + displayContent.rotateBounds(mRotation, newRotation, mTmpRect2); setBounds(mTmpRect2, mOverrideConfig); } @@ -430,6 +433,10 @@ class Task implements DimLayer.DimLayerUser { return mStack != null && mStack.mStackId == FREEFORM_WORKSPACE_STACK_ID; } + boolean inDockedWorkspace() { + return mStack != null && mStack.mStackId == DOCKED_STACK_ID; + } + @Override public boolean isFullscreen() { return mFullscreen; diff --git a/services/core/java/com/android/server/wm/TaskPositioner.java b/services/core/java/com/android/server/wm/TaskPositioner.java index 17b56ba2ada2..9557d121830d 100644 --- a/services/core/java/com/android/server/wm/TaskPositioner.java +++ b/services/core/java/com/android/server/wm/TaskPositioner.java @@ -19,6 +19,8 @@ package com.android.server.wm; import static android.app.ActivityManager.DOCKED_STACK_CREATE_MODE_BOTTOM_OR_RIGHT; import static android.app.ActivityManager.DOCKED_STACK_CREATE_MODE_TOP_OR_LEFT; import static android.app.ActivityManager.FREEFORM_WORKSPACE_STACK_ID; +import static android.app.ActivityManager.RESIZE_MODE_FORCED; +import static android.app.ActivityManager.RESIZE_MODE_USER; import static android.content.res.Configuration.ORIENTATION_LANDSCAPE; import static com.android.server.wm.WindowManagerService.DEBUG_TASK_POSITIONING; import static com.android.server.wm.WindowManagerService.SHOW_TRANSACTIONS; @@ -86,8 +88,7 @@ class TaskPositioner implements DimLayer.DimLayerUser { private int mMinVisibleWidth; private int mMinVisibleHeight; - private int mTaskId; - private TaskStack mStack; + private Task mTask; private boolean mResizing; private final Rect mWindowOriginalBounds = new Rect(); private final Rect mWindowDragBounds = new Rect(); @@ -95,6 +96,7 @@ class TaskPositioner implements DimLayer.DimLayerUser { private float mStartDragY; @CtrlType private int mCtrlType = CTRL_NONE; + private boolean mDragEnded = false; InputChannel mServerChannel; InputChannel mClientChannel; @@ -116,7 +118,14 @@ class TaskPositioner implements DimLayer.DimLayerUser { boolean handled = false; try { - boolean endDrag = false; + if (mDragEnded) { + // The drag has ended but the clean-up message has not been processed by + // window manager. Drop events that occur after this until window manager + // has a chance to clean-up the input handle. + handled = true; + return; + } + final float newX = motionEvent.getRawX(); final float newY = motionEvent.getRawY(); @@ -132,11 +141,11 @@ class TaskPositioner implements DimLayer.DimLayerUser { Slog.w(TAG, "ACTION_MOVE @ {" + newX + ", " + newY + "}"); } synchronized (mService.mWindowMap) { - endDrag = notifyMoveLocked(newX, newY); + mDragEnded = notifyMoveLocked(newX, newY); } try { mService.mActivityManager.resizeTask( - mTaskId, mWindowDragBounds, true /* resizedByUser */); + mTask.mTaskId, mWindowDragBounds, RESIZE_MODE_USER); } catch(RemoteException e) {} } break; @@ -144,33 +153,41 @@ class TaskPositioner implements DimLayer.DimLayerUser { if (DEBUG_TASK_POSITIONING) { Slog.w(TAG, "ACTION_UP @ {" + newX + ", " + newY + "}"); } - endDrag = true; + mDragEnded = true; } break; case MotionEvent.ACTION_CANCEL: { if (DEBUG_TASK_POSITIONING) { Slog.w(TAG, "ACTION_CANCEL @ {" + newX + ", " + newY + "}"); } - endDrag = true; + mDragEnded = true; } break; } - if (endDrag) { - mResizing = false; + if (mDragEnded) { + synchronized (mService.mWindowMap) { + endDragLocked(); + } try { - mService.mActivityManager.resizeTask( - mTaskId, mWindowDragBounds, true /* resizedByUser */); + if (mResizing) { + // We were using fullscreen surface during resizing. Request + // resizeTask() one last time to restore surface to window size. + mService.mActivityManager.resizeTask( + mTask.mTaskId, mWindowDragBounds, RESIZE_MODE_FORCED); + } + + if (mCurrentDimSide != CTRL_NONE) { + final int createMode = mCurrentDimSide == CTRL_LEFT + ? DOCKED_STACK_CREATE_MODE_TOP_OR_LEFT + : DOCKED_STACK_CREATE_MODE_BOTTOM_OR_RIGHT; + mService.mActivityManager.moveTaskToDockedStack( + mTask.mTaskId, createMode, true /*toTop*/); + } } catch(RemoteException e) {} + // Post back to WM to handle clean-ups. We still need the input // event handler for the last finishInputEvent()! mService.mH.sendEmptyMessage(H.FINISH_TASK_POSITIONING); - if (mCurrentDimSide != CTRL_NONE) { - final int createMode = mCurrentDimSide == CTRL_LEFT - ? DOCKED_STACK_CREATE_MODE_TOP_OR_LEFT - : DOCKED_STACK_CREATE_MODE_BOTTOM_OR_RIGHT; - mService.mActivityManager.moveTaskToDockedStack( - mTaskId, createMode, true /*toTop*/); - } } handled = true; } catch (Exception e) { @@ -253,6 +270,8 @@ class TaskPositioner implements DimLayer.DimLayerUser { mSideMargin = mService.dipToPixel(SIDE_MARGIN_DIP, mDisplayMetrics); mMinVisibleWidth = mService.dipToPixel(MINIMUM_VISIBLE_WIDTH_IN_DP, mDisplayMetrics); mMinVisibleHeight = mService.dipToPixel(MINIMUM_VISIBLE_HEIGHT_IN_DP, mDisplayMetrics); + + mDragEnded = false; } void unregister() { @@ -283,6 +302,7 @@ class TaskPositioner implements DimLayer.DimLayerUser { mDimLayer = null; } mCurrentDimSide = CTRL_NONE; + mDragEnded = true; // Resume rotations after a drag. if (WindowManagerService.DEBUG_ORIENTATION) { @@ -291,10 +311,6 @@ class TaskPositioner implements DimLayer.DimLayerUser { mService.resumeRotationLocked(); } - boolean isTaskResizing(final Task task) { - return mResizing && task != null && mTaskId == task.mTaskId; - } - void startDragLocked(WindowState win, boolean resize, float startX, float startY) { if (DEBUG_TASK_POSITIONING) { Slog.d(TAG, "startDragLocked: win=" + win + ", resize=" + resize @@ -318,13 +334,16 @@ class TaskPositioner implements DimLayer.DimLayerUser { mResizing = true; } - final Task task = win.getTask(); - mTaskId = task.mTaskId; - mStack = task.mStack; + mTask = win.getTask(); mStartDragX = startX; mStartDragY = startY; - mService.getTaskBounds(mTaskId, mWindowOriginalBounds); + mService.getTaskBounds(mTask.mTaskId, mWindowOriginalBounds); + } + + private void endDragLocked() { + mResizing = false; + mTask.setDragResizing(false); } /** Returns true if the move operation should be ended. */ @@ -354,11 +373,12 @@ class TaskPositioner implements DimLayer.DimLayerUser { bottom = Math.max(top + mMinVisibleHeight, bottom + deltaY); } mWindowDragBounds.set(left, top, right, bottom); + mTask.setDragResizing(true); return false; } // This is a moving operation. - mStack.getBounds(mTmpRect); + mTask.mStack.getBounds(mTmpRect); mTmpRect.inset(mMinVisibleWidth, mMinVisibleHeight); if (!mTmpRect.contains((int) x, (int) y)) { // We end the moving operation if position is outside the stack bounds. @@ -397,13 +417,13 @@ class TaskPositioner implements DimLayer.DimLayerUser { * shouldn't be shown. */ private int getDimSide(int x) { - if (mStack.mStackId != FREEFORM_WORKSPACE_STACK_ID - || !mStack.isFullscreen() + if (mTask.mStack.mStackId != FREEFORM_WORKSPACE_STACK_ID + || !mTask.mStack.isFullscreen() || mService.mCurConfiguration.orientation != ORIENTATION_LANDSCAPE) { return CTRL_NONE; } - mStack.getBounds(mTmpRect); + mTask.mStack.getBounds(mTmpRect); if (x - mSideMargin <= mTmpRect.left) { return CTRL_LEFT; } @@ -415,7 +435,7 @@ class TaskPositioner implements DimLayer.DimLayerUser { } private void showDimLayer() { - mStack.getBounds(mTmpRect); + mTask.mStack.getBounds(mTmpRect); if (mCurrentDimSide == CTRL_LEFT) { mTmpRect.right = mTmpRect.centerX(); } else if (mCurrentDimSide == CTRL_RIGHT) { @@ -433,7 +453,7 @@ class TaskPositioner implements DimLayer.DimLayerUser { @Override /** {@link DimLayer.DimLayerUser} */ public DisplayInfo getDisplayInfo() { - return mStack.getDisplayInfo(); + return mTask.mStack.getDisplayInfo(); } private int getDragLayerLocked() { diff --git a/services/core/java/com/android/server/wm/TaskStack.java b/services/core/java/com/android/server/wm/TaskStack.java index 571540fade62..96fcf93b5981 100644 --- a/services/core/java/com/android/server/wm/TaskStack.java +++ b/services/core/java/com/android/server/wm/TaskStack.java @@ -30,6 +30,7 @@ import android.util.Slog; import android.util.SparseArray; import android.view.DisplayInfo; +import android.view.Surface; import com.android.server.EventLogTags; import java.io.PrintWriter; @@ -57,6 +58,7 @@ public class TaskStack implements DimLayer.DimLayerUser { /** For comparison with DisplayContent bounds. */ private Rect mTmpRect = new Rect(); + private Rect TmpRect2 = new Rect(); /** Content limits relative to the DisplayContent this sits in. */ private Rect mBounds = new Rect(); @@ -64,6 +66,9 @@ public class TaskStack implements DimLayer.DimLayerUser { /** Whether mBounds is fullscreen */ private boolean mFullscreen = true; + // Device rotation as of the last time {@link #mBounds} was set. + int mRotation; + /** Support for non-zero {@link android.view.animation.Animation#getBackgroundColor()} */ DimLayer mAnimationBackgroundSurface; @@ -118,30 +123,22 @@ public class TaskStack implements DimLayer.DimLayerUser { /** * Set the bounds of the stack and its containing tasks. * @param stackBounds New stack bounds. Passing in null sets the bounds to fullscreen. - * @param resizeTasks If true, the tasks within the stack will also be resized. * @param configs Configuration for individual tasks, keyed by task id. * @param taskBounds Bounds for individual tasks, keyed by task id. * @return True if the stack bounds was changed. * */ - boolean setBounds(Rect stackBounds, boolean resizeTasks, SparseArray<Configuration> configs, - SparseArray<Rect> taskBounds) { + boolean setBounds( + Rect stackBounds, SparseArray<Configuration> configs, SparseArray<Rect> taskBounds) { if (!setBounds(stackBounds)) { return false; } - if (!resizeTasks) { - return true; - } - // Update bounds of containing tasks. for (int taskNdx = mTasks.size() - 1; taskNdx >= 0; --taskNdx) { final Task task = mTasks.get(taskNdx); Configuration config = configs.get(task.mTaskId); if (config != null) { Rect bounds = taskBounds.get(task.mTaskId); - if (bounds == null) { - bounds = stackBounds; - } task.setBounds(bounds, config); } else { Slog.wtf(TAG, "No config for task: " + task + ", is there a mismatch with AM?"); @@ -152,8 +149,10 @@ public class TaskStack implements DimLayer.DimLayerUser { private boolean setBounds(Rect bounds) { boolean oldFullscreen = mFullscreen; + int rotation = Surface.ROTATION_0; if (mDisplayContent != null) { mDisplayContent.getLogicalDisplayRect(mTmpRect); + rotation = mDisplayContent.getDisplayInfo().rotation; if (bounds == null) { bounds = mTmpRect; mFullscreen = true; @@ -171,12 +170,13 @@ public class TaskStack implements DimLayer.DimLayerUser { // Can't set to fullscreen if we don't have a display to get bounds from... return false; } - if (mBounds.equals(bounds) && oldFullscreen == mFullscreen) { + if (mBounds.equals(bounds) && oldFullscreen == mFullscreen && mRotation == rotation) { return false; } mAnimationBackgroundSurface.setBounds(bounds); mBounds.set(bounds); + mRotation = rotation; return true; } @@ -188,8 +188,13 @@ public class TaskStack implements DimLayer.DimLayerUser { if (mDisplayContent != null) { if (bounds != null) { setBounds(bounds); + } else if (mFullscreen) { + setBounds(null); } else { - setBounds(mFullscreen ? null : mBounds); + TmpRect2.set(mBounds); + mDisplayContent.rotateBounds( + mRotation, mDisplayContent.getDisplayInfo().rotation, TmpRect2); + setBounds(TmpRect2); } for (int taskNdx = mTasks.size() - 1; taskNdx >= 0; --taskNdx) { mTasks.get(taskNdx).updateDisplayInfo(mDisplayContent); @@ -347,7 +352,8 @@ public class TaskStack implements DimLayer.DimLayerUser { // the docked stack occupies a dedicated region on screen. bounds = new Rect(); displayContent.getLogicalDisplayRect(mTmpRect); - getInitialDockedStackBounds(mTmpRect, bounds, mStackId); + getInitialDockedStackBounds(mTmpRect, bounds, mStackId, + mDisplayContent.mDividerControllerLocked.getWidth() / 2); } updateDisplayInfo(bounds); @@ -366,27 +372,29 @@ public class TaskStack implements DimLayer.DimLayerUser { * @param displayRect The bounds of the display the docked stack is on. * @param outBounds Output bounds that should be used for the stack. * @param stackId Id of stack we are calculating the bounds for. + * @param adjustment */ - private static void getInitialDockedStackBounds( - Rect displayRect, Rect outBounds, int stackId) { + private static void getInitialDockedStackBounds(Rect displayRect, Rect outBounds, int stackId, + int adjustment) { // Docked stack start off occupying half the screen space. + final boolean dockedStack = stackId == DOCKED_STACK_ID; final boolean splitHorizontally = displayRect.width() > displayRect.height(); final boolean topOrLeftCreateMode = WindowManagerService.sDockedStackCreateMode == DOCKED_STACK_CREATE_MODE_TOP_OR_LEFT; - final boolean placeTopOrLeft = (stackId == DOCKED_STACK_ID && topOrLeftCreateMode) - || (stackId != DOCKED_STACK_ID && !topOrLeftCreateMode); + final boolean placeTopOrLeft = (dockedStack && topOrLeftCreateMode) + || (!dockedStack && !topOrLeftCreateMode); outBounds.set(displayRect); if (placeTopOrLeft) { if (splitHorizontally) { - outBounds.right = displayRect.centerX(); + outBounds.right = displayRect.centerX() - adjustment; } else { - outBounds.bottom = displayRect.centerY(); + outBounds.bottom = displayRect.centerY() - adjustment; } } else { if (splitHorizontally) { - outBounds.left = displayRect.centerX(); + outBounds.left = displayRect.centerX() + adjustment; } else { - outBounds.top = displayRect.centerY(); + outBounds.top = displayRect.centerY() + adjustment; } } } @@ -399,7 +407,8 @@ public class TaskStack implements DimLayer.DimLayerUser { private void resizeNonDockedStacks(boolean fullscreen) { mDisplayContent.getLogicalDisplayRect(mTmpRect); if (!fullscreen) { - getInitialDockedStackBounds(mTmpRect, mTmpRect, FULLSCREEN_WORKSPACE_STACK_ID); + getInitialDockedStackBounds(mTmpRect, mTmpRect, FULLSCREEN_WORKSPACE_STACK_ID, + mDisplayContent.mDividerControllerLocked.getWidth()); } final int count = mService.mStackIdToStack.size(); @@ -541,14 +550,14 @@ public class TaskStack implements DimLayer.DimLayerUser { final int orientation = mService.mCurConfiguration.orientation; if (orientation == Configuration.ORIENTATION_PORTRAIT) { // Portrait mode, docked either at the top or the bottom. - if (mTmpRect.top - mBounds.top < mTmpRect.bottom - mBounds.bottom) { + if (mBounds.top - mTmpRect.top < mTmpRect.bottom - mBounds.bottom) { return DOCKED_TOP; } else { return DOCKED_BOTTOM; } } else if (orientation == Configuration.ORIENTATION_LANDSCAPE) { // Landscape mode, docked either on the left or on the right. - if (mTmpRect.left - mBounds.left < mTmpRect.right - mBounds.right) { + if (mBounds.left - mTmpRect.left < mTmpRect.right - mBounds.right) { return DOCKED_LEFT; } else { return DOCKED_RIGHT; diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java index 22a6f62abad5..d510c4a4f7f0 100644 --- a/services/core/java/com/android/server/wm/WindowManagerService.java +++ b/services/core/java/com/android/server/wm/WindowManagerService.java @@ -17,6 +17,7 @@ package com.android.server.wm; import static android.app.ActivityManager.DOCKED_STACK_CREATE_MODE_TOP_OR_LEFT; +import static android.app.ActivityManager.DOCKED_STACK_ID; import static android.view.WindowManager.LayoutParams.FIRST_APPLICATION_WINDOW; import static android.view.WindowManager.LayoutParams.FIRST_SUB_WINDOW; import static android.view.WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM; @@ -33,6 +34,7 @@ import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION; import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_STARTING; import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION; import static android.view.WindowManager.LayoutParams.TYPE_BOOT_PROGRESS; +import static android.view.WindowManager.LayoutParams.TYPE_DOCK_DIVIDER; import static android.view.WindowManager.LayoutParams.TYPE_DREAM; import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD; import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD_DIALOG; @@ -921,6 +923,7 @@ public class WindowManagerService extends IWindowManager.Stub mAllowTheaterModeWakeFromLayout = context.getResources().getBoolean( com.android.internal.R.bool.config_allowTheaterModeWakeFromWindowLayout); + LocalServices.addService(WindowManagerInternal.class, new LocalService()); initPolicy(); @@ -1854,6 +1857,11 @@ public class WindowManagerService extends IWindowManager.Stub + attrs.token + ". Aborting."); return WindowManagerGlobal.ADD_BAD_APP_TOKEN; } + } else if (type == TYPE_DOCK_DIVIDER) { + if (displayContent.mDividerControllerLocked.hasDivider()) { + Slog.w(TAG, "Attempted to add docked stack divider twice. Aborting."); + return WindowManagerGlobal.ADD_MULTIPLE_SINGLETON; + } } else if (token.appWindowToken != null) { Slog.w(TAG, "Non-null appWindowToken for system window of type=" + type); // It is not valid to use an app token with other system types; we will @@ -2589,9 +2597,13 @@ public class WindowManagerService extends IWindowManager.Stub } } - dragResizing = win.isDragResizing(); - if (win.mDragResizing != dragResizing) { - win.mDragResizing = dragResizing; + // If we're starting a drag-resize, we'll be changing the surface size as well as + // notifying the client to render to with an offset from the surface's top-left. + // Do a screen freeze, and keep the old surface until the the first frame drawn to + // the new surface comes back, so that we avoid a flash due to mismatching surface + // setups on window manager side and client side. + if (win.isDragResizeChanged()) { + win.setDragResizing(); if (win.mHasSurface) { winAnimator.mDestroyPendingSurfaceUponRedraw = true; winAnimator.mSurfaceDestroyDeferred = true; @@ -2600,6 +2612,7 @@ public class WindowManagerService extends IWindowManager.Stub toBeDisplayed = true; } } + dragResizing = win.isDragResizing(); try { if (!win.mHasSurface) { surfaceChanged = true; @@ -4516,7 +4529,10 @@ public class WindowManagerService extends IWindowManager.Stub } stack.attachDisplayContent(displayContent); displayContent.attachStack(stack, onTop); - + if (stack.mStackId == DOCKED_STACK_ID) { + mH.obtainMessage(H.UPDATE_DOCKED_STACK_DIVIDER, + displayContent).sendToTarget(); + } moveStackWindowsLocked(displayContent); final WindowList windows = displayContent.getWindowList(); for (int winNdx = windows.size() - 1; winNdx >= 0; --winNdx) { @@ -4539,6 +4555,11 @@ public class WindowManagerService extends IWindowManager.Stub void detachStackLocked(DisplayContent displayContent, TaskStack stack) { displayContent.detachStack(stack); stack.detachDisplay(); + // We can't directly remove the divider, because only the WM thread can do these operations + // and we can be on AM thread. + if (stack.mStackId == DOCKED_STACK_ID) { + mH.obtainMessage(H.UPDATE_DOCKED_STACK_DIVIDER, displayContent).sendToTarget(); + } } public void detachStack(int stackId) { @@ -4627,12 +4648,11 @@ public class WindowManagerService extends IWindowManager.Stub * Re-sizes a stack and its containing tasks. * @param stackId Id of stack to resize. * @param bounds New stack bounds. Passing in null sets the bounds to fullscreen. - * @param resizeTasks If true, the tasks within the stack will also be resized. * @param configs Configurations for tasks in the resized stack, keyed by task id. * @param taskBounds Bounds for tasks in the resized stack, keyed by task id. * @return True if the stack is now fullscreen. * */ - public boolean resizeStack(int stackId, Rect bounds, boolean resizeTasks, + public boolean resizeStack(int stackId, Rect bounds, SparseArray<Configuration> configs, SparseArray<Rect> taskBounds) { synchronized (mWindowMap) { final TaskStack stack = mStackIdToStack.get(stackId); @@ -4640,7 +4660,7 @@ public class WindowManagerService extends IWindowManager.Stub throw new IllegalArgumentException("resizeStack: stackId " + stackId + " not found."); } - if (stack.setBounds(bounds, resizeTasks, configs, taskBounds)) { + if (stack.setBounds(bounds, configs, taskBounds)) { stack.resizeWindows(); stack.getDisplayContent().layoutNeeded = true; mWindowPlacerLocked.performSurfacePlacement(); @@ -4677,23 +4697,18 @@ public class WindowManagerService extends IWindowManager.Stub * Returns a {@link Configuration} object that contains configurations settings * that should be overridden due to the operation. */ - public void resizeTask(int taskId, Rect bounds, Configuration configuration, boolean relayout) { + public void resizeTask(int taskId, Rect bounds, Configuration configuration, + boolean relayout, boolean forced) { synchronized (mWindowMap) { Task task = mTaskIdToTask.get(taskId); if (task == null) { throw new IllegalArgumentException("resizeTask: taskId " + taskId + " not found."); } - final int boundsChanged = task.setBounds(bounds, configuration); - if (boundsChanged != Task.BOUNDS_CHANGE_NONE) { - if ((boundsChanged & Task.BOUNDS_CHANGE_SIZE) == Task.BOUNDS_CHANGE_SIZE) { - task.resizeWindows(); - } - if (relayout) { - task.getDisplayContent().layoutNeeded = true; - mWindowPlacerLocked.performSurfacePlacement(); - } + if (task.resizeLocked(bounds, configuration, forced) && relayout) { + task.getDisplayContent().layoutNeeded = true; + mWindowPlacerLocked.performSurfacePlacement(); } } } @@ -7221,6 +7236,8 @@ public class WindowManagerService extends IWindowManager.Stub public static final int TAP_DOWN_OUTSIDE_TASK = 40; public static final int FINISH_TASK_POSITIONING = 41; + public static final int UPDATE_DOCKED_STACK_DIVIDER = 42; + @Override public void handleMessage(Message msg) { if (DEBUG_WINDOW_TRACE) { @@ -7760,6 +7777,13 @@ public class WindowManagerService extends IWindowManager.Stub } } break; + case UPDATE_DOCKED_STACK_DIVIDER: { + DisplayContent content = (DisplayContent) msg.obj; + synchronized (mWindowMap) { + content.mDividerControllerLocked.update(); + } + } + break; } if (DEBUG_WINDOW_TRACE) { Slog.v(TAG, "handleMessage: exit"); @@ -8476,7 +8500,7 @@ public class WindowManagerService extends IWindowManager.Stub Slog.v(TAG, "Win " + w + " config changed: " + mCurConfiguration); } - final boolean dragResizingChanged = w.mDragResizing != w.isDragResizing(); + final boolean dragResizingChanged = w.isDragResizeChanged(); if (localLOGV) Slog.v(TAG, "Resizing " + w + ": configChanged=" + configChanged + " dragResizingChanged=" + dragResizingChanged diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java index 16347f560e64..64440d389910 100644 --- a/services/core/java/com/android/server/wm/WindowState.java +++ b/services/core/java/com/android/server/wm/WindowState.java @@ -23,6 +23,7 @@ import static android.view.WindowManager.LayoutParams.LAST_SUB_WINDOW; import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_COMPATIBLE_WINDOW; import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_KEYGUARD; import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_STARTING; +import static android.view.WindowManager.LayoutParams.TYPE_DOCK_DIVIDER; import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD; import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD_DIALOG; import static android.view.WindowManager.LayoutParams.TYPE_WALLPAPER; @@ -128,6 +129,7 @@ final class WindowState implements WindowManagerPolicy.WindowState { boolean mAttachedHidden; // is our parent window hidden? boolean mWallpaperVisible; // for wallpaper, what was last vis report? boolean mDragResizing; + boolean mDragResizeChanging; RemoteCallbackList<IWindowFocusObserver> mFocusCallbacks; @@ -706,6 +708,8 @@ final class WindowState implements WindowManagerPolicy.WindowState { mContentFrame.set(mFrame); mVisibleFrame.set(mContentFrame); mStableFrame.set(mContentFrame); + } else if (mAttrs.type == TYPE_DOCK_DIVIDER) { + mDisplayContent.mDividerControllerLocked.positionDockedStackedDivider(mFrame); } else { mContentFrame.set(Math.max(mContentFrame.left, mFrame.left), Math.max(mContentFrame.top, mFrame.top), @@ -1701,9 +1705,18 @@ final class WindowState implements WindowManagerPolicy.WindowState { return task != null && task.inFreeformWorkspace(); } - boolean isDragResizing() { + boolean isDragResizeChanged() { + final Task task = getTask(); + return task != null && mDragResizing != task.isDragResizing(); + } + + void setDragResizing() { final Task task = getTask(); - return mService.mTaskPositioner != null && mService.mTaskPositioner.isTaskResizing(task); + mDragResizing = task != null && task.isDragResizing(); + } + + boolean isDragResizing() { + return mDragResizing; } void dump(PrintWriter pw, String prefix, boolean dumpAll) { diff --git a/services/core/java/com/android/server/wm/WindowStateAnimator.java b/services/core/java/com/android/server/wm/WindowStateAnimator.java index e6fef2f0d22f..07e1fce4c741 100644 --- a/services/core/java/com/android/server/wm/WindowStateAnimator.java +++ b/services/core/java/com/android/server/wm/WindowStateAnimator.java @@ -818,7 +818,7 @@ class WindowStateAnimator { // so that we don't need to reallocate during the process. This also prevents // buffer drops due to size mismatch. final DisplayInfo displayInfo = w.getDisplayInfo(); - if (displayInfo != null && w.mDragResizing) { + if (displayInfo != null && w.isDragResizing()) { left = 0; top = 0; width = displayInfo.logicalWidth; @@ -1211,6 +1211,13 @@ class WindowStateAnimator { return; } else if (mIsWallpaper && mService.mWindowPlacerLocked.mWallpaperActionPending) { return; + } else if (mWin.isDragResizeChanged()) { + // This window is awaiting a relayout because user just started (or ended) + // drag-resizing. The shown frame (which affects surface size and pos) + // should not be updated until we get next finished draw with the new surface. + // Otherwise one or two frames rendered with old settings would be displayed + // with new geometry. + return; } if (WindowManagerService.localLOGV) Slog.v( @@ -1333,7 +1340,7 @@ class WindowStateAnimator { final boolean fullscreen = w.isFullscreen(displayInfo.appWidth, displayInfo.appHeight); final Rect clipRect = mTmpClipRect; - if (w.mDragResizing) { + if (w.isDragResizing()) { // When we're doing a drag-resizing, the surface is set up to cover full screen. // Set the clip rect to be the same size so that we don't get any scaling. clipRect.set(0, 0, displayInfo.logicalWidth, displayInfo.logicalHeight); @@ -1423,7 +1430,7 @@ class WindowStateAnimator { // so that we don't need to reallocate during the process. This also prevents // buffer drops due to size mismatch. final DisplayInfo displayInfo = w.getDisplayInfo(); - if (displayInfo != null && w.mDragResizing) { + if (displayInfo != null && w.isDragResizing()) { left = 0; top = 0; width = displayInfo.logicalWidth; diff --git a/services/core/jni/com_android_server_AlarmManagerService.cpp b/services/core/jni/com_android_server_AlarmManagerService.cpp index 3fd0f84f5957..5cbb277a2f12 100644 --- a/services/core/jni/com_android_server_AlarmManagerService.cpp +++ b/services/core/jni/com_android_server_AlarmManagerService.cpp @@ -460,7 +460,7 @@ static jint android_server_AlarmManagerService_waitForAlarm(JNIEnv*, jobject, jl return result; } -static JNINativeMethod sMethods[] = { +static const JNINativeMethod sMethods[] = { /* name, signature, funcPtr */ {"init", "()J", (void*)android_server_AlarmManagerService_init}, {"close", "(J)V", (void*)android_server_AlarmManagerService_close}, diff --git a/services/core/jni/com_android_server_AssetAtlasService.cpp b/services/core/jni/com_android_server_AssetAtlasService.cpp index 8f4fb51093d9..ed79ceb3a9d3 100644 --- a/services/core/jni/com_android_server_AssetAtlasService.cpp +++ b/services/core/jni/com_android_server_AssetAtlasService.cpp @@ -204,7 +204,7 @@ static jboolean com_android_server_AssetAtlasService_upload(JNIEnv* env, jobject const char* const kClassPathName = "com/android/server/AssetAtlasService"; -static JNINativeMethod gMethods[] = { +static const JNINativeMethod gMethods[] = { { "nUploadAtlas", "(Landroid/view/GraphicBuffer;Landroid/graphics/Bitmap;)Z", (void*) com_android_server_AssetAtlasService_upload }, }; diff --git a/services/core/jni/com_android_server_ConsumerIrService.cpp b/services/core/jni/com_android_server_ConsumerIrService.cpp index f5121cdf5580..7104870349b5 100644 --- a/services/core/jni/com_android_server_ConsumerIrService.cpp +++ b/services/core/jni/com_android_server_ConsumerIrService.cpp @@ -100,7 +100,7 @@ static jintArray halGetCarrierFrequencies(JNIEnv *env, jobject /* obj */, return freqsOut.getJavaArray(); } -static JNINativeMethod method_table[] = { +static const JNINativeMethod method_table[] = { { "halOpen", "()J", (void *)halOpen }, { "halTransmit", "(JI[I)I", (void *)halTransmit }, { "halGetCarrierFrequencies", "(J)[I", (void *)halGetCarrierFrequencies}, diff --git a/services/core/jni/com_android_server_PersistentDataBlockService.cpp b/services/core/jni/com_android_server_PersistentDataBlockService.cpp index 4ccfa56cd30c..06de592d7533 100644 --- a/services/core/jni/com_android_server_PersistentDataBlockService.cpp +++ b/services/core/jni/com_android_server_PersistentDataBlockService.cpp @@ -97,7 +97,7 @@ namespace android { return wipe_block_device(fd); } - static JNINativeMethod sMethods[] = { + static const JNINativeMethod sMethods[] = { /* name, signature, funcPtr */ {"nativeGetBlockDeviceSize", "(Ljava/lang/String;)J", (void*)com_android_server_PersistentDataBlockService_getBlockDeviceSize}, {"nativeWipe", "(Ljava/lang/String;)I", (void*)com_android_server_PersistentDataBlockService_wipe}, diff --git a/services/core/jni/com_android_server_SerialService.cpp b/services/core/jni/com_android_server_SerialService.cpp index d48d159b1178..1bd7a599ed60 100644 --- a/services/core/jni/com_android_server_SerialService.cpp +++ b/services/core/jni/com_android_server_SerialService.cpp @@ -55,7 +55,7 @@ static jobject android_server_SerialService_open(JNIEnv *env, jobject /* thiz */ } -static JNINativeMethod method_table[] = { +static const JNINativeMethod method_table[] = { { "native_open", "(Ljava/lang/String;)Landroid/os/ParcelFileDescriptor;", (void*)android_server_SerialService_open }, }; diff --git a/services/core/jni/com_android_server_SystemServer.cpp b/services/core/jni/com_android_server_SystemServer.cpp index 64514a9f72e8..c7d6b95083d2 100644 --- a/services/core/jni/com_android_server_SystemServer.cpp +++ b/services/core/jni/com_android_server_SystemServer.cpp @@ -37,7 +37,7 @@ static void android_server_SystemServer_startSensorService(JNIEnv* /* env */, jo /* * JNI registration. */ -static JNINativeMethod gMethods[] = { +static const JNINativeMethod gMethods[] = { /* name, signature, funcPtr */ { "startSensorService", "()V", (void*) android_server_SystemServer_startSensorService }, }; diff --git a/services/core/jni/com_android_server_UsbDeviceManager.cpp b/services/core/jni/com_android_server_UsbDeviceManager.cpp index a1bff9d850bf..3733a55e7504 100644 --- a/services/core/jni/com_android_server_UsbDeviceManager.cpp +++ b/services/core/jni/com_android_server_UsbDeviceManager.cpp @@ -118,7 +118,7 @@ static jint android_server_UsbDeviceManager_getAudioMode(JNIEnv* /* env */, jobj return result; } -static JNINativeMethod method_table[] = { +static const JNINativeMethod method_table[] = { { "nativeGetAccessoryStrings", "()[Ljava/lang/String;", (void*)android_server_UsbDeviceManager_getAccessoryStrings }, { "nativeOpenAccessory", "()Landroid/os/ParcelFileDescriptor;", diff --git a/services/core/jni/com_android_server_UsbHostManager.cpp b/services/core/jni/com_android_server_UsbHostManager.cpp index d8c172fd51cc..795f6aa6018a 100644 --- a/services/core/jni/com_android_server_UsbHostManager.cpp +++ b/services/core/jni/com_android_server_UsbHostManager.cpp @@ -186,7 +186,7 @@ static jobject android_server_UsbHostManager_openDevice(JNIEnv *env, jobject /* gParcelFileDescriptorOffsets.mConstructor, fileDescriptor); } -static JNINativeMethod method_table[] = { +static const JNINativeMethod method_table[] = { { "monitorUsbHostBus", "()V", (void*)android_server_UsbHostManager_monitorUsbHostBus }, { "nativeOpenDevice", "(Ljava/lang/String;)Landroid/os/ParcelFileDescriptor;", (void*)android_server_UsbHostManager_openDevice }, diff --git a/services/core/jni/com_android_server_VibratorService.cpp b/services/core/jni/com_android_server_VibratorService.cpp index fb1166b41d41..64278ed4499b 100644 --- a/services/core/jni/com_android_server_VibratorService.cpp +++ b/services/core/jni/com_android_server_VibratorService.cpp @@ -46,7 +46,7 @@ static void vibratorOff(JNIEnv* /* env */, jobject /* clazz */) vibrator_off(); } -static JNINativeMethod method_table[] = { +static const JNINativeMethod method_table[] = { { "vibratorExists", "()Z", (void*)vibratorExists }, { "vibratorOn", "(J)V", (void*)vibratorOn }, { "vibratorOff", "()V", (void*)vibratorOff } diff --git a/services/core/jni/com_android_server_am_ActivityManagerService.cpp b/services/core/jni/com_android_server_am_ActivityManagerService.cpp index 52217b955852..50e4502a9a3a 100644 --- a/services/core/jni/com_android_server_am_ActivityManagerService.cpp +++ b/services/core/jni/com_android_server_am_ActivityManagerService.cpp @@ -110,7 +110,6 @@ namespace android return 0; } char buf[17]; - char *curBuf = buf; while (fgets(buf, 16, boost_cpuset_file)) { //ALOGE("Appending FD %s to fg", buf); int i = 0; diff --git a/services/core/jni/com_android_server_am_BatteryStatsService.cpp b/services/core/jni/com_android_server_am_BatteryStatsService.cpp index dfc5ef6ec366..5c4365979644 100644 --- a/services/core/jni/com_android_server_am_BatteryStatsService.cpp +++ b/services/core/jni/com_android_server_am_BatteryStatsService.cpp @@ -170,7 +170,7 @@ static jint nativeWaitWakeup(JNIEnv *env, jobject clazz, jobject outBuf) return mergedreasonpos - mergedreason; } -static JNINativeMethod method_table[] = { +static const JNINativeMethod method_table[] = { { "nativeWaitWakeup", "(Ljava/nio/ByteBuffer;)I", (void*)nativeWaitWakeup }, }; diff --git a/services/core/jni/com_android_server_connectivity_Vpn.cpp b/services/core/jni/com_android_server_connectivity_Vpn.cpp index 7faeb49d7b56..2d0dfd2f7f26 100644 --- a/services/core/jni/com_android_server_connectivity_Vpn.cpp +++ b/services/core/jni/com_android_server_connectivity_Vpn.cpp @@ -350,7 +350,7 @@ static bool delAddress(JNIEnv *env, jobject thiz, jstring jName, jstring jAddres //------------------------------------------------------------------------------ -static JNINativeMethod gMethods[] = { +static const JNINativeMethod gMethods[] = { {"jniCreate", "(I)I", (void *)create}, {"jniGetName", "(I)Ljava/lang/String;", (void *)getName}, {"jniSetAddresses", "(Ljava/lang/String;Ljava/lang/String;)I", (void *)setAddresses}, diff --git a/services/core/jni/com_android_server_hdmi_HdmiCecController.cpp b/services/core/jni/com_android_server_hdmi_HdmiCecController.cpp index f2d0f060c66c..b72cf4dc94d0 100644 --- a/services/core/jni/com_android_server_hdmi_HdmiCecController.cpp +++ b/services/core/jni/com_android_server_hdmi_HdmiCecController.cpp @@ -384,7 +384,7 @@ static jboolean nativeIsConnected(JNIEnv* env, jclass clazz, jlong controllerPtr return controller->isConnected(port) ? JNI_TRUE : JNI_FALSE ; } -static JNINativeMethod sMethods[] = { +static const JNINativeMethod sMethods[] = { /* name, signature, funcPtr */ { "nativeInit", "(Lcom/android/server/hdmi/HdmiCecController;Landroid/os/MessageQueue;)J", diff --git a/services/core/jni/com_android_server_input_InputApplicationHandle.cpp b/services/core/jni/com_android_server_input_InputApplicationHandle.cpp index 11388d80a9d2..bdc109d086f6 100644 --- a/services/core/jni/com_android_server_input_InputApplicationHandle.cpp +++ b/services/core/jni/com_android_server_input_InputApplicationHandle.cpp @@ -120,7 +120,7 @@ static void android_server_InputApplicationHandle_nativeDispose(JNIEnv* env, job } -static JNINativeMethod gInputApplicationHandleMethods[] = { +static const JNINativeMethod gInputApplicationHandleMethods[] = { /* name, signature, funcPtr */ { "nativeDispose", "()V", (void*) android_server_InputApplicationHandle_nativeDispose }, diff --git a/services/core/jni/com_android_server_input_InputManagerService.cpp b/services/core/jni/com_android_server_input_InputManagerService.cpp index e29d0a94610c..1d4f047ff605 100644 --- a/services/core/jni/com_android_server_input_InputManagerService.cpp +++ b/services/core/jni/com_android_server_input_InputManagerService.cpp @@ -1369,7 +1369,7 @@ static void nativeMonitor(JNIEnv* /* env */, jclass /* clazz */, jlong ptr) { // ---------------------------------------------------------------------------- -static JNINativeMethod gInputManagerMethods[] = { +static const JNINativeMethod gInputManagerMethods[] = { /* name, signature, funcPtr */ { "nativeInit", "(Lcom/android/server/input/InputManagerService;Landroid/content/Context;Landroid/os/MessageQueue;)J", diff --git a/services/core/jni/com_android_server_input_InputWindowHandle.cpp b/services/core/jni/com_android_server_input_InputWindowHandle.cpp index 01c51cf6cfe0..92ef7f1ae096 100644 --- a/services/core/jni/com_android_server_input_InputWindowHandle.cpp +++ b/services/core/jni/com_android_server_input_InputWindowHandle.cpp @@ -210,7 +210,7 @@ static void android_server_InputWindowHandle_nativeDispose(JNIEnv* env, jobject } -static JNINativeMethod gInputWindowHandleMethods[] = { +static const JNINativeMethod gInputWindowHandleMethods[] = { /* name, signature, funcPtr */ { "nativeDispose", "()V", (void*) android_server_InputWindowHandle_nativeDispose }, diff --git a/services/core/jni/com_android_server_lights_LightsService.cpp b/services/core/jni/com_android_server_lights_LightsService.cpp index b2b27835274d..3f074f52f443 100644 --- a/services/core/jni/com_android_server_lights_LightsService.cpp +++ b/services/core/jni/com_android_server_lights_LightsService.cpp @@ -126,7 +126,7 @@ static void setLight_native(JNIEnv* /* env */, jobject /* clazz */, jlong ptr, } } -static JNINativeMethod method_table[] = { +static const JNINativeMethod method_table[] = { { "init_native", "()J", (void*)init_native }, { "finalize_native", "(J)V", (void*)finalize_native }, { "setLight_native", "(JIIIIII)V", (void*)setLight_native }, diff --git a/services/core/jni/com_android_server_location_FlpHardwareProvider.cpp b/services/core/jni/com_android_server_location_FlpHardwareProvider.cpp index c0a0c9cddba5..774577d43d69 100644 --- a/services/core/jni/com_android_server_location_FlpHardwareProvider.cpp +++ b/services/core/jni/com_android_server_location_FlpHardwareProvider.cpp @@ -1023,7 +1023,7 @@ static void RemoveGeofences( env->ReleaseIntArrayElements(geofenceIdsArray, geofenceIds, 0 /*mode*/); } -static JNINativeMethod sMethods[] = { +static const JNINativeMethod sMethods[] = { //{"name", "signature", functionPointer } {"nativeClassInit", "()V", reinterpret_cast<void*>(ClassInit)}, {"nativeInit", "()V", reinterpret_cast<void*>(Init)}, diff --git a/services/core/jni/com_android_server_location_GpsLocationProvider.cpp b/services/core/jni/com_android_server_location_GpsLocationProvider.cpp index 5c27b1f65f17..b8d4196dad16 100644 --- a/services/core/jni/com_android_server_location_GpsLocationProvider.cpp +++ b/services/core/jni/com_android_server_location_GpsLocationProvider.cpp @@ -1434,7 +1434,7 @@ static void android_location_GpsLocationProvider_configuration_update(JNIEnv* en env->ReleaseStringUTFChars(config_content, data); } -static JNINativeMethod sMethods[] = { +static const JNINativeMethod sMethods[] = { /* name, signature, funcPtr */ {"class_init_native", "()V", (void *)android_location_GpsLocationProvider_class_init_native}, {"native_is_supported", "()Z", (void*)android_location_GpsLocationProvider_is_supported}, diff --git a/services/core/jni/com_android_server_power_PowerManagerService.cpp b/services/core/jni/com_android_server_power_PowerManagerService.cpp index 1662755511f4..2fdb8e2469cd 100644 --- a/services/core/jni/com_android_server_power_PowerManagerService.cpp +++ b/services/core/jni/com_android_server_power_PowerManagerService.cpp @@ -166,7 +166,7 @@ static void nativeSetFeature(JNIEnv *env, jclass clazz, jint featureId, jint dat // ---------------------------------------------------------------------------- -static JNINativeMethod gPowerManagerServiceMethods[] = { +static const JNINativeMethod gPowerManagerServiceMethods[] = { /* name, signature, funcPtr */ { "nativeInit", "()V", (void*) nativeInit }, diff --git a/services/core/jni/com_android_server_tv_TvInputHal.cpp b/services/core/jni/com_android_server_tv_TvInputHal.cpp index 507bc9cb5269..89b2a47d73c6 100644 --- a/services/core/jni/com_android_server_tv_TvInputHal.cpp +++ b/services/core/jni/com_android_server_tv_TvInputHal.cpp @@ -662,7 +662,7 @@ static void nativeClose(JNIEnv* env, jclass clazz, jlong ptr) { delete tvInputHal; } -static JNINativeMethod gTvInputHalMethods[] = { +static const JNINativeMethod gTvInputHalMethods[] = { /* name, signature, funcPtr */ { "nativeOpen", "(Landroid/os/MessageQueue;)J", (void*) nativeOpen }, diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java index 67e57034cf91..3f70e0c7ccae 100644 --- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java +++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java @@ -73,8 +73,10 @@ import android.os.Environment; import android.os.FileUtils; import android.os.Handler; import android.os.IBinder; +import android.os.Looper; import android.os.PersistableBundle; import android.os.PowerManager; +import android.os.PowerManager.WakeLock; import android.os.PowerManagerInternal; import android.os.Process; import android.os.RecoverySystem; @@ -111,6 +113,7 @@ import android.view.inputmethod.InputMethodInfo; import android.view.inputmethod.InputMethodManager; import com.android.internal.R; +import com.android.internal.annotations.VisibleForTesting; import com.android.internal.statusbar.IStatusBarService; import com.android.internal.util.FastXmlSerializer; import com.android.internal.util.JournaledFile; @@ -266,16 +269,15 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { | DevicePolicyManager.KEYGUARD_DISABLE_UNREDACTED_NOTIFICATIONS; final Context mContext; + final PackageManager mPackageManager; final UserManager mUserManager; - final PowerManager.WakeLock mWakeLock; final LocalService mLocalService; - final PowerManager mPowerManager; final PowerManagerInternal mPowerManagerInternal; - IWindowManager mIWindowManager; - NotificationManager mNotificationManager; + final IWindowManager mIWindowManager; + final NotificationManager mNotificationManager; // Stores and loads state on device and profile owners. private final Owners mOwners; @@ -346,7 +348,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { final SparseArray<DevicePolicyData> mUserData = new SparseArray<>(); - Handler mHandler = new Handler(); + final Handler mHandler; BroadcastReceiver mReceiver = new BroadcastReceiver() { @Override @@ -992,7 +994,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { boolean removed = false; if (DBG) Slog.d(LOG_TAG, "Handling package changes for user " + userHandle); DevicePolicyData policy = getUserData(userHandle); - IPackageManager pm = AppGlobals.getPackageManager(); + IPackageManager pm = getIPackageManager(); synchronized (this) { for (int i = policy.mAdminList.size() - 1; i >= 0; i--) { ActiveAdmin aa = policy.mAdminList.get(i); @@ -1036,19 +1038,148 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { } } + /** Unit test will override it to inject a mock. */ + @VisibleForTesting + Owners newOwners() { + return new Owners(mContext); + } + + /** Unit test will override it to inject a mock. */ + @VisibleForTesting + UserManager getUserManager() { + return UserManager.get(mContext); + } + + /** Unit test will override it to inject a mock. */ + @VisibleForTesting + PackageManager getPackageManager() { + return mContext.getPackageManager(); + } + + /** Unit test will override it to inject a mock. */ + @VisibleForTesting + NotificationManager getNotificationManager() { + return mContext.getSystemService(NotificationManager.class); + } + + /** Unit test will override it to inject a mock. */ + @VisibleForTesting + PowerManagerInternal getPowerManagerInternal() { + return LocalServices.getService(PowerManagerInternal.class); + } + + /** Unit test will override it to inject a mock. */ + @VisibleForTesting + IWindowManager getIWindowManager() { + return IWindowManager.Stub.asInterface(ServiceManager.getService(Context.WINDOW_SERVICE)); + } + + /** Unit test will override it to inject a mock. */ + @VisibleForTesting + IActivityManager getIActivityManager() { + return ActivityManagerNative.getDefault(); + } + + /** Unit test will override it to inject a mock. */ + @VisibleForTesting + IPackageManager getIPackageManager() { + return AppGlobals.getPackageManager(); + } + + /** Unit test will override it to inject a mock. */ + @VisibleForTesting + LockPatternUtils newLockPatternUtils(Context context) { + return new LockPatternUtils(context); + } + + /** Unit test will override it to inject. */ + @VisibleForTesting + Looper getMyLooper() { + return Looper.myLooper(); + } + + @VisibleForTesting + long binderClearCallingIdentity() { + return Binder.clearCallingIdentity(); + } + + @VisibleForTesting + void binderRestoreCallingIdentity(long token) { + Binder.restoreCallingIdentity(token); + } + + @VisibleForTesting + int binderGetCallingUid() { + return Binder.getCallingUid(); + } + + @VisibleForTesting + int binderGetCallingPid() { + return Binder.getCallingPid(); + } + + @VisibleForTesting + UserHandle binderGetCallingUserHandle() { + return Binder.getCallingUserHandle(); + } + + @VisibleForTesting + boolean binderIsCallingUidMyUid() { + return getCallingUid() == Process.myUid(); + } + + @VisibleForTesting + File environmentGetUserSystemDirectory(int userId) { + return Environment.getUserSystemDirectory(userId); + } + + @VisibleForTesting + void powerManagerGoToSleep(long time, int reason, int flags) { + mContext.getSystemService(PowerManager.class).goToSleep(time, reason, flags); + } + + @VisibleForTesting + boolean systemPropertiesGetBoolean(String key, boolean def) { + return SystemProperties.getBoolean(key, def); + } + + @VisibleForTesting + long systemPropertiesGetLong(String key, long def) { + return SystemProperties.getLong(key, def); + } + + @VisibleForTesting + String systemPropertiesGet(String key, String def) { + return SystemProperties.get(key, def); + } + + @VisibleForTesting + String systemPropertiesGet(String key) { + return SystemProperties.get(key); + } + + @VisibleForTesting + void systemPropertiesSet(String key, String value) { + SystemProperties.set(key, value); + } + /** * Instantiates the service. */ public DevicePolicyManagerService(Context context) { mContext = context; - mOwners = new Owners(mContext); - mUserManager = UserManager.get(mContext); - mHasFeature = context.getPackageManager().hasSystemFeature( - PackageManager.FEATURE_DEVICE_ADMIN); - mPowerManager = (PowerManager)context.getSystemService(Context.POWER_SERVICE); - mPowerManagerInternal = LocalServices.getService(PowerManagerInternal.class); - mWakeLock = mPowerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "DPM"); + mHandler = new Handler(getMyLooper()); + mOwners = newOwners(); + + mUserManager = Preconditions.checkNotNull(getUserManager()); + mPackageManager = Preconditions.checkNotNull(getPackageManager()); + mPowerManagerInternal = Preconditions.checkNotNull(getPowerManagerInternal()); + mIWindowManager = Preconditions.checkNotNull(getIWindowManager()); + mNotificationManager = Preconditions.checkNotNull(getNotificationManager()); + mLocalService = new LocalService(); + + mHasFeature = mPackageManager.hasSystemFeature(PackageManager.FEATURE_DEVICE_ADMIN); if (!mHasFeature) { // Skip the rest of the initialization return; @@ -1076,6 +1207,15 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { } /** + * We need it for testing to allow accessing context from the test-only subclass while this + * class's constructor is still running. + */ + @VisibleForTesting + Context getContext() { + return mContext; + } + + /** * Creates and loads the policy data from xml. * @param userHandle the user for whom to load the policy data * @return @@ -1103,17 +1243,17 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { * @return */ DevicePolicyData getUserDataUnchecked(int userHandle) { - long ident = Binder.clearCallingIdentity(); + long ident = binderClearCallingIdentity(); try { return getUserData(userHandle); } finally { - Binder.restoreCallingIdentity(ident); + binderRestoreCallingIdentity(ident); } } void removeUserData(int userHandle) { synchronized (this) { - if (userHandle == UserHandle.USER_OWNER) { + if (userHandle == UserHandle.USER_SYSTEM) { Slog.w(LOG_TAG, "Tried to remove device policy file for user 0! Ignoring."); return; } @@ -1124,7 +1264,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { if (policy != null) { mUserData.remove(userHandle); } - File policyFile = new File(Environment.getUserSystemDirectory(userHandle), + File policyFile = new File(environmentGetUserSystemDirectory(userHandle), DEVICE_POLICIES_XML); policyFile.delete(); Slog.i(LOG_TAG, "Removed device policy file " + policyFile.getAbsolutePath()); @@ -1164,7 +1304,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { alarmTime = now + alarmInterval; } - long token = Binder.clearCallingIdentity(); + long token = binderClearCallingIdentity(); try { AlarmManager am = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE); PendingIntent pi = PendingIntent.getBroadcastAsUser(context, REQUEST_EXPIRE_PASSWORD, @@ -1176,24 +1316,8 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { am.set(AlarmManager.RTC, alarmTime, pi); } } finally { - Binder.restoreCallingIdentity(token); - } - } - - private IWindowManager getWindowManager() { - if (mIWindowManager == null) { - IBinder b = ServiceManager.getService(Context.WINDOW_SERVICE); - mIWindowManager = IWindowManager.Stub.asInterface(b); - } - return mIWindowManager; - } - - private NotificationManager getNotificationManager() { - if (mNotificationManager == null) { - mNotificationManager = - (NotificationManager) mContext.getSystemService(Context.NOTIFICATION_SERVICE); + binderRestoreCallingIdentity(token); } - return mNotificationManager; } ActiveAdmin getActiveAdminUncheckedLocked(ComponentName who, int userHandle) { @@ -1208,7 +1332,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { ActiveAdmin getActiveAdminForCallerLocked(ComponentName who, int reqPolicy) throws SecurityException { - final int callingUid = Binder.getCallingUid(); + final int callingUid = binderGetCallingUid(); ActiveAdmin result = getActiveAdminWithPolicyForUidLocked(who, reqPolicy, callingUid); if (result != null) { @@ -1232,7 +1356,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { + admin.info.getTagForPolicy(reqPolicy)); } else { throw new SecurityException("No active admin owned by uid " - + Binder.getCallingUid() + " for policy #" + reqPolicy); + + binderGetCallingUid() + " for policy #" + reqPolicy); } } @@ -1248,7 +1372,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { } if (admin.getUid() != uid) { throw new SecurityException("Admin " + who + " is not owned by uid " - + Binder.getCallingUid()); + + binderGetCallingUid()); } if (isActiveAdminWithPolicyForUserLocked(admin, reqPolicy, userId)) { return admin; @@ -1275,12 +1399,12 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { && !hasUserSetupCompleted(userId); if (reqPolicy == DeviceAdminInfo.USES_POLICY_DEVICE_OWNER) { - if ((userId == UserHandle.USER_OWNER && (ownsDevice || ownsInitialization)) + if ((userId == UserHandle.USER_SYSTEM && (ownsDevice || ownsInitialization)) || (ownsDevice && ownsProfile)) { return true; } } else if (reqPolicy == DeviceAdminInfo.USES_POLICY_PROFILE_OWNER) { - if ((userId == UserHandle.USER_OWNER && ownsDevice) || ownsProfile + if ((userId == UserHandle.USER_SYSTEM && ownsDevice) || ownsProfile || ownsInitialization) { return true; } @@ -1410,14 +1534,19 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { } } - private static JournaledFile makeJournaledFile(int userHandle) { - final String base = userHandle == 0 - ? "/data/system/" + DEVICE_POLICIES_XML - : new File(Environment.getUserSystemDirectory(userHandle), DEVICE_POLICIES_XML) + private JournaledFile makeJournaledFile(int userHandle) { + final String base = userHandle == UserHandle.USER_SYSTEM + ? getDevicePolicyFilePathForSystemUser() + DEVICE_POLICIES_XML + : new File(environmentGetUserSystemDirectory(userHandle), DEVICE_POLICIES_XML) .getAbsolutePath(); return new JournaledFile(new File(base), new File(base + ".tmp")); } + @VisibleForTesting + String getDevicePolicyFilePathForSystemUser() { + return "/data/system/"; + } + private void saveSettingsLocked(int userHandle) { DevicePolicyData policy = getUserData(userHandle); JournaledFile journal = makeJournaledFile(userHandle); @@ -1513,6 +1642,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { journal.commit(); sendChangedNotification(userHandle); } catch (IOException e) { + Slog.w(LOG_TAG, "failed writing file", e); try { if (stream != null) { stream.close(); @@ -1527,11 +1657,11 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { private void sendChangedNotification(int userHandle) { Intent intent = new Intent(DevicePolicyManager.ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED); intent.setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY); - long ident = Binder.clearCallingIdentity(); + long ident = binderClearCallingIdentity(); try { mContext.sendBroadcastAsUser(intent, new UserHandle(userHandle)); } finally { - Binder.restoreCallingIdentity(ident); + binderRestoreCallingIdentity(ident); } } @@ -1663,9 +1793,9 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { // sufficiently what is currently set. Note that this is only // a sanity check in case the two get out of sync; this should // never normally happen. - final long identity = Binder.clearCallingIdentity(); + final long identity = binderClearCallingIdentity(); try { - LockPatternUtils utils = new LockPatternUtils(mContext); + LockPatternUtils utils = newLockPatternUtils(mContext); if (utils.getActivePasswordQuality(userHandle) < policy.mActivePasswordQuality) { Slog.w(LOG_TAG, "Active password quality 0x" + Integer.toHexString(policy.mActivePasswordQuality) @@ -1681,7 +1811,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { policy.mActivePasswordNonLetter = 0; } } finally { - Binder.restoreCallingIdentity(identity); + binderRestoreCallingIdentity(identity); } validatePasswordOwnerLocked(policy); @@ -1695,26 +1825,26 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { } private void updateLockTaskPackagesLocked(List<String> packages, int userId) { - IActivityManager am = ActivityManagerNative.getDefault(); - long ident = Binder.clearCallingIdentity(); + IActivityManager am = getIActivityManager(); + long ident = binderClearCallingIdentity(); try { am.updateLockTaskPackages(userId, packages.toArray(new String[packages.size()])); } catch (RemoteException e) { // Not gonna happen. } finally { - Binder.restoreCallingIdentity(ident); + binderRestoreCallingIdentity(ident); } } private void updateDeviceOwnerLocked() { - IActivityManager am = ActivityManagerNative.getDefault(); - long ident = Binder.clearCallingIdentity(); + IActivityManager am = getIActivityManager(); + long ident = binderClearCallingIdentity(); try { am.updateDeviceOwner(getDeviceOwner()); } catch (RemoteException e) { // Not gonna happen. } finally { - Binder.restoreCallingIdentity(ident); + binderRestoreCallingIdentity(ident); } } @@ -1759,17 +1889,17 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { // Ensure the status of the camera is synced down to the system. Interested native services // should monitor this value and act accordingly. String cameraPropertyForUser = SYSTEM_PROP_DISABLE_CAMERA_PREFIX + policy.mUserHandle; - boolean systemState = SystemProperties.getBoolean(cameraPropertyForUser, false); + boolean systemState = systemPropertiesGetBoolean(cameraPropertyForUser, false); boolean cameraDisabled = getCameraDisabled(null, policy.mUserHandle); if (cameraDisabled != systemState) { - long token = Binder.clearCallingIdentity(); + long token = binderClearCallingIdentity(); try { String value = cameraDisabled ? "1" : "0"; if (DBG) Slog.v(LOG_TAG, "Change in camera state [" + cameraPropertyForUser + "] = " + value); - SystemProperties.set(cameraPropertyForUser, value); + systemPropertiesSet(cameraPropertyForUser, value); } finally { - Binder.restoreCallingIdentity(token); + binderRestoreCallingIdentity(token); } } } @@ -1789,7 +1919,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { } private void onLockSettingsReady() { - getUserData(UserHandle.USER_OWNER); + getUserData(UserHandle.USER_SYSTEM); loadOwners(); cleanUpOldUsers(); // Register an observer for watching for user setup complete. @@ -1809,7 +1939,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { private void ensureDeviceOwnerUserStarted() { if (mOwners.hasDeviceOwner()) { - final IActivityManager am = ActivityManagerNative.getDefault(); + final IActivityManager am = getIActivityManager(); final int userId = mOwners.getDeviceOwnerUserId(); if (VERBOSE_LOG) { Log.v(LOG_TAG, "Starting non-system DO user: " + userId); @@ -1917,7 +2047,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { Log.e(LOG_TAG, "Could not connect to KeyChain service", e); } if (!hasCert) { - getNotificationManager().cancelAsUser( + mNotificationManager.cancelAsUser( null, MONITORING_CERT_NOTIFICATION_ID, userHandle); return; } @@ -1962,7 +2092,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { com.android.internal.R.color.system_notification_accent_color)) .build(); - getNotificationManager().notifyAsUser( + mNotificationManager.notifyAsUser( null, MONITORING_CERT_NOTIFICATION_ID, noti, userHandle); } } @@ -1991,7 +2121,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { throw new IllegalArgumentException("Bad admin: " + adminReceiver); } synchronized (this) { - long ident = Binder.clearCallingIdentity(); + long ident = binderClearCallingIdentity(); try { if (!refreshing && getActiveAdminUncheckedLocked(adminReceiver, userHandle) != null) { @@ -2018,7 +2148,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { sendAdminCommandLocked(newAdmin, DeviceAdminReceiver.ACTION_DEVICE_ADMIN_ENABLED, onEnableData, null); } finally { - Binder.restoreCallingIdentity(ident); + binderRestoreCallingIdentity(ident); } } } @@ -2112,7 +2242,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { if (admin == null) { return; } - if (admin.getUid() != Binder.getCallingUid()) { + if (admin.getUid() != binderGetCallingUid()) { // Active device owners must remain active admins. if (isDeviceOwner(adminReceiver.getPackageName())) { return; @@ -2120,11 +2250,11 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { mContext.enforceCallingOrSelfPermission( android.Manifest.permission.MANAGE_DEVICE_ADMINS, null); } - long ident = Binder.clearCallingIdentity(); + long ident = binderClearCallingIdentity(); try { removeActiveAdminLocked(adminReceiver, userHandle); } finally { - Binder.restoreCallingIdentity(ident); + binderRestoreCallingIdentity(ident); } } } @@ -2394,7 +2524,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { || activeAdmin.crossProfileWidgetProviders.isEmpty()) { return null; } - if (Binder.getCallingUid() == Process.myUid()) { + if (binderIsCallingUidMyUid()) { return new ArrayList<>(activeAdmin.crossProfileWidgetProviders); } else { return activeAdmin.crossProfileWidgetProviders; @@ -2959,7 +3089,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { } } - int callingUid = Binder.getCallingUid(); + int callingUid = binderGetCallingUid(); DevicePolicyData policy = getUserData(userHandle); if (policy.mPasswordOwner >= 0 && policy.mPasswordOwner != callingUid) { Slog.w(LOG_TAG, "resetPassword: already set by another uid and not entered by user"); @@ -2975,7 +3105,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { // Don't do this with the lock held, because it is going to call // back in to the service. - long ident = Binder.clearCallingIdentity(); + long ident = binderClearCallingIdentity(); try { LockPatternUtils utils = new LockPatternUtils(mContext); if (!TextUtils.isEmpty(password)) { @@ -2996,7 +3126,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { } } } finally { - Binder.restoreCallingIdentity(ident); + binderRestoreCallingIdentity(ident); } return true; @@ -3004,10 +3134,10 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { private void setDoNotAskCredentialsOnBoot() { synchronized (this) { - DevicePolicyData policyData = getUserData(UserHandle.USER_OWNER); + DevicePolicyData policyData = getUserData(UserHandle.USER_SYSTEM); if (!policyData.doNotAskCredentialsOnBoot) { policyData.doNotAskCredentialsOnBoot = true; - saveSettingsLocked(UserHandle.USER_OWNER); + saveSettingsLocked(UserHandle.USER_SYSTEM); } } } @@ -3017,7 +3147,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { mContext.enforceCallingOrSelfPermission( android.Manifest.permission.QUERY_DO_NOT_ASK_CREDENTIALS_ON_BOOT, null); synchronized (this) { - DevicePolicyData policyData = getUserData(UserHandle.USER_OWNER); + DevicePolicyData policyData = getUserData(UserHandle.USER_SYSTEM); return policyData.doNotAskCredentialsOnBoot; } } @@ -3046,7 +3176,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { return; } - long ident = Binder.clearCallingIdentity(); + long ident = binderClearCallingIdentity(); try { if (timeMs <= 0) { timeMs = Integer.MAX_VALUE; @@ -3060,7 +3190,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { policy.mLastMaximumTimeToLock = timeMs; mPowerManagerInternal.setMaximumScreenOffTimeoutFromDeviceAdmin((int)timeMs); } finally { - Binder.restoreCallingIdentity(ident); + binderRestoreCallingIdentity(ident); } } @@ -3112,23 +3242,23 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { } private void lockNowUnchecked() { - long ident = Binder.clearCallingIdentity(); + long ident = binderClearCallingIdentity(); try { // Power off the display - mPowerManager.goToSleep(SystemClock.uptimeMillis(), + powerManagerGoToSleep(SystemClock.uptimeMillis(), PowerManager.GO_TO_SLEEP_REASON_DEVICE_ADMIN, 0); // Ensure the device is locked new LockPatternUtils(mContext).requireStrongAuth( STRONG_AUTH_REQUIRED_AFTER_DPM_LOCK_NOW, UserHandle.USER_ALL); - getWindowManager().lockNow(null); + mIWindowManager.lockNow(null); } catch (RemoteException e) { } finally { - Binder.restoreCallingIdentity(ident); + binderRestoreCallingIdentity(ident); } } private boolean isExtStorageEncrypted() { - String state = SystemProperties.get("vold.decrypt"); + String state = systemPropertiesGet("vold.decrypt"); return !"".equals(state); } @@ -3146,7 +3276,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { } private boolean isCallerDelegatedCertInstaller() { - final int callingUid = Binder.getCallingUid(); + final int callingUid = binderGetCallingUid(); final int userHandle = UserHandle.getUserId(callingUid); synchronized (this) { final DevicePolicyData policy = getUserData(userHandle); @@ -3181,7 +3311,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { } final UserHandle userHandle = new UserHandle(UserHandle.getCallingUserId()); - final long id = Binder.clearCallingIdentity(); + final long id = binderClearCallingIdentity(); try { final KeyChainConnection keyChainConnection = KeyChain.bindAsUser(mContext, userHandle); try { @@ -3196,7 +3326,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { Log.w(LOG_TAG, "installCaCertsToKeyChain(): ", e1); Thread.currentThread().interrupt(); } finally { - Binder.restoreCallingIdentity(id); + binderRestoreCallingIdentity(id); } return false; } @@ -3212,7 +3342,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { enforceCanManageCaCerts(admin); final UserHandle userHandle = new UserHandle(UserHandle.getCallingUserId()); - final long id = Binder.clearCallingIdentity(); + final long id = binderClearCallingIdentity(); try { final KeyChainConnection keyChainConnection = KeyChain.bindAsUser(mContext, userHandle); try { @@ -3228,7 +3358,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { Log.w(LOG_TAG, "CaCertUninstaller: ", ie); Thread.currentThread().interrupt(); } finally { - Binder.restoreCallingIdentity(id); + binderRestoreCallingIdentity(id); } } @@ -3244,7 +3374,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { } } final UserHandle userHandle = new UserHandle(UserHandle.getCallingUserId()); - final long id = Binder.clearCallingIdentity(); + final long id = binderClearCallingIdentity(); try { final KeyChainConnection keyChainConnection = KeyChain.bindAsUser(mContext, userHandle); try { @@ -3259,7 +3389,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { Log.w(LOG_TAG, "Interrupted while installing certificate", e); Thread.currentThread().interrupt(); } finally { - Binder.restoreCallingIdentity(id); + binderRestoreCallingIdentity(id); } return false; } @@ -3268,11 +3398,11 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { public void choosePrivateKeyAlias(final int uid, final Uri uri, final String alias, final IBinder response) { // Caller UID needs to be trusted, so we restrict this method to SYSTEM_UID callers. - if (UserHandle.getAppId(Binder.getCallingUid()) != Process.SYSTEM_UID) { + if (UserHandle.getAppId(binderGetCallingUid()) != Process.SYSTEM_UID) { return; } - final UserHandle caller = Binder.getCallingUserHandle(); + final UserHandle caller = binderGetCallingUserHandle(); // If there is a profile owner, redirect to that; otherwise query the device owner. ComponentName aliasChooser = getProfileOwner(caller.getIdentifier()); if (aliasChooser == null && caller.isOwner()) { @@ -3293,7 +3423,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { intent.putExtra(DeviceAdminReceiver.EXTRA_CHOOSE_PRIVATE_KEY_ALIAS, alias); intent.putExtra(DeviceAdminReceiver.EXTRA_CHOOSE_PRIVATE_KEY_RESPONSE, response); - final long id = Binder.clearCallingIdentity(); + final long id = binderClearCallingIdentity(); try { mContext.sendOrderedBroadcastAsUser(intent, caller, null, new BroadcastReceiver() { @Override @@ -3303,7 +3433,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { } }, null, Activity.RESULT_OK, null, null); } finally { - Binder.restoreCallingIdentity(id); + binderRestoreCallingIdentity(id); } } @@ -3372,20 +3502,14 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { final ActiveAdmin admin = getActiveAdminForCallerLocked(null, DeviceAdminInfo.USES_POLICY_WIPE_DATA); - final String source; - final ComponentName cname = admin.info.getComponent(); - if (cname != null) { - source = cname.flattenToShortString(); - } else { - source = admin.info.getPackageName(); - } + final String source = admin.info.getComponent().flattenToShortString(); - long ident = Binder.clearCallingIdentity(); + long ident = binderClearCallingIdentity(); try { if ((flags & WIPE_RESET_PROTECTION_DATA) != 0) { boolean ownsInitialization = isDeviceInitializer(admin.info.getPackageName()) && !hasUserSetupCompleted(userHandle); - if (userHandle != UserHandle.USER_OWNER + if (userHandle != UserHandle.USER_SYSTEM || !(isDeviceOwner(admin.info.getPackageName()) || ownsInitialization)) { throw new SecurityException( @@ -3401,22 +3525,22 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { wipeDeviceOrUserLocked(wipeExtRequested, userHandle, "DevicePolicyManager.wipeData() from " + source); } finally { - Binder.restoreCallingIdentity(ident); + binderRestoreCallingIdentity(ident); } } } private void wipeDeviceOrUserLocked(boolean wipeExtRequested, final int userHandle, String reason) { - if (userHandle == UserHandle.USER_OWNER) { + if (userHandle == UserHandle.USER_SYSTEM) { wipeDataLocked(wipeExtRequested, reason); } else { mHandler.post(new Runnable() { @Override public void run() { try { - IActivityManager am = ActivityManagerNative.getDefault(); + IActivityManager am = getIActivityManager(); if (am.getCurrentUser().id == userHandle) { - am.switchUser(UserHandle.USER_OWNER); + am.switchUser(UserHandle.USER_SYSTEM); } boolean isManagedProfile = isManagedProfile(userHandle); @@ -3442,11 +3566,11 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { .setColor(mContext.getColor(R.color.system_notification_accent_color)) .setStyle(new Notification.BigTextStyle().bigText(contentText)) .build(); - getNotificationManager().notify(PROFILE_WIPED_NOTIFICATION_ID, notification); + mNotificationManager.notify(PROFILE_WIPED_NOTIFICATION_ID, notification); } private void clearWipeProfileNotification() { - getNotificationManager().cancel(PROFILE_WIPED_NOTIFICATION_ID); + mNotificationManager.cancel(PROFILE_WIPED_NOTIFICATION_ID); } @Override @@ -3506,7 +3630,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { || p.mActivePasswordNumeric != numbers || p.mActivePasswordSymbols != symbols || p.mActivePasswordNonLetter != nonletter) { - long ident = Binder.clearCallingIdentity(); + long ident = binderClearCallingIdentity(); try { p.mActivePasswordQuality = quality; p.mActivePasswordLength = length; @@ -3524,7 +3648,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { DeviceAdminReceiver.ACTION_PASSWORD_CHANGED, DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD, userHandle); } finally { - Binder.restoreCallingIdentity(ident); + binderRestoreCallingIdentity(ident); } } } @@ -3560,7 +3684,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { mContext.enforceCallingOrSelfPermission( android.Manifest.permission.BIND_DEVICE_ADMIN, null); - long ident = Binder.clearCallingIdentity(); + long ident = binderClearCallingIdentity(); try { boolean wipeData = false; int identifier = 0; @@ -3591,7 +3715,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { "reportFailedPasswordAttempt()"); } } finally { - Binder.restoreCallingIdentity(ident); + binderRestoreCallingIdentity(ident); } } @@ -3604,7 +3728,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { synchronized (this) { DevicePolicyData policy = getUserData(userHandle); if (policy.mFailedPasswordAttempts != 0 || policy.mPasswordOwner >= 0) { - long ident = Binder.clearCallingIdentity(); + long ident = binderClearCallingIdentity(); try { policy.mFailedPasswordAttempts = 0; policy.mPasswordOwner = -1; @@ -3615,7 +3739,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { DeviceAdminInfo.USES_POLICY_WATCH_LOGIN, userHandle); } } finally { - Binder.restoreCallingIdentity(ident); + binderRestoreCallingIdentity(ident); } } } @@ -3630,8 +3754,8 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { synchronized(this) { Preconditions.checkNotNull(who, "ComponentName is null"); - // Only check if owner has set global proxy. We don't allow other users to set it. - DevicePolicyData policy = getUserData(UserHandle.USER_OWNER); + // Only check if system user has set global proxy. We don't allow other users to set it. + DevicePolicyData policy = getUserData(UserHandle.USER_SYSTEM); ActiveAdmin admin = getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_SETS_GLOBAL_PROXY); @@ -3647,8 +3771,8 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { } } - // If the user is not the owner, don't set the global proxy. Fail silently. - if (UserHandle.getCallingUserId() != UserHandle.USER_OWNER) { + // If the user is not system, don't set the global proxy. Fail silently. + if (UserHandle.getCallingUserId() != UserHandle.USER_SYSTEM) { Slog.w(LOG_TAG, "Only the owner is allowed to set the global proxy. User " + UserHandle.getCallingUserId() + " is not permitted."); return null; @@ -3666,11 +3790,11 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { // Reset the global proxy accordingly // Do this using system permissions, as apps cannot write to secure settings - long origId = Binder.clearCallingIdentity(); + long origId = binderClearCallingIdentity(); try { resetGlobalProxyLocked(policy); } finally { - Binder.restoreCallingIdentity(origId); + binderRestoreCallingIdentity(origId); } return null; } @@ -3683,7 +3807,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { } enforceCrossUserPermission(userHandle); synchronized(this) { - DevicePolicyData policy = getUserData(UserHandle.USER_OWNER); + DevicePolicyData policy = getUserData(UserHandle.USER_SYSTEM); // Scan through active admins and find if anyone has already // set the global proxy. final int N = policy.mAdminList.size(); @@ -3705,13 +3829,13 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { synchronized (this) { getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_DEVICE_OWNER); } - long token = Binder.clearCallingIdentity(); + long token = binderClearCallingIdentity(); try { ConnectivityManager connectivityManager = (ConnectivityManager) mContext.getSystemService(Context.CONNECTIVITY_SERVICE); connectivityManager.setGlobalProxy(proxyInfo); } finally { - Binder.restoreCallingIdentity(token); + binderRestoreCallingIdentity(token); } } @@ -3771,10 +3895,9 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { final int userHandle = UserHandle.getCallingUserId(); synchronized (this) { // Check for permissions - // Only owner can set storage encryption - if (userHandle != UserHandle.USER_OWNER - || UserHandle.getCallingUserId() != UserHandle.USER_OWNER) { - Slog.w(LOG_TAG, "Only owner is allowed to set storage encryption. User " + // Only system user can set storage encryption + if (userHandle != UserHandle.USER_SYSTEM) { + Slog.w(LOG_TAG, "Only owner/system user is allowed to set storage encryption. User " + UserHandle.getCallingUserId() + " is not permitted."); return 0; } @@ -3793,7 +3916,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { saveSettingsLocked(userHandle); } - DevicePolicyData policy = getUserData(UserHandle.USER_OWNER); + DevicePolicyData policy = getUserData(UserHandle.USER_SYSTEM); // (2) Compute "max" for all admins boolean newRequested = false; final int N = policy.mAdminList.size(); @@ -3873,15 +3996,15 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { * {@link DevicePolicyManager#ENCRYPTION_STATUS_ACTIVE}. */ private int getEncryptionStatus() { - String status = SystemProperties.get("ro.crypto.state", "unsupported"); + String status = systemPropertiesGet("ro.crypto.state", "unsupported"); if ("encrypted".equalsIgnoreCase(status)) { - final long token = Binder.clearCallingIdentity(); + final long token = binderClearCallingIdentity(); try { return LockPatternUtils.isDeviceEncrypted() ? DevicePolicyManager.ENCRYPTION_STATUS_ACTIVE : DevicePolicyManager.ENCRYPTION_STATUS_ACTIVE_DEFAULT_KEY; } finally { - Binder.restoreCallingIdentity(token); + binderRestoreCallingIdentity(token); } } else if ("unencrypted".equalsIgnoreCase(status)) { return DevicePolicyManager.ENCRYPTION_STATUS_INACTIVE; @@ -3946,13 +4069,13 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { } private void updateScreenCaptureDisabledInWindowManager(int userHandle, boolean disabled) { - long ident = Binder.clearCallingIdentity(); + long ident = binderClearCallingIdentity(); try { - getWindowManager().setScreenCaptureDisabled(userHandle, disabled); + mIWindowManager.setScreenCaptureDisabled(userHandle, disabled); } catch (RemoteException e) { Log.w(LOG_TAG, "Unable to notify WindowManager.", e); } finally { - Binder.restoreCallingIdentity(ident); + binderRestoreCallingIdentity(ident); } } @@ -3977,12 +4100,12 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { // Turn AUTO_TIME on in settings if it is required if (required) { - long ident = Binder.clearCallingIdentity(); + long ident = binderClearCallingIdentity(); try { Settings.Global.putInt(mContext.getContentResolver(), Settings.Global.AUTO_TIME, 1 /* AUTO_TIME on */); } finally { - Binder.restoreCallingIdentity(ident); + binderRestoreCallingIdentity(ident); } } } @@ -4091,7 +4214,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { return 0; } enforceCrossUserPermission(userHandle); - long ident = Binder.clearCallingIdentity(); + long ident = binderClearCallingIdentity(); try { synchronized (this) { if (who != null) { @@ -4134,7 +4257,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { return which; } } finally { - Binder.restoreCallingIdentity(ident); + binderRestoreCallingIdentity(ident); } } @@ -4152,15 +4275,15 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { enforceCanSetDeviceOwner(userId); // Shutting down backup manager service permanently. - long ident = Binder.clearCallingIdentity(); + long ident = binderClearCallingIdentity(); try { IBackupManager ibm = IBackupManager.Stub.asInterface( ServiceManager.getService(Context.BACKUP_SERVICE)); - ibm.setBackupServiceActive(UserHandle.USER_OWNER, false); + ibm.setBackupServiceActive(UserHandle.USER_SYSTEM, false); } catch (RemoteException e) { throw new IllegalStateException("Failed deactivating backup service.", e); } finally { - Binder.restoreCallingIdentity(ident); + binderRestoreCallingIdentity(ident); } mOwners.setDeviceOwner(packageName, ownerName, userId); @@ -4168,12 +4291,12 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { updateDeviceOwnerLocked(); Intent intent = new Intent(DevicePolicyManager.ACTION_DEVICE_OWNER_CHANGED); - ident = Binder.clearCallingIdentity(); + ident = binderClearCallingIdentity(); try { // TODO Send to system too? mContext.sendBroadcastAsUser(intent, new UserHandle(userId)); } finally { - Binder.restoreCallingIdentity(ident); + binderRestoreCallingIdentity(ident); } return true; } @@ -4211,7 +4334,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { return null; } String deviceOwnerPackage = mOwners.getDeviceOwnerPackageName(); - return getApplicationLabel(deviceOwnerPackage, UserHandle.USER_OWNER); + return getApplicationLabel(deviceOwnerPackage, UserHandle.USER_SYSTEM); } } @@ -4222,7 +4345,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { return null; } - DevicePolicyData policy = getUserData(UserHandle.USER_OWNER); + DevicePolicyData policy = getUserData(UserHandle.USER_SYSTEM); final int n = policy.mAdminList.size(); for (int i = 0; i < n; i++) { ActiveAdmin admin = policy.mAdminList.get(i); @@ -4238,7 +4361,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { Preconditions.checkNotNull(packageName, "packageName is null"); try { int uid = mContext.getPackageManager().getPackageUid(packageName, 0); - if (uid != Binder.getCallingUid()) { + if (uid != binderGetCallingUid()) { throw new SecurityException("Invalid packageName"); } } catch (NameNotFoundException e) { @@ -4248,21 +4371,21 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { throw new SecurityException("clearDeviceOwner can only be called by the device owner"); } synchronized (this) { - clearUserPoliciesLocked(new UserHandle(UserHandle.USER_OWNER)); + clearUserPoliciesLocked(new UserHandle(UserHandle.USER_SYSTEM)); mOwners.clearDeviceOwner(); mOwners.writeDeviceOwner(); updateDeviceOwnerLocked(); // Reactivate backup service. - long ident = Binder.clearCallingIdentity(); + long ident = binderClearCallingIdentity(); try { IBackupManager ibm = IBackupManager.Stub.asInterface( ServiceManager.getService(Context.BACKUP_SERVICE)); - ibm.setBackupServiceActive(UserHandle.USER_OWNER, true); + ibm.setBackupServiceActive(UserHandle.USER_SYSTEM, true); } catch (RemoteException e) { throw new IllegalStateException("Failed reactivating backup service.", e); } finally { - Binder.restoreCallingIdentity(ident); + binderRestoreCallingIdentity(ident); } } } @@ -4281,8 +4404,8 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { } boolean isInitializerSystemApp; try { - isInitializerSystemApp = isSystemApp(AppGlobals.getPackageManager(), - initializer.getPackageName(), Binder.getCallingUserHandle().getIdentifier()); + isInitializerSystemApp = isSystemApp(getIPackageManager(), + initializer.getPackageName(), binderGetCallingUserHandle().getIdentifier()); } catch (RemoteException | IllegalArgumentException e) { isInitializerSystemApp = false; Slog.e(LOG_TAG, "Fail to check if device initialzer is system app.", e); @@ -4365,9 +4488,9 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { ActiveAdmin admin = getActiveAdminUncheckedLocked(who, UserHandle.getCallingUserId()); - if (admin.getUid() != Binder.getCallingUid()) { + if (admin.getUid() != binderGetCallingUid()) { throw new SecurityException("Admin " + who + " is not owned by uid " - + Binder.getCallingUid()); + + binderGetCallingUid()); } if (!isDeviceInitializer(admin.info.getPackageName()) @@ -4376,12 +4499,12 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { "clearDeviceInitializer can only be called by the device initializer/owner"); } synchronized (this) { - long ident = Binder.clearCallingIdentity(); + long ident = binderClearCallingIdentity(); try { mOwners.clearDeviceInitializer(); mOwners.writeDeviceOwner(); } finally { - Binder.restoreCallingIdentity(ident); + binderRestoreCallingIdentity(ident); } } } @@ -4409,7 +4532,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { if (!mHasFeature) { return; } - UserHandle callingUser = Binder.getCallingUserHandle(); + UserHandle callingUser = binderGetCallingUserHandle(); // Check if this is the profile owner who is calling getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER); synchronized (this) { @@ -4429,15 +4552,15 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { policy.mStatusBarDisabled = false; saveSettingsLocked(userId); - final long ident = Binder.clearCallingIdentity(); + final long ident = binderClearCallingIdentity(); try { clearUserRestrictions(userHandle); - AppGlobals.getPackageManager().updatePermissionFlagsForAllApps( + getIPackageManager().updatePermissionFlagsForAllApps( PackageManager.FLAG_PERMISSION_POLICY_FIXED, 0 /* flagValues */, userHandle.getIdentifier()); } catch (RemoteException re) { } finally { - Binder.restoreCallingIdentity(ident); + binderRestoreCallingIdentity(ident); } } @@ -4497,10 +4620,10 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { "This method can only be called by device initializers"); } - long id = Binder.clearCallingIdentity(); + long id = binderClearCallingIdentity(); try { if (!isDeviceOwner(activeAdmin.info.getPackageName())) { - IPackageManager ipm = AppGlobals.getPackageManager(); + IPackageManager ipm = getIPackageManager(); ipm.setComponentEnabledSetting(who, PackageManager.COMPONENT_ENABLED_STATE_DISABLED, PackageManager.DONT_KILL_APP, userId); @@ -4508,7 +4631,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { removeActiveAdmin(who, userId); } - if (userId == UserHandle.USER_OWNER) { + if (userId == UserHandle.USER_SYSTEM) { Settings.Global.putInt(mContext.getContentResolver(), Settings.Global.DEVICE_PROVISIONED, 1); } @@ -4518,7 +4641,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { Log.i(LOG_TAG, "Can't talk to package manager", e); return false; } finally { - restoreCallingIdentity(id); + binderRestoreCallingIdentity(id); } return true; } @@ -4536,7 +4659,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER); int userId = UserHandle.getCallingUserId(); - long id = Binder.clearCallingIdentity(); + long id = binderClearCallingIdentity(); try { mUserManager.setUserEnabled(userId); UserInfo parent = mUserManager.getProfileParent(userId); @@ -4546,7 +4669,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { Intent.FLAG_RECEIVER_FOREGROUND); mContext.sendBroadcastAsUser(intent, new UserHandle(parent.id)); } finally { - restoreCallingIdentity(id); + binderRestoreCallingIdentity(id); } } } @@ -4558,11 +4681,11 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { // Check if this is the profile owner (includes device owner). getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER); - long id = Binder.clearCallingIdentity(); + long id = binderClearCallingIdentity(); try { mUserManager.setUserName(userId, profileName); } finally { - restoreCallingIdentity(id); + binderRestoreCallingIdentity(id); } } @@ -4612,7 +4735,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { * Canonical name for a given package. */ private String getApplicationLabel(String packageName, int userHandle) { - long token = Binder.clearCallingIdentity(); + long token = binderClearCallingIdentity(); try { final Context userContext; try { @@ -4630,7 +4753,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { } return result != null ? result.toString() : null; } finally { - Binder.restoreCallingIdentity(token); + binderRestoreCallingIdentity(token); } } @@ -4656,7 +4779,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { throw new IllegalStateException("Trying to set the profile owner, but profile owner " + "is already set."); } - int callingUid = Binder.getCallingUid(); + int callingUid = binderGetCallingUid(); if (callingUid == Process.SHELL_UID || callingUid == Process.ROOT_UID) { if (hasUserSetupCompleted(userHandle) && AccountManager.get(mContext).getAccountsAsUser(userHandle).length > 0) { @@ -4689,9 +4812,9 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { throw new IllegalStateException("User not running: " + userId); } - int callingUid = Binder.getCallingUid(); + int callingUid = binderGetCallingUid(); if (callingUid == Process.SHELL_UID || callingUid == Process.ROOT_UID) { - if (!hasUserSetupCompleted(UserHandle.USER_OWNER)) { + if (!hasUserSetupCompleted(UserHandle.USER_SYSTEM)) { return; } // STOPSHIP Do proper check in split user mode @@ -4715,7 +4838,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { android.Manifest.permission.MANAGE_PROFILE_AND_DEVICE_OWNERS, null); // STOPSHIP Do proper check in split user mode if (!UserManager.isSplitSystemUser()) { - if (hasUserSetupCompleted(UserHandle.USER_OWNER)) { + if (hasUserSetupCompleted(UserHandle.USER_SYSTEM)) { throw new IllegalStateException("Cannot set the device owner if the device is " + "already set-up"); } @@ -4726,7 +4849,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { if (userHandle < 0) { throw new IllegalArgumentException("Invalid userId " + userHandle); } - final int callingUid = Binder.getCallingUid(); + final int callingUid = binderGetCallingUid(); if (userHandle == UserHandle.getUserId(callingUid)) return; if (callingUid != Process.SYSTEM_UID && callingUid != 0) { mContext.enforceCallingOrSelfPermission( @@ -4742,26 +4865,26 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { } private UserInfo getProfileParent(int userHandle) { - long ident = Binder.clearCallingIdentity(); + long ident = binderClearCallingIdentity(); try { return mUserManager.getProfileParent(userHandle); } finally { - Binder.restoreCallingIdentity(ident); + binderRestoreCallingIdentity(ident); } } private boolean isManagedProfile(int userHandle) { - long ident = Binder.clearCallingIdentity(); + long ident = binderClearCallingIdentity(); try { return mUserManager.getUserInfo(userHandle).isManagedProfile(); } finally { - Binder.restoreCallingIdentity(ident); + binderRestoreCallingIdentity(ident); } } private void enableIfNecessary(String packageName, int userId) { try { - IPackageManager ipm = AppGlobals.getPackageManager(); + IPackageManager ipm = getIPackageManager(); ApplicationInfo ai = ipm.getApplicationInfo(packageName, PackageManager.GET_DISABLED_UNTIL_USED_COMPONENTS, userId); @@ -4781,8 +4904,8 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { != PackageManager.PERMISSION_GRANTED) { pw.println("Permission Denial: can't dump DevicePolicyManagerService from from pid=" - + Binder.getCallingPid() - + ", uid=" + Binder.getCallingUid()); + + binderGetCallingPid() + + ", uid=" + binderGetCallingUid()); return; } @@ -4823,14 +4946,14 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { synchronized (this) { getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER); - IPackageManager pm = AppGlobals.getPackageManager(); - long id = Binder.clearCallingIdentity(); + IPackageManager pm = getIPackageManager(); + long id = binderClearCallingIdentity(); try { pm.addPersistentPreferredActivity(filter, activity, userHandle); } catch (RemoteException re) { // Shouldn't happen } finally { - restoreCallingIdentity(id); + binderRestoreCallingIdentity(id); } } } @@ -4842,14 +4965,14 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { synchronized (this) { getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER); - IPackageManager pm = AppGlobals.getPackageManager(); - long id = Binder.clearCallingIdentity(); + IPackageManager pm = getIPackageManager(); + long id = binderClearCallingIdentity(); try { pm.clearPackagePersistentPreferredActivities(packageName, userHandle); } catch (RemoteException re) { // Shouldn't happen } finally { - restoreCallingIdentity(id); + binderRestoreCallingIdentity(id); } } } @@ -4861,11 +4984,11 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { synchronized (this) { getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER); - long id = Binder.clearCallingIdentity(); + long id = binderClearCallingIdentity(); try { mUserManager.setApplicationRestrictions(packageName, settings, userHandle); } finally { - restoreCallingIdentity(id); + binderRestoreCallingIdentity(id); } } } @@ -4963,7 +5086,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { @Override public ComponentName getRestrictionsProvider(int userHandle) { synchronized (this) { - if (Binder.getCallingUid() != Process.SYSTEM_UID) { + if (binderGetCallingUid() != Process.SYSTEM_UID) { throw new SecurityException("Only the system can query the permission provider"); } DevicePolicyData userData = getUserData(userHandle); @@ -4978,8 +5101,8 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { synchronized (this) { getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER); - IPackageManager pm = AppGlobals.getPackageManager(); - long id = Binder.clearCallingIdentity(); + IPackageManager pm = getIPackageManager(); + long id = binderClearCallingIdentity(); try { UserInfo parent = mUserManager.getProfileParent(callingUserId); if (parent == null) { @@ -4998,7 +5121,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { } catch (RemoteException re) { // Shouldn't happen } finally { - restoreCallingIdentity(id); + binderRestoreCallingIdentity(id); } } } @@ -5009,8 +5132,8 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { int callingUserId = UserHandle.getCallingUserId(); synchronized (this) { getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER); - IPackageManager pm = AppGlobals.getPackageManager(); - long id = Binder.clearCallingIdentity(); + IPackageManager pm = getIPackageManager(); + long id = binderClearCallingIdentity(); try { UserInfo parent = mUserManager.getProfileParent(callingUserId); if (parent == null) { @@ -5027,7 +5150,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { } catch (RemoteException re) { // Shouldn't happen } finally { - restoreCallingIdentity(id); + binderRestoreCallingIdentity(id); } } } @@ -5039,7 +5162,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { private boolean checkPackagesInPermittedListOrSystem(List<String> enabledPackages, List<String> permittedList) { int userIdToCheck = UserHandle.getCallingUserId(); - long id = Binder.clearCallingIdentity(); + long id = binderClearCallingIdentity(); try { // If we have an enabled packages list for a managed profile the packages // we should check are installed for the parent user. @@ -5048,7 +5171,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { userIdToCheck = user.profileGroupId; } - IPackageManager pm = AppGlobals.getPackageManager(); + IPackageManager pm = getIPackageManager(); for (String enabledPackage : enabledPackages) { boolean systemService = false; try { @@ -5063,7 +5186,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { } } } finally { - restoreCallingIdentity(id); + binderRestoreCallingIdentity(id); } return true; } @@ -5088,7 +5211,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { if (packageList != null) { int userId = UserHandle.getCallingUserId(); List<AccessibilityServiceInfo> enabledServices = null; - long id = Binder.clearCallingIdentity(); + long id = binderClearCallingIdentity(); try { UserInfo user = mUserManager.getUserInfo(userId); if (user.isManagedProfile()) { @@ -5098,7 +5221,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { enabledServices = accessibilityManager.getEnabledAccessibilityServiceList( AccessibilityServiceInfo.FEEDBACK_ALL_MASK); } finally { - restoreCallingIdentity(id); + binderRestoreCallingIdentity(id); } if (enabledServices != null) { @@ -5169,7 +5292,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { // If we have a permitted list add all system accessibility services. if (result != null) { - long id = Binder.clearCallingIdentity(); + long id = binderClearCallingIdentity(); try { UserInfo user = mUserManager.getUserInfo(userId); if (user.isManagedProfile()) { @@ -5180,7 +5303,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { List<AccessibilityServiceInfo> installedServices = accessibilityManager.getInstalledAccessibilityServiceList(); - IPackageManager pm = AppGlobals.getPackageManager(); + IPackageManager pm = getIPackageManager(); if (installedServices != null) { for (AccessibilityServiceInfo service : installedServices) { ServiceInfo serviceInfo = service.getResolveInfo().serviceInfo; @@ -5191,7 +5314,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { } } } finally { - restoreCallingIdentity(id); + binderRestoreCallingIdentity(id); } } @@ -5201,12 +5324,12 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { private boolean checkCallerIsCurrentUserOrProfile() { int callingUserId = UserHandle.getCallingUserId(); - long token = Binder.clearCallingIdentity(); + long token = binderClearCallingIdentity(); try { UserInfo currentUser; UserInfo callingUser = mUserManager.getUserInfo(callingUserId); try { - currentUser = ActivityManagerNative.getDefault().getCurrentUser(); + currentUser = getIActivityManager().getCurrentUser(); } catch (RemoteException e) { Slog.e(LOG_TAG, "Failed to talk to activity managed.", e); return false; @@ -5223,7 +5346,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { return false; } } finally { - Binder.restoreCallingIdentity(token); + binderRestoreCallingIdentity(token); } return true; } @@ -5289,7 +5412,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { public List getPermittedInputMethodsForCurrentUser() { UserInfo currentUser; try { - currentUser = ActivityManagerNative.getDefault().getCurrentUser(); + currentUser = getIActivityManager().getCurrentUser(); } catch (RemoteException e) { Slog.e(LOG_TAG, "Failed to make remote calls to get current user", e); // Activity managed is dead, just allow all IMEs @@ -5327,9 +5450,9 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { InputMethodManager inputMethodManager = (InputMethodManager) mContext .getSystemService(Context.INPUT_METHOD_SERVICE); List<InputMethodInfo> imes = inputMethodManager.getInputMethodList(); - long id = Binder.clearCallingIdentity(); + long id = binderClearCallingIdentity(); try { - IPackageManager pm = AppGlobals.getPackageManager(); + IPackageManager pm = getIPackageManager(); if (imes != null) { for (InputMethodInfo ime : imes) { ServiceInfo serviceInfo = ime.getServiceInfo(); @@ -5340,7 +5463,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { } } } finally { - restoreCallingIdentity(id); + binderRestoreCallingIdentity(id); } } return result; @@ -5353,7 +5476,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { synchronized (this) { getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_DEVICE_OWNER); - long id = Binder.clearCallingIdentity(); + long id = binderClearCallingIdentity(); try { UserInfo userInfo = mUserManager.createUser(name, 0 /* flags */); if (userInfo != null) { @@ -5361,7 +5484,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { } return null; } finally { - restoreCallingIdentity(id); + binderRestoreCallingIdentity(id); } } } @@ -5373,11 +5496,11 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { if (user == null) { return null; } - long id = Binder.clearCallingIdentity(); + long id = binderClearCallingIdentity(); try { String profileOwnerPkg = profileOwnerComponent.getPackageName(); - final IPackageManager ipm = AppGlobals.getPackageManager(); - IActivityManager activityManager = ActivityManagerNative.getDefault(); + final IPackageManager ipm = getIPackageManager(); + IActivityManager activityManager = getIActivityManager(); final int userHandle = user.getIdentifier(); try { @@ -5396,7 +5519,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { setProfileOwner(profileOwnerComponent, ownerName, userHandle); return user; } finally { - restoreCallingIdentity(id); + binderRestoreCallingIdentity(id); } } @@ -5406,11 +5529,11 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { synchronized (this) { getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_DEVICE_OWNER); - long id = Binder.clearCallingIdentity(); + long id = binderClearCallingIdentity(); try { return mUserManager.removeUser(userHandle.getIdentifier()); } finally { - restoreCallingIdentity(id); + binderRestoreCallingIdentity(id); } } } @@ -5421,18 +5544,18 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { synchronized (this) { getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_DEVICE_OWNER); - long id = Binder.clearCallingIdentity(); + long id = binderClearCallingIdentity(); try { - int userId = UserHandle.USER_OWNER; + int userId = UserHandle.USER_SYSTEM; if (userHandle != null) { userId = userHandle.getIdentifier(); } - return ActivityManagerNative.getDefault().switchUser(userId); + return getIActivityManager().switchUser(userId); } catch (RemoteException e) { Log.e(LOG_TAG, "Couldn't switch user", e); return false; } finally { - restoreCallingIdentity(id); + binderRestoreCallingIdentity(id); } } } @@ -5445,14 +5568,14 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { synchronized (this) { getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER); - long id = Binder.clearCallingIdentity(); + long id = binderClearCallingIdentity(); try { Bundle bundle = mUserManager.getApplicationRestrictions(packageName, userHandle); // if no restrictions were saved, mUserManager.getApplicationRestrictions // returns null, but DPM method should return an empty Bundle as per JavaDoc return bundle != null ? bundle : Bundle.EMPTY; } finally { - restoreCallingIdentity(id); + binderRestoreCallingIdentity(id); } } } @@ -5460,13 +5583,13 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { @Override public void setUserRestriction(ComponentName who, String key, boolean enabled) { Preconditions.checkNotNull(who, "ComponentName is null"); - final UserHandle user = new UserHandle(UserHandle.getCallingUserId()); - final int userHandle = user.getIdentifier(); + final int userHandle = UserHandle.getCallingUserId(); + final UserHandle user = new UserHandle(userHandle); synchronized (this) { ActiveAdmin activeAdmin = getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER); boolean isDeviceOwner = isDeviceOwner(activeAdmin.info.getPackageName()); - if (!isDeviceOwner && userHandle != UserHandle.USER_OWNER + if (!isDeviceOwner && userHandle != UserHandle.USER_SYSTEM && DEVICE_OWNER_USER_RESTRICTIONS.contains(key)) { throw new SecurityException("Profile owners cannot set user restriction " + key); } @@ -5482,7 +5605,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { ServiceManager.getService(Context.AUDIO_SERVICE)); } - long id = Binder.clearCallingIdentity(); + long id = binderClearCallingIdentity(); try { if (enabled && !alreadyRestricted) { if (UserManager.DISALLOW_UNMUTE_MICROPHONE.equals(key)) { @@ -5491,8 +5614,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { } else if (UserManager.DISALLOW_ADJUST_VOLUME.equals(key)) { iAudioService.setMasterMute(true, 0, mContext.getPackageName(), userHandle); - } - if (UserManager.DISALLOW_CONFIG_WIFI.equals(key)) { + } else if (UserManager.DISALLOW_CONFIG_WIFI.equals(key)) { Settings.Secure.putIntForUser(mContext.getContentResolver(), Settings.Secure.WIFI_NETWORKS_AVAILABLE_NOTIFICATION_ON, 0, userHandle); @@ -5504,8 +5626,9 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { Settings.Secure.LOCATION_PROVIDERS_ALLOWED, "", userHandle); } else if (UserManager.DISALLOW_DEBUGGING_FEATURES.equals(key)) { - // Only disable adb if changing for primary user, since it is global - if (userHandle == UserHandle.USER_OWNER) { + // Only disable adb if changing for system user, since it is global + // TODO: should this be admin user? + if (userHandle == UserHandle.USER_SYSTEM) { Settings.Global.putStringForUser(mContext.getContentResolver(), Settings.Global.ADB_ENABLED, "0", userHandle); } @@ -5528,8 +5651,8 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { // Send out notifications however as some clients may want to reread the // value which actually changed due to a restriction having been applied. final String property = Settings.Secure.SYS_PROP_SETTING_VERSION; - long version = SystemProperties.getLong(property, 0) + 1; - SystemProperties.set(property, Long.toString(version)); + long version = systemPropertiesGetLong(property, 0) + 1; + systemPropertiesSet(property, Long.toString(version)); final String name = Settings.Secure.LOCATION_PROVIDERS_ALLOWED; Uri url = Uri.withAppendedPath(Settings.Secure.CONTENT_URI, name); @@ -5548,7 +5671,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { } catch (RemoteException re) { Slog.e(LOG_TAG, "Failed to talk to AudioService.", re); } finally { - restoreCallingIdentity(id); + binderRestoreCallingIdentity(id); } sendChangedNotification(userHandle); } @@ -5562,15 +5685,15 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { synchronized (this) { getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER); - long id = Binder.clearCallingIdentity(); + long id = binderClearCallingIdentity(); try { - IPackageManager pm = AppGlobals.getPackageManager(); + IPackageManager pm = getIPackageManager(); return pm.setApplicationHiddenSettingAsUser(packageName, hidden, callingUserId); } catch (RemoteException re) { // shouldn't happen Slog.e(LOG_TAG, "Failed to setApplicationHiddenSetting", re); } finally { - restoreCallingIdentity(id); + binderRestoreCallingIdentity(id); } return false; } @@ -5583,15 +5706,15 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { synchronized (this) { getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER); - long id = Binder.clearCallingIdentity(); + long id = binderClearCallingIdentity(); try { - IPackageManager pm = AppGlobals.getPackageManager(); + IPackageManager pm = getIPackageManager(); return pm.getApplicationHiddenSettingAsUser(packageName, callingUserId); } catch (RemoteException re) { // shouldn't happen Slog.e(LOG_TAG, "Failed to getApplicationHiddenSettingAsUser", re); } finally { - restoreCallingIdentity(id); + binderRestoreCallingIdentity(id); } return false; } @@ -5606,7 +5729,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER); int userId = UserHandle.getCallingUserId(); - long id = Binder.clearCallingIdentity(); + long id = binderClearCallingIdentity(); try { if (DBG) { @@ -5622,7 +5745,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { primaryUser = um.getUserInfo(userId); } - IPackageManager pm = AppGlobals.getPackageManager(); + IPackageManager pm = getIPackageManager(); if (!isSystemApp(pm, packageName, primaryUser.id)) { throw new IllegalArgumentException("Only system apps can be enabled this way."); } @@ -5634,7 +5757,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { // shouldn't happen Slog.wtf(LOG_TAG, "Failed to install " + packageName, re); } finally { - restoreCallingIdentity(id); + binderRestoreCallingIdentity(id); } } } @@ -5648,7 +5771,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER); int userId = UserHandle.getCallingUserId(); - long id = Binder.clearCallingIdentity(); + long id = binderClearCallingIdentity(); try { UserManager um = UserManager.get(mContext); @@ -5659,7 +5782,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { primaryUser = um.getUserInfo(userId); } - IPackageManager pm = AppGlobals.getPackageManager(); + IPackageManager pm = getIPackageManager(); List<ResolveInfo> activitiesToEnable = pm.queryIntentActivities(intent, intent.resolveTypeIfNeeded(mContext.getContentResolver()), 0, // no flags @@ -5687,7 +5810,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { Slog.wtf(LOG_TAG, "Failed to resolve intent for: " + intent); return 0; } finally { - restoreCallingIdentity(id); + binderRestoreCallingIdentity(id); } } } @@ -5753,15 +5876,15 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { synchronized (this) { getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER); - long id = Binder.clearCallingIdentity(); + long id = binderClearCallingIdentity(); try { - IPackageManager pm = AppGlobals.getPackageManager(); + IPackageManager pm = getIPackageManager(); pm.setBlockUninstallForUser(packageName, uninstallBlocked, userId); } catch (RemoteException re) { // Shouldn't happen. Slog.e(LOG_TAG, "Failed to setBlockUninstallForUser", re); } finally { - restoreCallingIdentity(id); + binderRestoreCallingIdentity(id); } } } @@ -5778,15 +5901,15 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER); } - long id = Binder.clearCallingIdentity(); + long id = binderClearCallingIdentity(); try { - IPackageManager pm = AppGlobals.getPackageManager(); + IPackageManager pm = getIPackageManager(); return pm.getBlockUninstallForUser(packageName, userId); } catch (RemoteException re) { // Shouldn't happen. Slog.e(LOG_TAG, "Failed to getBlockUninstallForUser", re); } finally { - restoreCallingIdentity(id); + binderRestoreCallingIdentity(id); } } return false; @@ -5838,7 +5961,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { actualLookupKey, actualContactId, originalIntent); final int callingUserId = UserHandle.getCallingUserId(); - final long ident = Binder.clearCallingIdentity(); + final long ident = binderClearCallingIdentity(); try { synchronized (this) { final int managedUserId = getManagedUserId(callingUserId); @@ -5856,7 +5979,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { mContext, intent, new UserHandle(managedUserId)); } } finally { - Binder.restoreCallingIdentity(ident); + binderRestoreCallingIdentity(ident); } } @@ -5937,7 +6060,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { synchronized (this) { getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_DEVICE_OWNER); - int userHandle = Binder.getCallingUserHandle().getIdentifier(); + int userHandle = binderGetCallingUserHandle().getIdentifier(); setLockTaskPackagesLocked(userHandle, new ArrayList<>(Arrays.asList(packages))); } } @@ -5959,7 +6082,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { Preconditions.checkNotNull(who, "ComponentName is null"); synchronized (this) { getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_DEVICE_OWNER); - int userHandle = Binder.getCallingUserHandle().getIdentifier(); + int userHandle = binderGetCallingUserHandle().getIdentifier(); final List<String> packages = getLockTaskPackagesLocked(userHandle); return packages.toArray(new String[packages.size()]); } @@ -5978,7 +6101,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { @Override public boolean isLockTaskPermitted(String pkg) { // Get current user's devicepolicy - int uid = Binder.getCallingUid(); + int uid = binderGetCallingUid(); int userHandle = UserHandle.getUserId(uid); DevicePolicyData policy = getUserData(userHandle); synchronized (this) { @@ -5997,7 +6120,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { @Override public void notifyLockTaskModeChanged(boolean isEnabled, String pkg, int userHandle) { - if (Binder.getCallingUid() != Process.SYSTEM_UID) { + if (binderGetCallingUid() != Process.SYSTEM_UID) { throw new SecurityException("notifyLockTaskModeChanged can only be called by system"); } synchronized (this) { @@ -6048,11 +6171,11 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { } } - long id = Binder.clearCallingIdentity(); + long id = binderClearCallingIdentity(); try { Settings.Global.putString(contentResolver, setting, value); } finally { - restoreCallingIdentity(id); + binderRestoreCallingIdentity(id); } } } @@ -6077,11 +6200,11 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { "Permission denial: Profile owners cannot update %1$s", setting)); } - long id = Binder.clearCallingIdentity(); + long id = binderClearCallingIdentity(); try { Settings.Secure.putStringForUser(contentResolver, setting, value, callingUserId); } finally { - restoreCallingIdentity(id); + binderRestoreCallingIdentity(id); } } } @@ -6092,7 +6215,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { synchronized (this) { getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER); int userId = UserHandle.getCallingUserId(); - long identity = Binder.clearCallingIdentity(); + long identity = binderClearCallingIdentity(); try { IAudioService iAudioService = IAudioService.Stub.asInterface( ServiceManager.getService(Context.AUDIO_SERVICE)); @@ -6100,7 +6223,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { } catch (RemoteException re) { Slog.e(LOG_TAG, "Failed to setMasterMute", re); } finally { - Binder.restoreCallingIdentity(identity); + binderRestoreCallingIdentity(identity); } } } @@ -6124,11 +6247,11 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER); int userId = UserHandle.getCallingUserId(); - long id = Binder.clearCallingIdentity(); + long id = binderClearCallingIdentity(); try { mUserManager.setUserIcon(userId, icon); } finally { - restoreCallingIdentity(id); + binderRestoreCallingIdentity(id); } } } @@ -6142,7 +6265,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { final int userId = UserHandle.getCallingUserId(); LockPatternUtils utils = new LockPatternUtils(mContext); - long ident = Binder.clearCallingIdentity(); + long ident = binderClearCallingIdentity(); try { // disallow disabling the keyguard if a password is currently set if (disabled && utils.isSecure(userId)) { @@ -6150,7 +6273,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { } utils.setLockScreenDisabled(disabled, userId); } finally { - Binder.restoreCallingIdentity(ident); + binderRestoreCallingIdentity(ident); } return true; } @@ -6173,7 +6296,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { } private boolean setStatusBarDisabledInternal(boolean disabled, int userId) { - long ident = Binder.clearCallingIdentity(); + long ident = binderClearCallingIdentity(); try { IStatusBarService statusBarService = IStatusBarService.Stub.asInterface( ServiceManager.checkService(Context.STATUS_BAR_SERVICE)); @@ -6187,7 +6310,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { } catch (RemoteException e) { Slog.e(LOG_TAG, "Failed to disable the status bar", e); } finally { - Binder.restoreCallingIdentity(ident); + binderRestoreCallingIdentity(ident); } return false; } @@ -6394,8 +6517,8 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { mContext.enforceCallingOrSelfPermission(permission.NOTIFY_PENDING_SYSTEM_UPDATE, "Only the system update service can broadcast update information"); - if (UserHandle.getCallingUserId() != UserHandle.USER_OWNER) { - Slog.w(LOG_TAG, "Only the system update service in the primary user " + + if (UserHandle.getCallingUserId() != UserHandle.USER_SYSTEM) { + Slog.w(LOG_TAG, "Only the system update service in the system user " + "can broadcast update information."); return; } @@ -6418,7 +6541,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { Log.e(LOG_TAG, "Cannot find device owner package", e); } if (receivers != null) { - long ident = Binder.clearCallingIdentity(); + long ident = binderClearCallingIdentity(); try { for (int i = 0; i < receivers.length; i++) { if (permission.BIND_DEVICE_ADMIN.equals(receivers[i].permission)) { @@ -6428,7 +6551,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { } } } finally { - Binder.restoreCallingIdentity(ident); + binderRestoreCallingIdentity(ident); } } } @@ -6459,12 +6582,12 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { @Override public boolean setPermissionGrantState(ComponentName admin, String packageName, String permission, int grantState) throws RemoteException { - UserHandle user = Binder.getCallingUserHandle(); + UserHandle user = binderGetCallingUserHandle(); synchronized (this) { getActiveAdminForCallerLocked(admin, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER); - long ident = Binder.clearCallingIdentity(); + long ident = binderClearCallingIdentity(); try { - final ApplicationInfo ai = AppGlobals.getPackageManager() + final ApplicationInfo ai = getIPackageManager() .getApplicationInfo(packageName, 0, user.getIdentifier()); final int targetSdkVersion = ai == null ? 0 : ai.targetSdkVersion; if (targetSdkVersion < android.os.Build.VERSION_CODES.M) { @@ -6496,7 +6619,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { } catch (SecurityException se) { return false; } finally { - Binder.restoreCallingIdentity(ident); + binderRestoreCallingIdentity(ident); } } } @@ -6506,12 +6629,12 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { String permission) throws RemoteException { PackageManager packageManager = mContext.getPackageManager(); - UserHandle user = Binder.getCallingUserHandle(); + UserHandle user = binderGetCallingUserHandle(); synchronized (this) { getActiveAdminForCallerLocked(admin, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER); - long ident = Binder.clearCallingIdentity(); + long ident = binderClearCallingIdentity(); try { - int granted = AppGlobals.getPackageManager().checkPermission(permission, + int granted = getIPackageManager().checkPermission(permission, packageName, user.getIdentifier()); int permFlags = packageManager.getPermissionFlags(permission, packageName, user); if ((permFlags & PackageManager.FLAG_PERMISSION_POLICY_FIXED) @@ -6525,7 +6648,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { : DevicePolicyManager.PERMISSION_GRANT_STATE_DENIED; } } finally { - Binder.restoreCallingIdentity(ident); + binderRestoreCallingIdentity(ident); } } } diff --git a/services/midi/java/com/android/server/midi/MidiService.java b/services/midi/java/com/android/server/midi/MidiService.java index f6de12dbf6cb..c6d5a7e268b7 100644 --- a/services/midi/java/com/android/server/midi/MidiService.java +++ b/services/midi/java/com/android/server/midi/MidiService.java @@ -588,6 +588,8 @@ public class MidiService extends IMidiManager.Stub { Client client = getClient(token); if (client == null) return; client.addListener(listener); + // Let listener know whether any ports are already busy. + updateStickyDeviceStatus(client.mUid, listener); } @Override @@ -597,6 +599,25 @@ public class MidiService extends IMidiManager.Stub { client.removeListener(listener); } + // Inform listener of the status of all known devices. + private void updateStickyDeviceStatus(int uid, IMidiDeviceListener listener) { + synchronized (mDevicesByInfo) { + for (Device device : mDevicesByInfo.values()) { + // ignore private devices that our client cannot access + if (device.isUidAllowed(uid)) { + try { + MidiDeviceStatus status = device.getDeviceStatus(); + if (status != null) { + listener.onDeviceStatusChanged(status); + } + } catch (RemoteException e) { + Log.e(TAG, "remote exception", e); + } + } + } + } + } + private static final MidiDeviceInfo[] EMPTY_DEVICE_INFO_ARRAY = new MidiDeviceInfo[0]; public MidiDeviceInfo[] getDevices() { diff --git a/core/java/android/net/IpReachabilityMonitor.java b/services/net/java/android/net/ip/IpReachabilityMonitor.java index 2283004c7759..3acd56560f4a 100644 --- a/core/java/android/net/IpReachabilityMonitor.java +++ b/services/net/java/android/net/ip/IpReachabilityMonitor.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package android.net; +package android.net.ip; import com.android.internal.annotations.GuardedBy; diff --git a/core/java/android/net/netlink/NetlinkConstants.java b/services/net/java/android/net/netlink/NetlinkConstants.java index e331701efbce..e331701efbce 100644 --- a/core/java/android/net/netlink/NetlinkConstants.java +++ b/services/net/java/android/net/netlink/NetlinkConstants.java diff --git a/core/java/android/net/netlink/NetlinkErrorMessage.java b/services/net/java/android/net/netlink/NetlinkErrorMessage.java index e2755740453a..e2755740453a 100644 --- a/core/java/android/net/netlink/NetlinkErrorMessage.java +++ b/services/net/java/android/net/netlink/NetlinkErrorMessage.java diff --git a/core/java/android/net/netlink/NetlinkMessage.java b/services/net/java/android/net/netlink/NetlinkMessage.java index 3bf75cabea17..3bf75cabea17 100644 --- a/core/java/android/net/netlink/NetlinkMessage.java +++ b/services/net/java/android/net/netlink/NetlinkMessage.java diff --git a/core/java/android/net/netlink/NetlinkSocket.java b/services/net/java/android/net/netlink/NetlinkSocket.java index 657d48c15250..657d48c15250 100644 --- a/core/java/android/net/netlink/NetlinkSocket.java +++ b/services/net/java/android/net/netlink/NetlinkSocket.java diff --git a/core/java/android/net/netlink/RtNetlinkNeighborMessage.java b/services/net/java/android/net/netlink/RtNetlinkNeighborMessage.java index 02df1313c43f..02df1313c43f 100644 --- a/core/java/android/net/netlink/RtNetlinkNeighborMessage.java +++ b/services/net/java/android/net/netlink/RtNetlinkNeighborMessage.java diff --git a/core/java/android/net/netlink/StructNdMsg.java b/services/net/java/android/net/netlink/StructNdMsg.java index b68ec0bc6226..b68ec0bc6226 100644 --- a/core/java/android/net/netlink/StructNdMsg.java +++ b/services/net/java/android/net/netlink/StructNdMsg.java diff --git a/core/java/android/net/netlink/StructNdaCacheInfo.java b/services/net/java/android/net/netlink/StructNdaCacheInfo.java index 16cf56385eb8..16cf56385eb8 100644 --- a/core/java/android/net/netlink/StructNdaCacheInfo.java +++ b/services/net/java/android/net/netlink/StructNdaCacheInfo.java diff --git a/core/java/android/net/netlink/StructNlAttr.java b/services/net/java/android/net/netlink/StructNlAttr.java index 597a6aa1c9eb..597a6aa1c9eb 100644 --- a/core/java/android/net/netlink/StructNlAttr.java +++ b/services/net/java/android/net/netlink/StructNlAttr.java diff --git a/core/java/android/net/netlink/StructNlMsgErr.java b/services/net/java/android/net/netlink/StructNlMsgErr.java index f095af43c743..f095af43c743 100644 --- a/core/java/android/net/netlink/StructNlMsgErr.java +++ b/services/net/java/android/net/netlink/StructNlMsgErr.java diff --git a/core/java/android/net/netlink/StructNlMsgHdr.java b/services/net/java/android/net/netlink/StructNlMsgHdr.java index 98ab5e719d69..98ab5e719d69 100644 --- a/core/java/android/net/netlink/StructNlMsgHdr.java +++ b/services/net/java/android/net/netlink/StructNlMsgHdr.java diff --git a/services/tests/servicestests/AndroidManifest.xml b/services/tests/servicestests/AndroidManifest.xml index 7d1282bceac9..c147bccc19b5 100644 --- a/services/tests/servicestests/AndroidManifest.xml +++ b/services/tests/servicestests/AndroidManifest.xml @@ -67,6 +67,33 @@ </intent-filter> </receiver> + <receiver android:name="com.android.server.devicepolicy.DummyDeviceAdmins$Admin1" + android:permission="android.permission.BIND_DEVICE_ADMIN"> + <meta-data android:name="android.app.device_admin" + android:resource="@xml/device_admin_sample" /> + <intent-filter> + <action android:name="android.app.action.DEVICE_ADMIN_ENABLED" /> + </intent-filter> + </receiver> + + <receiver android:name="com.android.server.devicepolicy.DummyDeviceAdmins$Admin2" + android:permission="android.permission.BIND_DEVICE_ADMIN"> + <meta-data android:name="android.app.device_admin" + android:resource="@xml/device_admin_sample" /> + <intent-filter> + <action android:name="android.app.action.DEVICE_ADMIN_ENABLED" /> + </intent-filter> + </receiver> + + <receiver android:name="com.android.server.devicepolicy.DummyDeviceAdmins$Admin3" + android:permission="android.permission.BIND_DEVICE_ADMIN"> + <meta-data android:name="android.app.device_admin" + android:resource="@xml/device_admin_sample" /> + <intent-filter> + <action android:name="android.app.action.DEVICE_ADMIN_ENABLED" /> + </intent-filter> + </receiver> + </application> <instrumentation diff --git a/core/tests/coretests/src/android/net/netlink/NetlinkErrorMessageTest.java b/services/tests/servicestests/src/android/net/netlink/NetlinkErrorMessageTest.java index e677475f5907..e677475f5907 100644 --- a/core/tests/coretests/src/android/net/netlink/NetlinkErrorMessageTest.java +++ b/services/tests/servicestests/src/android/net/netlink/NetlinkErrorMessageTest.java diff --git a/core/tests/coretests/src/android/net/netlink/NetlinkSocketTest.java b/services/tests/servicestests/src/android/net/netlink/NetlinkSocketTest.java index c599fe3e5b76..c599fe3e5b76 100644 --- a/core/tests/coretests/src/android/net/netlink/NetlinkSocketTest.java +++ b/services/tests/servicestests/src/android/net/netlink/NetlinkSocketTest.java diff --git a/core/tests/coretests/src/android/net/netlink/RtNetlinkNeighborMessageTest.java b/services/tests/servicestests/src/android/net/netlink/RtNetlinkNeighborMessageTest.java index 19ee00036b61..19ee00036b61 100644 --- a/core/tests/coretests/src/android/net/netlink/RtNetlinkNeighborMessageTest.java +++ b/services/tests/servicestests/src/android/net/netlink/RtNetlinkNeighborMessageTest.java diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerServiceTestable.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerServiceTestable.java new file mode 100644 index 000000000000..7e730f6b5289 --- /dev/null +++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerServiceTestable.java @@ -0,0 +1,218 @@ +/* + * Copyright (C) 2015 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.android.server.devicepolicy; + +import com.android.internal.widget.LockPatternUtils; + +import android.app.IActivityManager; +import android.app.NotificationManager; +import android.content.Context; +import android.content.pm.IPackageManager; +import android.content.pm.PackageManager; +import android.os.Looper; +import android.os.PowerManager.WakeLock; +import android.os.PowerManagerInternal; +import android.os.UserHandle; +import android.os.UserManager; +import android.view.IWindowManager; + +import java.io.File; + +import static org.mockito.Matchers.eq; +import static org.mockito.Mockito.when; + +/** + * Overrides {@link #DevicePolicyManagerService} for dependency injection. + */ +public class DevicePolicyManagerServiceTestable extends DevicePolicyManagerService { + /** + * Overrides {@link #Owners} for dependency injection. + */ + public static class OwnersTestable extends Owners { + public static final String LEGACY_FILE = "legacy.xml"; + public static final String DEVICE_OWNER_FILE = "device_owner2.xml"; + public static final String PROFILE_OWNER_FILE_BASE = "profile_owner.xml"; + + private final File mLegacyFile; + private final File mDeviceOwnerFile; + private final File mProfileOwnerBase; + + public OwnersTestable(Context context, File dataDir) { + super(context); + mLegacyFile = new File(dataDir, LEGACY_FILE); + mDeviceOwnerFile = new File(dataDir, DEVICE_OWNER_FILE); + mProfileOwnerBase = new File(dataDir, PROFILE_OWNER_FILE_BASE); + } + + @Override + File getLegacyConfigFileWithTestOverride() { + return mLegacyFile; + } + + @Override + File getDeviceOwnerFileWithTestOverride() { + return mDeviceOwnerFile; + } + + @Override + File getProfileOwnerFileWithTestOverride(int userId) { + return new File(mDeviceOwnerFile.getAbsoluteFile() + "-" + userId); + } + } + + public final File dataDir; + public final File systemUserDataDir; + public final File secondUserDataDir; + + public DevicePolicyManagerServiceTestable(DpmMockContext context, File dataDir) { + super(context); + this.dataDir = dataDir; + + systemUserDataDir = new File(dataDir, "user0"); + DpmTestUtils.clearDir(dataDir); + + secondUserDataDir = new File(dataDir, "user" + DpmMockContext.CALLER_USER_HANDLE); + DpmTestUtils.clearDir(secondUserDataDir); + + when(getContext().environment.getUserSystemDirectory( + eq(DpmMockContext.CALLER_USER_HANDLE))).thenReturn(secondUserDataDir); + } + + @Override + DpmMockContext getContext() { + return (DpmMockContext) super.getContext(); + } + + @Override + Owners newOwners() { + return new OwnersTestable(getContext(), dataDir); + } + + @Override + UserManager getUserManager() { + return getContext().userManager; + } + + @Override + PackageManager getPackageManager() { + return getContext().packageManager; + } + + @Override + PowerManagerInternal getPowerManagerInternal() { + return getContext().powerManagerInternal; + } + + @Override + NotificationManager getNotificationManager() { + return getContext().notificationManager; + } + + @Override + IWindowManager getIWindowManager() { + return getContext().iwindowManager; + } + + @Override + IActivityManager getIActivityManager() { + return getContext().iactivityManager; + } + + @Override + IPackageManager getIPackageManager() { + return getContext().ipackageManager; + } + + @Override + LockPatternUtils newLockPatternUtils(Context context) { + return getContext().lockPatternUtils; + } + + @Override + Looper getMyLooper() { + return Looper.getMainLooper(); + } + + @Override + String getDevicePolicyFilePathForSystemUser() { + return systemUserDataDir.getAbsolutePath(); + } + + @Override + long binderClearCallingIdentity() { + return getContext().binder.clearCallingIdentity(); + } + + @Override + void binderRestoreCallingIdentity(long token) { + getContext().binder.restoreCallingIdentity(token); + } + + @Override + int binderGetCallingUid() { + return getContext().binder.getCallingUid(); + } + + @Override + int binderGetCallingPid() { + return getContext().binder.getCallingPid(); + } + + @Override + UserHandle binderGetCallingUserHandle() { + return getContext().binder.getCallingUserHandle(); + } + + @Override + boolean binderIsCallingUidMyUid() { + return getContext().binder.isCallerUidMyUid(); + } + + @Override + File environmentGetUserSystemDirectory(int userId) { + return getContext().environment.getUserSystemDirectory(userId); + } + + @Override + void powerManagerGoToSleep(long time, int reason, int flags) { + getContext().powerManager.goToSleep(time, reason, flags); + } + + @Override + boolean systemPropertiesGetBoolean(String key, boolean def) { + return getContext().systemProperties.getBoolean(key, def); + } + + @Override + long systemPropertiesGetLong(String key, long def) { + return getContext().systemProperties.getLong(key, def); + } + + @Override + String systemPropertiesGet(String key, String def) { + return getContext().systemProperties.get(key, def); + } + + @Override + String systemPropertiesGet(String key) { + return getContext().systemProperties.get(key); + } + + @Override + void systemPropertiesSet(String key, String value) { + getContext().systemProperties.set(key, value); + } +} diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java new file mode 100644 index 000000000000..0da459dab0d6 --- /dev/null +++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java @@ -0,0 +1,404 @@ +/* + * Copyright (C) 2015 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.android.server.devicepolicy; + +import com.android.server.LocalServices; + +import android.Manifest.permission; +import android.app.Activity; +import android.app.admin.DeviceAdminReceiver; +import android.app.admin.DevicePolicyManager; +import android.app.admin.DevicePolicyManagerInternal; +import android.content.BroadcastReceiver; +import android.content.ComponentName; +import android.content.Intent; +import android.content.pm.ApplicationInfo; +import android.content.pm.IPackageManager; +import android.content.pm.PackageManager; +import android.content.pm.ResolveInfo; +import android.os.Bundle; + +import org.mockito.ArgumentCaptor; + +import java.util.List; + +import static org.mockito.Matchers.any; +import static org.mockito.Matchers.anyString; +import static org.mockito.Matchers.eq; +import static org.mockito.Matchers.isNull; +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +/** + * Tests for DevicePolicyManager( and DevicePolicyManagerService). + * + m FrameworksServicesTests && + adb install \ + -r out/target/product/hammerhead/data/app/FrameworksServicesTests/FrameworksServicesTests.apk && + adb shell am instrument -e class com.android.server.devicepolicy.DevicePolicyManagerTest \ + -w com.android.frameworks.servicestests/android.support.test.runner.AndroidJUnitRunner + + (mmma frameworks/base/services/tests/servicestests/ for non-ninja build) + */ +public class DevicePolicyManagerTest extends DpmTestBase { + + + private DpmMockContext mContext; + public DevicePolicyManager dpm; + public DevicePolicyManagerServiceTestable dpms; + public ComponentName admin1; + public ComponentName admin2; + public ComponentName admin3; + + @Override + protected void setUp() throws Exception { + super.setUp(); + + mContext = getContext(); + + when(mContext.packageManager.hasSystemFeature(eq(PackageManager.FEATURE_DEVICE_ADMIN))) + .thenReturn(true); + + LocalServices.removeServiceForTest(DevicePolicyManagerInternal.class); + dpms = new DevicePolicyManagerServiceTestable(mContext, dataDir); + dpm = new DevicePolicyManagerTestable(mContext, dpms); + + admin1 = new ComponentName(mRealTestContext, DummyDeviceAdmins.Admin1.class); + admin2 = new ComponentName(mRealTestContext, DummyDeviceAdmins.Admin2.class); + admin3 = new ComponentName(mRealTestContext, DummyDeviceAdmins.Admin3.class); + + setUpPackageManagerForAdmin(admin1); + setUpPackageManagerForAdmin(admin2); + setUpPackageManagerForAdmin(admin3); + + setUpApplicationInfo(PackageManager.COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED); + } + + /** + * Set up a mock result for {@link PackageManager#queryBroadcastReceivers}. We'll return + * the actual ResolveInfo for the admin component, but we need to mock PM so it'll return + * it for user {@link DpmMockContext#CALLER_USER_HANDLE}. + */ + private void setUpPackageManagerForAdmin(ComponentName admin) { + final Intent resolveIntent = new Intent(); + resolveIntent.setComponent(admin); + final List<ResolveInfo> realResolveInfo = + mRealTestContext.getPackageManager().queryBroadcastReceivers( + resolveIntent, + PackageManager.GET_META_DATA); + assertNotNull(realResolveInfo); + assertEquals(1, realResolveInfo.size()); + + // We need to rewrite the UID in the activity info. + realResolveInfo.get(0).activityInfo.applicationInfo.uid = DpmMockContext.CALLER_UID; + + doReturn(realResolveInfo).when(mContext.packageManager).queryBroadcastReceivers( + MockUtils.checkIntentComponent(admin), + eq(PackageManager.GET_META_DATA + | PackageManager.GET_DISABLED_UNTIL_USED_COMPONENTS), + eq(DpmMockContext.CALLER_USER_HANDLE) + ); + } + + /** + * Set up a mock result for {@link IPackageManager#getApplicationInfo} for user + * {@link DpmMockContext#CALLER_USER_HANDLE}. + */ + private void setUpApplicationInfo(int enabledSetting) throws Exception { + final ApplicationInfo ai = mRealTestContext.getPackageManager().getApplicationInfo( + admin1.getPackageName(), + PackageManager.GET_DISABLED_UNTIL_USED_COMPONENTS); + + ai.enabledSetting = enabledSetting; + + doReturn(ai).when(mContext.ipackageManager).getApplicationInfo( + eq(admin1.getPackageName()), + eq(PackageManager.GET_DISABLED_UNTIL_USED_COMPONENTS), + eq(DpmMockContext.CALLER_USER_HANDLE)); + } + + public void testHasNoFeature() { + when(mContext.packageManager.hasSystemFeature(eq(PackageManager.FEATURE_DEVICE_ADMIN))) + .thenReturn(false); + + LocalServices.removeServiceForTest(DevicePolicyManagerInternal.class); + new DevicePolicyManagerServiceTestable(mContext, dataDir); + + // If the device has no DPMS feature, it shouldn't register the local service. + assertNull(LocalServices.getService(DevicePolicyManagerInternal.class)); + } + + /** + * Caller doesn't have proper permissions. + */ + public void testSetActiveAdmin_SecurityException() { + // 1. Failure cases. + + // Caller doesn't have MANAGE_DEVICE_ADMINS. + try { + dpm.setActiveAdmin(admin1, false); + fail("Didn't throw SecurityException"); + } catch (SecurityException expected) { + } + + // Caller has MANAGE_DEVICE_ADMINS, but for different user. + mContext.callerPermissions.add(android.Manifest.permission.MANAGE_DEVICE_ADMINS); + try { + dpm.setActiveAdmin(admin1, false, DpmMockContext.CALLER_USER_HANDLE + 1); + fail("Didn't throw SecurityException"); + } catch (SecurityException expected) { + } + } + + /** + * Test for: + * {@link DevicePolicyManager#setActiveAdmin} + * with replace=false and replace=true + * {@link DevicePolicyManager#isAdminActive} + * {@link DevicePolicyManager#isAdminActiveAsUser} + * {@link DevicePolicyManager#getActiveAdmins} + * {@link DevicePolicyManager#getActiveAdminsAsUser} + */ + public void testSetActiveAdmin() throws Exception { + // 1. Make sure the caller has proper permissions. + mContext.callerPermissions.add(android.Manifest.permission.MANAGE_DEVICE_ADMINS); + + // 2. Call the API. + dpm.setActiveAdmin(admin1, /* replace =*/ false); + + // 3. Verify internal calls. + + // Check if the boradcast is sent. + verify(mContext.spiedContext).sendBroadcastAsUser( + MockUtils.checkIntentAction( + DevicePolicyManager.ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED), + MockUtils.checkUserHandle(DpmMockContext.CALLER_USER_HANDLE)); + verify(mContext.spiedContext).sendBroadcastAsUser( + MockUtils.checkIntentAction( + DeviceAdminReceiver.ACTION_DEVICE_ADMIN_ENABLED), + MockUtils.checkUserHandle(DpmMockContext.CALLER_USER_HANDLE)); + + verify(mContext.ipackageManager, times(1)).setApplicationEnabledSetting( + eq(admin1.getPackageName()), + eq(PackageManager.COMPONENT_ENABLED_STATE_DEFAULT), + eq(PackageManager.DONT_KILL_APP), + eq(DpmMockContext.CALLER_USER_HANDLE), + anyString()); + + // TODO Verify other calls too. + + // Make sure it's active admin1. + assertTrue(dpm.isAdminActive(admin1)); + assertFalse(dpm.isAdminActive(admin2)); + assertFalse(dpm.isAdminActive(admin3)); + + // But not admin1 for a different user. + + // For this to work, caller needs android.permission.INTERACT_ACROSS_USERS_FULL. + // (Because we're checking a different user's status from CALLER_USER_HANDLE.) + mContext.callerPermissions.add("android.permission.INTERACT_ACROSS_USERS_FULL"); + + assertFalse(dpm.isAdminActiveAsUser(admin1, DpmMockContext.CALLER_USER_HANDLE + 1)); + assertFalse(dpm.isAdminActiveAsUser(admin2, DpmMockContext.CALLER_USER_HANDLE + 1)); + + mContext.callerPermissions.remove("android.permission.INTERACT_ACROSS_USERS_FULL"); + + // Next, add one more admin. + // Before doing so, update the application info, now it's enabled. + setUpApplicationInfo(PackageManager.COMPONENT_ENABLED_STATE_ENABLED); + + dpm.setActiveAdmin(admin2, /* replace =*/ false); + + // Now we have two admins. + assertTrue(dpm.isAdminActive(admin1)); + assertTrue(dpm.isAdminActive(admin2)); + assertFalse(dpm.isAdminActive(admin3)); + + // Admin2 was already enabled, so setApplicationEnabledSetting() shouldn't have called + // again. (times(1) because it was previously called for admin1) + verify(mContext.ipackageManager, times(1)).setApplicationEnabledSetting( + eq(admin1.getPackageName()), + eq(PackageManager.COMPONENT_ENABLED_STATE_DEFAULT), + eq(PackageManager.DONT_KILL_APP), + eq(DpmMockContext.CALLER_USER_HANDLE), + anyString()); + + // 4. Add the same admin1 again without replace, which should throw. + try { + dpm.setActiveAdmin(admin1, /* replace =*/ false); + fail("Didn't throw"); + } catch (IllegalArgumentException expected) { + } + + // 5. Add the same admin1 again with replace, which should succeed. + dpm.setActiveAdmin(admin1, /* replace =*/ true); + + // TODO make sure it's replaced. + + // 6. Test getActiveAdmins() + List<ComponentName> admins = dpm.getActiveAdmins(); + assertEquals(2, admins.size()); + assertEquals(admin1, admins.get(0)); + assertEquals(admin2, admins.get(1)); + + // Another user has no admins. + mContext.callerPermissions.add("android.permission.INTERACT_ACROSS_USERS_FULL"); + + assertEquals(0, DpmTestUtils.getListSizeAllowingNull( + dpm.getActiveAdminsAsUser(DpmMockContext.CALLER_USER_HANDLE + 1))); + + mContext.callerPermissions.remove("android.permission.INTERACT_ACROSS_USERS_FULL"); + } + + /** + * Test for: + * {@link DevicePolicyManager#setActiveAdmin} + * with replace=false + */ + public void testSetActiveAdmin_twiceWithoutReplace() throws Exception { + // 1. Make sure the caller has proper permissions. + mContext.callerPermissions.add(android.Manifest.permission.MANAGE_DEVICE_ADMINS); + + dpm.setActiveAdmin(admin1, /* replace =*/ false); + assertTrue(dpm.isAdminActive(admin1)); + + // Add the same admin1 again without replace, which should throw. + try { + dpm.setActiveAdmin(admin1, /* replace =*/ false); + fail("Didn't throw"); + } catch (IllegalArgumentException expected) { + } + } + + /** + * Test for: + * {@link DevicePolicyManager#removeActiveAdmin} + */ + public void testRemoveActiveAdmin_SecurityException() { + mContext.callerPermissions.add(android.Manifest.permission.MANAGE_DEVICE_ADMINS); + + // Add admin. + + dpm.setActiveAdmin(admin1, /* replace =*/ false); + + assertTrue(dpm.isAdminActive(admin1)); + + assertFalse(dpm.isRemovingAdmin(admin1, DpmMockContext.CALLER_USER_HANDLE)); + + // Directly call the DPMS method with a different userid, which should fail. + try { + dpms.removeActiveAdmin(admin1, DpmMockContext.CALLER_USER_HANDLE + 1); + fail("Didn't throw SecurityException"); + } catch (SecurityException expected) { + } + + // Try to remove active admin with a different caller userid should fail too, without + // having MANAGE_DEVICE_ADMINS. + mContext.callerPermissions.clear(); + + mContext.binder.callingUid = 1234567; + try { + dpm.removeActiveAdmin(admin1); + fail("Didn't throw SecurityException"); + } catch (SecurityException expected) { + } + } + + /** + * Test for: + * {@link DevicePolicyManager#removeActiveAdmin} + */ + public void testRemoveActiveAdmin_fromDifferentUserWithMINTERACT_ACROSS_USERS_FULL() { + mContext.callerPermissions.add(android.Manifest.permission.MANAGE_DEVICE_ADMINS); + + // Add admin1. + + dpm.setActiveAdmin(admin1, /* replace =*/ false); + + assertTrue(dpm.isAdminActive(admin1)); + assertFalse(dpm.isRemovingAdmin(admin1, DpmMockContext.CALLER_USER_HANDLE)); + + // Different user, but should work, because caller has proper permissions. + mContext.callerPermissions.add(permission.INTERACT_ACROSS_USERS_FULL); + mContext.binder.callingUid = 1234567; + dpm.removeActiveAdmin(admin1); + + assertTrue(dpm.isRemovingAdmin(admin1, DpmMockContext.CALLER_USER_HANDLE)); + + // TODO DO Still can't be removed in this case. + } + + /** + * Test for: + * {@link DevicePolicyManager#removeActiveAdmin} + */ + public void testRemoveActiveAdmin_sameUserNoMANAGE_DEVICE_ADMINS() { + // Need MANAGE_DEVICE_ADMINS for setActiveAdmin. We'll remove it later. + mContext.callerPermissions.add(android.Manifest.permission.MANAGE_DEVICE_ADMINS); + + // Add admin1. + + dpm.setActiveAdmin(admin1, /* replace =*/ false); + + assertTrue(dpm.isAdminActive(admin1)); + assertFalse(dpm.isRemovingAdmin(admin1, DpmMockContext.CALLER_USER_HANDLE)); + + // Broadcast from saveSettingsLocked(). + verify(mContext.spiedContext, times(1)).sendBroadcastAsUser( + MockUtils.checkIntentAction( + DevicePolicyManager.ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED), + MockUtils.checkUserHandle(DpmMockContext.CALLER_USER_HANDLE)); + + // Remove. No permissions, but same user, so it'll work. + mContext.callerPermissions.clear(); + dpm.removeActiveAdmin(admin1); + + final ArgumentCaptor<BroadcastReceiver> brCap = + ArgumentCaptor.forClass(BroadcastReceiver.class); + + // Is removing now, but not removed yet. + assertTrue(dpm.isAdminActive(admin1)); + assertTrue(dpm.isRemovingAdmin(admin1, DpmMockContext.CALLER_USER_HANDLE)); + + verify(mContext.spiedContext).sendOrderedBroadcastAsUser( + MockUtils.checkIntentAction( + DeviceAdminReceiver.ACTION_DEVICE_ADMIN_DISABLED), + MockUtils.checkUserHandle(DpmMockContext.CALLER_USER_HANDLE), + isNull(String.class), + brCap.capture(), + eq(dpms.mHandler), + eq(Activity.RESULT_OK), + isNull(String.class), + isNull(Bundle.class)); + + brCap.getValue().onReceive(mContext, null); + + assertFalse(dpm.isAdminActive(admin1)); + assertFalse(dpm.isRemovingAdmin(admin1, DpmMockContext.CALLER_USER_HANDLE)); + + // Again broadcast from saveSettingsLocked(). + verify(mContext.spiedContext, times(2)).sendBroadcastAsUser( + MockUtils.checkIntentAction( + DevicePolicyManager.ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED), + MockUtils.checkUserHandle(DpmMockContext.CALLER_USER_HANDLE)); + + // TODO Check other internal calls. + } +} + + diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTestable.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTestable.java new file mode 100644 index 000000000000..325bf9ff0225 --- /dev/null +++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTestable.java @@ -0,0 +1,36 @@ +/* + * Copyright (C) 2015 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.android.server.devicepolicy; + +import android.app.admin.DevicePolicyManager; + +/** + * Overrides {@link #DevicePolicyManager} for dependency injection. + */ +public class DevicePolicyManagerTestable extends DevicePolicyManager { + public final DevicePolicyManagerServiceTestable dpms; + + public DevicePolicyManagerTestable(DpmMockContext context, + DevicePolicyManagerServiceTestable dpms) { + super(context, dpms); + this.dpms = dpms; + } + + @Override + public int myUserId() { + return DpmMockContext.CALLER_USER_HANDLE; + } +} diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DpmMockContext.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DpmMockContext.java index c2b89819501b..6bb9833a883c 100644 --- a/services/tests/servicestests/src/com/android/server/devicepolicy/DpmMockContext.java +++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DpmMockContext.java @@ -16,31 +16,356 @@ package com.android.server.devicepolicy; +import com.android.internal.annotations.VisibleForTesting; +import com.android.internal.widget.LockPatternUtils; + +import android.app.IActivityManager; +import android.app.NotificationManager; +import android.content.BroadcastReceiver; import android.content.Context; -import android.content.ContextWrapper; +import android.content.Intent; +import android.content.IntentFilter; +import android.content.pm.IPackageManager; +import android.content.pm.PackageManager; +import android.os.Bundle; +import android.os.Handler; +import android.os.PowerManager.WakeLock; +import android.os.PowerManagerInternal; +import android.os.SystemProperties; +import android.os.UserHandle; import android.os.UserManager; +import android.test.mock.MockContext; +import android.view.IWindowManager; + +import java.io.File; +import java.util.ArrayList; +import java.util.List; import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.spy; -public class DpmMockContext extends ContextWrapper { - private final UserManager mMockUserManager; +/** + * Context used throughout DPMS tests. + */ +public class DpmMockContext extends MockContext { + /** + * User-id of a non-system user we use throughout unit tests. + */ + public static final int CALLER_USER_HANDLE = 20; + /** + * UID of the caller. + */ + public static final int CALLER_UID = UserHandle.PER_USER_RANGE * CALLER_USER_HANDLE + 123; - public DpmMockContext(Context context) { - super(context); - mMockUserManager = mock(UserManager.class); + /** + * PID of the caller. + */ + public static final int CALLER_PID = 22222; + + /** + * UID of the system server. + */ + public static final int SYSTEM_UID = android.os.Process.SYSTEM_UID; + + /** + * PID of the system server. + */ + public static final int SYSTEM_PID = 11111; + + public static class MockBinder { + public int callingUid = CALLER_UID; + public int callingPid = CALLER_PID; + + public long clearCallingIdentity() { + final long token = (((long) callingUid) << 32) | (callingPid); + callingUid = SYSTEM_UID; + callingPid = SYSTEM_PID; + return token; + } + + public void restoreCallingIdentity(long token) { + callingUid = (int) (token >> 32); + callingPid = (int) token; + } + + public int getCallingUid() { + return callingUid; + } + + public int getCallingPid() { + return callingPid; + } + + public UserHandle getCallingUserHandle() { + return new UserHandle(UserHandle.getUserId(getCallingUid())); + } + + public boolean isCallerUidMyUid() { + return callingUid == SYSTEM_UID; + } + } + + public static class EnvironmentForMock { + public File getUserSystemDirectory(int userId) { + return null; + } } - public UserManager getMockUserManager() { - return mMockUserManager; + public static class PowerManagerForMock { + public WakeLock newWakeLock(int levelAndFlags, String tag) { + return null; + } + + public void goToSleep(long time, int reason, int flags) { + } + } + + public static class SystemPropertiesForMock { + public boolean getBoolean(String key, boolean def) { + return false; + } + + public long getLong(String key, long def) { + return 0; + } + + public String get(String key, String def) { + return null; + } + + public String get(String key) { + return null; + } + + public void set(String key, String value) { + } + } + + public final Context realTestContext; + + /** + * Use this instance to verify unimplemented methods such as {@link #sendBroadcast}. + * (Spying on {@code this} instance will confuse mockito somehow and I got weired "wrong number + * of arguments" exceptions.) + */ + public final Context spiedContext; + + public final MockBinder binder; + public final EnvironmentForMock environment; + public final SystemPropertiesForMock systemProperties; + public final UserManager userManager; + public final PowerManagerForMock powerManager; + public final PowerManagerInternal powerManagerInternal; + public final NotificationManager notificationManager; + public final IWindowManager iwindowManager; + public final IActivityManager iactivityManager; + public final IPackageManager ipackageManager; + public final LockPatternUtils lockPatternUtils; + + /** Note this is a partial mock, not a real mock. */ + public final PackageManager packageManager; + + public final List<String> callerPermissions = new ArrayList<>(); + + public DpmMockContext(Context context) { + realTestContext = context; + binder = new MockBinder(); + environment = mock(EnvironmentForMock.class); + systemProperties= mock(SystemPropertiesForMock.class); + userManager = mock(UserManager.class); + powerManager = mock(PowerManagerForMock.class); + powerManagerInternal = mock(PowerManagerInternal.class); + notificationManager = mock(NotificationManager.class); + iwindowManager = mock(IWindowManager.class); + iactivityManager = mock(IActivityManager.class); + ipackageManager = mock(IPackageManager.class); + lockPatternUtils = mock(LockPatternUtils.class); + + // Package manager is huge, so we use a partial mock instead. + packageManager = spy(context.getPackageManager()); + + spiedContext = mock(Context.class); } @Override public Object getSystemService(String name) { switch (name) { case Context.USER_SERVICE: - return mMockUserManager; + return userManager; + case Context.POWER_SERVICE: + return powerManager; + } + throw new UnsupportedOperationException(); + } + + @Override + public PackageManager getPackageManager() { + return packageManager; + } + + @Override + public void enforceCallingOrSelfPermission(String permission, String message) { + if (binder.getCallingUid() == SYSTEM_UID) { + return; // Assume system has all permissions. } - return super.getSystemService(name); + if (!callerPermissions.contains(permission)) { + throw new SecurityException("Caller doesn't have " + permission + " : " + message); + } + } + + @Override + public void sendBroadcast(Intent intent) { + spiedContext.sendBroadcast(intent); + } + + @Override + public void sendBroadcast(Intent intent, String receiverPermission) { + spiedContext.sendBroadcast(intent, receiverPermission); + } + + @Override + public void sendBroadcastMultiplePermissions(Intent intent, String[] receiverPermissions) { + spiedContext.sendBroadcastMultiplePermissions(intent, receiverPermissions); + } + + @Override + public void sendBroadcast(Intent intent, String receiverPermission, Bundle options) { + spiedContext.sendBroadcast(intent, receiverPermission, options); + } + + @Override + public void sendBroadcast(Intent intent, String receiverPermission, int appOp) { + spiedContext.sendBroadcast(intent, receiverPermission, appOp); + } + + @Override + public void sendOrderedBroadcast(Intent intent, String receiverPermission) { + spiedContext.sendOrderedBroadcast(intent, receiverPermission); + } + + @Override + public void sendOrderedBroadcast(Intent intent, String receiverPermission, + BroadcastReceiver resultReceiver, Handler scheduler, int initialCode, + String initialData, Bundle initialExtras) { + spiedContext.sendOrderedBroadcast(intent, receiverPermission, resultReceiver, scheduler, + initialCode, initialData, initialExtras); + } + + @Override + public void sendOrderedBroadcast(Intent intent, String receiverPermission, Bundle options, + BroadcastReceiver resultReceiver, Handler scheduler, int initialCode, + String initialData, Bundle initialExtras) { + spiedContext.sendOrderedBroadcast(intent, receiverPermission, options, resultReceiver, + scheduler, + initialCode, initialData, initialExtras); + } + + @Override + public void sendOrderedBroadcast(Intent intent, String receiverPermission, int appOp, + BroadcastReceiver resultReceiver, Handler scheduler, int initialCode, + String initialData, Bundle initialExtras) { + spiedContext.sendOrderedBroadcast(intent, receiverPermission, appOp, resultReceiver, + scheduler, + initialCode, initialData, initialExtras); + } + + @Override + public void sendBroadcastAsUser(Intent intent, UserHandle user) { + spiedContext.sendBroadcastAsUser(intent, user); + } + + @Override + public void sendBroadcastAsUser(Intent intent, UserHandle user, String receiverPermission) { + spiedContext.sendBroadcastAsUser(intent, user, receiverPermission); + } + + @Override + public void sendBroadcastAsUser(Intent intent, UserHandle user, String receiverPermission, + int appOp) { + spiedContext.sendBroadcastAsUser(intent, user, receiverPermission, appOp); + } + + @Override + public void sendOrderedBroadcastAsUser(Intent intent, UserHandle user, + String receiverPermission, BroadcastReceiver resultReceiver, Handler scheduler, + int initialCode, String initialData, Bundle initialExtras) { + spiedContext.sendOrderedBroadcastAsUser(intent, user, receiverPermission, resultReceiver, + scheduler, initialCode, initialData, initialExtras); + } + + @Override + public void sendOrderedBroadcastAsUser(Intent intent, UserHandle user, + String receiverPermission, int appOp, BroadcastReceiver resultReceiver, + Handler scheduler, int initialCode, String initialData, Bundle initialExtras) { + spiedContext.sendOrderedBroadcastAsUser(intent, user, receiverPermission, appOp, + resultReceiver, + scheduler, initialCode, initialData, initialExtras); + } + + @Override + public void sendOrderedBroadcastAsUser(Intent intent, UserHandle user, + String receiverPermission, int appOp, Bundle options, BroadcastReceiver resultReceiver, + Handler scheduler, int initialCode, String initialData, Bundle initialExtras) { + spiedContext.sendOrderedBroadcastAsUser(intent, user, receiverPermission, appOp, options, + resultReceiver, scheduler, initialCode, initialData, initialExtras); + } + + @Override + public void sendStickyBroadcast(Intent intent) { + spiedContext.sendStickyBroadcast(intent); + } + + @Override + public void sendStickyOrderedBroadcast(Intent intent, BroadcastReceiver resultReceiver, + Handler scheduler, int initialCode, String initialData, Bundle initialExtras) { + spiedContext.sendStickyOrderedBroadcast(intent, resultReceiver, scheduler, initialCode, + initialData, initialExtras); + } + + @Override + public void removeStickyBroadcast(Intent intent) { + spiedContext.removeStickyBroadcast(intent); + } + + @Override + public void sendStickyBroadcastAsUser(Intent intent, UserHandle user) { + spiedContext.sendStickyBroadcastAsUser(intent, user); + } + + @Override + public void sendStickyOrderedBroadcastAsUser(Intent intent, UserHandle user, + BroadcastReceiver resultReceiver, Handler scheduler, int initialCode, + String initialData, Bundle initialExtras) { + spiedContext.sendStickyOrderedBroadcastAsUser(intent, user, resultReceiver, scheduler, initialCode, + initialData, initialExtras); + } + + @Override + public void removeStickyBroadcastAsUser(Intent intent, UserHandle user) { + spiedContext.removeStickyBroadcastAsUser(intent, user); + } + + @Override + public Intent registerReceiver(BroadcastReceiver receiver, IntentFilter filter) { + return spiedContext.registerReceiver(receiver, filter); + } + + @Override + public Intent registerReceiver(BroadcastReceiver receiver, IntentFilter filter, + String broadcastPermission, Handler scheduler) { + return spiedContext.registerReceiver(receiver, filter, broadcastPermission, scheduler); + } + + @Override + public Intent registerReceiverAsUser(BroadcastReceiver receiver, UserHandle user, + IntentFilter filter, String broadcastPermission, Handler scheduler) { + return spiedContext.registerReceiverAsUser(receiver, user, filter, broadcastPermission, + scheduler); + } + + @Override + public void unregisterReceiver(BroadcastReceiver receiver) { + spiedContext.unregisterReceiver(receiver); } } diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DpmTestBase.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DpmTestBase.java index 445260b9da6c..77270c8cec55 100644 --- a/services/tests/servicestests/src/com/android/server/devicepolicy/DpmTestBase.java +++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DpmTestBase.java @@ -19,14 +19,25 @@ package com.android.server.devicepolicy; import android.content.Context; import android.test.AndroidTestCase; +import java.io.File; + public class DpmTestBase extends AndroidTestCase { - private DpmMockContext mMockContext; + public static final String TAG = "DpmTest"; + + protected Context mRealTestContext; + protected DpmMockContext mMockContext; + + public File dataDir; @Override protected void setUp() throws Exception { super.setUp(); + mRealTestContext = super.getContext(); mMockContext = new DpmMockContext(super.getContext()); + + dataDir = new File(mRealTestContext.getCacheDir(), "test-data"); + DpmTestUtils.clearDir(dataDir); } @Override diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DpmTestUtils.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DpmTestUtils.java new file mode 100644 index 000000000000..44a851abe476 --- /dev/null +++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DpmTestUtils.java @@ -0,0 +1,50 @@ +/* + * Copyright (C) 2015 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server.devicepolicy; + +import android.os.FileUtils; +import android.util.Log; +import android.util.Printer; + +import org.junit.Assert; + +import java.io.File; +import java.util.List; + +public class DpmTestUtils { + private DpmTestUtils() { + } + + public static void clearDir(File dir) { + if (dir.exists()) { + Assert.assertTrue("failed to delete dir", FileUtils.deleteContents(dir)); + } + dir.mkdirs(); + Log.i(DpmTestBase.TAG, "Created " + dir); + } + + public static int getListSizeAllowingNull(List<?> list) { + return list == null ? 0 : list.size(); + } + + public static Printer LOG_PRINTER = new Printer() { + @Override + public void println(String x) { + Log.i(DpmTestBase.TAG, x); + } + }; +} diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DummyDeviceAdmins.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DummyDeviceAdmins.java new file mode 100644 index 000000000000..5cd15557a80d --- /dev/null +++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DummyDeviceAdmins.java @@ -0,0 +1,27 @@ +/* + * Copyright (C) 2015 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.android.server.devicepolicy; + +import android.app.admin.DeviceAdminReceiver; + +public class DummyDeviceAdmins { + public static class Admin1 extends DeviceAdminReceiver { + } + public static class Admin2 extends DeviceAdminReceiver { + } + public static class Admin3 extends DeviceAdminReceiver { + } +}
\ No newline at end of file diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/MockUtils.java b/services/tests/servicestests/src/com/android/server/devicepolicy/MockUtils.java new file mode 100644 index 000000000000..5008fbfa3b10 --- /dev/null +++ b/services/tests/servicestests/src/com/android/server/devicepolicy/MockUtils.java @@ -0,0 +1,80 @@ +/* + * Copyright (C) 2015 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.android.server.devicepolicy; + +import com.google.common.base.Objects; + +import android.content.ComponentName; +import android.content.Intent; +import android.os.UserHandle; + +import org.hamcrest.BaseMatcher; +import org.hamcrest.Description; +import org.hamcrest.Matcher; +import org.mockito.Mockito; + +public class MockUtils { + private MockUtils() { + } + + public static UserHandle checkUserHandle(final int userId) { + final Matcher<UserHandle> m = new BaseMatcher<UserHandle>() { + @Override + public boolean matches(Object item) { + if (item == null) return false; + return Objects.equal(((UserHandle) item).getIdentifier(), userId); + } + + @Override + public void describeTo(Description description) { + description.appendText("UserHandle: user-id= \"" + userId + "\""); + } + }; + return Mockito.argThat(m); + } + + public static Intent checkIntentComponent(final ComponentName component) { + final Matcher<Intent> m = new BaseMatcher<Intent>() { + @Override + public boolean matches(Object item) { + if (item == null) return false; + return Objects.equal(((Intent) item).getComponent(), component); + } + + @Override + public void describeTo(Description description) { + description.appendText("Intent: component=\"" + component + "\""); + } + }; + return Mockito.argThat(m); + } + + public static Intent checkIntentAction(final String action) { + final Matcher<Intent> m = new BaseMatcher<Intent>() { + @Override + public boolean matches(Object item) { + if (item == null) return false; + return Objects.equal(((Intent) item).getAction(), action); + } + + @Override + public void describeTo(Description description) { + description.appendText("Intent: action=\"" + action + "\""); + } + }; + return Mockito.argThat(m); + } +} diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/OwnersTest.java b/services/tests/servicestests/src/com/android/server/devicepolicy/OwnersTest.java index 3b88fb165775..a07d61520fa4 100644 --- a/services/tests/servicestests/src/com/android/server/devicepolicy/OwnersTest.java +++ b/services/tests/servicestests/src/com/android/server/devicepolicy/OwnersTest.java @@ -16,12 +16,11 @@ package com.android.server.devicepolicy; +import com.android.server.devicepolicy.DevicePolicyManagerServiceTestable.OwnersTestable; + import android.content.ComponentName; -import android.content.Context; import android.content.pm.UserInfo; -import android.os.FileUtils; import android.os.UserHandle; -import android.test.AndroidTestCase; import android.util.Log; import java.io.BufferedReader; @@ -31,8 +30,6 @@ import java.io.IOException; import java.io.InputStreamReader; import java.util.ArrayList; -import junit.framework.Assert; - import static org.mockito.Mockito.when; /** @@ -47,58 +44,11 @@ import static org.mockito.Mockito.when; (mmma frameworks/base/services/tests/servicestests/ for non-ninja build) */ public class OwnersTest extends DpmTestBase { - private static final String TAG = "DeviceOwnerTest"; - - private static final String LEGACY_FILE = "legacy.xml"; - private static final String DEVICE_OWNER_FILE = "device_owner2.xml"; - private static final String PROFILE_OWNER_FILE_BASE = "profile_owner.xml"; - - private File mDataDir; - - private class OwnersSub extends Owners { - final File mLegacyFile; - final File mDeviceOwnerFile; - final File mProfileOwnerBase; - - public OwnersSub() { - super(getContext()); - mLegacyFile = new File(mDataDir, LEGACY_FILE); - mDeviceOwnerFile = new File(mDataDir, DEVICE_OWNER_FILE); - mProfileOwnerBase = new File(mDataDir, PROFILE_OWNER_FILE_BASE); - } - - @Override - File getLegacyConfigFileWithTestOverride() { - return mLegacyFile; - } - - @Override - File getDeviceOwnerFileWithTestOverride() { - return mDeviceOwnerFile; - } - - @Override - File getProfileOwnerFileWithTestOverride(int userId) { - return new File(mDeviceOwnerFile.getAbsoluteFile() + "-" + userId); - } - } - - @Override - protected void setUp() throws Exception { - super.setUp(); - - mDataDir = new File(getContext().getCacheDir(), "OwnersTest"); - if (mDataDir.exists()) { - assertTrue("failed to delete dir", FileUtils.deleteContents(mDataDir)); - } - mDataDir.mkdirs(); - Log.i(TAG, "Created " + mDataDir); - } - private String readAsset(String assetPath) throws IOException { final StringBuilder sb = new StringBuilder(); try (BufferedReader br = new BufferedReader( - new InputStreamReader((getContext().getResources().getAssets().open(assetPath))))) { + new InputStreamReader( + mRealTestContext.getResources().getAssets().open(assetPath)))) { String line; while ((line = br.readLine()) != null) { sb.append(line); @@ -126,7 +76,7 @@ public class OwnersTest extends DpmTestBase { ui.id = userId; userInfos.add(ui); } - when(getContext().getMockUserManager().getUsers()).thenReturn(userInfos); + when(getContext().userManager.getUsers()).thenReturn(userInfos); } public void testUpgrade01() throws Exception { @@ -134,9 +84,10 @@ public class OwnersTest extends DpmTestBase { // First, migrate. { - final OwnersSub owners = new OwnersSub(); + final OwnersTestable owners = new OwnersTestable(getContext(), dataDir); - createLegacyFile(owners.mLegacyFile, readAsset("OwnersTest/test01/input.xml")); + createLegacyFile(owners.getLegacyConfigFileWithTestOverride(), + readAsset("OwnersTest/test01/input.xml")); owners.load(); @@ -160,7 +111,7 @@ public class OwnersTest extends DpmTestBase { // Then re-read and check. { - final OwnersSub owners = new OwnersSub(); + final OwnersTestable owners = new OwnersTestable(getContext(), dataDir); owners.load(); assertFalse(owners.hasDeviceOwner()); @@ -176,9 +127,10 @@ public class OwnersTest extends DpmTestBase { // First, migrate. { - final OwnersSub owners = new OwnersSub(); + final OwnersTestable owners = new OwnersTestable(getContext(), dataDir); - createLegacyFile(owners.mLegacyFile, readAsset("OwnersTest/test02/input.xml")); + createLegacyFile(owners.getLegacyConfigFileWithTestOverride(), + readAsset("OwnersTest/test02/input.xml")); owners.load(); @@ -204,7 +156,7 @@ public class OwnersTest extends DpmTestBase { // Then re-read and check. { - final OwnersSub owners = new OwnersSub(); + final OwnersTestable owners = new OwnersTestable(getContext(), dataDir); owners.load(); assertTrue(owners.hasDeviceOwner()); @@ -223,9 +175,10 @@ public class OwnersTest extends DpmTestBase { // First, migrate. { - final OwnersSub owners = new OwnersSub(); + final OwnersTestable owners = new OwnersTestable(getContext(), dataDir); - createLegacyFile(owners.mLegacyFile, readAsset("OwnersTest/test03/input.xml")); + createLegacyFile(owners.getLegacyConfigFileWithTestOverride(), + readAsset("OwnersTest/test03/input.xml")); owners.load(); @@ -259,7 +212,7 @@ public class OwnersTest extends DpmTestBase { // Then re-read and check. { - final OwnersSub owners = new OwnersSub(); + final OwnersTestable owners = new OwnersTestable(getContext(), dataDir); owners.load(); assertFalse(owners.hasDeviceOwner()); @@ -286,9 +239,10 @@ public class OwnersTest extends DpmTestBase { // First, migrate. { - final OwnersSub owners = new OwnersSub(); + final OwnersTestable owners = new OwnersTestable(getContext(), dataDir); - createLegacyFile(owners.mLegacyFile, readAsset("OwnersTest/test04/input.xml")); + createLegacyFile(owners.getLegacyConfigFileWithTestOverride(), + readAsset("OwnersTest/test04/input.xml")); owners.load(); @@ -327,7 +281,7 @@ public class OwnersTest extends DpmTestBase { // Then re-read and check. { - final OwnersSub owners = new OwnersSub(); + final OwnersTestable owners = new OwnersTestable(getContext(), dataDir); owners.load(); assertTrue(owners.hasDeviceOwner()); @@ -359,9 +313,10 @@ public class OwnersTest extends DpmTestBase { // First, migrate. { - final OwnersSub owners = new OwnersSub(); + final OwnersTestable owners = new OwnersTestable(getContext(), dataDir); - createLegacyFile(owners.mLegacyFile, readAsset("OwnersTest/test05/input.xml")); + createLegacyFile(owners.getLegacyConfigFileWithTestOverride(), + readAsset("OwnersTest/test05/input.xml")); owners.load(); @@ -386,7 +341,7 @@ public class OwnersTest extends DpmTestBase { // Then re-read and check. { - final OwnersSub owners = new OwnersSub(); + final OwnersTestable owners = new OwnersTestable(getContext(), dataDir); owners.load(); assertFalse(owners.hasDeviceOwner()); @@ -405,9 +360,10 @@ public class OwnersTest extends DpmTestBase { // First, migrate. { - final OwnersSub owners = new OwnersSub(); + final OwnersTestable owners = new OwnersTestable(getContext(), dataDir); - createLegacyFile(owners.mLegacyFile, readAsset("OwnersTest/test06/input.xml")); + createLegacyFile(owners.getLegacyConfigFileWithTestOverride(), + readAsset("OwnersTest/test06/input.xml")); owners.load(); @@ -431,7 +387,7 @@ public class OwnersTest extends DpmTestBase { // Then re-read and check. { - final OwnersSub owners = new OwnersSub(); + final OwnersTestable owners = new OwnersTestable(getContext(), dataDir); owners.load(); assertFalse(owners.hasDeviceOwner()); @@ -447,10 +403,11 @@ public class OwnersTest extends DpmTestBase { public void testRemoveExistingFiles() throws Exception { addUsersToUserManager(10, 11, 20, 21); - final OwnersSub owners = new OwnersSub(); + final OwnersTestable owners = new OwnersTestable(getContext(), dataDir); // First, migrate to create new-style config files. - createLegacyFile(owners.mLegacyFile, readAsset("OwnersTest/test04/input.xml")); + createLegacyFile(owners.getLegacyConfigFileWithTestOverride(), + readAsset("OwnersTest/test04/input.xml")); owners.load(); diff --git a/services/usb/java/com/android/server/usb/UsbSettingsManager.java b/services/usb/java/com/android/server/usb/UsbSettingsManager.java index 2cf42f09111d..154cbd30d836 100644 --- a/services/usb/java/com/android/server/usb/UsbSettingsManager.java +++ b/services/usb/java/com/android/server/usb/UsbSettingsManager.java @@ -517,7 +517,7 @@ class UsbSettingsManager { com.android.internal.R.bool.config_disableUsbPermissionDialogs); synchronized (mLock) { - if (UserHandle.OWNER.equals(user)) { + if (UserHandle.SYSTEM.equals(user)) { upgradeSingleUserLocked(); } readSettingsLocked(); diff --git a/tests/ActivityTests/src/com/google/android/test/activity/ActivityTestMain.java b/tests/ActivityTests/src/com/google/android/test/activity/ActivityTestMain.java index 5fbfe8ace7e1..ceb3993e1705 100644 --- a/tests/ActivityTests/src/com/google/android/test/activity/ActivityTestMain.java +++ b/tests/ActivityTests/src/com/google/android/test/activity/ActivityTestMain.java @@ -57,6 +57,7 @@ import android.content.pm.UserInfo; import android.content.res.Configuration; import android.util.Log; + public class ActivityTestMain extends Activity { static final String TAG = "ActivityTest"; @@ -315,7 +316,7 @@ public class ActivityTestMain extends Activity { Log.i(TAG, "Service disconnected " + name); } }; - if (bindServiceAsUser(intent, conn, Context.BIND_AUTO_CREATE, UserHandle.OWNER)) { + if (bindServiceAsUser(intent, conn, Context.BIND_AUTO_CREATE, UserHandle.SYSTEM)) { mConnections.add(conn); } else { Toast.makeText(ActivityTestMain.this, "Failed to bind", diff --git a/tests/HwAccelerationTest/AndroidManifest.xml b/tests/HwAccelerationTest/AndroidManifest.xml index 10cf5c1b2f8b..b028ce61f821 100644 --- a/tests/HwAccelerationTest/AndroidManifest.xml +++ b/tests/HwAccelerationTest/AndroidManifest.xml @@ -944,5 +944,14 @@ </intent-filter> </activity> + <activity + android:name="MultiProducerActivity" + android:label="Threads/Multiple Producers"> + <intent-filter> + <action android:name="android.intent.action.MAIN" /> + <category android:name="com.android.test.hwui.TEST" /> + </intent-filter> + </activity> + </application> </manifest> diff --git a/tests/HwAccelerationTest/src/com/android/test/hwui/MultiProducerActivity.java b/tests/HwAccelerationTest/src/com/android/test/hwui/MultiProducerActivity.java new file mode 100644 index 000000000000..b458d9b14096 --- /dev/null +++ b/tests/HwAccelerationTest/src/com/android/test/hwui/MultiProducerActivity.java @@ -0,0 +1,347 @@ +/* + * Copyright (C) 2014 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.test.hwui; + +import android.app.Activity; +import android.graphics.Canvas; +import android.graphics.ColorFilter; +import android.graphics.Paint; +import android.graphics.PixelFormat; +import android.graphics.Rect; +import android.graphics.drawable.Drawable; +import android.os.Bundle; +import android.view.DisplayListCanvas; +import android.view.HardwareRenderer; +import android.view.RenderNode; +import android.view.ThreadedRenderer; +import android.view.View; +import android.view.View.OnClickListener; +import android.widget.AbsoluteLayout; +import android.widget.AbsoluteLayout.LayoutParams; + +public class MultiProducerActivity extends Activity implements OnClickListener { + private static final int DURATION = 800; + private View mBackgroundTarget = null; + private View mFrameTarget = null; + private View mContent = null; + // The width & height of our "output drawing". + private final int WIDTH = 900; + private final int HEIGHT = 600; + // A border width around the drawing. + private static final int BORDER_WIDTH = 20; + // The Gap between the content and the frame which should get filled on the right and bottom + // side by the backdrop. + final int CONTENT_GAP = 100; + + // For debug purposes - disable drawing of frame / background. + private final boolean USE_FRAME = true; + private final boolean USE_BACK = true; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + // To make things simple - we do a quick and dirty absolute layout. + final AbsoluteLayout layout = new AbsoluteLayout(this); + + // Create the outer frame + if (USE_FRAME) { + mFrameTarget = new View(this); + LayoutParams frameLP = new LayoutParams(WIDTH, HEIGHT, 0, 0); + layout.addView(mFrameTarget, frameLP); + } + + // Create the background which fills the gap between content and frame. + if (USE_BACK) { + mBackgroundTarget = new View(this); + LayoutParams backgroundLP = new LayoutParams( + WIDTH - 2 * BORDER_WIDTH, HEIGHT - 2 * BORDER_WIDTH, + BORDER_WIDTH, BORDER_WIDTH); + layout.addView(mBackgroundTarget, backgroundLP); + } + + // Create the content + // Note: We reduce the size by CONTENT_GAP pixels on right and bottom, so that they get + // drawn by the backdrop. + mContent = new View(this); + mContent.setBackground(new ColorPulse(0xFFF44336, 0xFF9C27B0, null)); + mContent.setOnClickListener(this); + LayoutParams contentLP = new LayoutParams(WIDTH - 2 * BORDER_WIDTH - CONTENT_GAP, + HEIGHT - 2 * BORDER_WIDTH - CONTENT_GAP, BORDER_WIDTH, BORDER_WIDTH); + layout.addView(mContent, contentLP); + + setContentView(layout); + } + + @Override + protected void onStart() { + super.onStart(); + View view = mBackgroundTarget != null ? mBackgroundTarget : mFrameTarget; + if (view != null) { + view.post(mSetup); + } + } + + @Override + protected void onStop() { + super.onStop(); + View view = mBackgroundTarget != null ? mBackgroundTarget : mFrameTarget; + if (view != null) { + view.removeCallbacks(mSetup); + } + if (mBgRenderer != null) { + mBgRenderer.destroy(); + mBgRenderer = null; + } + } + + @Override + public void onClick(View view) { + sBlockThread.run(); + } + + private Runnable mSetup = new Runnable() { + @Override + public void run() { + View view = mBackgroundTarget != null ? mBackgroundTarget : mFrameTarget; + if (view == null) { + view.postDelayed(mSetup, 50); + } + HardwareRenderer renderer = view.getHardwareRenderer(); + if (renderer == null || view.getWidth() == 0) { + view.postDelayed(mSetup, 50); + } + ThreadedRenderer threaded = (ThreadedRenderer) renderer; + + mBgRenderer = new FakeFrame(threaded,mFrameTarget, mBackgroundTarget); + mBgRenderer.start(); + } + }; + + private FakeFrame mBgRenderer; + private class FakeFrame extends Thread { + ThreadedRenderer mRenderer; + volatile boolean mRunning = true; + View mTargetFrame; + View mTargetBack; + Drawable mFrameContent; + Drawable mBackContent; + // The Z value where to place this. + int mZFrame; + int mZBack; + String mRenderNodeName; + + FakeFrame(ThreadedRenderer renderer, View targetFrame, View targetBack) { + mRenderer = renderer; + mTargetFrame = targetFrame; + + mTargetBack = targetBack; + mFrameContent = new ColorPulse(0xFF101010, 0xFF707070, new Rect(0, 0, WIDTH, HEIGHT)); + mBackContent = new ColorPulse(0xFF909090, 0xFFe0e0e0, null); + } + + @Override + public void run() { + Rect currentFrameBounds = new Rect(); + Rect currentBackBounds = new Rect(); + Rect newBounds = new Rect(); + int[] surfaceOrigin = new int[2]; + RenderNode nodeFrame = null; + RenderNode nodeBack = null; + + // Since we are overriding the window painting logic we need to at least fill the + // surface with some window content (otherwise the world will go black). + try { + Thread.sleep(200); + } catch (InterruptedException e) { + } + + if (mTargetBack != null) { + nodeBack = RenderNode.create("FakeBackdrop", null); + nodeBack.setClipToBounds(true); + mRenderer.addRenderNode(nodeBack, true); + } + + if (mTargetFrame != null) { + nodeFrame = RenderNode.create("FakeFrame", null); + nodeFrame.setClipToBounds(true); + mRenderer.addRenderNode(nodeFrame, false); + } + + while (mRunning) { + // Get the surface position to draw to within our surface. + surfaceOrigin[0] = 0; + surfaceOrigin[1] = 0; + // This call should be done while the rendernode's displaylist is produced. + // For simplicity of this test we do this before we kick off the draw. + mContent.getLocationInSurface(surfaceOrigin); + mRenderer.setContentOverdrawProtectionBounds(surfaceOrigin[0], surfaceOrigin[1], + surfaceOrigin[0] + mContent.getWidth(), + surfaceOrigin[1] + mContent.getHeight()); + // Determine new position for frame. + if (nodeFrame != null) { + surfaceOrigin[0] = 0; + surfaceOrigin[1] = 0; + mTargetFrame.getLocationInSurface(surfaceOrigin); + newBounds.set(surfaceOrigin[0], surfaceOrigin[1], + surfaceOrigin[0] + mTargetFrame.getWidth(), + surfaceOrigin[1] + mTargetFrame.getHeight()); + if (!currentFrameBounds.equals(newBounds)) { + currentFrameBounds.set(newBounds); + nodeFrame.setLeftTopRightBottom(currentFrameBounds.left, + currentFrameBounds.top, + currentFrameBounds.right, currentFrameBounds.bottom); + } + + // Draw frame + DisplayListCanvas canvas = nodeFrame.start(currentFrameBounds.width(), + currentFrameBounds.height()); + mFrameContent.draw(canvas); + nodeFrame.end(canvas); + } + + // Determine new position for backdrop + if (nodeBack != null) { + surfaceOrigin[0] = 0; + surfaceOrigin[1] = 0; + mTargetBack.getLocationInSurface(surfaceOrigin); + newBounds.set(surfaceOrigin[0], surfaceOrigin[1], + surfaceOrigin[0] + mTargetBack.getWidth(), + surfaceOrigin[1] + mTargetBack.getHeight()); + if (!currentBackBounds.equals(newBounds)) { + currentBackBounds.set(newBounds); + nodeBack.setLeftTopRightBottom(currentBackBounds.left, + currentBackBounds.top, + currentBackBounds.right, currentBackBounds.bottom); + } + + // Draw Backdrop + DisplayListCanvas canvas = nodeBack.start(currentBackBounds.width(), + currentBackBounds.height()); + mBackContent.draw(canvas); + nodeBack.end(canvas); + } + + // we need to only render one guy - the rest will happen automatically (I think). + if (nodeFrame != null) { + mRenderer.drawRenderNode(nodeFrame); + } + if (nodeBack != null) { + mRenderer.drawRenderNode(nodeBack); + } + try { + Thread.sleep(5); + } catch (InterruptedException e) {} + } + if (nodeFrame != null) { + mRenderer.removeRenderNode(nodeFrame); + } + if (nodeBack != null) { + mRenderer.removeRenderNode(nodeBack); + } + } + + public void destroy() { + mRunning = false; + try { + join(); + } catch (InterruptedException e) {} + } + } + + private final static Runnable sBlockThread = new Runnable() { + @Override + public void run() { + try { + Thread.sleep(DURATION); + } catch (InterruptedException e) { + } + } + }; + + static class ColorPulse extends Drawable { + + private int mColorStart; + private int mColorEnd; + private int mStep; + private Rect mRect; + private Paint mPaint = new Paint(); + + public ColorPulse(int color1, int color2, Rect rect) { + mColorStart = color1; + mColorEnd = color2; + if (rect != null) { + mRect = new Rect(rect.left + BORDER_WIDTH / 2, rect.top + BORDER_WIDTH / 2, + rect.right - BORDER_WIDTH / 2, rect.bottom - BORDER_WIDTH / 2); + } + } + + static int evaluate(float fraction, int startInt, int endInt) { + int startA = (startInt >> 24) & 0xff; + int startR = (startInt >> 16) & 0xff; + int startG = (startInt >> 8) & 0xff; + int startB = startInt & 0xff; + + int endA = (endInt >> 24) & 0xff; + int endR = (endInt >> 16) & 0xff; + int endG = (endInt >> 8) & 0xff; + int endB = endInt & 0xff; + + return (int)((startA + (int)(fraction * (endA - startA))) << 24) | + (int)((startR + (int)(fraction * (endR - startR))) << 16) | + (int)((startG + (int)(fraction * (endG - startG))) << 8) | + (int)((startB + (int)(fraction * (endB - startB)))); + } + + @Override + public void draw(Canvas canvas) { + float frac = mStep / 50.0f; + int color = evaluate(frac, mColorStart, mColorEnd); + if (mRect != null && !mRect.isEmpty()) { + mPaint.setStyle(Paint.Style.STROKE); + mPaint.setStrokeWidth(BORDER_WIDTH); + mPaint.setColor(color); + canvas.drawRect(mRect, mPaint); + } else { + canvas.drawColor(color); + } + + mStep++; + if (mStep >= 50) { + mStep = 0; + int tmp = mColorStart; + mColorStart = mColorEnd; + mColorEnd = tmp; + } + invalidateSelf(); + } + + @Override + public void setAlpha(int alpha) { + } + + @Override + public void setColorFilter(ColorFilter colorFilter) { + } + + @Override + public int getOpacity() { + return mRect == null || mRect.isEmpty() ? PixelFormat.OPAQUE : PixelFormat.TRANSLUCENT; + } + + } +} + diff --git a/tests/VectorDrawableTest/res/drawable/vector_drawable01.xml b/tests/VectorDrawableTest/res/drawable/vector_drawable01.xml index 705cc34ff62b..2be99bed4bfb 100644 --- a/tests/VectorDrawableTest/res/drawable/vector_drawable01.xml +++ b/tests/VectorDrawableTest/res/drawable/vector_drawable01.xml @@ -21,10 +21,14 @@ <group> <path + android:name="box0" + android:pathData="m0,0l480,0l0,480l-480,0l0-480z" + android:fillColor="@android:color/white" /> + <path android:name="box1" android:pathData="m20,200l100,90l180-180l-35-35l-145,145l-60-60l-40,40z" - android:fillColor="?android:attr/colorControlActivated" - android:strokeColor="?android:attr/colorControlActivated" + android:fillColor="?android:attr/colorControlNormal" + android:strokeColor="?android:attr/colorControlNormal" android:strokeLineCap="round" android:strokeLineJoin="round" /> </group> diff --git a/tests/VectorDrawableTest/src/com/android/test/dynamic/VectorDrawable01.java b/tests/VectorDrawableTest/src/com/android/test/dynamic/VectorDrawable01.java index a23d81933749..85fc452add3e 100644 --- a/tests/VectorDrawableTest/src/com/android/test/dynamic/VectorDrawable01.java +++ b/tests/VectorDrawableTest/src/com/android/test/dynamic/VectorDrawable01.java @@ -18,7 +18,12 @@ import android.graphics.drawable.VectorDrawable; import android.os.Bundle; import android.util.Log; import android.view.View; +import android.view.View.OnClickListener; +import android.view.ViewGroup; import android.widget.Button; +import android.widget.CheckBox; +import android.widget.CompoundButton; +import android.widget.CompoundButton.OnCheckedChangeListener; import android.widget.GridLayout; @SuppressWarnings({"UnusedDeclaration"}) @@ -55,6 +60,23 @@ public class VectorDrawable01 extends Activity { container.setBackgroundColor(0xFF888888); final Button []bArray = new Button[icon.length]; + CheckBox toggle = new CheckBox(this); + toggle.setText("Toggle"); + toggle.setChecked(true); + toggle.setOnCheckedChangeListener(new OnCheckedChangeListener() { + @Override + public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { + ViewGroup vg = (ViewGroup) buttonView.getParent(); + for (int i = 0, count = vg.getChildCount(); i < count; i++) { + View child = vg.getChildAt(i); + if (child != buttonView) { + child.setEnabled(isChecked); + } + } + } + }); + container.addView(toggle); + for (int i = 0; i < icon.length; i++) { Button button = new Button(this); bArray[i] = button; diff --git a/tools/layoutlib/bridge/src/android/content/res/BridgeResources.java b/tools/layoutlib/bridge/src/android/content/res/BridgeResources.java index 163fbcb7f900..3b7bf8549181 100644 --- a/tools/layoutlib/bridge/src/android/content/res/BridgeResources.java +++ b/tools/layoutlib/bridge/src/android/content/res/BridgeResources.java @@ -48,9 +48,6 @@ import java.io.FileNotFoundException; import java.io.InputStream; import java.util.Iterator; -/** - * - */ public final class BridgeResources extends Resources { private BridgeContext mContext; @@ -278,7 +275,7 @@ public final class BridgeResources extends Resources { * always Strings. The ideal signature for the method should be <T super String>, but java * generics don't support it. */ - private <T extends CharSequence> T[] fillValues(ArrayResourceValue resValue, T[] values) { + <T extends CharSequence> T[] fillValues(ArrayResourceValue resValue, T[] values) { int i = 0; for (Iterator<String> iterator = resValue.iterator(); iterator.hasNext(); i++) { @SuppressWarnings("unchecked") diff --git a/tools/layoutlib/bridge/src/android/content/res/BridgeTypedArray.java b/tools/layoutlib/bridge/src/android/content/res/BridgeTypedArray.java index 6a6109047573..31dd3d943769 100644 --- a/tools/layoutlib/bridge/src/android/content/res/BridgeTypedArray.java +++ b/tools/layoutlib/bridge/src/android/content/res/BridgeTypedArray.java @@ -16,6 +16,7 @@ package android.content.res; +import com.android.ide.common.rendering.api.ArrayResourceValue; import com.android.ide.common.rendering.api.AttrResourceValue; import com.android.ide.common.rendering.api.LayoutLog; import com.android.ide.common.rendering.api.RenderResources; @@ -33,6 +34,7 @@ import org.xmlpull.v1.XmlPullParser; import org.xmlpull.v1.XmlPullParserException; import android.annotation.Nullable; +import android.content.res.Resources.NotFoundException; import android.content.res.Resources.Theme; import android.graphics.drawable.Drawable; import android.util.DisplayMetrics; @@ -740,12 +742,20 @@ public final class BridgeTypedArray extends TypedArray { */ @Override public CharSequence[] getTextArray(int index) { - String value = getString(index); - if (value != null) { - return new CharSequence[] { value }; + if (!hasValue(index)) { + return null; } - - return null; + ResourceValue resVal = mResourceData[index]; + if (resVal instanceof ArrayResourceValue) { + ArrayResourceValue array = (ArrayResourceValue) resVal; + int count = array.getElementCount(); + return count >= 0 ? mBridgeResources.fillValues(array, new CharSequence[count]) : null; + } + int id = getResourceId(index, 0); + String resIdMessage = id > 0 ? " (resource id 0x" + Integer.toHexString(id) + ')' : ""; + throw new NotFoundException( + String.format("%1$s in %2$s%3$s is not a valid array resource.", + resVal.getValue(), mNames[index], resIdMessage)); } @Override diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/RenderSessionImpl.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/RenderSessionImpl.java index 24e1ce7db7ec..2a4f58381aee 100644 --- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/RenderSessionImpl.java +++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/RenderSessionImpl.java @@ -1050,11 +1050,7 @@ public class RenderSessionImpl extends RenderAction<SessionParams> { } if (scrollPos != 0) { view.scrollBy(0, scrollPos); - } else { - view.scrollBy(0, scrollPos); } - } else { - view.scrollBy(0, scrollPos); } if (!(view instanceof ViewGroup)) { diff --git a/wifi/java/android/net/wifi/IWifiManager.aidl b/wifi/java/android/net/wifi/IWifiManager.aidl index 0d95b38feb46..23be8e076174 100644 --- a/wifi/java/android/net/wifi/IWifiManager.aidl +++ b/wifi/java/android/net/wifi/IWifiManager.aidl @@ -23,6 +23,7 @@ import android.net.wifi.WifiInfo; import android.net.wifi.ScanSettings; import android.net.wifi.WifiChannel; import android.net.wifi.ScanResult; +import android.net.wifi.ScanInfo; import android.net.wifi.WifiConnectionStatistics; import android.net.wifi.WifiActivityEnergyInfo; import android.net.Network; @@ -70,6 +71,10 @@ interface IWifiManager void disconnect(); + List<ScanInfo> getScanInfos(String callingPackage); + + void setOsuSelection(int osuID); + void reconnect(); void reassociate(); diff --git a/wifi/java/android/net/wifi/ScanInfo.aidl b/wifi/java/android/net/wifi/ScanInfo.aidl new file mode 100644 index 000000000000..18ae5088146f --- /dev/null +++ b/wifi/java/android/net/wifi/ScanInfo.aidl @@ -0,0 +1,19 @@ +/** + * Copyright (c) 2015, The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.net.wifi; + +parcelable ScanInfo; diff --git a/wifi/java/android/net/wifi/ScanInfo.java b/wifi/java/android/net/wifi/ScanInfo.java new file mode 100644 index 000000000000..39186fa7a38a --- /dev/null +++ b/wifi/java/android/net/wifi/ScanInfo.java @@ -0,0 +1,189 @@ +package android.net.wifi; + +import android.os.Parcel; +import android.os.Parcelable; + +public class ScanInfo implements Parcelable { + private final ScanResult mScanResult; + + private final long mBSSID; // The BSSID of the best AP with an SSID matching the OSU + private final int mRSSI; // RSSI of the AP with BSSID + private final String mSSID; // The SSID to connect to for an OSU connection. + private final String mName; + private final String mServiceDescription; + private final String mIconType; + private final byte[] mIconData; + private final int mOSUIdentity; + + public ScanInfo(ScanResult scanResult) { + mScanResult = scanResult; + + mBSSID = -1; + mRSSI = -1; + mSSID = null; + mName = null; + mServiceDescription = null; + mIconType = null; + mIconData = null; + mOSUIdentity = -1; + } + + public ScanInfo(long BSSID, int rssi, String SSID, String name, String serviceDescription, + String iconType, byte[] iconData, int OSUIdentity) { + mBSSID = BSSID; + mRSSI = rssi; + mSSID = SSID; + mName = name; + mServiceDescription = serviceDescription; + mIconType = iconType; + mIconData = iconData; + mOSUIdentity = OSUIdentity; + + mScanResult = null; + } + + /** + * Get the scan result of this ScanInfo. + * @return The ScanResult, if this ScanInfo contains a one. If the ScanInfo contains + * OSU information getScanResult will return null. + */ + public ScanResult getScanResult() { + return mScanResult; + } + + /** + * OSU only: The BSSID of the AP who advertises the OSU SSID. This value is not guaranteed to + * be correct; In the somewhat unlikely case that multiple APs advertise OSU SSIDs that matches + * an OSU information element returned through ANQP and one of those is not related to an OSU + * there is a (slight) risk that the BSSID is for a "spoof" OSU. + * The matching algorithm that produces the ScanInfo objects makes a best effort to get the + * matching right though and since it is (a) fair to assume that the OSU SSID resides on the + * same AP as the one advertising the OSU information, and (b) BSSIDs for multi-SSID APs are + * typically adjacent to each other, matching will prefer the BSSID closest to the advertising + * APs BSSID if multiple SSIDs match. + * @return The BSSID. + */ + public long getBssid() { + return mBSSID; + } + + /** + * OSU only. + * @return The signal level of the AP associated with the BSSID from getBSSID. + */ + public int getRssi() { + return mRSSI; + } + + /** + * OSU only. + * @return The SSID of the AP to which to associate to establish an OSU connection. + */ + public String getSsid() { + return mSSID; + } + + /** + * OSU only. + * @return The name of the Service Provider of the OSU. + */ + public String getName() { + return mName; + } + + /** + * OSU only. + * @return The service description of the OSU. + */ + public String getServiceDescription() { + return mServiceDescription; + } + + /** + * OSU only. + * Get the type of icon that icon data represents, e.g. JPG, PNG etc. This field is formatted + * using standard MIME encodings per RFC-4288 and IANA MIME media types. + * @return The icon type in icon data. + */ + public String getIconType() { + return mIconType; + } + + /** + * OSU only. + * @return The binary data of the icon. + */ + public byte[] getIconData() { + return mIconData; + } + + /** + * OSU only. + * @return a unique identity for the OSU. This value is generated by the framework and should + * be used to uniquely identify a specific OSU. Please note that values may be reused after + * a very long time-span (in any normal scenario, likely years) and implementations should make + * sure to not rely on any long term persisted values. + */ + public int getOsuIdentity() { + return mOSUIdentity; + } + + private static final int ScanResultMarker = 0; + private static final int OSUMarker = 1; + + @Override + public int describeContents() { + return 0; + } + + /** Implement the Parcelable interface {@hide} */ + public static final Creator<ScanInfo> CREATOR = + new Creator<ScanInfo>() { + @Override + public ScanInfo createFromParcel(Parcel source) { + int marker = source.readInt(); + if (marker == ScanResultMarker) { + return new ScanInfo(ScanResult.CREATOR.createFromParcel(source)); + } + else if (marker == OSUMarker) { + return new ScanInfo( + source.readLong(), + source.readInt(), + source.readString(), + source.readString(), + source.readString(), + source.readString(), + source.createByteArray(), + source.readInt() + ); + } + else { + throw new RuntimeException("Bad ScanInfo data"); + } + } + + @Override + public ScanInfo[] newArray(int size) { + return new ScanInfo[0]; + } + }; + + @Override + public void writeToParcel(Parcel dest, int flags) { + if (mScanResult != null) { + dest.writeInt(ScanResultMarker); + mScanResult.writeToParcel(dest, flags); + return; + } + + dest.writeInt(OSUMarker); + dest.writeLong(mBSSID); + dest.writeInt(mRSSI); + dest.writeString(mSSID); + dest.writeString(mName); + dest.writeString(mServiceDescription); + dest.writeString(mIconType); + dest.writeByteArray(mIconData); + dest.writeInt(mOSUIdentity); + } +} diff --git a/wifi/java/android/net/wifi/WifiManager.java b/wifi/java/android/net/wifi/WifiManager.java index cf88df42f8d3..ff8d6d4d09aa 100644 --- a/wifi/java/android/net/wifi/WifiManager.java +++ b/wifi/java/android/net/wifi/WifiManager.java @@ -1315,6 +1315,30 @@ public class WifiManager { } /** + * An augmented version of getScanResults that returns ScanResults as well as OSU information + * wrapped in ScanInfo objects. + * @return + */ + public List<ScanInfo> getScanInfos() { + try { + return mService.getScanInfos(mContext.getOpPackageName()); + } catch (RemoteException e) { + return null; + } + } + + /** + * Notify the OSU framework about the currently selected OSU. + * @param osuID The OSU ID from ScanInfo.getOsuIdentity() + */ + public void setOsuSelection(int osuID) { + try { + mService.setOsuSelection(osuID); + } catch (RemoteException e) { + } + } + + /** * Check if scanning is always available. * * If this return {@code true}, apps can issue {@link #startScan} and fetch scan results |