donut snapshot
This commit is contained in:
@@ -369,30 +369,33 @@ public abstract class AbstractTableMerger
|
||||
// An existing server item has changed
|
||||
// If serverSyncVersion is null, there is no edit URL;
|
||||
// server won't let this change be written.
|
||||
// Just hold onto it, I guess, in case the server permissions
|
||||
// change later.
|
||||
if (serverSyncVersion != null) {
|
||||
boolean recordChanged = (localSyncVersion == null) ||
|
||||
!serverSyncVersion.equals(localSyncVersion);
|
||||
if (recordChanged) {
|
||||
if (localSyncDirty) {
|
||||
if (Log.isLoggable(TAG, Log.VERBOSE)) {
|
||||
Log.v(TAG, "remote record " + serverSyncId
|
||||
+ " conflicts with local _sync_id " + localSyncID
|
||||
+ ", local _id " + localRowId);
|
||||
}
|
||||
conflict = true;
|
||||
} else {
|
||||
if (Log.isLoggable(TAG, Log.VERBOSE)) {
|
||||
Log.v(TAG,
|
||||
"remote record " +
|
||||
serverSyncId +
|
||||
" updates local _sync_id " +
|
||||
localSyncID + ", local _id " +
|
||||
localRowId);
|
||||
}
|
||||
update = true;
|
||||
boolean recordChanged = (localSyncVersion == null) ||
|
||||
(serverSyncVersion == null) ||
|
||||
!serverSyncVersion.equals(localSyncVersion);
|
||||
if (recordChanged) {
|
||||
if (localSyncDirty) {
|
||||
if (Log.isLoggable(TAG, Log.VERBOSE)) {
|
||||
Log.v(TAG, "remote record " + serverSyncId
|
||||
+ " conflicts with local _sync_id " + localSyncID
|
||||
+ ", local _id " + localRowId);
|
||||
}
|
||||
conflict = true;
|
||||
} else {
|
||||
if (Log.isLoggable(TAG, Log.VERBOSE)) {
|
||||
Log.v(TAG,
|
||||
"remote record " +
|
||||
serverSyncId +
|
||||
" updates local _sync_id " +
|
||||
localSyncID + ", local _id " +
|
||||
localRowId);
|
||||
}
|
||||
update = true;
|
||||
}
|
||||
} else {
|
||||
if (Log.isLoggable(TAG, Log.VERBOSE)) {
|
||||
Log.v(TAG,
|
||||
"Skipping update: localSyncVersion: " + localSyncVersion +
|
||||
", serverSyncVersion: " + serverSyncVersion);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
package android.content;
|
||||
|
||||
import android.content.pm.PackageManager;
|
||||
import android.content.pm.PathPermission;
|
||||
import android.content.pm.ProviderInfo;
|
||||
import android.content.res.AssetFileDescriptor;
|
||||
import android.content.res.Configuration;
|
||||
@@ -29,6 +30,7 @@ import android.database.SQLException;
|
||||
import android.net.Uri;
|
||||
import android.os.Binder;
|
||||
import android.os.ParcelFileDescriptor;
|
||||
import android.os.Process;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileNotFoundException;
|
||||
@@ -65,8 +67,10 @@ import java.io.FileNotFoundException;
|
||||
*/
|
||||
public abstract class ContentProvider implements ComponentCallbacks {
|
||||
private Context mContext = null;
|
||||
private int mMyUid;
|
||||
private String mReadPermission;
|
||||
private String mWritePermission;
|
||||
private PathPermission[] mPathPermissions;
|
||||
|
||||
private Transport mTransport = new Transport();
|
||||
|
||||
@@ -108,24 +112,20 @@ public abstract class ContentProvider implements ComponentCallbacks {
|
||||
public IBulkCursor bulkQuery(Uri uri, String[] projection,
|
||||
String selection, String[] selectionArgs, String sortOrder,
|
||||
IContentObserver observer, CursorWindow window) {
|
||||
checkReadPermission(uri);
|
||||
enforceReadPermission(uri);
|
||||
Cursor cursor = ContentProvider.this.query(uri, projection,
|
||||
selection, selectionArgs, sortOrder);
|
||||
if (cursor == null) {
|
||||
return null;
|
||||
}
|
||||
String wperm = getWritePermission();
|
||||
return new CursorToBulkCursorAdaptor(cursor, observer,
|
||||
ContentProvider.this.getClass().getName(),
|
||||
wperm == null ||
|
||||
getContext().checkCallingOrSelfPermission(getWritePermission())
|
||||
== PackageManager.PERMISSION_GRANTED,
|
||||
window);
|
||||
hasWritePermission(uri), window);
|
||||
}
|
||||
|
||||
public Cursor query(Uri uri, String[] projection,
|
||||
String selection, String[] selectionArgs, String sortOrder) {
|
||||
checkReadPermission(uri);
|
||||
enforceReadPermission(uri);
|
||||
return ContentProvider.this.query(uri, projection, selection,
|
||||
selectionArgs, sortOrder);
|
||||
}
|
||||
@@ -136,55 +136,84 @@ public abstract class ContentProvider implements ComponentCallbacks {
|
||||
|
||||
|
||||
public Uri insert(Uri uri, ContentValues initialValues) {
|
||||
checkWritePermission(uri);
|
||||
enforceWritePermission(uri);
|
||||
return ContentProvider.this.insert(uri, initialValues);
|
||||
}
|
||||
|
||||
public int bulkInsert(Uri uri, ContentValues[] initialValues) {
|
||||
checkWritePermission(uri);
|
||||
enforceWritePermission(uri);
|
||||
return ContentProvider.this.bulkInsert(uri, initialValues);
|
||||
}
|
||||
|
||||
public int delete(Uri uri, String selection, String[] selectionArgs) {
|
||||
checkWritePermission(uri);
|
||||
enforceWritePermission(uri);
|
||||
return ContentProvider.this.delete(uri, selection, selectionArgs);
|
||||
}
|
||||
|
||||
public int update(Uri uri, ContentValues values, String selection,
|
||||
String[] selectionArgs) {
|
||||
checkWritePermission(uri);
|
||||
enforceWritePermission(uri);
|
||||
return ContentProvider.this.update(uri, values, selection, selectionArgs);
|
||||
}
|
||||
|
||||
public ParcelFileDescriptor openFile(Uri uri, String mode)
|
||||
throws FileNotFoundException {
|
||||
if (mode != null && mode.startsWith("rw")) checkWritePermission(uri);
|
||||
else checkReadPermission(uri);
|
||||
if (mode != null && mode.startsWith("rw")) enforceWritePermission(uri);
|
||||
else enforceReadPermission(uri);
|
||||
return ContentProvider.this.openFile(uri, mode);
|
||||
}
|
||||
|
||||
public AssetFileDescriptor openAssetFile(Uri uri, String mode)
|
||||
throws FileNotFoundException {
|
||||
if (mode != null && mode.startsWith("rw")) checkWritePermission(uri);
|
||||
else checkReadPermission(uri);
|
||||
if (mode != null && mode.startsWith("rw")) enforceWritePermission(uri);
|
||||
else enforceReadPermission(uri);
|
||||
return ContentProvider.this.openAssetFile(uri, mode);
|
||||
}
|
||||
|
||||
public ISyncAdapter getSyncAdapter() {
|
||||
checkWritePermission(null);
|
||||
enforceWritePermission(null);
|
||||
SyncAdapter sa = ContentProvider.this.getSyncAdapter();
|
||||
return sa != null ? sa.getISyncAdapter() : null;
|
||||
}
|
||||
|
||||
private void checkReadPermission(Uri uri) {
|
||||
private void enforceReadPermission(Uri uri) {
|
||||
final int uid = Binder.getCallingUid();
|
||||
if (uid == mMyUid) {
|
||||
return;
|
||||
}
|
||||
|
||||
final Context context = getContext();
|
||||
final String rperm = getReadPermission();
|
||||
final int pid = Binder.getCallingPid();
|
||||
final int uid = Binder.getCallingUid();
|
||||
if (getContext().checkUriPermission(uri, rperm, null, pid, uid,
|
||||
if (rperm == null
|
||||
|| context.checkPermission(rperm, pid, uid)
|
||||
== PackageManager.PERMISSION_GRANTED) {
|
||||
return;
|
||||
}
|
||||
|
||||
PathPermission[] pps = getPathPermissions();
|
||||
if (pps != null) {
|
||||
final String path = uri.getPath();
|
||||
int i = pps.length;
|
||||
while (i > 0) {
|
||||
i--;
|
||||
final PathPermission pp = pps[i];
|
||||
final String pprperm = pp.getReadPermission();
|
||||
if (pprperm != null && pp.match(path)) {
|
||||
if (context.checkPermission(pprperm, pid, uid)
|
||||
== PackageManager.PERMISSION_GRANTED) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (context.checkUriPermission(uri, pid, uid,
|
||||
Intent.FLAG_GRANT_READ_URI_PERMISSION)
|
||||
== PackageManager.PERMISSION_GRANTED) {
|
||||
return;
|
||||
}
|
||||
|
||||
String msg = "Permission Denial: reading "
|
||||
+ ContentProvider.this.getClass().getName()
|
||||
+ " uri " + uri + " from pid=" + Binder.getCallingPid()
|
||||
@@ -193,20 +222,57 @@ public abstract class ContentProvider implements ComponentCallbacks {
|
||||
throw new SecurityException(msg);
|
||||
}
|
||||
|
||||
private void checkWritePermission(Uri uri) {
|
||||
private boolean hasWritePermission(Uri uri) {
|
||||
final int uid = Binder.getCallingUid();
|
||||
if (uid == mMyUid) {
|
||||
return true;
|
||||
}
|
||||
|
||||
final Context context = getContext();
|
||||
final String wperm = getWritePermission();
|
||||
final int pid = Binder.getCallingPid();
|
||||
final int uid = Binder.getCallingUid();
|
||||
if (getContext().checkUriPermission(uri, null, wperm, pid, uid,
|
||||
if (wperm == null
|
||||
|| context.checkPermission(wperm, pid, uid)
|
||||
== PackageManager.PERMISSION_GRANTED) {
|
||||
return true;
|
||||
}
|
||||
|
||||
PathPermission[] pps = getPathPermissions();
|
||||
if (pps != null) {
|
||||
final String path = uri.getPath();
|
||||
int i = pps.length;
|
||||
while (i > 0) {
|
||||
i--;
|
||||
final PathPermission pp = pps[i];
|
||||
final String ppwperm = pp.getWritePermission();
|
||||
if (ppwperm != null && pp.match(path)) {
|
||||
if (context.checkPermission(ppwperm, pid, uid)
|
||||
== PackageManager.PERMISSION_GRANTED) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (context.checkUriPermission(uri, pid, uid,
|
||||
Intent.FLAG_GRANT_WRITE_URI_PERMISSION)
|
||||
== PackageManager.PERMISSION_GRANTED) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private void enforceWritePermission(Uri uri) {
|
||||
if (hasWritePermission(uri)) {
|
||||
return;
|
||||
}
|
||||
|
||||
String msg = "Permission Denial: writing "
|
||||
+ ContentProvider.this.getClass().getName()
|
||||
+ " uri " + uri + " from pid=" + Binder.getCallingPid()
|
||||
+ ", uid=" + Binder.getCallingUid()
|
||||
+ " requires " + wperm;
|
||||
+ " requires " + getWritePermission();
|
||||
throw new SecurityException(msg);
|
||||
}
|
||||
}
|
||||
@@ -265,6 +331,28 @@ public abstract class ContentProvider implements ComponentCallbacks {
|
||||
return mWritePermission;
|
||||
}
|
||||
|
||||
/**
|
||||
* Change the path-based permission required to read and/or write data in
|
||||
* the content provider. This is normally set for you from its manifest
|
||||
* information when the provider is first created.
|
||||
*
|
||||
* @param permissions Array of path permission descriptions.
|
||||
*/
|
||||
protected final void setPathPermissions(PathPermission[] permissions) {
|
||||
mPathPermissions = permissions;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the path-based permissions required for read and/or write access to
|
||||
* this content provider. This method can be called from multiple
|
||||
* threads, as described in
|
||||
* <a href="{@docRoot}guide/topics/fundamentals.html#procthread">Application Fundamentals:
|
||||
* Processes and Threads</a>.
|
||||
*/
|
||||
public final PathPermission[] getPathPermissions() {
|
||||
return mPathPermissions;
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when the provider is being started.
|
||||
*
|
||||
@@ -600,9 +688,11 @@ public abstract class ContentProvider implements ComponentCallbacks {
|
||||
*/
|
||||
if (mContext == null) {
|
||||
mContext = context;
|
||||
mMyUid = Process.myUid();
|
||||
if (info != null) {
|
||||
setReadPermission(info.readPermission);
|
||||
setWritePermission(info.writePermission);
|
||||
setPathPermissions(info.pathPermissions);
|
||||
}
|
||||
ContentProvider.this.onCreate();
|
||||
}
|
||||
|
||||
@@ -91,6 +91,21 @@ public interface DialogInterface {
|
||||
public void onDismiss(DialogInterface dialog);
|
||||
}
|
||||
|
||||
/**
|
||||
* Interface used to allow the creator of a dialog to run some code when the
|
||||
* dialog is shown.
|
||||
* @hide Pending API council approval
|
||||
*/
|
||||
interface OnShowListener {
|
||||
/**
|
||||
* This method will be invoked when the dialog is shown.
|
||||
*
|
||||
* @param dialog The dialog that was shown will be passed into the
|
||||
* method.
|
||||
*/
|
||||
public void onShow(DialogInterface dialog);
|
||||
}
|
||||
|
||||
/**
|
||||
* Interface used to allow the creator of a dialog to run some code when an
|
||||
* item on the dialog is clicked..
|
||||
|
||||
@@ -1112,11 +1112,17 @@ public class Intent implements Parcelable {
|
||||
|
||||
/**
|
||||
* Broadcast Action: Sent after the screen turns off.
|
||||
*
|
||||
* <p class="note">This is a protected intent that can only be sent
|
||||
* by the system.
|
||||
*/
|
||||
@SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
|
||||
public static final String ACTION_SCREEN_OFF = "android.intent.action.SCREEN_OFF";
|
||||
/**
|
||||
* Broadcast Action: Sent after the screen turns on.
|
||||
*
|
||||
* <p class="note">This is a protected intent that can only be sent
|
||||
* by the system.
|
||||
*/
|
||||
@SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
|
||||
public static final String ACTION_SCREEN_ON = "android.intent.action.SCREEN_ON";
|
||||
@@ -1124,6 +1130,9 @@ public class Intent implements Parcelable {
|
||||
/**
|
||||
* Broadcast Action: Sent when the user is present after device wakes up (e.g when the
|
||||
* keyguard is gone).
|
||||
*
|
||||
* <p class="note">This is a protected intent that can only be sent
|
||||
* by the system.
|
||||
*/
|
||||
@SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
|
||||
public static final String ACTION_USER_PRESENT= "android.intent.action.USER_PRESENT";
|
||||
@@ -1134,6 +1143,9 @@ public class Intent implements Parcelable {
|
||||
* in manifests, only by exlicitly registering for it with
|
||||
* {@link Context#registerReceiver(BroadcastReceiver, IntentFilter)
|
||||
* Context.registerReceiver()}.
|
||||
*
|
||||
* <p class="note">This is a protected intent that can only be sent
|
||||
* by the system.
|
||||
*/
|
||||
@SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
|
||||
public static final String ACTION_TIME_TICK = "android.intent.action.TIME_TICK";
|
||||
@@ -1152,6 +1164,9 @@ public class Intent implements Parcelable {
|
||||
* <ul>
|
||||
* <li><em>time-zone</em> - The java.util.TimeZone.getID() value identifying the new time zone.</li>
|
||||
* </ul>
|
||||
*
|
||||
* <p class="note">This is a protected intent that can only be sent
|
||||
* by the system.
|
||||
*/
|
||||
@SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
|
||||
public static final String ACTION_TIMEZONE_CHANGED = "android.intent.action.TIMEZONE_CHANGED";
|
||||
@@ -1177,6 +1192,9 @@ public class Intent implements Parcelable {
|
||||
* such as installing alarms. You must hold the
|
||||
* {@link android.Manifest.permission#RECEIVE_BOOT_COMPLETED} permission
|
||||
* in order to receive this broadcast.
|
||||
*
|
||||
* <p class="note">This is a protected intent that can only be sent
|
||||
* by the system.
|
||||
*/
|
||||
@SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
|
||||
public static final String ACTION_BOOT_COMPLETED = "android.intent.action.BOOT_COMPLETED";
|
||||
@@ -1190,6 +1208,9 @@ public class Intent implements Parcelable {
|
||||
* Broadcast Action: Trigger the download and eventual installation
|
||||
* of a package.
|
||||
* <p>Input: {@link #getData} is the URI of the package file to download.
|
||||
*
|
||||
* <p class="note">This is a protected intent that can only be sent
|
||||
* by the system.
|
||||
*/
|
||||
@SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
|
||||
public static final String ACTION_PACKAGE_INSTALL = "android.intent.action.PACKAGE_INSTALL";
|
||||
@@ -1203,6 +1224,9 @@ public class Intent implements Parcelable {
|
||||
* <li> {@link #EXTRA_REPLACING} is set to true if this is following
|
||||
* an {@link #ACTION_PACKAGE_REMOVED} broadcast for the same package.
|
||||
* </ul>
|
||||
*
|
||||
* <p class="note">This is a protected intent that can only be sent
|
||||
* by the system.
|
||||
*/
|
||||
@SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
|
||||
public static final String ACTION_PACKAGE_ADDED = "android.intent.action.PACKAGE_ADDED";
|
||||
@@ -1214,6 +1238,9 @@ public class Intent implements Parcelable {
|
||||
* <ul>
|
||||
* <li> {@link #EXTRA_UID} containing the integer uid assigned to the new package.
|
||||
* </ul>
|
||||
*
|
||||
* <p class="note">This is a protected intent that can only be sent
|
||||
* by the system.
|
||||
*/
|
||||
@SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
|
||||
public static final String ACTION_PACKAGE_REPLACED = "android.intent.action.PACKAGE_REPLACED";
|
||||
@@ -1229,6 +1256,9 @@ public class Intent implements Parcelable {
|
||||
* <li> {@link #EXTRA_REPLACING} is set to true if this will be followed
|
||||
* by an {@link #ACTION_PACKAGE_ADDED} broadcast for the same package.
|
||||
* </ul>
|
||||
*
|
||||
* <p class="note">This is a protected intent that can only be sent
|
||||
* by the system.
|
||||
*/
|
||||
@SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
|
||||
public static final String ACTION_PACKAGE_REMOVED = "android.intent.action.PACKAGE_REMOVED";
|
||||
@@ -1238,6 +1268,9 @@ public class Intent implements Parcelable {
|
||||
* <ul>
|
||||
* <li> {@link #EXTRA_UID} containing the integer uid assigned to the package.
|
||||
* </ul>
|
||||
*
|
||||
* <p class="note">This is a protected intent that can only be sent
|
||||
* by the system.
|
||||
*/
|
||||
@SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
|
||||
public static final String ACTION_PACKAGE_CHANGED = "android.intent.action.PACKAGE_CHANGED";
|
||||
@@ -1251,6 +1284,9 @@ public class Intent implements Parcelable {
|
||||
* <ul>
|
||||
* <li> {@link #EXTRA_UID} containing the integer uid assigned to the package.
|
||||
* </ul>
|
||||
*
|
||||
* <p class="note">This is a protected intent that can only be sent
|
||||
* by the system.
|
||||
*/
|
||||
@SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
|
||||
public static final String ACTION_PACKAGE_RESTARTED = "android.intent.action.PACKAGE_RESTARTED";
|
||||
@@ -1263,12 +1299,18 @@ public class Intent implements Parcelable {
|
||||
* <ul>
|
||||
* <li> {@link #EXTRA_UID} containing the integer uid assigned to the package.
|
||||
* </ul>
|
||||
*
|
||||
* <p class="note">This is a protected intent that can only be sent
|
||||
* by the system.
|
||||
*/
|
||||
@SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
|
||||
public static final String ACTION_PACKAGE_DATA_CLEARED = "android.intent.action.PACKAGE_DATA_CLEARED";
|
||||
/**
|
||||
* Broadcast Action: A user ID has been removed from the system. The user
|
||||
* ID number is stored in the extra data under {@link #EXTRA_UID}.
|
||||
*
|
||||
* <p class="note">This is a protected intent that can only be sent
|
||||
* by the system.
|
||||
*/
|
||||
@SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
|
||||
public static final String ACTION_UID_REMOVED = "android.intent.action.UID_REMOVED";
|
||||
@@ -1287,6 +1329,9 @@ public class Intent implements Parcelable {
|
||||
* application to make sure it sees the new changes. Some system code that
|
||||
* can not be restarted will need to watch for this action and handle it
|
||||
* appropriately.
|
||||
*
|
||||
* <p class="note">This is a protected intent that can only be sent
|
||||
* by the system.
|
||||
*
|
||||
* @see android.content.res.Configuration
|
||||
*/
|
||||
@@ -1298,15 +1343,21 @@ public class Intent implements Parcelable {
|
||||
*
|
||||
* <p class="note">
|
||||
* You can <em>not</em> receive this through components declared
|
||||
* in manifests, only by exlicitly registering for it with
|
||||
* in manifests, only by explicitly registering for it with
|
||||
* {@link Context#registerReceiver(BroadcastReceiver, IntentFilter)
|
||||
* Context.registerReceiver()}.
|
||||
*
|
||||
* <p class="note">This is a protected intent that can only be sent
|
||||
* by the system.
|
||||
*/
|
||||
@SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
|
||||
public static final String ACTION_BATTERY_CHANGED = "android.intent.action.BATTERY_CHANGED";
|
||||
/**
|
||||
* Broadcast Action: Indicates low battery condition on the device.
|
||||
* This broadcast corresponds to the "Low battery warning" system dialog.
|
||||
*
|
||||
* <p class="note">This is a protected intent that can only be sent
|
||||
* by the system.
|
||||
*/
|
||||
@SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
|
||||
public static final String ACTION_BATTERY_LOW = "android.intent.action.BATTERY_LOW";
|
||||
@@ -1314,6 +1365,9 @@ public class Intent implements Parcelable {
|
||||
* Broadcast Action: Indicates the battery is now okay after being low.
|
||||
* This will be sent after {@link #ACTION_BATTERY_LOW} once the battery has
|
||||
* gone back up to an okay state.
|
||||
*
|
||||
* <p class="note">This is a protected intent that can only be sent
|
||||
* by the system.
|
||||
*/
|
||||
@SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
|
||||
public static final String ACTION_BATTERY_OKAY = "android.intent.action.BATTERY_OKAY";
|
||||
@@ -1323,6 +1377,9 @@ public class Intent implements Parcelable {
|
||||
* Unlike ACTION_BATTERY_CHANGED, applications will be woken for this and so do not have to
|
||||
* stay active to receive this notification. This action can be used to implement actions
|
||||
* that wait until power is available to trigger.
|
||||
*
|
||||
* <p class="note">This is a protected intent that can only be sent
|
||||
* by the system.
|
||||
*/
|
||||
@SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
|
||||
public static final String ACTION_POWER_CONNECTED = "android.intent.action.ACTION_POWER_CONNECTED";
|
||||
@@ -1332,6 +1389,9 @@ public class Intent implements Parcelable {
|
||||
* Unlike ACTION_BATTERY_CHANGED, applications will be woken for this and so do not have to
|
||||
* stay active to receive this notification. This action can be used to implement actions
|
||||
* that wait until power is available to trigger.
|
||||
*
|
||||
* <p class="note">This is a protected intent that can only be sent
|
||||
* by the system.
|
||||
*/
|
||||
@SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
|
||||
public static final String ACTION_POWER_DISCONNECTED = "android.intent.action.ACTION_POWER_DISCONNECTED";
|
||||
@@ -1341,16 +1401,25 @@ public class Intent implements Parcelable {
|
||||
* off, not sleeping). Once the broadcast is complete, the final shutdown
|
||||
* will proceed and all unsaved data lost. Apps will not normally need
|
||||
* to handle this, since the forground activity will be paused as well.
|
||||
*
|
||||
* <p class="note">This is a protected intent that can only be sent
|
||||
* by the system.
|
||||
*/
|
||||
@SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
|
||||
public static final String ACTION_SHUTDOWN = "android.intent.action.ACTION_SHUTDOWN";
|
||||
/**
|
||||
* Broadcast Action: Indicates low memory condition on the device
|
||||
*
|
||||
* <p class="note">This is a protected intent that can only be sent
|
||||
* by the system.
|
||||
*/
|
||||
@SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
|
||||
public static final String ACTION_DEVICE_STORAGE_LOW = "android.intent.action.DEVICE_STORAGE_LOW";
|
||||
/**
|
||||
* Broadcast Action: Indicates low memory condition on the device no longer exists
|
||||
*
|
||||
* <p class="note">This is a protected intent that can only be sent
|
||||
* by the system.
|
||||
*/
|
||||
@SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
|
||||
public static final String ACTION_DEVICE_STORAGE_OK = "android.intent.action.DEVICE_STORAGE_OK";
|
||||
@@ -1515,6 +1584,9 @@ public class Intent implements Parcelable {
|
||||
* then cell radio and possibly other radios such as bluetooth or WiFi may have also been
|
||||
* turned off</li>
|
||||
* </ul>
|
||||
*
|
||||
* <p class="note">This is a protected intent that can only be sent
|
||||
* by the system.
|
||||
*/
|
||||
@SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
|
||||
public static final String ACTION_AIRPLANE_MODE_CHANGED = "android.intent.action.AIRPLANE_MODE";
|
||||
@@ -1593,6 +1665,9 @@ public class Intent implements Parcelable {
|
||||
* <p>You must hold the
|
||||
* {@link android.Manifest.permission#PROCESS_OUTGOING_CALLS}
|
||||
* permission to receive this Intent.</p>
|
||||
*
|
||||
* <p class="note">This is a protected intent that can only be sent
|
||||
* by the system.
|
||||
*/
|
||||
@SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
|
||||
public static final String ACTION_NEW_OUTGOING_CALL =
|
||||
@@ -1601,14 +1676,54 @@ public class Intent implements Parcelable {
|
||||
/**
|
||||
* Broadcast Action: Have the device reboot. This is only for use by
|
||||
* system code.
|
||||
*
|
||||
* <p class="note">This is a protected intent that can only be sent
|
||||
* by the system.
|
||||
*/
|
||||
@SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
|
||||
public static final String ACTION_REBOOT =
|
||||
"android.intent.action.REBOOT";
|
||||
/**
|
||||
* Broadcast Action: Triggers the platform Text-To-Speech engine to
|
||||
* start the activity that installs the resource files on the device
|
||||
* that are required for TTS to be operational. Since the installation
|
||||
* of the data can be interrupted or declined by the user, the application
|
||||
* shouldn't expect successful installation upon return from that intent,
|
||||
* and if need be, should check installation status with
|
||||
* {@link #ACTION_TTS_CHECK_TTS_DATA}.
|
||||
*/
|
||||
@SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
|
||||
public static final String ACTION_TTS_INSTALL_TTS_DATA =
|
||||
"android.intent.action.INSTALL_TTS_DATA";
|
||||
|
||||
/**
|
||||
* Broadcast Action: Starts the activity from the platform Text-To-Speech
|
||||
* engine to verify the proper installation and availability of the
|
||||
* resource files on the system. Upon completion, the activity will
|
||||
* return one of the following codes:
|
||||
* {@link android.speech.tts.TextToSpeech.Engine#CHECK_VOICE_DATA_PASS},
|
||||
* {@link android.speech.tts.TextToSpeech.Engine#CHECK_VOICE_DATA_FAIL},
|
||||
* {@link android.speech.tts.TextToSpeech.Engine#CHECK_VOICE_DATA_BAD_DATA},
|
||||
* {@link android.speech.tts.TextToSpeech.Engine#CHECK_VOICE_DATA_MISSING_DATA}, or
|
||||
* {@link android.speech.tts.TextToSpeech.Engine#CHECK_VOICE_DATA_MISSING_VOLUME}.
|
||||
* <p> Moreover, the data received in the activity result will contain the following
|
||||
* fields:
|
||||
* <ul>
|
||||
* <li>{@link android.speech.tts.TextToSpeech.Engine#VOICE_DATA_ROOT_DIRECTORY} which
|
||||
* indicates the path to the location of the resource files</li>,
|
||||
* <li>{@link android.speech.tts.TextToSpeech.Engine#VOICE_DATA_FILES} which contains
|
||||
* the list of all the resource files</li>,
|
||||
* <li>and {@link android.speech.tts.TextToSpeech.Engine#VOICE_DATA_FILES_INFO} which
|
||||
* contains, for each resource file, the description of the language covered by
|
||||
* the file in the xxx-YYY format, where xxx is the 3-letter ISO language code,
|
||||
* and YYY is the 3-letter ISO country code.</li>
|
||||
* </ul>
|
||||
*/
|
||||
@SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
|
||||
public static final String ACTION_TTS_CHECK_TTS_DATA =
|
||||
"android.intent.action.CHECK_TTS_DATA";
|
||||
|
||||
/**
|
||||
* @hide
|
||||
* TODO: This will be unhidden in a later CL.
|
||||
* Broadcast Action: The TextToSpeech synthesizer has completed processing
|
||||
* all of the text in the speech queue.
|
||||
*/
|
||||
@@ -4398,6 +4513,9 @@ public class Intent implements Parcelable {
|
||||
* and {@link #FILL_IN_COMPONENT} to override the restriction where the
|
||||
* corresponding field will not be replaced if it is already set.
|
||||
*
|
||||
* <p>Note: The component field will only be copied if {@link #FILL_IN_COMPONENT} is explicitly
|
||||
* specified.
|
||||
*
|
||||
* <p>For example, consider Intent A with {data="foo", categories="bar"}
|
||||
* and Intent B with {action="gotit", data-type="some/thing",
|
||||
* categories="one","two"}.
|
||||
|
||||
@@ -338,6 +338,7 @@ public class SyncStorageEngine extends Handler {
|
||||
}
|
||||
reports.add(mChangeListeners.getBroadcastItem(i));
|
||||
}
|
||||
mChangeListeners.finishBroadcast();
|
||||
}
|
||||
|
||||
if (DEBUG) Log.v(TAG, "reportChange " + which + " to: " + reports);
|
||||
|
||||
@@ -160,20 +160,28 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable {
|
||||
*/
|
||||
public static final int FLAG_SUPPORTS_LARGE_SCREENS = 1<<11;
|
||||
|
||||
/**
|
||||
* Value for {@link #flags}: true when the application knows how to adjust
|
||||
* its UI for different screen sizes. Corresponds to
|
||||
* {@link android.R.styleable#AndroidManifestSupportsScreens_resizeable
|
||||
* android:resizeable}.
|
||||
*/
|
||||
public static final int FLAG_RESIZEABLE_FOR_SCREENS = 1<<12;
|
||||
|
||||
/**
|
||||
* Value for {@link #flags}: this is false if the application has set
|
||||
* its android:allowBackup to false, true otherwise.
|
||||
*
|
||||
* {@hide}
|
||||
*/
|
||||
public static final int FLAG_ALLOW_BACKUP = 1<<12;
|
||||
public static final int FLAG_ALLOW_BACKUP = 1<<13;
|
||||
|
||||
/**
|
||||
* Indicates that the application supports any densities;
|
||||
* {@hide}
|
||||
*/
|
||||
public static final int ANY_DENSITY = -1;
|
||||
private static final int[] ANY_DENSITIES_ARRAY = { ANY_DENSITY };
|
||||
static final int[] ANY_DENSITIES_ARRAY = { ANY_DENSITY };
|
||||
|
||||
/**
|
||||
* Flags associated with the application. Any combination of
|
||||
@@ -183,7 +191,7 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable {
|
||||
* {@link #FLAG_ALLOW_CLEAR_USER_DATA}, {@link #FLAG_UPDATED_SYSTEM_APP},
|
||||
* {@link #FLAG_TEST_ONLY}, {@link #FLAG_SUPPORTS_SMALL_SCREENS},
|
||||
* {@link #FLAG_SUPPORTS_NORMAL_SCREENS},
|
||||
* {@link #FLAG_SUPPORTS_LARGE_SCREENS}.
|
||||
* {@link #FLAG_SUPPORTS_LARGE_SCREENS}, {@link #FLAG_RESIZEABLE_FOR_SCREENS}.
|
||||
*/
|
||||
public int flags = 0;
|
||||
|
||||
@@ -399,7 +407,8 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable {
|
||||
* @hide
|
||||
*/
|
||||
public void disableCompatibilityMode() {
|
||||
flags |= FLAG_SUPPORTS_LARGE_SCREENS;
|
||||
flags |= (FLAG_SUPPORTS_LARGE_SCREENS | FLAG_SUPPORTS_NORMAL_SCREENS |
|
||||
FLAG_SUPPORTS_SMALL_SCREENS | FLAG_RESIZEABLE_FOR_SCREENS);
|
||||
supportsDensities = ANY_DENSITIES_ARRAY;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -71,6 +71,8 @@ interface IPackageManager {
|
||||
|
||||
void removePermission(String name);
|
||||
|
||||
boolean isProtectedBroadcast(String actionName);
|
||||
|
||||
int checkSignatures(String pkg1, String pkg2);
|
||||
|
||||
String[] getPackagesForUid(int uid);
|
||||
|
||||
@@ -92,6 +92,8 @@ public class PackageParser {
|
||||
private static final Object mSync = new Object();
|
||||
private static WeakReference<byte[]> mReadBuffer;
|
||||
|
||||
private static boolean sCompatibilityModeEnabled = true;
|
||||
|
||||
static class ParsePackageItemArgs {
|
||||
final Package owner;
|
||||
final String[] outError;
|
||||
@@ -672,6 +674,7 @@ public class PackageParser {
|
||||
int supportsSmallScreens = 1;
|
||||
int supportsNormalScreens = 1;
|
||||
int supportsLargeScreens = 1;
|
||||
int resizeable = 1;
|
||||
|
||||
int outerDepth = parser.getDepth();
|
||||
while ((type=parser.next()) != parser.END_DOCUMENT
|
||||
@@ -720,7 +723,7 @@ public class PackageParser {
|
||||
sa.recycle();
|
||||
|
||||
if (name != null && !pkg.requestedPermissions.contains(name)) {
|
||||
pkg.requestedPermissions.add(name);
|
||||
pkg.requestedPermissions.add(name.intern());
|
||||
}
|
||||
|
||||
XmlUtils.skipCurrentTag(parser);
|
||||
@@ -851,21 +854,6 @@ public class PackageParser {
|
||||
|
||||
XmlUtils.skipCurrentTag(parser);
|
||||
|
||||
} else if (tagName.equals("instrumentation")) {
|
||||
if (parseInstrumentation(pkg, res, parser, attrs, outError) == null) {
|
||||
return null;
|
||||
}
|
||||
} else if (tagName.equals("eat-comment")) {
|
||||
// Just skip this tag
|
||||
XmlUtils.skipCurrentTag(parser);
|
||||
continue;
|
||||
} else if (RIGID_PARSER) {
|
||||
outError[0] = "Bad element under <manifest>: "
|
||||
+ parser.getName();
|
||||
mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
|
||||
return null;
|
||||
|
||||
|
||||
} else if (tagName.equals("supports-density")) {
|
||||
sa = res.obtainAttributes(attrs,
|
||||
com.android.internal.R.styleable.AndroidManifestSupportsDensity);
|
||||
@@ -896,10 +884,50 @@ public class PackageParser {
|
||||
supportsLargeScreens = sa.getInteger(
|
||||
com.android.internal.R.styleable.AndroidManifestSupportsScreens_largeScreens,
|
||||
supportsLargeScreens);
|
||||
resizeable = sa.getInteger(
|
||||
com.android.internal.R.styleable.AndroidManifestSupportsScreens_resizeable,
|
||||
supportsLargeScreens);
|
||||
|
||||
sa.recycle();
|
||||
|
||||
XmlUtils.skipCurrentTag(parser);
|
||||
|
||||
} else if (tagName.equals("protected-broadcast")) {
|
||||
sa = res.obtainAttributes(attrs,
|
||||
com.android.internal.R.styleable.AndroidManifestProtectedBroadcast);
|
||||
|
||||
String name = sa.getNonResourceString(
|
||||
com.android.internal.R.styleable.AndroidManifestProtectedBroadcast_name);
|
||||
|
||||
sa.recycle();
|
||||
|
||||
if (name != null && (flags&PARSE_IS_SYSTEM) != 0) {
|
||||
if (pkg.protectedBroadcasts == null) {
|
||||
pkg.protectedBroadcasts = new ArrayList<String>();
|
||||
}
|
||||
if (!pkg.protectedBroadcasts.contains(name)) {
|
||||
pkg.protectedBroadcasts.add(name.intern());
|
||||
}
|
||||
}
|
||||
|
||||
XmlUtils.skipCurrentTag(parser);
|
||||
|
||||
} else if (tagName.equals("instrumentation")) {
|
||||
if (parseInstrumentation(pkg, res, parser, attrs, outError) == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
} else if (tagName.equals("eat-comment")) {
|
||||
// Just skip this tag
|
||||
XmlUtils.skipCurrentTag(parser);
|
||||
continue;
|
||||
|
||||
} else if (RIGID_PARSER) {
|
||||
outError[0] = "Bad element under <manifest>: "
|
||||
+ parser.getName();
|
||||
mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
|
||||
return null;
|
||||
|
||||
} else {
|
||||
Log.w(TAG, "Bad element under <manifest>: "
|
||||
+ parser.getName());
|
||||
@@ -945,15 +973,30 @@ public class PackageParser {
|
||||
>= android.os.Build.VERSION_CODES.CUR_DEVELOPMENT)) {
|
||||
pkg.applicationInfo.flags |= ApplicationInfo.FLAG_SUPPORTS_LARGE_SCREENS;
|
||||
}
|
||||
|
||||
if (resizeable < 0 || (resizeable > 0
|
||||
&& pkg.applicationInfo.targetSdkVersion
|
||||
>= android.os.Build.VERSION_CODES.CUR_DEVELOPMENT)) {
|
||||
pkg.applicationInfo.flags |= ApplicationInfo.FLAG_RESIZEABLE_FOR_SCREENS;
|
||||
}
|
||||
int densities[] = null;
|
||||
int size = pkg.supportsDensityList.size();
|
||||
if (size > 0) {
|
||||
int densities[] = pkg.supportsDensities = new int[size];
|
||||
densities = pkg.supportsDensities = new int[size];
|
||||
List<Integer> densityList = pkg.supportsDensityList;
|
||||
for (int i = 0; i < size; i++) {
|
||||
densities[i] = densityList.get(i);
|
||||
}
|
||||
}
|
||||
/**
|
||||
* TODO: enable this before code freeze. b/1967935
|
||||
* *
|
||||
if ((densities == null || densities.length == 0)
|
||||
&& (pkg.applicationInfo.targetSdkVersion
|
||||
>= android.os.Build.VERSION_CODES.CUR_DEVELOPMENT)) {
|
||||
pkg.supportsDensities = ApplicationInfo.ANY_DENSITIES_ARRAY;
|
||||
}
|
||||
*/
|
||||
|
||||
return pkg;
|
||||
}
|
||||
|
||||
@@ -1419,7 +1462,7 @@ public class PackageParser {
|
||||
sa.recycle();
|
||||
|
||||
if (lname != null && !owner.usesLibraries.contains(lname)) {
|
||||
owner.usesLibraries.add(lname);
|
||||
owner.usesLibraries.add(lname.intern());
|
||||
}
|
||||
|
||||
XmlUtils.skipCurrentTag(parser);
|
||||
@@ -1908,6 +1951,7 @@ public class PackageParser {
|
||||
outInfo.metaData, outError)) == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
} else if (parser.getName().equals("grant-uri-permission")) {
|
||||
TypedArray sa = res.obtainAttributes(attrs,
|
||||
com.android.internal.R.styleable.AndroidManifestGrantUriPermission);
|
||||
@@ -1931,7 +1975,7 @@ public class PackageParser {
|
||||
if (str != null) {
|
||||
pa = new PatternMatcher(str, PatternMatcher.PATTERN_SIMPLE_GLOB);
|
||||
}
|
||||
|
||||
|
||||
sa.recycle();
|
||||
|
||||
if (pa != null) {
|
||||
@@ -1946,6 +1990,101 @@ public class PackageParser {
|
||||
outInfo.info.uriPermissionPatterns = newp;
|
||||
}
|
||||
outInfo.info.grantUriPermissions = true;
|
||||
} else {
|
||||
if (!RIGID_PARSER) {
|
||||
Log.w(TAG, "Problem in package " + mArchiveSourcePath + ":");
|
||||
Log.w(TAG, "No path, pathPrefix, or pathPattern for <path-permission>");
|
||||
XmlUtils.skipCurrentTag(parser);
|
||||
continue;
|
||||
}
|
||||
outError[0] = "No path, pathPrefix, or pathPattern for <path-permission>";
|
||||
return false;
|
||||
}
|
||||
XmlUtils.skipCurrentTag(parser);
|
||||
|
||||
} else if (parser.getName().equals("path-permission")) {
|
||||
TypedArray sa = res.obtainAttributes(attrs,
|
||||
com.android.internal.R.styleable.AndroidManifestPathPermission);
|
||||
|
||||
PathPermission pa = null;
|
||||
|
||||
String permission = sa.getNonResourceString(
|
||||
com.android.internal.R.styleable.AndroidManifestPathPermission_permission);
|
||||
String readPermission = sa.getNonResourceString(
|
||||
com.android.internal.R.styleable.AndroidManifestPathPermission_readPermission);
|
||||
if (readPermission == null) {
|
||||
readPermission = permission;
|
||||
}
|
||||
String writePermission = sa.getNonResourceString(
|
||||
com.android.internal.R.styleable.AndroidManifestPathPermission_writePermission);
|
||||
if (writePermission == null) {
|
||||
writePermission = permission;
|
||||
}
|
||||
|
||||
boolean havePerm = false;
|
||||
if (readPermission != null) {
|
||||
readPermission = readPermission.intern();
|
||||
havePerm = true;
|
||||
}
|
||||
if (writePermission != null) {
|
||||
writePermission = readPermission.intern();
|
||||
havePerm = true;
|
||||
}
|
||||
|
||||
if (!havePerm) {
|
||||
if (!RIGID_PARSER) {
|
||||
Log.w(TAG, "Problem in package " + mArchiveSourcePath + ":");
|
||||
Log.w(TAG, "No readPermission or writePermssion for <path-permission>");
|
||||
XmlUtils.skipCurrentTag(parser);
|
||||
continue;
|
||||
}
|
||||
outError[0] = "No readPermission or writePermssion for <path-permission>";
|
||||
return false;
|
||||
}
|
||||
|
||||
String path = sa.getNonResourceString(
|
||||
com.android.internal.R.styleable.AndroidManifestPathPermission_path);
|
||||
if (path != null) {
|
||||
pa = new PathPermission(path,
|
||||
PatternMatcher.PATTERN_LITERAL, readPermission, writePermission);
|
||||
}
|
||||
|
||||
path = sa.getNonResourceString(
|
||||
com.android.internal.R.styleable.AndroidManifestPathPermission_pathPrefix);
|
||||
if (path != null) {
|
||||
pa = new PathPermission(path,
|
||||
PatternMatcher.PATTERN_PREFIX, readPermission, writePermission);
|
||||
}
|
||||
|
||||
path = sa.getNonResourceString(
|
||||
com.android.internal.R.styleable.AndroidManifestPathPermission_pathPattern);
|
||||
if (path != null) {
|
||||
pa = new PathPermission(path,
|
||||
PatternMatcher.PATTERN_SIMPLE_GLOB, readPermission, writePermission);
|
||||
}
|
||||
|
||||
sa.recycle();
|
||||
|
||||
if (pa != null) {
|
||||
if (outInfo.info.pathPermissions == null) {
|
||||
outInfo.info.pathPermissions = new PathPermission[1];
|
||||
outInfo.info.pathPermissions[0] = pa;
|
||||
} else {
|
||||
final int N = outInfo.info.pathPermissions.length;
|
||||
PathPermission[] newp = new PathPermission[N+1];
|
||||
System.arraycopy(outInfo.info.pathPermissions, 0, newp, 0, N);
|
||||
newp[N] = pa;
|
||||
outInfo.info.pathPermissions = newp;
|
||||
}
|
||||
} else {
|
||||
if (!RIGID_PARSER) {
|
||||
Log.w(TAG, "Problem in package " + mArchiveSourcePath + ":");
|
||||
Log.w(TAG, "No path, pathPrefix, or pathPattern for <path-permission>");
|
||||
XmlUtils.skipCurrentTag(parser);
|
||||
continue;
|
||||
}
|
||||
outError[0] = "No path, pathPrefix, or pathPattern for <path-permission>";
|
||||
return false;
|
||||
}
|
||||
XmlUtils.skipCurrentTag(parser);
|
||||
|
||||
@@ -2104,8 +2243,8 @@ public class PackageParser {
|
||||
return null;
|
||||
}
|
||||
|
||||
boolean success = true;
|
||||
|
||||
name = name.intern();
|
||||
|
||||
TypedValue v = sa.peekValue(
|
||||
com.android.internal.R.styleable.AndroidManifestMetaData_resource);
|
||||
if (v != null && v.resourceId != 0) {
|
||||
@@ -2118,7 +2257,7 @@ public class PackageParser {
|
||||
if (v != null) {
|
||||
if (v.type == TypedValue.TYPE_STRING) {
|
||||
CharSequence cs = v.coerceToString();
|
||||
data.putString(name, cs != null ? cs.toString() : null);
|
||||
data.putString(name, cs != null ? cs.toString().intern() : null);
|
||||
} else if (v.type == TypedValue.TYPE_INT_BOOLEAN) {
|
||||
data.putBoolean(name, v.data != 0);
|
||||
} else if (v.type >= TypedValue.TYPE_FIRST_INT
|
||||
@@ -2299,6 +2438,8 @@ public class PackageParser {
|
||||
|
||||
public final ArrayList<String> requestedPermissions = new ArrayList<String>();
|
||||
|
||||
public ArrayList<String> protectedBroadcasts;
|
||||
|
||||
public final ArrayList<String> usesLibraries = new ArrayList<String>();
|
||||
public String[] usesLibraryFiles = null;
|
||||
|
||||
@@ -2499,6 +2640,11 @@ public class PackageParser {
|
||||
public static ApplicationInfo generateApplicationInfo(Package p, int flags) {
|
||||
if (p == null) return null;
|
||||
if (!copyNeeded(flags, p, null)) {
|
||||
// CompatibilityMode is global state. It's safe to modify the instance
|
||||
// of the package.
|
||||
if (!sCompatibilityModeEnabled) {
|
||||
p.applicationInfo.disableCompatibilityMode();
|
||||
}
|
||||
return p.applicationInfo;
|
||||
}
|
||||
|
||||
@@ -2513,6 +2659,9 @@ public class PackageParser {
|
||||
if ((flags & PackageManager.GET_SUPPORTS_DENSITIES) != 0) {
|
||||
ai.supportsDensities = p.supportsDensities;
|
||||
}
|
||||
if (!sCompatibilityModeEnabled) {
|
||||
ai.disableCompatibilityMode();
|
||||
}
|
||||
return ai;
|
||||
}
|
||||
|
||||
@@ -2697,4 +2846,11 @@ public class PackageParser {
|
||||
+ " " + service.info.name + "}";
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @hide
|
||||
*/
|
||||
public static void setCompatibilityModeEnabled(boolean compatibilityModeEnabled) {
|
||||
sCompatibilityModeEnabled = compatibilityModeEnabled;
|
||||
}
|
||||
}
|
||||
|
||||
68
core/java/android/content/pm/PathPermission.java
Normal file
68
core/java/android/content/pm/PathPermission.java
Normal file
@@ -0,0 +1,68 @@
|
||||
/*
|
||||
* Copyright (C) 2009 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.pm;
|
||||
|
||||
import android.os.Parcel;
|
||||
import android.os.Parcelable;
|
||||
import android.os.PatternMatcher;
|
||||
|
||||
/**
|
||||
* Description of permissions needed to access a particular path
|
||||
* in a {@link ProviderInfo}.
|
||||
*/
|
||||
public class PathPermission extends PatternMatcher {
|
||||
private final String mReadPermission;
|
||||
private final String mWritePermission;
|
||||
|
||||
public PathPermission(String pattern, int type, String readPermission,
|
||||
String writePermission) {
|
||||
super(pattern, type);
|
||||
mReadPermission = readPermission;
|
||||
mWritePermission = writePermission;
|
||||
}
|
||||
|
||||
public String getReadPermission() {
|
||||
return mReadPermission;
|
||||
}
|
||||
|
||||
public String getWritePermission() {
|
||||
return mWritePermission;
|
||||
}
|
||||
|
||||
public void writeToParcel(Parcel dest, int flags) {
|
||||
super.writeToParcel(dest, flags);
|
||||
dest.writeString(mReadPermission);
|
||||
dest.writeString(mWritePermission);
|
||||
}
|
||||
|
||||
public PathPermission(Parcel src) {
|
||||
super(src);
|
||||
mReadPermission = src.readString();
|
||||
mWritePermission = src.readString();
|
||||
}
|
||||
|
||||
public static final Parcelable.Creator<PathPermission> CREATOR
|
||||
= new Parcelable.Creator<PathPermission>() {
|
||||
public PathPermission createFromParcel(Parcel source) {
|
||||
return new PathPermission(source);
|
||||
}
|
||||
|
||||
public PathPermission[] newArray(int size) {
|
||||
return new PathPermission[size];
|
||||
}
|
||||
};
|
||||
}
|
||||
@@ -28,6 +28,7 @@ import android.os.PatternMatcher;
|
||||
*/
|
||||
public final class ProviderInfo extends ComponentInfo
|
||||
implements Parcelable {
|
||||
|
||||
/** The name provider is published under content:// */
|
||||
public String authority = null;
|
||||
|
||||
@@ -56,6 +57,14 @@ public final class ProviderInfo extends ComponentInfo
|
||||
*/
|
||||
public PatternMatcher[] uriPermissionPatterns = null;
|
||||
|
||||
/**
|
||||
* If non-null, these are path-specific permissions that are allowed for
|
||||
* accessing the provider. Any permissions listed here will allow a
|
||||
* holding client to access the provider, and the provider will check
|
||||
* the URI it provides when making calls against the patterns here.
|
||||
*/
|
||||
public PathPermission[] pathPermissions = null;
|
||||
|
||||
/** If true, this content provider allows multiple instances of itself
|
||||
* to run in different process. If false, a single instances is always
|
||||
* run in {@link #processName}. */
|
||||
@@ -78,6 +87,7 @@ public final class ProviderInfo extends ComponentInfo
|
||||
writePermission = orig.writePermission;
|
||||
grantUriPermissions = orig.grantUriPermissions;
|
||||
uriPermissionPatterns = orig.uriPermissionPatterns;
|
||||
pathPermissions = orig.pathPermissions;
|
||||
multiprocess = orig.multiprocess;
|
||||
initOrder = orig.initOrder;
|
||||
isSyncable = orig.isSyncable;
|
||||
@@ -94,6 +104,7 @@ public final class ProviderInfo extends ComponentInfo
|
||||
out.writeString(writePermission);
|
||||
out.writeInt(grantUriPermissions ? 1 : 0);
|
||||
out.writeTypedArray(uriPermissionPatterns, parcelableFlags);
|
||||
out.writeTypedArray(pathPermissions, parcelableFlags);
|
||||
out.writeInt(multiprocess ? 1 : 0);
|
||||
out.writeInt(initOrder);
|
||||
out.writeInt(isSyncable ? 1 : 0);
|
||||
@@ -122,6 +133,7 @@ public final class ProviderInfo extends ComponentInfo
|
||||
writePermission = in.readString();
|
||||
grantUriPermissions = in.readInt() != 0;
|
||||
uriPermissionPatterns = in.createTypedArray(PatternMatcher.CREATOR);
|
||||
pathPermissions = in.createTypedArray(PathPermission.CREATOR);
|
||||
multiprocess = in.readInt() != 0;
|
||||
initOrder = in.readInt();
|
||||
isSyncable = in.readInt() != 0;
|
||||
|
||||
@@ -38,7 +38,12 @@ public class CompatibilityInfo {
|
||||
private static final String TAG = "CompatibilityInfo";
|
||||
|
||||
/** default compatibility info object for compatible applications */
|
||||
public static final CompatibilityInfo DEFAULT_COMPATIBILITY_INFO = new CompatibilityInfo();
|
||||
public static final CompatibilityInfo DEFAULT_COMPATIBILITY_INFO = new CompatibilityInfo() {
|
||||
@Override
|
||||
public void setExpandable(boolean expandable) {
|
||||
throw new UnsupportedOperationException("trying to change default compatibility info");
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* The default width of the screen in portrait mode.
|
||||
@@ -50,18 +55,6 @@ public class CompatibilityInfo {
|
||||
*/
|
||||
public static final int DEFAULT_PORTRAIT_HEIGHT = 480;
|
||||
|
||||
/**
|
||||
* The x-shift mode that controls the position of the content or the window under
|
||||
* compatibility mode.
|
||||
* {@see getTranslator}
|
||||
* {@see Translator#mShiftMode}
|
||||
*/
|
||||
private static final int X_SHIFT_NONE = 0;
|
||||
private static final int X_SHIFT_CONTENT = 1;
|
||||
private static final int X_SHIFT_AND_CLIP_CONTENT = 2;
|
||||
private static final int X_SHIFT_WINDOW = 3;
|
||||
|
||||
|
||||
/**
|
||||
* A compatibility flags
|
||||
*/
|
||||
@@ -76,8 +69,8 @@ public class CompatibilityInfo {
|
||||
/**
|
||||
* A flag mask to indicates that the application can expand over the original size.
|
||||
* The flag is set to true if
|
||||
* 1) Application declares its expandable in manifest file using <expandable /> or
|
||||
* 2) The screen size is same as (320 x 480) * density.
|
||||
* 1) Application declares its expandable in manifest file using <supports-screens> or
|
||||
* 2) Configuration.SCREENLAYOUT_COMPAT_NEEDED is not set
|
||||
* {@see compatibilityFlag}
|
||||
*/
|
||||
private static final int EXPANDABLE = 2;
|
||||
@@ -85,12 +78,34 @@ public class CompatibilityInfo {
|
||||
/**
|
||||
* A flag mask to tell if the application is configured to be expandable. This differs
|
||||
* from EXPANDABLE in that the application that is not expandable will be
|
||||
* marked as expandable if it runs in (320x 480) * density screen size.
|
||||
* marked as expandable if Configuration.SCREENLAYOUT_COMPAT_NEEDED is not set.
|
||||
*/
|
||||
private static final int CONFIGURED_EXPANDABLE = 4;
|
||||
|
||||
private static final int SCALING_EXPANDABLE_MASK = SCALING_REQUIRED | EXPANDABLE;
|
||||
/**
|
||||
* A flag mask to indicates that the application supports large screens.
|
||||
* The flag is set to true if
|
||||
* 1) Application declares it supports large screens in manifest file using <supports-screens> or
|
||||
* 2) The screen size is not large
|
||||
* {@see compatibilityFlag}
|
||||
*/
|
||||
private static final int LARGE_SCREENS = 8;
|
||||
|
||||
/**
|
||||
* A flag mask to tell if the application supports large screens. This differs
|
||||
* from LARGE_SCREENS in that the application that does not support large
|
||||
* screens will be marked as supporting them if the current screen is not
|
||||
* large.
|
||||
*/
|
||||
private static final int CONFIGURED_LARGE_SCREENS = 16;
|
||||
|
||||
private static final int SCALING_EXPANDABLE_MASK = SCALING_REQUIRED | EXPANDABLE | LARGE_SCREENS;
|
||||
|
||||
/**
|
||||
* The effective screen density we have selected for this application.
|
||||
*/
|
||||
public final int applicationDensity;
|
||||
|
||||
/**
|
||||
* Application's scale.
|
||||
*/
|
||||
@@ -106,62 +121,60 @@ public class CompatibilityInfo {
|
||||
*/
|
||||
public final int appFlags;
|
||||
|
||||
/**
|
||||
* Window size in Compatibility Mode, in real pixels. This is updated by
|
||||
* {@link DisplayMetrics#updateMetrics}.
|
||||
*/
|
||||
private int mWidth;
|
||||
private int mHeight;
|
||||
|
||||
/**
|
||||
* The x offset to center the window content. In X_SHIFT_WINDOW mode, the offset is added
|
||||
* to the window's layout. In X_SHIFT_CONTENT/X_SHIFT_AND_CLIP_CONTENT mode, the offset
|
||||
* is used to translate the Canvas.
|
||||
*/
|
||||
private int mXOffset;
|
||||
|
||||
public CompatibilityInfo(ApplicationInfo appInfo) {
|
||||
appFlags = appInfo.flags;
|
||||
|
||||
if ((appInfo.flags & ApplicationInfo.FLAG_SUPPORTS_LARGE_SCREENS) != 0) {
|
||||
mCompatibilityFlags = EXPANDABLE | CONFIGURED_EXPANDABLE;
|
||||
mCompatibilityFlags |= LARGE_SCREENS | CONFIGURED_LARGE_SCREENS;
|
||||
}
|
||||
if ((appInfo.flags & ApplicationInfo.FLAG_RESIZEABLE_FOR_SCREENS) != 0) {
|
||||
mCompatibilityFlags |= EXPANDABLE | CONFIGURED_EXPANDABLE;
|
||||
}
|
||||
|
||||
float packageDensityScale = -1.0f;
|
||||
int packageDensity = 0;
|
||||
if (appInfo.supportsDensities != null) {
|
||||
int minDiff = Integer.MAX_VALUE;
|
||||
for (int density : appInfo.supportsDensities) {
|
||||
if (density == ApplicationInfo.ANY_DENSITY) {
|
||||
if (density == ApplicationInfo.ANY_DENSITY) {
|
||||
packageDensity = DisplayMetrics.DENSITY_DEVICE;
|
||||
packageDensityScale = 1.0f;
|
||||
break;
|
||||
}
|
||||
int tmpDiff = Math.abs(DisplayMetrics.DEVICE_DENSITY - density);
|
||||
int tmpDiff = Math.abs(DisplayMetrics.DENSITY_DEVICE - density);
|
||||
if (tmpDiff == 0) {
|
||||
packageDensity = DisplayMetrics.DENSITY_DEVICE;
|
||||
packageDensityScale = 1.0f;
|
||||
break;
|
||||
}
|
||||
// prefer higher density (appScale>1.0), unless that's only option.
|
||||
if (tmpDiff < minDiff && packageDensityScale < 1.0f) {
|
||||
packageDensityScale = DisplayMetrics.DEVICE_DENSITY / (float) density;
|
||||
packageDensity = density;
|
||||
packageDensityScale = DisplayMetrics.DENSITY_DEVICE / (float) density;
|
||||
minDiff = tmpDiff;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (packageDensityScale > 0.0f) {
|
||||
applicationDensity = packageDensity;
|
||||
applicationScale = packageDensityScale;
|
||||
} else {
|
||||
applicationDensity = DisplayMetrics.DENSITY_DEFAULT;
|
||||
applicationScale =
|
||||
DisplayMetrics.DEVICE_DENSITY / (float) DisplayMetrics.DEFAULT_DENSITY;
|
||||
DisplayMetrics.DENSITY_DEVICE / (float) DisplayMetrics.DENSITY_DEFAULT;
|
||||
}
|
||||
|
||||
applicationInvertedScale = 1.0f / applicationScale;
|
||||
if (applicationScale != 1.0f) {
|
||||
mCompatibilityFlags |= SCALING_REQUIRED;
|
||||
}
|
||||
}
|
||||
|
||||
private CompatibilityInfo(int appFlags, int compFlags, float scale, float invertedScale) {
|
||||
private CompatibilityInfo(int appFlags, int compFlags,
|
||||
int dens, float scale, float invertedScale) {
|
||||
this.appFlags = appFlags;
|
||||
mCompatibilityFlags = compFlags;
|
||||
applicationDensity = dens;
|
||||
applicationScale = scale;
|
||||
applicationInvertedScale = invertedScale;
|
||||
}
|
||||
@@ -169,8 +182,10 @@ public class CompatibilityInfo {
|
||||
private CompatibilityInfo() {
|
||||
this(ApplicationInfo.FLAG_SUPPORTS_SMALL_SCREENS
|
||||
| ApplicationInfo.FLAG_SUPPORTS_NORMAL_SCREENS
|
||||
| ApplicationInfo.FLAG_SUPPORTS_LARGE_SCREENS,
|
||||
| ApplicationInfo.FLAG_SUPPORTS_LARGE_SCREENS
|
||||
| ApplicationInfo.FLAG_RESIZEABLE_FOR_SCREENS,
|
||||
EXPANDABLE | CONFIGURED_EXPANDABLE,
|
||||
DisplayMetrics.DENSITY_DEVICE,
|
||||
1.0f,
|
||||
1.0f);
|
||||
}
|
||||
@@ -180,23 +195,10 @@ public class CompatibilityInfo {
|
||||
*/
|
||||
public CompatibilityInfo copy() {
|
||||
CompatibilityInfo info = new CompatibilityInfo(appFlags, mCompatibilityFlags,
|
||||
applicationScale, applicationInvertedScale);
|
||||
info.setVisibleRect(mXOffset, mWidth, mHeight);
|
||||
applicationDensity, applicationScale, applicationInvertedScale);
|
||||
return info;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the application's visible rect in compatibility mode.
|
||||
* @param xOffset the application's x offset that is added to center the content.
|
||||
* @param widthPixels the application's width in real pixels on the screen.
|
||||
* @param heightPixels the application's height in real pixels on the screen.
|
||||
*/
|
||||
public void setVisibleRect(int xOffset, int widthPixels, int heightPixels) {
|
||||
this.mXOffset = xOffset;
|
||||
mWidth = widthPixels;
|
||||
mHeight = heightPixels;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets expandable bit in the compatibility flag.
|
||||
*/
|
||||
@@ -208,6 +210,17 @@ public class CompatibilityInfo {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets large screen bit in the compatibility flag.
|
||||
*/
|
||||
public void setLargeScreens(boolean expandable) {
|
||||
if (expandable) {
|
||||
mCompatibilityFlags |= CompatibilityInfo.LARGE_SCREENS;
|
||||
} else {
|
||||
mCompatibilityFlags &= ~CompatibilityInfo.LARGE_SCREENS;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return true if the application is configured to be expandable.
|
||||
*/
|
||||
@@ -215,6 +228,13 @@ public class CompatibilityInfo {
|
||||
return (mCompatibilityFlags & CompatibilityInfo.CONFIGURED_EXPANDABLE) != 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return true if the application is configured to be expandable.
|
||||
*/
|
||||
public boolean isConfiguredLargeScreens() {
|
||||
return (mCompatibilityFlags & CompatibilityInfo.CONFIGURED_LARGE_SCREENS) != 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return true if the scaling is required
|
||||
*/
|
||||
@@ -222,67 +242,32 @@ public class CompatibilityInfo {
|
||||
return (mCompatibilityFlags & SCALING_REQUIRED) != 0;
|
||||
}
|
||||
|
||||
public boolean supportsScreen() {
|
||||
return (mCompatibilityFlags & (EXPANDABLE|LARGE_SCREENS))
|
||||
== (EXPANDABLE|LARGE_SCREENS);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "CompatibilityInfo{scale=" + applicationScale +
|
||||
", compatibility flag=" + mCompatibilityFlags + "}";
|
||||
", supports screen=" + supportsScreen() + "}";
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the translator which can translate the coordinates of the window.
|
||||
* There are five different types of Translator.
|
||||
*
|
||||
* 1) {@link CompatibilityInfo#X_SHIFT_AND_CLIP_CONTENT}
|
||||
* Shift and clip the content of the window at drawing time. Used for activities'
|
||||
* main window (with no gravity).
|
||||
* 2) {@link CompatibilityInfo#X_SHIFT_CONTENT}
|
||||
* Shift the content of the window at drawing time. Used for windows that is created by
|
||||
* an application and expected to be aligned with the application window.
|
||||
* 3) {@link CompatibilityInfo#X_SHIFT_WINDOW}
|
||||
* Create the window with adjusted x- coordinates. This is typically used
|
||||
* in popup window, where it has to be placed relative to main window.
|
||||
* 4) {@link CompatibilityInfo#X_SHIFT_NONE}
|
||||
* No adjustment required, such as dialog.
|
||||
* 5) Same as X_SHIFT_WINDOW, but no scaling. This is used by {@link SurfaceView}, which
|
||||
* does not require scaling, but its window's location has to be adjusted.
|
||||
*
|
||||
* @param params the window's parameter
|
||||
*/
|
||||
public Translator getTranslator(WindowManager.LayoutParams params) {
|
||||
if ( (mCompatibilityFlags & CompatibilityInfo.SCALING_EXPANDABLE_MASK)
|
||||
== CompatibilityInfo.EXPANDABLE) {
|
||||
if ( (mCompatibilityFlags & SCALING_EXPANDABLE_MASK)
|
||||
== (EXPANDABLE|LARGE_SCREENS)) {
|
||||
if (DBG) Log.d(TAG, "no translation required");
|
||||
return null;
|
||||
}
|
||||
|
||||
if ((mCompatibilityFlags & CompatibilityInfo.EXPANDABLE) == 0) {
|
||||
if ((params.flags & WindowManager.LayoutParams.FLAG_NO_COMPATIBILITY_SCALING) != 0) {
|
||||
if (DBG) Log.d(TAG, "translation for surface view selected");
|
||||
return new Translator(X_SHIFT_WINDOW, false, 1.0f, 1.0f);
|
||||
} else {
|
||||
int shiftMode;
|
||||
if (params.gravity == Gravity.NO_GRAVITY) {
|
||||
// For Regular Application window
|
||||
shiftMode = X_SHIFT_AND_CLIP_CONTENT;
|
||||
if (DBG) Log.d(TAG, "shift and clip translator");
|
||||
} else if (params.width == WindowManager.LayoutParams.FILL_PARENT) {
|
||||
// For Regular Application window
|
||||
shiftMode = X_SHIFT_CONTENT;
|
||||
if (DBG) Log.d(TAG, "shift content translator");
|
||||
} else if ((params.gravity & Gravity.LEFT) != 0 && params.x > 0) {
|
||||
shiftMode = X_SHIFT_WINDOW;
|
||||
if (DBG) Log.d(TAG, "shift window translator");
|
||||
} else {
|
||||
shiftMode = X_SHIFT_NONE;
|
||||
if (DBG) Log.d(TAG, "no content/window translator");
|
||||
}
|
||||
return new Translator(shiftMode);
|
||||
}
|
||||
} else if (isScalingRequired()) {
|
||||
return new Translator();
|
||||
} else {
|
||||
if (!isScalingRequired()) {
|
||||
return null;
|
||||
}
|
||||
return new Translator();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -290,97 +275,48 @@ public class CompatibilityInfo {
|
||||
* @hide
|
||||
*/
|
||||
public class Translator {
|
||||
final private int mShiftMode;
|
||||
final public boolean scalingRequired;
|
||||
final public float applicationScale;
|
||||
final public float applicationInvertedScale;
|
||||
|
||||
private Rect mContentInsetsBuffer = null;
|
||||
private Rect mVisibleInsets = null;
|
||||
private Rect mVisibleInsetsBuffer = null;
|
||||
|
||||
Translator(int shiftMode, boolean scalingRequired, float applicationScale,
|
||||
float applicationInvertedScale) {
|
||||
mShiftMode = shiftMode;
|
||||
this.scalingRequired = scalingRequired;
|
||||
Translator(float applicationScale, float applicationInvertedScale) {
|
||||
this.applicationScale = applicationScale;
|
||||
this.applicationInvertedScale = applicationInvertedScale;
|
||||
}
|
||||
|
||||
Translator(int shiftMode) {
|
||||
this(shiftMode,
|
||||
isScalingRequired(),
|
||||
CompatibilityInfo.this.applicationScale,
|
||||
CompatibilityInfo.this.applicationInvertedScale);
|
||||
}
|
||||
|
||||
Translator() {
|
||||
this(X_SHIFT_NONE);
|
||||
this(CompatibilityInfo.this.applicationScale,
|
||||
CompatibilityInfo.this.applicationInvertedScale);
|
||||
}
|
||||
|
||||
/**
|
||||
* Translate the screen rect to the application frame.
|
||||
*/
|
||||
public void translateRectInScreenToAppWinFrame(Rect rect) {
|
||||
if (rect.isEmpty()) return; // skip if the window size is empty.
|
||||
switch (mShiftMode) {
|
||||
case X_SHIFT_AND_CLIP_CONTENT:
|
||||
rect.intersect(0, 0, mWidth, mHeight);
|
||||
break;
|
||||
case X_SHIFT_CONTENT:
|
||||
rect.intersect(0, 0, mWidth + mXOffset, mHeight);
|
||||
break;
|
||||
case X_SHIFT_WINDOW:
|
||||
case X_SHIFT_NONE:
|
||||
break;
|
||||
}
|
||||
if (scalingRequired) {
|
||||
rect.scale(applicationInvertedScale);
|
||||
}
|
||||
rect.scale(applicationInvertedScale);
|
||||
}
|
||||
|
||||
/**
|
||||
* Translate the region in window to screen.
|
||||
*/
|
||||
public void translateRegionInWindowToScreen(Region transparentRegion) {
|
||||
switch (mShiftMode) {
|
||||
case X_SHIFT_AND_CLIP_CONTENT:
|
||||
case X_SHIFT_CONTENT:
|
||||
transparentRegion.scale(applicationScale);
|
||||
transparentRegion.translate(mXOffset, 0);
|
||||
break;
|
||||
case X_SHIFT_WINDOW:
|
||||
case X_SHIFT_NONE:
|
||||
transparentRegion.scale(applicationScale);
|
||||
}
|
||||
transparentRegion.scale(applicationScale);
|
||||
}
|
||||
|
||||
/**
|
||||
* Apply translation to the canvas that is necessary to draw the content.
|
||||
*/
|
||||
public void translateCanvas(Canvas canvas) {
|
||||
if (mShiftMode == X_SHIFT_CONTENT ||
|
||||
mShiftMode == X_SHIFT_AND_CLIP_CONTENT) {
|
||||
// TODO: clear outside when rotation is changed.
|
||||
|
||||
// Translate x-offset only when the content is shifted.
|
||||
canvas.translate(mXOffset, 0);
|
||||
}
|
||||
if (scalingRequired) {
|
||||
canvas.scale(applicationScale, applicationScale);
|
||||
}
|
||||
canvas.scale(applicationScale, applicationScale);
|
||||
}
|
||||
|
||||
/**
|
||||
* Translate the motion event captured on screen to the application's window.
|
||||
*/
|
||||
public void translateEventInScreenToAppWindow(MotionEvent event) {
|
||||
if (mShiftMode == X_SHIFT_CONTENT ||
|
||||
mShiftMode == X_SHIFT_AND_CLIP_CONTENT) {
|
||||
event.translate(-mXOffset, 0);
|
||||
}
|
||||
if (scalingRequired) {
|
||||
event.scale(applicationInvertedScale);
|
||||
}
|
||||
event.scale(applicationInvertedScale);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -388,62 +324,21 @@ public class CompatibilityInfo {
|
||||
* Screen's view.
|
||||
*/
|
||||
public void translateWindowLayout(WindowManager.LayoutParams params) {
|
||||
switch (mShiftMode) {
|
||||
case X_SHIFT_NONE:
|
||||
case X_SHIFT_AND_CLIP_CONTENT:
|
||||
case X_SHIFT_CONTENT:
|
||||
params.scale(applicationScale);
|
||||
break;
|
||||
case X_SHIFT_WINDOW:
|
||||
params.scale(applicationScale);
|
||||
params.x += mXOffset;
|
||||
break;
|
||||
}
|
||||
params.scale(applicationScale);
|
||||
}
|
||||
|
||||
/**
|
||||
* Translate a Rect in application's window to screen.
|
||||
*/
|
||||
public void translateRectInAppWindowToScreen(Rect rect) {
|
||||
// TODO Auto-generated method stub
|
||||
if (scalingRequired) {
|
||||
rect.scale(applicationScale);
|
||||
}
|
||||
switch(mShiftMode) {
|
||||
case X_SHIFT_NONE:
|
||||
case X_SHIFT_WINDOW:
|
||||
break;
|
||||
case X_SHIFT_CONTENT:
|
||||
case X_SHIFT_AND_CLIP_CONTENT:
|
||||
rect.offset(mXOffset, 0);
|
||||
break;
|
||||
}
|
||||
rect.scale(applicationScale);
|
||||
}
|
||||
|
||||
/**
|
||||
* Translate a Rect in screen coordinates into the app window's coordinates.
|
||||
*/
|
||||
public void translateRectInScreenToAppWindow(Rect rect) {
|
||||
switch (mShiftMode) {
|
||||
case X_SHIFT_NONE:
|
||||
case X_SHIFT_WINDOW:
|
||||
break;
|
||||
case X_SHIFT_CONTENT: {
|
||||
rect.intersects(mXOffset, 0, rect.right, rect.bottom);
|
||||
int dx = Math.min(mXOffset, rect.left);
|
||||
rect.offset(-dx, 0);
|
||||
break;
|
||||
}
|
||||
case X_SHIFT_AND_CLIP_CONTENT: {
|
||||
rect.intersects(mXOffset, 0, mWidth + mXOffset, mHeight);
|
||||
int dx = Math.min(mXOffset, rect.left);
|
||||
rect.offset(-dx, 0);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (scalingRequired) {
|
||||
rect.scale(applicationInvertedScale);
|
||||
}
|
||||
rect.scale(applicationInvertedScale);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -451,19 +346,7 @@ public class CompatibilityInfo {
|
||||
* @param params
|
||||
*/
|
||||
public void translateLayoutParamsInAppWindowToScreen(LayoutParams params) {
|
||||
if (scalingRequired) {
|
||||
params.scale(applicationScale);
|
||||
}
|
||||
switch (mShiftMode) {
|
||||
// the window location on these mode does not require adjustmenet.
|
||||
case X_SHIFT_NONE:
|
||||
case X_SHIFT_WINDOW:
|
||||
break;
|
||||
case X_SHIFT_CONTENT:
|
||||
case X_SHIFT_AND_CLIP_CONTENT:
|
||||
params.x += mXOffset;
|
||||
break;
|
||||
}
|
||||
params.scale(applicationScale);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -482,10 +365,31 @@ public class CompatibilityInfo {
|
||||
* the internal buffer for content insets to avoid extra object allocation.
|
||||
*/
|
||||
public Rect getTranslatedVisbileInsets(Rect visibleInsets) {
|
||||
if (mVisibleInsets == null) mVisibleInsets = new Rect();
|
||||
mVisibleInsets.set(visibleInsets);
|
||||
translateRectInAppWindowToScreen(mVisibleInsets);
|
||||
return mVisibleInsets;
|
||||
if (mVisibleInsetsBuffer == null) mVisibleInsetsBuffer = new Rect();
|
||||
mVisibleInsetsBuffer.set(visibleInsets);
|
||||
translateRectInAppWindowToScreen(mVisibleInsetsBuffer);
|
||||
return mVisibleInsetsBuffer;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the frame Rect for applications runs under compatibility mode.
|
||||
*
|
||||
* @param dm the display metrics used to compute the frame size.
|
||||
* @param orientation the orientation of the screen.
|
||||
* @param outRect the output parameter which will contain the result.
|
||||
*/
|
||||
public static void updateCompatibleScreenFrame(DisplayMetrics dm, int orientation,
|
||||
Rect outRect) {
|
||||
int width = dm.widthPixels;
|
||||
int portraitHeight = (int) (DEFAULT_PORTRAIT_HEIGHT * dm.density + 0.5f);
|
||||
int portraitWidth = (int) (DEFAULT_PORTRAIT_WIDTH * dm.density + 0.5f);
|
||||
if (orientation == Configuration.ORIENTATION_LANDSCAPE) {
|
||||
int xOffset = (width - portraitHeight) / 2 ;
|
||||
outRect.set(xOffset, 0, xOffset + portraitHeight, portraitWidth);
|
||||
} else {
|
||||
int xOffset = (width - portraitWidth) / 2 ;
|
||||
outRect.set(xOffset, 0, xOffset + portraitWidth, portraitHeight);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -41,6 +41,39 @@ public final class Configuration implements Parcelable, Comparable<Configuration
|
||||
*/
|
||||
public boolean userSetLocale;
|
||||
|
||||
public static final int SCREENLAYOUT_SIZE_MASK = 0x0f;
|
||||
public static final int SCREENLAYOUT_SIZE_UNDEFINED = 0x00;
|
||||
public static final int SCREENLAYOUT_SIZE_SMALL = 0x01;
|
||||
public static final int SCREENLAYOUT_SIZE_NORMAL = 0x02;
|
||||
public static final int SCREENLAYOUT_SIZE_LARGE = 0x03;
|
||||
|
||||
public static final int SCREENLAYOUT_LONG_MASK = 0x30;
|
||||
public static final int SCREENLAYOUT_LONG_UNDEFINED = 0x00;
|
||||
public static final int SCREENLAYOUT_LONG_NO = 0x10;
|
||||
public static final int SCREENLAYOUT_LONG_YES = 0x20;
|
||||
|
||||
/**
|
||||
* Special flag we generate to indicate that the screen layout requires
|
||||
* us to use a compatibility mode for apps that are not modern layout
|
||||
* aware.
|
||||
* @hide
|
||||
*/
|
||||
public static final int SCREENLAYOUT_COMPAT_NEEDED = 0x10000000;
|
||||
|
||||
/**
|
||||
* Bit mask of overall layout of the screen. Currently there are two
|
||||
* fields:
|
||||
* <p>The {@link #SCREENLAYOUT_SIZE_MASK} bits define the overall size
|
||||
* of the screen. They may be one of
|
||||
* {@link #SCREENLAYOUT_SIZE_SMALL}, {@link #SCREENLAYOUT_SIZE_NORMAL},
|
||||
* or {@link #SCREENLAYOUT_SIZE_LARGE}.
|
||||
*
|
||||
* <p>The {@link #SCREENLAYOUT_LONG_MASK} defines whether the screen
|
||||
* is wider/taller than normal. They may be one of
|
||||
* {@link #SCREENLAYOUT_LONG_NO} or {@link #SCREENLAYOUT_LONG_YES}.
|
||||
*/
|
||||
public int screenLayout;
|
||||
|
||||
public static final int TOUCHSCREEN_UNDEFINED = 0;
|
||||
public static final int TOUCHSCREEN_NOTOUCH = 1;
|
||||
public static final int TOUCHSCREEN_STYLUS = 2;
|
||||
@@ -116,18 +149,6 @@ public final class Configuration implements Parcelable, Comparable<Configuration
|
||||
*/
|
||||
public int orientation;
|
||||
|
||||
public static final int SCREENLAYOUT_UNDEFINED = 0;
|
||||
public static final int SCREENLAYOUT_SMALL = 1;
|
||||
public static final int SCREENLAYOUT_NORMAL = 2;
|
||||
public static final int SCREENLAYOUT_LARGE = 3;
|
||||
|
||||
/**
|
||||
* Overall layout of the screen. May be one of
|
||||
* {@link #SCREENLAYOUT_SMALL}, {@link #SCREENLAYOUT_NORMAL},
|
||||
* or {@link #SCREENLAYOUT_LARGE}.
|
||||
*/
|
||||
public int screenLayout;
|
||||
|
||||
/**
|
||||
* Construct an invalid Configuration. You must call {@link #setToDefaults}
|
||||
* for this object to be valid. {@more}
|
||||
@@ -198,7 +219,7 @@ public final class Configuration implements Parcelable, Comparable<Configuration
|
||||
hardKeyboardHidden = HARDKEYBOARDHIDDEN_UNDEFINED;
|
||||
navigation = NAVIGATION_UNDEFINED;
|
||||
orientation = ORIENTATION_UNDEFINED;
|
||||
screenLayout = SCREENLAYOUT_UNDEFINED;
|
||||
screenLayout = SCREENLAYOUT_SIZE_UNDEFINED;
|
||||
}
|
||||
|
||||
/** {@hide} */
|
||||
@@ -269,7 +290,7 @@ public final class Configuration implements Parcelable, Comparable<Configuration
|
||||
changed |= ActivityInfo.CONFIG_ORIENTATION;
|
||||
orientation = delta.orientation;
|
||||
}
|
||||
if (delta.screenLayout != SCREENLAYOUT_UNDEFINED
|
||||
if (delta.screenLayout != SCREENLAYOUT_SIZE_UNDEFINED
|
||||
&& screenLayout != delta.screenLayout) {
|
||||
changed |= ActivityInfo.CONFIG_SCREEN_LAYOUT;
|
||||
screenLayout = delta.screenLayout;
|
||||
@@ -342,7 +363,7 @@ public final class Configuration implements Parcelable, Comparable<Configuration
|
||||
&& orientation != delta.orientation) {
|
||||
changed |= ActivityInfo.CONFIG_ORIENTATION;
|
||||
}
|
||||
if (delta.screenLayout != SCREENLAYOUT_UNDEFINED
|
||||
if (delta.screenLayout != SCREENLAYOUT_SIZE_UNDEFINED
|
||||
&& screenLayout != delta.screenLayout) {
|
||||
changed |= ActivityInfo.CONFIG_SCREEN_LAYOUT;
|
||||
}
|
||||
|
||||
@@ -34,6 +34,7 @@ import android.util.Log;
|
||||
import android.util.SparseArray;
|
||||
import android.util.TypedValue;
|
||||
import android.util.LongSparseArray;
|
||||
import android.view.Display;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
@@ -86,7 +87,8 @@ public class Resources {
|
||||
/*package*/ final DisplayMetrics mMetrics = new DisplayMetrics();
|
||||
PluralRules mPluralRule;
|
||||
|
||||
private final CompatibilityInfo mCompatibilityInfo;
|
||||
private CompatibilityInfo mCompatibilityInfo;
|
||||
private Display mDefaultDisplay;
|
||||
|
||||
private static final LongSparseArray<Object> EMPTY_ARRAY = new LongSparseArray<Object>() {
|
||||
@Override
|
||||
@@ -129,53 +131,30 @@ public class Resources {
|
||||
*/
|
||||
public Resources(AssetManager assets, DisplayMetrics metrics,
|
||||
Configuration config) {
|
||||
this(assets, metrics, config, (ApplicationInfo) null);
|
||||
this(assets, metrics, config, (CompatibilityInfo) null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new Resources object with ApplicationInfo.
|
||||
* Creates a new Resources object with CompatibilityInfo.
|
||||
*
|
||||
* @param assets Previously created AssetManager.
|
||||
* @param metrics Current display metrics to consider when
|
||||
* selecting/computing resource values.
|
||||
* @param config Desired device configuration to consider when
|
||||
* selecting/computing resource values (optional).
|
||||
* @param appInfo this resource's application info.
|
||||
* @param compInfo this resource's compatibility info. It will use the default compatibility
|
||||
* info when it's null.
|
||||
* @hide
|
||||
*/
|
||||
public Resources(AssetManager assets, DisplayMetrics metrics,
|
||||
Configuration config, ApplicationInfo appInfo) {
|
||||
Configuration config, CompatibilityInfo compInfo) {
|
||||
mAssets = assets;
|
||||
mConfiguration.setToDefaults();
|
||||
mMetrics.setToDefaults();
|
||||
if (appInfo != null) {
|
||||
mCompatibilityInfo = new CompatibilityInfo(appInfo);
|
||||
if (DEBUG_CONFIG) {
|
||||
Log.d(TAG, "compatibility for " + appInfo.packageName + " : " + mCompatibilityInfo);
|
||||
}
|
||||
} else {
|
||||
if (compInfo == null) {
|
||||
mCompatibilityInfo = CompatibilityInfo.DEFAULT_COMPATIBILITY_INFO;
|
||||
}
|
||||
updateConfiguration(config, metrics);
|
||||
assets.ensureStringBlocks();
|
||||
if (mCompatibilityInfo.isScalingRequired()) {
|
||||
mPreloadedDrawables = emptySparseArray();
|
||||
} else {
|
||||
mPreloadedDrawables = sPreloadedDrawables;
|
||||
mCompatibilityInfo = compInfo;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new resources that uses the given compatibility info. Used to create
|
||||
* a context for widgets using the container's compatibility info.
|
||||
* {@see ApplicationContext#createPackageCotnext}.
|
||||
* @hide
|
||||
*/
|
||||
public Resources(AssetManager assets, DisplayMetrics metrics,
|
||||
Configuration config, CompatibilityInfo info) {
|
||||
mAssets = assets;
|
||||
mMetrics.setToDefaults();
|
||||
mCompatibilityInfo = info;
|
||||
updateConfiguration(config, metrics);
|
||||
assets.ensureStringBlocks();
|
||||
if (mCompatibilityInfo.isScalingRequired()) {
|
||||
@@ -1406,6 +1385,15 @@ public class Resources {
|
||||
return mCompatibilityInfo;
|
||||
}
|
||||
|
||||
/**
|
||||
* This is just for testing.
|
||||
* @hide
|
||||
*/
|
||||
public void setCompatibilityInfo(CompatibilityInfo ci) {
|
||||
mCompatibilityInfo = ci;
|
||||
updateConfiguration(mConfiguration, mMetrics);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a resource identifier for the given resource name. A fully
|
||||
* qualified resource name is of the form "package:type/entry". The first
|
||||
@@ -1938,6 +1926,24 @@ public class Resources {
|
||||
+ Integer.toHexString(id));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the display adjusted for the Resources' metrics.
|
||||
* @hide
|
||||
*/
|
||||
public Display getDefaultDisplay(Display defaultDisplay) {
|
||||
if (mDefaultDisplay == null) {
|
||||
if (!mCompatibilityInfo.isScalingRequired() && mCompatibilityInfo.supportsScreen()) {
|
||||
// the app supports the display. just use the default one.
|
||||
mDefaultDisplay = defaultDisplay;
|
||||
} else {
|
||||
// display needs adjustment.
|
||||
mDefaultDisplay = Display.createMetricsBasedDisplay(
|
||||
defaultDisplay.getDisplayId(), mMetrics);
|
||||
}
|
||||
}
|
||||
return mDefaultDisplay;
|
||||
}
|
||||
|
||||
private TypedArray getCachedStyledAttributes(int len) {
|
||||
synchronized (mTmpValue) {
|
||||
TypedArray attrs = mCachedStyledAttributes;
|
||||
|
||||
Reference in New Issue
Block a user