Merge "Import translations. DO NOT MERGE" into klp-dev
diff --git a/api/current.txt b/api/current.txt
index a603b773..c2dfa92 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -71,6 +71,7 @@
field public static final java.lang.String INJECT_EVENTS = "android.permission.INJECT_EVENTS";
field public static final java.lang.String INSTALL_LOCATION_PROVIDER = "android.permission.INSTALL_LOCATION_PROVIDER";
field public static final java.lang.String INSTALL_PACKAGES = "android.permission.INSTALL_PACKAGES";
+ field public static final java.lang.String INSTALL_SHORTCUT = "com.android.launcher.permission.INSTALL_SHORTCUT";
field public static final java.lang.String INTERNAL_SYSTEM_WINDOW = "android.permission.INTERNAL_SYSTEM_WINDOW";
field public static final java.lang.String INTERNET = "android.permission.INTERNET";
field public static final java.lang.String KILL_BACKGROUND_PROCESSES = "android.permission.KILL_BACKGROUND_PROCESSES";
@@ -132,6 +133,7 @@
field public static final java.lang.String SUBSCRIBED_FEEDS_WRITE = "android.permission.SUBSCRIBED_FEEDS_WRITE";
field public static final java.lang.String SYSTEM_ALERT_WINDOW = "android.permission.SYSTEM_ALERT_WINDOW";
field public static final java.lang.String TRANSMIT_IR = "android.permission.TRANSMIT_IR";
+ field public static final java.lang.String UNINSTALL_SHORTCUT = "com.android.launcher.permission.UNINSTALL_SHORTCUT";
field public static final java.lang.String UPDATE_DEVICE_STATS = "android.permission.UPDATE_DEVICE_STATS";
field public static final java.lang.String USE_CREDENTIALS = "android.permission.USE_CREDENTIALS";
field public static final java.lang.String USE_SIP = "android.permission.USE_SIP";
@@ -5744,11 +5746,10 @@
method public final int delete(android.net.Uri, java.lang.String, java.lang.String[]);
method public static deprecated android.content.SyncInfo getCurrentSync();
method public static java.util.List<android.content.SyncInfo> getCurrentSyncs();
- method public android.net.Uri[] getIncomingUriPermissionGrants(int, int);
method public static int getIsSyncable(android.accounts.Account, java.lang.String);
method public static boolean getMasterSyncAutomatically();
- method public android.net.Uri[] getOutgoingUriPermissionGrants(int, int);
method public static java.util.List<android.content.PeriodicSync> getPeriodicSyncs(android.accounts.Account, java.lang.String);
+ method public java.util.List<android.content.UriPermission> getPersistedUriPermissions();
method public java.lang.String[] getStreamTypes(android.net.Uri, java.lang.String);
method public static android.content.SyncAdapterType[] getSyncAdapterTypes();
method public static boolean getSyncAutomatically(android.accounts.Account, java.lang.String);
@@ -5770,6 +5771,7 @@
method public final android.database.Cursor query(android.net.Uri, java.lang.String[], java.lang.String, java.lang.String[], java.lang.String);
method public final android.database.Cursor query(android.net.Uri, java.lang.String[], java.lang.String, java.lang.String[], java.lang.String, android.os.CancellationSignal);
method public final void registerContentObserver(android.net.Uri, boolean, android.database.ContentObserver);
+ method public void releasePersistableUriPermission(android.net.Uri, int);
method public static void removePeriodicSync(android.accounts.Account, java.lang.String, android.os.Bundle);
method public static void removeStatusChangeListener(java.lang.Object);
method public static void requestSync(android.accounts.Account, java.lang.String, android.os.Bundle);
@@ -5778,6 +5780,7 @@
method public static void setMasterSyncAutomatically(boolean);
method public static void setSyncAutomatically(android.accounts.Account, java.lang.String, boolean);
method public deprecated void startSync(android.net.Uri, android.os.Bundle);
+ method public void takePersistableUriPermission(android.net.Uri, int);
method public final android.net.Uri uncanonicalize(android.net.Uri);
method public final void unregisterContentObserver(android.database.ContentObserver);
method public final int update(android.net.Uri, android.content.ContentValues, java.lang.String, java.lang.String[]);
@@ -6515,10 +6518,10 @@
field public static final int FLAG_DEBUG_LOG_RESOLUTION = 8; // 0x8
field public static final int FLAG_EXCLUDE_STOPPED_PACKAGES = 16; // 0x10
field public static final int FLAG_FROM_BACKGROUND = 4; // 0x4
+ field public static final int FLAG_GRANT_PERSISTABLE_URI_PERMISSION = 64; // 0x40
field public static final int FLAG_GRANT_READ_URI_PERMISSION = 1; // 0x1
field public static final int FLAG_GRANT_WRITE_URI_PERMISSION = 2; // 0x2
field public static final int FLAG_INCLUDE_STOPPED_PACKAGES = 32; // 0x20
- field public static final int FLAG_PERSIST_GRANT_URI_PERMISSION = 64; // 0x40
field public static final int FLAG_RECEIVER_FOREGROUND = 268435456; // 0x10000000
field public static final int FLAG_RECEIVER_NO_ABORT = 134217728; // 0x8000000
field public static final int FLAG_RECEIVER_REGISTERED_ONLY = 1073741824; // 0x40000000
@@ -6911,6 +6914,17 @@
field public static final int NO_MATCH = -1; // 0xffffffff
}
+ public final class UriPermission implements android.os.Parcelable {
+ method public int describeContents();
+ method public long getPersistedTime();
+ method public android.net.Uri getUri();
+ method public boolean isReadPermission();
+ method public boolean isWritePermission();
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final android.os.Parcelable.Creator CREATOR;
+ field public static final long INVALID_TIME = -9223372036854775808L; // 0x8000000000000000L
+ }
+
}
package android.content.pm {
@@ -20954,7 +20968,6 @@
method public static boolean deleteDocument(android.content.ContentResolver, android.net.Uri);
method public static java.lang.String getDocumentId(android.net.Uri);
method public static android.graphics.Bitmap getDocumentThumbnail(android.content.ContentResolver, android.net.Uri, android.graphics.Point, android.os.CancellationSignal);
- method public static android.net.Uri[] getOpenDocuments(android.content.Context);
method public static java.lang.String getRootId(android.net.Uri);
method public static java.lang.String getSearchDocumentsQuery(android.net.Uri);
field public static final java.lang.String EXTRA_ERROR = "error";
diff --git a/core/java/android/app/ActivityManagerNative.java b/core/java/android/app/ActivityManagerNative.java
index 7d4d57c..3b88973 100644
--- a/core/java/android/app/ActivityManagerNative.java
+++ b/core/java/android/app/ActivityManagerNative.java
@@ -23,9 +23,11 @@
import android.content.Intent;
import android.content.IntentFilter;
import android.content.IntentSender;
+import android.content.UriPermission;
import android.content.pm.ApplicationInfo;
import android.content.pm.ConfigurationInfo;
import android.content.pm.IPackageDataObserver;
+import android.content.pm.ParceledListSlice;
import android.content.pm.UserInfo;
import android.content.res.Configuration;
import android.graphics.Bitmap;
@@ -1130,6 +1132,32 @@
return true;
}
+ case TAKE_PERSISTABLE_URI_PERMISSION_TRANSACTION: {
+ data.enforceInterface(IActivityManager.descriptor);
+ Uri uri = Uri.CREATOR.createFromParcel(data);
+ int mode = data.readInt();
+ takePersistableUriPermission(uri, mode);
+ reply.writeNoException();
+ return true;
+ }
+
+ case RELEASE_PERSISTABLE_URI_PERMISSION_TRANSACTION: {
+ data.enforceInterface(IActivityManager.descriptor);
+ Uri uri = Uri.CREATOR.createFromParcel(data);
+ int mode = data.readInt();
+ releasePersistableUriPermission(uri, mode);
+ reply.writeNoException();
+ return true;
+ }
+
+ case GET_PERSISTED_URI_PERMISSIONS_TRANSACTION: {
+ data.enforceInterface(IActivityManager.descriptor);
+ final ParceledListSlice<UriPermission> perms = getPersistedUriPermissions();
+ reply.writeNoException();
+ perms.writeToParcel(reply, Parcelable.PARCELABLE_WRITE_RETURN_VALUE);
+ return true;
+ }
+
case SHOW_WAITING_FOR_DEBUGGER_TRANSACTION: {
data.enforceInterface(IActivityManager.descriptor);
IBinder b = data.readStrongBinder();
@@ -1983,19 +2011,6 @@
return true;
}
- case GET_GRANTED_URI_PERMISSIONS_TRANSACTION: {
- data.enforceInterface(IActivityManager.descriptor);
- final String sourcePackage = data.readString();
- final String targetPackage = data.readString();
- final int modeFlags = data.readInt();
- final int modeMask = data.readInt();
- final Uri[] uris = getGrantedUriPermissions(
- sourcePackage, targetPackage, modeFlags, modeMask);
- reply.writeNoException();
- reply.writeParcelableArray(uris, 0);
- return true;
- }
-
case PERFORM_IDLE_MAINTENANCE_TRANSACTION: {
data.enforceInterface(IActivityManager.descriptor);
performIdleMaintenance();
@@ -3436,6 +3451,47 @@
data.recycle();
reply.recycle();
}
+
+ @Override
+ public void takePersistableUriPermission(Uri uri, int mode) throws RemoteException {
+ Parcel data = Parcel.obtain();
+ Parcel reply = Parcel.obtain();
+ data.writeInterfaceToken(IActivityManager.descriptor);
+ uri.writeToParcel(data, 0);
+ data.writeInt(mode);
+ mRemote.transact(TAKE_PERSISTABLE_URI_PERMISSION_TRANSACTION, data, reply, 0);
+ reply.readException();
+ data.recycle();
+ reply.recycle();
+ }
+
+ @Override
+ public void releasePersistableUriPermission(Uri uri, int mode) throws RemoteException {
+ Parcel data = Parcel.obtain();
+ Parcel reply = Parcel.obtain();
+ data.writeInterfaceToken(IActivityManager.descriptor);
+ uri.writeToParcel(data, 0);
+ data.writeInt(mode);
+ mRemote.transact(RELEASE_PERSISTABLE_URI_PERMISSION_TRANSACTION, data, reply, 0);
+ reply.readException();
+ data.recycle();
+ reply.recycle();
+ }
+
+ @Override
+ public ParceledListSlice<UriPermission> getPersistedUriPermissions() throws RemoteException {
+ Parcel data = Parcel.obtain();
+ Parcel reply = Parcel.obtain();
+ data.writeInterfaceToken(IActivityManager.descriptor);
+ mRemote.transact(GET_PERSISTED_URI_PERMISSIONS_TRANSACTION, data, reply, 0);
+ reply.readException();
+ final ParceledListSlice<UriPermission> perms = ParceledListSlice.CREATOR.createFromParcel(
+ reply);
+ data.recycle();
+ reply.recycle();
+ return perms;
+ }
+
public void showWaitingForDebugger(IApplicationThread who, boolean waiting)
throws RemoteException {
Parcel data = Parcel.obtain();
@@ -4567,24 +4623,6 @@
reply.recycle();
}
- public Uri[] getGrantedUriPermissions(
- String sourcePackage, String targetPackage, int modeFlags, int modeMask)
- throws RemoteException {
- Parcel data = Parcel.obtain();
- Parcel reply = Parcel.obtain();
- data.writeInterfaceToken(IActivityManager.descriptor);
- data.writeString(sourcePackage);
- data.writeString(targetPackage);
- data.writeInt(modeFlags);
- data.writeInt(modeMask);
- mRemote.transact(GET_GRANTED_URI_PERMISSIONS_TRANSACTION, data, reply, 0);
- reply.readException();
- final Uri[] uris = (Uri[]) reply.readParcelableArray(null);
- data.recycle();
- reply.recycle();
- return uris;
- }
-
public void performIdleMaintenance() throws RemoteException {
Parcel data = Parcel.obtain();
Parcel reply = Parcel.obtain();
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index 3e20f1f..6605b5b 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -533,7 +533,8 @@
private native void dumpGraphicsInfo(FileDescriptor fd);
private class ApplicationThread extends ApplicationThreadNative {
- private static final String HEAP_COLUMN = "%13s %8s %8s %8s %8s %8s %8s %8s %8s %8s";
+ private static final String HEAP_FULL_COLUMN = "%13s %8s %8s %8s %8s %8s %8s %8s %8s %8s";
+ private static final String HEAP_COLUMN = "%13s %8s %8s %8s %8s %8s %8s %8s";
private static final String ONE_COUNT_COLUMN = "%21s %8d";
private static final String TWO_COUNT_COLUMNS = "%21s %8d %21s %8d";
private static final String DB_INFO_FORMAT = " %8s %8s %14s %14s %s";
@@ -892,18 +893,18 @@
@Override
public void dumpMemInfo(FileDescriptor fd, Debug.MemoryInfo mem, boolean checkin,
- boolean dumpInfo, boolean dumpDalvik, String[] args) {
+ boolean dumpFullInfo, boolean dumpDalvik, String[] args) {
FileOutputStream fout = new FileOutputStream(fd);
PrintWriter pw = new FastPrintWriter(fout);
try {
- dumpMemInfo(pw, mem, checkin, dumpInfo, dumpDalvik);
+ dumpMemInfo(pw, mem, checkin, dumpFullInfo, dumpDalvik);
} finally {
pw.flush();
}
}
private void dumpMemInfo(PrintWriter pw, Debug.MemoryInfo memInfo, boolean checkin,
- boolean dumpInfo, boolean dumpDalvik) {
+ boolean dumpFullInfo, boolean dumpDalvik) {
long nativeMax = Debug.getNativeHeapSize() / 1024;
long nativeAllocated = Debug.getNativeHeapAllocatedSize() / 1024;
long nativeFree = Debug.getNativeHeapFreeSize() / 1024;
@@ -1036,20 +1037,37 @@
}
// otherwise, show human-readable format
- printRow(pw, HEAP_COLUMN, "", "Pss", "Pss","Shared", "Private", "Shared", "Private",
- "Heap", "Heap", "Heap");
- printRow(pw, HEAP_COLUMN, "", "Total", "Clean", "Dirty", "Dirty", "Clean", "Clean",
- "Size", "Alloc", "Free");
- printRow(pw, HEAP_COLUMN, "", "------", "------", "------", "------", "------",
- "------", "------", "------", "------");
- printRow(pw, HEAP_COLUMN, "Native Heap", memInfo.nativePss, memInfo.nativeSwappablePss,
- memInfo.nativeSharedDirty,
- memInfo.nativePrivateDirty, memInfo.nativeSharedClean,
- memInfo.nativePrivateClean, nativeMax, nativeAllocated, nativeFree);
- printRow(pw, HEAP_COLUMN, "Dalvik Heap", memInfo.dalvikPss, memInfo.dalvikSwappablePss,
- memInfo.dalvikSharedDirty,
- memInfo.dalvikPrivateDirty, memInfo.dalvikSharedClean,
- memInfo.dalvikPrivateClean, dalvikMax, dalvikAllocated, dalvikFree);
+ if (dumpFullInfo) {
+ printRow(pw, HEAP_FULL_COLUMN, "", "Pss", "Pss", "Shared", "Private",
+ "Shared", "Private", "Heap", "Heap", "Heap");
+ printRow(pw, HEAP_FULL_COLUMN, "", "Total", "Clean", "Dirty", "Dirty",
+ "Clean", "Clean", "Size", "Alloc", "Free");
+ printRow(pw, HEAP_FULL_COLUMN, "", "------", "------", "------", "------",
+ "------", "------", "------", "------", "------");
+ printRow(pw, HEAP_FULL_COLUMN, "Native Heap", memInfo.nativePss,
+ memInfo.nativeSwappablePss, memInfo.nativeSharedDirty,
+ memInfo.nativePrivateDirty, memInfo.nativeSharedClean,
+ memInfo.nativePrivateClean, nativeMax, nativeAllocated, nativeFree);
+ printRow(pw, HEAP_FULL_COLUMN, "Dalvik Heap", memInfo.dalvikPss,
+ memInfo.dalvikSwappablePss, memInfo.dalvikSharedDirty,
+ memInfo.dalvikPrivateDirty, memInfo.dalvikSharedClean,
+ memInfo.dalvikPrivateClean, dalvikMax, dalvikAllocated, dalvikFree);
+ } else {
+ printRow(pw, HEAP_COLUMN, "", "Pss", "Pss", "Private",
+ "Private", "Heap", "Heap", "Heap");
+ printRow(pw, HEAP_COLUMN, "", "Total", "Clean", "Dirty",
+ "Clean", "Size", "Alloc", "Free");
+ printRow(pw, HEAP_COLUMN, "", "------", "------", "------",
+ "------", "------", "------", "------");
+ printRow(pw, HEAP_COLUMN, "Native Heap", memInfo.nativePss,
+ memInfo.nativeSwappablePss,
+ memInfo.nativePrivateDirty,
+ memInfo.nativePrivateClean, nativeMax, nativeAllocated, nativeFree);
+ printRow(pw, HEAP_COLUMN, "Dalvik Heap", memInfo.dalvikPss,
+ memInfo.dalvikSwappablePss,
+ memInfo.dalvikPrivateDirty,
+ memInfo.dalvikPrivateClean, dalvikMax, dalvikAllocated, dalvikFree);
+ }
int otherPss = memInfo.otherPss;
int otherSwappablePss = memInfo.otherSwappablePss;
@@ -1067,9 +1085,15 @@
final int myPrivateClean = memInfo.getOtherPrivateClean(i);
if (myPss != 0 || mySharedDirty != 0 || myPrivateDirty != 0
|| mySharedClean != 0 || myPrivateClean != 0) {
- printRow(pw, HEAP_COLUMN, Debug.MemoryInfo.getOtherLabel(i),
- myPss, mySwappablePss, mySharedDirty, myPrivateDirty,
- mySharedClean, myPrivateClean, "", "", "");
+ if (dumpFullInfo) {
+ printRow(pw, HEAP_FULL_COLUMN, Debug.MemoryInfo.getOtherLabel(i),
+ myPss, mySwappablePss, mySharedDirty, myPrivateDirty,
+ mySharedClean, myPrivateClean, "", "", "");
+ } else {
+ printRow(pw, HEAP_COLUMN, Debug.MemoryInfo.getOtherLabel(i),
+ myPss, mySwappablePss, myPrivateDirty,
+ myPrivateClean, "", "", "");
+ }
otherPss -= myPss;
otherSwappablePss -= mySwappablePss;
otherSharedDirty -= mySharedDirty;
@@ -1079,16 +1103,27 @@
}
}
-
-
- printRow(pw, HEAP_COLUMN, "Unknown", otherPss, otherSwappablePss, otherSharedDirty,
- otherPrivateDirty, otherSharedClean, otherPrivateClean,"", "", "");
- printRow(pw, HEAP_COLUMN, "TOTAL", memInfo.getTotalPss(),
- memInfo.getTotalSwappablePss(),
- memInfo.getTotalSharedDirty(), memInfo.getTotalPrivateDirty(),
- memInfo.getTotalSharedClean(), memInfo.getTotalPrivateClean(),
- nativeMax+dalvikMax,
- nativeAllocated+dalvikAllocated, nativeFree+dalvikFree);
+ if (dumpFullInfo) {
+ printRow(pw, HEAP_FULL_COLUMN, "Unknown", otherPss, otherSwappablePss,
+ otherSharedDirty, otherPrivateDirty, otherSharedClean, otherPrivateClean,
+ "", "", "");
+ printRow(pw, HEAP_FULL_COLUMN, "TOTAL", memInfo.getTotalPss(),
+ memInfo.getTotalSwappablePss(),
+ memInfo.getTotalSharedDirty(), memInfo.getTotalPrivateDirty(),
+ memInfo.getTotalSharedClean(), memInfo.getTotalPrivateClean(),
+ nativeMax+dalvikMax,
+ nativeAllocated+dalvikAllocated, nativeFree+dalvikFree);
+ } else {
+ printRow(pw, HEAP_COLUMN, "Unknown", otherPss, otherSwappablePss,
+ otherPrivateDirty, otherPrivateClean,
+ "", "", "");
+ printRow(pw, HEAP_COLUMN, "TOTAL", memInfo.getTotalPss(),
+ memInfo.getTotalSwappablePss(),
+ memInfo.getTotalPrivateDirty(),
+ memInfo.getTotalPrivateClean(),
+ nativeMax+dalvikMax,
+ nativeAllocated+dalvikAllocated, nativeFree+dalvikFree);
+ }
if (dumpDalvik) {
pw.println(" ");
@@ -1104,9 +1139,15 @@
final int myPrivateClean = memInfo.getOtherPrivateClean(i);
if (myPss != 0 || mySharedDirty != 0 || myPrivateDirty != 0
|| mySharedClean != 0 || myPrivateClean != 0) {
- printRow(pw, HEAP_COLUMN, Debug.MemoryInfo.getOtherLabel(i),
- myPss, mySwappablePss, mySharedDirty, myPrivateDirty,
- mySharedClean, myPrivateClean, "", "", "");
+ if (dumpFullInfo) {
+ printRow(pw, HEAP_FULL_COLUMN, Debug.MemoryInfo.getOtherLabel(i),
+ myPss, mySwappablePss, mySharedDirty, myPrivateDirty,
+ mySharedClean, myPrivateClean, "", "", "");
+ } else {
+ printRow(pw, HEAP_COLUMN, Debug.MemoryInfo.getOtherLabel(i),
+ myPss, mySwappablePss, myPrivateDirty,
+ myPrivateClean, "", "", "");
+ }
}
}
}
diff --git a/core/java/android/app/IActivityManager.java b/core/java/android/app/IActivityManager.java
index 25c02df..9a77377 100644
--- a/core/java/android/app/IActivityManager.java
+++ b/core/java/android/app/IActivityManager.java
@@ -27,9 +27,11 @@
import android.content.Intent;
import android.content.IntentFilter;
import android.content.IntentSender;
+import android.content.UriPermission;
import android.content.pm.ApplicationInfo;
import android.content.pm.ConfigurationInfo;
import android.content.pm.IPackageDataObserver;
+import android.content.pm.ParceledListSlice;
import android.content.pm.ProviderInfo;
import android.content.pm.UserInfo;
import android.content.res.Configuration;
@@ -210,7 +212,10 @@
Uri uri, int mode) throws RemoteException;
public void revokeUriPermission(IApplicationThread caller, Uri uri,
int mode) throws RemoteException;
-
+ public void takePersistableUriPermission(Uri uri, int modeFlags) throws RemoteException;
+ public void releasePersistableUriPermission(Uri uri, int modeFlags) throws RemoteException;
+ public ParceledListSlice<UriPermission> getPersistedUriPermissions() throws RemoteException;
+
public void showWaitingForDebugger(IApplicationThread who, boolean waiting)
throws RemoteException;
@@ -399,10 +404,6 @@
public void restart() throws RemoteException;
- public Uri[] getGrantedUriPermissions(
- String sourcePackage, String targetPackage, int modeFlags, int modeMask)
- throws RemoteException;
-
public void performIdleMaintenance() throws RemoteException;
/*
@@ -686,6 +687,8 @@
int NOTIFY_ACTIVITY_DRAWN_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+175;
int REPORT_ACTIVITY_FULLY_DRAWN_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+176;
int RESTART_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+177;
- int GET_GRANTED_URI_PERMISSIONS_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+178;
- int PERFORM_IDLE_MAINTENANCE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+179;
+ int PERFORM_IDLE_MAINTENANCE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+178;
+ int TAKE_PERSISTABLE_URI_PERMISSION_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+179;
+ int RELEASE_PERSISTABLE_URI_PERMISSION_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+180;
+ int GET_PERSISTED_URI_PERMISSIONS_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+181;
}
diff --git a/core/java/android/content/ContentResolver.java b/core/java/android/content/ContentResolver.java
index 2750d68..95fb6858 100644
--- a/core/java/android/content/ContentResolver.java
+++ b/core/java/android/content/ContentResolver.java
@@ -266,12 +266,18 @@
/** @hide */
protected abstract IContentProvider acquireProvider(Context c, String name);
- /** Providing a default implementation of this, to avoid having to change
- * a lot of other things, but implementations of ContentResolver should
- * implement it. @hide */
+
+ /**
+ * Providing a default implementation of this, to avoid having to change a
+ * lot of other things, but implementations of ContentResolver should
+ * implement it.
+ *
+ * @hide
+ */
protected IContentProvider acquireExistingProvider(Context c, String name) {
return acquireProvider(c, name);
}
+
/** @hide */
public abstract boolean releaseProvider(IContentProvider icp);
/** @hide */
@@ -1616,54 +1622,50 @@
}
/**
- * Return list of all Uri permissions that have been granted <em>to</em> the
- * calling package, and which exactly match the requested flags. For
- * example, to return all Uris that the calling application has
- * <em>non-persistent</em> read access to:
+ * Take a persistable Uri permission grant that has been offered. Once
+ * taken, the permission grant will be remembered across device reboots.
+ * Only Uri permissions granted with
+ * {@link Intent#FLAG_GRANT_PERSISTABLE_URI_PERMISSION} can be persisted. If
+ * the grant has already been persisted, taking it again will touch
+ * {@link UriPermission#getPersistedTime()}.
*
- * <pre class="prettyprint">
- * getIncomingUriPermissionGrants(Intent.FLAG_GRANT_READ_URI_PERMISSION,
- * Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_PERSIST_GRANT_URI_PERMISSION);
- * </pre>
- *
- * @param modeFlags any combination of
- * {@link Intent#FLAG_GRANT_READ_URI_PERMISSION},
- * {@link Intent#FLAG_GRANT_WRITE_URI_PERMISSION}, or
- * {@link Intent#FLAG_PERSIST_GRANT_URI_PERMISSION}.
- * @param modeMask mask indicating which flags must match.
+ * @see #getPersistedUriPermissions()
*/
- public Uri[] getIncomingUriPermissionGrants(int modeFlags, int modeMask) {
+ public void takePersistableUriPermission(Uri uri, int modeFlags) {
try {
- return ActivityManagerNative.getDefault()
- .getGrantedUriPermissions(null, getPackageName(), modeFlags, modeMask);
+ ActivityManagerNative.getDefault().takePersistableUriPermission(uri, modeFlags);
} catch (RemoteException e) {
- return new Uri[0];
}
}
/**
- * Return list of all Uri permissions that have been granted <em>from</em> the
- * calling package, and which exactly match the requested flags. For
- * example, to return all Uris that the calling application has granted
- * <em>non-persistent</em> read access to:
+ * Relinquish a persisted Uri permission grant. The Uri must have been
+ * previously made persistent with
+ * {@link #takePersistableUriPermission(Uri, int)}. Any non-persistent
+ * grants to the calling package will remain intact.
*
- * <pre class="prettyprint">
- * getOutgoingUriPermissionGrants(Intent.FLAG_GRANT_READ_URI_PERMISSION,
- * Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_PERSIST_GRANT_URI_PERMISSION);
- * </pre>
- *
- * @param modeFlags any combination of
- * {@link Intent#FLAG_GRANT_READ_URI_PERMISSION},
- * {@link Intent#FLAG_GRANT_WRITE_URI_PERMISSION}, or
- * {@link Intent#FLAG_PERSIST_GRANT_URI_PERMISSION}.
- * @param modeMask mask indicating which flags must match.
+ * @see #getPersistedUriPermissions()
*/
- public Uri[] getOutgoingUriPermissionGrants(int modeFlags, int modeMask) {
+ public void releasePersistableUriPermission(Uri uri, int modeFlags) {
try {
- return ActivityManagerNative.getDefault()
- .getGrantedUriPermissions(getPackageName(), null, modeFlags, modeMask);
+ ActivityManagerNative.getDefault().releasePersistableUriPermission(uri, modeFlags);
} catch (RemoteException e) {
- return new Uri[0];
+ }
+ }
+
+ /**
+ * Return list of all Uri permission grants that have been persisted for the
+ * calling app. Only persistable grants taken with
+ * {@link #takePersistableUriPermission(Uri, int)} are returned.
+ *
+ * @see #takePersistableUriPermission(Uri, int)
+ * @see #releasePersistableUriPermission(Uri, int)
+ */
+ public List<UriPermission> getPersistedUriPermissions() {
+ try {
+ return ActivityManagerNative.getDefault().getPersistedUriPermissions().getList();
+ } catch (RemoteException e) {
+ throw new RuntimeException("Activity manager has died", e);
}
}
diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java
index dcc6328..047f175 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -3339,12 +3339,18 @@
/**
* When combined with {@link #FLAG_GRANT_READ_URI_PERMISSION} and/or
- * {@link #FLAG_GRANT_WRITE_URI_PERMISSION}, the grant will be remembered
- * until explicitly revoked with
- * {@link Context#revokeUriPermission(Uri, int)}. These grants persist
- * across device reboots.
+ * {@link #FLAG_GRANT_WRITE_URI_PERMISSION}, the Uri permission grant can be
+ * persisted across device reboots until explicitly revoked with
+ * {@link Context#revokeUriPermission(Uri, int)}. This flag only offers the
+ * grant for possible persisting; the receiving application must call
+ * {@link ContentResolver#takePersistableUriPermission(Uri, int)} to
+ * actually persist.
+ *
+ * @see ContentResolver#takePersistableUriPermission(Uri, int)
+ * @see ContentResolver#releasePersistableUriPermission(Uri, int)
+ * @see ContentResolver#getPersistedUriPermissions()
*/
- public static final int FLAG_PERSIST_GRANT_URI_PERMISSION = 0x00000040;
+ public static final int FLAG_GRANT_PERSISTABLE_URI_PERMISSION = 0x00000040;
/**
* If set, the new activity is not kept in the history stack. As soon as
@@ -7173,7 +7179,7 @@
setClipData(target.getClipData());
addFlags(target.getFlags()
& (FLAG_GRANT_READ_URI_PERMISSION | FLAG_GRANT_WRITE_URI_PERMISSION
- | FLAG_PERSIST_GRANT_URI_PERMISSION));
+ | FLAG_GRANT_PERSISTABLE_URI_PERMISSION));
return true;
} else {
return false;
diff --git a/core/java/android/content/UriPermission.java b/core/java/android/content/UriPermission.java
new file mode 100644
index 0000000..df9200d
--- /dev/null
+++ b/core/java/android/content/UriPermission.java
@@ -0,0 +1,117 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.content;
+
+import android.net.Uri;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+/**
+ * Description of a single Uri permission grant. This grants may have been
+ * created via {@link Intent#FLAG_GRANT_READ_URI_PERMISSION}, etc when sending
+ * an {@link Intent}, or explicitly through
+ * {@link Context#grantUriPermission(String, android.net.Uri, int)}.
+ *
+ * @see ContentResolver#getPersistedUriPermissions()
+ */
+public final class UriPermission implements Parcelable {
+ private final Uri mUri;
+ private final int mModeFlags;
+ private final long mPersistedTime;
+
+ /**
+ * Value returned when a permission has not been persisted.
+ */
+ public static final long INVALID_TIME = Long.MIN_VALUE;
+
+ /** {@hide} */
+ public UriPermission(Uri uri, int modeFlags, long persistedTime) {
+ mUri = uri;
+ mModeFlags = modeFlags;
+ mPersistedTime = persistedTime;
+ }
+
+ /** {@hide} */
+ public UriPermission(Parcel in) {
+ mUri = in.readParcelable(null);
+ mModeFlags = in.readInt();
+ mPersistedTime = in.readLong();
+ }
+
+ /**
+ * Return the Uri this permission pertains to.
+ */
+ public Uri getUri() {
+ return mUri;
+ }
+
+ /**
+ * Returns if this permission offers read access.
+ */
+ public boolean isReadPermission() {
+ return (mModeFlags & Intent.FLAG_GRANT_READ_URI_PERMISSION) != 0;
+ }
+
+ /**
+ * Returns if this permission offers write access.
+ */
+ public boolean isWritePermission() {
+ return (mModeFlags & Intent.FLAG_GRANT_WRITE_URI_PERMISSION) != 0;
+ }
+
+ /**
+ * Return the time when this permission was first persisted, in milliseconds
+ * since January 1, 1970 00:00:00.0 UTC. Returns {@link #INVALID_TIME} if
+ * not persisted.
+ *
+ * @see ContentResolver#takePersistableUriPermission(Uri, int)
+ * @see System#currentTimeMillis()
+ */
+ public long getPersistedTime() {
+ return mPersistedTime;
+ }
+
+ @Override
+ public String toString() {
+ return "UriPermission {uri=" + mUri + ", modeFlags=" + mModeFlags + ", persistedTime="
+ + mPersistedTime + "}";
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeParcelable(mUri, flags);
+ dest.writeInt(mModeFlags);
+ dest.writeLong(mPersistedTime);
+ }
+
+ public static final Creator<UriPermission> CREATOR = new Creator<UriPermission>() {
+ @Override
+ public UriPermission createFromParcel(Parcel source) {
+ return new UriPermission(source);
+ }
+
+ @Override
+ public UriPermission[] newArray(int size) {
+ return new UriPermission[size];
+ }
+ };
+}
diff --git a/core/java/android/hardware/ICameraService.aidl b/core/java/android/hardware/ICameraService.aidl
index fc54828..542af6a 100644
--- a/core/java/android/hardware/ICameraService.aidl
+++ b/core/java/android/hardware/ICameraService.aidl
@@ -22,6 +22,7 @@
import android.hardware.IProCameraCallbacks;
import android.hardware.camera2.ICameraDeviceUser;
import android.hardware.camera2.ICameraDeviceCallbacks;
+import android.hardware.camera2.impl.CameraMetadataNative;
import android.hardware.camera2.utils.BinderHolder;
import android.hardware.ICameraServiceListener;
import android.hardware.CameraInfo;
@@ -58,4 +59,6 @@
int addListener(ICameraServiceListener listener);
int removeListener(ICameraServiceListener listener);
+
+ int getCameraCharacteristics(int cameraId, out CameraMetadataNative info);
}
diff --git a/core/java/android/hardware/camera2/CameraManager.java b/core/java/android/hardware/camera2/CameraManager.java
index af0512e..798ad7b 100644
--- a/core/java/android/hardware/camera2/CameraManager.java
+++ b/core/java/android/hardware/camera2/CameraManager.java
@@ -176,10 +176,17 @@
}
}
- // TODO: implement and call a service function to get the capabilities on C++ side
+ CameraMetadataNative info = new CameraMetadataNative();
+ try {
+ mCameraService.getCameraCharacteristics(Integer.valueOf(cameraId), info);
+ } catch(CameraRuntimeException e) {
+ throw e.asChecked();
+ } catch(RemoteException e) {
+ // impossible
+ return null;
+ }
- // TODO: get properties from service
- return new CameraCharacteristics(new CameraMetadataNative());
+ return new CameraCharacteristics(info);
}
/**
diff --git a/core/java/android/os/Debug.java b/core/java/android/os/Debug.java
index 0c718f4..0a1ffc9 100644
--- a/core/java/android/os/Debug.java
+++ b/core/java/android/os/Debug.java
@@ -1031,7 +1031,13 @@
/** @hide */
public static final int MEMINFO_SLAB = 5;
/** @hide */
- public static final int MEMINFO_COUNT = 6;
+ public static final int MEMINFO_SWAP_TOTAL = 6;
+ /** @hide */
+ public static final int MEMINFO_SWAP_FREE = 7;
+ /** @hide */
+ public static final int MEMINFO_ZRAM_TOTAL = 8;
+ /** @hide */
+ public static final int MEMINFO_COUNT = 9;
/**
* Retrieves /proc/meminfo. outSizes is filled with fields
diff --git a/core/java/android/provider/DocumentsContract.java b/core/java/android/provider/DocumentsContract.java
index 3f33e80..8f22312 100644
--- a/core/java/android/provider/DocumentsContract.java
+++ b/core/java/android/provider/DocumentsContract.java
@@ -21,10 +21,7 @@
import android.content.ContentProviderClient;
import android.content.ContentResolver;
-import android.content.Context;
import android.content.Intent;
-import android.content.pm.PackageManager;
-import android.content.pm.ProviderInfo;
import android.content.res.AssetFileDescriptor;
import android.database.Cursor;
import android.graphics.Bitmap;
@@ -38,8 +35,6 @@
import android.os.RemoteException;
import android.util.Log;
-import com.google.android.collect.Lists;
-
import libcore.io.ErrnoException;
import libcore.io.IoUtils;
import libcore.io.Libcore;
@@ -624,37 +619,6 @@
}
/**
- * Return list of all documents that the calling package has "open." These
- * are Uris matching {@link DocumentsContract} to which persistent
- * read/write access has been granted, usually through
- * {@link Intent#ACTION_OPEN_DOCUMENT} or
- * {@link Intent#ACTION_CREATE_DOCUMENT}.
- *
- * @see Context#grantUriPermission(String, Uri, int)
- * @see Context#revokeUriPermission(Uri, int)
- * @see ContentResolver#getIncomingUriPermissionGrants(int, int)
- */
- public static Uri[] getOpenDocuments(Context context) {
- final int openedFlags = Intent.FLAG_GRANT_READ_URI_PERMISSION
- | Intent.FLAG_GRANT_WRITE_URI_PERMISSION | Intent.FLAG_PERSIST_GRANT_URI_PERMISSION;
- final Uri[] uris = context.getContentResolver()
- .getIncomingUriPermissionGrants(openedFlags, openedFlags);
-
- // Filter to only include document providers
- final PackageManager pm = context.getPackageManager();
- final List<Uri> result = Lists.newArrayList();
- for (Uri uri : uris) {
- final ProviderInfo info = pm.resolveContentProvider(
- uri.getAuthority(), PackageManager.GET_META_DATA);
- if (info.metaData.containsKey(META_DATA_DOCUMENT_PROVIDER)) {
- result.add(uri);
- }
- }
-
- return result.toArray(new Uri[result.size()]);
- }
-
- /**
* Return thumbnail representing the document at the given Uri. Callers are
* responsible for their own in-memory caching.
*
diff --git a/core/java/android/provider/DocumentsProvider.java b/core/java/android/provider/DocumentsProvider.java
index bc4e28b..337b735 100644
--- a/core/java/android/provider/DocumentsProvider.java
+++ b/core/java/android/provider/DocumentsProvider.java
@@ -387,7 +387,7 @@
context.grantUriPermission(getCallingPackage(), newDocumentUri,
Intent.FLAG_GRANT_READ_URI_PERMISSION
| Intent.FLAG_GRANT_WRITE_URI_PERMISSION
- | Intent.FLAG_PERSIST_GRANT_URI_PERMISSION);
+ | Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION);
}
} else if (METHOD_DELETE_DOCUMENT.equals(method)) {
@@ -396,7 +396,7 @@
// Document no longer exists, clean up any grants
context.revokeUriPermission(documentUri, Intent.FLAG_GRANT_READ_URI_PERMISSION
| Intent.FLAG_GRANT_WRITE_URI_PERMISSION
- | Intent.FLAG_PERSIST_GRANT_URI_PERMISSION);
+ | Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION);
} else {
throw new UnsupportedOperationException("Method not supported " + method);
diff --git a/core/java/com/android/internal/policy/IKeyguardService.aidl b/core/java/com/android/internal/policy/IKeyguardService.aidl
index dd2e006..45a38be 100644
--- a/core/java/com/android/internal/policy/IKeyguardService.aidl
+++ b/core/java/com/android/internal/policy/IKeyguardService.aidl
@@ -42,4 +42,5 @@
oneway void setCurrentUser(int userId);
oneway void showAssistant();
oneway void dispatch(in MotionEvent event);
+ oneway void launchCamera();
}
diff --git a/core/java/com/android/internal/util/MemInfoReader.java b/core/java/com/android/internal/util/MemInfoReader.java
index ad65433..5f240f7 100644
--- a/core/java/com/android/internal/util/MemInfoReader.java
+++ b/core/java/com/android/internal/util/MemInfoReader.java
@@ -16,47 +16,11 @@
package com.android.internal.util;
-import java.io.FileInputStream;
-
import android.os.Debug;
import android.os.StrictMode;
-public class MemInfoReader {
- byte[] mBuffer = new byte[1024];
-
- private long mTotalSize;
- private long mFreeSize;
- private long mCachedSize;
-
- private boolean matchText(byte[] buffer, int index, String text) {
- int N = text.length();
- if ((index+N) >= buffer.length) {
- return false;
- }
- for (int i=0; i<N; i++) {
- if (buffer[index+i] != text.charAt(i)) {
- return false;
- }
- }
- return true;
- }
-
- private long extractMemValue(byte[] buffer, int index) {
- while (index < buffer.length && buffer[index] != '\n') {
- if (buffer[index] >= '0' && buffer[index] <= '9') {
- int start = index;
- index++;
- while (index < buffer.length && buffer[index] >= '0'
- && buffer[index] <= '9') {
- index++;
- }
- String str = new String(buffer, 0, start, index-start);
- return ((long)Integer.parseInt(str)) * 1024;
- }
- index++;
- }
- return 0;
- }
+public final class MemInfoReader {
+ final long[] mInfos = new long[Debug.MEMINFO_COUNT];
public void readMemInfo() {
// Permit disk reads here, as /proc/meminfo isn't really "on
@@ -64,25 +28,57 @@
// /proc/ and /sys/ files perhaps?
StrictMode.ThreadPolicy savedPolicy = StrictMode.allowThreadDiskReads();
try {
- long[] infos = new long[Debug.MEMINFO_COUNT];
- Debug.getMemInfo(infos);
- mTotalSize = infos[Debug.MEMINFO_TOTAL] * 1024;
- mFreeSize = infos[Debug.MEMINFO_FREE] * 1024;
- mCachedSize = infos[Debug.MEMINFO_CACHED] * 1024;
+ Debug.getMemInfo(mInfos);
} finally {
StrictMode.setThreadPolicy(savedPolicy);
}
}
public long getTotalSize() {
- return mTotalSize;
+ return mInfos[Debug.MEMINFO_TOTAL] * 1024;
}
public long getFreeSize() {
- return mFreeSize;
+ return mInfos[Debug.MEMINFO_FREE] * 1024;
}
public long getCachedSize() {
- return mCachedSize;
+ return mInfos[Debug.MEMINFO_CACHED] * 1024;
+ }
+
+ public long getTotalSizeKb() {
+ return mInfos[Debug.MEMINFO_TOTAL];
+ }
+
+ public long getFreeSizeKb() {
+ return mInfos[Debug.MEMINFO_FREE];
+ }
+
+ public long getCachedSizeKb() {
+ return mInfos[Debug.MEMINFO_CACHED];
+ }
+
+ public long getBuffersSizeKb() {
+ return mInfos[Debug.MEMINFO_BUFFERS];
+ }
+
+ public long getShmemSizeKb() {
+ return mInfos[Debug.MEMINFO_SHMEM];
+ }
+
+ public long getSlabSizeKb() {
+ return mInfos[Debug.MEMINFO_SLAB];
+ }
+
+ public long getSwapTotalSizeKb() {
+ return mInfos[Debug.MEMINFO_SWAP_TOTAL];
+ }
+
+ public long getSwapFreeSizeKb() {
+ return mInfos[Debug.MEMINFO_SWAP_FREE];
+ }
+
+ public long getZramTotalSizeKb() {
+ return mInfos[Debug.MEMINFO_ZRAM_TOTAL];
}
}
diff --git a/core/java/com/android/internal/util/XmlUtils.java b/core/java/com/android/internal/util/XmlUtils.java
index f40f48c..0b74cf3 100644
--- a/core/java/com/android/internal/util/XmlUtils.java
+++ b/core/java/com/android/internal/util/XmlUtils.java
@@ -931,6 +931,15 @@
out.attribute(null, name, Integer.toString(value));
}
+ public static long readLongAttribute(XmlPullParser in, String name, long defaultValue) {
+ final String value = in.getAttributeValue(null, name);
+ try {
+ return Long.parseLong(value);
+ } catch (NumberFormatException e) {
+ return defaultValue;
+ }
+ }
+
public static long readLongAttribute(XmlPullParser in, String name) throws IOException {
final String value = in.getAttributeValue(null, name);
try {
diff --git a/core/java/com/android/internal/widget/SubtitleView.java b/core/java/com/android/internal/widget/SubtitleView.java
index 356401c..e30c1ff 100644
--- a/core/java/com/android/internal/widget/SubtitleView.java
+++ b/core/java/com/android/internal/widget/SubtitleView.java
@@ -31,7 +31,6 @@
import android.text.Layout.Alignment;
import android.text.StaticLayout;
import android.text.TextPaint;
-import android.text.TextUtils;
import android.util.AttributeSet;
import android.util.DisplayMetrics;
import android.util.TypedValue;
@@ -52,14 +51,12 @@
/** Temporary rectangle used for computing line bounds. */
private final RectF mLineBounds = new RectF();
- /** Temporary array used for computing line wrapping. */
- private float[] mTextWidths;
-
/** Reusable string builder used for holding text. */
private final StringBuilder mText = new StringBuilder();
- private final StringBuilder mBreakText = new StringBuilder();
- private TextPaint mPaint;
+ private Alignment mAlignment;
+ private TextPaint mTextPaint;
+ private Paint mPaint;
private int mForegroundColor;
private int mBackgroundColor;
@@ -122,11 +119,12 @@
mShadowOffsetX = res.getDimension(com.android.internal.R.dimen.subtitle_shadow_offset);
mShadowOffsetY = mShadowOffsetX;
- final TextPaint paint = new TextPaint();
- paint.setAntiAlias(true);
- paint.setSubpixelText(true);
+ mTextPaint = new TextPaint();
+ mTextPaint.setAntiAlias(true);
+ mTextPaint.setSubpixelText(true);
- mPaint = paint;
+ mPaint = new Paint();
+ mPaint.setAntiAlias(true);
setText(text);
setTextSize(textSize);
@@ -174,21 +172,30 @@
public void setTextSize(float size) {
final DisplayMetrics metrics = getContext().getResources().getDisplayMetrics();
final float pixels = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, size, metrics);
- if (mPaint.getTextSize() != size) {
- mHasMeasurements = false;
+ if (mTextPaint.getTextSize() != size) {
+ mTextPaint.setTextSize(size);
mInnerPaddingX = (int) (size * INNER_PADDING_RATIO + 0.5f);
- mPaint.setTextSize(size);
- requestLayout();
+ mHasMeasurements = false;
+ forceLayout();
}
}
public void setTypeface(Typeface typeface) {
- if (mPaint.getTypeface() != typeface) {
- mHasMeasurements = false;
- mPaint.setTypeface(typeface);
+ if (mTextPaint.getTypeface() != typeface) {
+ mTextPaint.setTypeface(typeface);
- requestLayout();
+ mHasMeasurements = false;
+ forceLayout();
+ }
+ }
+
+ public void setAlignment(Alignment textAlignment) {
+ if (mAlignment != textAlignment) {
+ mAlignment = textAlignment;
+
+ mHasMeasurements = false;
+ forceLayout();
}
}
@@ -222,63 +229,19 @@
}
// Account for padding.
- final int paddingX = mPaddingLeft + mPaddingRight + mInnerPaddingX;
+ final int paddingX = mPaddingLeft + mPaddingRight + mInnerPaddingX * 2;
maxWidth -= paddingX;
-
if (maxWidth <= 0) {
return false;
}
- final TextPaint paint = mPaint;
- final CharSequence text = mText;
- final int textLength = text.length();
- if (mTextWidths == null || mTextWidths.length < textLength) {
- mTextWidths = new float[textLength];
- }
-
- final float[] textWidths = mTextWidths;
- paint.getTextWidths(text, 0, textLength, textWidths);
-
- // Compute total length.
- float runLength = 0;
- for (int i = 0; i < textLength; i++) {
- runLength += textWidths[i];
- }
-
- final int lineCount = (int) (runLength / maxWidth) + 1;
- final int lineLength = (int) (runLength / lineCount);
-
- // Build line break buffer.
- final StringBuilder breakText = mBreakText;
- breakText.setLength(0);
-
- int line = 0;
- int lastBreak = 0;
- int maxRunLength = 0;
- runLength = 0;
- for (int i = 0; i < textLength; i++) {
- if (runLength > lineLength) {
- final CharSequence sequence = text.subSequence(lastBreak, i);
- final int trimmedLength = TextUtils.getTrimmedLength(sequence);
- breakText.append(sequence, 0, trimmedLength);
- breakText.append('\n');
- lastBreak = i;
- runLength = 0;
- }
-
- runLength += textWidths[i];
-
- if (runLength > maxRunLength) {
- maxRunLength = (int) Math.ceil(runLength);
- }
- }
- breakText.append(text.subSequence(lastBreak, textLength));
-
+ // TODO: Implement minimum-difference line wrapping. Adding the results
+ // of Paint.getTextWidths() seems to return different values than
+ // StaticLayout.getWidth(), so this is non-trivial.
mHasMeasurements = true;
mLastMeasuredWidth = maxWidth;
-
- mLayout = new StaticLayout(breakText, paint, maxRunLength, Alignment.ALIGN_LEFT,
- mSpacingMult, mSpacingAdd, true);
+ mLayout = new StaticLayout(
+ mText, mTextPaint, maxWidth, mAlignment, mSpacingMult, mSpacingAdd, true);
return true;
}
@@ -316,54 +279,50 @@
final int innerPaddingX = mInnerPaddingX;
c.translate(mPaddingLeft + innerPaddingX, mPaddingTop);
- final RectF bounds = mLineBounds;
final int lineCount = layout.getLineCount();
- final Paint paint = layout.getPaint();
- paint.setShadowLayer(0, 0, 0, 0);
+ final Paint textPaint = mTextPaint;
+ final Paint paint = mPaint;
+ final RectF bounds = mLineBounds;
- final int backgroundColor = mBackgroundColor;
- if (Color.alpha(backgroundColor) > 0) {
- paint.setColor(backgroundColor);
- paint.setStyle(Style.FILL);
-
+ if (Color.alpha(mBackgroundColor) > 0) {
final float cornerRadius = mCornerRadius;
float previousBottom = layout.getLineTop(0);
+ paint.setColor(mBackgroundColor);
+ paint.setStyle(Style.FILL);
+
for (int i = 0; i < lineCount; i++) {
- bounds.left = layout.getLineLeft(i) - innerPaddingX;
+ bounds.left = layout.getLineLeft(i) -innerPaddingX;
bounds.right = layout.getLineRight(i) + innerPaddingX;
bounds.top = previousBottom;
bounds.bottom = layout.getLineBottom(i);
-
previousBottom = bounds.bottom;
c.drawRoundRect(bounds, cornerRadius, cornerRadius, paint);
}
}
- final int edgeType = mEdgeType;
- if (edgeType == CaptionStyle.EDGE_TYPE_OUTLINE) {
- paint.setColor(mEdgeColor);
- paint.setStyle(Style.FILL_AND_STROKE);
- paint.setStrokeJoin(Join.ROUND);
- paint.setStrokeWidth(mOutlineWidth);
+ if (mEdgeType == CaptionStyle.EDGE_TYPE_OUTLINE) {
+ textPaint.setStrokeJoin(Join.ROUND);
+ textPaint.setStrokeWidth(mOutlineWidth);
+ textPaint.setColor(mEdgeColor);
+ textPaint.setStyle(Style.FILL_AND_STROKE);
for (int i = 0; i < lineCount; i++) {
layout.drawText(c, i, i);
}
+ } else if (mEdgeType == CaptionStyle.EDGE_TYPE_DROP_SHADOW) {
+ textPaint.setShadowLayer(mShadowRadius, mShadowOffsetX, mShadowOffsetY, mEdgeColor);
}
- if (edgeType == CaptionStyle.EDGE_TYPE_DROP_SHADOW) {
- paint.setShadowLayer(mShadowRadius, mShadowOffsetX, mShadowOffsetY, mEdgeColor);
- }
-
- paint.setColor(mForegroundColor);
- paint.setStyle(Style.FILL);
+ textPaint.setColor(mForegroundColor);
+ textPaint.setStyle(Style.FILL);
for (int i = 0; i < lineCount; i++) {
layout.drawText(c, i, i);
}
+ textPaint.setShadowLayer(0, 0, 0, 0);
c.restoreToCount(saveCount);
}
}
diff --git a/core/jni/android_os_Debug.cpp b/core/jni/android_os_Debug.cpp
index 60540f4..aa5b254 100644
--- a/core/jni/android_os_Debug.cpp
+++ b/core/jni/android_os_Debug.cpp
@@ -516,6 +516,19 @@
return android_os_Debug_getPssPid(env, clazz, getpid(), NULL);
}
+enum {
+ MEMINFO_TOTAL,
+ MEMINFO_FREE,
+ MEMINFO_BUFFERS,
+ MEMINFO_CACHED,
+ MEMINFO_SHMEM,
+ MEMINFO_SLAB,
+ MEMINFO_SWAP_TOTAL,
+ MEMINFO_SWAP_FREE,
+ MEMINFO_ZRAM_TOTAL,
+ MEMINFO_COUNT
+};
+
static void android_os_Debug_getMemInfo(JNIEnv *env, jobject clazz, jlongArray out)
{
char buffer[1024];
@@ -529,15 +542,15 @@
int fd = open("/proc/meminfo", O_RDONLY);
if (fd < 0) {
- printf("Unable to open /proc/meminfo: %s\n", strerror(errno));
+ ALOGW("Unable to open /proc/meminfo: %s\n", strerror(errno));
return;
}
- const int len = read(fd, buffer, sizeof(buffer)-1);
+ int len = read(fd, buffer, sizeof(buffer)-1);
close(fd);
if (len < 0) {
- printf("Empty /proc/meminfo");
+ ALOGW("Empty /proc/meminfo");
return;
}
buffer[len] = 0;
@@ -549,6 +562,8 @@
"Cached:",
"Shmem:",
"Slab:",
+ "SwapTotal:",
+ "SwapFree:",
NULL
};
static const int tagsLen[] = {
@@ -558,12 +573,14 @@
7,
6,
5,
+ 10,
+ 9,
0
};
- long mem[] = { 0, 0, 0, 0, 0, 0 };
+ long mem[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0 };
char* p = buffer;
- while (*p && numFound < 6) {
+ while (*p && numFound < 8) {
int i = 0;
while (tags[i]) {
if (strncmp(p, tags[i], tagsLen[i]) == 0) {
@@ -587,7 +604,20 @@
if (*p) p++;
}
+ fd = open("/sys/block/zram0/mem_used_total", O_RDONLY);
+ if (fd >= 0) {
+ len = read(fd, buffer, sizeof(buffer)-1);
+ close(fd);
+ if (len > 0) {
+ buffer[len] = 0;
+ mem[MEMINFO_ZRAM_TOTAL] = atoll(buffer);
+ }
+ }
+
int maxNum = env->GetArrayLength(out);
+ if (maxNum > MEMINFO_COUNT) {
+ maxNum = MEMINFO_COUNT;
+ }
jlong* outArray = env->GetLongArrayElements(out, 0);
if (outArray != NULL) {
for (int i=0; i<maxNum && tags[i]; i++) {
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 4c15e18..b41b5b5 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -1403,6 +1403,27 @@
android:label="@string/permlab_expandStatusBar"
android:description="@string/permdesc_expandStatusBar" />
+ <!-- ============================================================== -->
+ <!-- Permissions related to adding/removing shortcuts from Launcher -->
+ <!-- ============================================================== -->
+ <eat-comment />
+
+ <!-- Allows an application to install a shortcut in Launcher -->
+ <permission
+ android:name="com.android.launcher.permission.INSTALL_SHORTCUT"
+ android:permissionGroup="android.permission-group.SYSTEM_TOOLS"
+ android:protectionLevel="dangerous"
+ android:label="@string/permlab_install_shortcut"
+ android:description="@string/permdesc_install_shortcut" />
+
+ <!-- Allows an application to uninstall a shortcut in Launcher -->
+ <permission
+ android:name="com.android.launcher.permission.UNINSTALL_SHORTCUT"
+ android:permissionGroup="android.permission-group.SYSTEM_TOOLS"
+ android:protectionLevel="dangerous"
+ android:label="@string/permlab_uninstall_shortcut"
+ android:description="@string/permdesc_uninstall_shortcut"/>
+
<!-- ==================================================== -->
<!-- Permissions related to accessing sync settings -->
<!-- ==================================================== -->
diff --git a/core/res/res/drawable-hdpi/toast_frame_holo.9.png b/core/res/res/drawable-hdpi/toast_frame_holo.9.png
index ca65994..f0d9b21 100644
--- a/core/res/res/drawable-hdpi/toast_frame_holo.9.png
+++ b/core/res/res/drawable-hdpi/toast_frame_holo.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/toast_frame_holo.9.png b/core/res/res/drawable-mdpi/toast_frame_holo.9.png
index 9e93fe7..458137c 100644
--- a/core/res/res/drawable-mdpi/toast_frame_holo.9.png
+++ b/core/res/res/drawable-mdpi/toast_frame_holo.9.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/toast_frame_holo.9.png b/core/res/res/drawable-xhdpi/toast_frame_holo.9.png
index 1f63420..f1209a2 100644
--- a/core/res/res/drawable-xhdpi/toast_frame_holo.9.png
+++ b/core/res/res/drawable-xhdpi/toast_frame_holo.9.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/kg_add_widget.png b/core/res/res/drawable-xxhdpi/kg_add_widget.png
deleted file mode 100644
index 33d839e..0000000
--- a/core/res/res/drawable-xxhdpi/kg_add_widget.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/kg_add_widget_disabled.png b/core/res/res/drawable-xxhdpi/kg_add_widget_disabled.png
deleted file mode 100644
index 405ab30..0000000
--- a/core/res/res/drawable-xxhdpi/kg_add_widget_disabled.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/kg_add_widget_pressed.png b/core/res/res/drawable-xxhdpi/kg_add_widget_pressed.png
deleted file mode 100644
index f23fad5..0000000
--- a/core/res/res/drawable-xxhdpi/kg_add_widget_pressed.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/kg_bouncer_bg_focused.9.png b/core/res/res/drawable-xxhdpi/kg_bouncer_bg_focused.9.png
deleted file mode 100644
index 67e5900..0000000
--- a/core/res/res/drawable-xxhdpi/kg_bouncer_bg_focused.9.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/kg_bouncer_bg_normal.9.png b/core/res/res/drawable-xxhdpi/kg_bouncer_bg_normal.9.png
deleted file mode 100644
index b474e7d..0000000
--- a/core/res/res/drawable-xxhdpi/kg_bouncer_bg_normal.9.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/kg_bouncer_bg_pressed.9.png b/core/res/res/drawable-xxhdpi/kg_bouncer_bg_pressed.9.png
deleted file mode 100644
index 5edf225..0000000
--- a/core/res/res/drawable-xxhdpi/kg_bouncer_bg_pressed.9.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/kg_dot_pattern.png b/core/res/res/drawable-xxhdpi/kg_dot_pattern.png
deleted file mode 100644
index 2ce3ba2..0000000
--- a/core/res/res/drawable-xxhdpi/kg_dot_pattern.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/kg_security_grip.9.png b/core/res/res/drawable-xxhdpi/kg_security_grip.9.png
deleted file mode 100644
index 47fd407..0000000
--- a/core/res/res/drawable-xxhdpi/kg_security_grip.9.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/kg_security_lock_focused.png b/core/res/res/drawable-xxhdpi/kg_security_lock_focused.png
deleted file mode 100644
index e0a2e2a..0000000
--- a/core/res/res/drawable-xxhdpi/kg_security_lock_focused.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/kg_security_lock_normal.png b/core/res/res/drawable-xxhdpi/kg_security_lock_normal.png
deleted file mode 100644
index 2d62c45..0000000
--- a/core/res/res/drawable-xxhdpi/kg_security_lock_normal.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/kg_security_lock_pressed.png b/core/res/res/drawable-xxhdpi/kg_security_lock_pressed.png
deleted file mode 100644
index 97900d5..0000000
--- a/core/res/res/drawable-xxhdpi/kg_security_lock_pressed.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/kg_widget_bg_padded.9.png b/core/res/res/drawable-xxhdpi/kg_widget_bg_padded.9.png
deleted file mode 100644
index a22bc8e..0000000
--- a/core/res/res/drawable-xxhdpi/kg_widget_bg_padded.9.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/toast_frame_holo.9.png b/core/res/res/drawable-xxhdpi/toast_frame_holo.9.png
index 882b9c6..6c86258 100644
--- a/core/res/res/drawable-xxhdpi/toast_frame_holo.9.png
+++ b/core/res/res/drawable-xxhdpi/toast_frame_holo.9.png
Binary files differ
diff --git a/core/res/res/layout/transient_notification.xml b/core/res/res/layout/transient_notification.xml
index 5523807..daa9faf 100644
--- a/core/res/res/layout/transient_notification.xml
+++ b/core/res/res/layout/transient_notification.xml
@@ -30,7 +30,7 @@
android:layout_height="wrap_content"
android:layout_weight="1"
android:layout_gravity="center_horizontal"
- android:textAppearance="@style/TextAppearance.Small"
+ android:textAppearance="@style/TextAppearance.Toast"
android:textColor="@color/bright_foreground_dark"
android:shadowColor="#BB000000"
android:shadowRadius="2.75"
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 84a0d37..b3cb2a1 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -1255,4 +1255,8 @@
<!-- Threshold (in ms) under which a screen off / screen on will be considered a reset of the
transient navigation confirmation prompt.-->
<integer name="config_transient_navigation_confirmation_panic">5000</integer>
+
+ <!-- For some operators, PDU has garbages. To fix it, need to use valid index -->
+ <integer name="config_valid_wappush_index">-1</integer>
+
</resources>
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index c57873e..c20c427 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -599,6 +599,22 @@
<!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
<string name="permdesc_expandStatusBar">Allows the app to expand or collapse the status bar.</string>
+ <!-- Title of an application permission, listed so the user can install application shortcuts
+ in their Launcher -->
+ <string name="permlab_install_shortcut">install shortcuts</string>
+ <!-- Description of an application permission, listed so the user can install application shortcuts
+ in their Launcher -->
+ <string name="permdesc_install_shortcut">Allows an application to add
+ Homescreen shortcuts without user intervention.</string>
+
+ <!-- Title of an application permission, listed so the user can uninstall application shortcuts
+ in their Launcher -->
+ <string name="permlab_uninstall_shortcut">uninstall shortcuts</string>
+ <!-- Description of an application permission, listed so the user can install application shortcuts
+ in their Launcher -->
+ <string name="permdesc_uninstall_shortcut">Allows the application to remove
+ Homescreen shortcuts without user intervention.</string>
+
<!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
<string name="permlab_processOutgoingCalls">reroute outgoing calls</string>
<!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
diff --git a/core/res/res/values/styles.xml b/core/res/res/values/styles.xml
index ba72a2b..c5dab3b 100644
--- a/core/res/res/values/styles.xml
+++ b/core/res/res/values/styles.xml
@@ -918,6 +918,10 @@
<item name="android:textSize">30sp</item>
</style>
+ <style name="TextAppearance.Toast">
+ <item name="android:fontFamily">sans-serif-condensed</item>
+ </style>
+
<style name="Widget.ActivityChooserView">
<item name="android:gravity">center</item>
<item name="android:background">@android:drawable/ab_share_pack_holo_dark</item>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 14b319f..57a4bb7 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -316,6 +316,7 @@
<java-symbol type="integer" name="config_safe_media_volume_index" />
<java-symbol type="integer" name="config_mobile_mtu" />
<java-symbol type="integer" name="config_volte_replacement_rat"/>
+ <java-symbol type="integer" name="config_valid_wappush_index" />
<java-symbol type="color" name="tab_indicator_text_v4" />
diff --git a/docs/html/sdk/installing/studio.jd b/docs/html/sdk/installing/studio.jd
index 5a47f85..3399ee8 100644
--- a/docs/html/sdk/installing/studio.jd
+++ b/docs/html/sdk/installing/studio.jd
@@ -187,7 +187,7 @@
<div id="main">
-<div class="figure" style="width:400px;margin-top:-50px">
+<div class="figure" style="width:400px;margin-top:-20px">
<img src="{@docRoot}images/tools/android-studio.png" height="330" width="400" style="margin-bottom:20px" />
<a class="big button subtitle" id="download-ide-button"
@@ -221,6 +221,10 @@
<li>Template-based wizards to create common Android designs and components.</li>
<li>A rich layout editor that allows you to drag-and-drop UI components, preview layouts on
multiple screen configurations, and much more.</li>
+ <li>Built-in support for <a
+ href="http://android-developers.blogspot.com/2013/06/adding-backend-to-your-app-in-android.html"
+ class="external-link">Google Cloud Platform</a>, making it easy to integrate Google Cloud
+ Messaging and App Engine as server-side components.
</ul>
<p class="caution"><strong>Caution:</strong> Android Studio is currently available as
diff --git a/graphics/java/android/graphics/BitmapFactory.java b/graphics/java/android/graphics/BitmapFactory.java
index c8ace44..a7c5b20 100644
--- a/graphics/java/android/graphics/BitmapFactory.java
+++ b/graphics/java/android/graphics/BitmapFactory.java
@@ -553,6 +553,11 @@
* @return The decoded bitmap, or null if the image data could not be
* decoded, or, if opts is non-null, if opts requested only the
* size be returned (in opts.outWidth and opts.outHeight)
+ *
+ * <p class="note">Prior to {@link android.os.Build.VERSION_CODES#KITKAT},
+ * if {@link InputStream#markSupported is.markSupported()} returns true,
+ * <code>is.mark(1024)</code> would be called. As of
+ * {@link android.os.Build.VERSION_CODES#KITKAT}, this is no longer the case.</p>
*/
public static Bitmap decodeStream(InputStream is, Rect outPadding, Options opts) {
// we don't throw in this case, thus allowing the caller to only check
diff --git a/graphics/java/android/graphics/BitmapRegionDecoder.java b/graphics/java/android/graphics/BitmapRegionDecoder.java
index 3524b25..3a99977 100644
--- a/graphics/java/android/graphics/BitmapRegionDecoder.java
+++ b/graphics/java/android/graphics/BitmapRegionDecoder.java
@@ -104,6 +104,11 @@
* allowing sharing may degrade the decoding speed.
* @return BitmapRegionDecoder, or null if the image data could not be decoded.
* @throws IOException if the image format is not supported or can not be decoded.
+ *
+ * <p class="note">Prior to {@link android.os.Build.VERSION_CODES#KITKAT},
+ * if {@link InputStream#markSupported is.markSupported()} returns true,
+ * <code>is.mark(1024)</code> would be called. As of
+ * {@link android.os.Build.VERSION_CODES#KITKAT}, this is no longer the case.</p>
*/
public static BitmapRegionDecoder newInstance(InputStream is,
boolean isShareable) throws IOException {
diff --git a/libs/hwui/Extensions.h b/libs/hwui/Extensions.h
index 5e574a6..25d4c5e 100644
--- a/libs/hwui/Extensions.h
+++ b/libs/hwui/Extensions.h
@@ -41,7 +41,7 @@
inline bool has1BitStencil() const { return mHas1BitStencil; }
inline bool has4BitStencil() const { return mHas4BitStencil; }
inline bool hasNvSystemTime() const { return mHasNvSystemTime; }
-
+ inline bool hasUnpackRowLength() const { return mVersionMajor >= 3; }
inline bool hasPixelBufferObjects() const { return mVersionMajor >= 3; }
inline bool hasOcclusionQueries() const { return mVersionMajor >= 3; }
inline bool hasFloatTextures() const { return mVersionMajor >= 3; }
diff --git a/libs/hwui/TextureCache.cpp b/libs/hwui/TextureCache.cpp
index a63cac6..ed0a79a 100644
--- a/libs/hwui/TextureCache.cpp
+++ b/libs/hwui/TextureCache.cpp
@@ -240,20 +240,20 @@
switch (bitmap->getConfig()) {
case SkBitmap::kA8_Config:
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
- uploadToTexture(resize, GL_ALPHA, bitmap->rowBytesAsPixels(), texture->height,
- GL_UNSIGNED_BYTE, bitmap->getPixels());
+ uploadToTexture(resize, GL_ALPHA, bitmap->rowBytesAsPixels(),
+ texture->width, texture->height, GL_UNSIGNED_BYTE, bitmap->getPixels());
texture->blend = true;
break;
case SkBitmap::kRGB_565_Config:
glPixelStorei(GL_UNPACK_ALIGNMENT, bitmap->bytesPerPixel());
- uploadToTexture(resize, GL_RGB, bitmap->rowBytesAsPixels(), texture->height,
- GL_UNSIGNED_SHORT_5_6_5, bitmap->getPixels());
+ uploadToTexture(resize, GL_RGB, bitmap->rowBytesAsPixels(),
+ texture->width, texture->height, GL_UNSIGNED_SHORT_5_6_5, bitmap->getPixels());
texture->blend = false;
break;
case SkBitmap::kARGB_8888_Config:
glPixelStorei(GL_UNPACK_ALIGNMENT, bitmap->bytesPerPixel());
- uploadToTexture(resize, GL_RGBA, bitmap->rowBytesAsPixels(), texture->height,
- GL_UNSIGNED_BYTE, bitmap->getPixels());
+ uploadToTexture(resize, GL_RGBA, bitmap->rowBytesAsPixels(),
+ texture->width, texture->height, GL_UNSIGNED_BYTE, bitmap->getPixels());
// Do this after calling getPixels() to make sure Skia's deferred
// decoding happened
texture->blend = !bitmap->isOpaque();
@@ -293,17 +293,28 @@
SkCanvas canvas(rgbaBitmap);
canvas.drawBitmap(*bitmap, 0.0f, 0.0f, NULL);
- uploadToTexture(resize, GL_RGBA, rgbaBitmap.rowBytesAsPixels(), height,
+ uploadToTexture(resize, GL_RGBA, rgbaBitmap.rowBytesAsPixels(), width, height,
GL_UNSIGNED_BYTE, rgbaBitmap.getPixels());
}
-void TextureCache::uploadToTexture(bool resize, GLenum format, GLsizei width, GLsizei height,
- GLenum type, const GLvoid * data) {
+void TextureCache::uploadToTexture(bool resize, GLenum format, GLsizei stride,
+ GLsizei width, GLsizei height, GLenum type, const GLvoid * data) {
+ // TODO: With OpenGL ES 2.0 we need to copy the bitmap in a temporary buffer
+ // if the stride doesn't match the width
+ const bool useStride = stride != width && Extensions::getInstance().hasUnpackRowLength();
+ if (useStride) {
+ glPixelStorei(GL_UNPACK_ROW_LENGTH, stride);
+ }
+
if (resize) {
glTexImage2D(GL_TEXTURE_2D, 0, format, width, height, 0, format, type, data);
} else {
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, width, height, format, type, data);
}
+
+ if (useStride) {
+ glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
+ }
}
}; // namespace uirenderer
diff --git a/libs/hwui/TextureCache.h b/libs/hwui/TextureCache.h
index 80bb22e..57fc19a 100644
--- a/libs/hwui/TextureCache.h
+++ b/libs/hwui/TextureCache.h
@@ -125,8 +125,8 @@
void generateTexture(SkBitmap* bitmap, Texture* texture, bool regenerate = false);
void uploadLoFiTexture(bool resize, SkBitmap* bitmap, uint32_t width, uint32_t height);
- void uploadToTexture(bool resize, GLenum format, GLsizei width, GLsizei height,
- GLenum type, const GLvoid * data);
+ void uploadToTexture(bool resize, GLenum format, GLsizei stride,
+ GLsizei width, GLsizei height, GLenum type, const GLvoid * data);
void init();
diff --git a/libs/hwui/font/CacheTexture.cpp b/libs/hwui/font/CacheTexture.cpp
index cbed3e4..d5f38b5 100644
--- a/libs/hwui/font/CacheTexture.cpp
+++ b/libs/hwui/font/CacheTexture.cpp
@@ -119,7 +119,7 @@
// OpenGL ES 3.0+ lets us specify the row length for unpack operations such
// as glTexSubImage2D(). This allows us to upload a sub-rectangle of a texture.
// With OpenGL ES 2.0 we have to upload entire stripes instead.
- mHasES3 = Extensions::getInstance().getMajorGlVersion() >= 3;
+ mHasUnpackRowLength = Extensions::getInstance().hasUnpackRowLength();
}
CacheTexture::~CacheTexture() {
@@ -206,21 +206,21 @@
bool CacheTexture::upload() {
const Rect& dirtyRect = mDirtyRect;
- uint32_t x = mHasES3 ? dirtyRect.left : 0;
+ uint32_t x = mHasUnpackRowLength ? dirtyRect.left : 0;
uint32_t y = dirtyRect.top;
- uint32_t width = mHasES3 ? dirtyRect.getWidth() : mWidth;
+ uint32_t width = mHasUnpackRowLength ? dirtyRect.getWidth() : mWidth;
uint32_t height = dirtyRect.getHeight();
// The unpack row length only needs to be specified when a new
// texture is bound
- if (mHasES3) {
+ if (mHasUnpackRowLength) {
glPixelStorei(GL_UNPACK_ROW_LENGTH, mWidth);
}
mTexture->upload(x, y, width, height);
setDirty(false);
- return mHasES3;
+ return mHasUnpackRowLength;
}
void CacheTexture::setDirty(bool dirty) {
diff --git a/libs/hwui/font/CacheTexture.h b/libs/hwui/font/CacheTexture.h
index 028b611..61b38f8 100644
--- a/libs/hwui/font/CacheTexture.h
+++ b/libs/hwui/font/CacheTexture.h
@@ -190,7 +190,7 @@
uint32_t mMaxQuadCount;
Caches& mCaches;
CacheBlock* mCacheBlocks;
- bool mHasES3;
+ bool mHasUnpackRowLength;
Rect mDirtyRect;
};
diff --git a/media/java/android/media/WebVttRenderer.java b/media/java/android/media/WebVttRenderer.java
index edde68d..4dec081 100644
--- a/media/java/android/media/WebVttRenderer.java
+++ b/media/java/android/media/WebVttRenderer.java
@@ -17,6 +17,7 @@
package android.media;
import android.content.Context;
+import android.text.Layout.Alignment;
import android.text.SpannableStringBuilder;
import android.util.ArrayMap;
import android.util.AttributeSet;
@@ -1583,6 +1584,7 @@
}
final CueLayout cueBox = new CueLayout(getContext(), cue, mCaptionStyle, mFontSize);
+ mRegionCueBoxes.add(cueBox);
addView(cueBox, LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
if (getChildCount() > mRegion.mLines) {
@@ -1696,12 +1698,27 @@
removeAllViews();
+ final int cueAlignment = resolveCueAlignment(getLayoutDirection(), mCue.mAlignment);
+ final Alignment alignment;
+ switch (cueAlignment) {
+ case TextTrackCue.ALIGNMENT_LEFT:
+ alignment = Alignment.ALIGN_LEFT;
+ break;
+ case TextTrackCue.ALIGNMENT_RIGHT:
+ alignment = Alignment.ALIGN_RIGHT;
+ break;
+ case TextTrackCue.ALIGNMENT_MIDDLE:
+ default:
+ alignment = Alignment.ALIGN_CENTER;
+ }
+
final CaptionStyle captionStyle = mCaptionStyle;
final float fontSize = mFontSize;
final TextTrackCueSpan[][] lines = mCue.mLines;
final int lineCount = lines.length;
for (int i = 0; i < lineCount; i++) {
final SpanLayout lineBox = new SpanLayout(getContext(), lines[i]);
+ lineBox.setAlignment(alignment);
lineBox.setCaptionStyle(captionStyle, fontSize);
addView(lineBox, LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/integration/CameraDeviceBinderTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/integration/CameraDeviceBinderTest.java
index 9d8489c..aef61c7 100644
--- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/integration/CameraDeviceBinderTest.java
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/integration/CameraDeviceBinderTest.java
@@ -68,6 +68,7 @@
}
class IsMetadataNotEmpty extends ArgumentMatcher<CameraMetadataNative> {
+ @Override
public boolean matches(Object obj) {
return !((CameraMetadataNative) obj).isEmpty();
}
@@ -273,6 +274,17 @@
}
@SmallTest
+ public void testCameraCharacteristics() throws RemoteException {
+ CameraMetadataNative info = new CameraMetadataNative();
+
+ int status = mUtils.getCameraService().getCameraCharacteristics(mCameraId, /*out*/info);
+ assertEquals(CameraBinderTestUtils.NO_ERROR, status);
+
+ assertFalse(info.isEmpty());
+ assertNotNull(info.get(CameraCharacteristics.SCALER_AVAILABLE_FORMATS));
+ }
+
+ @SmallTest
public void testWaitUntilIdle() throws Exception {
CaptureRequest.Builder builder = createDefaultBuilder(/* needStream */true);
int requestIdStreaming = submitCameraRequest(builder.build(), /* streaming */true);
diff --git a/packages/DocumentsUI/src/com/android/documentsui/DocumentsActivity.java b/packages/DocumentsUI/src/com/android/documentsui/DocumentsActivity.java
index ca9bea4..72fdc57 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/DocumentsActivity.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/DocumentsActivity.java
@@ -1001,7 +1001,7 @@
} else {
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION
| Intent.FLAG_GRANT_WRITE_URI_PERMISSION
- | Intent.FLAG_PERSIST_GRANT_URI_PERMISSION);
+ | Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION);
}
setResult(Activity.RESULT_OK, intent);
diff --git a/packages/DocumentsUI/src/com/android/documentsui/TestActivity.java b/packages/DocumentsUI/src/com/android/documentsui/TestActivity.java
index 1cc35a7..9861399 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/TestActivity.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/TestActivity.java
@@ -209,6 +209,8 @@
if (requestCode == CODE_READ) {
final Uri uri = data != null ? data.getData() : null;
if (uri != null) {
+ getContentResolver()
+ .takePersistableUriPermission(uri, Intent.FLAG_GRANT_READ_URI_PERMISSION);
InputStream is = null;
try {
is = getContentResolver().openInputStream(uri);
@@ -226,6 +228,8 @@
} else if (requestCode == CODE_WRITE) {
final Uri uri = data != null ? data.getData() : null;
if (uri != null) {
+ getContentResolver()
+ .takePersistableUriPermission(uri, Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
OutputStream os = null;
try {
os = getContentResolver().openOutputStream(uri);
diff --git a/packages/Keyguard/res/values/strings.xml b/packages/Keyguard/res/values/strings.xml
index 5cf05f8..89e7240 100644
--- a/packages/Keyguard/res/values/strings.xml
+++ b/packages/Keyguard/res/values/strings.xml
@@ -149,6 +149,20 @@
<!-- Shown on transport control of lockscreen. Pressing button pauses playback -->
<string name="keyguard_accessibility_transport_stop_description">Stop button</string>
+ <!-- Accessibility description for when the device prompts the user to dismiss keyguard
+ in order to complete an action. This will be followed by a message about the current
+ security option (e.g. "Pattern unlock."). [CHAR LIMIT=NONE] -->
+ <string name="keyguard_accessibility_show_bouncer">Unlock to continue</string>
+
+ <!-- Accessibility description for when the bouncer prompt is dismissed. [CHAR LIMIT=NONE] -->
+ <string name="keyguard_accessibility_hide_bouncer">Launch canceled</string>
+
+ <!-- Accessibility description announced when user drags widget over the delete drop target [CHAR LIMIT=NONE] -->
+ <string name="keyguard_accessibility_delete_widget_start">Drop <xliff:g id="widget_index">%1$s</xliff:g> to delete.</string>
+
+ <!-- Accessibility description announced when user drags widget away from delete drop target [CHAR LIMIT=NONE] -->
+ <string name="keyguard_accessibility_delete_widget_end"><xliff:g id="widget_index">%1$s</xliff:g> will not be deleted.</string>
+
<!-- Password keyboard strings. Used by LockScreen and Settings --><skip />
<!-- Label for "switch to symbols" key. Must be short to fit on key! -->
<string name="password_keyboard_label_symbol_key">\?123</string>
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardHostView.java b/packages/Keyguard/src/com/android/keyguard/KeyguardHostView.java
index aa43711..a9e9d3a 100644
--- a/packages/Keyguard/src/com/android/keyguard/KeyguardHostView.java
+++ b/packages/Keyguard/src/com/android/keyguard/KeyguardHostView.java
@@ -24,7 +24,6 @@
import android.app.ActivityManager;
import android.app.ActivityOptions;
import android.app.AlertDialog;
-import android.app.PendingIntent;
import android.app.SearchManager;
import android.app.admin.DevicePolicyManager;
import android.appwidget.AppWidgetHost;
@@ -41,7 +40,6 @@
import android.graphics.Canvas;
import android.graphics.Rect;
import android.media.RemoteControlClient;
-import android.os.Bundle;
import android.os.Looper;
import android.os.Parcel;
import android.os.Parcelable;
@@ -49,11 +47,9 @@
import android.os.UserHandle;
import android.os.UserManager;
import android.provider.Settings;
-import android.telephony.TelephonyManager;
import android.util.AttributeSet;
import android.util.Log;
import android.util.Slog;
-import android.view.KeyEvent;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
@@ -206,6 +202,13 @@
}
}
+ public void announceCurrentSecurityMethod() {
+ View v = (View) getSecurityView(mCurrentSecuritySelection);
+ if (v != null) {
+ v.announceForAccessibility(v.getContentDescription());
+ }
+ }
+
private void getInitialTransportState() {
DisplayClientState dcs = KeyguardUpdateMonitor.getInstance(mContext)
.getCachedDisplayClientState();
@@ -1663,4 +1666,8 @@
mAppWidgetContainer.handleExternalCameraEvent(event);
}
+ public void launchCamera() {
+ mActivityLauncher.launchCamera(getHandler(), null);
+ }
+
}
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardService.java b/packages/Keyguard/src/com/android/keyguard/KeyguardService.java
index 77006c5..d7c5fe2 100644
--- a/packages/Keyguard/src/com/android/keyguard/KeyguardService.java
+++ b/packages/Keyguard/src/com/android/keyguard/KeyguardService.java
@@ -137,6 +137,10 @@
checkPermission();
mKeyguardViewMediator.dispatch(event);
}
+ public void launchCamera() {
+ checkPermission();
+ mKeyguardViewMediator.launchCamera();
+ }
};
}
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardViewManager.java b/packages/Keyguard/src/com/android/keyguard/KeyguardViewManager.java
index 177e0f8..a0e44d7 100644
--- a/packages/Keyguard/src/com/android/keyguard/KeyguardViewManager.java
+++ b/packages/Keyguard/src/com/android/keyguard/KeyguardViewManager.java
@@ -506,4 +506,10 @@
mKeyguardView.dispatch(event);
}
}
+
+ public void launchCamera() {
+ if (mKeyguardView != null) {
+ mKeyguardView.launchCamera();
+ }
+ }
}
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardViewMediator.java b/packages/Keyguard/src/com/android/keyguard/KeyguardViewMediator.java
index 478096c..0606d83 100644
--- a/packages/Keyguard/src/com/android/keyguard/KeyguardViewMediator.java
+++ b/packages/Keyguard/src/com/android/keyguard/KeyguardViewMediator.java
@@ -122,6 +122,7 @@
private static final int KEYGUARD_TIMEOUT = 13;
private static final int SHOW_ASSISTANT = 14;
private static final int DISPATCH_EVENT = 15;
+ private static final int LAUNCH_CAMERA = 16;
/**
* The default amount of time we stay awake (used for all key input)
@@ -1071,6 +1072,9 @@
case DISPATCH_EVENT:
handleDispatchEvent((MotionEvent) msg.obj);
break;
+ case LAUNCH_CAMERA:
+ handleLaunchCamera();
+ break;
}
}
};
@@ -1107,6 +1111,10 @@
sendUserPresentBroadcast();
}
+ protected void handleLaunchCamera() {
+ mKeyguardViewManager.launchCamera();
+ }
+
protected void handleDispatchEvent(MotionEvent event) {
mKeyguardViewManager.dispatch(event);
}
@@ -1341,4 +1349,9 @@
Message msg = mHandler.obtainMessage(DISPATCH_EVENT, event);
mHandler.sendMessage(msg);
}
+
+ public void launchCamera() {
+ Message msg = mHandler.obtainMessage(LAUNCH_CAMERA);
+ mHandler.sendMessage(msg);
+ }
}
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardViewStateManager.java b/packages/Keyguard/src/com/android/keyguard/KeyguardViewStateManager.java
index d9f9471..d1862cd 100644
--- a/packages/Keyguard/src/com/android/keyguard/KeyguardViewStateManager.java
+++ b/packages/Keyguard/src/com/android/keyguard/KeyguardViewStateManager.java
@@ -87,6 +87,11 @@
}
public void showBouncer(boolean show) {
+ CharSequence what = mKeyguardHostView.getContext().getResources().getText(
+ show ? R.string.keyguard_accessibility_show_bouncer
+ : R.string.keyguard_accessibility_hide_bouncer);
+ mKeyguardHostView.announceForAccessibility(what);
+ mKeyguardHostView.announceCurrentSecurityMethod();
mChallengeLayout.showBouncer();
}
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardWidgetFrame.java b/packages/Keyguard/src/com/android/keyguard/KeyguardWidgetFrame.java
index 81f6221..c0586d5 100644
--- a/packages/Keyguard/src/com/android/keyguard/KeyguardWidgetFrame.java
+++ b/packages/Keyguard/src/com/android/keyguard/KeyguardWidgetFrame.java
@@ -147,6 +147,10 @@
if (ENABLE_HOVER_OVER_DELETE_DROP_TARGET_OVERLAY) {
if (mIsHoveringOverDeleteDropTarget != isHovering) {
mIsHoveringOverDeleteDropTarget = isHovering;
+ int resId = isHovering ? R.string.keyguard_accessibility_delete_widget_start
+ : R.string.keyguard_accessibility_delete_widget_end;
+ String text = getContext().getResources().getString(resId, getContentDescription());
+ announceForAccessibility(text);
invalidate();
}
}
@@ -326,7 +330,7 @@
/**
* Depending on whether the security is up, the widget size needs to change
- *
+ *
* @param height The height of the widget, -1 for full height
*/
private void setWidgetHeight(int height) {
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardWidgetPager.java b/packages/Keyguard/src/com/android/keyguard/KeyguardWidgetPager.java
index f7dc058..f8857ab 100644
--- a/packages/Keyguard/src/com/android/keyguard/KeyguardWidgetPager.java
+++ b/packages/Keyguard/src/com/android/keyguard/KeyguardWidgetPager.java
@@ -90,6 +90,7 @@
// Background worker thread: used here for persistence, also made available to widget frames
private final HandlerThread mBackgroundWorkerThread;
private final Handler mBackgroundWorkerHandler;
+ private boolean mCameraEventInProgress;
public KeyguardWidgetPager(Context context, AttributeSet attrs) {
this(context, attrs, 0);
@@ -941,14 +942,18 @@
beginCameraEvent();
int cameraPage = getPageCount() - 1;
boolean endWarp = false;
- if (isCameraPage(cameraPage)) {
+ if (isCameraPage(cameraPage) || mCameraEventInProgress) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
+ // Once we start dispatching camera events, we must continue to do so
+ // to keep event dispatch happy.
+ mCameraEventInProgress = true;
userActivity();
startWarp(cameraPage);
break;
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_CANCEL:
+ mCameraEventInProgress = false;
endWarp = true;
break;
}
diff --git a/packages/Keyguard/src/com/android/keyguard/PagedView.java b/packages/Keyguard/src/com/android/keyguard/PagedView.java
index b6279d0..666227c 100644
--- a/packages/Keyguard/src/com/android/keyguard/PagedView.java
+++ b/packages/Keyguard/src/com/android/keyguard/PagedView.java
@@ -125,6 +125,7 @@
private int[] mChildOffsets;
private int[] mChildRelativeOffsets;
private int[] mChildOffsetsWithLayoutScale;
+ private String mDeleteString; // Accessibility announcement when widget is deleted
protected final static int TOUCH_STATE_REST = 0;
protected final static int TOUCH_STATE_SCROLLING = 1;
@@ -1118,6 +1119,8 @@
// i.e. fall through to the next case (don't break)
// (We sometimes miss ACTION_DOWN events in Workspace because it ignores all events
// while it's small- this was causing a crash before we checked for INVALID_POINTER)
+
+ break;
}
case MotionEvent.ACTION_DOWN: {
@@ -2194,8 +2197,13 @@
protected void onEndReordering() {
if (AccessibilityManager.getInstance(mContext).isEnabled()) {
- announceForAccessibility(mContext.getString(
- R.string.keyguard_accessibility_widget_reorder_end));
+ if (mDeleteString != null) {
+ announceForAccessibility(mDeleteString);
+ mDeleteString = null;
+ } else {
+ announceForAccessibility(mContext.getString(
+ R.string.keyguard_accessibility_widget_reorder_end));
+ }
}
mIsReordering = false;
@@ -2507,6 +2515,9 @@
AnimatorUpdateListener updateCb = new FlingAlongVectorAnimatorUpdateListener(dragView, vel,
from, startTime, FLING_TO_DELETE_FRICTION);
+ mDeleteString = getContext().getResources()
+ .getString(R.string.keyguard_accessibility_widget_deleted,
+ mDragView.getContentDescription());
final Runnable onAnimationEndRunnable = createPostDeleteAnimationRunnable(dragView);
// Create and start the animation
@@ -2562,6 +2573,9 @@
ObjectAnimator.ofFloat(dragView, "alpha", toAlpha));
animations.add(alphaAnim);
+ mDeleteString = getContext().getResources()
+ .getString(R.string.keyguard_accessibility_widget_deleted,
+ mDragView.getContentDescription());
final Runnable onAnimationEndRunnable = createPostDeleteAnimationRunnable(dragView);
AnimatorSet anim = new AnimatorSet();
diff --git a/packages/SystemUI/res/drawable-hdpi/recents_thumbnail_bg_press.9.png b/packages/SystemUI/res/drawable-hdpi/recents_thumbnail_bg_press.9.png
index e591a7b..cbcb3e3 100644
--- a/packages/SystemUI/res/drawable-hdpi/recents_thumbnail_bg_press.9.png
+++ b/packages/SystemUI/res/drawable-hdpi/recents_thumbnail_bg_press.9.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/recents_thumbnail_bg_press.9.png b/packages/SystemUI/res/drawable-mdpi/recents_thumbnail_bg_press.9.png
index 7dfea4c..3ac7c40 100644
--- a/packages/SystemUI/res/drawable-mdpi/recents_thumbnail_bg_press.9.png
+++ b/packages/SystemUI/res/drawable-mdpi/recents_thumbnail_bg_press.9.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/recents_thumbnail_bg_press.9.png b/packages/SystemUI/res/drawable-xhdpi/recents_thumbnail_bg_press.9.png
index f01a79e..78a69f5 100644
--- a/packages/SystemUI/res/drawable-xhdpi/recents_thumbnail_bg_press.9.png
+++ b/packages/SystemUI/res/drawable-xhdpi/recents_thumbnail_bg_press.9.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/recents_thumbnail_bg_press.9.png b/packages/SystemUI/res/drawable-xxhdpi/recents_thumbnail_bg_press.9.png
index b7bbd82..1fa1e62 100644
--- a/packages/SystemUI/res/drawable-xxhdpi/recents_thumbnail_bg_press.9.png
+++ b/packages/SystemUI/res/drawable-xxhdpi/recents_thumbnail_bg_press.9.png
Binary files differ
diff --git a/packages/SystemUI/res/layout-ldrtl/navigation_bar.xml b/packages/SystemUI/res/layout-ldrtl/navigation_bar.xml
index 765b274..aa7256b 100644
--- a/packages/SystemUI/res/layout-ldrtl/navigation_bar.xml
+++ b/packages/SystemUI/res/layout-ldrtl/navigation_bar.xml
@@ -153,6 +153,7 @@
android:src="@drawable/search_light"
android:scaleType="center"
android:visibility="gone"
+ android:contentDescription="@string/accessibility_search_light"
/>
<com.android.systemui.statusbar.policy.DeadZone
@@ -297,6 +298,7 @@
android:src="@drawable/search_light"
android:scaleType="center"
android:visibility="gone"
+ android:contentDescription="@string/accessibility_search_light"
/>
<com.android.systemui.statusbar.policy.DeadZone
diff --git a/packages/SystemUI/res/layout-sw600dp/navigation_bar.xml b/packages/SystemUI/res/layout-sw600dp/navigation_bar.xml
index 9592b18..b9ad799 100644
--- a/packages/SystemUI/res/layout-sw600dp/navigation_bar.xml
+++ b/packages/SystemUI/res/layout-sw600dp/navigation_bar.xml
@@ -149,6 +149,7 @@
android:src="@drawable/search_light"
android:scaleType="center"
android:visibility="gone"
+ android:contentDescription="@string/accessibility_search_light"
/>
<com.android.systemui.statusbar.policy.DeadZone
@@ -290,6 +291,7 @@
android:src="@drawable/search_light"
android:scaleType="center"
android:visibility="gone"
+ android:contentDescription="@string/accessibility_search_light"
/>
<com.android.systemui.statusbar.policy.DeadZone
diff --git a/packages/SystemUI/res/layout/navigation_bar.xml b/packages/SystemUI/res/layout/navigation_bar.xml
index 11cbbc7..aa365ae 100644
--- a/packages/SystemUI/res/layout/navigation_bar.xml
+++ b/packages/SystemUI/res/layout/navigation_bar.xml
@@ -157,6 +157,7 @@
android:src="@drawable/search_light"
android:scaleType="center"
android:visibility="gone"
+ android:contentDescription="@string/accessibility_search_light"
/>
<com.android.systemui.statusbar.policy.KeyButtonView
@@ -167,6 +168,7 @@
android:src="@drawable/ic_sysbar_camera"
android:scaleType="center"
android:visibility="gone"
+ android:contentDescription="@string/accessibility_camera_button"
/>
</FrameLayout>
@@ -312,6 +314,7 @@
android:src="@drawable/search_light"
android:scaleType="center"
android:visibility="gone"
+ android:contentDescription="@string/accessibility_search_light"
/>
<!-- No camera button in landscape mode -->
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index eb425e6..58865ab 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -192,6 +192,10 @@
<string name="accessibility_menu">Menu</string>
<!-- Content description of the recents button for accessibility (not shown on the screen). [CHAR LIMIT=NONE] -->
<string name="accessibility_recent">Recent apps</string>
+ <!-- Content description of the search button for accessibility. [CHAR LIMIT=NONE] -->
+ <string name="accessibility_search_light">Search</string>
+ <!-- Content description of the camera button for accessibility (not shown on the screen). [CHAR LIMIT=NONE] -->
+ <string name="accessibility_camera_button">Camera</string>
<!-- Content description of the switch input method button for accessibility (not shown on the screen). [CHAR LIMIT=NONE] -->
<string name="accessibility_ime_switch_button">Switch input method button.</string>
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/DelegateViewHelper.java b/packages/SystemUI/src/com/android/systemui/statusbar/DelegateViewHelper.java
index 3a5524d..3a82753 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/DelegateViewHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/DelegateViewHelper.java
@@ -50,8 +50,7 @@
}
public boolean onInterceptTouchEvent(MotionEvent event) {
- if (mSourceView == null || mDelegateView == null || mDisabled
- || mBar.shouldDisableNavbarGestures()) {
+ if (mSourceView == null || mDelegateView == null || mBar.shouldDisableNavbarGestures()) {
return false;
}
@@ -73,7 +72,7 @@
return false;
}
- if (!mPanelShowing && action == MotionEvent.ACTION_MOVE) {
+ if (!mDisabled && !mPanelShowing && action == MotionEvent.ACTION_MOVE) {
final int historySize = event.getHistorySize();
for (int k = 0; k < historySize + 1; k++) {
float x = k < historySize ? event.getHistoricalX(k) : event.getX();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardTouchDelegate.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardTouchDelegate.java
index a6e2347..1221a55 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardTouchDelegate.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardTouchDelegate.java
@@ -103,4 +103,30 @@
return false;
}
+ public void showAssistant() {
+ if (mService != null) {
+ try {
+ mService.showAssistant();
+ } catch (RemoteException e) {
+ // What to do?
+ Log.e(TAG, "RemoteException launching assistant!", e);
+ }
+ } else {
+ Log.w(TAG, "dispatch(event): NO SERVICE!");
+ }
+ }
+
+ public void launchCamera() {
+ if (mService != null) {
+ try {
+ mService.launchCamera();
+ } catch (RemoteException e) {
+ // What to do?
+ Log.e(TAG, "RemoteException launching camera!", e);
+ }
+ } else {
+ Log.w(TAG, "dispatch(event): NO SERVICE!");
+ }
+ }
+
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
index 24e27b1..596fac6 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
@@ -37,8 +37,10 @@
import android.view.MotionEvent;
import android.view.Surface;
import android.view.View;
+import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.view.WindowManager;
+import android.view.accessibility.AccessibilityManager;
import android.widget.ImageView;
import android.widget.LinearLayout;
@@ -86,7 +88,7 @@
// used to disable the camera icon in navbar when disabled by DPM
private boolean mCameraDisabledByDpm;
- KeyguardTouchDelegate mTouchDelegate;
+ KeyguardTouchDelegate mKeyguardTouchDelegate;
private final OnTouchListener mCameraTouchListener = new OnTouchListener() {
@Override
@@ -110,7 +112,7 @@
}
break;
}
- return mTouchDelegate.dispatch(event);
+ return mKeyguardTouchDelegate.dispatch(event);
}
};
@@ -153,7 +155,7 @@
mBarTransitions = new NavigationBarTransitions(this);
- mTouchDelegate = new KeyguardTouchDelegate(mContext);
+ mKeyguardTouchDelegate = new KeyguardTouchDelegate(mContext);
mCameraDisabledByDpm = isCameraDisabledByDpm();
watchForDevicePolicyChanges();
@@ -339,7 +341,7 @@
final int disabledFlags = dpm.getKeyguardDisabledFeatures(null, userId);
final boolean disabledBecauseKeyguardSecure =
(disabledFlags & DevicePolicyManager.KEYGUARD_DISABLE_SECURE_CAMERA) != 0
- && mTouchDelegate.isSecure();
+ && mKeyguardTouchDelegate.isSecure();
return dpm.getCameraDisabled(null) || disabledBecauseKeyguardSecure;
} catch (RemoteException e) {
Log.e(TAG, "Can't get userId", e);
@@ -389,12 +391,44 @@
mCurrentView = mRotatedViews[Surface.ROTATION_0];
- // Add a touch handler for camera icon for all view orientations.
- for (int i = 0; i < mRotatedViews.length; i++) {
- View cameraButton = mRotatedViews[i].findViewById(R.id.camera_button);
- if (cameraButton != null) {
- cameraButton.setOnTouchListener(mCameraTouchListener);
+
+ final AccessibilityManager accessibilityManager =
+ (AccessibilityManager) mContext.getSystemService(Context.ACCESSIBILITY_SERVICE);
+ if (accessibilityManager.isEnabled()) {
+ // In accessibility mode, we add a simple click handler since swipe is tough to
+ // trigger near screen edges.
+ View camera = getCameraButton();
+ View searchLight = getSearchLight();
+ if (camera != null || searchLight != null) {
+ OnClickListener listener = new OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ launchForAccessibilityClick(v);
+ }
+ };
+ if (camera != null) {
+ camera.setOnClickListener(listener);
+ }
+ if (searchLight != null) {
+ searchLight.setOnClickListener(listener);
+ }
}
+ } else {
+ // Add a touch handler for camera icon for all view orientations.
+ for (int i = 0; i < mRotatedViews.length; i++) {
+ View cameraButton = mRotatedViews[i].findViewById(R.id.camera_button);
+ if (cameraButton != null) {
+ cameraButton.setOnTouchListener(mCameraTouchListener);
+ }
+ }
+ }
+ }
+
+ protected void launchForAccessibilityClick(View v) {
+ if (v == getCameraButton()) {
+ mKeyguardTouchDelegate.launchCamera();
+ } else if (v == getSearchLight()) {
+ mKeyguardTouchDelegate.showAssistant();
}
}
diff --git a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardServiceWrapper.java b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardServiceWrapper.java
index b27584d..5e299ee 100644
--- a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardServiceWrapper.java
+++ b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardServiceWrapper.java
@@ -192,6 +192,10 @@
// Not used by PhoneWindowManager. See code in {@link NavigationBarView}
}
+ public void launchCamera() {
+ // Not used by PhoneWindowManager. See code in {@link NavigationBarView}
+ }
+
@Override
public IBinder asBinder() {
return mService.asBinder();
diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java
index 4f73588..3c11933 100644
--- a/services/java/com/android/server/am/ActivityManagerService.java
+++ b/services/java/com/android/server/am/ActivityManagerService.java
@@ -18,7 +18,9 @@
import static android.content.pm.PackageManager.PERMISSION_GRANTED;
import static com.android.internal.util.XmlUtils.readIntAttribute;
+import static com.android.internal.util.XmlUtils.readLongAttribute;
import static com.android.internal.util.XmlUtils.writeIntAttribute;
+import static com.android.internal.util.XmlUtils.writeLongAttribute;
import static org.xmlpull.v1.XmlPullParser.END_DOCUMENT;
import static org.xmlpull.v1.XmlPullParser.START_TAG;
@@ -36,7 +38,6 @@
import com.android.internal.os.BatteryStatsImpl;
import com.android.internal.os.ProcessCpuTracker;
import com.android.internal.os.TransferPipe;
-import com.android.internal.util.ArrayUtils;
import com.android.internal.util.FastPrintWriter;
import com.android.internal.util.FastXmlSerializer;
import com.android.internal.util.MemInfoReader;
@@ -113,6 +114,7 @@
import android.content.pm.InstrumentationInfo;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
+import android.content.pm.ParceledListSlice;
import android.content.pm.UserInfo;
import android.content.pm.PackageManager.NameNotFoundException;
import android.content.pm.PathPermission;
@@ -153,6 +155,7 @@
import android.os.UpdateLock;
import android.os.UserHandle;
import android.provider.Settings;
+import android.text.format.DateUtils;
import android.text.format.Time;
import android.util.AtomicFile;
import android.util.EventLog;
@@ -310,6 +313,9 @@
// to respond with the result.
static final int PENDING_ASSIST_EXTRAS_TIMEOUT = 500;
+ // Maximum number of persisted Uri grants a package is allowed
+ static final int MAX_PERSISTED_URI_GRANTS = 128;
+
static final int MY_PID = Process.myPid();
static final String[] EMPTY_STRING_ARRAY = new String[0];
@@ -504,6 +510,12 @@
int mLruProcessActivityStart = 0;
/**
+ * Where in mLruProcesses that the processes hosting services start.
+ * This is after (lower index) than mLruProcessesActivityStart.
+ */
+ int mLruProcessServiceStart = 0;
+
+ /**
* List of processes that should gc as soon as things are idle.
*/
final ArrayList<ProcessRecord> mProcessesToGc = new ArrayList<ProcessRecord>();
@@ -685,6 +697,7 @@
private static final String ATTR_TARGET_PKG = "targetPkg";
private static final String ATTR_URI = "uri";
private static final String ATTR_MODE_FLAGS = "modeFlags";
+ private static final String ATTR_CREATED_TIME = "createdTime";
/**
* Global set of specific {@link Uri} permissions that have been granted.
@@ -853,6 +866,7 @@
* determine on the next iteration which should be B services.
*/
int mNumServiceProcs = 0;
+ int mNewNumAServiceProcs = 0;
int mNewNumServiceProcs = 0;
/**
@@ -1540,7 +1554,15 @@
logBuilder.append(infos[Debug.MEMINFO_BUFFERS]).append(" kB buffers, ");
logBuilder.append(infos[Debug.MEMINFO_CACHED]).append(" kB cached, ");
logBuilder.append(infos[Debug.MEMINFO_FREE]).append(" kB free\n");
-
+ if (infos[Debug.MEMINFO_ZRAM_TOTAL] != 0) {
+ logBuilder.append(" ZRAM: ");
+ logBuilder.append(infos[Debug.MEMINFO_ZRAM_TOTAL]);
+ logBuilder.append(" kB RAM, ");
+ logBuilder.append(infos[Debug.MEMINFO_SWAP_TOTAL]);
+ logBuilder.append(" kB swap total, ");
+ logBuilder.append(infos[Debug.MEMINFO_SWAP_FREE]);
+ logBuilder.append(" kB swap free\n");
+ }
Slog.i(TAG, logBuilder.toString());
StringBuilder dropBuilder = new StringBuilder(1024);
@@ -2250,6 +2272,12 @@
return index;
}
+ if (lrui >= index) {
+ // Don't want to cause this to move dependent processes *back* in the
+ // list as if they were less frequently used.
+ return index;
+ }
+
if (lrui >= mLruProcessActivityStart) {
// Don't want to touch dependent processes that are hosting activities.
return index;
@@ -2269,12 +2297,16 @@
if (lrui <= mLruProcessActivityStart) {
mLruProcessActivityStart--;
}
+ if (lrui <= mLruProcessServiceStart) {
+ mLruProcessServiceStart--;
+ }
mLruProcesses.remove(lrui);
}
}
final void updateLruProcessLocked(ProcessRecord app, boolean oomAdj, boolean activityChange) {
final boolean hasActivity = app.activities.size() > 0;
+ final boolean hasService = false; // not impl yet. app.services.size() > 0;
if (!activityChange && hasActivity) {
// The process has activties, so we are only going to allow activity-based
// adjustments move it. It should be kept in the front of the list with other
@@ -2293,19 +2325,28 @@
if (lrui < mLruProcessActivityStart) {
mLruProcessActivityStart--;
}
+ if (lrui < mLruProcessServiceStart) {
+ mLruProcessServiceStart--;
+ }
mLruProcesses.remove(lrui);
}
int nextIndex;
- if (!hasActivity) {
- // Process doesn't have activities, it goes to the top of the non-activity area.
- mLruProcesses.add(mLruProcessActivityStart, app);
- nextIndex = mLruProcessActivityStart-1;
- mLruProcessActivityStart++;
- } else {
- // Process does have activities, put it at the very tipsy-top.
+ if (hasActivity) {
+ // Process has activities, put it at the very tipsy-top.
mLruProcesses.add(app);
nextIndex = mLruProcessActivityStart;
+ } else if (hasService) {
+ // Process has services, put it at the top of the service list.
+ mLruProcesses.add(mLruProcessActivityStart, app);
+ nextIndex = mLruProcessServiceStart;
+ mLruProcessActivityStart++;
+ } else {
+ // Process not otherwise of interest, it goes to the top of the non-service area.
+ mLruProcesses.add(mLruProcessServiceStart, app);
+ nextIndex = mLruProcessServiceStart-1;
+ mLruProcessActivityStart++;
+ mLruProcessServiceStart++;
}
// If the app is currently using a content provider or service,
@@ -2359,7 +2400,7 @@
&& mLastMemoryLevel > ProcessStats.ADJ_MEM_FACTOR_NORMAL
&& proc.setProcState >= ActivityManager.PROCESS_STATE_CACHED_EMPTY) {
if (DEBUG_PSS) Slog.d(TAG, "May not keep " + proc + ": pss=" + proc.lastCachedPss);
- if (proc.lastCachedPss >= mProcessList.getCachedRestoreThreshold()) {
+ if (proc.lastCachedPss >= mProcessList.getCachedRestoreThresholdKb()) {
if (proc.baseProcessTracker != null) {
proc.baseProcessTracker.reportCachedKill(proc.pkgList, proc.lastCachedPss);
}
@@ -5669,6 +5710,15 @@
return pi;
}
+ private UriPermission findUriPermissionLocked(int targetUid, Uri uri) {
+ ArrayMap<Uri, UriPermission> targetUris = mGrantedUriPermissions.get(targetUid);
+ if (targetUris != null) {
+ return targetUris.get(uri);
+ } else {
+ return null;
+ }
+ }
+
private UriPermission findOrCreateUriPermissionLocked(
String sourcePkg, String targetPkg, int targetUid, Uri uri) {
ArrayMap<Uri, UriPermission> targetUris = mGrantedUriPermissions.get(targetUid);
@@ -5686,8 +5736,8 @@
return perm;
}
- private final boolean checkUriPermissionLocked(Uri uri, int uid,
- int modeFlags) {
+ private final boolean checkUriPermissionLocked(
+ Uri uri, int uid, int modeFlags, int minStrength) {
// Root gets to do everything.
if (uid == 0) {
return true;
@@ -5696,7 +5746,7 @@
if (perms == null) return false;
UriPermission perm = perms.get(uri);
if (perm == null) return false;
- return (modeFlags&perm.modeFlags) == modeFlags;
+ return perm.getStrength(modeFlags) >= minStrength;
}
@Override
@@ -5716,7 +5766,7 @@
return PackageManager.PERMISSION_GRANTED;
}
synchronized(this) {
- return checkUriPermissionLocked(uri, uid, modeFlags)
+ return checkUriPermissionLocked(uri, uid, modeFlags, UriPermission.STRENGTH_OWNED)
? PackageManager.PERMISSION_GRANTED
: PackageManager.PERMISSION_DENIED;
}
@@ -5733,7 +5783,7 @@
*/
int checkGrantUriPermissionLocked(int callingUid, String targetPkg,
Uri uri, int modeFlags, int lastTargetUid) {
- final boolean persist = (modeFlags & Intent.FLAG_PERSIST_GRANT_URI_PERMISSION) != 0;
+ final boolean persistable = (modeFlags & Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION) != 0;
modeFlags &= (Intent.FLAG_GRANT_READ_URI_PERMISSION
| Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
if (modeFlags == 0) {
@@ -5777,7 +5827,7 @@
if (targetUid >= 0) {
// First... does the target actually need this permission?
- if (checkHoldingPermissionsLocked(pm, pi, uri, targetUid, modeFlags) && !persist) {
+ if (checkHoldingPermissionsLocked(pm, pi, uri, targetUid, modeFlags)) {
// No need to grant the target this permission.
if (DEBUG_URI_PERMISSION) Slog.v(TAG,
"Target " + targetPkg + " already has full permission to " + uri);
@@ -5796,7 +5846,7 @@
allowed = false;
}
}
- if (allowed && !persist) {
+ if (allowed) {
return -1;
}
}
@@ -5830,7 +5880,10 @@
// this uri?
if (callingUid != Process.myUid()) {
if (!checkHoldingPermissionsLocked(pm, pi, uri, callingUid, modeFlags)) {
- if (!checkUriPermissionLocked(uri, callingUid, modeFlags)) {
+ // Require they hold a strong enough Uri permission
+ final int minStrength = persistable ? UriPermission.STRENGTH_PERSISTABLE
+ : UriPermission.STRENGTH_OWNED;
+ if (!checkUriPermissionLocked(uri, callingUid, modeFlags, minStrength)) {
throw new SecurityException("Uid " + callingUid
+ " does not have permission to uri " + uri);
}
@@ -5851,7 +5904,7 @@
void grantUriPermissionUncheckedLocked(
int targetUid, String targetPkg, Uri uri, int modeFlags, UriPermissionOwner owner) {
- final boolean persist = (modeFlags & Intent.FLAG_PERSIST_GRANT_URI_PERMISSION) != 0;
+ final boolean persistable = (modeFlags & Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION) != 0;
modeFlags &= (Intent.FLAG_GRANT_READ_URI_PERMISSION
| Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
if (modeFlags == 0) {
@@ -5874,11 +5927,7 @@
final UriPermission perm = findOrCreateUriPermissionLocked(
pi.packageName, targetPkg, targetUid, uri);
- final boolean persistChanged = perm.grantModes(modeFlags, persist, owner);
- if (persistChanged) {
- mHandler.removeMessages(PERSIST_URI_GRANTS_MSG);
- mHandler.obtainMessage(PERSIST_URI_GRANTS_MSG).sendToTarget();
- }
+ perm.grantModes(modeFlags, persistable, owner);
}
void grantUriPermissionLocked(int callingUid, String targetPkg, Uri uri,
@@ -5930,6 +5979,7 @@
if (data == null && clip == null) {
return null;
}
+
if (data != null) {
int targetUid = checkGrantUriPermissionLocked(callingUid, targetPkg, data,
mode, needed != null ? needed.targetUid : -1);
@@ -6011,6 +6061,14 @@
throw new IllegalArgumentException("null uri");
}
+ // Persistable only supported through Intents
+ modeFlags &= (Intent.FLAG_GRANT_READ_URI_PERMISSION
+ | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
+ if (modeFlags == 0) {
+ throw new IllegalArgumentException("Mode flags must be "
+ + "FLAG_GRANT_READ_URI_PERMISSION and/or FLAG_GRANT_WRITE_URI_PERMISSION");
+ }
+
grantUriPermissionLocked(r.uid, targetPkg, uri, modeFlags,
null);
}
@@ -6032,8 +6090,7 @@
}
}
- private void revokeUriPermissionLocked(
- int callingUid, Uri uri, int modeFlags, boolean persist) {
+ private void revokeUriPermissionLocked(int callingUid, Uri uri, int modeFlags) {
if (DEBUG_URI_PERMISSION) Slog.v(TAG, "Revoking all granted permissions to " + uri);
final IPackageManager pm = AppGlobals.getPackageManager();
@@ -6086,7 +6143,7 @@
}
if (DEBUG_URI_PERMISSION) Slog.v(TAG,
"Revoking " + perm.targetUid + " permission to " + perm.uri);
- persistChanged |= perm.clearModes(modeFlags, persist);
+ persistChanged |= perm.clearModes(modeFlags, true);
if (perm.modeFlags == 0) {
it.remove();
}
@@ -6101,8 +6158,7 @@
}
if (persistChanged) {
- mHandler.removeMessages(PERSIST_URI_GRANTS_MSG);
- mHandler.obtainMessage(PERSIST_URI_GRANTS_MSG).sendToTarget();
+ schedulePersistUriGrants();
}
}
@@ -6122,7 +6178,6 @@
return;
}
- final boolean persist = (modeFlags & Intent.FLAG_PERSIST_GRANT_URI_PERMISSION) != 0;
modeFlags &= (Intent.FLAG_GRANT_READ_URI_PERMISSION
| Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
if (modeFlags == 0) {
@@ -6138,7 +6193,7 @@
return;
}
- revokeUriPermissionLocked(r.uid, uri, modeFlags, persist);
+ revokeUriPermissionLocked(r.uid, uri, modeFlags);
}
}
@@ -6150,10 +6205,10 @@
* packages.
* @param userHandle User to match, or {@link UserHandle#USER_ALL} to apply
* to all users.
- * @param persist If persistent grants should be removed.
+ * @param persistable If persistable grants should be removed.
*/
private void removeUriPermissionsForPackageLocked(
- String packageName, int userHandle, boolean persist) {
+ String packageName, int userHandle, boolean persistable) {
if (userHandle == UserHandle.USER_ALL && packageName == null) {
throw new IllegalArgumentException("Must narrow by either package or user");
}
@@ -6173,7 +6228,7 @@
// Only inspect grants matching package
if (packageName == null || perm.sourcePkg.equals(packageName)
|| perm.targetPkg.equals(packageName)) {
- persistChanged |= perm.clearModes(~0, persist);
+ persistChanged |= perm.clearModes(~0, persistable);
// Only remove when no modes remain; any persisted grants
// will keep this alive.
@@ -6186,8 +6241,7 @@
}
if (persistChanged) {
- mHandler.removeMessages(PERSIST_URI_GRANTS_MSG);
- mHandler.obtainMessage(PERSIST_URI_GRANTS_MSG).sendToTarget();
+ schedulePersistUriGrants();
}
}
@@ -6242,6 +6296,13 @@
}
}
+ private void schedulePersistUriGrants() {
+ if (!mHandler.hasMessages(PERSIST_URI_GRANTS_MSG)) {
+ mHandler.sendMessageDelayed(mHandler.obtainMessage(PERSIST_URI_GRANTS_MSG),
+ 10 * DateUtils.SECOND_IN_MILLIS);
+ }
+ }
+
private void writeGrantedUriPermissions() {
if (DEBUG_URI_PERMISSION) Slog.v(TAG, "writeGrantedUriPermissions()");
@@ -6273,6 +6334,7 @@
out.attribute(null, ATTR_TARGET_PKG, perm.targetPkg);
out.attribute(null, ATTR_URI, String.valueOf(perm.uri));
writeIntAttribute(out, ATTR_MODE_FLAGS, perm.persistedModeFlags);
+ writeLongAttribute(out, ATTR_CREATED_TIME, perm.persistedCreateTime);
out.endTag(null, TAG_URI_GRANT);
}
out.endTag(null, TAG_URI_GRANTS);
@@ -6289,6 +6351,8 @@
private void readGrantedUriPermissionsLocked() {
if (DEBUG_URI_PERMISSION) Slog.v(TAG, "readGrantedUriPermissions()");
+ final long now = System.currentTimeMillis();
+
FileInputStream fis = null;
try {
fis = mGrantFile.openRead();
@@ -6305,6 +6369,7 @@
final String targetPkg = in.getAttributeValue(null, ATTR_TARGET_PKG);
final Uri uri = Uri.parse(in.getAttributeValue(null, ATTR_URI));
final int modeFlags = readIntAttribute(in, ATTR_MODE_FLAGS);
+ final long createdTime = readLongAttribute(in, ATTR_CREATED_TIME, now);
// Sanity check that provider still belongs to source package
final ProviderInfo pi = getProviderInfoLocked(
@@ -6319,7 +6384,7 @@
if (targetUid != -1) {
final UriPermission perm = findOrCreateUriPermissionLocked(
sourcePkg, targetPkg, targetUid, uri);
- perm.grantModes(modeFlags, true, null);
+ perm.initPersistedModes(modeFlags, createdTime);
}
} else {
Slog.w(TAG, "Persisted grant for " + uri + " had source " + sourcePkg
@@ -6340,47 +6405,117 @@
}
@Override
- public Uri[] getGrantedUriPermissions(
- String sourcePackage, String targetPackage, int modeFlags, int modeMask) {
- enforceNotIsolatedCaller("getGrantedUriPermissions");
+ public void takePersistableUriPermission(Uri uri, int modeFlags) {
+ enforceNotIsolatedCaller("takePersistableUriPermission");
+
+ modeFlags &= (Intent.FLAG_GRANT_READ_URI_PERMISSION
+ | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
+ if (modeFlags == 0) {
+ return;
+ }
+
synchronized (this) {
- // Verify that caller owns at least one of the requested packages
- final int uid = Binder.getCallingUid();
- final IPackageManager pm = AppGlobals.getPackageManager();
- final String[] callerPackages;
- try {
- callerPackages = pm.getPackagesForUid(uid);
- } catch (RemoteException e) {
- throw new SecurityException("Failed to find packages for UID " + uid);
- }
- final boolean callerOwnsSource = sourcePackage != null
- && ArrayUtils.contains(callerPackages, sourcePackage);
- final boolean callerOwnsTarget = targetPackage != null
- && ArrayUtils.contains(callerPackages, targetPackage);
- if (!(callerOwnsSource || callerOwnsTarget)) {
- throw new SecurityException("Caller " + Arrays.toString(callerPackages)
- + " doesn't own " + sourcePackage + " or " + targetPackage);
+ final int callingUid = Binder.getCallingUid();
+ final UriPermission perm = findUriPermissionLocked(callingUid, uri);
+ if (perm == null) {
+ Slog.w(TAG, "No permission grant found for UID " + callingUid + " and Uri "
+ + uri.toSafeString());
+ return;
}
- final ArrayList<Uri> result = Lists.newArrayList();
- final int size = mGrantedUriPermissions.size();
- for (int i = 0; i < size; i++) {
- final ArrayMap<Uri, UriPermission> map = mGrantedUriPermissions.valueAt(i);
- final int mapSize = map.size();
- for (int j = 0; j < mapSize; j++) {
- final UriPermission perm = map.valueAt(j);
- final boolean sourceMatch = sourcePackage == null
- || sourcePackage.equals(perm.sourcePkg);
- final boolean targetMatch = targetPackage == null
- || targetPackage.equals(perm.targetPkg);
- final boolean modeMatch = (perm.modeFlags & modeMask) == modeFlags;
- if (sourceMatch && targetMatch && modeMatch) {
- result.add(perm.uri);
+ boolean persistChanged = perm.takePersistableModes(modeFlags);
+ persistChanged |= maybePrunePersistedUriGrantsLocked(callingUid);
+
+ if (persistChanged) {
+ schedulePersistUriGrants();
+ }
+ }
+ }
+
+ @Override
+ public void releasePersistableUriPermission(Uri uri, int modeFlags) {
+ enforceNotIsolatedCaller("releasePersistableUriPermission");
+
+ modeFlags &= (Intent.FLAG_GRANT_READ_URI_PERMISSION
+ | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
+ if (modeFlags == 0) {
+ return;
+ }
+
+ synchronized (this) {
+ final int callingUid = Binder.getCallingUid();
+
+ final UriPermission perm = findUriPermissionLocked(callingUid, uri);
+ if (perm == null) {
+ Slog.w(TAG, "No permission grant found for UID " + callingUid + " and Uri "
+ + uri.toSafeString());
+ return;
+ }
+
+ final boolean persistChanged = perm.releasePersistableModes(modeFlags);
+ removeUriPermissionIfNeededLocked(perm);
+ if (persistChanged) {
+ schedulePersistUriGrants();
+ }
+ }
+ }
+
+ /**
+ * Prune any older {@link UriPermission} for the given UID until outstanding
+ * persisted grants are below {@link #MAX_PERSISTED_URI_GRANTS}.
+ *
+ * @return if any mutations occured that require persisting.
+ */
+ private boolean maybePrunePersistedUriGrantsLocked(int uid) {
+ final ArrayMap<Uri, UriPermission> perms = mGrantedUriPermissions.get(uid);
+ if (perms == null) return false;
+ if (perms.size() < MAX_PERSISTED_URI_GRANTS) return false;
+
+ final ArrayList<UriPermission> persisted = Lists.newArrayList();
+ for (UriPermission perm : perms.values()) {
+ if (perm.persistedModeFlags != 0) {
+ persisted.add(perm);
+ }
+ }
+
+ final int trimCount = persisted.size() - MAX_PERSISTED_URI_GRANTS;
+ if (trimCount <= 0) return false;
+
+ Collections.sort(persisted, new UriPermission.PersistedTimeComparator());
+ for (int i = 0; i < trimCount; i++) {
+ final UriPermission perm = persisted.get(i);
+
+ if (DEBUG_URI_PERMISSION) {
+ Slog.v(TAG, "Trimming grant created at " + perm.persistedCreateTime);
+ }
+
+ perm.releasePersistableModes(~0);
+ removeUriPermissionIfNeededLocked(perm);
+ }
+
+ return true;
+ }
+
+ @Override
+ public ParceledListSlice<android.content.UriPermission> getPersistedUriPermissions() {
+ enforceNotIsolatedCaller("getPersistedUriPermissions");
+
+ synchronized (this) {
+ final int callingUid = Binder.getCallingUid();
+ final ArrayList<android.content.UriPermission> result = Lists.newArrayList();
+ final ArrayMap<Uri, UriPermission> perms = mGrantedUriPermissions.get(callingUid);
+ if (perms == null) {
+ Slog.w(TAG, "No permission grants found for UID " + callingUid);
+ } else {
+ final int size = perms.size();
+ for (int i = 0; i < size; i++) {
+ final UriPermission perm = perms.valueAt(i);
+ if (perm.persistedModeFlags != 0) {
+ result.add(perm.buildPersistedPublicApiObject());
}
}
}
-
- return result.toArray(new Uri[result.size()]);
+ return new ParceledListSlice<android.content.UriPermission>(result);
}
}
@@ -10327,8 +10462,10 @@
pw.println();
}
pw.print(" Process LRU list (sorted by oom_adj, "); pw.print(mLruProcesses.size());
- pw.print(" total, non-activities at ");
+ pw.print(" total, non-act at ");
pw.print(mLruProcesses.size()-mLruProcessActivityStart);
+ pw.print(", non-svc at ");
+ pw.print(mLruProcesses.size()-mLruProcessServiceStart);
pw.println("):");
dumpProcessOomList(pw, this, mLruProcesses, " ", "Proc", "PERS", false, dumpPackage);
needSep = true;
@@ -10704,8 +10841,10 @@
if (needSep) pw.println();
pw.print(" Process OOM control ("); pw.print(mLruProcesses.size());
- pw.print(" total, non-activities at ");
+ pw.print(" total, non-act at ");
pw.print(mLruProcesses.size()-mLruProcessActivityStart);
+ pw.print(", non-svc at ");
+ pw.print(mLruProcesses.size()-mLruProcessServiceStart);
pw.println("):");
dumpProcessOomList(pw, this, mLruProcesses, " ", "Proc", "PERS", true, null);
needSep = true;
@@ -11513,6 +11652,7 @@
final void dumpApplicationMemoryUsage(FileDescriptor fd,
PrintWriter pw, String prefix, String[] args, boolean brief, PrintWriter categoryPw) {
boolean dumpDetails = false;
+ boolean dumpFullDetails = false;
boolean dumpDalvik = false;
boolean oomOnly = false;
boolean isCompact = false;
@@ -11526,6 +11666,7 @@
opti++;
if ("-a".equals(opt)) {
dumpDetails = true;
+ dumpFullDetails = true;
dumpDalvik = true;
} else if ("-d".equals(opt)) {
dumpDalvik = true;
@@ -11613,7 +11754,8 @@
if (dumpDetails) {
try {
pw.flush();
- thread.dumpMemInfo(fd, mi, isCheckinRequest, true, dumpDalvik, innerArgs);
+ thread.dumpMemInfo(fd, mi, isCheckinRequest, dumpFullDetails,
+ dumpDalvik, innerArgs);
} catch (RemoteException e) {
if (!isCheckinRequest) {
pw.println("Got RemoteException!");
@@ -11754,25 +11896,53 @@
if (!isCompact) {
pw.println();
}
+ MemInfoReader memInfo = new MemInfoReader();
+ memInfo.readMemInfo();
if (!brief) {
- MemInfoReader memInfo = new MemInfoReader();
- memInfo.readMemInfo();
if (!isCompact) {
- pw.print("Total RAM: "); pw.print(memInfo.getTotalSize()/1024);
+ pw.print("Total RAM: "); pw.print(memInfo.getTotalSizeKb());
pw.println(" kB");
- pw.print(" Free RAM: "); pw.print(cachedPss + (memInfo.getCachedSize()/1024)
- + (memInfo.getFreeSize()/1024)); pw.println(" kB");
+ pw.print(" Free RAM: "); pw.print(cachedPss + memInfo.getCachedSizeKb()
+ + memInfo.getFreeSizeKb()); pw.print(" kB (");
+ pw.print(cachedPss); pw.print(" cached pss + ");
+ pw.print(memInfo.getCachedSizeKb()); pw.print(" cached + ");
+ pw.print(memInfo.getFreeSizeKb()); pw.println(" free)");
} else {
- pw.print("ram,"); pw.print(memInfo.getTotalSize()/1024); pw.print(",");
- pw.print(cachedPss + (memInfo.getCachedSize()/1024)
- + (memInfo.getFreeSize()/1024)); pw.print(",");
+ pw.print("ram,"); pw.print(memInfo.getTotalSizeKb()); pw.print(",");
+ pw.print(cachedPss + memInfo.getCachedSizeKb()
+ + memInfo.getFreeSizeKb()); pw.print(",");
pw.println(totalPss - cachedPss);
}
}
if (!isCompact) {
- pw.print(" Used PSS: "); pw.print(totalPss - cachedPss); pw.println(" kB");
+ pw.print(" Used RAM: "); pw.print(totalPss - cachedPss
+ + memInfo.getBuffersSizeKb() + memInfo.getShmemSizeKb()
+ + memInfo.getSlabSizeKb()); pw.print(" kB (");
+ pw.print(totalPss - cachedPss); pw.print(" used pss + ");
+ pw.print(memInfo.getBuffersSizeKb()); pw.print(" buffers + ");
+ pw.print(memInfo.getShmemSizeKb()); pw.print(" shmem + ");
+ pw.print(memInfo.getSlabSizeKb()); pw.println(" slab)");
+ pw.print(" Lost RAM: "); pw.print(memInfo.getTotalSizeKb()
+ - totalPss - memInfo.getFreeSizeKb() - memInfo.getCachedSizeKb()
+ - memInfo.getBuffersSizeKb() - memInfo.getShmemSizeKb()
+ - memInfo.getSlabSizeKb()); pw.println(" kB");
}
if (!brief) {
+ if (memInfo.getZramTotalSizeKb() != 0) {
+ if (!isCompact) {
+ pw.print(" ZRAM: "); pw.print(memInfo.getZramTotalSizeKb());
+ pw.print(" kB used for ");
+ pw.print(memInfo.getSwapTotalSizeKb()
+ - memInfo.getSwapFreeSizeKb());
+ pw.print(" kB in swap (");
+ pw.print(memInfo.getSwapTotalSizeKb());
+ pw.println(" kB total swap)");
+ } else {
+ pw.print("zram,"); pw.print(memInfo.getZramTotalSizeKb()); pw.print(",");
+ pw.print(memInfo.getSwapTotalSizeKb()); pw.print(",");
+ pw.println(memInfo.getSwapFreeSizeKb());
+ }
+ }
final int[] SINGLE_LONG_FORMAT = new int[] {
Process.PROC_SPACE_TERM|Process.PROC_OUT_LONG
};
@@ -11807,6 +11977,9 @@
pw.print("), oom ");
pw.print(mProcessList.getMemLevel(ProcessList.CACHED_APP_MAX_ADJ)/1024);
pw.print(" kB");
+ pw.print(", restore limit ");
+ pw.print(mProcessList.getCachedRestoreThresholdKb());
+ pw.print(" kB");
if (ActivityManager.isLowRamDeviceStatic()) {
pw.print(" (low-ram)");
}
@@ -14342,14 +14515,30 @@
if (adj == ProcessList.SERVICE_ADJ) {
if (doingAll) {
- app.serviceb = mNewNumServiceProcs > (mNumServiceProcs/3);
+ app.serviceb = mNewNumAServiceProcs > (mNumServiceProcs/3);
mNewNumServiceProcs++;
+ //Slog.i(TAG, "ADJ " + app + " serviceb=" + app.serviceb);
+ if (!app.serviceb) {
+ // This service isn't far enough down on the LRU list to
+ // normally be a B service, but if we are low on RAM and it
+ // is large we want to force it down since we would prefer to
+ // keep launcher over it.
+ if (mLastMemoryLevel > ProcessStats.ADJ_MEM_FACTOR_NORMAL
+ && app.lastPss >= mProcessList.getCachedRestoreThresholdKb()) {
+ app.serviceHighRam = true;
+ app.serviceb = true;
+ //Slog.i(TAG, "ADJ " + app + " high ram!");
+ } else {
+ mNewNumAServiceProcs++;
+ //Slog.i(TAG, "ADJ " + app + " not high ram!");
+ }
+ } else {
+ app.serviceHighRam = false;
+ }
}
if (app.serviceb) {
adj = ProcessList.SERVICE_B_ADJ;
}
- } else {
- app.serviceb = false;
}
app.curRawAdj = adj;
@@ -14905,6 +15094,7 @@
mAdjSeq++;
mNewNumServiceProcs = 0;
+ mNewNumAServiceProcs = 0;
final int emptyProcessLimit;
final int cachedProcessLimit;
diff --git a/services/java/com/android/server/am/ProcessList.java b/services/java/com/android/server/am/ProcessList.java
index f24e7fe..d3777c7 100644
--- a/services/java/com/android/server/am/ProcessList.java
+++ b/services/java/com/android/server/am/ProcessList.java
@@ -502,7 +502,7 @@
* Return the maximum pss size in kb that we consider a process acceptable to
* restore from its cached state for running in the background when RAM is low.
*/
- long getCachedRestoreThreshold() {
+ long getCachedRestoreThresholdKb() {
return mCachedRestoreLevel;
}
diff --git a/services/java/com/android/server/am/ProcessRecord.java b/services/java/com/android/server/am/ProcessRecord.java
index c5491ef..4b62e7d 100644
--- a/services/java/com/android/server/am/ProcessRecord.java
+++ b/services/java/com/android/server/am/ProcessRecord.java
@@ -82,6 +82,7 @@
int setProcState = -1; // Last set process state in process tracker
int pssProcState = -1; // The proc state we are currently requesting pss for
boolean serviceb; // Process currently is on the service B list
+ boolean serviceHighRam; // We are forcing to service B list due to its RAM use
boolean keeping; // Actively running code so don't kill due to that?
boolean setIsForeground; // Running foreground UI when last set?
boolean notCachedSinceIdle; // Has this process not been in a cached state since last idle?
@@ -223,10 +224,13 @@
pw.print(" lruSeq="); pw.print(lruSeq);
pw.print(" lastPss="); pw.print(lastPss);
pw.print(" lastCachedPss="); pw.println(lastCachedPss);
- pw.print(prefix); pw.print("serviceb="); pw.print(serviceb);
- pw.print(" keeping="); pw.print(keeping);
+ pw.print(prefix); pw.print("keeping="); pw.print(keeping);
pw.print(" cached="); pw.print(cached);
pw.print(" empty="); pw.println(empty);
+ if (serviceb) {
+ pw.print(prefix); pw.print("serviceb="); pw.print(serviceb);
+ pw.print(" serviceHighRam="); pw.println(serviceHighRam);
+ }
if (notCachedSinceIdle) {
pw.print(prefix); pw.print("notCachedSinceIdle="); pw.print(notCachedSinceIdle);
pw.print(" initialIdlePss="); pw.println(initialIdlePss);
diff --git a/services/java/com/android/server/am/UriPermission.java b/services/java/com/android/server/am/UriPermission.java
index 5e2ad009..7057c24 100644
--- a/services/java/com/android/server/am/UriPermission.java
+++ b/services/java/com/android/server/am/UriPermission.java
@@ -20,11 +20,12 @@
import android.net.Uri;
import android.os.UserHandle;
import android.util.Log;
+import android.util.Slog;
-import com.android.internal.util.IndentingPrintWriter;
import com.google.android.collect.Sets;
import java.io.PrintWriter;
+import java.util.Comparator;
import java.util.HashSet;
/**
@@ -38,6 +39,11 @@
final class UriPermission {
private static final String TAG = "UriPermission";
+ public static final int STRENGTH_NONE = 0;
+ public static final int STRENGTH_OWNED = 1;
+ public static final int STRENGTH_GLOBAL = 2;
+ public static final int STRENGTH_PERSISTABLE = 3;
+
final int userHandle;
final String sourcePkg;
final String targetPkg;
@@ -49,26 +55,29 @@
/**
* Allowed modes. All permission enforcement should use this field. Must
- * always be a superset of {@link #globalModeFlags},
- * {@link #persistedModeFlags}, {@link #mReadOwners}, and
- * {@link #mWriteOwners}. Mutations should only be performed by the owning
- * class.
+ * always be a combination of {@link #ownedModeFlags},
+ * {@link #globalModeFlags}, {@link #persistableModeFlags}, and
+ * {@link #persistedModeFlags}. Mutations <em>must</em> only be performed by
+ * the owning class.
*/
int modeFlags = 0;
- /**
- * Allowed modes without explicit owner. Must always be a superset of
- * {@link #persistedModeFlags}. Mutations should only be performed by the
- * owning class.
- */
+ /** Allowed modes with explicit owner. */
+ int ownedModeFlags = 0;
+ /** Allowed modes without explicit owner. */
int globalModeFlags = 0;
+ /** Allowed modes that have been offered for possible persisting. */
+ int persistableModeFlags = 0;
+ /** Allowed modes that should be persisted across device boots. */
+ int persistedModeFlags = 0;
/**
- * Allowed modes that should be persisted across device boots. These modes
- * have no explicit owners. Mutations should only be performed by the owning
- * class.
+ * Timestamp when {@link #persistedModeFlags} was first defined in
+ * {@link System#currentTimeMillis()} time base.
*/
- int persistedModeFlags = 0;
+ long persistedCreateTime = INVALID_TIME;
+
+ private static final long INVALID_TIME = Long.MIN_VALUE;
private HashSet<UriPermissionOwner> mReadOwners;
private HashSet<UriPermissionOwner> mWriteOwners;
@@ -83,21 +92,25 @@
this.uri = uri;
}
+ private void updateModeFlags() {
+ modeFlags = ownedModeFlags | globalModeFlags | persistableModeFlags | persistedModeFlags;
+ }
+
/**
- * @return If mode changes should trigger persisting.
+ * Initialize persisted modes as read from file. This doesn't issue any
+ * global or owner grants.
*/
- boolean grantModes(int modeFlagsToGrant, boolean persist, UriPermissionOwner owner) {
- boolean persistChanged = false;
+ void initPersistedModes(int modeFlags, long createdTime) {
+ persistableModeFlags = modeFlags;
+ persistedModeFlags = modeFlags;
+ persistedCreateTime = createdTime;
- modeFlags |= modeFlagsToGrant;
+ updateModeFlags();
+ }
- if (persist) {
- final int before = persistedModeFlags;
- persistedModeFlags |= modeFlagsToGrant;
- persistChanged = persistedModeFlags != before;
-
- // Treat persisted grants as global (ownerless)
- owner = null;
+ void grantModes(int modeFlags, boolean persistable, UriPermissionOwner owner) {
+ if (persistable) {
+ persistableModeFlags |= modeFlags;
}
if (owner == null) {
@@ -105,43 +118,77 @@
} else {
if ((modeFlags & Intent.FLAG_GRANT_READ_URI_PERMISSION) != 0) {
addReadOwner(owner);
- owner.addReadPermission(this);
}
if ((modeFlags & Intent.FLAG_GRANT_WRITE_URI_PERMISSION) != 0) {
addWriteOwner(owner);
- owner.addWritePermission(this);
}
}
- return persistChanged;
+ updateModeFlags();
}
-
+
/**
- * @return If mode changes should trigger persisting.
+ * @return if mode changes should trigger persisting.
*/
- boolean clearModes(int modeFlagsToClear, boolean persist) {
+ boolean takePersistableModes(int modeFlags) {
+ if ((~persistableModeFlags & modeFlags) != 0) {
+ Slog.w(TAG, "Trying to take 0x" + Integer.toHexString(modeFlags) + " but only 0x"
+ + Integer.toHexString(persistableModeFlags) + " are available");
+ }
+
+ final int before = persistedModeFlags;
+ persistedModeFlags |= (persistableModeFlags & modeFlags);
+
+ if (persistedModeFlags != 0) {
+ persistedCreateTime = System.currentTimeMillis();
+ }
+
+ updateModeFlags();
+ return persistedModeFlags != before;
+ }
+
+ boolean releasePersistableModes(int modeFlags) {
final int before = persistedModeFlags;
- if ((modeFlagsToClear & Intent.FLAG_GRANT_READ_URI_PERMISSION) != 0) {
- if (persist) {
+ persistableModeFlags &= ~modeFlags;
+ persistedModeFlags &= ~modeFlags;
+
+ if (persistedModeFlags == 0) {
+ persistedCreateTime = INVALID_TIME;
+ }
+
+ updateModeFlags();
+ return persistedModeFlags != before;
+ }
+
+ /**
+ * @return if mode changes should trigger persisting.
+ */
+ boolean clearModes(int modeFlags, boolean persistable) {
+ final int before = persistedModeFlags;
+
+ if ((modeFlags & Intent.FLAG_GRANT_READ_URI_PERMISSION) != 0) {
+ if (persistable) {
+ persistableModeFlags &= ~Intent.FLAG_GRANT_READ_URI_PERMISSION;
persistedModeFlags &= ~Intent.FLAG_GRANT_READ_URI_PERMISSION;
}
globalModeFlags &= ~Intent.FLAG_GRANT_READ_URI_PERMISSION;
- modeFlags &= ~Intent.FLAG_GRANT_READ_URI_PERMISSION;
if (mReadOwners != null) {
+ ownedModeFlags &= ~Intent.FLAG_GRANT_READ_URI_PERMISSION;
for (UriPermissionOwner r : mReadOwners) {
r.removeReadPermission(this);
}
mReadOwners = null;
}
}
- if ((modeFlagsToClear & Intent.FLAG_GRANT_WRITE_URI_PERMISSION) != 0) {
- if (persist) {
+ if ((modeFlags & Intent.FLAG_GRANT_WRITE_URI_PERMISSION) != 0) {
+ if (persistable) {
+ persistableModeFlags &= ~Intent.FLAG_GRANT_WRITE_URI_PERMISSION;
persistedModeFlags &= ~Intent.FLAG_GRANT_WRITE_URI_PERMISSION;
}
globalModeFlags &= ~Intent.FLAG_GRANT_WRITE_URI_PERMISSION;
- modeFlags &= ~Intent.FLAG_GRANT_WRITE_URI_PERMISSION;
if (mWriteOwners != null) {
+ ownedModeFlags &= ~Intent.FLAG_GRANT_WRITE_URI_PERMISSION;
for (UriPermissionOwner r : mWriteOwners) {
r.removeWritePermission(this);
}
@@ -149,18 +196,38 @@
}
}
- // Mode flags always bubble up
- globalModeFlags |= persistedModeFlags;
- modeFlags |= globalModeFlags;
+ if (persistedModeFlags == 0) {
+ persistedCreateTime = INVALID_TIME;
+ }
+ updateModeFlags();
return persistedModeFlags != before;
}
+ /**
+ * Return strength of this permission grant for the given flags.
+ */
+ public int getStrength(int modeFlags) {
+ if ((persistableModeFlags & modeFlags) == modeFlags) {
+ return STRENGTH_PERSISTABLE;
+ } else if ((globalModeFlags & modeFlags) == modeFlags) {
+ return STRENGTH_GLOBAL;
+ } else if ((ownedModeFlags & modeFlags) == modeFlags) {
+ return STRENGTH_OWNED;
+ } else {
+ return STRENGTH_NONE;
+ }
+ }
+
private void addReadOwner(UriPermissionOwner owner) {
if (mReadOwners == null) {
mReadOwners = Sets.newHashSet();
+ ownedModeFlags |= Intent.FLAG_GRANT_READ_URI_PERMISSION;
+ updateModeFlags();
}
- mReadOwners.add(owner);
+ if (mReadOwners.add(owner)) {
+ owner.addReadPermission(this);
+ }
}
/**
@@ -172,17 +239,20 @@
}
if (mReadOwners.size() == 0) {
mReadOwners = null;
- if ((globalModeFlags & Intent.FLAG_GRANT_READ_URI_PERMISSION) == 0) {
- modeFlags &= ~Intent.FLAG_GRANT_READ_URI_PERMISSION;
- }
+ ownedModeFlags &= ~Intent.FLAG_GRANT_READ_URI_PERMISSION;
+ updateModeFlags();
}
}
private void addWriteOwner(UriPermissionOwner owner) {
if (mWriteOwners == null) {
mWriteOwners = Sets.newHashSet();
+ ownedModeFlags |= Intent.FLAG_GRANT_WRITE_URI_PERMISSION;
+ updateModeFlags();
}
- mWriteOwners.add(owner);
+ if (mWriteOwners.add(owner)) {
+ owner.addWritePermission(this);
+ }
}
/**
@@ -194,9 +264,8 @@
}
if (mWriteOwners.size() == 0) {
mWriteOwners = null;
- if ((globalModeFlags & Intent.FLAG_GRANT_WRITE_URI_PERMISSION) == 0) {
- modeFlags &= ~Intent.FLAG_GRANT_WRITE_URI_PERMISSION;
- }
+ ownedModeFlags &= ~Intent.FLAG_GRANT_WRITE_URI_PERMISSION;
+ updateModeFlags();
}
}
@@ -221,9 +290,15 @@
pw.println(" targetPkg=" + targetPkg);
pw.print(prefix);
- pw.print("modeFlags=0x" + Integer.toHexString(modeFlags));
- pw.print(" globalModeFlags=0x" + Integer.toHexString(globalModeFlags));
- pw.println(" persistedModeFlags=0x" + Integer.toHexString(persistedModeFlags));
+ pw.print("mode=0x" + Integer.toHexString(modeFlags));
+ pw.print(" owned=0x" + Integer.toHexString(ownedModeFlags));
+ pw.print(" global=0x" + Integer.toHexString(globalModeFlags));
+ pw.print(" persistable=0x" + Integer.toHexString(persistableModeFlags));
+ pw.print(" persisted=0x" + Integer.toHexString(persistedModeFlags));
+ if (persistedCreateTime != INVALID_TIME) {
+ pw.print(" persistedCreate=" + persistedCreateTime);
+ }
+ pw.println();
if (mReadOwners != null) {
pw.print(prefix);
@@ -243,6 +318,13 @@
}
}
+ public static class PersistedTimeComparator implements Comparator<UriPermission> {
+ @Override
+ public int compare(UriPermission lhs, UriPermission rhs) {
+ return Long.compare(lhs.persistedCreateTime, rhs.persistedCreateTime);
+ }
+ }
+
/**
* Snapshot of {@link UriPermission} with frozen
* {@link UriPermission#persistedModeFlags} state.
@@ -253,6 +335,7 @@
final String targetPkg;
final Uri uri;
final int persistedModeFlags;
+ final long persistedCreateTime;
private Snapshot(UriPermission perm) {
this.userHandle = perm.userHandle;
@@ -260,10 +343,15 @@
this.targetPkg = perm.targetPkg;
this.uri = perm.uri;
this.persistedModeFlags = perm.persistedModeFlags;
+ this.persistedCreateTime = perm.persistedCreateTime;
}
}
public Snapshot snapshot() {
return new Snapshot(this);
}
+
+ public android.content.UriPermission buildPersistedPublicApiObject() {
+ return new android.content.UriPermission(uri, persistedModeFlags, persistedCreateTime);
+ }
}