donut snapshot

This commit is contained in:
Jean-Baptiste Queru
2009-07-29 14:25:07 -07:00
parent cf4550c319
commit a8675f67e3
326 changed files with 18109 additions and 5040 deletions

View File

@@ -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 {

View File

@@ -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();
}

View File

@@ -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..

View File

@@ -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"}.

View File

@@ -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);

View File

@@ -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;
}
}

View File

@@ -71,6 +71,8 @@ interface IPackageManager {
void removePermission(String name);
boolean isProtectedBroadcast(String actionName);
int checkSignatures(String pkg1, String pkg2);
String[] getPackagesForUid(int uid);

View File

@@ -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;
}
}

View 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];
}
};
}

View File

@@ -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;

View File

@@ -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);
}
}
}

View File

@@ -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;
}

View File

@@ -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;