Merge "media: update AMessage to use handler instead of handler-id"
diff --git a/api/current.txt b/api/current.txt
index d688820..c36d03f 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -3545,6 +3545,7 @@
method public int getLargeMemoryClass();
method public int getLauncherLargeIconDensity();
method public int getLauncherLargeIconSize();
+ method public int getLockTaskModeState();
method public int getMemoryClass();
method public void getMemoryInfo(android.app.ActivityManager.MemoryInfo);
method public static void getMyMemoryState(android.app.ActivityManager.RunningAppProcessInfo);
@@ -3555,7 +3556,7 @@
method public android.app.PendingIntent getRunningServiceControlPanel(android.content.ComponentName) throws java.lang.SecurityException;
method public java.util.List<android.app.ActivityManager.RunningServiceInfo> getRunningServices(int) throws java.lang.SecurityException;
method public deprecated java.util.List<android.app.ActivityManager.RunningTaskInfo> getRunningTasks(int) throws java.lang.SecurityException;
- method public boolean isInLockTaskMode();
+ method public deprecated boolean isInLockTaskMode();
method public boolean isLowRamDevice();
method public static boolean isRunningInTestHarness();
method public static boolean isUserAMonkey();
@@ -3563,6 +3564,9 @@
method public void moveTaskToFront(int, int);
method public void moveTaskToFront(int, int, android.os.Bundle);
method public deprecated void restartPackage(java.lang.String);
+ field public static final int LOCK_TASK_MODE_LOCKED = 1; // 0x1
+ field public static final int LOCK_TASK_MODE_NONE = 0; // 0x0
+ field public static final int LOCK_TASK_MODE_PINNED = 2; // 0x2
field public static final java.lang.String META_HOME_ALTERNATE = "android.app.home.alternate";
field public static final int MOVE_TASK_NO_USER_ACTION = 2; // 0x2
field public static final int MOVE_TASK_WITH_HOME = 1; // 0x1
@@ -5454,7 +5458,7 @@
method public void addPersistentPreferredActivity(android.content.ComponentName, android.content.IntentFilter, android.content.ComponentName);
method public void addUserRestriction(android.content.ComponentName, java.lang.String);
method public void clearCrossProfileIntentFilters(android.content.ComponentName);
- method public void clearDeviceInitializerApp();
+ method public void clearDeviceInitializerApp(android.content.ComponentName);
method public void clearDeviceOwnerApp(java.lang.String);
method public void clearPackagePersistentPreferredActivities(android.content.ComponentName, java.lang.String);
method public void clearUserRestriction(android.content.ComponentName, java.lang.String);
@@ -5543,6 +5547,7 @@
method public int setStorageEncryption(android.content.ComponentName, boolean);
method public void setUninstallBlocked(android.content.ComponentName, java.lang.String, boolean);
method public boolean setUserEnabled(android.content.ComponentName);
+ method public void setUserIcon(android.content.ComponentName, android.graphics.Bitmap);
method public boolean switchUser(android.content.ComponentName, android.os.UserHandle);
method public void uninstallAllUserCaCerts(android.content.ComponentName);
method public void uninstallCaCert(android.content.ComponentName, byte[]);
@@ -24910,6 +24915,7 @@
field public static final int ORGANIZATION = 30; // 0x1e
field public static final int PHONE = 20; // 0x14
field public static final int STRUCTURED_NAME = 40; // 0x28
+ field public static final int STRUCTURED_PHONETIC_NAME = 37; // 0x25
field public static final int UNDEFINED = 0; // 0x0
}
@@ -29325,6 +29331,7 @@
}
public class TelephonyManager {
+ method public boolean canChangeDtmfToneLength();
method public java.util.List<android.telephony.CellInfo> getAllCellInfo();
method public int getCallState();
method public android.telephony.CellLocation getCellLocation();
@@ -29360,6 +29367,7 @@
method public boolean isNetworkRoaming();
method public boolean isSmsCapable();
method public boolean isVoiceCapable();
+ method public boolean isWorldPhone();
method public void listen(android.telephony.PhoneStateListener, int);
method public java.lang.String sendEnvelopeWithStatus(java.lang.String);
method public boolean setLine1NumberForDisplay(java.lang.String, java.lang.String);
diff --git a/api/system-current.txt b/api/system-current.txt
index f06ff1f..52098e6 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -3633,6 +3633,7 @@
method public int getLargeMemoryClass();
method public int getLauncherLargeIconDensity();
method public int getLauncherLargeIconSize();
+ method public int getLockTaskModeState();
method public int getMemoryClass();
method public void getMemoryInfo(android.app.ActivityManager.MemoryInfo);
method public static void getMyMemoryState(android.app.ActivityManager.RunningAppProcessInfo);
@@ -3643,7 +3644,7 @@
method public android.app.PendingIntent getRunningServiceControlPanel(android.content.ComponentName) throws java.lang.SecurityException;
method public java.util.List<android.app.ActivityManager.RunningServiceInfo> getRunningServices(int) throws java.lang.SecurityException;
method public deprecated java.util.List<android.app.ActivityManager.RunningTaskInfo> getRunningTasks(int) throws java.lang.SecurityException;
- method public boolean isInLockTaskMode();
+ method public deprecated boolean isInLockTaskMode();
method public boolean isLowRamDevice();
method public static boolean isRunningInTestHarness();
method public static boolean isUserAMonkey();
@@ -3651,6 +3652,9 @@
method public void moveTaskToFront(int, int);
method public void moveTaskToFront(int, int, android.os.Bundle);
method public deprecated void restartPackage(java.lang.String);
+ field public static final int LOCK_TASK_MODE_LOCKED = 1; // 0x1
+ field public static final int LOCK_TASK_MODE_NONE = 0; // 0x0
+ field public static final int LOCK_TASK_MODE_PINNED = 2; // 0x2
field public static final java.lang.String META_HOME_ALTERNATE = "android.app.home.alternate";
field public static final int MOVE_TASK_NO_USER_ACTION = 2; // 0x2
field public static final int MOVE_TASK_WITH_HOME = 1; // 0x1
@@ -5548,7 +5552,7 @@
method public void addPersistentPreferredActivity(android.content.ComponentName, android.content.IntentFilter, android.content.ComponentName);
method public void addUserRestriction(android.content.ComponentName, java.lang.String);
method public void clearCrossProfileIntentFilters(android.content.ComponentName);
- method public void clearDeviceInitializerApp();
+ method public void clearDeviceInitializerApp(android.content.ComponentName);
method public void clearDeviceOwnerApp(java.lang.String);
method public void clearPackagePersistentPreferredActivities(android.content.ComponentName, java.lang.String);
method public void clearProfileOwner(android.content.ComponentName);
@@ -5645,6 +5649,7 @@
method public int setStorageEncryption(android.content.ComponentName, boolean);
method public void setUninstallBlocked(android.content.ComponentName, java.lang.String, boolean);
method public boolean setUserEnabled(android.content.ComponentName);
+ method public void setUserIcon(android.content.ComponentName, android.graphics.Bitmap);
method public boolean switchUser(android.content.ComponentName, android.os.UserHandle);
method public void uninstallAllUserCaCerts(android.content.ComponentName);
method public void uninstallCaCert(android.content.ComponentName, byte[]);
@@ -26510,6 +26515,7 @@
field public static final int ORGANIZATION = 30; // 0x1e
field public static final int PHONE = 20; // 0x14
field public static final int STRUCTURED_NAME = 40; // 0x28
+ field public static final int STRUCTURED_PHONETIC_NAME = 37; // 0x25
field public static final int UNDEFINED = 0; // 0x0
}
@@ -31452,6 +31458,7 @@
public class TelephonyManager {
method public void answerRingingCall();
method public void call(java.lang.String, java.lang.String);
+ method public boolean canChangeDtmfToneLength();
method public int checkCarrierPrivilegesForPackage(java.lang.String);
method public void dial(java.lang.String);
method public boolean disableDataConnectivity();
@@ -31511,6 +31518,7 @@
method public boolean isSmsCapable();
method public boolean isVideoCallingEnabled();
method public boolean isVoiceCapable();
+ method public boolean isWorldPhone();
method public void listen(android.telephony.PhoneStateListener, int);
method public boolean needsOtaServiceProvisioning();
method public java.lang.String sendEnvelopeWithStatus(java.lang.String);
diff --git a/cmds/settings/src/com/android/commands/settings/SettingsCmd.java b/cmds/settings/src/com/android/commands/settings/SettingsCmd.java
index a31b150..c27d0c0 100644
--- a/cmds/settings/src/com/android/commands/settings/SettingsCmd.java
+++ b/cmds/settings/src/com/android/commands/settings/SettingsCmd.java
@@ -20,6 +20,7 @@
import android.app.IActivityManager;
import android.app.IActivityManager.ContentProviderHolder;
import android.content.IContentProvider;
+import android.database.Cursor;
import android.net.Uri;
import android.os.Binder;
import android.os.Bundle;
@@ -29,13 +30,18 @@
import android.os.UserHandle;
import android.provider.Settings;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
public final class SettingsCmd {
enum CommandVerb {
UNSPECIFIED,
GET,
PUT,
- DELETE
+ DELETE,
+ LIST,
}
static String[] mArgs;
@@ -47,7 +53,7 @@
String mValue = null;
public static void main(String[] args) {
- if (args == null || args.length < 3) {
+ if (args == null || args.length < 2) {
printUsage();
return;
}
@@ -78,6 +84,8 @@
mVerb = CommandVerb.PUT;
} else if ("delete".equalsIgnoreCase(arg)) {
mVerb = CommandVerb.DELETE;
+ } else if ("list".equalsIgnoreCase(arg)) {
+ mVerb = CommandVerb.LIST;
} else {
// invalid
System.err.println("Invalid command: " + arg);
@@ -91,6 +99,10 @@
break; // invalid
}
mTable = arg.toLowerCase();
+ if (mVerb == CommandVerb.LIST) {
+ valid = true;
+ break;
+ }
} else if (mVerb == CommandVerb.GET || mVerb == CommandVerb.DELETE) {
mKey = arg;
if (mNextArg >= mArgs.length) {
@@ -144,6 +156,11 @@
System.out.println("Deleted "
+ deleteForUser(provider, mUser, mTable, mKey) + " rows");
break;
+ case LIST:
+ for (String line : listForUser(provider, mUser, mTable)) {
+ System.out.println(line);
+ }
+ break;
default:
System.err.println("Unspecified command");
break;
@@ -164,6 +181,34 @@
}
}
+ private List<String> listForUser(IContentProvider provider, int userHandle, String table) {
+ final Uri uri = "system".equals(table) ? Settings.System.CONTENT_URI
+ : "secure".equals(table) ? Settings.Secure.CONTENT_URI
+ : "global".equals(table) ? Settings.Global.CONTENT_URI
+ : null;
+ final ArrayList<String> lines = new ArrayList<String>();
+ if (uri == null) {
+ return lines;
+ }
+ try {
+ final Cursor cursor = provider.query(resolveCallingPackage(), uri, null, null, null,
+ null, null);
+ try {
+ while (cursor != null && cursor.moveToNext()) {
+ lines.add(cursor.getString(1) + "=" + cursor.getString(2));
+ }
+ } finally {
+ if (cursor != null) {
+ cursor.close();
+ }
+ }
+ Collections.sort(lines);
+ } catch (RemoteException e) {
+ System.err.println("List failed in " + table + " for user " + userHandle);
+ }
+ return lines;
+ }
+
private String nextArg() {
if (mNextArg >= mArgs.length) {
return null;
@@ -244,6 +289,7 @@
System.err.println("usage: settings [--user NUM] get namespace key");
System.err.println(" settings [--user NUM] put namespace key value");
System.err.println(" settings [--user NUM] delete namespace key");
+ System.err.println(" settings [--user NUM] list namespace");
System.err.println("\n'namespace' is one of {system, secure, global}, case-insensitive");
System.err.println("If '--user NUM' is not given, the operations are performed on the owner user.");
}
diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java
index c6ffef6..c525ef2 100644
--- a/core/java/android/app/ActivityManager.java
+++ b/core/java/android/app/ActivityManager.java
@@ -309,6 +309,21 @@
/** @hide Process is being cached for later use and is empty. */
public static final int PROCESS_STATE_CACHED_EMPTY = 13;
+ /**
+ * Lock task mode is not active.
+ */
+ public static final int LOCK_TASK_MODE_NONE = 0;
+
+ /**
+ * Full lock task mode is active.
+ */
+ public static final int LOCK_TASK_MODE_LOCKED = 1;
+
+ /**
+ * App pinning mode is active.
+ */
+ public static final int LOCK_TASK_MODE_PINNED = 2;
+
Point mAppTaskThumbnailSize;
/*package*/ ActivityManager(Context context, Handler handler) {
@@ -2684,12 +2699,25 @@
* no new tasks can be created or switched to.
*
* @see Activity#startLockTask()
+ *
+ * @deprecated Use {@link #getLockTaskModeState} instead.
*/
public boolean isInLockTaskMode() {
+ return getLockTaskModeState() != LOCK_TASK_MODE_NONE;
+ }
+
+ /**
+ * Return the current state of task locking. The three possible outcomes
+ * are {@link #LOCK_TASK_MODE_NONE}, {@link #LOCK_TASK_MODE_LOCKED}
+ * and {@link #LOCK_TASK_MODE_PINNED}.
+ *
+ * @see Activity#startLockTask()
+ */
+ public int getLockTaskModeState() {
try {
- return ActivityManagerNative.getDefault().isInLockTaskMode();
+ return ActivityManagerNative.getDefault().getLockTaskModeState();
} catch (RemoteException e) {
- return false;
+ return ActivityManager.LOCK_TASK_MODE_NONE;
}
}
diff --git a/core/java/android/app/ActivityManagerNative.java b/core/java/android/app/ActivityManagerNative.java
index bb307bb..3197461 100644
--- a/core/java/android/app/ActivityManagerNative.java
+++ b/core/java/android/app/ActivityManagerNative.java
@@ -2294,6 +2294,14 @@
return true;
}
+ case GET_LOCK_TASK_MODE_STATE_TRANSACTION: {
+ data.enforceInterface(IActivityManager.descriptor);
+ final int lockTaskModeState = getLockTaskModeState();
+ reply.writeNoException();
+ reply.writeInt(lockTaskModeState);
+ return true;
+ }
+
case SET_TASK_DESCRIPTION_TRANSACTION: {
data.enforceInterface(IActivityManager.descriptor);
IBinder token = data.readStrongBinder();
@@ -5420,6 +5428,19 @@
}
@Override
+ public int getLockTaskModeState() throws RemoteException {
+ Parcel data = Parcel.obtain();
+ Parcel reply = Parcel.obtain();
+ data.writeInterfaceToken(IActivityManager.descriptor);
+ mRemote.transact(GET_LOCK_TASK_MODE_STATE_TRANSACTION, data, reply, 0);
+ reply.readException();
+ int lockTaskModeState = reply.readInt();
+ data.recycle();
+ reply.recycle();
+ return lockTaskModeState;
+ }
+
+ @Override
public void setTaskDescription(IBinder token, ActivityManager.TaskDescription values)
throws RemoteException {
Parcel data = Parcel.obtain();
diff --git a/core/java/android/app/IActivityManager.java b/core/java/android/app/IActivityManager.java
index a7e9413..1277cfa 100644
--- a/core/java/android/app/IActivityManager.java
+++ b/core/java/android/app/IActivityManager.java
@@ -461,6 +461,8 @@
public boolean isInLockTaskMode() throws RemoteException;
+ public int getLockTaskModeState() throws RemoteException;
+
public void setTaskDescription(IBinder token, ActivityManager.TaskDescription values)
throws RemoteException;
public void setTaskResizeable(int taskId, boolean resizeable) throws RemoteException;
@@ -810,4 +812,5 @@
int SET_TASK_RESIZEABLE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+283;
int REQUEST_ASSIST_CONTEXT_EXTRAS_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+284;
int RESIZE_TASK_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+285;
+ int GET_LOCK_TASK_MODE_STATE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+286;
}
diff --git a/core/java/android/app/admin/DeviceAdminReceiver.java b/core/java/android/app/admin/DeviceAdminReceiver.java
index 6d4a0ff..fe284ce 100644
--- a/core/java/android/app/admin/DeviceAdminReceiver.java
+++ b/core/java/android/app/admin/DeviceAdminReceiver.java
@@ -168,8 +168,8 @@
/**
* Action sent to a device administrator to notify that the device is entering
- * lock task mode from an authorized package. The extra {@link #EXTRA_LOCK_TASK_PACKAGE}
- * will describe the authorized package using lock task mode.
+ * lock task mode. The extra {@link #EXTRA_LOCK_TASK_PACKAGE}
+ * will describe the package using lock task mode.
*
* <p>The calling device admin must be the device owner or profile
* owner to receive this broadcast.
@@ -182,7 +182,7 @@
/**
* Action sent to a device administrator to notify that the device is exiting
- * lock task mode from an authorized package.
+ * lock task mode.
*
* <p>The calling device admin must be the device owner or profile
* owner to receive this broadcast.
@@ -447,8 +447,7 @@
}
/**
- * Called when a device is entering lock task mode by a package authorized
- * by {@link DevicePolicyManager#isLockTaskPermitted(String)}
+ * Called when a device is entering lock task mode.
*
* @param context The running context as per {@link #onReceive}.
* @param intent The received intent as per {@link #onReceive}.
@@ -458,8 +457,7 @@
}
/**
- * Called when a device is exiting lock task mode by a package authorized
- * by {@link DevicePolicyManager#isLockTaskPermitted(String)}
+ * Called when a device is exiting lock task mode.
*
* @param context The running context as per {@link #onReceive}.
* @param intent The received intent as per {@link #onReceive}.
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index add7130..c708859 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -28,6 +28,7 @@
import android.content.pm.ActivityInfo;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
+import android.graphics.Bitmap;
import android.net.ProxyInfo;
import android.os.Bundle;
import android.os.Handler;
@@ -2476,12 +2477,14 @@
/**
* Removes the device initializer, so that it will not be invoked on user initialization for any
* subsequently created users. This method can be called by either the device owner or device
- * initializer itself.
+ * initializer itself. The caller must be an active administrator.
+ *
+ * @param who Which {@link DeviceAdminReceiver} this request is associated with.
*/
- public void clearDeviceInitializerApp() {
+ public void clearDeviceInitializerApp(ComponentName who) {
if (mService != null) {
try {
- mService.clearDeviceInitializer(mContext.getPackageName());
+ mService.clearDeviceInitializer(who);
} catch (RemoteException re) {
Log.w(TAG, "Failed to clear device initializer");
}
@@ -3740,4 +3743,18 @@
}
return Collections.emptyList();
}
+
+ /**
+ * Called by profile or device owners to set the current user's photo.
+ *
+ * @param admin Which {@link DeviceAdminReceiver} this request is associated with.
+ * @param icon the bitmap to set as the photo.
+ */
+ public void setUserIcon(ComponentName admin, Bitmap icon) {
+ try {
+ mService.setUserIcon(admin, icon);
+ } catch (RemoteException re) {
+ Log.w(TAG, "Could not set the user icon ", re);
+ }
+ }
}
diff --git a/core/java/android/app/admin/IDevicePolicyManager.aidl b/core/java/android/app/admin/IDevicePolicyManager.aidl
index 5e58fe0..f69cf36 100644
--- a/core/java/android/app/admin/IDevicePolicyManager.aidl
+++ b/core/java/android/app/admin/IDevicePolicyManager.aidl
@@ -20,6 +20,7 @@
import android.content.ComponentName;
import android.content.Intent;
import android.content.IntentFilter;
+import android.graphics.Bitmap;
import android.net.ProxyInfo;
import android.os.Bundle;
import android.os.PersistableBundle;
@@ -202,7 +203,9 @@
boolean setUserEnabled(in ComponentName who);
boolean isDeviceInitializer(String packageName);
- void clearDeviceInitializer(String packageName);
+ void clearDeviceInitializer(in ComponentName who);
boolean setDeviceInitializer(in ComponentName who, in ComponentName initializer, String initializerName);
String getDeviceInitializer();
+
+ void setUserIcon(in ComponentName admin, in Bitmap icon);
}
diff --git a/core/java/android/provider/ContactsContract.java b/core/java/android/provider/ContactsContract.java
index 9cc12b5..cc7783f 100644
--- a/core/java/android/provider/ContactsContract.java
+++ b/core/java/android/provider/ContactsContract.java
@@ -1010,7 +1010,8 @@
/**
* Types of data used to produce the display name for a contact. In the order
* of increasing priority: {@link #EMAIL}, {@link #PHONE},
- * {@link #ORGANIZATION}, {@link #NICKNAME}, {@link #STRUCTURED_NAME}.
+ * {@link #ORGANIZATION}, {@link #NICKNAME}, {@link #STRUCTURED_PHONETIC_NAME},
+ * {@link #STRUCTURED_NAME}.
*/
public interface DisplayNameSources {
public static final int UNDEFINED = 0;
@@ -1018,6 +1019,8 @@
public static final int PHONE = 20;
public static final int ORGANIZATION = 30;
public static final int NICKNAME = 35;
+ /** Display name comes from a structured name that only has phonetic components. */
+ public static final int STRUCTURED_PHONETIC_NAME = 37;
public static final int STRUCTURED_NAME = 40;
}
diff --git a/core/java/android/text/StaticLayout.java b/core/java/android/text/StaticLayout.java
index d1caa43..967e80c 100644
--- a/core/java/android/text/StaticLayout.java
+++ b/core/java/android/text/StaticLayout.java
@@ -28,6 +28,7 @@
import com.android.internal.util.GrowingArrayUtils;
import java.util.Arrays;
+import java.util.Locale;
/**
* StaticLayout is a Layout for text that will not be edited after it
@@ -51,6 +52,10 @@
* @hide
*/
public final static class Builder {
+ private Builder() {
+ mNativePtr = nNewBuilder();
+ }
+
static Builder obtain() {
Builder b = null;
synchronized (sLock) {
@@ -96,6 +101,7 @@
// release any expensive state
/* package */ void finish() {
+ nFinishBuilder(mNativePtr);
mMeasuredText.finish();
}
@@ -160,6 +166,14 @@
return this;
}
+ /* @hide */
+ public void setLocale(Locale locale) {
+ if (!locale.equals(mLocale)) {
+ nBuilderSetLocale(mNativePtr, locale.toLanguageTag());
+ mLocale = locale;
+ }
+ }
+
public StaticLayout build() {
// TODO: can optimize based on whether ellipsis is needed
StaticLayout result = new StaticLayout(mText);
@@ -168,6 +182,17 @@
return result;
}
+ @Override
+ protected void finalize() throws Throwable {
+ try {
+ nFreeBuilder(mNativePtr);
+ } finally {
+ super.finalize();
+ }
+ }
+
+ /* package */ long mNativePtr;
+
CharSequence mText;
int mStart;
int mEnd;
@@ -186,6 +211,8 @@
// This will go away and be subsumed by native builder code
MeasuredText mMeasuredText;
+ Locale mLocale;
+
private static final Object sLock = new Object();
private static final Builder[] sCached = new Builder[3];
}
@@ -322,13 +349,13 @@
float spacingadd = b.mSpacingAdd;
float ellipsizedWidth = b.mEllipsizedWidth;
TextUtils.TruncateAt ellipsize = b.mEllipsize;
- LineBreaks lineBreaks = new LineBreaks();
+ LineBreaks lineBreaks = new LineBreaks(); // TODO: move to builder to avoid allocation costs
// store span end locations
int[] spanEndCache = new int[4];
// store fontMetrics per span range
// must be a multiple of 4 (and > 0) (store top, bottom, ascent, and descent per range)
int[] fmCache = new int[4 * 4];
- final String localeLanguageTag = paint.getTextLocale().toLanguageTag();
+ b.setLocale(paint.getTextLocale()); // TODO: also respect LocaleSpan within the text
mLineCount = 0;
@@ -466,7 +493,7 @@
}
}
- int breakCount = nComputeLineBreaks(localeLanguageTag, chs, widths, paraEnd - paraStart, firstWidth,
+ int breakCount = nComputeLineBreaks(b.mNativePtr, chs, widths, paraEnd - paraStart, firstWidth,
firstWidthLineCount, restWidth, variableTabStops, TAB_INCREMENT, false, lineBreaks,
lineBreaks.breaks, lineBreaks.widths, lineBreaks.flags, lineBreaks.breaks.length);
@@ -911,11 +938,16 @@
// the arrays inside the LineBreaks objects are passed in as well
// to reduce the number of JNI calls in the common case where the
// arrays do not have to be resized
- private static native int nComputeLineBreaks(String locale, char[] text, float[] widths,
+ private static native int nComputeLineBreaks(long nativePtr, char[] text, float[] widths,
int length, float firstWidth, int firstWidthLineCount, float restWidth,
int[] variableTabStops, int defaultTabStop, boolean optimize, LineBreaks recycle,
int[] recycleBreaks, float[] recycleWidths, boolean[] recycleFlags, int recycleLength);
+ private static native long nNewBuilder();
+ private static native void nFreeBuilder(long nativePtr);
+ private static native void nFinishBuilder(long nativePtr);
+ private static native void nBuilderSetLocale(long nativePtr, String locale);
+
private int mLineCount;
private int mTopPadding, mBottomPadding;
private int mColumns;
diff --git a/core/java/android/util/ArraySet.java b/core/java/android/util/ArraySet.java
index 68f725e..7da3941 100644
--- a/core/java/android/util/ArraySet.java
+++ b/core/java/android/util/ArraySet.java
@@ -475,6 +475,26 @@
}
/**
+ * Perform a {@link #remove(Object)} of all values in <var>array</var>
+ * @param array The array whose contents are to be removed.
+ */
+ public boolean removeAll(ArraySet<? extends E> array) {
+ // TODO: If array is sufficiently large, a marking approach might be beneficial. In a first
+ // pass, use the property that the sets are sorted by hash to make this linear passes
+ // (except for hash collisions, which means worst case still n*m), then do one
+ // collection pass into a new array. This avoids binary searches and excessive memcpy.
+ final int N = array.mSize;
+
+ // Note: ArraySet does not make thread-safety guarantees. So instead of OR-ing together all
+ // the single results, compare size before and after.
+ final int originalSize = mSize;
+ for (int i = 0; i < N; i++) {
+ remove(array.valueAt(i));
+ }
+ return originalSize != mSize;
+ }
+
+ /**
* Return the number of items in this array map.
*/
@Override
diff --git a/core/java/android/view/GLES20Canvas.java b/core/java/android/view/GLES20Canvas.java
index 0d36949..06e196d 100644
--- a/core/java/android/view/GLES20Canvas.java
+++ b/core/java/android/view/GLES20Canvas.java
@@ -204,7 +204,7 @@
Bitmap bitmap = patch.getBitmap();
throwIfCannotDraw(bitmap);
final long nativePaint = paint == null ? 0 : paint.getNativeInstance();
- nDrawPatch(mNativeCanvasWrapper, bitmap.mNativeBitmap, patch.mNativeChunk,
+ nDrawPatch(mNativeCanvasWrapper, bitmap.getSkBitmap(), patch.mNativeChunk,
dst.left, dst.top, dst.right, dst.bottom, nativePaint);
}
@@ -214,7 +214,7 @@
Bitmap bitmap = patch.getBitmap();
throwIfCannotDraw(bitmap);
final long nativePaint = paint == null ? 0 : paint.getNativeInstance();
- nDrawPatch(mNativeCanvasWrapper, bitmap.mNativeBitmap, patch.mNativeChunk,
+ nDrawPatch(mNativeCanvasWrapper, bitmap.getSkBitmap(), patch.mNativeChunk,
dst.left, dst.top, dst.right, dst.bottom, nativePaint);
}
diff --git a/core/java/android/view/ThreadedRenderer.java b/core/java/android/view/ThreadedRenderer.java
index df0838f..69b4c47 100644
--- a/core/java/android/view/ThreadedRenderer.java
+++ b/core/java/android/view/ThreadedRenderer.java
@@ -364,7 +364,7 @@
@Override
boolean copyLayerInto(final HardwareLayer layer, final Bitmap bitmap) {
return nCopyLayerInto(mNativeProxy,
- layer.getDeferredLayerUpdater(), bitmap.mNativeBitmap);
+ layer.getDeferredLayerUpdater(), bitmap.getSkBitmap());
}
@Override
@@ -465,7 +465,7 @@
for (int i = 0; i < count; i++) {
drawables.valueAt(i).addAtlasableBitmaps(tmpList);
for (int j = 0; j < tmpList.size(); j++) {
- preloadedPointers.add(tmpList.get(j).mNativeBitmap);
+ preloadedPointers.add(tmpList.get(j).getSkBitmap());
}
tmpList.clear();
}
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index f25b640..4b3765a 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -5849,7 +5849,7 @@
*
* @see AccessibilityDelegate
*/
- public void setAccessibilityDelegate(AccessibilityDelegate delegate) {
+ public void setAccessibilityDelegate(@Nullable AccessibilityDelegate delegate) {
mAccessibilityDelegate = delegate;
}
diff --git a/core/java/android/widget/Editor.java b/core/java/android/widget/Editor.java
index f8e207f..5d519ed 100644
--- a/core/java/android/widget/Editor.java
+++ b/core/java/android/widget/Editor.java
@@ -217,6 +217,12 @@
WordIterator mWordIterator;
SpellChecker mSpellChecker;
+ // This word iterator is set with text and used to determine word boundaries
+ // when a user is selecting text.
+ private WordIterator mWordIteratorWithText;
+ // Indicate that the text in the word iterator needs to be updated.
+ private boolean mUpdateWordIteratorText;
+
private Rect mTempRect;
private TextView mTextView;
@@ -689,9 +695,52 @@
return mTextView.getTransformationMethod() instanceof PasswordTransformationMethod;
}
+ private int getWordStart(int offset) {
+ // FIXME - For this and similar methods we're not doing anything to check if there's
+ // a LocaleSpan in the text, this may be something we should try handling or checking for.
+ int retOffset = getWordIteratorWithText().getBeginning(offset);
+ if (retOffset == BreakIterator.DONE) retOffset = offset;
+ return retOffset;
+ }
+
+ private int getWordEnd(int offset, boolean includePunctuation) {
+ int retOffset = getWordIteratorWithText().getEnd(offset);
+ if (retOffset == BreakIterator.DONE) {
+ retOffset = offset;
+ } else if (includePunctuation) {
+ retOffset = handlePunctuation(retOffset);
+ }
+ return retOffset;
+ }
+
+ private boolean isEndBoundary(int offset) {
+ int thisEnd = getWordEnd(offset, false);
+ return offset == thisEnd;
+ }
+
+ private boolean isStartBoundary(int offset) {
+ int thisStart = getWordStart(offset);
+ return thisStart == offset;
+ }
+
+ private int handlePunctuation(int offset) {
+ // FIXME - Check with UX how repeated ending punctuation should be handled.
+ // FIXME - Check with UX if / how we would handle non sentence ending characters.
+ // FIXME - Consider punctuation in different languages.
+ CharSequence text = mTextView.getText();
+ if (offset < text.length()) {
+ int c = Character.codePointAt(text, offset);
+ if (c == 0x002e /* period */|| c == 0x003f /* question mark */
+ || c == 0x0021 /* exclamation mark */) {
+ offset = Character.offsetByCodePoints(text, offset, 1);
+ }
+ }
+ return offset;
+ }
+
/**
- * Adjusts selection to the word under last touch offset.
- * Return true if the operation was successfully performed.
+ * Adjusts selection to the word under last touch offset. Return true if the operation was
+ * successfully performed.
*/
private boolean selectCurrentWord() {
if (!canSelectText()) {
@@ -738,6 +787,8 @@
selectionStart = ((Spanned) mTextView.getText()).getSpanStart(urlSpan);
selectionEnd = ((Spanned) mTextView.getText()).getSpanEnd(urlSpan);
} else {
+ // FIXME - We should check if there's a LocaleSpan in the text, this may be
+ // something we should try handling or checking for.
final WordIterator wordIterator = getWordIterator();
wordIterator.setCharSequence(mTextView.getText(), minOffset, maxOffset);
@@ -760,6 +811,7 @@
void onLocaleChanged() {
// Will be re-created on demand in getWordIterator with the proper new locale
mWordIterator = null;
+ mWordIteratorWithText = null;
}
/**
@@ -772,6 +824,23 @@
return mWordIterator;
}
+ private WordIterator getWordIteratorWithText() {
+ if (mWordIteratorWithText == null) {
+ mWordIteratorWithText = new WordIterator(mTextView.getTextServicesLocale());
+ mUpdateWordIteratorText = true;
+ }
+ if (mUpdateWordIteratorText) {
+ // FIXME - Shouldn't copy all of the text as only the area of the text relevant
+ // to the user's selection is needed. A possible solution would be to
+ // copy some number N of characters near the selection and then when the
+ // user approaches N then we'd do another copy of the next N characters.
+ CharSequence text = mTextView.getText();
+ mWordIteratorWithText.setCharSequence(text, 0, text.length());
+ mUpdateWordIteratorText = false;
+ }
+ return mWordIteratorWithText;
+ }
+
private long getCharRange(int offset) {
final int textLength = mTextView.getText().length();
if (offset + 1 < textLength) {
@@ -920,9 +989,8 @@
mTextView.startDrag(data, getTextThumbnailBuilder(selectedText), localState, 0);
stopSelectionActionMode();
} else {
- getSelectionController().hide();
- selectCurrentWord();
- getSelectionController().show();
+ stopSelectionActionMode();
+ startSelectionActionMode();
}
handled = true;
}
@@ -1058,6 +1126,9 @@
void sendOnTextChanged(int start, int after) {
updateSpellCheckSpans(start, start + after, false);
+ // Flip flag to indicate the word iterator needs to have the text reset.
+ mUpdateWordIteratorText = true;
+
// Hide the controllers as soon as text is modified (typing, procedural...)
// We do not hide the span controllers, since they can be added when a new text is
// inserted into the text view (voice IME).
@@ -1613,6 +1684,9 @@
}
}
+ if (selectionStarted) {
+ getSelectionController().enterDrag();
+ }
return selectionStarted;
}
@@ -2894,7 +2968,6 @@
}
if (menu.hasVisibleItems() || mode.getCustomView() != null) {
- getSelectionController().show();
mTextView.setHasTransientState(true);
return true;
} else {
@@ -3232,6 +3305,8 @@
private Runnable mActionPopupShower;
// Minimum touch target size for handles
private int mMinSize;
+ // Indicates the line of text that the handle is on.
+ protected int mLine = -1;
public HandleView(Drawable drawableLtr, Drawable drawableRtl) {
super(mTextView.getContext());
@@ -3407,6 +3482,7 @@
addPositionToTouchUpFilter(offset);
}
final int line = layout.getLineForOffset(offset);
+ mLine = line;
mPositionX = (int) (layout.getPrimaryHorizontal(offset) - 0.5f - mHotspotX -
getHorizontalOffset() + getCursorOffset());
@@ -3456,6 +3532,30 @@
}
}
+ public void showAtLocation(int offset) {
+ // TODO - investigate if there's a better way to show the handles
+ // after the drag accelerator has occured.
+ int[] tmpCords = new int[2];
+ mTextView.getLocationInWindow(tmpCords);
+
+ Layout layout = mTextView.getLayout();
+ int posX = tmpCords[0];
+ int posY = tmpCords[1];
+
+ final int line = layout.getLineForOffset(offset);
+
+ int startX = (int) (layout.getPrimaryHorizontal(offset) - 0.5f
+ - mHotspotX - getHorizontalOffset() + getCursorOffset());
+ int startY = layout.getLineBottom(line);
+
+ // Take TextView's padding and scroll into account.
+ startX += mTextView.viewportToContentHorizontalOffset();
+ startY += mTextView.viewportToContentVerticalOffset();
+
+ mContainer.showAtLocation(mTextView, Gravity.NO_GRAVITY,
+ startX + posX, startY + posY);
+ }
+
@Override
protected void onDraw(Canvas c) {
final int drawWidth = mDrawable.getIntrinsicWidth();
@@ -3694,6 +3794,12 @@
}
private class SelectionStartHandleView extends HandleView {
+ // The previous offset this handle was at.
+ private int mPrevOffset;
+ // Indicates whether the cursor is making adjustments within a word.
+ private boolean mInWord = false;
+ // Offset to track difference between touch and word boundary.
+ protected int mTouchWordOffset;
public SelectionStartHandleView(Drawable drawableLtr, Drawable drawableRtl) {
super(drawableLtr, drawableRtl);
@@ -3701,11 +3807,7 @@
@Override
protected int getHotspotX(Drawable drawable, boolean isRtlRun) {
- if (isRtlRun) {
- return drawable.getIntrinsicWidth() / 4;
- } else {
- return (drawable.getIntrinsicWidth() * 3) / 4;
- }
+ return isRtlRun ? 0 : drawable.getIntrinsicWidth();
}
@Override
@@ -3727,21 +3829,81 @@
@Override
public void updatePosition(float x, float y) {
- int offset = mTextView.getOffsetForPosition(x, y);
+ final int trueOffset = mTextView.getOffsetForPosition(x, y);
+ final int currLine = mTextView.getLineAtCoordinate(y);
+ int offset = trueOffset;
+ boolean positionCursor = false;
- // Handles can not cross and selection is at least one character
- final int selectionEnd = mTextView.getSelectionEnd();
- if (offset >= selectionEnd) offset = Math.max(0, selectionEnd - 1);
+ int end = getWordEnd(offset, true);
+ int start = getWordStart(offset);
- positionAtCursorOffset(offset, false);
+ if (offset < mPrevOffset) {
+ // User is increasing the selection.
+ if (!mInWord || currLine < mLine) {
+ // We're not in a word, or we're on a different line so we'll expand by
+ // word. First ensure the user has at least entered the next word.
+ int offsetToWord = Math.min((end - start) / 2, 2);
+ if (offset <= end - offsetToWord || currLine < mLine) {
+ offset = start;
+ } else {
+ offset = mPrevOffset;
+ }
+ }
+ mPrevOffset = offset;
+ mTouchWordOffset = trueOffset - offset;
+ mInWord = !isStartBoundary(offset);
+ positionCursor = true;
+ } else if (offset - mTouchWordOffset > mPrevOffset) {
+ // User is shrinking the selection.
+ if (currLine > mLine) {
+ // We're on a different line, so we'll snap to word boundaries.
+ offset = end;
+ }
+ offset -= mTouchWordOffset;
+ mPrevOffset = offset;
+ mInWord = !isEndBoundary(offset);
+ positionCursor = true;
+ }
+
+ // Handles can not cross and selection is at least one character.
+ if (positionCursor) {
+ final int selectionEnd = mTextView.getSelectionEnd();
+ if (offset >= selectionEnd) {
+ // We can't cross the handles so let's just constrain the Y value.
+ int alteredOffset = mTextView.getOffsetAtCoordinate(mLine, x);
+ if (alteredOffset >= selectionEnd) {
+ // Can't pass the other drag handle.
+ offset = Math.max(0, selectionEnd - 1);
+ } else {
+ offset = alteredOffset;
+ }
+ }
+ positionAtCursorOffset(offset, false);
+ }
}
public ActionPopupWindow getActionPopupWindow() {
return mActionPopupWindow;
}
+
+ @Override
+ public boolean onTouchEvent(MotionEvent event) {
+ boolean superResult = super.onTouchEvent(event);
+ if (event.getActionMasked() == MotionEvent.ACTION_UP) {
+ // Reset the touch word offset when the user has lifted their finger.
+ mTouchWordOffset = 0;
+ }
+ return superResult;
+ }
}
private class SelectionEndHandleView extends HandleView {
+ // The previous offset this handle was at.
+ private int mPrevOffset;
+ // Indicates whether the cursor is making adjustments within a word.
+ private boolean mInWord = false;
+ // Offset to track difference between touch and word boundary.
+ protected int mTouchWordOffset;
public SelectionEndHandleView(Drawable drawableLtr, Drawable drawableRtl) {
super(drawableLtr, drawableRtl);
@@ -3749,11 +3911,7 @@
@Override
protected int getHotspotX(Drawable drawable, boolean isRtlRun) {
- if (isRtlRun) {
- return (drawable.getIntrinsicWidth() * 3) / 4;
- } else {
- return drawable.getIntrinsicWidth() / 4;
- }
+ return isRtlRun ? drawable.getIntrinsicWidth() : 0;
}
@Override
@@ -3775,20 +3933,72 @@
@Override
public void updatePosition(float x, float y) {
- int offset = mTextView.getOffsetForPosition(x, y);
+ final int trueOffset = mTextView.getOffsetForPosition(x, y);
+ final int currLine = mTextView.getLineAtCoordinate(y);
+ int offset = trueOffset;
+ boolean positionCursor = false;
- // Handles can not cross and selection is at least one character
- final int selectionStart = mTextView.getSelectionStart();
- if (offset <= selectionStart) {
- offset = Math.min(selectionStart + 1, mTextView.getText().length());
+ int end = getWordEnd(offset, true);
+ int start = getWordStart(offset);
+
+ if (offset > mPrevOffset) {
+ // User is increasing the selection.
+ if (!mInWord || currLine > mLine) {
+ // We're not in a word, or we're on a different line so we'll expand by
+ // word. First ensure the user has at least entered the next word.
+ int midPoint = Math.min((end - start) / 2, 2);
+ if (offset >= start + midPoint || currLine > mLine) {
+ offset = end;
+ } else {
+ offset = mPrevOffset;
+ }
+ }
+ mPrevOffset = offset;
+ mTouchWordOffset = offset - trueOffset;
+ mInWord = !isEndBoundary(offset);
+ positionCursor = true;
+ } else if (offset + mTouchWordOffset < mPrevOffset) {
+ // User is shrinking the selection.
+ if (currLine > mLine) {
+ // We're on a different line, so we'll snap to word boundaries.
+ offset = getWordStart(offset);
+ }
+ offset += mTouchWordOffset;
+ mPrevOffset = offset;
+ positionCursor = true;
+ mInWord = !isStartBoundary(offset);
}
- positionAtCursorOffset(offset, false);
+ if (positionCursor) {
+ final int selectionStart = mTextView.getSelectionStart();
+ if (offset <= selectionStart) {
+ // We can't cross the handles so let's just constrain the Y value.
+ int alteredOffset = mTextView.getOffsetAtCoordinate(mLine, x);
+ int length = mTextView.getText().length();
+ if (alteredOffset <= selectionStart) {
+ // Can't pass the other drag handle.
+ offset = Math.min(selectionStart + 1, length);
+ } else {
+ offset = Math.min(alteredOffset, length);
+ }
+ }
+ positionAtCursorOffset(offset, false);
+ }
}
public void setActionPopupWindow(ActionPopupWindow actionPopupWindow) {
mActionPopupWindow = actionPopupWindow;
}
+
+ @Override
+ public boolean onTouchEvent(MotionEvent event) {
+ boolean superResult = super.onTouchEvent(event);
+ if (event.getActionMasked() == MotionEvent.ACTION_UP) {
+ // Reset the touch word offset when the user has lifted their finger.
+ mTouchWordOffset = 0;
+ }
+ return superResult;
+ }
}
/**
@@ -3871,6 +4081,11 @@
private float mDownPositionX, mDownPositionY;
private boolean mGestureStayedInTapRegion;
+ // Where the user first starts the drag motion.
+ private int mStartOffset = -1;
+ // Indicates whether the user is selecting text and using the drag accelerator.
+ private boolean mDragAcceleratorActive;
+
SelectionModifierCursorController() {
resetTouchOffsets();
}
@@ -3920,6 +4135,22 @@
if (mEndHandle != null) mEndHandle.hide();
}
+ public void enterDrag() {
+ // Just need to init the handles / hide insertion cursor.
+ show();
+ mDragAcceleratorActive = true;
+ // Start location of selection.
+ mStartOffset = mTextView.getOffsetForPosition(mLastDownPositionX,
+ mLastDownPositionY);
+ // Don't show the handles until user has lifted finger.
+ hide();
+
+ // This stops scrolling parents from intercepting the touch event, allowing
+ // the user to continue dragging across the screen to select text; TextView will
+ // scroll as necessary.
+ mTextView.getParent().requestDisallowInterceptTouchEvent(true);
+ }
+
public void onTouchEvent(MotionEvent event) {
// This is done even when the View does not have focus, so that long presses can start
// selection and tap can move cursor from this tap position.
@@ -3928,7 +4159,7 @@
final float x = event.getX();
final float y = event.getY();
- // Remember finger down position, to be able to start selection from there
+ // Remember finger down position, to be able to start selection from there.
mMinTouchOffset = mMaxTouchOffset = mTextView.getOffsetForPosition(x, y);
// Double tap detection
@@ -3967,23 +4198,112 @@
break;
case MotionEvent.ACTION_MOVE:
+ final ViewConfiguration viewConfiguration = ViewConfiguration.get(
+ mTextView.getContext());
+
if (mGestureStayedInTapRegion) {
final float deltaX = event.getX() - mDownPositionX;
final float deltaY = event.getY() - mDownPositionY;
final float distanceSquared = deltaX * deltaX + deltaY * deltaY;
- final ViewConfiguration viewConfiguration = ViewConfiguration.get(
- mTextView.getContext());
int doubleTapTouchSlop = viewConfiguration.getScaledDoubleTapTouchSlop();
if (distanceSquared > doubleTapTouchSlop * doubleTapTouchSlop) {
mGestureStayedInTapRegion = false;
}
}
+
+ if (mStartHandle != null && mStartHandle.isShowing()) {
+ // Don't do the drag if the handles are showing already.
+ break;
+ }
+
+ if (mStartOffset != -1) {
+ final int rawOffset = mTextView.getOffsetForPosition(event.getX(),
+ event.getY());
+ int offset = rawOffset;
+
+ // We don't start "dragging" until the user is past the initial word that
+ // gets selected on long press.
+ int firstWordStart = getWordStart(mStartOffset);
+ int firstWordEnd = getWordEnd(mStartOffset, false);
+ if (offset > firstWordEnd || offset < firstWordStart) {
+
+ // Basically the goal in the below code is to have the highlight be
+ // offset so that your finger isn't covering the end point.
+ int fingerOffset = viewConfiguration.getScaledTouchSlop();
+ float mx = event.getX();
+ float my = event.getY();
+ if (mx > fingerOffset) mx -= fingerOffset;
+ if (my > fingerOffset) my -= fingerOffset;
+ offset = mTextView.getOffsetForPosition(mx, my);
+
+ // Perform the check for closeness at edge of view, if we're very close
+ // don't adjust the offset to be in front of the finger - otherwise the
+ // user can't select words at the edge.
+ if (mTextView.getWidth() - fingerOffset > mx) {
+ // We're going by word, so we need to make sure that the offset
+ // that we get is within this, so we'll get the previous boundary.
+ final WordIterator wordIterator = getWordIteratorWithText();
+
+ final int precedingOffset = wordIterator.preceding(offset);
+ if (mStartOffset < offset) {
+ // Expanding with bottom handle, in this case the selection end
+ // is before the finger.
+ offset = Math.max(precedingOffset - 1, 0);
+ } else {
+ // Expand with the start handle, in this case the selection
+ // start is before the finger.
+ if (precedingOffset == WordIterator.DONE) {
+ offset = 0;
+ } else {
+ offset = wordIterator.preceding(precedingOffset);
+ }
+ }
+ }
+ if (offset == WordIterator.DONE)
+ offset = rawOffset;
+
+ // Need to adjust start offset based on direction of movement.
+ int newStart = mStartOffset < offset ? getWordStart(mStartOffset)
+ : getWordEnd(mStartOffset, true);
+ Selection.setSelection((Spannable) mTextView.getText(), newStart,
+ offset);
+ }
+ }
break;
case MotionEvent.ACTION_UP:
mPreviousTapUpTime = SystemClock.uptimeMillis();
+ if (mDragAcceleratorActive) {
+ // No longer dragging to select text, let the parent intercept events.
+ mTextView.getParent().requestDisallowInterceptTouchEvent(false);
+
+ show();
+ int startOffset = mTextView.getSelectionStart();
+ int endOffset = mTextView.getSelectionEnd();
+
+ // Since we don't let drag handles pass once they're visible, we need to
+ // make sure the start / end locations are correct because the user *can*
+ // switch directions during the initial drag.
+ if (endOffset < startOffset) {
+ int tmp = endOffset;
+ endOffset = startOffset;
+ startOffset = tmp;
+
+ // Also update the selection with the right offsets in this case.
+ Selection.setSelection((Spannable) mTextView.getText(),
+ startOffset, endOffset);
+ }
+
+ // Need to do this to display the handles.
+ mStartHandle.showAtLocation(startOffset);
+ mEndHandle.showAtLocation(endOffset);
+
+ // No longer the first dragging motion, reset.
+ mDragAcceleratorActive = false;
+ mStartOffset = -1;
+ }
break;
}
}
@@ -4010,6 +4330,8 @@
public void resetTouchOffsets() {
mMinTouchOffset = mMaxTouchOffset = -1;
+ mStartOffset = -1;
+ mDragAcceleratorActive = false;
}
/**
@@ -4019,6 +4341,13 @@
return mStartHandle != null && mStartHandle.isDragging();
}
+ /**
+ * @return true if the user is selecting text using the drag accelerator.
+ */
+ public boolean isDragAcceleratorActive() {
+ return mDragAcceleratorActive;
+ }
+
public void onTouchModeChanged(boolean isInTouchMode) {
if (!isInTouchMode) {
hide();
diff --git a/core/java/android/widget/GridLayout.java b/core/java/android/widget/GridLayout.java
index e8fe191..c748e00 100644
--- a/core/java/android/widget/GridLayout.java
+++ b/core/java/android/widget/GridLayout.java
@@ -141,7 +141,9 @@
* view was alone in a column, that column would itself collapse to zero width if and only if
* no gravity was defined on the view. If gravity was defined, then the gone-marked
* view has no effect on the layout and the container should be laid out as if the view
- * had never been added to it.
+ * had never been added to it. GONE views are taken to have zero weight during excess space
+ * distribution.
+ * <p>
* These statements apply equally to rows as well as columns, and to groups of rows or columns.
*
* <p>
@@ -1015,7 +1017,7 @@
} else {
boolean horizontal = (mOrientation == HORIZONTAL);
Spec spec = horizontal ? lp.columnSpec : lp.rowSpec;
- if (spec.alignment == FILL) {
+ if (spec.getAbsoluteAlignment(horizontal) == FILL) {
Interval span = spec.span;
Axis axis = horizontal ? mHorizontalAxis : mVerticalAxis;
int[] locations = axis.getLocations();
@@ -1091,11 +1093,6 @@
invalidateValues();
}
- final Alignment getAlignment(Alignment alignment, boolean horizontal) {
- return (alignment != UNDEFINED_ALIGNMENT) ? alignment :
- (horizontal ? START : BASELINE);
- }
-
// Layout container
/**
@@ -1150,8 +1147,8 @@
int pWidth = getMeasurement(c, true);
int pHeight = getMeasurement(c, false);
- Alignment hAlign = getAlignment(columnSpec.alignment, true);
- Alignment vAlign = getAlignment(rowSpec.alignment, false);
+ Alignment hAlign = columnSpec.getAbsoluteAlignment(true);
+ Alignment vAlign = rowSpec.getAbsoluteAlignment(false);
Bounds boundsX = mHorizontalAxis.getGroupBounds().getValue(i);
Bounds boundsY = mVerticalAxis.getGroupBounds().getValue(i);
@@ -1297,7 +1294,7 @@
// we must include views that are GONE here, see introductory javadoc
LayoutParams lp = getLayoutParams(c);
Spec spec = horizontal ? lp.columnSpec : lp.rowSpec;
- Bounds bounds = getAlignment(spec.alignment, horizontal).getBounds();
+ Bounds bounds = spec.getAbsoluteAlignment(horizontal).getBounds();
assoc.put(spec, bounds);
}
return assoc.pack();
@@ -1703,7 +1700,11 @@
private boolean computeHasWeights() {
for (int i = 0, N = getChildCount(); i < N; i++) {
- LayoutParams lp = getLayoutParams(getChildAt(i));
+ final View child = getChildAt(i);
+ if (child.getVisibility() == View.GONE) {
+ continue;
+ }
+ LayoutParams lp = getLayoutParams(child);
Spec spec = horizontal ? lp.columnSpec : lp.rowSpec;
if (spec.weight != 0) {
return true;
@@ -1743,7 +1744,10 @@
private void shareOutDelta(int totalDelta, float totalWeight) {
Arrays.fill(deltas, 0);
for (int i = 0, N = getChildCount(); i < N; i++) {
- View c = getChildAt(i);
+ final View c = getChildAt(i);
+ if (c.getVisibility() == View.GONE) {
+ continue;
+ }
LayoutParams lp = getLayoutParams(c);
Spec spec = horizontal ? lp.columnSpec : lp.rowSpec;
float weight = spec.weight;
@@ -1796,6 +1800,9 @@
float totalWeight = 0f;
for (int i = 0, N = getChildCount(); i < N; i++) {
View c = getChildAt(i);
+ if (c.getVisibility() == View.GONE) {
+ continue;
+ }
LayoutParams lp = getLayoutParams(c);
Spec spec = horizontal ? lp.columnSpec : lp.rowSpec;
totalWeight += spec.weight;
@@ -2011,7 +2018,6 @@
R.styleable.ViewGroup_MarginLayout_layout_marginRight;
private static final int BOTTOM_MARGIN =
R.styleable.ViewGroup_MarginLayout_layout_marginBottom;
-
private static final int COLUMN = R.styleable.GridLayout_Layout_layout_column;
private static final int COLUMN_SPAN = R.styleable.GridLayout_Layout_layout_columnSpan;
private static final int COLUMN_WEIGHT = R.styleable.GridLayout_Layout_layout_columnWeight;
@@ -2405,7 +2411,7 @@
protected final void include(GridLayout gl, View c, Spec spec, Axis axis, int size) {
this.flexibility &= spec.getFlexibility();
boolean horizontal = axis.horizontal;
- Alignment alignment = gl.getAlignment(spec.alignment, horizontal);
+ Alignment alignment = spec.getAbsoluteAlignment(axis.horizontal);
// todo test this works correctly when the returned value is UNDEFINED
int before = alignment.getAlignmentValue(c, size, gl.getLayoutMode());
include(before, size - before);
@@ -2556,6 +2562,16 @@
this(startDefined, new Interval(start, start + size), alignment, weight);
}
+ private Alignment getAbsoluteAlignment(boolean horizontal) {
+ if (alignment != UNDEFINED_ALIGNMENT) {
+ return alignment;
+ }
+ if (weight == 0f) {
+ return horizontal ? START : BASELINE;
+ }
+ return FILL;
+ }
+
final Spec copyWriteSpan(Interval span) {
return new Spec(startDefined, span, alignment, weight);
}
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index 632f5c7..9bef1fe 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -8098,7 +8098,14 @@
public boolean onTouchEvent(MotionEvent event) {
final int action = event.getActionMasked();
- if (mEditor != null) mEditor.onTouchEvent(event);
+ if (mEditor != null) {
+ mEditor.onTouchEvent(event);
+
+ if (mEditor.mSelectionModifierCursorController != null &&
+ mEditor.mSelectionModifierCursorController.isDragAcceleratorActive()) {
+ return true;
+ }
+ }
final boolean superResult = super.onTouchEvent(event);
@@ -9104,7 +9111,7 @@
return getLayout().getLineForVertical((int) y);
}
- private int getOffsetAtCoordinate(int line, float x) {
+ int getOffsetAtCoordinate(int line, float x) {
x = convertToLocalHorizontalCoordinate(x);
return getLayout().getOffsetForHorizontal(line, x);
}
@@ -9726,4 +9733,4 @@
TextView.this.spanChange(buf, what, s, -1, e, -1);
}
}
-}
\ No newline at end of file
+}
diff --git a/core/java/com/android/internal/backup/LocalTransport.java b/core/java/com/android/internal/backup/LocalTransport.java
index c3cc60a..fb0ffb0 100644
--- a/core/java/com/android/internal/backup/LocalTransport.java
+++ b/core/java/com/android/internal/backup/LocalTransport.java
@@ -369,6 +369,9 @@
return TRANSPORT_ERROR;
}
}
+ if (DEBUG) {
+ Log.v(TAG, " stored " + numBytes + " of data");
+ }
return TRANSPORT_OK;
}
@@ -431,6 +434,10 @@
@Override
public RestoreDescription nextRestorePackage() {
+ if (DEBUG) {
+ Log.v(TAG, "nextRestorePackage() : mRestorePackage=" + mRestorePackage
+ + " length=" + mRestorePackages.length);
+ }
if (mRestorePackages == null) throw new IllegalStateException("startRestore not called");
boolean found = false;
@@ -441,7 +448,10 @@
// skip packages where we have a data dir but no actual contents
String[] contents = (new File(mRestoreSetIncrementalDir, name)).list();
if (contents != null && contents.length > 0) {
- if (DEBUG) Log.v(TAG, " nextRestorePackage(TYPE_KEY_VALUE) = " + name);
+ if (DEBUG) {
+ Log.v(TAG, " nextRestorePackage(TYPE_KEY_VALUE) @ "
+ + mRestorePackage + " = " + name);
+ }
mRestoreType = RestoreDescription.TYPE_KEY_VALUE;
found = true;
}
@@ -450,7 +460,10 @@
// No key/value data; check for [non-empty] full data
File maybeFullData = new File(mRestoreSetFullDir, name);
if (maybeFullData.length() > 0) {
- if (DEBUG) Log.v(TAG, " nextRestorePackage(TYPE_FULL_STREAM) = " + name);
+ if (DEBUG) {
+ Log.v(TAG, " nextRestorePackage(TYPE_FULL_STREAM) @ "
+ + mRestorePackage + " = " + name);
+ }
mRestoreType = RestoreDescription.TYPE_FULL_STREAM;
mCurFullRestoreStream = null; // ensure starting from the ground state
found = true;
@@ -460,6 +473,11 @@
if (found) {
return new RestoreDescription(name, mRestoreType);
}
+
+ if (DEBUG) {
+ Log.v(TAG, " ... package @ " + mRestorePackage + " = " + name
+ + " has no data; skipping");
+ }
}
if (DEBUG) Log.v(TAG, " no more packages to restore");
diff --git a/core/java/com/android/internal/transition/EpicenterClipReveal.java b/core/java/com/android/internal/transition/EpicenterClipReveal.java
index d8a7f16..abb50c1 100644
--- a/core/java/com/android/internal/transition/EpicenterClipReveal.java
+++ b/core/java/com/android/internal/transition/EpicenterClipReveal.java
@@ -16,6 +16,7 @@
package com.android.internal.transition;
import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
import android.animation.ObjectAnimator;
import android.animation.RectEvaluator;
import android.content.Context;
@@ -75,13 +76,13 @@
return null;
}
- final Rect start = getEpicenter();
final Rect end = getBestRect(endValues);
+ final Rect start = getEpicenterOrCenter(end);
// Prepare the view.
view.setClipBounds(start);
- return createRectAnimator(view, start, end);
+ return createRectAnimator(view, start, end, endValues);
}
@Override
@@ -92,12 +93,23 @@
}
final Rect start = getBestRect(startValues);
- final Rect end = getEpicenter();
+ final Rect end = getEpicenterOrCenter(start);
// Prepare the view.
view.setClipBounds(start);
- return createRectAnimator(view, start, end);
+ return createRectAnimator(view, start, end, endValues);
+ }
+
+ private Rect getEpicenterOrCenter(Rect bestRect) {
+ final Rect epicenter = getEpicenter();
+ if (epicenter != null) {
+ return epicenter;
+ }
+
+ int centerX = bestRect.centerX();
+ int centerY = bestRect.centerY();
+ return new Rect(centerX, centerY, centerX, centerY);
}
private Rect getBestRect(TransitionValues values) {
@@ -108,8 +120,17 @@
return clipRect;
}
- private Animator createRectAnimator(View view, Rect start, Rect end) {
+ private Animator createRectAnimator(final View view, Rect start, Rect end,
+ TransitionValues endValues) {
+ final Rect terminalClip = (Rect) endValues.values.get(PROPNAME_CLIP);
final RectEvaluator evaluator = new RectEvaluator(new Rect());
- return ObjectAnimator.ofObject(view, "clipBounds", evaluator, start, end);
+ ObjectAnimator anim = ObjectAnimator.ofObject(view, "clipBounds", evaluator, start, end);
+ anim.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ view.setClipBounds(terminalClip);
+ }
+ });
+ return anim;
}
}
diff --git a/core/jni/Android.mk b/core/jni/Android.mk
index 28f1a3a..97744ea 100644
--- a/core/jni/Android.mk
+++ b/core/jni/Android.mk
@@ -147,7 +147,7 @@
android_hardware_location_ActivityRecognitionHardware.cpp \
android_util_FileObserver.cpp \
android/opengl/poly_clip.cpp.arm \
- android/opengl/util.cpp.arm \
+ android/opengl/util.cpp \
android_server_FingerprintManager.cpp \
android_server_NetworkManagementSocketTagger.cpp \
android_server_Watchdog.cpp \
diff --git a/core/jni/android/graphics/BitmapFactory.cpp b/core/jni/android/graphics/BitmapFactory.cpp
index 672008d..6a50b52 100644
--- a/core/jni/android/graphics/BitmapFactory.cpp
+++ b/core/jni/android/graphics/BitmapFactory.cpp
@@ -41,7 +41,6 @@
jfieldID gOptions_mCancelID;
jfieldID gOptions_bitmapFieldID;
-jfieldID gBitmap_nativeBitmapFieldID;
jfieldID gBitmap_ninePatchInsetsFieldID;
jclass gInsetStruct_class;
@@ -262,7 +261,7 @@
SkBitmap* outputBitmap = NULL;
unsigned int existingBufferSize = 0;
if (javaBitmap != NULL) {
- outputBitmap = (SkBitmap*) env->GetLongField(javaBitmap, gBitmap_nativeBitmapFieldID);
+ outputBitmap = GraphicsJNI::getSkBitmap(env, javaBitmap);
if (outputBitmap->isImmutable()) {
ALOGW("Unable to reuse an immutable bitmap as an image decoder target.");
javaBitmap = NULL;
@@ -601,7 +600,6 @@
gOptions_mCancelID = GetFieldIDOrDie(env, options_class, "mCancel", "Z");
jclass bitmap_class = FindClassOrDie(env, "android/graphics/Bitmap");
- gBitmap_nativeBitmapFieldID = GetFieldIDOrDie(env, bitmap_class, "mNativeBitmap", "J");
gBitmap_ninePatchInsetsFieldID = GetFieldIDOrDie(env, bitmap_class, "mNinePatchInsets",
"Landroid/graphics/NinePatch$InsetStruct;");
diff --git a/core/jni/android/graphics/BitmapRegionDecoder.cpp b/core/jni/android/graphics/BitmapRegionDecoder.cpp
index 90a7f69..04afe3e 100644
--- a/core/jni/android/graphics/BitmapRegionDecoder.cpp
+++ b/core/jni/android/graphics/BitmapRegionDecoder.cpp
@@ -213,7 +213,7 @@
if (tileBitmap != NULL) {
// Re-use bitmap.
- bitmap = GraphicsJNI::getNativeBitmap(env, tileBitmap);
+ bitmap = GraphicsJNI::getSkBitmap(env, tileBitmap);
}
if (bitmap == NULL) {
bitmap = new SkBitmap;
diff --git a/core/jni/android/graphics/ColorFilter.cpp b/core/jni/android/graphics/ColorFilter.cpp
index 026cbee..d03bcf0 100644
--- a/core/jni/android/graphics/ColorFilter.cpp
+++ b/core/jni/android/graphics/ColorFilter.cpp
@@ -21,7 +21,7 @@
#include "SkColorFilter.h"
#include "SkColorMatrixFilter.h"
-#include "SkPorterDuff.h"
+#include "SkXfermode.h"
#include <Caches.h>
@@ -36,10 +36,9 @@
if (filter) SkSafeUnref(filter);
}
- static jlong CreatePorterDuffFilter(JNIEnv* env, jobject, jint srcColor,
- jint modeHandle) {
- SkPorterDuff::Mode mode = (SkPorterDuff::Mode) modeHandle;
- return reinterpret_cast<jlong>(SkColorFilter::CreateModeFilter(srcColor, SkPorterDuff::ToXfermodeMode(mode)));
+ static jlong CreatePorterDuffFilter(JNIEnv* env, jobject, jint srcColor, jint modeHandle) {
+ SkXfermode::Mode mode = static_cast<SkXfermode::Mode>(modeHandle);
+ return reinterpret_cast<jlong>(SkColorFilter::CreateModeFilter(srcColor, mode));
}
static jlong CreateLightingFilter(JNIEnv* env, jobject, jint mul, jint add) {
diff --git a/core/jni/android/graphics/Graphics.cpp b/core/jni/android/graphics/Graphics.cpp
index dde1393..0747969 100644
--- a/core/jni/android/graphics/Graphics.cpp
+++ b/core/jni/android/graphics/Graphics.cpp
@@ -154,7 +154,7 @@
static jfieldID gPointF_yFieldID;
static jclass gBitmap_class;
-static jfieldID gBitmap_nativeInstanceID;
+static jfieldID gBitmap_skBitmapPtr;
static jmethodID gBitmap_constructorMethodID;
static jmethodID gBitmap_reinitMethodID;
static jmethodID gBitmap_getAllocationByteCountMethodID;
@@ -338,11 +338,11 @@
return static_cast<SkColorType>(gConfig2ColorType[legacyConfig]);
}
-SkBitmap* GraphicsJNI::getNativeBitmap(JNIEnv* env, jobject bitmap) {
+SkBitmap* GraphicsJNI::getSkBitmap(JNIEnv* env, jobject bitmap) {
SkASSERT(env);
SkASSERT(bitmap);
SkASSERT(env->IsInstanceOf(bitmap, gBitmap_class));
- jlong bitmapHandle = env->GetLongField(bitmap, gBitmap_nativeInstanceID);
+ jlong bitmapHandle = env->GetLongField(bitmap, gBitmap_skBitmapPtr);
SkBitmap* b = reinterpret_cast<SkBitmap*>(bitmapHandle);
SkASSERT(b);
return b;
@@ -676,7 +676,7 @@
gPointF_yFieldID = getFieldIDCheck(env, gPointF_class, "y", "F");
gBitmap_class = make_globalref(env, "android/graphics/Bitmap");
- gBitmap_nativeInstanceID = getFieldIDCheck(env, gBitmap_class, "mNativeBitmap", "J");
+ gBitmap_skBitmapPtr = getFieldIDCheck(env, gBitmap_class, "mSkBitmapPtr", "J");
gBitmap_constructorMethodID = env->GetMethodID(gBitmap_class, "<init>", "(J[BIIIZZ[BLandroid/graphics/NinePatch$InsetStruct;)V");
gBitmap_reinitMethodID = env->GetMethodID(gBitmap_class, "reinit", "(IIZ)V");
gBitmap_getAllocationByteCountMethodID = env->GetMethodID(gBitmap_class, "getAllocationByteCount", "()I");
diff --git a/core/jni/android/graphics/GraphicsJNI.h b/core/jni/android/graphics/GraphicsJNI.h
index a202c38..422d3f1 100644
--- a/core/jni/android/graphics/GraphicsJNI.h
+++ b/core/jni/android/graphics/GraphicsJNI.h
@@ -48,7 +48,7 @@
static void point_to_jpointf(const SkPoint& point, JNIEnv*, jobject jpointf);
static SkCanvas* getNativeCanvas(JNIEnv*, jobject canvas);
- static SkBitmap* getNativeBitmap(JNIEnv*, jobject bitmap);
+ static SkBitmap* getSkBitmap(JNIEnv*, jobject bitmap);
static SkRegion* getNativeRegion(JNIEnv*, jobject region);
// Given the 'native' long held by the Rasterizer.java object, return a
diff --git a/core/jni/android/graphics/PorterDuff.cpp b/core/jni/android/graphics/PorterDuff.cpp
index 73b1691..d65864d 100644
--- a/core/jni/android/graphics/PorterDuff.cpp
+++ b/core/jni/android/graphics/PorterDuff.cpp
@@ -24,7 +24,7 @@
#include "GraphicsJNI.h"
#include "core_jni_helpers.h"
-#include "SkPorterDuff.h"
+#include "SkXfermode.h"
namespace android {
@@ -32,8 +32,28 @@
public:
static jlong CreateXfermode(JNIEnv* env, jobject, jint modeHandle) {
- SkPorterDuff::Mode mode = static_cast<SkPorterDuff::Mode>(modeHandle);
- return reinterpret_cast<jlong>(SkPorterDuff::CreateXfermode(mode));
+ // validate that the Java enum values match our expectations
+ SK_COMPILE_ASSERT(0 == SkXfermode::kClear_Mode, xfermode_mismatch);
+ SK_COMPILE_ASSERT(1 == SkXfermode::kSrc_Mode, xfermode_mismatch);
+ SK_COMPILE_ASSERT(2 == SkXfermode::kDst_Mode, xfermode_mismatch);
+ SK_COMPILE_ASSERT(3 == SkXfermode::kSrcOver_Mode, xfermode_mismatch);
+ SK_COMPILE_ASSERT(4 == SkXfermode::kDstOver_Mode, xfermode_mismatch);
+ SK_COMPILE_ASSERT(5 == SkXfermode::kSrcIn_Mode, xfermode_mismatch);
+ SK_COMPILE_ASSERT(6 == SkXfermode::kDstIn_Mode, xfermode_mismatch);
+ SK_COMPILE_ASSERT(7 == SkXfermode::kSrcOut_Mode, xfermode_mismatch);
+ SK_COMPILE_ASSERT(8 == SkXfermode::kDstOut_Mode, xfermode_mismatch);
+ SK_COMPILE_ASSERT(9 == SkXfermode::kSrcATop_Mode, xfermode_mismatch);
+ SK_COMPILE_ASSERT(10 == SkXfermode::kDstATop_Mode, xfermode_mismatch);
+ SK_COMPILE_ASSERT(11 == SkXfermode::kXor_Mode, xfermode_mismatch);
+ SK_COMPILE_ASSERT(16 == SkXfermode::kDarken_Mode, xfermode_mismatch);
+ SK_COMPILE_ASSERT(17 == SkXfermode::kLighten_Mode, xfermode_mismatch);
+ SK_COMPILE_ASSERT(13 == SkXfermode::kModulate_Mode, xfermode_mismatch);
+ SK_COMPILE_ASSERT(14 == SkXfermode::kScreen_Mode, xfermode_mismatch);
+ SK_COMPILE_ASSERT(12 == SkXfermode::kPlus_Mode, xfermode_mismatch);
+ SK_COMPILE_ASSERT(15 == SkXfermode::kOverlay_Mode, xfermode_mismatch);
+
+ SkXfermode::Mode mode = static_cast<SkXfermode::Mode>(modeHandle);
+ return reinterpret_cast<jlong>(SkXfermode::Create(mode));
}
};
diff --git a/core/jni/android/graphics/Shader.cpp b/core/jni/android/graphics/Shader.cpp
index 3f47a72..6591d29 100644
--- a/core/jni/android/graphics/Shader.cpp
+++ b/core/jni/android/graphics/Shader.cpp
@@ -3,7 +3,6 @@
#include "SkShader.h"
#include "SkGradientShader.h"
-#include "SkPorterDuff.h"
#include "SkComposeShader.h"
#include "SkTemplates.h"
#include "SkXfermode.h"
@@ -227,14 +226,13 @@
}
static jlong ComposeShader_create2(JNIEnv* env, jobject o,
- jlong shaderAHandle, jlong shaderBHandle, jint porterDuffModeHandle)
+ jlong shaderAHandle, jlong shaderBHandle, jint xfermodeHandle)
{
SkShader* shaderA = reinterpret_cast<SkShader *>(shaderAHandle);
SkShader* shaderB = reinterpret_cast<SkShader *>(shaderBHandle);
- SkPorterDuff::Mode porterDuffMode = static_cast<SkPorterDuff::Mode>(porterDuffModeHandle);
- SkAutoUnref au(SkPorterDuff::CreateXfermode(porterDuffMode));
- SkXfermode* mode = (SkXfermode*) au.get();
- SkShader* shader = new SkComposeShader(shaderA, shaderB, mode);
+ SkXfermode::Mode mode = static_cast<SkXfermode::Mode>(xfermodeHandle);
+ SkAutoTUnref<SkXfermode> xfermode(SkXfermode::Create(mode));
+ SkShader* shader = new SkComposeShader(shaderA, shaderB, xfermode.get());
return reinterpret_cast<jlong>(shader);
}
diff --git a/core/jni/android/opengl/util.cpp b/core/jni/android/opengl/util.cpp
index 461507f..5c2d0d0 100644
--- a/core/jni/android/opengl/util.cpp
+++ b/core/jni/android/opengl/util.cpp
@@ -16,6 +16,7 @@
#include "jni.h"
#include "JNIHelp.h"
+#include "GraphicsJNI.h"
#include <math.h>
#include <stdio.h>
@@ -149,10 +150,6 @@
return result;
}
-static void doThrowIAE(JNIEnv* env, const char* msg) {
- jniThrowException(env, "java/lang/IllegalArgumentException", msg);
-}
-
template<class JArray, class T>
class ArrayHelper {
public:
@@ -548,14 +545,6 @@
// ---------------------------------------------------------------------------
-static jfieldID nativeBitmapID = 0;
-
-void nativeUtilsClassInit(JNIEnv *env, jclass clazz)
-{
- jclass bitmapClass = env->FindClass("android/graphics/Bitmap");
- nativeBitmapID = env->GetFieldID(bitmapClass, "mNativeBitmap", "J");
-}
-
extern void setGLDebugLevel(int level);
void setTracingLevel(JNIEnv *env, jclass clazz, jint level)
{
@@ -629,16 +618,14 @@
static jint util_getInternalFormat(JNIEnv *env, jclass clazz,
jobject jbitmap)
{
- SkBitmap const * nativeBitmap =
- (SkBitmap const *)env->GetLongField(jbitmap, nativeBitmapID);
+ SkBitmap const * nativeBitmap = GraphicsJNI::getSkBitmap(env, jbitmap);
return getInternalFormat(nativeBitmap->colorType());
}
static jint util_getType(JNIEnv *env, jclass clazz,
jobject jbitmap)
{
- SkBitmap const * nativeBitmap =
- (SkBitmap const *)env->GetLongField(jbitmap, nativeBitmapID);
+ SkBitmap const * nativeBitmap = GraphicsJNI::getSkBitmap(env, jbitmap);
return getType(nativeBitmap->colorType());
}
@@ -646,8 +633,7 @@
jint target, jint level, jint internalformat,
jobject jbitmap, jint type, jint border)
{
- SkBitmap const * nativeBitmap =
- (SkBitmap const *)env->GetLongField(jbitmap, nativeBitmapID);
+ SkBitmap const * nativeBitmap = GraphicsJNI::getSkBitmap(env, jbitmap);
const SkBitmap& bitmap(*nativeBitmap);
SkColorType colorType = bitmap.colorType();
if (internalformat < 0) {
@@ -694,8 +680,7 @@
jint target, jint level, jint xoffset, jint yoffset,
jobject jbitmap, jint format, jint type)
{
- SkBitmap const * nativeBitmap =
- (SkBitmap const *)env->GetLongField(jbitmap, nativeBitmapID);
+ SkBitmap const * nativeBitmap = GraphicsJNI::getSkBitmap(env, jbitmap);
const SkBitmap& bitmap(*nativeBitmap);
SkColorType colorType = bitmap.colorType();
if (format < 0) {
@@ -1014,7 +999,6 @@
};
static JNINativeMethod gUtilsMethods[] = {
- {"nativeClassInit", "()V", (void*)nativeUtilsClassInit },
{ "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 },
diff --git a/core/jni/android_graphics_Canvas.cpp b/core/jni/android_graphics_Canvas.cpp
index 7d5ca8d..c337a9f 100644
--- a/core/jni/android_graphics_Canvas.cpp
+++ b/core/jni/android_graphics_Canvas.cpp
@@ -21,7 +21,6 @@
#include <Canvas.h>
#include "SkDrawFilter.h"
#include "SkGraphics.h"
-#include "SkPorterDuff.h"
#include "Paint.h"
#include "TypefaceImpl.h"
@@ -186,8 +185,8 @@
}
static void drawColor(JNIEnv* env, jobject, jlong canvasHandle, jint color, jint modeHandle) {
- SkPorterDuff::Mode mode = static_cast<SkPorterDuff::Mode>(modeHandle);
- get_canvas(canvasHandle)->drawColor(color, SkPorterDuff::ToXfermodeMode(mode));
+ SkXfermode::Mode mode = static_cast<SkXfermode::Mode>(modeHandle);
+ get_canvas(canvasHandle)->drawColor(color, mode);
}
static void drawPaint(JNIEnv* env, jobject, jlong canvasHandle, jlong paintHandle) {
diff --git a/core/jni/android_text_StaticLayout.cpp b/core/jni/android_text_StaticLayout.cpp
index db73e69..a6f19b1 100644
--- a/core/jni/android_text_StaticLayout.cpp
+++ b/core/jni/android_text_StaticLayout.cpp
@@ -29,6 +29,7 @@
#include <list>
#include <algorithm>
+
namespace android {
struct JLineBreaksID {
@@ -40,6 +41,53 @@
static jclass gLineBreaks_class;
static JLineBreaksID gLineBreaks_fieldID;
+class Builder {
+ public:
+ ~Builder() {
+ utext_close(&mUText);
+ delete mBreakIterator;
+ }
+
+ void setLocale(const Locale& locale) {
+ delete mBreakIterator;
+ UErrorCode status = U_ZERO_ERROR;
+ mBreakIterator = BreakIterator::createLineInstance(locale, status);
+ // TODO: check status
+ }
+
+ void resize(size_t size) {
+ mTextBuf.resize(size);
+ }
+
+ uint16_t* buffer() {
+ return mTextBuf.data();
+ }
+
+ // set text to current contents of buffer
+ void setText() {
+ UErrorCode status = U_ZERO_ERROR;
+ utext_openUChars(&mUText, mTextBuf.data(), mTextBuf.size(), &status);
+ mBreakIterator->setText(&mUText, status);
+ }
+
+ void finish() {
+ if (mTextBuf.size() > MAX_TEXT_BUF_RETAIN) {
+ mTextBuf.clear();
+ mTextBuf.shrink_to_fit();
+ }
+ }
+
+ BreakIterator* breakIterator() const {
+ return mBreakIterator;
+ }
+
+ private:
+ const size_t MAX_TEXT_BUF_RETAIN = 32678;
+ BreakIterator* mBreakIterator = nullptr;
+ UText mUText = UTEXT_INITIALIZER;
+ std::vector<uint16_t>mTextBuf;
+};
+
static const int CHAR_SPACE = 0x20;
static const int CHAR_TAB = 0x09;
static const int CHAR_NEWLINE = 0x0a;
@@ -50,7 +98,7 @@
// specified stops must be a sorted array (allowed to be null)
TabStops(JNIEnv* env, jintArray stops, jint defaultTabWidth) :
mStops(env), mTabWidth(defaultTabWidth) {
- if (stops != NULL) {
+ if (stops != nullptr) {
mStops.reset(stops);
mNumStops = mStops.size();
} else {
@@ -430,37 +478,6 @@
}
};
-class ScopedBreakIterator {
- public:
- ScopedBreakIterator(JNIEnv* env, BreakIterator* breakIterator, const jchar* inputText,
- jint length) : mBreakIterator(breakIterator), mChars(inputText) {
- UErrorCode status = U_ZERO_ERROR;
- mUText = utext_openUChars(NULL, mChars, length, &status);
- if (mUText == NULL) {
- return;
- }
-
- mBreakIterator->setText(mUText, status);
- }
-
- inline BreakIterator* operator->() {
- return mBreakIterator;
- }
-
- ~ScopedBreakIterator() {
- utext_close(mUText);
- delete mBreakIterator;
- }
- private:
- BreakIterator* mBreakIterator;
- const jchar* mChars;
- UText* mUText;
-
- // disable copying and assignment
- ScopedBreakIterator(const ScopedBreakIterator&);
- void operator=(const ScopedBreakIterator&);
-};
-
static jint recycleCopy(JNIEnv* env, jobject recycle, jintArray recycleBreaks,
jfloatArray recycleWidths, jbooleanArray recycleFlags,
jint recycleLength, const std::vector<jint>& breaks,
@@ -526,7 +543,7 @@
primitives->push_back(p);
}
-static jint nComputeLineBreaks(JNIEnv* env, jclass, jstring javaLocaleName,
+static jint nComputeLineBreaks(JNIEnv* env, jclass, jlong nativePtr,
jcharArray inputText, jfloatArray widths, jint length,
jfloat firstWidth, jint firstWidthLineLimit, jfloat restWidth,
jintArray variableTabStops, jint defaultTabStop, jboolean optimize,
@@ -535,29 +552,24 @@
jint recycleLength) {
std::vector<int> breaks;
- ScopedCharArrayRO textScopedArr(env, inputText);
+ Builder* b = reinterpret_cast<Builder*>(nativePtr);
+ b->resize(length);
+ env->GetCharArrayRegion(inputText, 0, length, b->buffer());
+ b->setText();
+
+ // TODO: this array access is pretty inefficient, but we'll replace it anyway
ScopedFloatArrayRO widthsScopedArr(env, widths);
- ScopedIcuLocale icuLocale(env, javaLocaleName);
- if (icuLocale.valid()) {
- UErrorCode status = U_ZERO_ERROR;
- BreakIterator* it = BreakIterator::createLineInstance(icuLocale.locale(), status);
- if (!U_SUCCESS(status) || it == NULL) {
- if (it) {
- delete it;
- }
- } else {
- ScopedBreakIterator breakIterator(env, it, textScopedArr.get(), length);
- int loc = breakIterator->first();
- while ((loc = breakIterator->next()) != BreakIterator::DONE) {
- breaks.push_back(loc);
- }
- }
+ BreakIterator* breakIterator = b->breakIterator();
+ int loc = breakIterator->first();
+ while ((loc = breakIterator->next()) != BreakIterator::DONE) {
+ breaks.push_back(loc);
}
+ // TODO: all these allocations can be moved into the builder
std::vector<Primitive> primitives;
TabStops tabStops(env, variableTabStops, defaultTabStop);
- computePrimitives(textScopedArr.get(), widthsScopedArr.get(), length, breaks, tabStops, &primitives);
+ computePrimitives(b->buffer(), widthsScopedArr.get(), length, breaks, tabStops, &primitives);
LineWidth lineWidth(firstWidth, firstWidthLineLimit, restWidth);
std::vector<int> computedBreaks;
@@ -571,13 +583,41 @@
GreedyLineBreaker breaker(primitives, lineWidth);
breaker.computeBreaks(&computedBreaks, &computedWidths, &computedFlags);
}
+ b->finish();
return recycleCopy(env, recycle, recycleBreaks, recycleWidths, recycleFlags, recycleLength,
computedBreaks, computedWidths, computedFlags);
}
+static jlong nNewBuilder(JNIEnv*, jclass) {
+ return reinterpret_cast<jlong>(new Builder);
+}
+
+static void nFreeBuilder(JNIEnv*, jclass, jlong nativePtr) {
+ delete reinterpret_cast<Builder*>(nativePtr);
+}
+
+static void nFinishBuilder(JNIEnv*, jclass, jlong nativePtr) {
+ Builder* b = reinterpret_cast<Builder*>(nativePtr);
+ b->finish();
+}
+
+static void nBuilderSetLocale(JNIEnv* env, jclass, jlong nativePtr, jstring javaLocaleName) {
+ ScopedIcuLocale icuLocale(env, javaLocaleName);
+ Builder* b = reinterpret_cast<Builder*>(nativePtr);
+
+ if (icuLocale.valid()) {
+ b->setLocale(icuLocale.locale());
+ }
+}
+
static JNINativeMethod gMethods[] = {
- {"nComputeLineBreaks", "(Ljava/lang/String;[C[FIFIF[IIZLandroid/text/StaticLayout$LineBreaks;[I[F[ZI)I", (void*) nComputeLineBreaks}
+ {"nNewBuilder", "()J", (void*) nNewBuilder},
+ {"nFreeBuilder", "(J)V", (void*) nFreeBuilder},
+ {"nFinishBuilder", "(J)V", (void*) nFinishBuilder},
+ {"nBuilderSetLocale", "(JLjava/lang/String;)V", (void*) nBuilderSetLocale},
+ {"nComputeLineBreaks", "(J[C[FIFIF[IIZLandroid/text/StaticLayout$LineBreaks;[I[F[ZI)I",
+ (void*) nComputeLineBreaks}
};
int register_android_text_StaticLayout(JNIEnv* env)
diff --git a/core/jni/android_view_PointerIcon.cpp b/core/jni/android_view_PointerIcon.cpp
index bbd031e..f6d9a1a 100644
--- a/core/jni/android_view_PointerIcon.cpp
+++ b/core/jni/android_view_PointerIcon.cpp
@@ -80,7 +80,7 @@
jobject bitmapObj = env->GetObjectField(loadedPointerIconObj, gPointerIconClassInfo.mBitmap);
if (bitmapObj) {
- SkBitmap* bitmap = GraphicsJNI::getNativeBitmap(env, bitmapObj);
+ SkBitmap* bitmap = GraphicsJNI::getSkBitmap(env, bitmapObj);
if (bitmap) {
outPointerIcon->bitmap = *bitmap; // use a shared pixel ref
}
diff --git a/core/jni/com_google_android_gles_jni_EGLImpl.cpp b/core/jni/com_google_android_gles_jni_EGLImpl.cpp
index 6c21bab..7080e2a 100644
--- a/core/jni/com_google_android_gles_jni_EGLImpl.cpp
+++ b/core/jni/com_google_android_gles_jni_EGLImpl.cpp
@@ -30,6 +30,7 @@
#include <gui/GLConsumer.h>
#include <gui/Surface.h>
+#include <GraphicsJNI.h>
#include <SkBitmap.h>
#include <SkPixelRef.h>
@@ -46,7 +47,6 @@
static jfieldID gSurface_EGLSurfaceFieldID;
static jfieldID gSurface_NativePixelRefFieldID;
static jfieldID gConfig_EGLConfigFieldID;
-static jfieldID gBitmap_NativeBitmapFieldID;
static inline EGLDisplay getDisplay(JNIEnv* env, jobject o) {
if (!o) return EGL_NO_DISPLAY;
@@ -85,9 +85,6 @@
jclass surface_class = _env->FindClass("com/google/android/gles_jni/EGLSurfaceImpl");
gSurface_EGLSurfaceFieldID = _env->GetFieldID(surface_class, "mEGLSurface", "J");
gSurface_NativePixelRefFieldID = _env->GetFieldID(surface_class, "mNativePixelRef", "J");
-
- jclass bitmap_class = _env->FindClass("android/graphics/Bitmap");
- gBitmap_NativeBitmapFieldID = _env->GetFieldID(bitmap_class, "mNativeBitmap", "J");
}
static const jint gNull_attrib_base[] = {EGL_NONE};
@@ -280,9 +277,7 @@
EGLConfig cnf = getConfig(_env, config);
jint* base = 0;
- SkBitmap const * nativeBitmap =
- (SkBitmap const *)_env->GetLongField(native_pixmap,
- gBitmap_NativeBitmapFieldID);
+ SkBitmap const * nativeBitmap = GraphicsJNI::getSkBitmap(_env, native_pixmap);
SkPixelRef* ref = nativeBitmap ? nativeBitmap->pixelRef() : 0;
if (ref == NULL) {
jniThrowException(_env, "java/lang/IllegalArgumentException", "Bitmap has no PixelRef");
diff --git a/core/res/res/drawable-hdpi/text_select_handle_left_mtrl_alpha.png b/core/res/res/drawable-hdpi/text_select_handle_left_mtrl_alpha.png
index 9cdc25b..1550b44 100644
--- a/core/res/res/drawable-hdpi/text_select_handle_left_mtrl_alpha.png
+++ b/core/res/res/drawable-hdpi/text_select_handle_left_mtrl_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/text_select_handle_right_mtrl_alpha.png b/core/res/res/drawable-hdpi/text_select_handle_right_mtrl_alpha.png
index 276d480..b309dfd 100644
--- a/core/res/res/drawable-hdpi/text_select_handle_right_mtrl_alpha.png
+++ b/core/res/res/drawable-hdpi/text_select_handle_right_mtrl_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/text_select_handle_left_mtrl_alpha.png b/core/res/res/drawable-mdpi/text_select_handle_left_mtrl_alpha.png
index 95c0168..b36a413 100644
--- a/core/res/res/drawable-mdpi/text_select_handle_left_mtrl_alpha.png
+++ b/core/res/res/drawable-mdpi/text_select_handle_left_mtrl_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/text_select_handle_right_mtrl_alpha.png b/core/res/res/drawable-mdpi/text_select_handle_right_mtrl_alpha.png
index 569332a..afd0bd2 100644
--- a/core/res/res/drawable-mdpi/text_select_handle_right_mtrl_alpha.png
+++ b/core/res/res/drawable-mdpi/text_select_handle_right_mtrl_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/text_select_handle_left_mtrl_alpha.png b/core/res/res/drawable-xhdpi/text_select_handle_left_mtrl_alpha.png
index a01ac10..58f8c43 100644
--- a/core/res/res/drawable-xhdpi/text_select_handle_left_mtrl_alpha.png
+++ b/core/res/res/drawable-xhdpi/text_select_handle_left_mtrl_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/text_select_handle_right_mtrl_alpha.png b/core/res/res/drawable-xhdpi/text_select_handle_right_mtrl_alpha.png
index d3602d9..42a893d 100644
--- a/core/res/res/drawable-xhdpi/text_select_handle_right_mtrl_alpha.png
+++ b/core/res/res/drawable-xhdpi/text_select_handle_right_mtrl_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/text_select_handle_left_mtrl_alpha.png b/core/res/res/drawable-xxhdpi/text_select_handle_left_mtrl_alpha.png
index 75085ce..d0f274a 100644
--- a/core/res/res/drawable-xxhdpi/text_select_handle_left_mtrl_alpha.png
+++ b/core/res/res/drawable-xxhdpi/text_select_handle_left_mtrl_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/text_select_handle_right_mtrl_alpha.png b/core/res/res/drawable-xxhdpi/text_select_handle_right_mtrl_alpha.png
index e2eb5be..f1f637a 100644
--- a/core/res/res/drawable-xxhdpi/text_select_handle_right_mtrl_alpha.png
+++ b/core/res/res/drawable-xxhdpi/text_select_handle_right_mtrl_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/text_select_handle_left_mtrl_alpha.png b/core/res/res/drawable-xxxhdpi/text_select_handle_left_mtrl_alpha.png
new file mode 100644
index 0000000..643168f
--- /dev/null
+++ b/core/res/res/drawable-xxxhdpi/text_select_handle_left_mtrl_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/text_select_handle_right_mtrl_alpha.png b/core/res/res/drawable-xxxhdpi/text_select_handle_right_mtrl_alpha.png
new file mode 100644
index 0000000..e8f3aad
--- /dev/null
+++ b/core/res/res/drawable-xxxhdpi/text_select_handle_right_mtrl_alpha.png
Binary files differ
diff --git a/core/res/res/values-watch/strings.xml b/core/res/res/values-watch/strings.xml
new file mode 100644
index 0000000..4ea2b52
--- /dev/null
+++ b/core/res/res/values-watch/strings.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** Copyright 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.
+*/
+-->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <!-- [CHAR LIMIT=16] Message shown in upgrading dialog for each .apk that is optimized. -->
+ <!-- Each word has an 8 character limit due to screen width limitation. -->
+ <string name="android_upgrading_apk">App
+ <xliff:g id="number" example="123">%1$d</xliff:g> of
+ <xliff:g id="number" example="123">%2$d</xliff:g>.</string>
+</resources>
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index 3f729ce..67ce159 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -5060,7 +5060,7 @@
<!-- Notify use that they are in Lock-to-app in accessibility mode -->
<string name="lock_to_app_toast_accessible">To unpin this screen, touch and hold Overview.</string>
<!-- Notify user that they are locked in lock-to-app mode -->
- <string name="lock_to_app_toast_locked">Screen is pinned. Unpinning isn\'t allowed by your organization.</string>
+ <string name="lock_to_app_toast_locked">App is pinned: Unpinning isn\'t allowed on this device.</string>
<!-- Starting lock-to-app indication. -->
<string name="lock_to_app_start">Screen pinned</string>
<!-- Exting lock-to-app indication. -->
diff --git a/docs/html/google/play-services/wallet.jd b/docs/html/google/play-services/wallet.jd
index e5ed514..744c8d3 100644
--- a/docs/html/google/play-services/wallet.jd
+++ b/docs/html/google/play-services/wallet.jd
@@ -17,14 +17,14 @@
available to US-based merchants. Once you've completed integration, you can
apply for production access by <a class="external-link" href="https://support.google.com/wallet/business/contact/ui_review">submitting your sandbox integration for review</a>.</p>
- <p>Check out the <a
+ <p>Check out the <a
href="{@docRoot}reference/com/google/android/gms/wallet/package-summary.html">Instant
Buy API reference</a> and visit
<a href="https://developers.google.com/wallet/instant-buy/">developers.google.com/wallet/instant-buy/</a>
for complete information about integrating Google Wallet Instant Buy into your app.</p>
</div>
-<div class="col-4">
+<div class="col-4">
<img src="{@docRoot}images/google/gps-wallet-instant.png" alt="" style="padding-bottom:14px;width:210px">
</div>
</div>
@@ -44,16 +44,16 @@
<h4>Streamline Purchases with Google+ Sign-On</h4>
<p>For users ready to purchase, you can simplify the login and account creation steps
by adding Google+ sign in. Users can sign in with a single click and share their
- profile information during the purchase.
+ profile information during the purchase.
<br />
<a href="https://developers.google.com/commerce/wallet/instant-buy/wallet-sso#android"
class="external-link">Add Google+ Sign-In for Wallet</a>.</p>
-
+
<h4>Minimize User Data Entry</h4>
<p>Google Wallet provides auto-completion of addresses, minimizing user data entry. You can also
retrieve billing and shipping addresses directly from the user’s Wallet to-do form pre-fills.<br />
<a class="external-link"
- href="https://developers.google.com/commerce/wallet/instant-buy/android/reference/com/google/android/gms/wallet/MaskedWallet#getBillingAddress()">Get
+ href="{@docRoot}reference/com/google/android/gms/wallet/MaskedWallet.html#getBillingAddress()">Get
billing addresses</a>.</p>
</div>
@@ -75,7 +75,7 @@
class="external-link" href="https://developers.google.com/wallet/instant-buy/android/tutorial">Instant Buy Android API tutorial</a>
provides directions on how to get the Wallet sample up and running.</p>
<h4>3. Read the documentation</h4>
- <p>For quick access while developing your Android apps, the <a
+ <p>For quick access while developing your Android apps, the <a
href="{@docRoot}reference/com/google/android/gms/wallet/package-summary.html">Google Wallet
API reference</a> is available here on developer.android.com.</p>
diff --git a/docs/html/tools/sdk/tools-notes.jd b/docs/html/tools/sdk/tools-notes.jd
index b5a6477..47b603a 100644
--- a/docs/html/tools/sdk/tools-notes.jd
+++ b/docs/html/tools/sdk/tools-notes.jd
@@ -24,7 +24,7 @@
<div class="toggle-content opened">
<p><a href="#" onclick="return toggleContent(this)">
<img src="{@docRoot}assets/images/triangle-opened.png" class="toggle-content-img"
- alt=""/>SDK Tools, Revision 24.1.2</a> <em>(February 2014)</em>
+ alt=""/>SDK Tools, Revision 24.1.2</a> <em>(February 2015)</em>
</p>
<div class="toggle-content-toggleme">
diff --git a/docs/html/training/scheduling/index.jd b/docs/html/training/scheduling/index.jd
index 4d2db60..4239ffb 100644
--- a/docs/html/training/scheduling/index.jd
+++ b/docs/html/training/scheduling/index.jd
@@ -1,5 +1,5 @@
page.title=Managing Device Awake State
-page.tags=
+page.tags=wakelock, AlarmManager, WakefulBroadcastReceiver
trainingnavtop=true
startpage=true
diff --git a/graphics/java/android/graphics/Bitmap.java b/graphics/java/android/graphics/Bitmap.java
index 132c6ef..5b20d48 100644
--- a/graphics/java/android/graphics/Bitmap.java
+++ b/graphics/java/android/graphics/Bitmap.java
@@ -21,6 +21,7 @@
import android.os.Parcelable;
import android.os.Trace;
import android.util.DisplayMetrics;
+
import dalvik.system.VMRuntime;
import java.io.OutputStream;
@@ -37,21 +38,14 @@
* @see Bitmap#setDensity(int)
*/
public static final int DENSITY_NONE = 0;
-
- /**
- * Note: mNativeBitmap is used by FaceDetector_jni.cpp
- * Don't change/rename without updating FaceDetector_jni.cpp
- *
- * @hide
- */
- public final long mNativeBitmap;
+
+ private final long mSkBitmapPtr;
/**
* Backing buffer for the Bitmap.
*/
private byte[] mBuffer;
- @SuppressWarnings({"FieldCanBeLocal", "UnusedDeclaration"}) // Keep to finalize native resources
private final BitmapFinalizer mFinalizer;
private final boolean mIsMutable;
@@ -92,11 +86,11 @@
sDefaultDensity = density;
}
+ @SuppressWarnings("deprecation")
static int getDefaultDensity() {
if (sDefaultDensity >= 0) {
return sDefaultDensity;
}
- //noinspection deprecation
sDefaultDensity = DisplayMetrics.DENSITY_DEVICE;
return sDefaultDensity;
}
@@ -105,7 +99,7 @@
* Private constructor that must received an already allocated native bitmap
* int (pointer).
*/
- @SuppressWarnings({"UnusedDeclaration"}) // called from JNI
+ // called from JNI
Bitmap(long nativeBitmap, byte[] buffer, int width, int height, int density,
boolean isMutable, boolean requestPremultiplied,
byte[] ninePatchChunk, NinePatch.InsetStruct ninePatchInsets) {
@@ -120,7 +114,7 @@
mBuffer = buffer;
// we delete this in our finalizer
- mNativeBitmap = nativeBitmap;
+ mSkBitmapPtr = nativeBitmap;
mNinePatchChunk = ninePatchChunk;
mNinePatchInsets = ninePatchInsets;
@@ -136,7 +130,7 @@
* Native bitmap has been reconfigured, so set premult and cached
* width/height values
*/
- @SuppressWarnings({"UnusedDeclaration"}) // called from JNI
+ // called from JNI
void reinit(int width, int height, boolean requestPremultiplied) {
mWidth = width;
mHeight = height;
@@ -227,7 +221,7 @@
throw new IllegalStateException("native-backed bitmaps may not be reconfigured");
}
- nativeReconfigure(mNativeBitmap, width, height, config.nativeInt, mBuffer.length,
+ nativeReconfigure(mSkBitmapPtr, width, height, config.nativeInt, mBuffer.length,
mRequestPremultiplied);
mWidth = width;
mHeight = height;
@@ -305,7 +299,7 @@
*/
public void recycle() {
if (!mRecycled && mFinalizer.mNativeBitmap != 0) {
- if (nativeRecycle(mNativeBitmap)) {
+ if (nativeRecycle(mSkBitmapPtr)) {
// return value indicates whether native pixel object was actually recycled.
// false indicates that it is still in use at the native level and these
// objects should not be collected now. They will be collected later when the
@@ -331,13 +325,13 @@
* Returns the generation ID of this bitmap. The generation ID changes
* whenever the bitmap is modified. This can be used as an efficient way to
* check if a bitmap has changed.
- *
+ *
* @return The current generation ID for this bitmap.
*/
public int getGenerationId() {
- return nativeGenerationId(mNativeBitmap);
+ return nativeGenerationId(mSkBitmapPtr);
}
-
+
/**
* This is called by methods that want to throw an exception if the bitmap
* has already been recycled.
@@ -399,12 +393,12 @@
* encoded: red is stored with 5 bits of precision (32 possible
* values), green is stored with 6 bits of precision (64 possible
* values) and blue is stored with 5 bits of precision.
- *
+ *
* This configuration can produce slight visual artifacts depending
* on the configuration of the source. For instance, without
* dithering, the result might show a greenish tint. To get better
* results dithering should be applied.
- *
+ *
* This configuration may be useful when using opaque bitmaps
* that do not require high color fidelity.
*/
@@ -414,18 +408,18 @@
* Each pixel is stored on 2 bytes. The three RGB color channels
* and the alpha channel (translucency) are stored with a 4 bits
* precision (16 possible values.)
- *
+ *
* This configuration is mostly useful if the application needs
* to store translucency information but also needs to save
* memory.
- *
+ *
* It is recommended to use {@link #ARGB_8888} instead of this
* configuration.
*
* Note: as of {@link android.os.Build.VERSION_CODES#KITKAT},
* any bitmap created with this configuration will be created
* using {@link #ARGB_8888} instead.
- *
+ *
* @deprecated Because of the poor quality of this configuration,
* it is advised to use {@link #ARGB_8888} instead.
*/
@@ -436,7 +430,7 @@
* Each pixel is stored on 4 bytes. Each channel (RGB and alpha
* for translucency) is stored with 8 bits of precision (256
* possible values.)
- *
+ *
* This configuration is very flexible and offers the best
* quality. It should be used whenever possible.
*/
@@ -444,11 +438,10 @@
final int nativeInt;
- @SuppressWarnings({"deprecation"})
private static Config sConfigs[] = {
null, ALPHA_8, null, RGB_565, ARGB_4444, ARGB_8888
};
-
+
Config(int ni) {
this.nativeInt = ni;
}
@@ -492,7 +485,7 @@
throw new RuntimeException("Buffer not large enough for pixels");
}
- nativeCopyPixelsToBuffer(mNativeBitmap, dst);
+ nativeCopyPixelsToBuffer(mSkBitmapPtr, dst);
// now update the buffer's position
int position = dst.position();
@@ -532,7 +525,7 @@
throw new RuntimeException("Buffer not large enough for pixels");
}
- nativeCopyPixelsFromBuffer(mNativeBitmap, src);
+ nativeCopyPixelsFromBuffer(mSkBitmapPtr, src);
// now update the buffer's position
int position = src.position();
@@ -554,7 +547,7 @@
*/
public Bitmap copy(Config config, boolean isMutable) {
checkRecycled("Can't copy a recycled bitmap");
- Bitmap b = nativeCopy(mNativeBitmap, config.nativeInt, isMutable);
+ Bitmap b = nativeCopy(mSkBitmapPtr, config.nativeInt, isMutable);
if (b != null) {
b.setPremultiplied(mRequestPremultiplied);
b.mDensity = mDensity;
@@ -564,7 +557,7 @@
/**
* Creates a new bitmap, scaled from an existing bitmap, when possible. If the
- * specified width and height are the same as the current width and height of
+ * specified width and height are the same as the current width and height of
* the source bitmap, the source bitmap is returned and no new bitmap is
* created.
*
@@ -639,7 +632,7 @@
* transformed by the optional matrix. The new bitmap may be the
* same object as source, or a copy may have been made. It is
* initialized with the same density as the original bitmap.
- *
+ *
* If the source bitmap is immutable and the requested subset is the
* same as the source bitmap itself, then the source bitmap is
* returned and no new bitmap is created.
@@ -781,8 +774,8 @@
* @param config The bitmap config to create.
* @param hasAlpha If the bitmap is ARGB_8888 this flag can be used to mark the
* bitmap as opaque. Doing so will clear the bitmap in black
- * instead of transparent.
- *
+ * instead of transparent.
+ *
* @throws IllegalArgumentException if the width or height are <= 0
*/
private static Bitmap createBitmap(int width, int height, Config config, boolean hasAlpha) {
@@ -800,8 +793,8 @@
* @param config The bitmap config to create.
* @param hasAlpha If the bitmap is ARGB_8888 this flag can be used to mark the
* bitmap as opaque. Doing so will clear the bitmap in black
- * instead of transparent.
- *
+ * instead of transparent.
+ *
* @throws IllegalArgumentException if the width or height are <= 0
*/
private static Bitmap createBitmap(DisplayMetrics display, int width, int height,
@@ -815,7 +808,7 @@
}
bm.setHasAlpha(hasAlpha);
if (config == Config.ARGB_8888 && !hasAlpha) {
- nativeErase(bm.mNativeBitmap, 0xff000000);
+ nativeErase(bm.mSkBitmapPtr, 0xff000000);
}
// No need to initialize the bitmap to zeroes with other configs;
// it is backed by a VM byte array which is by definition preinitialized
@@ -1005,7 +998,7 @@
throw new IllegalArgumentException("quality must be 0..100");
}
Trace.traceBegin(Trace.TRACE_TAG_RESOURCES, "Bitmap.compress");
- boolean result = nativeCompress(mNativeBitmap, format.nativeInt, quality,
+ boolean result = nativeCompress(mSkBitmapPtr, format.nativeInt, quality,
stream, new byte[WORKING_COMPRESS_STORAGE]);
Trace.traceEnd(Trace.TRACE_TAG_RESOURCES);
return result;
@@ -1022,12 +1015,12 @@
* <p>Indicates whether pixels stored in this bitmaps are stored pre-multiplied.
* When a pixel is pre-multiplied, the RGB components have been multiplied by
* the alpha component. For instance, if the original color is a 50%
- * translucent red <code>(128, 255, 0, 0)</code>, the pre-multiplied form is
+ * translucent red <code>(128, 255, 0, 0)</code>, the pre-multiplied form is
* <code>(128, 128, 0, 0)</code>.</p>
- *
+ *
* <p>This method always returns false if {@link #getConfig()} is
* {@link Bitmap.Config#RGB_565}.</p>
- *
+ *
* <p>The return value is undefined if {@link #getConfig()} is
* {@link Bitmap.Config#ALPHA_8}.</p>
*
@@ -1046,7 +1039,7 @@
* @see BitmapFactory.Options#inPremultiplied
*/
public final boolean isPremultiplied() {
- return nativeIsPremultiplied(mNativeBitmap);
+ return nativeIsPremultiplied(mSkBitmapPtr);
}
/**
@@ -1071,7 +1064,7 @@
*/
public final void setPremultiplied(boolean premultiplied) {
mRequestPremultiplied = premultiplied;
- nativeSetPremultiplied(mNativeBitmap, premultiplied);
+ nativeSetPremultiplied(mSkBitmapPtr, premultiplied);
}
/** Returns the bitmap's width */
@@ -1137,7 +1130,7 @@
public int getScaledHeight(int targetDensity) {
return scaleFromDensity(getHeight(), mDensity, targetDensity);
}
-
+
/**
* @hide
*/
@@ -1145,11 +1138,11 @@
if (sdensity == DENSITY_NONE || tdensity == DENSITY_NONE || sdensity == tdensity) {
return size;
}
-
+
// Scale by tdensity / sdensity, rounding up.
return ((size * tdensity) + (sdensity >> 1)) / sdensity;
}
-
+
/**
* Return the number of bytes between rows in the bitmap's pixels. Note that
* this refers to the pixels as stored natively by the bitmap. If you call
@@ -1163,7 +1156,7 @@
* @return number of bytes between rows of the native bitmap pixels.
*/
public final int getRowBytes() {
- return nativeRowBytes(mNativeBitmap);
+ return nativeRowBytes(mSkBitmapPtr);
}
/**
@@ -1206,7 +1199,7 @@
* that config, otherwise return null.
*/
public final Config getConfig() {
- return Config.nativeToConfig(nativeConfig(mNativeBitmap));
+ return Config.nativeToConfig(nativeConfig(mSkBitmapPtr));
}
/** Returns true if the bitmap's config supports per-pixel alpha, and
@@ -1218,7 +1211,7 @@
* it will return true by default.
*/
public final boolean hasAlpha() {
- return nativeHasAlpha(mNativeBitmap);
+ return nativeHasAlpha(mSkBitmapPtr);
}
/**
@@ -1232,28 +1225,28 @@
* non-opaque per-pixel alpha values.
*/
public void setHasAlpha(boolean hasAlpha) {
- nativeSetHasAlpha(mNativeBitmap, hasAlpha, mRequestPremultiplied);
+ nativeSetHasAlpha(mSkBitmapPtr, hasAlpha, mRequestPremultiplied);
}
/**
* Indicates whether the renderer responsible for drawing this
* bitmap should attempt to use mipmaps when this bitmap is drawn
* scaled down.
- *
+ *
* If you know that you are going to draw this bitmap at less than
* 50% of its original size, you may be able to obtain a higher
* quality
- *
+ *
* This property is only a suggestion that can be ignored by the
* renderer. It is not guaranteed to have any effect.
- *
+ *
* @return true if the renderer should attempt to use mipmaps,
* false otherwise
- *
+ *
* @see #setHasMipMap(boolean)
*/
public final boolean hasMipMap() {
- return nativeHasMipMap(mNativeBitmap);
+ return nativeHasMipMap(mSkBitmapPtr);
}
/**
@@ -1264,7 +1257,7 @@
* If you know that you are going to draw this bitmap at less than
* 50% of its original size, you may be able to obtain a higher
* quality by turning this property on.
- *
+ *
* Note that if the renderer respects this hint it might have to
* allocate extra memory to hold the mipmap levels for this bitmap.
*
@@ -1277,7 +1270,7 @@
* @see #hasMipMap()
*/
public final void setHasMipMap(boolean hasMipMap) {
- nativeSetHasMipMap(mNativeBitmap, hasMipMap);
+ nativeSetHasMipMap(mSkBitmapPtr, hasMipMap);
}
/**
@@ -1290,7 +1283,7 @@
if (!isMutable()) {
throw new IllegalStateException("cannot erase immutable bitmaps");
}
- nativeErase(mNativeBitmap, c);
+ nativeErase(mSkBitmapPtr, c);
}
/**
@@ -1306,7 +1299,7 @@
public int getPixel(int x, int y) {
checkRecycled("Can't call getPixel() on a recycled bitmap");
checkPixelAccess(x, y);
- return nativeGetPixel(mNativeBitmap, x, y);
+ return nativeGetPixel(mSkBitmapPtr, x, y);
}
/**
@@ -1339,14 +1332,14 @@
return; // nothing to do
}
checkPixelsAccess(x, y, width, height, offset, stride, pixels);
- nativeGetPixels(mNativeBitmap, pixels, offset, stride,
+ nativeGetPixels(mSkBitmapPtr, pixels, offset, stride,
x, y, width, height);
}
/**
* Shared code to check for illegal arguments passed to getPixel()
* or setPixel()
- *
+ *
* @param x x coordinate of the pixel
* @param y y coordinate of the pixel
*/
@@ -1420,7 +1413,7 @@
throw new IllegalStateException();
}
checkPixelAccess(x, y);
- nativeSetPixel(mNativeBitmap, x, y, color);
+ nativeSetPixel(mSkBitmapPtr, x, y, color);
}
/**
@@ -1456,7 +1449,7 @@
return; // nothing to do
}
checkPixelsAccess(x, y, width, height, offset, stride, pixels);
- nativeSetPixels(mNativeBitmap, pixels, offset, stride,
+ nativeSetPixels(mSkBitmapPtr, pixels, offset, stride,
x, y, width, height);
}
@@ -1494,7 +1487,7 @@
*/
public void writeToParcel(Parcel p, int flags) {
checkRecycled("Can't parcel a recycled bitmap");
- if (!nativeWriteToParcel(mNativeBitmap, mIsMutable, mDensity, p)) {
+ if (!nativeWriteToParcel(mSkBitmapPtr, mIsMutable, mDensity, p)) {
throw new RuntimeException("native writeToParcel failed");
}
}
@@ -1522,9 +1515,9 @@
* -2, -2, so that drawing the alpha bitmap offset by (-2, -2) and then
* drawing the original would result in the blur visually aligning with
* the original.
- *
+ *
* <p>The initial density of the returned bitmap is the same as the original's.
- *
+ *
* @param paint Optional paint used to modify the alpha values in the
* resulting bitmap. Pass null for default behavior.
* @param offsetXY Optional array that returns the X (index 0) and Y
@@ -1538,7 +1531,7 @@
public Bitmap extractAlpha(Paint paint, int[] offsetXY) {
checkRecycled("Can't extractAlpha on a recycled bitmap");
long nativePaint = paint != null ? paint.getNativeInstance() : 0;
- Bitmap bm = nativeExtractAlpha(mNativeBitmap, nativePaint, offsetXY);
+ Bitmap bm = nativeExtractAlpha(mSkBitmapPtr, nativePaint, offsetXY);
if (bm == null) {
throw new RuntimeException("Failed to extractAlpha on Bitmap");
}
@@ -1552,7 +1545,7 @@
* If other is null, return false.
*/
public boolean sameAs(Bitmap other) {
- return this == other || (other != null && nativeSameAs(mNativeBitmap, other.mNativeBitmap));
+ return this == other || (other != null && nativeSameAs(mSkBitmapPtr, other.mSkBitmapPtr));
}
/**
@@ -1567,7 +1560,12 @@
* and therefore is harmless.
*/
public void prepareToDraw() {
- nativePrepareToDraw(mNativeBitmap);
+ nativePrepareToDraw(mSkBitmapPtr);
+ }
+
+ /** @hide */
+ public final long getSkBitmap() {
+ return mSkBitmapPtr;
}
private static class BitmapFinalizer {
@@ -1658,8 +1656,4 @@
private static native boolean nativeHasMipMap(long nativeBitmap);
private static native void nativeSetHasMipMap(long nativeBitmap, boolean hasMipMap);
private static native boolean nativeSameAs(long nativeBitmap0, long nativeBitmap1);
-
- /* package */ final long ni() {
- return mNativeBitmap;
- }
}
diff --git a/graphics/java/android/graphics/BitmapShader.java b/graphics/java/android/graphics/BitmapShader.java
index 5e004a3..f2f890e 100644
--- a/graphics/java/android/graphics/BitmapShader.java
+++ b/graphics/java/android/graphics/BitmapShader.java
@@ -42,7 +42,7 @@
mBitmap = bitmap;
mTileX = tileX;
mTileY = tileY;
- final long b = bitmap.ni();
+ final long b = bitmap.getSkBitmap();
init(nativeCreate(b, tileX.nativeInt, tileY.nativeInt));
}
diff --git a/graphics/java/android/graphics/Canvas.java b/graphics/java/android/graphics/Canvas.java
index e4c2f0e..85fa3cb 100644
--- a/graphics/java/android/graphics/Canvas.java
+++ b/graphics/java/android/graphics/Canvas.java
@@ -154,7 +154,7 @@
throw new IllegalStateException("Immutable bitmap passed to Canvas constructor");
}
throwIfCannotDraw(bitmap);
- mNativeCanvasWrapper = initRaster(bitmap.ni());
+ mNativeCanvasWrapper = initRaster(bitmap.getSkBitmap());
mFinalizer = new CanvasFinalizer(mNativeCanvasWrapper);
mBitmap = bitmap;
mDensity = bitmap.mDensity;
@@ -219,7 +219,7 @@
}
throwIfCannotDraw(bitmap);
- native_setBitmap(mNativeCanvasWrapper, bitmap.ni(), true);
+ native_setBitmap(mNativeCanvasWrapper, bitmap.getSkBitmap(), true);
mDensity = bitmap.mDensity;
}
@@ -1339,7 +1339,7 @@
*/
public void drawBitmap(@NonNull Bitmap bitmap, float left, float top, @Nullable Paint paint) {
throwIfCannotDraw(bitmap);
- native_drawBitmap(mNativeCanvasWrapper, bitmap.ni(), left, top,
+ native_drawBitmap(mNativeCanvasWrapper, bitmap.getSkBitmap(), left, top,
paint != null ? paint.getNativeInstance() : 0, mDensity, mScreenDensity, bitmap.mDensity);
}
@@ -1385,7 +1385,7 @@
bottom = src.bottom;
}
- native_drawBitmap(mNativeCanvasWrapper, bitmap.ni(), left, top, right, bottom,
+ native_drawBitmap(mNativeCanvasWrapper, bitmap.getSkBitmap(), left, top, right, bottom,
dst.left, dst.top, dst.right, dst.bottom, nativePaint, mScreenDensity,
bitmap.mDensity);
}
@@ -1432,7 +1432,7 @@
bottom = src.bottom;
}
- native_drawBitmap(mNativeCanvasWrapper, bitmap.ni(), left, top, right, bottom,
+ native_drawBitmap(mNativeCanvasWrapper, bitmap.getSkBitmap(), left, top, right, bottom,
dst.left, dst.top, dst.right, dst.bottom, nativePaint, mScreenDensity,
bitmap.mDensity);
}
@@ -1513,7 +1513,7 @@
* @param paint May be null. The paint used to draw the bitmap
*/
public void drawBitmap(@NonNull Bitmap bitmap, @NonNull Matrix matrix, @Nullable Paint paint) {
- nativeDrawBitmapMatrix(mNativeCanvasWrapper, bitmap.ni(), matrix.ni(),
+ nativeDrawBitmapMatrix(mNativeCanvasWrapper, bitmap.getSkBitmap(), matrix.ni(),
paint != null ? paint.getNativeInstance() : 0);
}
@@ -1568,7 +1568,7 @@
// no mul by 2, since we need only 1 color per vertex
checkRange(colors.length, colorOffset, count);
}
- nativeDrawBitmapMesh(mNativeCanvasWrapper, bitmap.ni(), meshWidth, meshHeight,
+ nativeDrawBitmapMesh(mNativeCanvasWrapper, bitmap.getSkBitmap(), meshWidth, meshHeight,
verts, vertOffset, colors, colorOffset,
paint != null ? paint.getNativeInstance() : 0);
}
diff --git a/graphics/java/android/graphics/NinePatch.java b/graphics/java/android/graphics/NinePatch.java
index ebc86aa..9c4299a 100644
--- a/graphics/java/android/graphics/NinePatch.java
+++ b/graphics/java/android/graphics/NinePatch.java
@@ -98,7 +98,7 @@
public NinePatch(Bitmap bitmap, byte[] chunk, String srcName) {
mBitmap = bitmap;
mSrcName = srcName;
- mNativeChunk = validateNinePatchChunk(mBitmap.ni(), chunk);
+ mNativeChunk = validateNinePatchChunk(mBitmap.getSkBitmap(), chunk);
}
/**
@@ -199,12 +199,12 @@
}
void drawSoftware(Canvas canvas, RectF location, Paint paint) {
- nativeDraw(canvas.getNativeCanvasWrapper(), location, mBitmap.ni(), mNativeChunk,
+ nativeDraw(canvas.getNativeCanvasWrapper(), location, mBitmap.getSkBitmap(), mNativeChunk,
paint != null ? paint.getNativeInstance() : 0, canvas.mDensity, mBitmap.mDensity);
}
void drawSoftware(Canvas canvas, Rect location, Paint paint) {
- nativeDraw(canvas.getNativeCanvasWrapper(), location, mBitmap.ni(), mNativeChunk,
+ nativeDraw(canvas.getNativeCanvasWrapper(), location, mBitmap.getSkBitmap(), mNativeChunk,
paint != null ? paint.getNativeInstance() : 0, canvas.mDensity, mBitmap.mDensity);
}
@@ -252,7 +252,7 @@
* that are transparent.
*/
public final Region getTransparentRegion(Rect bounds) {
- long r = nativeGetTransparentRegion(mBitmap.ni(), mNativeChunk, bounds);
+ long r = nativeGetTransparentRegion(mBitmap.getSkBitmap(), mNativeChunk, bounds);
return r != 0 ? new Region(r) : null;
}
diff --git a/graphics/java/android/graphics/Paint.java b/graphics/java/android/graphics/Paint.java
index 91c8dba..681bc62 100644
--- a/graphics/java/android/graphics/Paint.java
+++ b/graphics/java/android/graphics/Paint.java
@@ -534,8 +534,9 @@
* @hide
*/
public long getNativeInstance() {
- if (mShader != null && mShader.getNativeInstance() != mNativeShader) {
- mNativeShader = mShader.getNativeInstance();
+ long newNativeShader = mShader == null ? 0 : mShader.getNativeInstance();
+ if (newNativeShader != mNativeShader) {
+ mNativeShader = newNativeShader;
native_setShader(mNativePaint, mNativeShader);
}
return mNativePaint;
diff --git a/graphics/java/android/graphics/PorterDuff.java b/graphics/java/android/graphics/PorterDuff.java
index 2ef1662..f5fbe70 100644
--- a/graphics/java/android/graphics/PorterDuff.java
+++ b/graphics/java/android/graphics/PorterDuff.java
@@ -18,7 +18,7 @@
public class PorterDuff {
- // these value must match their native equivalents. See SkPorterDuff.h
+ // these value must match their native equivalents. See SkXfermode.h
public enum Mode {
/** [0, 0] */
CLEAR (0),
@@ -46,17 +46,17 @@
XOR (11),
/** [Sa + Da - Sa*Da,
Sc*(1 - Da) + Dc*(1 - Sa) + min(Sc, Dc)] */
- DARKEN (12),
+ DARKEN (16),
/** [Sa + Da - Sa*Da,
Sc*(1 - Da) + Dc*(1 - Sa) + max(Sc, Dc)] */
- LIGHTEN (13),
+ LIGHTEN (17),
/** [Sa * Da, Sc * Dc] */
- MULTIPLY (14),
+ MULTIPLY (24),
/** [Sa + Da - Sa * Da, Sc + Dc - Sc * Dc] */
- SCREEN (15),
+ SCREEN (14),
/** Saturate(S + D) */
- ADD (16),
- OVERLAY (17);
+ ADD (12),
+ OVERLAY (15);
Mode(int nativeInt) {
this.nativeInt = nativeInt;
diff --git a/graphics/java/android/graphics/pdf/PdfRenderer.java b/graphics/java/android/graphics/pdf/PdfRenderer.java
index 79934da..b32dcc6 100644
--- a/graphics/java/android/graphics/pdf/PdfRenderer.java
+++ b/graphics/java/android/graphics/pdf/PdfRenderer.java
@@ -380,7 +380,7 @@
final long transformPtr = (transform != null) ? transform.native_instance : 0;
- nativeRenderPage(mNativeDocument, mNativePage, destination.mNativeBitmap, contentLeft,
+ nativeRenderPage(mNativeDocument, mNativePage, destination.getSkBitmap(), contentLeft,
contentTop, contentRight, contentBottom, transformPtr, renderMode);
}
diff --git a/libs/hwui/DisplayListRenderer.h b/libs/hwui/DisplayListRenderer.h
index 71c1fc3..d313c18 100644
--- a/libs/hwui/DisplayListRenderer.h
+++ b/libs/hwui/DisplayListRenderer.h
@@ -216,7 +216,7 @@
virtual void drawVertices(SkCanvas::VertexMode vertexMode, int vertexCount,
const float* verts, const float* tex, const int* colors,
const uint16_t* indices, int indexCount, const SkPaint& paint) override
- { LOG_ALWAYS_FATAL("DisplayListRenderer does not support drawVertices()"); }
+ { /* DisplayListRenderer does not support drawVertices(); ignore */ }
// Bitmap-based
virtual void drawBitmap(const SkBitmap& bitmap, float left, float top, const SkPaint* paint) override;
diff --git a/libs/hwui/SkiaCanvas.cpp b/libs/hwui/SkiaCanvas.cpp
index efbb709..71088b7 100644
--- a/libs/hwui/SkiaCanvas.cpp
+++ b/libs/hwui/SkiaCanvas.cpp
@@ -22,7 +22,6 @@
#include <SkDeque.h>
#include <SkDrawFilter.h>
#include <SkGraphics.h>
-#include <SkPorterDuff.h>
#include <SkShader.h>
#include <SkTArray.h>
#include <SkTemplates.h>
diff --git a/libs/hwui/SkiaCanvasProxy.cpp b/libs/hwui/SkiaCanvasProxy.cpp
index 3c65705..ec1bb90 100644
--- a/libs/hwui/SkiaCanvasProxy.cpp
+++ b/libs/hwui/SkiaCanvasProxy.cpp
@@ -22,9 +22,10 @@
namespace android {
namespace uirenderer {
-SkiaCanvasProxy::SkiaCanvasProxy(Canvas* canvas)
+SkiaCanvasProxy::SkiaCanvasProxy(Canvas* canvas, bool filterHwuiCalls)
: INHERITED(canvas->width(), canvas->height())
- , mCanvas(canvas) {}
+ , mCanvas(canvas)
+ , mFilterHwuiCalls(filterHwuiCalls) {}
void SkiaCanvasProxy::onDrawPaint(const SkPaint& paint) {
mCanvas->drawPaint(paint);
@@ -32,6 +33,10 @@
void SkiaCanvasProxy::onDrawPoints(PointMode pointMode, size_t count, const SkPoint pts[],
const SkPaint& paint) {
+ if (!pts || count == 0) {
+ return;
+ }
+
// convert the SkPoints into floats
SK_COMPILE_ASSERT(sizeof(SkPoint) == sizeof(float)*2, SkPoint_is_no_longer_2_floats);
const size_t floatCount = count << 1;
@@ -118,6 +123,9 @@
void SkiaCanvasProxy::onDrawVertices(VertexMode mode, int vertexCount, const SkPoint vertices[],
const SkPoint texs[], const SkColor colors[], SkXfermode*, const uint16_t indices[],
int indexCount, const SkPaint& paint) {
+ if (mFilterHwuiCalls) {
+ return;
+ }
// convert the SkPoints into floats
SK_COMPILE_ASSERT(sizeof(SkPoint) == sizeof(float)*2, SkPoint_is_no_longer_2_floats);
const int floatCount = vertexCount << 1;
@@ -312,6 +320,9 @@
void SkiaCanvasProxy::onDrawPatch(const SkPoint cubics[12], const SkColor colors[4],
const SkPoint texCoords[4], SkXfermode* xmode, const SkPaint& paint) {
+ if (mFilterHwuiCalls) {
+ return;
+ }
SkPatchUtils::VertexData data;
SkMatrix matrix;
diff --git a/libs/hwui/SkiaCanvasProxy.h b/libs/hwui/SkiaCanvasProxy.h
index 4322fcf..0de9650 100644
--- a/libs/hwui/SkiaCanvasProxy.h
+++ b/libs/hwui/SkiaCanvasProxy.h
@@ -27,16 +27,19 @@
/**
* This class serves as a proxy between Skia's SkCanvas and Android Framework's
- * Canvas. The class does not maintain any state and will pass through any request
- * directly to the Canvas provided in the constructor.
+ * Canvas. The class does not maintain any draw-related state and will pass
+ * through most requests directly to the Canvas provided in the constructor.
*
* Upon construction it is expected that the provided Canvas has already been
* prepared for recording and will continue to be in the recording state while
* this proxy class is being used.
+ *
+ * If filterHwuiCalls is true, the proxy silently ignores away draw calls that
+ * aren't supported by HWUI.
*/
class ANDROID_API SkiaCanvasProxy : public SkCanvas {
public:
- SkiaCanvasProxy(Canvas* canvas);
+ SkiaCanvasProxy(Canvas* canvas, bool filterHwuiCalls = false);
virtual ~SkiaCanvasProxy() {}
protected:
@@ -94,6 +97,7 @@
private:
Canvas* mCanvas;
+ bool mFilterHwuiCalls;
typedef SkCanvas INHERITED;
};
diff --git a/media/jni/android_media_MediaMetadataRetriever.cpp b/media/jni/android_media_MediaMetadataRetriever.cpp
index 93138fa..2f6bbf4 100644
--- a/media/jni/android_media_MediaMetadataRetriever.cpp
+++ b/media/jni/android_media_MediaMetadataRetriever.cpp
@@ -40,7 +40,6 @@
struct fields_t {
jfieldID context;
jclass bitmapClazz; // Must be a global ref
- jfieldID nativeBitmap;
jmethodID createBitmapMethod;
jmethodID createScaledBitmapMethod;
jclass configClazz; // Must be a global ref
@@ -282,8 +281,7 @@
return NULL;
}
- SkBitmap *bitmap =
- (SkBitmap *) env->GetLongField(jBitmap, fields.nativeBitmap);
+ SkBitmap *bitmap = GraphicsJNI::getSkBitmap(env, jBitmap);
bitmap->lockPixels();
rotate((uint16_t*)bitmap->getPixels(),
@@ -421,10 +419,6 @@
if (fields.createScaledBitmapMethod == NULL) {
return;
}
- fields.nativeBitmap = env->GetFieldID(fields.bitmapClazz, "mNativeBitmap", "J");
- if (fields.nativeBitmap == NULL) {
- return;
- }
jclass configClazz = env->FindClass("android/graphics/Bitmap$Config");
if (configClazz == NULL) {
diff --git a/native/graphics/jni/bitmap.cpp b/native/graphics/jni/bitmap.cpp
index ea32edc..ddb01a0 100644
--- a/native/graphics/jni/bitmap.cpp
+++ b/native/graphics/jni/bitmap.cpp
@@ -27,7 +27,7 @@
return ANDROID_BITMAP_RESULT_BAD_PARAMETER;
}
- SkBitmap* bm = GraphicsJNI::getNativeBitmap(env, jbitmap);
+ SkBitmap* bm = GraphicsJNI::getSkBitmap(env, jbitmap);
if (NULL == bm) {
return ANDROID_BITMAP_RESULT_JNI_EXCEPTION;
}
@@ -64,7 +64,7 @@
return ANDROID_BITMAP_RESULT_BAD_PARAMETER;
}
- SkBitmap* bm = GraphicsJNI::getNativeBitmap(env, jbitmap);
+ SkBitmap* bm = GraphicsJNI::getSkBitmap(env, jbitmap);
if (NULL == bm) {
return ANDROID_BITMAP_RESULT_JNI_EXCEPTION;
}
@@ -87,7 +87,7 @@
return ANDROID_BITMAP_RESULT_BAD_PARAMETER;
}
- SkBitmap* bm = GraphicsJNI::getNativeBitmap(env, jbitmap);
+ SkBitmap* bm = GraphicsJNI::getSkBitmap(env, jbitmap);
if (NULL == bm) {
return ANDROID_BITMAP_RESULT_JNI_EXCEPTION;
}
diff --git a/opengl/java/android/opengl/GLUtils.java b/opengl/java/android/opengl/GLUtils.java
index a9d33dd..4d890c9 100644
--- a/opengl/java/android/opengl/GLUtils.java
+++ b/opengl/java/android/opengl/GLUtils.java
@@ -29,14 +29,6 @@
public final class GLUtils {
- /*
- * We use a class initializer to allow the native code to cache some
- * field offsets.
- */
- static {
- nativeClassInit();
- }
-
private GLUtils() {
}
@@ -275,8 +267,6 @@
*/
native public static void setTracingLevel(int level);
- native private static void nativeClassInit();
-
native private static int native_getInternalFormat(Bitmap bitmap);
native private static int native_getType(Bitmap bitmap);
native private static int native_texImage2D(int target, int level, int internalformat,
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
index 3a812cc..37d9a73 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
@@ -59,6 +59,7 @@
import android.service.notification.StatusBarNotification;
import android.text.TextUtils;
import android.util.Log;
+import android.util.Slog;
import android.util.SparseArray;
import android.util.SparseBooleanArray;
import android.view.Display;
@@ -2150,6 +2151,14 @@
}
public boolean isKeyguardSecure() {
+ if (mStatusBarKeyguardViewManager == null) {
+ // startKeyguard() hasn't been called yet, so we don't know.
+ // Make sure anything that needs to know isKeyguardSecure() checks and re-checks this
+ // value onVisibilityChanged().
+ Slog.w(TAG, "isKeyguardSecure() called before startKeyguard(), returning false",
+ new Throwable());
+ return false;
+ }
return mStatusBarKeyguardViewManager.isSecure();
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java
index acf7af9..0c21b20 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java
@@ -220,6 +220,7 @@
public void setPhoneStatusBar(PhoneStatusBar phoneStatusBar) {
mPhoneStatusBar = phoneStatusBar;
+ updateCameraVisibility(); // in case onFinishInflate() was called too early
}
private Intent getCameraIntent() {
@@ -231,6 +232,10 @@
}
private void updateCameraVisibility() {
+ if (mCameraImageView == null) {
+ // Things are not set up yet; reply hazy, ask again later
+ return;
+ }
ResolveInfo resolved = mContext.getPackageManager().resolveActivityAsUser(getCameraIntent(),
PackageManager.MATCH_DEFAULT_ONLY,
mLockPatternUtils.getCurrentUser());
@@ -253,7 +258,7 @@
private boolean isCameraDisabledByDpm() {
final DevicePolicyManager dpm =
(DevicePolicyManager) getContext().getSystemService(Context.DEVICE_POLICY_SERVICE);
- if (dpm != null) {
+ if (dpm != null && mPhoneStatusBar != null) {
try {
final int userId = ActivityManagerNative.getDefault().getCurrentUser().id;
final int disabledFlags = dpm.getKeyguardDisabledFeatures(null, userId);
diff --git a/preloaded-classes b/preloaded-classes
index dee84f0..c8d8c5d 100644
--- a/preloaded-classes
+++ b/preloaded-classes
@@ -1172,6 +1172,7 @@
android.telecom.InCallService
android.telephony.PhoneNumberUtils
android.telephony.Rlog
+android.telephony.SignalStrength
android.telephony.SubscriptionManager
android.telephony.TelephonyManager
android.text.AndroidBidi
diff --git a/rs/jni/Android.mk b/rs/jni/Android.mk
index f1f0bfc..94f0859 100644
--- a/rs/jni/Android.mk
+++ b/rs/jni/Android.mk
@@ -14,7 +14,8 @@
libskia \
libutils \
libui \
- libgui
+ libgui \
+ libjnigraphics
LOCAL_STATIC_LIBRARIES :=
@@ -23,6 +24,7 @@
LOCAL_C_INCLUDES += \
$(JNI_H_INCLUDE) \
frameworks/rs \
+ frameworks/base/core/jni \
$(rs_generated_include_dir)
LOCAL_CFLAGS += -Wno-unused-parameter -std=c++11
diff --git a/rs/jni/android_renderscript_RenderScript.cpp b/rs/jni/android_renderscript_RenderScript.cpp
index a145166..d8e1464 100644
--- a/rs/jni/android_renderscript_RenderScript.cpp
+++ b/rs/jni/android_renderscript_RenderScript.cpp
@@ -24,8 +24,6 @@
#include <utils/misc.h>
#include <inttypes.h>
-#include <SkBitmap.h>
-
#include <androidfw/Asset.h>
#include <androidfw/AssetManager.h>
#include <androidfw/ResourceTypes.h>
@@ -35,6 +33,7 @@
#include "android_runtime/AndroidRuntime.h"
#include "android_runtime/android_view_Surface.h"
#include "android_runtime/android_util_AssetManager.h"
+#include "android/graphics/GraphicsJNI.h"
#include <rs.h>
#include <rsEnv.h>
@@ -172,14 +171,10 @@
// ---------------------------------------------------------------------------
static jfieldID gContextId = 0;
-static jfieldID gNativeBitmapID = 0;
static void _nInit(JNIEnv *_env, jclass _this)
{
gContextId = _env->GetFieldID(_this, "mContext", "J");
-
- jclass bitmapClass = _env->FindClass("android/graphics/Bitmap");
- gNativeBitmapID = _env->GetFieldID(bitmapClass, "mNativeBitmap", "J");
}
// ---------------------------------------------------------------------------
@@ -934,7 +929,7 @@
jobject jbitmap, jint usage)
{
SkBitmap const * nativeBitmap =
- (SkBitmap const *)_env->GetLongField(jbitmap, gNativeBitmapID);
+ GraphicsJNI::getSkBitmap(_env, jbitmap);
const SkBitmap& bitmap(*nativeBitmap);
bitmap.lockPixels();
@@ -951,7 +946,7 @@
jint mip, jobject jbitmap, jint usage)
{
SkBitmap const * nativeBitmap =
- (SkBitmap const *)_env->GetLongField(jbitmap, gNativeBitmapID);
+ GraphicsJNI::getSkBitmap(_env, jbitmap);
const SkBitmap& bitmap(*nativeBitmap);
bitmap.lockPixels();
@@ -968,7 +963,7 @@
jobject jbitmap, jint usage)
{
SkBitmap const * nativeBitmap =
- (SkBitmap const *)_env->GetLongField(jbitmap, gNativeBitmapID);
+ GraphicsJNI::getSkBitmap(_env, jbitmap);
const SkBitmap& bitmap(*nativeBitmap);
bitmap.lockPixels();
@@ -984,7 +979,7 @@
nAllocationCopyFromBitmap(JNIEnv *_env, jobject _this, jlong con, jlong alloc, jobject jbitmap)
{
SkBitmap const * nativeBitmap =
- (SkBitmap const *)_env->GetLongField(jbitmap, gNativeBitmapID);
+ GraphicsJNI::getSkBitmap(_env, jbitmap);
const SkBitmap& bitmap(*nativeBitmap);
int w = bitmap.width();
int h = bitmap.height();
@@ -1001,7 +996,7 @@
nAllocationCopyToBitmap(JNIEnv *_env, jobject _this, jlong con, jlong alloc, jobject jbitmap)
{
SkBitmap const * nativeBitmap =
- (SkBitmap const *)_env->GetLongField(jbitmap, gNativeBitmapID);
+ GraphicsJNI::getSkBitmap(_env, jbitmap);
const SkBitmap& bitmap(*nativeBitmap);
bitmap.lockPixels();
diff --git a/services/backup/java/com/android/server/backup/BackupManagerService.java b/services/backup/java/com/android/server/backup/BackupManagerService.java
index 94d400a..26510328 100644
--- a/services/backup/java/com/android/server/backup/BackupManagerService.java
+++ b/services/backup/java/com/android/server/backup/BackupManagerService.java
@@ -601,7 +601,7 @@
return token;
}
- // High level policy: apps are ineligible for backup if certain conditions apply
+ // High level policy: apps are generally ineligible for backup if certain conditions apply
public static boolean appIsEligibleForBackup(ApplicationInfo app) {
// 1. their manifest states android:allowBackup="false"
if ((app.flags&ApplicationInfo.FLAG_ALLOW_BACKUP) == 0) {
@@ -628,7 +628,7 @@
return (pkg.applicationInfo.flags & ApplicationInfo.FLAG_FULL_BACKUP_ONLY) != 0;
}
- // No agent means we do full backups for it
+ // No agent or fullBackupOnly="true" means we do indeed perform full-data backups for it
return true;
}
@@ -1266,7 +1266,23 @@
for (int i = 0; i < N; i++) {
String pkgName = in.readUTF();
long lastBackup = in.readLong();
- schedule.add(new FullBackupEntry(pkgName, lastBackup));
+ try {
+ PackageInfo pkg = mPackageManager.getPackageInfo(pkgName, 0);
+ if (appGetsFullBackup(pkg)
+ && appIsEligibleForBackup(pkg.applicationInfo)) {
+ schedule.add(new FullBackupEntry(pkgName, lastBackup));
+ } else {
+ if (DEBUG) {
+ Slog.i(TAG, "Package " + pkgName
+ + " no longer eligible for full backup");
+ }
+ }
+ } catch (NameNotFoundException e) {
+ if (DEBUG) {
+ Slog.i(TAG, "Package " + pkgName
+ + " not installed; dropping from full backup");
+ }
+ }
}
Collections.sort(schedule);
} catch (Exception e) {
@@ -1289,7 +1305,7 @@
schedule = new ArrayList<FullBackupEntry>(N);
for (int i = 0; i < N; i++) {
PackageInfo info = apps.get(i);
- if (appGetsFullBackup(info)) {
+ if (appGetsFullBackup(info) && appIsEligibleForBackup(info.applicationInfo)) {
schedule.add(new FullBackupEntry(info.packageName, 0));
}
}
@@ -1761,11 +1777,11 @@
addPackageParticipantsLocked(pkgList);
}
// If they're full-backup candidates, add them there instead
+ final long now = System.currentTimeMillis();
for (String packageName : pkgList) {
try {
PackageInfo app = mPackageManager.getPackageInfo(packageName, 0);
- long now = System.currentTimeMillis();
- if (appGetsFullBackup(app)) {
+ if (appGetsFullBackup(app) && appIsEligibleForBackup(app.applicationInfo)) {
enqueueFullBackup(packageName, now);
scheduleNextFullBackupJob();
}
@@ -2462,7 +2478,7 @@
BackupRequest request = mQueue.get(0);
mQueue.remove(0);
- Slog.d(TAG, "starting agent for backup of " + request);
+ Slog.d(TAG, "starting key/value backup of " + request);
addBackupTrace("launch agent for " + request.packageName);
// Verify that the requested app exists; it might be something that
@@ -2473,13 +2489,24 @@
try {
mCurrentPackage = mPackageManager.getPackageInfo(request.packageName,
PackageManager.GET_SIGNATURES);
- if (mCurrentPackage.applicationInfo.backupAgentName == null) {
+ if (!appIsEligibleForBackup(mCurrentPackage.applicationInfo)) {
// The manifest has changed but we had a stale backup request pending.
// This won't happen again because the app won't be requesting further
// backups.
Slog.i(TAG, "Package " + request.packageName
+ " no longer supports backup; skipping");
- addBackupTrace("skipping - no agent, completion is noop");
+ addBackupTrace("skipping - not eligible, completion is noop");
+ executeNextState(BackupState.RUNNING_QUEUE);
+ return;
+ }
+
+ if (appGetsFullBackup(mCurrentPackage)) {
+ // It's possible that this app *formerly* was enqueued for key/value backup,
+ // but has since been updated and now only supports the full-data path.
+ // Don't proceed with a key/value backup for it in this case.
+ Slog.i(TAG, "Package " + request.packageName
+ + " requests full-data rather than key/value; skipping");
+ addBackupTrace("skipping - fullBackupOnly, completion is noop");
executeNextState(BackupState.RUNNING_QUEUE);
return;
}
@@ -9161,6 +9188,8 @@
// check whether there is data for it in the current dataset, falling back
// to the ancestral dataset if not.
long token = getAvailableRestoreToken(packageName);
+ if (DEBUG) Slog.v(TAG, "restorePackage pkg=" + packageName
+ + " token=" + Long.toHexString(token));
// If we didn't come up with a place to look -- no ancestral dataset and
// the app has never been backed up from this device -- there's nothing
diff --git a/services/core/java/com/android/server/AssetAtlasService.java b/services/core/java/com/android/server/AssetAtlasService.java
index a2c87b9..e6dc1c7 100644
--- a/services/core/java/com/android/server/AssetAtlasService.java
+++ b/services/core/java/com/android/server/AssetAtlasService.java
@@ -291,7 +291,7 @@
}
canvas.drawBitmap(bitmap, 0.0f, 0.0f, null);
canvas.restore();
- atlasMap[mapIndex++] = bitmap.mNativeBitmap;
+ atlasMap[mapIndex++] = bitmap.getSkBitmap();
atlasMap[mapIndex++] = entry.x;
atlasMap[mapIndex++] = entry.y;
atlasMap[mapIndex++] = entry.rotated ? 1 : 0;
diff --git a/services/core/java/com/android/server/am/ActiveServices.java b/services/core/java/com/android/server/am/ActiveServices.java
index 059dde1..fc95b00 100755
--- a/services/core/java/com/android/server/am/ActiveServices.java
+++ b/services/core/java/com/android/server/am/ActiveServices.java
@@ -16,6 +16,8 @@
package com.android.server.am;
+import static com.android.server.am.ActivityManagerDebugConfig.*;
+
import java.io.FileDescriptor;
import java.io.IOException;
import java.io.PrintWriter;
@@ -33,6 +35,7 @@
import android.os.SystemProperties;
import android.util.ArrayMap;
import android.util.ArraySet;
+
import com.android.internal.app.ProcessStats;
import com.android.internal.os.BatteryStatsImpl;
import com.android.internal.os.TransferPipe;
@@ -67,14 +70,15 @@
import android.util.TimeUtils;
public final class ActiveServices {
- static final boolean DEBUG_SERVICE = ActivityManagerService.DEBUG_SERVICE;
- static final boolean DEBUG_SERVICE_EXECUTING = ActivityManagerService.DEBUG_SERVICE_EXECUTING;
- static final boolean DEBUG_DELAYED_SERVICE = ActivityManagerService.DEBUG_SERVICE;
- static final boolean DEBUG_DELAYED_STARTS = DEBUG_DELAYED_SERVICE;
- static final boolean DEBUG_MU = ActivityManagerService.DEBUG_MU;
- static final boolean LOG_SERVICE_START_STOP = false;
- static final String TAG = ActivityManagerService.TAG;
- static final String TAG_MU = ActivityManagerService.TAG_MU;
+ private static final String TAG = TAG_WITH_CLASS_NAME ? "ActiveServices" : TAG_AM;
+ private static final String TAG_MU = TAG + POSTFIX_MU;
+ private static final String TAG_SERVICE = TAG + POSTFIX_SERVICE;
+ private static final String TAG_SERVICE_EXECUTING = TAG + POSTFIX_SERVICE_EXECUTING;
+
+ private static final boolean DEBUG_DELAYED_SERVICE = DEBUG_SERVICE;
+ private static final boolean DEBUG_DELAYED_STARTS = DEBUG_DELAYED_SERVICE;
+
+ private static final boolean LOG_SERVICE_START_STOP = false;
// How long we wait for a service to finish executing.
static final int SERVICE_TIMEOUT = 20*1000;
@@ -206,11 +210,12 @@
void ensureNotStartingBackground(ServiceRecord r) {
if (mStartingBackground.remove(r)) {
- if (DEBUG_DELAYED_STARTS) Slog.v(TAG, "No longer background starting: " + r);
+ if (DEBUG_DELAYED_STARTS) Slog.v(TAG_SERVICE,
+ "No longer background starting: " + r);
rescheduleDelayedStarts();
}
if (mDelayedStartList.remove(r)) {
- if (DEBUG_DELAYED_STARTS) Slog.v(TAG, "No longer delaying start: " + r);
+ if (DEBUG_DELAYED_STARTS) Slog.v(TAG_SERVICE, "No longer delaying start: " + r);
}
}
@@ -229,16 +234,17 @@
while (mDelayedStartList.size() > 0
&& mStartingBackground.size() < mMaxStartingBackground) {
ServiceRecord r = mDelayedStartList.remove(0);
- if (DEBUG_DELAYED_STARTS) Slog.v(TAG, "REM FR DELAY LIST (exec next): " + r);
+ if (DEBUG_DELAYED_STARTS) Slog.v(TAG_SERVICE,
+ "REM FR DELAY LIST (exec next): " + r);
if (r.pendingStarts.size() <= 0) {
Slog.w(TAG, "**** NO PENDING STARTS! " + r + " startReq=" + r.startRequested
+ " delayedStop=" + r.delayedStop);
}
if (DEBUG_DELAYED_SERVICE) {
if (mDelayedStartList.size() > 0) {
- Slog.v(TAG, "Remaining delayed list:");
+ Slog.v(TAG_SERVICE, "Remaining delayed list:");
for (int i=0; i<mDelayedStartList.size(); i++) {
- Slog.v(TAG, " #" + i + ": " + mDelayedStartList.get(i));
+ Slog.v(TAG_SERVICE, " #" + i + ": " + mDelayedStartList.get(i));
}
}
}
@@ -248,7 +254,7 @@
if (mStartingBackground.size() > 0) {
ServiceRecord next = mStartingBackground.get(0);
long when = next.startingBgTimeout > now ? next.startingBgTimeout : now;
- if (DEBUG_DELAYED_SERVICE) Slog.v(TAG, "Top bg start is " + next
+ if (DEBUG_DELAYED_SERVICE) Slog.v(TAG_SERVICE, "Top bg start is " + next
+ ", can delay others up to " + when);
Message msg = obtainMessage(MSG_BG_START_TIMEOUT);
sendMessageAtTime(msg, when);
@@ -298,7 +304,7 @@
ComponentName startServiceLocked(IApplicationThread caller,
Intent service, String resolvedType,
int callingPid, int callingUid, int userId) {
- if (DEBUG_DELAYED_STARTS) Slog.v(TAG, "startService: " + service
+ if (DEBUG_DELAYED_STARTS) Slog.v(TAG_SERVICE, "startService: " + service
+ " type=" + resolvedType + " args=" + service.getExtras());
final boolean callerFg;
@@ -337,7 +343,7 @@
NeededUriGrants neededGrants = mAm.checkGrantUriPermissionFromIntentLocked(
callingUid, r.packageName, service, service.getFlags(), null, r.userId);
if (unscheduleServiceRestartLocked(r, callingUid, false)) {
- if (DEBUG_SERVICE) Slog.v(TAG, "START SERVICE WHILE RESTART PENDING: " + r);
+ if (DEBUG_SERVICE) Slog.v(TAG_SERVICE, "START SERVICE WHILE RESTART PENDING: " + r);
}
r.lastActivity = SystemClock.uptimeMillis();
r.startRequested = true;
@@ -360,29 +366,30 @@
// service is started. This is especially the case for receivers, which
// may start a service in onReceive() to do some additional work and have
// initialized some global state as part of that.
- if (DEBUG_DELAYED_SERVICE) Slog.v(TAG, "Potential start delay of " + r + " in "
- + proc);
+ if (DEBUG_DELAYED_SERVICE) Slog.v(TAG_SERVICE, "Potential start delay of "
+ + r + " in " + proc);
if (r.delayed) {
// This service is already scheduled for a delayed start; just leave
// it still waiting.
- if (DEBUG_DELAYED_STARTS) Slog.v(TAG, "Continuing to delay: " + r);
+ if (DEBUG_DELAYED_STARTS) Slog.v(TAG_SERVICE, "Continuing to delay: " + r);
return r.name;
}
if (smap.mStartingBackground.size() >= mMaxStartingBackground) {
// Something else is starting, delay!
- Slog.i(TAG, "Delaying start of: " + r);
+ Slog.i(TAG_SERVICE, "Delaying start of: " + r);
smap.mDelayedStartList.add(r);
r.delayed = true;
return r.name;
}
- if (DEBUG_DELAYED_STARTS) Slog.v(TAG, "Not delaying: " + r);
+ if (DEBUG_DELAYED_STARTS) Slog.v(TAG_SERVICE, "Not delaying: " + r);
addToStarting = true;
} else if (proc.curProcState >= ActivityManager.PROCESS_STATE_SERVICE) {
// We slightly loosen when we will enqueue this new service as a background
// starting service we are waiting for, to also include processes that are
// currently running other services or receivers.
addToStarting = true;
- if (DEBUG_DELAYED_STARTS) Slog.v(TAG, "Not delaying, but counting as bg: " + r);
+ if (DEBUG_DELAYED_STARTS) Slog.v(TAG_SERVICE,
+ "Not delaying, but counting as bg: " + r);
} else if (DEBUG_DELAYED_STARTS) {
StringBuilder sb = new StringBuilder(128);
sb.append("Not potential delay (state=").append(proc.curProcState)
@@ -394,16 +401,17 @@
}
sb.append("): ");
sb.append(r.toString());
- Slog.v(TAG, sb.toString());
+ Slog.v(TAG_SERVICE, sb.toString());
}
} else if (DEBUG_DELAYED_STARTS) {
if (callerFg) {
- Slog.v(TAG, "Not potential delay (callerFg=" + callerFg + " uid="
+ Slog.v(TAG_SERVICE, "Not potential delay (callerFg=" + callerFg + " uid="
+ callingUid + " pid=" + callingPid + "): " + r);
} else if (r.app != null) {
- Slog.v(TAG, "Not potential delay (cur app=" + r.app + "): " + r);
+ Slog.v(TAG_SERVICE, "Not potential delay (cur app=" + r.app + "): " + r);
} else {
- Slog.v(TAG, "Not potential delay (user " + r.userId + " not started): " + r);
+ Slog.v(TAG_SERVICE,
+ "Not potential delay (user " + r.userId + " not started): " + r);
}
}
@@ -432,9 +440,9 @@
if (DEBUG_DELAYED_SERVICE) {
RuntimeException here = new RuntimeException("here");
here.fillInStackTrace();
- Slog.v(TAG, "Starting background (first=" + first + "): " + r, here);
+ Slog.v(TAG_SERVICE, "Starting background (first=" + first + "): " + r, here);
} else if (DEBUG_DELAYED_STARTS) {
- Slog.v(TAG, "Starting background (first=" + first + "): " + r);
+ Slog.v(TAG_SERVICE, "Starting background (first=" + first + "): " + r);
}
if (first) {
smap.rescheduleDelayedStarts();
@@ -451,7 +459,7 @@
// If service isn't actually running, but is is being held in the
// delayed list, then we need to keep it started but note that it
// should be stopped once no longer delayed.
- if (DEBUG_DELAYED_STARTS) Slog.v(TAG, "Delaying stop of pending: " + service);
+ if (DEBUG_DELAYED_STARTS) Slog.v(TAG_SERVICE, "Delaying stop of pending: " + service);
service.delayedStop = true;
return;
}
@@ -469,7 +477,7 @@
int stopServiceLocked(IApplicationThread caller, Intent service,
String resolvedType, int userId) {
- if (DEBUG_SERVICE) Slog.v(TAG, "stopService: " + service
+ if (DEBUG_SERVICE) Slog.v(TAG_SERVICE, "stopService: " + service
+ " type=" + resolvedType);
final ProcessRecord callerApp = mAm.getRecordForAppLocked(caller);
@@ -525,7 +533,7 @@
boolean stopServiceTokenLocked(ComponentName className, IBinder token,
int startId) {
- if (DEBUG_SERVICE) Slog.v(TAG, "stopServiceToken: " + className
+ if (DEBUG_SERVICE) Slog.v(TAG_SERVICE, "stopServiceToken: " + className
+ " " + token + " startId=" + startId);
ServiceRecord r = findServiceLocked(className, token, UserHandle.getCallingUserId());
if (r != null) {
@@ -687,7 +695,7 @@
int bindServiceLocked(IApplicationThread caller, IBinder token,
Intent service, String resolvedType,
IServiceConnection connection, int flags, int userId) {
- if (DEBUG_SERVICE) Slog.v(TAG, "bindService: " + service
+ if (DEBUG_SERVICE) Slog.v(TAG_SERVICE, "bindService: " + service
+ " type=" + resolvedType + " conn=" + connection.asBinder()
+ " flags=0x" + Integer.toHexString(flags));
final ProcessRecord callerApp = mAm.getRecordForAppLocked(caller);
@@ -751,7 +759,7 @@
try {
if (unscheduleServiceRestartLocked(s, callerApp.info.uid, false)) {
- if (DEBUG_SERVICE) Slog.v(TAG, "BIND SERVICE WHILE RESTART PENDING: "
+ if (DEBUG_SERVICE) Slog.v(TAG_SERVICE, "BIND SERVICE WHILE RESTART PENDING: "
+ s);
}
@@ -819,7 +827,7 @@
mAm.updateOomAdjLocked(s.app);
}
- if (DEBUG_SERVICE) Slog.v(TAG, "Bind " + s + " with " + b
+ if (DEBUG_SERVICE) Slog.v(TAG_SERVICE, "Bind " + s + " with " + b
+ ": received=" + b.intent.received
+ " apps=" + b.intent.apps.size()
+ " doRebind=" + b.intent.doRebind);
@@ -857,7 +865,7 @@
void publishServiceLocked(ServiceRecord r, Intent intent, IBinder service) {
final long origId = Binder.clearCallingIdentity();
try {
- if (DEBUG_SERVICE) Slog.v(TAG, "PUBLISHING " + r
+ if (DEBUG_SERVICE) Slog.v(TAG_SERVICE, "PUBLISHING " + r
+ " " + intent + ": " + service);
if (r != null) {
Intent.FilterComparison filter
@@ -873,14 +881,14 @@
ConnectionRecord c = clist.get(i);
if (!filter.equals(c.binding.intent.intent)) {
if (DEBUG_SERVICE) Slog.v(
- TAG, "Not publishing to: " + c);
+ TAG_SERVICE, "Not publishing to: " + c);
if (DEBUG_SERVICE) Slog.v(
- TAG, "Bound intent: " + c.binding.intent.intent);
+ TAG_SERVICE, "Bound intent: " + c.binding.intent.intent);
if (DEBUG_SERVICE) Slog.v(
- TAG, "Published intent: " + intent);
+ TAG_SERVICE, "Published intent: " + intent);
continue;
}
- if (DEBUG_SERVICE) Slog.v(TAG, "Publishing to: " + c);
+ if (DEBUG_SERVICE) Slog.v(TAG_SERVICE, "Publishing to: " + c);
try {
c.conn.connected(r.name, service);
} catch (Exception e) {
@@ -901,7 +909,7 @@
boolean unbindServiceLocked(IServiceConnection connection) {
IBinder binder = connection.asBinder();
- if (DEBUG_SERVICE) Slog.v(TAG, "unbindService: conn=" + binder);
+ if (DEBUG_SERVICE) Slog.v(TAG_SERVICE, "unbindService: conn=" + binder);
ArrayList<ConnectionRecord> clist = mServiceConnections.get(binder);
if (clist == null) {
Slog.w(TAG, "Unbind failed: could not find connection for "
@@ -945,7 +953,7 @@
Intent.FilterComparison filter
= new Intent.FilterComparison(intent);
IntentBindRecord b = r.bindings.get(filter);
- if (DEBUG_SERVICE) Slog.v(TAG, "unbindFinished in " + r
+ if (DEBUG_SERVICE) Slog.v(TAG_SERVICE, "unbindFinished in " + r
+ " at " + b + ": apps="
+ (b != null ? b.apps.size() : 0));
@@ -1012,7 +1020,7 @@
String resolvedType, int callingPid, int callingUid, int userId,
boolean createIfNeeded, boolean callingFromFg) {
ServiceRecord r = null;
- if (DEBUG_SERVICE) Slog.v(TAG, "retrieveServiceLocked: " + service
+ if (DEBUG_SERVICE) Slog.v(TAG_SERVICE, "retrieveServiceLocked: " + service
+ " type=" + resolvedType + " callingUid=" + callingUid);
userId = mAm.handleIncomingUser(callingPid, callingUid, userId,
@@ -1036,7 +1044,7 @@
ServiceInfo sInfo =
rInfo != null ? rInfo.serviceInfo : null;
if (sInfo == null) {
- Slog.w(TAG, "Unable to start service " + service + " U=" + userId +
+ Slog.w(TAG_SERVICE, "Unable to start service " + service + " U=" + userId +
": not found");
return null;
}
@@ -1110,9 +1118,9 @@
}
private final void bumpServiceExecutingLocked(ServiceRecord r, boolean fg, String why) {
- if (DEBUG_SERVICE) Slog.v(TAG, ">>> EXECUTING "
+ if (DEBUG_SERVICE) Slog.v(TAG_SERVICE, ">>> EXECUTING "
+ why + " of " + r + " in app " + r.app);
- else if (DEBUG_SERVICE_EXECUTING) Slog.v(TAG, ">>> EXECUTING "
+ else if (DEBUG_SERVICE_EXECUTING) Slog.v(TAG_SERVICE_EXECUTING, ">>> EXECUTING "
+ why + " of " + r.shortName);
long now = SystemClock.uptimeMillis();
if (r.executeNesting == 0) {
@@ -1155,7 +1163,7 @@
i.hasBound = true;
i.doRebind = false;
} catch (RemoteException e) {
- if (DEBUG_SERVICE) Slog.v(TAG, "Crashed while binding " + r);
+ if (DEBUG_SERVICE) Slog.v(TAG_SERVICE, "Crashed while binding " + r);
return false;
}
}
@@ -1336,7 +1344,7 @@
return null;
}
- if (DEBUG_SERVICE) Slog.v(TAG, "Bringing up " + r + " " + r.intent);
+ if (DEBUG_SERVICE) Slog.v(TAG_SERVICE, "Bringing up " + r + " " + r.intent);
// We are now bringing the service up, so no longer in the
// restarting state.
@@ -1347,7 +1355,7 @@
// Make sure this service is no longer considered delayed, we are starting it now.
if (r.delayed) {
- if (DEBUG_DELAYED_STARTS) Slog.v(TAG, "REM FR DELAY LIST (bring up): " + r);
+ if (DEBUG_DELAYED_STARTS) Slog.v(TAG_SERVICE, "REM FR DELAY LIST (bring up): " + r);
getServiceMap(r.userId).mDelayedStartList.remove(r);
r.delayed = false;
}
@@ -1430,7 +1438,8 @@
// Oh and hey we've already been asked to stop!
r.delayedStop = false;
if (r.startRequested) {
- if (DEBUG_DELAYED_STARTS) Slog.v(TAG, "Applying delayed stop (in bring up): " + r);
+ if (DEBUG_DELAYED_STARTS) Slog.v(TAG_SERVICE,
+ "Applying delayed stop (in bring up): " + r);
stopServiceLocked(r);
}
}
@@ -1509,7 +1518,7 @@
sendServiceArgsLocked(r, execInFg, true);
if (r.delayed) {
- if (DEBUG_DELAYED_STARTS) Slog.v(TAG, "REM FR DELAY LIST (new proc): " + r);
+ if (DEBUG_DELAYED_STARTS) Slog.v(TAG_SERVICE, "REM FR DELAY LIST (new proc): " + r);
getServiceMap(r.userId).mDelayedStartList.remove(r);
r.delayed = false;
}
@@ -1518,7 +1527,8 @@
// Oh and hey we've already been asked to stop!
r.delayedStop = false;
if (r.startRequested) {
- if (DEBUG_DELAYED_STARTS) Slog.v(TAG, "Applying delayed stop (from start): " + r);
+ if (DEBUG_DELAYED_STARTS) Slog.v(TAG_SERVICE,
+ "Applying delayed stop (from start): " + r);
stopServiceLocked(r);
}
}
@@ -1534,7 +1544,7 @@
while (r.pendingStarts.size() > 0) {
try {
ServiceRecord.StartItem si = r.pendingStarts.remove(0);
- if (DEBUG_SERVICE) Slog.v(TAG, "Sending arguments to: "
+ if (DEBUG_SERVICE) Slog.v(TAG_SERVICE, "Sending arguments to: "
+ r + " " + r.intent + " args=" + si.intent);
if (si.intent == null && N > 1) {
// If somehow we got a dummy null intent in the middle,
@@ -1566,7 +1576,7 @@
} catch (RemoteException e) {
// Remote process gone... we'll let the normal cleanup take
// care of this.
- if (DEBUG_SERVICE) Slog.v(TAG, "Crashed while scheduling start: " + r);
+ if (DEBUG_SERVICE) Slog.v(TAG_SERVICE, "Crashed while scheduling start: " + r);
break;
} catch (Exception e) {
Slog.w(TAG, "Unexpected exception", e);
@@ -1636,7 +1646,7 @@
if (r.app != null && r.app.thread != null) {
for (int i=r.bindings.size()-1; i>=0; i--) {
IntentBindRecord ibr = r.bindings.valueAt(i);
- if (DEBUG_SERVICE) Slog.v(TAG, "Bringing down binding " + ibr
+ if (DEBUG_SERVICE) Slog.v(TAG_SERVICE, "Bringing down binding " + ibr
+ ": hasBound=" + ibr.hasBound);
if (ibr.hasBound) {
try {
@@ -1654,7 +1664,7 @@
}
}
- if (DEBUG_SERVICE) Slog.v(TAG, "Bringing down " + r + " " + r.intent);
+ if (DEBUG_SERVICE) Slog.v(TAG_SERVICE, "Bringing down " + r + " " + r.intent);
r.destroyTime = SystemClock.uptimeMillis();
if (LOG_SERVICE_START_STOP) {
EventLogTags.writeAmDestroyService(
@@ -1671,7 +1681,7 @@
for (int i=mPendingServices.size()-1; i>=0; i--) {
if (mPendingServices.get(i) == r) {
mPendingServices.remove(i);
- if (DEBUG_SERVICE) Slog.v(TAG, "Removed pending: " + r);
+ if (DEBUG_SERVICE) Slog.v(TAG_SERVICE, "Removed pending: " + r);
}
}
@@ -1704,11 +1714,11 @@
}
} else {
if (DEBUG_SERVICE) Slog.v(
- TAG, "Removed service that has no process: " + r);
+ TAG_SERVICE, "Removed service that has no process: " + r);
}
} else {
if (DEBUG_SERVICE) Slog.v(
- TAG, "Removed service that is not running: " + r);
+ TAG_SERVICE, "Removed service that is not running: " + r);
}
if (r.bindings.size() > 0) {
@@ -1775,7 +1785,7 @@
}
if (!c.serviceDead) {
- if (DEBUG_SERVICE) Slog.v(TAG, "Disconnecting binding " + b.intent
+ if (DEBUG_SERVICE) Slog.v(TAG_SERVICE, "Disconnecting binding " + b.intent
+ ": shouldUnbind=" + b.intent.hasBound);
if (s.app != null && s.app.thread != null && b.intent.apps.size() == 0
&& b.intent.hasBound) {
@@ -1902,19 +1912,20 @@
private void serviceDoneExecutingLocked(ServiceRecord r, boolean inDestroying,
boolean finishing) {
- if (DEBUG_SERVICE) Slog.v(TAG, "<<< DONE EXECUTING " + r
+ if (DEBUG_SERVICE) Slog.v(TAG_SERVICE, "<<< DONE EXECUTING " + r
+ ": nesting=" + r.executeNesting
+ ", inDestroying=" + inDestroying + ", app=" + r.app);
- else if (DEBUG_SERVICE_EXECUTING) Slog.v(TAG, "<<< DONE EXECUTING " + r.shortName);
+ else if (DEBUG_SERVICE_EXECUTING) Slog.v(TAG_SERVICE_EXECUTING,
+ "<<< DONE EXECUTING " + r.shortName);
r.executeNesting--;
if (r.executeNesting <= 0) {
if (r.app != null) {
- if (DEBUG_SERVICE) Slog.v(TAG,
+ if (DEBUG_SERVICE) Slog.v(TAG_SERVICE,
"Nesting at 0 of " + r.shortName);
r.app.execServicesFg = false;
r.app.executingServices.remove(r);
if (r.app.executingServices.size() == 0) {
- if (DEBUG_SERVICE || DEBUG_SERVICE_EXECUTING) Slog.v(TAG,
+ if (DEBUG_SERVICE || DEBUG_SERVICE_EXECUTING) Slog.v(TAG_SERVICE_EXECUTING,
"No more executingServices of " + r.shortName);
mAm.mHandler.removeMessages(ActivityManagerService.SERVICE_TIMEOUT_MSG, r.app);
} else if (r.executeFg) {
@@ -1927,7 +1938,7 @@
}
}
if (inDestroying) {
- if (DEBUG_SERVICE) Slog.v(TAG,
+ if (DEBUG_SERVICE) Slog.v(TAG_SERVICE,
"doneExecuting remove destroying " + r);
mDestroyingServices.remove(r);
r.bindings.clear();
@@ -2141,13 +2152,13 @@
sr.executeNesting = 0;
sr.forceClearTracker();
if (mDestroyingServices.remove(sr)) {
- if (DEBUG_SERVICE) Slog.v(TAG, "killServices remove destroying " + sr);
+ if (DEBUG_SERVICE) Slog.v(TAG_SERVICE, "killServices remove destroying " + sr);
}
final int numClients = sr.bindings.size();
for (int bindingi=numClients-1; bindingi>=0; bindingi--) {
IntentBindRecord b = sr.bindings.valueAt(bindingi);
- if (DEBUG_SERVICE) Slog.v(TAG, "Killing binding " + b
+ if (DEBUG_SERVICE) Slog.v(TAG_SERVICE, "Killing binding " + b
+ ": shouldUnbind=" + b.hasBound);
b.binder = null;
b.requested = b.received = b.hasBound = false;
@@ -2281,7 +2292,7 @@
if (sr.app == app) {
sr.forceClearTracker();
mDestroyingServices.remove(i);
- if (DEBUG_SERVICE) Slog.v(TAG, "killServices remove destroying " + sr);
+ if (DEBUG_SERVICE) Slog.v(TAG_SERVICE, "killServices remove destroying " + sr);
}
}
diff --git a/services/core/java/com/android/server/am/ActivityManagerDebugConfig.java b/services/core/java/com/android/server/am/ActivityManagerDebugConfig.java
new file mode 100644
index 0000000..03f253b
--- /dev/null
+++ b/services/core/java/com/android/server/am/ActivityManagerDebugConfig.java
@@ -0,0 +1,84 @@
+/*
+ * 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.server.am;
+
+/**
+ * Common class for the various debug {@link android.util.Log} output configuration in the activity
+ * manager package.
+ */
+class ActivityManagerDebugConfig {
+
+ // All output logs in the activity manager package use the {@link #TAG_AM} string for tagging
+ // their log output. This makes it easy to identify the origin of the log message when sifting
+ // through a large amount of log output from multiple sources. However, it also makes trying
+ // to figure-out the origin of a log message while debugging the activity manager a little
+ // painful. By setting this constant to true, log messages from the activity manager package
+ // will be tagged with their class names instead fot the generic tag.
+ static final boolean TAG_WITH_CLASS_NAME = false;
+
+ // While debugging it is sometimes useful to have the category name of the log prepended to the
+ // base log tag to make sifting through logs with the same base tag easier. By setting this
+ // constant to true, the category name of the log point will be prepended to the log tag.
+ static final boolean PREPEND_CATEGORY_NAME = false;
+
+ // Default log tag for the activity manager package.
+ static final String TAG_AM = "ActivityManager";
+
+ // Enable all debug log categories.
+ static final boolean DEBUG_ALL = false;
+
+ // Available log categories in the activity manager package.
+ static final boolean DEBUG_BACKUP = DEBUG_ALL || false;
+ static final boolean DEBUG_BROADCAST = DEBUG_ALL || false;
+ static final boolean DEBUG_BROADCAST_BACKGROUND = DEBUG_BROADCAST || false;
+ static final boolean DEBUG_BROADCAST_LIGHT = DEBUG_BROADCAST || false;
+ static final boolean DEBUG_CLEANUP = DEBUG_ALL || false;
+ static final boolean DEBUG_CONFIGURATION = DEBUG_ALL || false;
+ static final boolean DEBUG_FOCUS = false;
+ static final boolean DEBUG_IMMERSIVE = DEBUG_ALL || false;
+ static final boolean DEBUG_LOCKSCREEN = DEBUG_ALL || false;
+ static final boolean DEBUG_LRU = DEBUG_ALL || false;
+ static final boolean DEBUG_MU = DEBUG_ALL || false;
+ static final boolean DEBUG_OOM_ADJ = DEBUG_ALL || false;
+ static final boolean DEBUG_PAUSE = DEBUG_ALL || false;
+ static final boolean DEBUG_POWER = DEBUG_ALL || false;
+ static final boolean DEBUG_POWER_QUICK = DEBUG_POWER || false;
+ static final boolean DEBUG_PROCESS_OBSERVERS = DEBUG_ALL || false;
+ static final boolean DEBUG_PROCESSES = DEBUG_ALL || false;
+ static final boolean DEBUG_PROVIDER = DEBUG_ALL || false;
+ static final boolean DEBUG_PSS = DEBUG_ALL || false;
+ static final boolean DEBUG_RECENTS = DEBUG_ALL || false;
+ static final boolean DEBUG_RESULTS = DEBUG_ALL || false;
+ static final boolean DEBUG_SERVICE = DEBUG_ALL || false;
+ static final boolean DEBUG_SERVICE_EXECUTING = DEBUG_ALL || false;
+ static final boolean DEBUG_STACK = DEBUG_ALL || false;
+ static final boolean DEBUG_SWITCH = DEBUG_ALL || false;
+ static final boolean DEBUG_TASKS = DEBUG_ALL || false;
+ static final boolean DEBUG_THUMBNAILS = DEBUG_ALL || false;
+ static final boolean DEBUG_TRANSITION = DEBUG_ALL || false;
+ static final boolean DEBUG_URI_PERMISSION = DEBUG_ALL || false;
+ static final boolean DEBUG_USER_LEAVING = DEBUG_ALL || false;
+ static final boolean DEBUG_VISBILITY = DEBUG_ALL || false;
+
+ static final String POSTFIX_BACKUP = (PREPEND_CATEGORY_NAME) ? "_Backup" : "";
+ static final String POSTFIX_BROADCAST = (PREPEND_CATEGORY_NAME) ? "_Broadcast" : "";
+ static final String POSTFIX_MU = "_MU";
+ static final String POSTFIX_SERVICE = (PREPEND_CATEGORY_NAME) ? "_Service" : "";
+ static final String POSTFIX_SERVICE_EXECUTING =
+ (PREPEND_CATEGORY_NAME) ? "_ServiceExecuting" : "";
+
+}
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 008d718..1247105 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -30,6 +30,7 @@
import static org.xmlpull.v1.XmlPullParser.END_DOCUMENT;
import static org.xmlpull.v1.XmlPullParser.START_TAG;
import static com.android.server.am.ActivityStackSupervisor.HOME_STACK_ID;
+import static com.android.server.am.ActivityManagerDebugConfig.*;
import static com.android.server.am.TaskRecord.INVALID_TASK_ID;
import android.Manifest;
@@ -245,10 +246,11 @@
// File that stores last updated system version and called preboot receivers
static final String CALLED_PRE_BOOTS_FILENAME = "called_pre_boots.dat";
- static final String TAG = "ActivityManager";
- static final String TAG_MU = "ActivityManagerServiceMU";
- static final boolean DEBUG = false;
- static final boolean localLOGV = DEBUG;
+ static final String TAG = TAG_WITH_CLASS_NAME ? "ActivityManagerService" : TAG_AM;
+ private static final String TAG_MU = TAG + POSTFIX_MU;
+
+ // TODO(ogunwale): Migrate all the constants below to use ActivityManagerDebugConfig class.
+ static final boolean localLOGV = DEBUG_ALL || false;
static final boolean DEBUG_BACKUP = localLOGV || false;
static final boolean DEBUG_BROADCAST = localLOGV || false;
static final boolean DEBUG_BROADCAST_LIGHT = DEBUG_BROADCAST || false;
@@ -8347,6 +8349,9 @@
synchronized (this) {
pkg = task.intent.getComponent().getPackageName();
}
+ // isSystemInitiated is used to distinguish between locked and pinned mode, as pinned mode
+ // is initiated by system after the pinning request was shown and locked mode is initiated
+ // by an authorized app directly
boolean isSystemInitiated = Binder.getCallingUid() == Process.SYSTEM_UID;
if (!isSystemInitiated && !isLockTaskAuthorized(pkg)) {
StatusBarManagerInternal statusBarManager = LocalServices.getService(
@@ -8367,7 +8372,9 @@
|| (task != mStackSupervisor.getFocusedStack().topTask()))) {
throw new IllegalArgumentException("Invalid task, not in foreground");
}
- mStackSupervisor.setLockTaskModeLocked(task, !isSystemInitiated,
+ mStackSupervisor.setLockTaskModeLocked(task, isSystemInitiated ?
+ ActivityManager.LOCK_TASK_MODE_PINNED :
+ ActivityManager.LOCK_TASK_MODE_LOCKED,
"startLockTask");
}
}
@@ -8453,7 +8460,8 @@
Log.d(TAG, "stopLockTaskMode");
// Stop lock task
synchronized (this) {
- mStackSupervisor.setLockTaskModeLocked(null, false, "stopLockTask");
+ mStackSupervisor.setLockTaskModeLocked(null, ActivityManager.LOCK_TASK_MODE_NONE,
+ "stopLockTask");
}
} finally {
Binder.restoreCallingIdentity(ident);
@@ -8474,8 +8482,13 @@
@Override
public boolean isInLockTaskMode() {
+ return getLockTaskModeState() != ActivityManager.LOCK_TASK_MODE_NONE;
+ }
+
+ @Override
+ public int getLockTaskModeState() {
synchronized (this) {
- return mStackSupervisor.isInLockTaskMode();
+ return mStackSupervisor.getLockTaskModeState();
}
}
@@ -18534,7 +18547,8 @@
return true;
}
- mStackSupervisor.setLockTaskModeLocked(null, false, "startUser");
+ mStackSupervisor.setLockTaskModeLocked(null, ActivityManager.LOCK_TASK_MODE_NONE,
+ "startUser");
final UserInfo userInfo = getUserManagerLocked().getUserInfo(userId);
if (userInfo == null) {
diff --git a/services/core/java/com/android/server/am/ActivityStackSupervisor.java b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
index a260330..8b95ae8 100644
--- a/services/core/java/com/android/server/am/ActivityStackSupervisor.java
+++ b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
@@ -20,6 +20,7 @@
import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK;
import static android.content.Intent.FLAG_ACTIVITY_TASK_ON_HOME;
import static android.content.pm.PackageManager.PERMISSION_GRANTED;
+import static com.android.server.am.ActivityManagerDebugConfig.*;
import static com.android.server.am.ActivityManagerService.localLOGV;
import static com.android.server.am.ActivityManagerService.DEBUG_CONFIGURATION;
import static com.android.server.am.ActivityManagerService.DEBUG_FOCUS;
@@ -116,7 +117,7 @@
import java.util.List;
public final class ActivityStackSupervisor implements DisplayListener {
- static final boolean DEBUG = ActivityManagerService.DEBUG || false;
+ static final boolean DEBUG = DEBUG_ALL || false;
static final boolean DEBUG_ADD_REMOVE = DEBUG || false;
static final boolean DEBUG_APP = DEBUG || false;
static final boolean DEBUG_CONTAINERS = DEBUG || false;
@@ -267,9 +268,11 @@
/** If non-null then the task specified remains in front and no other tasks may be started
* until the task exits or #stopLockTaskMode() is called. */
TaskRecord mLockTaskModeTask;
- /** Whether lock task has been entered by an authorized app and cannot
- * be exited. */
- private boolean mLockTaskIsLocked;
+ /** Store the current lock task mode. Possible values:
+ * {@link ActivityManager#LOCK_TASK_MODE_NONE}, {@link ActicityManager#LOCK_TASK_MODE_LOCKED},
+ * {@link ActicityManager#LOCK_TASK_MODE_PINNED}
+ */
+ private int mLockTaskModeState;
/**
* Notifies the user when entering/exiting lock-task.
*/
@@ -3546,10 +3549,10 @@
}
void showLockTaskToast() {
- mLockTaskNotify.showToast(mLockTaskIsLocked);
+ mLockTaskNotify.showToast(mLockTaskModeState);
}
- void setLockTaskModeLocked(TaskRecord task, boolean isLocked, String reason) {
+ void setLockTaskModeLocked(TaskRecord task, int lockTaskModeState, String reason) {
if (task == null) {
// Take out of lock task mode if necessary
if (mLockTaskModeTask != null) {
@@ -3573,7 +3576,7 @@
lockTaskMsg.obj = mLockTaskModeTask.intent.getComponent().getPackageName();
lockTaskMsg.arg1 = mLockTaskModeTask.userId;
lockTaskMsg.what = LOCK_TASK_START_MSG;
- lockTaskMsg.arg2 = !isLocked ? 1 : 0;
+ lockTaskMsg.arg2 = lockTaskModeState;
mHandler.sendMessage(lockTaskMsg);
}
@@ -3591,8 +3594,8 @@
}
}
- boolean isInLockTaskMode() {
- return mLockTaskModeTask != null;
+ int getLockTaskModeState() {
+ return mLockTaskModeState;
}
private final class ActivityStackSupervisorHandler extends Handler {
@@ -3684,13 +3687,18 @@
mLockTaskNotify = new LockTaskNotify(mService.mContext);
}
mLockTaskNotify.show(true);
- mLockTaskIsLocked = msg.arg2 == 0;
+ mLockTaskModeState = msg.arg2;
if (getStatusBarService() != null) {
- int flags =
- StatusBarManager.DISABLE_MASK ^ StatusBarManager.DISABLE_BACK;
- if (!mLockTaskIsLocked) {
- flags ^= StatusBarManager.DISABLE_HOME
- | StatusBarManager.DISABLE_RECENT;
+ int flags = 0;
+ if (mLockTaskModeState == ActivityManager.LOCK_TASK_MODE_LOCKED) {
+ flags = StatusBarManager.DISABLE_MASK
+ & (~StatusBarManager.DISABLE_BACK);
+ } else if (mLockTaskModeState ==
+ ActivityManager.LOCK_TASK_MODE_PINNED) {
+ flags = StatusBarManager.DISABLE_MASK
+ & (~StatusBarManager.DISABLE_BACK)
+ & (~StatusBarManager.DISABLE_HOME)
+ & (~StatusBarManager.DISABLE_RECENT);
}
getStatusBarService().disable(flags, mToken,
mService.mContext.getPackageName());
@@ -3724,7 +3732,8 @@
boolean shouldLockKeyguard = Settings.Secure.getInt(
mService.mContext.getContentResolver(),
Settings.Secure.LOCK_TO_APP_EXIT_LOCKED) != 0;
- if (!mLockTaskIsLocked && shouldLockKeyguard) {
+ if (mLockTaskModeState == ActivityManager.LOCK_TASK_MODE_PINNED &&
+ shouldLockKeyguard) {
mWindowManager.lockNow(null);
mWindowManager.dismissKeyguard();
new LockPatternUtils(mService.mContext)
@@ -3735,6 +3744,8 @@
}
} catch (RemoteException ex) {
throw new RuntimeException(ex);
+ } finally {
+ mLockTaskModeState = ActivityManager.LOCK_TASK_MODE_NONE;
}
} break;
case CONTAINER_CALLBACK_TASK_LIST_EMPTY: {
diff --git a/services/core/java/com/android/server/am/BroadcastQueue.java b/services/core/java/com/android/server/am/BroadcastQueue.java
index 5083b1d..7a29a88 100644
--- a/services/core/java/com/android/server/am/BroadcastQueue.java
+++ b/services/core/java/com/android/server/am/BroadcastQueue.java
@@ -41,6 +41,8 @@
import android.util.EventLog;
import android.util.Slog;
+import static com.android.server.am.ActivityManagerDebugConfig.*;
+
/**
* BROADCASTS
*
@@ -48,11 +50,9 @@
* foreground priority, and one for normal (background-priority) broadcasts.
*/
public final class BroadcastQueue {
- static final String TAG = "BroadcastQueue";
- static final String TAG_MU = ActivityManagerService.TAG_MU;
- static final boolean DEBUG_BROADCAST = ActivityManagerService.DEBUG_BROADCAST;
- static final boolean DEBUG_BROADCAST_LIGHT = ActivityManagerService.DEBUG_BROADCAST_LIGHT;
- static final boolean DEBUG_MU = ActivityManagerService.DEBUG_MU;
+ private static final String TAG = TAG_WITH_CLASS_NAME ? "BroadcastQueue" : TAG_AM;
+ private static final String TAG_MU = TAG + POSTFIX_MU;
+ private static final String TAG_BROADCAST = TAG + POSTFIX_BROADCAST;
static final int MAX_BROADCAST_HISTORY = ActivityManager.isLowRamDeviceStatic() ? 10 : 50;
static final int MAX_BROADCAST_SUMMARY_HISTORY
@@ -143,7 +143,7 @@
switch (msg.what) {
case BROADCAST_INTENT_MSG: {
if (DEBUG_BROADCAST) Slog.v(
- TAG, "Received BROADCAST_INTENT_MSG");
+ TAG_BROADCAST, "Received BROADCAST_INTENT_MSG");
processNextBroadcast(true);
} break;
case BROADCAST_TIMEOUT_MSG: {
@@ -196,7 +196,7 @@
public final boolean replaceParallelBroadcastLocked(BroadcastRecord r) {
for (int i=mParallelBroadcasts.size()-1; i>=0; i--) {
if (r.intent.filterEquals(mParallelBroadcasts.get(i).intent)) {
- if (DEBUG_BROADCAST) Slog.v(TAG,
+ if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST,
"***** DROPPING PARALLEL ["
+ mQueueName + "]: " + r.intent);
mParallelBroadcasts.set(i, r);
@@ -209,7 +209,7 @@
public final boolean replaceOrderedBroadcastLocked(BroadcastRecord r) {
for (int i=mOrderedBroadcasts.size()-1; i>0; i--) {
if (r.intent.filterEquals(mOrderedBroadcasts.get(i).intent)) {
- if (DEBUG_BROADCAST) Slog.v(TAG,
+ if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST,
"***** DROPPING ORDERED ["
+ mQueueName + "]: " + r.intent);
mOrderedBroadcasts.set(i, r);
@@ -221,7 +221,7 @@
private final void processCurBroadcastLocked(BroadcastRecord r,
ProcessRecord app) throws RemoteException {
- if (DEBUG_BROADCAST) Slog.v(TAG,
+ if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST,
"Process cur broadcast " + r + " for app " + app);
if (app.thread == null) {
throw new RemoteException();
@@ -238,7 +238,7 @@
boolean started = false;
try {
- if (DEBUG_BROADCAST_LIGHT) Slog.v(TAG,
+ if (DEBUG_BROADCAST_LIGHT) Slog.v(TAG_BROADCAST,
"Delivering to component " + r.curComponent
+ ": " + r);
mService.ensurePackageDexOpt(r.intent.getComponent().getPackageName());
@@ -246,12 +246,12 @@
mService.compatibilityInfoForPackageLocked(r.curReceiver.applicationInfo),
r.resultCode, r.resultData, r.resultExtras, r.ordered, r.userId,
app.repProcState);
- if (DEBUG_BROADCAST) Slog.v(TAG,
+ if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST,
"Process cur broadcast " + r + " DELIVERED for app " + app);
started = true;
} finally {
if (!started) {
- if (DEBUG_BROADCAST) Slog.v(TAG,
+ if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST,
"Process cur broadcast " + r + ": NOT STARTED!");
r.receiver = null;
r.curApp = null;
@@ -308,7 +308,7 @@
r = mPendingBroadcast;
if (r != null && r.curApp == app) {
- if (DEBUG_BROADCAST) Slog.v(TAG,
+ if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST,
"[" + mQueueName + "] skip & discard pending app " + r);
logBroadcastReceiverDiscardLocked(r);
finishReceiverLocked(r, r.resultCode, r.resultData,
@@ -321,7 +321,7 @@
}
public void scheduleBroadcastsLocked() {
- if (DEBUG_BROADCAST) Slog.v(TAG, "Schedule broadcasts ["
+ if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST, "Schedule broadcasts ["
+ mQueueName + "]: current="
+ mBroadcastsScheduled);
@@ -391,8 +391,7 @@
// on. If there are background services currently starting, then we will go into a
// special state where we hold off on continuing this broadcast until they are done.
if (mService.mServices.hasBackgroundServices(r.userId)) {
- Slog.i(ActivityManagerService.TAG, "Delay finish: "
- + r.curComponent.flattenToShortString());
+ Slog.i(TAG, "Delay finish: " + r.curComponent.flattenToShortString());
r.state = BroadcastRecord.WAITING_SERVICES;
return false;
}
@@ -412,7 +411,7 @@
if (mOrderedBroadcasts.size() > 0) {
BroadcastRecord br = mOrderedBroadcasts.get(0);
if (br.userId == userId && br.state == BroadcastRecord.WAITING_SERVICES) {
- Slog.i(ActivityManagerService.TAG, "Resuming delayed broadcast");
+ Slog.i(TAG, "Resuming delayed broadcast");
br.curComponent = null;
br.state = BroadcastRecord.IDLE;
processNextBroadcast(false);
@@ -475,7 +474,7 @@
int mode = mService.mAppOpsService.noteOperation(r.appOp,
filter.receiverList.uid, filter.packageName);
if (mode != AppOpsManager.MODE_ALLOWED) {
- if (DEBUG_BROADCAST) Slog.v(TAG,
+ if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST,
"App op " + r.appOp + " not allowed for broadcast to uid "
+ filter.receiverList.uid + " pkg " + filter.packageName);
skip = true;
@@ -513,7 +512,7 @@
}
}
try {
- if (DEBUG_BROADCAST_LIGHT) Slog.i(TAG, "Delivering to " + filter + " : " + r);
+ if (DEBUG_BROADCAST_LIGHT) Slog.i(TAG_BROADCAST, "Delivering to " + filter + " : " + r);
performReceiveLocked(filter.receiverList.app, filter.receiverList.receiver,
new Intent(r.intent), r.resultCode, r.resultData,
r.resultExtras, r.ordered, r.initialSticky, r.userId);
@@ -538,7 +537,7 @@
synchronized(mService) {
BroadcastRecord r;
- if (DEBUG_BROADCAST) Slog.v(TAG, "processNextBroadcast ["
+ if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST, "processNextBroadcast ["
+ mQueueName + "]: "
+ mParallelBroadcasts.size() + " broadcasts, "
+ mOrderedBroadcasts.size() + " ordered broadcasts");
@@ -555,17 +554,17 @@
r.dispatchTime = SystemClock.uptimeMillis();
r.dispatchClockTime = System.currentTimeMillis();
final int N = r.receivers.size();
- if (DEBUG_BROADCAST_LIGHT) Slog.v(TAG, "Processing parallel broadcast ["
+ if (DEBUG_BROADCAST_LIGHT) Slog.v(TAG_BROADCAST, "Processing parallel broadcast ["
+ mQueueName + "] " + r);
for (int i=0; i<N; i++) {
Object target = r.receivers.get(i);
- if (DEBUG_BROADCAST) Slog.v(TAG,
+ if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST,
"Delivering non-ordered on [" + mQueueName + "] to registered "
+ target + ": " + r);
deliverToRegisteredReceiverLocked(r, (BroadcastFilter)target, false);
}
addBroadcastToHistoryLocked(r);
- if (DEBUG_BROADCAST_LIGHT) Slog.v(TAG, "Done with parallel broadcast ["
+ if (DEBUG_BROADCAST_LIGHT) Slog.v(TAG_BROADCAST, "Done with parallel broadcast ["
+ mQueueName + "] " + r);
}
@@ -576,7 +575,7 @@
// check that the process we're waiting for still exists.
if (mPendingBroadcast != null) {
if (DEBUG_BROADCAST_LIGHT) {
- Slog.v(TAG, "processNextBroadcast ["
+ Slog.v(TAG_BROADCAST, "processNextBroadcast ["
+ mQueueName + "]: waiting for "
+ mPendingBroadcast.curApp);
}
@@ -645,7 +644,7 @@
}
if (r.state != BroadcastRecord.IDLE) {
- if (DEBUG_BROADCAST) Slog.d(TAG,
+ if (DEBUG_BROADCAST) Slog.d(TAG_BROADCAST,
"processNextBroadcast("
+ mQueueName + ") called when not idle (state="
+ r.state + ")");
@@ -658,7 +657,7 @@
// result if requested...
if (r.resultTo != null) {
try {
- if (DEBUG_BROADCAST) Slog.i(TAG,
+ if (DEBUG_BROADCAST) Slog.i(TAG_BROADCAST,
"Finishing broadcast [" + mQueueName + "] "
+ r.intent.getAction() + " app=" + r.callerApp);
performReceiveLocked(r.callerApp, r.resultTo,
@@ -675,10 +674,10 @@
}
}
- if (DEBUG_BROADCAST) Slog.v(TAG, "Cancelling BROADCAST_TIMEOUT_MSG");
+ if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST, "Cancelling BROADCAST_TIMEOUT_MSG");
cancelBroadcastTimeoutLocked();
- if (DEBUG_BROADCAST_LIGHT) Slog.v(TAG, "Finished with ordered broadcast "
+ if (DEBUG_BROADCAST_LIGHT) Slog.v(TAG_BROADCAST, "Finished with ordered broadcast "
+ r);
// ... and on to the next...
@@ -699,12 +698,12 @@
if (recIdx == 0) {
r.dispatchTime = r.receiverTime;
r.dispatchClockTime = System.currentTimeMillis();
- if (DEBUG_BROADCAST_LIGHT) Slog.v(TAG, "Processing ordered broadcast ["
+ if (DEBUG_BROADCAST_LIGHT) Slog.v(TAG_BROADCAST, "Processing ordered broadcast ["
+ mQueueName + "] " + r);
}
if (! mPendingBroadcastTimeoutMessage) {
long timeoutTime = r.receiverTime + mTimeoutPeriod;
- if (DEBUG_BROADCAST) Slog.v(TAG,
+ if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST,
"Submitting BROADCAST_TIMEOUT_MSG ["
+ mQueueName + "] for " + r + " at " + timeoutTime);
setBroadcastTimeoutLocked(timeoutTime);
@@ -715,7 +714,7 @@
// Simple case: this is a registered receiver who gets
// a direct call.
BroadcastFilter filter = (BroadcastFilter)nextReceiver;
- if (DEBUG_BROADCAST) Slog.v(TAG,
+ if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST,
"Delivering ordered ["
+ mQueueName + "] to registered "
+ filter + ": " + r);
@@ -723,7 +722,7 @@
if (r.receiver == null || !r.ordered) {
// The receiver has already finished, so schedule to
// process the next one.
- if (DEBUG_BROADCAST) Slog.v(TAG, "Quick finishing ["
+ if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST, "Quick finishing ["
+ mQueueName + "]: ordered="
+ r.ordered + " receiver=" + r.receiver);
r.state = BroadcastRecord.IDLE;
@@ -786,7 +785,7 @@
int mode = mService.mAppOpsService.noteOperation(r.appOp,
info.activityInfo.applicationInfo.uid, info.activityInfo.packageName);
if (mode != AppOpsManager.MODE_ALLOWED) {
- if (DEBUG_BROADCAST) Slog.v(TAG,
+ if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST,
"App op " + r.appOp + " not allowed for broadcast to uid "
+ info.activityInfo.applicationInfo.uid + " pkg "
+ info.activityInfo.packageName);
@@ -836,7 +835,7 @@
}
if (!isAvailable) {
if (DEBUG_BROADCAST) {
- Slog.v(TAG, "Skipping delivery to " + info.activityInfo.packageName
+ Slog.v(TAG_BROADCAST, "Skipping delivery to " + info.activityInfo.packageName
+ " / " + info.activityInfo.applicationInfo.uid
+ " : package no longer available");
}
@@ -845,7 +844,7 @@
}
if (skip) {
- if (DEBUG_BROADCAST) Slog.v(TAG,
+ if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST,
"Skipping delivery of ordered ["
+ mQueueName + "] " + r + " for whatever reason");
r.receiver = null;
@@ -915,7 +914,7 @@
}
// Not running -- get it started, to be executed when the app comes up.
- if (DEBUG_BROADCAST) Slog.v(TAG,
+ if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST,
"Need to start app ["
+ mQueueName + "] " + targetProcess + " for broadcast " + r);
if ((r.curApp=mService.startProcessLocked(targetProcess,
@@ -990,7 +989,7 @@
// broadcast timeout message after each receiver finishes. Instead, we set up
// an initial timeout then kick it down the road a little further as needed
// when it expires.
- if (DEBUG_BROADCAST) Slog.v(TAG,
+ if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST,
"Premature timeout ["
+ mQueueName + "] @ " + now + ": resetting BROADCAST_TIMEOUT_MSG for "
+ timeoutTime);
@@ -1005,7 +1004,7 @@
// for started services to finish as well before going on. So if we have actually
// waited long enough time timeout the broadcast, let's give up on the whole thing
// and just move on to the next.
- Slog.i(ActivityManagerService.TAG, "Waited long enough for: " + (br.curComponent != null
+ Slog.i(TAG, "Waited long enough for: " + (br.curComponent != null
? br.curComponent.flattenToShortString() : "(null)"));
br.curComponent = null;
br.state = BroadcastRecord.IDLE;
diff --git a/services/core/java/com/android/server/am/LockTaskNotify.java b/services/core/java/com/android/server/am/LockTaskNotify.java
index b3777ed..afde322 100644
--- a/services/core/java/com/android/server/am/LockTaskNotify.java
+++ b/services/core/java/com/android/server/am/LockTaskNotify.java
@@ -16,6 +16,7 @@
package com.android.server.am;
+import android.app.ActivityManager;
import android.content.Context;
import android.os.Handler;
import android.os.Message;
@@ -44,15 +45,20 @@
mHandler = new H();
}
- public void showToast(boolean isLocked) {
- mHandler.obtainMessage(H.SHOW_TOAST, isLocked ? 1 : 0, 0 /* Not used */).sendToTarget();
+ public void showToast(int lockTaskModeState) {
+ mHandler.obtainMessage(H.SHOW_TOAST, lockTaskModeState, 0 /* Not used */).sendToTarget();
}
- public void handleShowToast(boolean isLocked) {
- String text = mContext.getString(isLocked
- ? R.string.lock_to_app_toast_locked : R.string.lock_to_app_toast);
- if (!isLocked && mAccessibilityManager.isEnabled()) {
- text = mContext.getString(R.string.lock_to_app_toast_accessible);
+ public void handleShowToast(int lockTaskModeState) {
+ String text = null;
+ if (lockTaskModeState == ActivityManager.LOCK_TASK_MODE_LOCKED) {
+ text = mContext.getString(R.string.lock_to_app_toast_locked);
+ } else if (lockTaskModeState == ActivityManager.LOCK_TASK_MODE_PINNED) {
+ text = mContext.getString(mAccessibilityManager.isEnabled()
+ ? R.string.lock_to_app_toast_accessible : R.string.lock_to_app_toast);
+ }
+ if (text == null) {
+ return;
}
if (mLastToast != null) {
mLastToast.cancel();
@@ -83,7 +89,7 @@
public void handleMessage(Message msg) {
switch(msg.what) {
case SHOW_TOAST:
- handleShowToast(msg.arg1 != 0);
+ handleShowToast(msg.arg1);
break;
}
}
diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java
index 4b7f698..5d386bd 100644
--- a/services/core/java/com/android/server/audio/AudioService.java
+++ b/services/core/java/com/android/server/audio/AudioService.java
@@ -3616,6 +3616,19 @@
final int index = (mIndexMap.valueAt(i) + 5) / 10;
pw.print(index);
}
+ pw.println();
+ pw.print(" Devices: ");
+ final int devices = AudioSystem.getDevicesForStream(mStreamType);
+ int device, i = 0, n = 0;
+ while ((device = 1 << i) <= AudioSystem.DEVICE_OUT_DEFAULT) {
+ if ((devices & device) != 0) {
+ if (n++ > 0) {
+ pw.print(", ");
+ }
+ pw.print(AudioSystem.getOutputDeviceName(device));
+ }
+ i++;
+ }
}
}
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java
index 82c99f78..7c93e56 100644
--- a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java
@@ -202,7 +202,6 @@
reason != HdmiControlService.INITIATED_BY_BOOT_UP);
mLocalDeviceAddresses = initLocalDeviceAddresses();
launchDeviceDiscovery();
- startQueuedActions();
}
diff --git a/services/core/java/com/android/server/pm/KeySetManagerService.java b/services/core/java/com/android/server/pm/KeySetManagerService.java
index 773b164..aa63932 100644
--- a/services/core/java/com/android/server/pm/KeySetManagerService.java
+++ b/services/core/java/com/android/server/pm/KeySetManagerService.java
@@ -414,9 +414,9 @@
// Get the package's known keys and KeySets
ArraySet<Long> deletableKeySets = getOriginalKeySetsByPackageNameLPr(packageName);
ArraySet<Long> deletableKeys = new ArraySet<Long>();
- ArraySet<Long> knownKeys = null;
- for (Long ks : deletableKeySets) {
- knownKeys = mKeySetMapping.get(ks);
+ final int origDksSize = deletableKeySets.size();
+ for (int i = 0; i < origDksSize; i++) {
+ ArraySet<Long> knownKeys = mKeySetMapping.get(deletableKeySets.valueAt(i));
if (knownKeys != null) {
deletableKeys.addAll(knownKeys);
}
@@ -429,9 +429,9 @@
}
ArraySet<Long> knownKeySets = getOriginalKeySetsByPackageNameLPr(pkgName);
deletableKeySets.removeAll(knownKeySets);
- knownKeys = new ArraySet<Long>();
- for (Long ks : knownKeySets) {
- knownKeys = mKeySetMapping.get(ks);
+ final int kksSize = knownKeySets.size();
+ for (int i = 0; i < kksSize; i++) {
+ ArraySet<Long> knownKeys = mKeySetMapping.get(knownKeySets.valueAt(i));
if (knownKeys != null) {
deletableKeys.removeAll(knownKeys);
}
@@ -440,18 +440,22 @@
// The remaining keys and KeySets are not relied on by any other
// application and so can be safely deleted.
- for (Long ks : deletableKeySets) {
+ final int dksSize = deletableKeySets.size();
+ for (int i = 0; i < dksSize; i++) {
+ Long ks = deletableKeySets.valueAt(i);
mKeySets.delete(ks);
mKeySetMapping.delete(ks);
}
- for (Long keyId : deletableKeys) {
- mPublicKeys.delete(keyId);
+ final int dkSize = deletableKeys.size();
+ for (int i = 0; i < dkSize; i++) {
+ mPublicKeys.delete(deletableKeys.valueAt(i));
}
// Now remove the deleted KeySets from each package's signingKeySets
for (String pkgName : mPackages.keySet()) {
PackageSetting p = mPackages.get(pkgName);
- for (Long ks : deletableKeySets) {
+ for (int i = 0; i < dksSize; i++) {
+ Long ks = deletableKeySets.valueAt(i);
p.keySetData.removeSigningKeySet(ks);
}
}
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index aa9d8dd..b90666f 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -51,6 +51,7 @@
import android.content.pm.ServiceInfo;
import android.content.pm.UserInfo;
import android.database.ContentObserver;
+import android.graphics.Bitmap;
import android.hardware.usb.UsbManager;
import android.media.AudioManager;
import android.media.IAudioService;
@@ -3940,15 +3941,21 @@
}
@Override
- public void clearDeviceInitializer(String packageName) {
+ public void clearDeviceInitializer(ComponentName who) {
if (!mHasFeature) {
return;
}
- if (packageName == null) {
- throw new NullPointerException("packageName is null");
+ Preconditions.checkNotNull(who, "ComponentName is null");
+
+ ActiveAdmin admin = getActiveAdminUncheckedLocked(who, UserHandle.getCallingUserId());
+
+ if (admin.getUid() != Binder.getCallingUid()) {
+ throw new SecurityException("Admin " + who + " is not owned by uid "
+ + Binder.getCallingUid());
}
- if (!isDeviceInitializer(packageName) && !isDeviceOwner(packageName)) {
+ if (!isDeviceInitializer(admin.info.getPackageName())
+ && !isDeviceOwner(admin.info.getPackageName())) {
throw new SecurityException(
"clearDeviceInitializer can only be called by the device initializer/owner");
}
@@ -5485,6 +5492,22 @@
}
}
+ @Override
+ public void setUserIcon(ComponentName who, Bitmap icon) {
+ synchronized (this) {
+ Preconditions.checkNotNull(who, "ComponentName is null");
+ getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
+
+ int userId = UserHandle.getCallingUserId();
+ long id = Binder.clearCallingIdentity();
+ try {
+ mUserManager.setUserIcon(userId, icon);
+ } finally {
+ restoreCallingIdentity(id);
+ }
+ }
+ }
+
/**
* We need to update the internal state of whether a user has completed setup once. After
* that, we ignore any changes that reset the Settings.Secure.USER_SETUP_COMPLETE changes
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index cd6e786..a0c7f86 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -669,7 +669,8 @@
mSystemServiceManager.startService("com.android.server.wifi.RttService");
- if (mPackageManager.hasSystemFeature(PackageManager.FEATURE_ETHERNET)) {
+ if (mPackageManager.hasSystemFeature(PackageManager.FEATURE_ETHERNET) ||
+ mPackageManager.hasSystemFeature(PackageManager.FEATURE_USB_HOST)) {
mSystemServiceManager.startService(ETHERNET_SERVICE_CLASS);
}
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index 0a4b787..f3b2d2e 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -3716,6 +3716,34 @@
}
/**
+ * Whether the device supports configuring the DTMF tone length.
+ *
+ * @return {@code true} if the DTMF tone length can be changed, and {@code false} otherwise.
+ */
+ public boolean canChangeDtmfToneLength() {
+ try {
+ return getITelephony().canChangeDtmfToneLength();
+ } catch (RemoteException e) {
+ Log.e(TAG, "Error calling ITelephony#canChangeDtmfToneLength", e);
+ }
+ return false;
+ }
+
+ /**
+ * Whether the device is a world phone.
+ *
+ * @return {@code true} if the device is a world phone, and {@code false} otherwise.
+ */
+ public boolean isWorldPhone() {
+ try {
+ return getITelephony().isWorldPhone();
+ } catch (RemoteException e) {
+ Log.e(TAG, "Error calling ITelephony#isWorldPhone", e);
+ }
+ return false;
+ }
+
+ /**
* This function retrieves value for setting "name+subId", and if that is not found
* retrieves value for setting "name", and if that is not found uses def as default
*
diff --git a/telephony/java/com/android/internal/telephony/ITelephony.aidl b/telephony/java/com/android/internal/telephony/ITelephony.aidl
index 62c8746..3769dee 100644
--- a/telephony/java/com/android/internal/telephony/ITelephony.aidl
+++ b/telephony/java/com/android/internal/telephony/ITelephony.aidl
@@ -863,11 +863,25 @@
/**
* Whether video calling has been enabled by the user.
*
- * @return {@code True} if the user has enabled video calling, {@code false} otherwise.
+ * @return {@code true} if the user has enabled video calling, {@code false} otherwise.
*/
boolean isVideoCallingEnabled();
/**
+ * Whether the DTMF tone length can be changed.
+ *
+ * @return {@code true} if the DTMF tone length can be changed.
+ */
+ boolean canChangeDtmfToneLength();
+
+ /**
+ * Whether the device is a world phone.
+ *
+ * @return {@code true} if the devices is a world phone.
+ */
+ boolean isWorldPhone();
+
+ /**
* Get IMS Registration Status
*/
boolean isImsRegistered();
diff --git a/tools/aapt/Images.cpp b/tools/aapt/Images.cpp
index 5ab177b..063b4e6 100644
--- a/tools/aapt/Images.cpp
+++ b/tools/aapt/Images.cpp
@@ -481,8 +481,9 @@
// assuming the image is a round rect, compute the radius by marching
// diagonally from the top left corner towards the center
- image->outlineAlpha = max(max_alpha_over_row(image->rows[innerMidY], innerStartX, innerEndX),
- max_alpha_over_col(image->rows, innerMidX, innerStartY, innerStartY));
+ image->outlineAlpha = std::max(
+ max_alpha_over_row(image->rows[innerMidY], innerStartX, innerEndX),
+ max_alpha_over_col(image->rows, innerMidX, innerStartY, innerStartY));
int diagonalInset = 0;
find_max_opacity(image->rows, innerStartX, innerStartY, innerMidX, innerMidY, 1, 1,
diff --git a/tools/aapt/ResourceTable.cpp b/tools/aapt/ResourceTable.cpp
index 6fbc17c..941a288 100644
--- a/tools/aapt/ResourceTable.cpp
+++ b/tools/aapt/ResourceTable.cpp
@@ -1807,7 +1807,7 @@
}
const ResTable& featureTable = featureAssetManager.getResources(false);
- mTypeIdOffset = max(mTypeIdOffset,
+ mTypeIdOffset = std::max(mTypeIdOffset,
findLargestTypeIdForPackage(featureTable, mAssetsPackage));
}
@@ -2703,20 +2703,16 @@
const String8 defaultLocale;
// For all strings...
- for (map<String16, map<String8, SourcePos> >::iterator nameIter = mLocalizations.begin();
- nameIter != mLocalizations.end();
- nameIter++) {
- const map<String8, SourcePos>& configSrcMap = nameIter->second;
+ for (const auto& nameIter : mLocalizations) {
+ const std::map<String8, SourcePos>& configSrcMap = nameIter.second;
// Look for strings with no default localization
if (configSrcMap.count(defaultLocale) == 0) {
SourcePos().warning("string '%s' has no default translation.",
- String8(nameIter->first).string());
+ String8(nameIter.first).string());
if (mBundle->getVerbose()) {
- for (map<String8, SourcePos>::const_iterator locales = configSrcMap.begin();
- locales != configSrcMap.end();
- locales++) {
- locales->second.printf("locale %s found", locales->first.string());
+ for (const auto& locale : configSrcMap) {
+ locale.second.printf("locale %s found", locale.first.string());
}
}
// !!! TODO: throw an error here in some circumstances
@@ -2727,8 +2723,8 @@
const char* allConfigs = mBundle->getConfigurations().string();
const char* start = allConfigs;
const char* comma;
-
- set<String8> missingConfigs;
+
+ std::set<String8> missingConfigs;
AaptLocaleValue locale;
do {
String8 config;
@@ -2762,13 +2758,11 @@
if (!missingConfigs.empty()) {
String8 configStr;
- for (set<String8>::iterator iter = missingConfigs.begin();
- iter != missingConfigs.end();
- iter++) {
- configStr.appendFormat(" %s", iter->string());
+ for (const auto& iter : missingConfigs) {
+ configStr.appendFormat(" %s", iter.string());
}
SourcePos().warning("string '%s' is missing %u required localizations:%s",
- String8(nameIter->first).string(),
+ String8(nameIter.first).string(),
(unsigned int)missingConfigs.size(),
configStr.string());
}
diff --git a/tools/aapt/ResourceTable.h b/tools/aapt/ResourceTable.h
index eef0ae1..9644224 100644
--- a/tools/aapt/ResourceTable.h
+++ b/tools/aapt/ResourceTable.h
@@ -17,8 +17,6 @@
#include "StringPool.h"
#include "Symbol.h"
-using namespace std;
-
class XMLNode;
class ResourceTable;
@@ -29,7 +27,7 @@
XML_COMPILE_STRIP_WHITESPACE = 1<<3,
XML_COMPILE_STRIP_RAW_VALUES = 1<<4,
XML_COMPILE_UTF8 = 1<<5,
-
+
XML_COMPILE_STANDARD_RESOURCE =
XML_COMPILE_STRIP_COMMENTS | XML_COMPILE_ASSIGN_ATTRIBUTE_IDS
| XML_COMPILE_STRIP_WHITESPACE | XML_COMPILE_STRIP_RAW_VALUES
@@ -116,7 +114,7 @@
* and would mess up iteration order for the existing
* resources.
*/
- queue<CompileResourceWorkItem>& getWorkQueue() {
+ std::queue<CompileResourceWorkItem>& getWorkQueue() {
return mWorkQueue;
}
@@ -587,10 +585,10 @@
size_t mNumLocal;
SourcePos mCurrentXmlPos;
Bundle* mBundle;
-
+
// key = string resource name, value = set of locales in which that name is defined
- map<String16, map<String8, SourcePos> > mLocalizations;
- queue<CompileResourceWorkItem> mWorkQueue;
+ std::map<String16, std::map<String8, SourcePos>> mLocalizations;
+ std::queue<CompileResourceWorkItem> mWorkQueue;
};
#endif
diff --git a/tools/layoutlib/bridge/src/android/graphics/Bitmap_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/Bitmap_Delegate.java
index 8d24d38..970b9d0 100644
--- a/tools/layoutlib/bridge/src/android/graphics/Bitmap_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/graphics/Bitmap_Delegate.java
@@ -76,13 +76,6 @@
// ---- Public Helper methods ----
/**
- * Returns the native delegate associated to a given {@link Bitmap_Delegate} object.
- */
- public static Bitmap_Delegate getDelegate(Bitmap bitmap) {
- return sManager.getDelegate(bitmap.mNativeBitmap);
- }
-
- /**
* Returns the native delegate associated to a given an int referencing a {@link Bitmap} object.
*/
public static Bitmap_Delegate getDelegate(long native_bitmap) {
@@ -187,19 +180,6 @@
return createBitmap(delegate, createFlags, density.getDpiValue());
}
- /**
- * Returns the {@link BufferedImage} used by the delegate of the given {@link Bitmap}.
- */
- public static BufferedImage getImage(Bitmap bitmap) {
- // get the delegate from the native int.
- Bitmap_Delegate delegate = sManager.getDelegate(bitmap.mNativeBitmap);
- if (delegate == null) {
- return null;
- }
-
- return delegate.mImage;
- }
-
public static int getBufferedImageType(int nativeBitmapConfig) {
switch (Config.nativeToConfig(nativeBitmapConfig)) {
case ALPHA_8:
diff --git a/tools/layoutlib/bridge/src/android/view/ShadowPainter.java b/tools/layoutlib/bridge/src/android/view/ShadowPainter.java
index 38846bd..a0db7bf 100644
--- a/tools/layoutlib/bridge/src/android/view/ShadowPainter.java
+++ b/tools/layoutlib/bridge/src/android/view/ShadowPainter.java
@@ -65,6 +65,9 @@
@SuppressWarnings({"SuspiciousNameCombination", "UnnecessaryLocalVariable"}) // Imported code
public static BufferedImage createDropShadow(BufferedImage source, int shadowSize,
float shadowOpacity, int shadowRgb) {
+ if (shadowSize == 0) {
+ return source;
+ }
// This code is based on
// http://www.jroller.com/gfx/entry/non_rectangular_shadow
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/Bridge.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/Bridge.java
index 4d2c2fc..c6d60f8 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/Bridge.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/Bridge.java
@@ -181,7 +181,7 @@
*/
private static LayoutLog sCurrentLog = sDefaultLog;
- private static final int LAST_SUPPORTED_FEATURE = Features.PREFERENCES_RENDERING;
+ private static final int LAST_SUPPORTED_FEATURE = Features.RENDER_ALL_DRAWABLE_STATES;
@Override
public int getApiLevel() {
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/RenderParamsFlags.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/RenderParamsFlags.java
new file mode 100644
index 0000000..cfc8f40
--- /dev/null
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/RenderParamsFlags.java
@@ -0,0 +1,39 @@
+/*
+ * 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.layoutlib.bridge.android;
+
+import com.android.ide.common.rendering.api.SessionParams.Key;
+
+/**
+ * This contains all known keys for the {@link RenderParams#getFlag(Key)}.
+ * <p/>
+ * The IDE has its own copy of this class which may be newer or older than this one.
+ * <p/>
+ * Constants should never be modified or removed from this class.
+ */
+public final class RenderParamsFlags {
+
+ public static final Key<String> FLAG_KEY_ROOT_TAG =
+ new Key<String>("rootTag", String.class);
+ public static final Key<Boolean> FLAG_KEY_DISABLE_BITMAP_CACHING =
+ new Key<Boolean>("disableBitmapCaching", Boolean.class);
+ public static final Key<Boolean> FLAG_KEY_RENDER_ALL_DRAWABLE_STATES =
+ new Key<Boolean>("renderAllDrawableStates", Boolean.class);
+
+ // Disallow instances.
+ private RenderParamsFlags() {}
+}
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/SessionParamsFlags.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/SessionParamsFlags.java
deleted file mode 100644
index 51a0104..0000000
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/SessionParamsFlags.java
+++ /dev/null
@@ -1,37 +0,0 @@
-/*
- * 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.layoutlib.bridge.android;
-
-import com.android.ide.common.rendering.api.SessionParams;
-
-/**
- * This contains all known keys for the {@link SessionParams#getFlag(SessionParams.Key)}.
- * <p/>
- * The IDE has its own copy of this class which may be newer or older than this one.
- * <p/>
- * Constants should never be modified or removed from this class.
- */
-public final class SessionParamsFlags {
-
- public static final SessionParams.Key<String> FLAG_KEY_ROOT_TAG =
- new SessionParams.Key<String>("rootTag", String.class);
- public static final SessionParams.Key<Boolean> FLAG_KEY_DISABLE_BITMAP_CACHING =
- new SessionParams.Key<Boolean>("disableBitmapCaching", Boolean.class);
-
- // Disallow instances.
- private SessionParamsFlags() {}
-}
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/RenderDrawable.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/RenderDrawable.java
index 669e6b5..3dee1e2 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/RenderDrawable.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/RenderDrawable.java
@@ -16,20 +16,20 @@
package com.android.layoutlib.bridge.impl;
-import static com.android.ide.common.rendering.api.Result.Status.ERROR_UNKNOWN;
-
import com.android.ide.common.rendering.api.DrawableParams;
import com.android.ide.common.rendering.api.HardwareConfig;
import com.android.ide.common.rendering.api.ResourceValue;
import com.android.ide.common.rendering.api.Result;
import com.android.ide.common.rendering.api.Result.Status;
import com.android.layoutlib.bridge.android.BridgeContext;
+import com.android.layoutlib.bridge.android.RenderParamsFlags;
import com.android.resources.ResourceType;
import android.graphics.Bitmap;
import android.graphics.Bitmap_Delegate;
import android.graphics.Canvas;
import android.graphics.drawable.Drawable;
+import android.graphics.drawable.StateListDrawable;
import android.view.AttachInfo_Accessor;
import android.view.View.MeasureSpec;
import android.widget.FrameLayout;
@@ -38,7 +38,9 @@
import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.image.BufferedImage;
-import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
/**
* Action to render a given Drawable provided through {@link DrawableParams#getDrawable()}.
@@ -71,11 +73,37 @@
return Status.ERROR_NOT_A_DRAWABLE.createResult();
}
+ Drawable d = ResourceHelper.getDrawable(drawableResource, context);
+
+ final Boolean allStates =
+ params.getFlag(RenderParamsFlags.FLAG_KEY_RENDER_ALL_DRAWABLE_STATES);
+ if (allStates == Boolean.TRUE) {
+ final List<BufferedImage> result;
+
+ if (d instanceof StateListDrawable) {
+ result = new ArrayList<BufferedImage>();
+ final StateListDrawable stateList = (StateListDrawable) d;
+ for (int i = 0; i < stateList.getStateCount(); i++) {
+ final Drawable stateDrawable = stateList.getStateDrawable(i);
+ result.add(renderImage(hardwareConfig, stateDrawable, context));
+ }
+ } else {
+ result = Collections.singletonList(renderImage(hardwareConfig, d, context));
+ }
+
+ return Status.SUCCESS.createResult(result);
+ } else {
+ BufferedImage image = renderImage(hardwareConfig, d, context);
+ return Status.SUCCESS.createResult(image);
+ }
+ }
+
+ private BufferedImage renderImage(HardwareConfig hardwareConfig, Drawable d,
+ BridgeContext context) {
// create a simple FrameLayout
FrameLayout content = new FrameLayout(context);
// get the actual Drawable object to draw
- Drawable d = ResourceHelper.getDrawable(drawableResource, context);
content.setBackground(d);
// set the AttachInfo on the root view.
@@ -83,8 +111,27 @@
// measure
- int w = hardwareConfig.getScreenWidth();
- int h = hardwareConfig.getScreenHeight();
+ int w = d.getIntrinsicWidth();
+ int h = d.getIntrinsicHeight();
+
+ final int screenWidth = hardwareConfig.getScreenWidth();
+ final int screenHeight = hardwareConfig.getScreenHeight();
+
+ if (w == -1 || h == -1) {
+ // Use screen size when either intrinsic width or height isn't available
+ w = screenWidth;
+ h = screenHeight;
+ } else if (w > screenWidth || h > screenHeight) {
+ // If image wouldn't fit to the screen, resize it to avoid cropping.
+
+ // We need to find scale such that scale * w <= screenWidth, scale * h <= screenHeight
+ double scale = Math.min((double) screenWidth / w, (double) screenHeight / h);
+
+ // scale * w / scale * h = w / h, so, proportions are preserved.
+ w = (int) Math.floor(scale * w);
+ h = (int) Math.floor(scale * h);
+ }
+
int w_spec = MeasureSpec.makeMeasureSpec(w, MeasureSpec.EXACTLY);
int h_spec = MeasureSpec.makeMeasureSpec(h, MeasureSpec.EXACTLY);
content.measure(w_spec, h_spec);
@@ -108,8 +155,7 @@
// and draw
content.draw(canvas);
-
- return Status.SUCCESS.createResult(image);
+ return image;
}
protected BufferedImage getImage(int w, int h) {
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 875cc87..607563a 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
@@ -50,7 +50,7 @@
import com.android.layoutlib.bridge.android.BridgeContext;
import com.android.layoutlib.bridge.android.BridgeLayoutParamsMapAttributes;
import com.android.layoutlib.bridge.android.BridgeXmlBlockParser;
-import com.android.layoutlib.bridge.android.SessionParamsFlags;
+import com.android.layoutlib.bridge.android.RenderParamsFlags;
import com.android.layoutlib.bridge.bars.BridgeActionBar;
import com.android.layoutlib.bridge.bars.AppCompatActionBar;
import com.android.layoutlib.bridge.bars.Config;
@@ -400,7 +400,7 @@
// it can instantiate the custom Fragment.
Fragment_Delegate.setProjectCallback(params.getProjectCallback());
- String rootTag = params.getFlag(SessionParamsFlags.FLAG_KEY_ROOT_TAG);
+ String rootTag = params.getFlag(RenderParamsFlags.FLAG_KEY_ROOT_TAG);
boolean isPreference = "PreferenceScreen".equals(rootTag);
View view;
if (isPreference) {
@@ -557,7 +557,7 @@
// This is useful when mImage is just a wrapper of Graphics2D so
// it doesn't get cached.
boolean disableBitmapCaching = Boolean.TRUE.equals(params.getFlag(
- SessionParamsFlags.FLAG_KEY_DISABLE_BITMAP_CACHING));
+ RenderParamsFlags.FLAG_KEY_DISABLE_BITMAP_CACHING));
if (newRenderSize || mCanvas == null || disableBitmapCaching) {
if (params.getImageFactory() != null) {
mImage = params.getImageFactory().getImage(