Merge "Give IMEs the entire screen to use for measuring purposes." into klp-dev
diff --git a/api/current.txt b/api/current.txt
index 40c7bf5..abb330e 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -7497,11 +7497,13 @@
public class AssetFileDescriptor implements java.io.Closeable android.os.Parcelable {
ctor public AssetFileDescriptor(android.os.ParcelFileDescriptor, long, long);
+ ctor public AssetFileDescriptor(android.os.ParcelFileDescriptor, long, long, android.os.Bundle);
method public void close() throws java.io.IOException;
method public java.io.FileInputStream createInputStream() throws java.io.IOException;
method public java.io.FileOutputStream createOutputStream() throws java.io.IOException;
method public int describeContents();
method public long getDeclaredLength();
+ method public android.os.Bundle getExtras();
method public java.io.FileDescriptor getFileDescriptor();
method public long getLength();
method public android.os.ParcelFileDescriptor getParcelFileDescriptor();
diff --git a/core/java/android/app/WallpaperManager.java b/core/java/android/app/WallpaperManager.java
index c39415f..eb1f265 100644
--- a/core/java/android/app/WallpaperManager.java
+++ b/core/java/android/app/WallpaperManager.java
@@ -16,6 +16,7 @@
package android.app;
+import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
@@ -72,6 +73,7 @@
* an intent; instead, use {@link #getCropAndSetWallpaperIntent}.
* <p>Input: {@link Intent#getData} is the URI of the image to crop and set as wallpaper.
* <p>Output: RESULT_OK if user decided to crop/set the wallpaper, RESULT_CANCEL otherwise
+ * Activities that support this intent should specify a MIME filter of "image/*"
*/
public static final String ACTION_CROP_AND_SET_WALLPAPER =
"android.service.wallpaper.CROP_AND_SET_WALLPAPER";
@@ -657,8 +659,19 @@
* that supports cropping wallpapers, it will be preferred as the default.
* Use this method instead of directly creating a {@link #ACTION_CROP_AND_SET_WALLPAPER}
* intent.
+ *
+ * @param imageUri The image URI that will be set in the intent. The must be a content
+ * URI and its provider must resolve its type to "image/*"
+ *
+ * @throws IllegalArgumentException if the URI is not a content URI or its MIME type is
+ * not "image/*"
*/
public Intent getCropAndSetWallpaperIntent(Uri imageUri) {
+ if (!ContentResolver.SCHEME_CONTENT.equals(imageUri.getScheme())) {
+ throw new IllegalArgumentException("Image URI must be of the "
+ + ContentResolver.SCHEME_CONTENT + " scheme type");
+ }
+
final PackageManager packageManager = mContext.getPackageManager();
Intent cropAndSetWallpaperIntent =
new Intent(ACTION_CROP_AND_SET_WALLPAPER, imageUri);
@@ -680,7 +693,15 @@
// fallback crop activity
cropAndSetWallpaperIntent.setPackage("com.android.wallpapercropper");
- return cropAndSetWallpaperIntent;
+ List<ResolveInfo> cropAppList = packageManager.queryIntentActivities(
+ cropAndSetWallpaperIntent, 0);
+ if (cropAppList.size() > 0) {
+ return cropAndSetWallpaperIntent;
+ }
+ // If the URI is not of the right type, or for some reason the system wallpaper
+ // cropper doesn't exist, return null
+ throw new IllegalArgumentException("Cannot use passed URI to set wallpaper; " +
+ "check that the type returned by ContentProvider matches image/*");
}
/**
diff --git a/core/java/android/content/res/AssetFileDescriptor.java b/core/java/android/content/res/AssetFileDescriptor.java
index e4cc77f..28edde0 100644
--- a/core/java/android/content/res/AssetFileDescriptor.java
+++ b/core/java/android/content/res/AssetFileDescriptor.java
@@ -16,6 +16,7 @@
package android.content.res;
+import android.os.Bundle;
import android.os.Parcel;
import android.os.ParcelFileDescriptor;
import android.os.Parcelable;
@@ -42,17 +43,35 @@
private final ParcelFileDescriptor mFd;
private final long mStartOffset;
private final long mLength;
-
+ private final Bundle mExtras;
+
/**
* Create a new AssetFileDescriptor from the given values.
+ *
* @param fd The underlying file descriptor.
* @param startOffset The location within the file that the asset starts.
- * This must be 0 if length is UNKNOWN_LENGTH.
+ * This must be 0 if length is UNKNOWN_LENGTH.
* @param length The number of bytes of the asset, or
- * {@link #UNKNOWN_LENGTH} if it extends to the end of the file.
+ * {@link #UNKNOWN_LENGTH} if it extends to the end of the file.
*/
public AssetFileDescriptor(ParcelFileDescriptor fd, long startOffset,
long length) {
+ this(fd, startOffset, length, null);
+ }
+
+ /**
+ * Create a new AssetFileDescriptor from the given values.
+ *
+ * @param fd The underlying file descriptor.
+ * @param startOffset The location within the file that the asset starts.
+ * This must be 0 if length is UNKNOWN_LENGTH.
+ * @param length The number of bytes of the asset, or
+ * {@link #UNKNOWN_LENGTH} if it extends to the end of the file.
+ * @param extras additional details that can be used to interpret the
+ * underlying file descriptor. May be null.
+ */
+ public AssetFileDescriptor(ParcelFileDescriptor fd, long startOffset,
+ long length, Bundle extras) {
if (fd == null) {
throw new IllegalArgumentException("fd must not be null");
}
@@ -63,8 +82,9 @@
mFd = fd;
mStartOffset = startOffset;
mLength = length;
+ mExtras = extras;
}
-
+
/**
* The AssetFileDescriptor contains its own ParcelFileDescriptor, which
* in addition to the normal FileDescriptor object also allows you to close
@@ -88,7 +108,15 @@
public long getStartOffset() {
return mStartOffset;
}
-
+
+ /**
+ * Returns any additional details that can be used to interpret the
+ * underlying file descriptor. May be null.
+ */
+ public Bundle getExtras() {
+ return mExtras;
+ }
+
/**
* Returns the total number of bytes of this asset entry's data. May be
* {@link #UNKNOWN_LENGTH} if the asset extends to the end of the file.
@@ -307,25 +335,37 @@
super.write(oneByte);
}
}
-
-
+
/* Parcelable interface */
+ @Override
public int describeContents() {
return mFd.describeContents();
}
+ @Override
public void writeToParcel(Parcel out, int flags) {
mFd.writeToParcel(out, flags);
out.writeLong(mStartOffset);
out.writeLong(mLength);
+ if (mExtras != null) {
+ out.writeInt(1);
+ out.writeBundle(mExtras);
+ } else {
+ out.writeInt(0);
+ }
}
AssetFileDescriptor(Parcel src) {
mFd = ParcelFileDescriptor.CREATOR.createFromParcel(src);
mStartOffset = src.readLong();
mLength = src.readLong();
+ if (src.readInt() != 0) {
+ mExtras = src.readBundle();
+ } else {
+ mExtras = null;
+ }
}
-
+
public static final Parcelable.Creator<AssetFileDescriptor> CREATOR
= new Parcelable.Creator<AssetFileDescriptor>() {
public AssetFileDescriptor createFromParcel(Parcel in) {
diff --git a/core/java/android/nfc/cardemulation/CardEmulation.java b/core/java/android/nfc/cardemulation/CardEmulation.java
index 3cd7863..58d9616 100644
--- a/core/java/android/nfc/cardemulation/CardEmulation.java
+++ b/core/java/android/nfc/cardemulation/CardEmulation.java
@@ -33,6 +33,18 @@
import java.util.HashMap;
import java.util.List;
+/**
+ * This class can be used to query the state of
+ * NFC card emulation services.
+ *
+ * For a general introduction into NFC card emulation,
+ * please read the <a href="{@docRoot}guide/topics/nfc/ce.html">
+ * NFC card emulation developer guide</a>.</p>
+ *
+ * <p class="note">Use of this class requires the
+ * {@link PackageManager#FEATURE_NFC_HOST_CARD_EMULATION} to be present
+ * on the device.
+ */
public final class CardEmulation {
static final String TAG = "CardEmulation";
@@ -50,32 +62,28 @@
"android.nfc.cardemulation.action.ACTION_CHANGE_DEFAULT";
/**
- * The category extra for {@link #ACTION_CHANGE_DEFAULT}
+ * The category extra for {@link #ACTION_CHANGE_DEFAULT}.
*
* @see #ACTION_CHANGE_DEFAULT
*/
public static final String EXTRA_CATEGORY = "category";
/**
- * The ComponentName object passed in as a parcelable
- * extra for {@link #ACTION_CHANGE_DEFAULT}
+ * The service {@link ComponentName} object passed in as an
+ * extra for {@link #ACTION_CHANGE_DEFAULT}.
*
* @see #ACTION_CHANGE_DEFAULT
*/
public static final String EXTRA_SERVICE_COMPONENT = "component";
/**
- * The payment category can be used to indicate that an AID
- * represents a payment application.
+ * Category used for NFC payment services.
*/
public static final String CATEGORY_PAYMENT = "payment";
/**
- * If an AID group does not contain a category, or the
- * specified category is not defined by the platform version
- * that is parsing the AID group, all AIDs in the group will
- * automatically be categorized under the {@link #CATEGORY_OTHER}
- * category.
+ * Category that can be used for all other card emulation
+ * services.
*/
public static final String CATEGORY_OTHER = "other";
@@ -83,49 +91,23 @@
* Return value for {@link #getSelectionModeForCategory(String)}.
*
* <p>In this mode, the user has set a default service for this
- * AID category. If a remote reader selects any of the AIDs
+ * category.
+ *
+ * <p>When using ISO-DEP card emulation with {@link HostApduService}
+ * or {@link OffHostApduService}, if a remote NFC device selects
+ * any of the Application IDs (AIDs)
* that the default service has registered in this category,
* that service will automatically be bound to to handle
* the transaction.
- *
- * <p>There are still cases where a service that is
- * not the default for a category can selected:
- * <p>
- * If a remote reader selects an AID in this category
- * that is not handled by the default service, and there is a set
- * of other services {S} that do handle this AID, the
- * user is asked if he wants to use any of the services in
- * {S} instead.
- * <p>
- * As a special case, if the size of {S} is one, containing a single service X,
- * and all AIDs X has registered in this category are not
- * registered by any other service, then X will be
- * selected automatically without asking the user.
- * <p>Example:
- * <ul>
- * <li>Service A registers AIDs "1", "2" and "3" in the category
- * <li>Service B registers AIDs "3" and "4" in the category
- * <li>Service C registers AIDs "5" and "6" in the category
- * </ul>
- * In this case, the following will happen when service A
- * is the default:
- * <ul>
- * <li>Reader selects AID "1", "2" or "3": service A is invoked automatically
- * <li>Reader selects AID "4": the user is asked to confirm he
- * wants to use service B, because its AIDs overlap with service A.
- * <li>Reader selects AID "5" or "6": service C is invoked automatically,
- * because all AIDs it has asked for are only registered by C,
- * and there is no overlap.
- * </ul>
- *
*/
public static final int SELECTION_MODE_PREFER_DEFAULT = 0;
/**
* Return value for {@link #getSelectionModeForCategory(String)}.
*
- * <p>In this mode, whenever an AID of this category is selected,
- * the user is asked which service he wants to use to handle
+ * <p>In this mode, when using ISO-DEP card emulation with {@link HostApduService}
+ * or {@link OffHostApduService}, whenever an Application ID (AID) of this category
+ * is selected, the user is asked which service he wants to use to handle
* the transaction, even if there is only one matching service.
*/
public static final int SELECTION_MODE_ALWAYS_ASK = 1;
@@ -133,13 +115,16 @@
/**
* Return value for {@link #getSelectionModeForCategory(String)}.
*
- * <p>In this mode, the user will only be asked to select a service
- * if the selected AID has been registered by multiple applications.
+ * <p>In this mode, when using ISO-DEP card emulation with {@link HostApduService}
+ * or {@link OffHostApduService}, the user will only be asked to select a service
+ * if the Application ID (AID) selected by the reader has been registered by multiple
+ * services. If there is only one service that has registered for the AID,
+ * that service will be invoked directly.
*/
public static final int SELECTION_MODE_ASK_IF_CONFLICT = 2;
static boolean sIsInitialized = false;
- static HashMap<Context, CardEmulation> sCardEmus = new HashMap();
+ static HashMap<Context, CardEmulation> sCardEmus = new HashMap<Context, CardEmulation>();
static INfcCardEmulation sService;
final Context mContext;
@@ -149,6 +134,12 @@
sService = service;
}
+ /**
+ * Helper to get an instance of this class.
+ *
+ * @param adapter A reference to an NfcAdapter object.
+ * @return
+ */
public static synchronized CardEmulation getInstance(NfcAdapter adapter) {
if (adapter == null) throw new NullPointerException("NfcAdapter is null");
Context context = adapter.getContext();
@@ -188,12 +179,19 @@
* the default service to handle a card emulation category.
*
* <p>Note that if {@link #getSelectionModeForCategory(String)}
- * returns {@link #SELECTION_MODE_ALWAYS_ASK}, this method will always
- * return false.
+ * returns {@link #SELECTION_MODE_ALWAYS_ASK} or {@link #SELECTION_MODE_ASK_IF_CONFLICT},
+ * this method will always return false. That is because in these
+ * selection modes a default can't be set at the category level. For categories where
+ * the selection mode is {@link #SELECTION_MODE_ALWAYS_ASK} or
+ * {@link #SELECTION_MODE_ASK_IF_CONFLICT}, use
+ * {@link #isDefaultServiceForAid(ComponentName, String)} to determine whether a service
+ * is the default for a specific AID.
*
* @param service The ComponentName of the service
* @param category The category
* @return whether service is currently the default service for the category.
+ *
+ * <p class="note">Requires the {@link android.Manifest.permission#NFC} permission.
*/
public boolean isDefaultServiceForCategory(ComponentName service, String category) {
try {
@@ -222,7 +220,9 @@
*
* @param service The ComponentName of the service
* @param aid The ISO7816-4 Application ID
- * @return
+ * @return whether the service is the default handler for the specified AID
+ *
+ * <p class="note">Requires the {@link android.Manifest.permission#NFC} permission.
*/
public boolean isDefaultServiceForAid(ComponentName service, String aid) {
try {
@@ -244,16 +244,16 @@
}
/**
- * Returns the application selection mode for the passed in category.
+ * Returns the service selection mode for the passed in category.
* Valid return values are:
* <p>{@link #SELECTION_MODE_PREFER_DEFAULT} the user has requested a default
- * application for this category, which will be preferred.
+ * service for this category, which will be preferred.
* <p>{@link #SELECTION_MODE_ALWAYS_ASK} the user has requested to be asked
- * every time what app he would like to use in this category.
+ * every time what service he would like to use in this category.
* <p>{@link #SELECTION_MODE_ASK_IF_CONFLICT} the user will only be asked
* to pick a service if there is a conflict.
* @param category The category, for example {@link #CATEGORY_PAYMENT}
- * @return
+ * @return the selection mode for the passed in category
*/
public int getSelectionModeForCategory(String category) {
if (CATEGORY_PAYMENT.equals(category)) {
@@ -314,6 +314,7 @@
}
}
}
+
/**
* @hide
*/
diff --git a/core/java/android/nfc/cardemulation/HostApduService.java b/core/java/android/nfc/cardemulation/HostApduService.java
index e2c3ca6..ad34e61 100644
--- a/core/java/android/nfc/cardemulation/HostApduService.java
+++ b/core/java/android/nfc/cardemulation/HostApduService.java
@@ -4,6 +4,7 @@
import android.annotation.SdkConstant.SdkConstantType;
import android.app.Service;
import android.content.Intent;
+import android.content.pm.PackageManager;
import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
@@ -13,30 +14,136 @@
import android.util.Log;
/**
- * <p>A convenience class that can be extended to implement
- * a service that processes ISO7816-4 commands on top of
- * the ISO14443-4 / IsoDep protocol (T=CL).
+ * <p>HostApduService is a convenience {@link Service} class that can be
+ * extended to emulate an NFC card inside an Android
+ * service component.
*
- * <p>To tell the platform which ISO7816 application ID (AIDs)
- * are implemented by this service, a {@link #SERVICE_META_DATA}
+ * <div class="special reference">
+ * <h3>Developer Guide</h3>
+ * For a general introduction into the topic of card emulation,
+ * please read the <a href="{@docRoot}guide/topics/nfc/ce.html">
+ * NFC card emulation developer guide.</a></p>
+ * </div>
+ *
+ * <h3>NFC Protocols</h3>
+ * <p>Cards emulated by this class are based on the NFC-Forum ISO-DEP
+ * protocol (based on ISO/IEC 14443-4) and support processing
+ * command Application Protocol Data Units (APDUs) as
+ * defined in the ISO/IEC 7816-4 specification.
+ *
+ * <h3>Service selection</h3>
+ * <p>When a remote NFC device wants to talk to your
+ * service, it sends a so-called
+ * "SELECT AID" APDU as defined in the ISO/IEC 7816-4 specification.
+ * The AID is an application identifier defined in ISO/IEC 7816-4.
+ *
+ * <p>The registration procedure for AIDs is defined in the
+ * ISO/IEC 7816-5 specification. If you don't want to register an
+ * AID, you are free to use AIDs in the proprietary range:
+ * bits 8-5 of the first byte must each be set to '1'. For example,
+ * "0xF00102030405" is a proprietary AID. If you do use proprietary
+ * AIDs, it is recommended to choose an AID of at least 6 bytes,
+ * to reduce the risk of collisions with other applications that
+ * might be using proprietary AIDs as well.
+ *
+ * <h3>AID groups</h3>
+ * <p>In some cases, a service may need to register multiple AIDs
+ * to implement a certain application, and it needs to be sure
+ * that it is the default handler for all of these AIDs (as opposed
+ * to some AIDs in the group going to another service).
+ *
+ * <p>An AID group is a list of AIDs that should be considered as
+ * belonging together by the OS. For all AIDs in an AID group, the
+ * OS will guarantee one of the following:
+ * <ul>
+ * <li>All AIDs in the group are routed to this service
+ * <li>No AIDs in the group are routed to this service
+ * </ul>
+ * In other words, there is no in-between state, where some AIDs
+ * in the group can be routed to this service, and some to another.
+ * <h3>AID groups and categories</h3>
+ * <p>Each AID group can be associated with a category. This allows
+ * the Android OS to classify services, and it allows the user to
+ * set defaults at the category level instead of the AID level.
+ *
+ * <p>You can use
+ * {@link CardEmulation#isDefaultServiceForCategory(android.content.ComponentName, String)}
+ * to determine if your service is the default handler for a category.
+ *
+ * <p>In this version of the platform, the only known categories
+ * are {@link CardEmulation#CATEGORY_PAYMENT} and {@link CardEmulation#CATEGORY_OTHER}.
+ * AID groups without a category, or with a category that is not recognized
+ * by the current platform version, will automatically be
+ * grouped into the {@link CardEmulation#CATEGORY_OTHER} category.
+ * <h3>Service AID registration</h3>
+ * <p>To tell the platform which AIDs groups
+ * are requested by this service, a {@link #SERVICE_META_DATA}
* entry must be included in the declaration of the service. An
- * example of such a service declaration is shown below:
- * <pre> <service android:name=".MyHostApduService">
+ * example of a HostApduService manifest declaration is shown below:
+ * <pre> <service android:name=".MyHostApduService" android:exported="true" android:permission="android.permission.BIND_NFC_SERVICE">
* <intent-filter>
- * <action android:name="android.nfc.HostApduService"/>
+ * <action android:name="android.nfc.cardemulation.action.HOST_APDU_SERVICE"/>
* </intent-filter>
- * <meta-data android:name="android.nfc.HostApduService" android:resource="@xml/apduservice.xml"/>
+ * <meta-data android:name="android.nfc.cardemulation.host_apdu_ervice" android:resource="@xml/apduservice"/>
* </service></pre>
- * <p>For more details refer to {@link #SERVICE_META_DATA},
- * <code><{@link android.R.styleable#HostApduService host-apdu-service}></code>,
- * <code><{@link android.R.styleable#AidGroup aid-group}></code> and
- * <code><{@link android.R.styleable#AidFilter aid-filter}></code>.
- * <p class="note">The Android platform currently only supports a single
- * logical channel.
+ *
+ * This meta-data tag points to an apduservice.xml file.
+ * An example of this file with a single AID group declaration is shown below:
+ * <pre>
+ * <host-apdu-service xmlns:android="http://schemas.android.com/apk/res/android"
+ * android:description="@string/servicedesc" android:requireDeviceUnlock="false">
+ * <aid-group android:description="@string/aiddescription" android:category="other">
+ * <aid-filter android:name="F0010203040506"/>
+ * <aid-filter android:name="F0394148148100"/>
+ * </aid-group>
+ * </host-apdu-service>
+ * </pre>
+ *
+ * <p>The {@link android.R.styleable#HostApduService <host-apdu-service>} is required
+ * to contain a
+ * {@link android.R.styleable#HostApduService_description <android:description>}
+ * attribute that contains a user-friendly description of the service that may be shown in UI.
+ * The
+ * {@link android.R.styleable#HostApduService_requireDeviceUnlock <requireDeviceUnlock>}
+ * attribute can be used to specify that the device must be unlocked before this service
+ * can be invoked to handle APDUs.
+ * <p>The {@link android.R.styleable#HostApduService <host-apdu-service>} must
+ * contain one or more {@link android.R.styleable#AidGroup <aid-group>} tags.
+ * Each {@link android.R.styleable#AidGroup <aid-group>} must contain one or
+ * more {@link android.R.styleable#AidFilter <aid-filter>} tags, each of which
+ * contains a single AID. The AID must be specified in hexadecimal format, and contain
+ * an even number of characters.
+ * <h3>AID conflict resolution</h3>
+ * Multiple HostApduServices may be installed on a single device, and the same AID
+ * can be registered by more than one service. The Android platform resolves AID
+ * conflicts depending on which category an AID belongs to. Each category may
+ * have a different conflict resolution policy. For example, for some categories
+ * the user may be able to select a default service in the Android settings UI.
+ * For other categories, to policy may be to always ask the user which service
+ * is to be invoked in case of conflict.
+ *
+ * To query the conflict resolution policy for a certain category, see
+ * {@link CardEmulation#getSelectionModeForCategory(String)}.
+ *
+ * <h3>Data exchange</h3>
+ * <p>Once the platform has resolved a "SELECT AID" command APDU to a specific
+ * service component, the "SELECT AID" command APDU and all subsequent
+ * command APDUs will be sent to that service through
+ * {@link #processCommandApdu(byte[], Bundle)}, until either:
+ * <ul>
+ * <li>The NFC link is broken</li>
+ * <li>A "SELECT AID" APDU is received which resolves to another service</li>
+ * </ul>
+ * These two scenarios are indicated by a call to {@link #onDeactivated(int)}.
+ *
+ * <p class="note">Use of this class requires the
+ * {@link PackageManager#FEATURE_NFC_HOST_CARD_EMULATION} to be present
+ * on the device.
+ *
*/
public abstract class HostApduService extends Service {
/**
- * The {@link Intent} that must be declared as handled by the service.
+ * The {@link Intent} action that must be declared as handled by the service.
*/
@SdkConstant(SdkConstantType.SERVICE_ACTION)
public static final String SERVICE_INTERFACE =
@@ -260,7 +367,7 @@
* If you cannot return a response APDU immediately, return null
* and use the {@link #sendResponseApdu(byte[])} method later.
*
- * @param commandApdu The APDU that received from the remote device
+ * @param commandApdu The APDU that was received from the remote device
* @param extras A bundle containing extra data. May be null.
* @return a byte-array containing the response APDU, or null if no
* response APDU can be sent at this point.
diff --git a/core/java/android/nfc/cardemulation/OffHostApduService.java b/core/java/android/nfc/cardemulation/OffHostApduService.java
index 15f63f9..0d01762 100644
--- a/core/java/android/nfc/cardemulation/OffHostApduService.java
+++ b/core/java/android/nfc/cardemulation/OffHostApduService.java
@@ -4,41 +4,126 @@
import android.annotation.SdkConstant.SdkConstantType;
import android.app.Service;
import android.content.Intent;
+import android.content.pm.PackageManager;
import android.os.IBinder;
/**
- * <p>A convenience class that can be extended to implement
- * a service that registers ISO7814-4 AIDs that reside off-host,
- * for example on an embedded secure element or UICC.
+ * <p>OffHostApduService is a convenience {@link Service} class that can be
+ * extended to describe one or more NFC applications that are residing
+ * off-host, for example on an embedded secure element or a UICC.
+ *
+ * <div class="special reference">
+ * <h3>Developer Guide</h3>
+ * For a general introduction into the topic of card emulation,
+ * please read the <a href="{@docRoot}guide/topics/nfc/ce.html">
+ * NFC card emulation developer guide.</a></p>
+ * </div>
+ *
+ * <h3>NFC Protocols</h3>
+ * <p>Off-host applications represented by this class are based on the NFC-Forum ISO-DEP
+ * protocol (based on ISO/IEC 14443-4) and support processing
+ * command Application Protocol Data Units (APDUs) as
+ * defined in the ISO/IEC 7816-4 specification.
+ *
+ * <h3>Service selection</h3>
+ * <p>When a remote NFC device wants to talk to your
+ * off-host NFC application, it sends a so-called
+ * "SELECT AID" APDU as defined in the ISO/IEC 7816-4 specification.
+ * The AID is an application identifier defined in ISO/IEC 7816-4.
+ *
+ * <p>The registration procedure for AIDs is defined in the
+ * ISO/IEC 7816-5 specification. If you don't want to register an
+ * AID, you are free to use AIDs in the proprietary range:
+ * bits 8-5 of the first byte must each be set to '1'. For example,
+ * "0xF00102030405" is a proprietary AID. If you do use proprietary
+ * AIDs, it is recommended to choose an AID of at least 6 bytes,
+ * to reduce the risk of collisions with other applications that
+ * might be using proprietary AIDs as well.
+ *
+ * <h3>AID groups</h3>
+ * <p>In some cases, an off-host environment may need to register multiple AIDs
+ * to implement a certain application, and it needs to be sure
+ * that it is the default handler for all of these AIDs (as opposed
+ * to some AIDs in the group going to another service).
+ *
+ * <p>An AID group is a list of AIDs that should be considered as
+ * belonging together by the OS. For all AIDs in an AID group, the
+ * OS will guarantee one of the following:
+ * <ul>
+ * <li>All AIDs in the group are routed to the off-host execution environment
+ * <li>No AIDs in the group are routed to the off-host execution environment
+ * </ul>
+ * In other words, there is no in-between state, where some AIDs
+ * in the group can be routed to this off-host execution environment,
+ * and some to another or a host-based {@link HostApduService}.
+ * <h3>AID groups and categories</h3>
+ * <p>Each AID group can be associated with a category. This allows
+ * the Android OS to classify services, and it allows the user to
+ * set defaults at the category level instead of the AID level.
+ *
+ * <p>You can use
+ * {@link CardEmulation#isDefaultServiceForCategory(android.content.ComponentName, String)}
+ * to determine if your off-host service is the default handler for a category.
+ *
+ * <p>In this version of the platform, the only known categories
+ * are {@link CardEmulation#CATEGORY_PAYMENT} and {@link CardEmulation#CATEGORY_OTHER}.
+ * AID groups without a category, or with a category that is not recognized
+ * by the current platform version, will automatically be
+ * grouped into the {@link CardEmulation#CATEGORY_OTHER} category.
+ *
+ * <h3>Service AID registration</h3>
+ * <p>To tell the platform which AIDs
+ * reside off-host and are managed by this service, a {@link #SERVICE_META_DATA}
+ * entry must be included in the declaration of the service. An
+ * example of a OffHostApduService manifest declaration is shown below:
+ * <pre> <service android:name=".MyOffHostApduService" android:exported="true" android:permission="android.permission.BIND_NFC_SERVICE">
+ * <intent-filter>
+ * <action android:name="android.nfc.cardemulation.action.OFF_HOST_APDU_SERVICE"/>
+ * </intent-filter>
+ * <meta-data android:name="android.nfc.cardemulation.off_host_apdu_ervice" android:resource="@xml/apduservice"/>
+ * </service></pre>
+ *
+ * This meta-data tag points to an apduservice.xml file.
+ * An example of this file with a single AID group declaration is shown below:
+ * <pre>
+ * <offhost-apdu-service xmlns:android="http://schemas.android.com/apk/res/android"
+ * android:description="@string/servicedesc">
+ * <aid-group android:description="@string/subscription" android:category="other">
+ * <aid-filter android:name="F0010203040506"/>
+ * <aid-filter android:name="F0394148148100"/>
+ * </aid-group>
+ * </offhost-apdu-service>
+ * </pre>
+ *
+ * <p>The {@link android.R.styleable#OffHostApduService <offhost-apdu-service>} is required
+ * to contain a
+ * {@link android.R.styleable#OffHostApduService_description <android:description>}
+ * attribute that contains a user-friendly description of the service that may be shown in UI.
+ *
+ * <p>The {@link android.R.styleable#OffHostApduService <offhost-apdu-service>} must
+ * contain one or more {@link android.R.styleable#AidGroup <aid-group>} tags.
+ * Each {@link android.R.styleable#AidGroup <aid-group>} must contain one or
+ * more {@link android.R.styleable#AidFilter <aid-filter>} tags, each of which
+ * contains a single AID. The AID must be specified in hexadecimal format, and contain
+ * an even number of characters.
*
* <p>This registration will allow the service to be included
- * as an option for handling these AIDs on non-host execution
- * environments. The Operating System will take care of correctly
- * routing the AIDs, based on which service the user has selected
- * to be the handler for an AID.
+ * as an option for being the default handler for categories.
+ * The Android OS will take care of correctly
+ * routing the AIDs to the off-host execution environment,
+ * based on which service the user has selected to be the handler for a certain category.
*
* <p>The service may define additional actions outside of the
* Android namespace that provide further interaction with
* the off-host execution environment.
*
- * <p>To tell the platform which ISO7816 application ID (AIDs)
- * are present and handled by the app containing this service,
- * a {@link #SERVICE_META_DATA} entry must be included in the declaration
- * of the service. An example of such a service declaration is shown below:
- * <pre> <service android:name=".MyOffHostApduService">
- * <intent-filter>
- * <action android:name="android.nfc.OffHostApduService"/>
- * </intent-filter>
- * <meta-data android:name="android.nfc.OffHostApduService" android:resource="@xml/apduservice.xml"/>
- * </service></pre>
- * <p>For more details refer to {@link #SERVICE_META_DATA},
- * <code><{@link android.R.styleable#OffHostApduService offhost-apdu-service}></code>,
- * <code><{@link android.R.styleable#AidGroup aid-group}></code> and
- * <code><{@link android.R.styleable#AidFilter aid-filter}></code>.
+ * <p class="note">Use of this class requires the
+ * {@link PackageManager#FEATURE_NFC_HOST_CARD_EMULATION} to be present
+ * on the device.
*/
public abstract class OffHostApduService extends Service {
/**
- * The {@link Intent} that must be declared as handled by the service.
+ * The {@link Intent} action that must be declared as handled by the service.
*/
@SdkConstant(SdkConstantType.SERVICE_ACTION)
public static final String SERVICE_INTERFACE =
diff --git a/core/java/android/nfc/tech/NfcBarcode.java b/core/java/android/nfc/tech/NfcBarcode.java
index 76627de..8901f28 100644
--- a/core/java/android/nfc/tech/NfcBarcode.java
+++ b/core/java/android/nfc/tech/NfcBarcode.java
@@ -102,15 +102,21 @@
* </ul>
* <p>The following 12 bytes are payload:<ul>
* <li> In case of a URL payload, the payload is encoded in US-ASCII,
- * following the limitations defined in RF3987,
- * {@see http://www.ietf.org/rfc/rfc3987.txt}</li>
- * <li> In case of GS1 EPC daya, {@see http://www.gs1.org/gsmp/kc/epcglobal/tds/}
- * for more details.</li></ul>
+ * following the limitations defined in RFC3987.
+ * {@see <a href="http://www.ietf.org/rfc/rfc3987.txt">RFC 3987</a>}</li>
+ * <li> In case of GS1 EPC data, see <a href="http://www.gs1.org/gsmp/kc/epcglobal/tds/">
+ * GS1 Electronic Product Code (EPC) Tag Data Standard (TDS)</a> for more details.
+ * </li>
+ * </ul>
* <p>The last 2 bytes comprise the CRC.
* </ul>
* <p>Does not cause any RF activity and does not block.
*
* @return a byte array containing the barcode
+ * @see <a href="http://www.kovio.com/docs/kovionfcbarcode.pdf">
+ * Kovio 128-bit NFC barcode datasheet</a>
+ * @see <a href="http://kovio.com/docs/kovio-128-nfc-barcode-data-format.pdf">
+ * Kovio 128-bit NFC barcode data format</a>
*/
public byte[] getBarcode() {
switch (mType) {
diff --git a/core/java/android/os/Environment.java b/core/java/android/os/Environment.java
index db5cf1c..b5413db 100644
--- a/core/java/android/os/Environment.java
+++ b/core/java/android/os/Environment.java
@@ -686,7 +686,8 @@
* {@link #MEDIA_BAD_REMOVAL}, or {@link #MEDIA_UNMOUNTABLE}.
*/
public static String getExternalStorageState() {
- return getStorageState(getExternalStorageDirectory());
+ final File externalDir = sCurrentUser.getExternalDirsForApp()[0];
+ return getStorageState(externalDir);
}
/**
diff --git a/core/java/android/provider/DocumentsContract.java b/core/java/android/provider/DocumentsContract.java
index c5e4f21..9d35847 100644
--- a/core/java/android/provider/DocumentsContract.java
+++ b/core/java/android/provider/DocumentsContract.java
@@ -28,7 +28,9 @@
import android.database.Cursor;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
+import android.graphics.Matrix;
import android.graphics.Point;
+import android.media.ExifInterface;
import android.net.Uri;
import android.os.Bundle;
import android.os.CancellationSignal;
@@ -42,8 +44,10 @@
import libcore.io.Libcore;
import java.io.BufferedInputStream;
+import java.io.File;
import java.io.FileDescriptor;
import java.io.FileInputStream;
+import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.List;
@@ -76,6 +80,15 @@
/** {@hide} */
public static final String EXTRA_PACKAGE_NAME = "android.content.extra.PACKAGE_NAME";
+ /**
+ * Included in {@link AssetFileDescriptor#getExtras()} when returned
+ * thumbnail should be rotated.
+ *
+ * @see MediaStore.Images.ImageColumns#ORIENTATION
+ * @hide
+ */
+ public static final String EXTRA_ORIENTATION = "android.content.extra.ORIENTATION";
+
/** {@hide} */
public static final String ACTION_MANAGE_ROOT = "android.provider.action.MANAGE_ROOT";
/** {@hide} */
@@ -657,6 +670,7 @@
openOpts.putParcelable(DocumentsContract.EXTRA_THUMBNAIL_SIZE, size);
AssetFileDescriptor afd = null;
+ Bitmap bitmap = null;
try {
afd = client.openTypedAssetFileDescriptor(documentUri, "image/*", openOpts, signal);
@@ -688,21 +702,36 @@
opts.inJustDecodeBounds = false;
opts.inSampleSize = Math.min(widthSample, heightSample);
- Log.d(TAG, "Decoding with sample size " + opts.inSampleSize);
if (is != null) {
is.reset();
- return BitmapFactory.decodeStream(is, null, opts);
+ bitmap = BitmapFactory.decodeStream(is, null, opts);
} else {
try {
Libcore.os.lseek(fd, offset, SEEK_SET);
} catch (ErrnoException e) {
e.rethrowAsIOException();
}
- return BitmapFactory.decodeFileDescriptor(fd, null, opts);
+ bitmap = BitmapFactory.decodeFileDescriptor(fd, null, opts);
+ }
+
+ // Transform the bitmap if requested. We use a side-channel to
+ // communicate the orientation, since EXIF thumbnails don't contain
+ // the rotation flags of the original image.
+ final Bundle extras = afd.getExtras();
+ final int orientation = (extras != null) ? extras.getInt(EXTRA_ORIENTATION, 0) : 0;
+ if (orientation != 0) {
+ final int width = bitmap.getWidth();
+ final int height = bitmap.getHeight();
+
+ final Matrix m = new Matrix();
+ m.setRotate(orientation, width / 2, height / 2);
+ bitmap = Bitmap.createBitmap(bitmap, 0, 0, width, height, m, false);
}
} finally {
IoUtils.closeQuietly(afd);
}
+
+ return bitmap;
}
/**
@@ -770,4 +799,44 @@
client.call(METHOD_DELETE_DOCUMENT, null, in);
}
+
+ /**
+ * Open the given image for thumbnail purposes, using any embedded EXIF
+ * thumbnail if available, and providing orientation hints from the parent
+ * image.
+ *
+ * @hide
+ */
+ public static AssetFileDescriptor openImageThumbnail(File file) throws FileNotFoundException {
+ final ParcelFileDescriptor pfd = ParcelFileDescriptor.open(
+ file, ParcelFileDescriptor.MODE_READ_ONLY);
+ Bundle extras = null;
+
+ try {
+ final ExifInterface exif = new ExifInterface(file.getAbsolutePath());
+
+ switch (exif.getAttributeInt(ExifInterface.TAG_ORIENTATION, -1)) {
+ case ExifInterface.ORIENTATION_ROTATE_90:
+ extras = new Bundle(1);
+ extras.putInt(EXTRA_ORIENTATION, 90);
+ break;
+ case ExifInterface.ORIENTATION_ROTATE_180:
+ extras = new Bundle(1);
+ extras.putInt(EXTRA_ORIENTATION, 180);
+ break;
+ case ExifInterface.ORIENTATION_ROTATE_270:
+ extras = new Bundle(1);
+ extras.putInt(EXTRA_ORIENTATION, 270);
+ break;
+ }
+
+ final long[] thumb = exif.getThumbnailRange();
+ if (thumb != null) {
+ return new AssetFileDescriptor(pfd, thumb[0], thumb[1], extras);
+ }
+ } catch (IOException e) {
+ }
+
+ return new AssetFileDescriptor(pfd, 0, AssetFileDescriptor.UNKNOWN_LENGTH, extras);
+ }
}
diff --git a/core/java/android/util/Log.java b/core/java/android/util/Log.java
index 8c1cf5f..abd173a 100644
--- a/core/java/android/util/Log.java
+++ b/core/java/android/util/Log.java
@@ -253,7 +253,7 @@
* @param msg The message you would like logged.
*/
public static int wtf(String tag, String msg) {
- return wtf(tag, msg, null);
+ return wtf(LOG_ID_MAIN, tag, msg, null, false);
}
/**
@@ -262,7 +262,7 @@
* @hide
*/
public static int wtfStack(String tag, String msg) {
- return wtfStack(LOG_ID_MAIN, tag, msg);
+ return wtf(LOG_ID_MAIN, tag, msg, null, true);
}
/**
@@ -272,7 +272,7 @@
* @param tr An exception to log.
*/
public static int wtf(String tag, Throwable tr) {
- return wtf(tag, tr.getMessage(), tr);
+ return wtf(LOG_ID_MAIN, tag, tr.getMessage(), tr, false);
}
/**
@@ -283,18 +283,13 @@
* @param tr An exception to log. May be null.
*/
public static int wtf(String tag, String msg, Throwable tr) {
- return wtf(LOG_ID_MAIN, tag, msg, tr);
+ return wtf(LOG_ID_MAIN, tag, msg, tr, false);
}
- static int wtfStack(int logId, String tag, String msg) {
- TerribleFailure here = new TerribleFailure("here", null);
- here.fillInStackTrace();
- return wtf(logId, tag, msg, here);
- }
-
- static int wtf(int logId, String tag, String msg, Throwable tr) {
+ static int wtf(int logId, String tag, String msg, Throwable tr, boolean localStack) {
TerribleFailure what = new TerribleFailure(msg, tr);
- int bytes = println_native(logId, ASSERT, tag, msg + '\n' + getStackTraceString(tr));
+ int bytes = println_native(logId, ASSERT, tag, msg + '\n'
+ + getStackTraceString(localStack ? what : tr));
sWtfHandler.onTerribleFailure(tag, what);
return bytes;
}
diff --git a/core/java/android/util/Slog.java b/core/java/android/util/Slog.java
index a5c22ff..70795bb 100644
--- a/core/java/android/util/Slog.java
+++ b/core/java/android/util/Slog.java
@@ -79,19 +79,19 @@
}
public static int wtf(String tag, String msg) {
- return Log.wtf(Log.LOG_ID_SYSTEM, tag, msg, null);
+ return Log.wtf(Log.LOG_ID_SYSTEM, tag, msg, null, false);
}
public static int wtfStack(String tag, String msg) {
- return Log.wtfStack(Log.LOG_ID_SYSTEM, tag, msg);
+ return Log.wtf(Log.LOG_ID_SYSTEM, tag, msg, null, true);
}
public static int wtf(String tag, Throwable tr) {
- return Log.wtf(Log.LOG_ID_SYSTEM, tag, tr.getMessage(), tr);
+ return Log.wtf(Log.LOG_ID_SYSTEM, tag, tr.getMessage(), tr, false);
}
public static int wtf(String tag, String msg, Throwable tr) {
- return Log.wtf(Log.LOG_ID_SYSTEM, tag, msg, tr);
+ return Log.wtf(Log.LOG_ID_SYSTEM, tag, msg, tr, false);
}
public static int println(int priority, String tag, String msg) {
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 9c388dd..e2d98ed 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -18,6 +18,7 @@
import android.content.ClipData;
import android.content.Context;
+import android.content.pm.ApplicationInfo;
import android.content.res.Configuration;
import android.content.res.Resources;
import android.content.res.TypedArray;
@@ -691,9 +692,23 @@
*/
public static final int NO_ID = -1;
+ /**
+ * Signals that compatibility booleans have been initialized according to
+ * target SDK versions.
+ */
+ private static boolean sCompatibilityDone = false;
+
+ /**
+ * Use the old (broken) way of building MeasureSpecs.
+ */
private static boolean sUseBrokenMakeMeasureSpec = false;
/**
+ * Ignore any optimizations using the measure cache.
+ */
+ private static boolean sIgnoreMeasureCache = false;
+
+ /**
* This view does not want keystrokes. Use with TAKES_FOCUS_MASK when
* calling setFlags.
*/
@@ -3426,10 +3441,17 @@
mUserPaddingStart = UNDEFINED_PADDING;
mUserPaddingEnd = UNDEFINED_PADDING;
- if (!sUseBrokenMakeMeasureSpec && context != null &&
- context.getApplicationInfo().targetSdkVersion <= JELLY_BEAN_MR1) {
+ if (!sCompatibilityDone && context != null) {
+ final int targetSdkVersion = context.getApplicationInfo().targetSdkVersion;
+
// Older apps may need this compatibility hack for measurement.
- sUseBrokenMakeMeasureSpec = true;
+ sUseBrokenMakeMeasureSpec = targetSdkVersion <= JELLY_BEAN_MR1;
+
+ // Older apps expect onMeasure() to always be called on a layout pass, regardless
+ // of whether a layout was requested on that View.
+ sIgnoreMeasureCache = targetSdkVersion < KITKAT;
+
+ sCompatibilityDone = true;
}
}
@@ -16431,7 +16453,7 @@
int cacheIndex = (mPrivateFlags & PFLAG_FORCE_LAYOUT) == PFLAG_FORCE_LAYOUT ? -1 :
mMeasureCache.indexOfKey(key);
- if (cacheIndex < 0) {
+ if (cacheIndex < 0 || sIgnoreMeasureCache) {
// measure ourselves, this should set the measured dimension flag back
onMeasure(widthMeasureSpec, heightMeasureSpec);
mPrivateFlags3 &= ~PFLAG3_MEASURE_NEEDED_BEFORE_LAYOUT;
diff --git a/core/java/com/android/internal/app/ProcessStats.java b/core/java/com/android/internal/app/ProcessStats.java
index 430e43a..222e446 100644
--- a/core/java/com/android/internal/app/ProcessStats.java
+++ b/core/java/com/android/internal/app/ProcessStats.java
@@ -2918,29 +2918,38 @@
}
}
- public void clearCurrentOwner(Object owner) {
+ public void clearCurrentOwner(Object owner, boolean silently) {
if (mOwner == owner) {
- mOwner = null;
mProc.decActiveServices(mName);
if (mStartedState != STATE_NOTHING || mBoundState != STATE_NOTHING
|| mExecState != STATE_NOTHING) {
long now = SystemClock.uptimeMillis();
if (mStartedState != STATE_NOTHING) {
- Slog.wtfStack(TAG, "Service owner " + owner + " cleared while started: pkg="
- + mPackage + " service=" + mName + " proc=" + mProc);
+ if (!silently) {
+ Slog.wtfStack(TAG, "Service owner " + owner
+ + " cleared while started: pkg=" + mPackage + " service="
+ + mName + " proc=" + mProc);
+ }
setStarted(false, 0, now);
}
if (mBoundState != STATE_NOTHING) {
- Slog.wtfStack(TAG, "Service owner " + owner + " cleared while bound: pkg="
- + mPackage + " service=" + mName + " proc=" + mProc);
+ if (!silently) {
+ Slog.wtfStack(TAG, "Service owner " + owner
+ + " cleared while bound: pkg=" + mPackage + " service="
+ + mName + " proc=" + mProc);
+ }
setBound(false, 0, now);
}
if (mExecState != STATE_NOTHING) {
- Slog.wtfStack(TAG, "Service owner " + owner + " cleared while exec: pkg="
- + mPackage + " service=" + mName + " proc=" + mProc);
+ if (!silently) {
+ Slog.wtfStack(TAG, "Service owner " + owner
+ + " cleared while exec: pkg=" + mPackage + " service="
+ + mName + " proc=" + mProc);
+ }
setExecuting(false, 0, now);
}
}
+ mOwner = null;
}
}
diff --git a/core/res/res/values-mcc208-mnc01/config.xml b/core/res/res/values-mcc208-mnc01/config.xml
deleted file mode 100644
index 3b84ff2..0000000
--- a/core/res/res/values-mcc208-mnc01/config.xml
+++ /dev/null
@@ -1,39 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/*
-** Copyright 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.
-*/
--->
-
-<!-- These resources are around just to allow their values to be customized
- for different hardware and product builds. Do not translate. -->
-<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <!-- Array of ConnectivityManager.TYPE_xxxx values allowable for tethering -->
- <!-- Common options are [1, 4] for TYPE_WIFI and TYPE_MOBILE_DUN or
- <!== [0,1,5,7] for TYPE_MOBILE, TYPE_WIFI, TYPE_MOBILE_HIPRI and TYPE_BLUETOOTH -->
- <integer-array translatable="false" name="config_tether_upstream_types">
- <item>1</item>
- <item>4</item>
- <item>7</item>
- <item>9</item>
- </integer-array>
-
- <!-- String containing the apn value for tethering. May be overriden by secure settings
- TETHER_DUN_APN. Value is a comma separated series of strings:
- "name,apn,proxy,port,username,password,server,mmsc,mmsproxy,mmsport,mcc,mnc,auth,type"
- note that empty fields can be ommitted: "name,apn,,,,,,,,,310,260,,DUN" -->
- <string translatable="false" name="config_tether_apndata">Orange Internet,orange.fr,,,orange,orange,,,,,208,01,1,DUN</string>
-
-</resources>
diff --git a/core/res/res/values-mcc214-mnc03/config.xml b/core/res/res/values-mcc214-mnc03/config.xml
deleted file mode 100644
index 4a51a2f..0000000
--- a/core/res/res/values-mcc214-mnc03/config.xml
+++ /dev/null
@@ -1,39 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/*
-** Copyright 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.
-*/
--->
-
-<!-- These resources are around just to allow their values to be customized
- for different hardware and product builds. Do not translate. -->
-<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <!-- Array of ConnectivityManager.TYPE_xxxx values allowable for tethering -->
- <!-- Common options are [1, 4] for TYPE_WIFI and TYPE_MOBILE_DUN or
- <!== [0,1,5,7] for TYPE_MOBILE, TYPE_WIFI, TYPE_MOBILE_HIPRI and TYPE_BLUETOOTH -->
- <integer-array translatable="false" name="config_tether_upstream_types">
- <item>1</item>
- <item>4</item>
- <item>7</item>
- <item>9</item>
- </integer-array>
-
- <!-- String containing the apn value for tethering. May be overriden by secure settings
- TETHER_DUN_APN. Value is a comma separated series of strings:
- "name,apn,proxy,port,username,password,server,mmsc,mmsproxy,mmsport,mcc,mnc,auth,type"
- note that empty fields can be ommitted: "name,apn,,,,,,,,,310,260,,DUN" -->
- <string translatable="false" name="config_tether_apndata">Orange Internet PC,internet,,,orange,orange,,,,,214,03,1,DUN</string>
-
-</resources>
diff --git a/core/res/res/values-mcc214-mnc07/config.xml b/core/res/res/values-mcc214-mnc07/config.xml
deleted file mode 100644
index b49ad74..0000000
--- a/core/res/res/values-mcc214-mnc07/config.xml
+++ /dev/null
@@ -1,39 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/*
-** Copyright 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.
-*/
--->
-
-<!-- These resources are around just to allow their values to be customized
- for different hardware and product builds. Do not translate. -->
-<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <!-- Array of ConnectivityManager.TYPE_xxxx values allowable for tethering -->
- <!-- Common options are [1, 4] for TYPE_WIFI and TYPE_MOBILE_DUN or
- <!== [0,1,5,7] for TYPE_MOBILE, TYPE_WIFI, TYPE_MOBILE_HIPRI and TYPE_BLUETOOTH -->
- <integer-array translatable="false" name="config_tether_upstream_types">
- <item>1</item>
- <item>4</item>
- <item>7</item>
- <item>9</item>
- </integer-array>
-
- <!-- String containing the apn value for tethering. May be overriden by secure settings
- TETHER_DUN_APN. Value is a comma separated series of strings:
- "name,apn,proxy,port,username,password,server,mmsc,mmsproxy,mmsport,mcc,mnc,auth,type"
- note that empty fields can be ommitted: "name,apn,,,,,,,,,310,260,,DUN" -->
- <string translatable="false" name="config_tether_apndata">Conexión Compartida,movistar.es,,,MOVISTAR,MOVISTAR,,,,,214,07,1,DUN</string>
-
-</resources>
diff --git a/core/res/res/values-mcc222-mnc01/config.xml b/core/res/res/values-mcc222-mnc01/config.xml
deleted file mode 100644
index 6bb1196..0000000
--- a/core/res/res/values-mcc222-mnc01/config.xml
+++ /dev/null
@@ -1,38 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/*
-** Copyright 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.
-*/
--->
-
-<!-- These resources are around just to allow their values to be customized
- for different hardware and product builds. Do not translate. -->
-<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <!-- Array of ConnectivityManager.TYPE_xxxx values allowable for tethering -->
- <!-- Common options are [1, 4] for TYPE_WIFI and TYPE_MOBILE_DUN or
- <!== [0,1,5,7] for TYPE_MOBILE, TYPE_WIFI, TYPE_MOBILE_HIPRI and TYPE_BLUETOOTH -->
- <integer-array translatable="false" name="config_tether_upstream_types">
- <item>1</item>
- <item>4</item>
- <item>7</item>
- <item>9</item>
- </integer-array>
-
- <!-- String containing the apn value for tethering. May be overriden by secure settings
- TETHER_DUN_APN. Value is a comma separated series of strings:
- "name,apn,proxy,port,username,password,server,mmsc,mmsproxy,mmsport,mcc,mnc,auth,type"
- note that empty fields can be ommitted: "name,apn,,,,,,,,,310,260,,DUN" -->
- <string translatable="false" name="config_tether_apndata">TIM WEB,ibox.tim.it,,,,,,,,,222,01,,DUN</string>
-</resources>
diff --git a/core/res/res/values-mcc234-mnc33/config.xml b/core/res/res/values-mcc234-mnc33/config.xml
index 175f76e..776b570 100644
--- a/core/res/res/values-mcc234-mnc33/config.xml
+++ b/core/res/res/values-mcc234-mnc33/config.xml
@@ -20,22 +20,6 @@
<!-- These resources are around just to allow their values to be customized
for different hardware and product builds. Do not translate. -->
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <!-- Array of ConnectivityManager.TYPE_xxxx values allowable for tethering -->
- <!-- Common options are [1, 4] for TYPE_WIFI and TYPE_MOBILE_DUN or
- <!== [0,1,5,7] for TYPE_MOBILE, TYPE_WIFI, TYPE_MOBILE_HIPRI and TYPE_BLUETOOTH -->
- <integer-array translatable="false" name="config_tether_upstream_types">
- <item>1</item>
- <item>4</item>
- <item>7</item>
- <item>9</item>
- </integer-array>
-
- <!-- String containing the apn value for tethering. May be overriden by secure settings
- TETHER_DUN_APN. Value is a comma separated series of strings:
- "name,apn,proxy,port,username,password,server,mmsc,mmsproxy,mmsport,mcc,mnc,auth,type"
- note that empty fields can be ommitted: "name,apn,,,,,,,,,310,260,,DUN" -->
- <string translatable="false" name="config_tether_apndata">Consumer Broadband,consumerbroadband,,,,,,,,,234,33,,DUN</string>
-
<!-- Don't use roaming icon for considered operators -->
<string-array translatable="false" name="config_operatorConsideredNonRoaming">
<item>23430</item>
diff --git a/core/res/res/values-mcc454-mnc03/config.xml b/core/res/res/values-mcc268-mnc03/config.xml
similarity index 91%
copy from core/res/res/values-mcc454-mnc03/config.xml
copy to core/res/res/values-mcc268-mnc03/config.xml
index c7dc960..0d5fe57 100644
--- a/core/res/res/values-mcc454-mnc03/config.xml
+++ b/core/res/res/values-mcc268-mnc03/config.xml
@@ -34,7 +34,7 @@
<!-- String containing the apn value for tethering. May be overriden by secure settings
TETHER_DUN_APN. Value is a comma separated series of strings:
"name,apn,proxy,port,username,password,server,mmsc,mmsproxy,mmsport,mcc,mnc,auth,type"
- note that empty fields can be ommitted: "name,apn,,,,,,,,,310,260,,DUN" -->
- <string translatable="false" name="config_tether_apndata">3 Share,share.lte.three.com.hk,,,,,,,,,454,03,1,DUN</string>
+ note that empty fields can be ommitted: "name,apn,,,,,,,,,310,270,,DUN" -->
+ <string translatable="false" name="config_tether_apndata">Optimus HotSpot,modem,,,,,,,,,268,03,,DUN</string>
</resources>
diff --git a/core/res/res/values-mcc454-mnc03/config.xml b/core/res/res/values-mcc334-mnc050/config.xml
similarity index 91%
rename from core/res/res/values-mcc454-mnc03/config.xml
rename to core/res/res/values-mcc334-mnc050/config.xml
index c7dc960..00c4155 100644
--- a/core/res/res/values-mcc454-mnc03/config.xml
+++ b/core/res/res/values-mcc334-mnc050/config.xml
@@ -35,6 +35,6 @@
TETHER_DUN_APN. Value is a comma separated series of strings:
"name,apn,proxy,port,username,password,server,mmsc,mmsproxy,mmsport,mcc,mnc,auth,type"
note that empty fields can be ommitted: "name,apn,,,,,,,,,310,260,,DUN" -->
- <string translatable="false" name="config_tether_apndata">3 Share,share.lte.three.com.hk,,,,,,,,,454,03,1,DUN</string>
+ <string translatable="false" name="config_tether_apndata">Modem,modem.iusacellgsm.mx,,,iusacellgsm,iusacellgsm,,,,,334,050,1,DUN</string>
</resources>
diff --git a/core/res/res/values-mcc340-mnc01/config.xml b/core/res/res/values-mcc340-mnc01/config.xml
index fb71f3bc..bbab4ad 100644
--- a/core/res/res/values-mcc340-mnc01/config.xml
+++ b/core/res/res/values-mcc340-mnc01/config.xml
@@ -34,5 +34,5 @@
TETHER_DUN_APN. Value is a comma separated series of strings:
"name,apn,proxy,port,username,password,server,mmsc,mmsproxy,mmsport,mcc,mnc,auth,type"
note that empty fields can be ommitted: "name,apn,,,,,,,,,310,260,,DUN" -->
- <string translatable="false" name="config_tether_apndata">Orangeweb,orangeweb,,,,,,orange,orange,,340,01,1,DUN</string>
+ <string translatable="false" name="config_tether_apndata">Orangeweb,orangeweb,,,orange,orange,,,,,340,01,1,DUN</string>
</resources>
diff --git a/core/res/res/values-mcc454-mnc00/config.xml b/core/res/res/values-mcc454-mnc00/config.xml
deleted file mode 100644
index c92b9c7..0000000
--- a/core/res/res/values-mcc454-mnc00/config.xml
+++ /dev/null
@@ -1,40 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/*
-** Copyright 2013, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You my 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.
-*/
--->
-
-<!-- These resources are around just to allow their values to be customized
- for different hardware and product builds. -->
-<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-
- <!-- Array of ConnectivityManager.TYPE_xxxx values allowable for tethering -->
- <!-- Common options are [1, 4] for TYPE_WIFI and TYPE_MOBILE_DUN or
- <!== [0,1,5,7] for TYPE_MOBILE, TYPE_WIFI, TYPE_MOBILE_HIPRI and TYPE_BLUETOOTH -->
- <integer-array translatable="false" name="config_tether_upstream_types">
- <item>1</item>
- <item>4</item>
- <item>7</item>
- <item>9</item>
- </integer-array>
-
- <!-- String containing the apn value for tethering. May be overriden by secure settings
- TETHER_DUN_APN. Value is a comma separated series of strings:
- "name,apn,proxy,port,username,password,server,mmsc,mmsproxy,mmsport,mcc,mnc,auth,type"
- note that empty fields can be ommitted: "name,apn,,,,,,,,,310,260,,DUN" -->
- <string translatable="false" name="config_tether_apndata">1O1O tethering,lte.internet,,,,,,,,,454,00,3,DUN</string>
-
-</resources>
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 196be74..42ea384 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -588,6 +588,9 @@
<!-- Disable lockscreen translucent decor by default -->
<bool name="config_enableLockScreenTranslucentDecor">false</bool>
+ <!-- Enable translucent decor by default -->
+ <bool name="config_enableTranslucentDecor">true</bool>
+
<!-- Enable puk unlockscreen by default.
If unlock screen is disabled, the puk should be unlocked through Emergency Dialer -->
<bool name="config_enable_puk_unlock_screen">true</bool>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 0b050c7..611c085 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -1295,6 +1295,7 @@
<java-symbol type="bool" name="config_enableLockBeforeUnlockScreen" />
<java-symbol type="bool" name="config_enableLockScreenRotation" />
<java-symbol type="bool" name="config_enableLockScreenTranslucentDecor" />
+ <java-symbol type="bool" name="config_enableTranslucentDecor" />
<java-symbol type="bool" name="config_lidControlsSleep" />
<java-symbol type="bool" name="config_reverseDefaultRotation" />
<java-symbol type="bool" name="config_showNavigationBar" />
diff --git a/packages/DocumentsUI/res/values-sw720dp/styles.xml b/packages/DocumentsUI/res/values-sw720dp/styles.xml
index a581e08..19d2ebe 100644
--- a/packages/DocumentsUI/res/values-sw720dp/styles.xml
+++ b/packages/DocumentsUI/res/values-sw720dp/styles.xml
@@ -20,5 +20,6 @@
<item name="android:windowBackground">@*android:drawable/dialog_full_holo_light</item>
<item name="android:colorBackgroundCacheHint">@null</item>
<item name="android:windowIsTranslucent">true</item>
+ <item name="android:windowAnimationStyle">@*android:style/Animation.Holo.Dialog</item>
</style>
</resources>
diff --git a/packages/ExternalStorageProvider/src/com/android/externalstorage/ExternalStorageProvider.java b/packages/ExternalStorageProvider/src/com/android/externalstorage/ExternalStorageProvider.java
index 189e985..11ff2d8 100644
--- a/packages/ExternalStorageProvider/src/com/android/externalstorage/ExternalStorageProvider.java
+++ b/packages/ExternalStorageProvider/src/com/android/externalstorage/ExternalStorageProvider.java
@@ -27,6 +27,7 @@
import android.os.ParcelFileDescriptor;
import android.provider.DocumentsContract.Document;
import android.provider.DocumentsContract.Root;
+import android.provider.DocumentsContract;
import android.provider.DocumentsProvider;
import android.webkit.MimeTypeMap;
@@ -313,19 +314,7 @@
String documentId, Point sizeHint, CancellationSignal signal)
throws FileNotFoundException {
final File file = getFileForDocId(documentId);
- final ParcelFileDescriptor pfd = ParcelFileDescriptor.open(
- file, ParcelFileDescriptor.MODE_READ_ONLY);
-
- try {
- final ExifInterface exif = new ExifInterface(file.getAbsolutePath());
- final long[] thumb = exif.getThumbnailRange();
- if (thumb != null) {
- return new AssetFileDescriptor(pfd, thumb[0], thumb[1]);
- }
- } catch (IOException e) {
- }
-
- return new AssetFileDescriptor(pfd, 0, AssetFileDescriptor.UNKNOWN_LENGTH);
+ return DocumentsContract.openImageThumbnail(file);
}
private static String getTypeForFile(File file) {
diff --git a/packages/Keyguard/res/values-mcc262-mnc08/bools.xml b/packages/Keyguard/res/values-mcc262-mnc08/bools.xml
new file mode 100644
index 0000000..6cd4c55
--- /dev/null
+++ b/packages/Keyguard/res/values-mcc262-mnc08/bools.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2013 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<resources>
+ <!-- Carriers in this locale are sensitive to capitalization of carrier text.
+ This makes the entire interface consistent by switching back to normal case. -->
+ <bool name="kg_use_all_caps">false</bool>
+</resources>
diff --git a/packages/Keyguard/res/values-mcc262-mnc11/bools.xml b/packages/Keyguard/res/values-mcc262-mnc11/bools.xml
new file mode 100644
index 0000000..6cd4c55
--- /dev/null
+++ b/packages/Keyguard/res/values-mcc262-mnc11/bools.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2013 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<resources>
+ <!-- Carriers in this locale are sensitive to capitalization of carrier text.
+ This makes the entire interface consistent by switching back to normal case. -->
+ <bool name="kg_use_all_caps">false</bool>
+</resources>
diff --git a/packages/PrintSpooler/res/drawable-hdpi/ic_menu_print.png b/packages/PrintSpooler/res/drawable-hdpi/ic_menu_print.png
new file mode 100644
index 0000000..09ab1a2
--- /dev/null
+++ b/packages/PrintSpooler/res/drawable-hdpi/ic_menu_print.png
Binary files differ
diff --git a/packages/PrintSpooler/res/drawable-mdpi/ic_menu_print.png b/packages/PrintSpooler/res/drawable-mdpi/ic_menu_print.png
new file mode 100644
index 0000000..637d94e
--- /dev/null
+++ b/packages/PrintSpooler/res/drawable-mdpi/ic_menu_print.png
Binary files differ
diff --git a/packages/PrintSpooler/res/drawable-xhdpi/ic_menu_print.png b/packages/PrintSpooler/res/drawable-xhdpi/ic_menu_print.png
new file mode 100644
index 0000000..4d4b3cc
--- /dev/null
+++ b/packages/PrintSpooler/res/drawable-xhdpi/ic_menu_print.png
Binary files differ
diff --git a/packages/PrintSpooler/res/layout/print_job_config_activity_content_editing.xml b/packages/PrintSpooler/res/layout/print_job_config_activity_content_editing.xml
index 83019b9..02740a3 100644
--- a/packages/PrintSpooler/res/layout/print_job_config_activity_content_editing.xml
+++ b/packages/PrintSpooler/res/layout/print_job_config_activity_content_editing.xml
@@ -107,7 +107,7 @@
android:layout_marginStart="36dip"
android:textAppearance="@style/PrintOptionTitleTextAppearance"
android:labelFor="@+id/range_options_spinner"
- android:text="@string/label_pages">
+ android:text="@string/page_count_unknown">
</TextView>
<Spinner
diff --git a/packages/PrintSpooler/src/com/android/printspooler/PrintJobConfigActivity.java b/packages/PrintSpooler/src/com/android/printspooler/PrintJobConfigActivity.java
index 22a9950..2997707 100644
--- a/packages/PrintSpooler/src/com/android/printspooler/PrintJobConfigActivity.java
+++ b/packages/PrintSpooler/src/com/android/printspooler/PrintJobConfigActivity.java
@@ -1248,13 +1248,20 @@
continue;
}
+ // If nothing changed - done.
+ if (mCurrentPrinter.equals(printer)) {
+ return;
+ }
+
// If the current printer became available and has no
// capabilities, we refresh it.
if (mCurrentPrinter.getStatus() == PrinterInfo.STATUS_UNAVAILABLE
&& printer.getStatus() != PrinterInfo.STATUS_UNAVAILABLE
- && printer.getCapabilities() == null
- && !mCapabilitiesTimeout.isPosted()) {
- mCapabilitiesTimeout.post();
+ && printer.getCapabilities() == null) {
+ if (!mCapabilitiesTimeout.isPosted()) {
+ mCapabilitiesTimeout.post();
+ }
+ mCurrentPrinter.copyFrom(printer);
refreshCurrentPrinter();
return;
}
@@ -1268,10 +1275,10 @@
&& printer.getCapabilities() == null)) {
if (!mCapabilitiesTimeout.isPosted()) {
mCapabilitiesTimeout.post();
- mCurrentPrinter.copyFrom(printer);
- updateUi();
- return;
}
+ mCurrentPrinter.copyFrom(printer);
+ updateUi();
+ return;
}
// We just refreshed the current printer.
@@ -2168,10 +2175,17 @@
mIsPosted = false;
if (mDestinationSpinner.getSelectedItemPosition() >= 0) {
View itemView = mDestinationSpinner.getSelectedView();
- TextView titleView = (TextView) itemView.findViewById(R.id.title);
- String title = getString(R.string.printer_unavailable,
- mCurrentPrinter.getName());
- titleView.setText(title);
+ TextView titleView = (TextView) itemView.findViewById(R.id.subtitle);
+ try {
+ PackageInfo packageInfo = getPackageManager().getPackageInfo(
+ mCurrentPrinter.getId().getServiceName().getPackageName(), 0);
+ CharSequence service = packageInfo.applicationInfo.loadLabel(
+ getPackageManager());
+ String subtitle = getString(R.string.printer_unavailable, service.toString());
+ titleView.setText(subtitle);
+ } catch (NameNotFoundException nnfe) {
+ /* ignore */
+ }
}
}
}
diff --git a/packages/PrintSpooler/src/com/android/printspooler/SelectPrinterFragment.java b/packages/PrintSpooler/src/com/android/printspooler/SelectPrinterFragment.java
index d688932..be94ba4 100644
--- a/packages/PrintSpooler/src/com/android/printspooler/SelectPrinterFragment.java
+++ b/packages/PrintSpooler/src/com/android/printspooler/SelectPrinterFragment.java
@@ -93,6 +93,7 @@
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setHasOptionsMenu(true);
+ getActivity().getActionBar().setIcon(R.drawable.ic_menu_print);
}
@Override
diff --git a/packages/SettingsProvider/AndroidManifest.xml b/packages/SettingsProvider/AndroidManifest.xml
index ab2feb9..783aa03 100644
--- a/packages/SettingsProvider/AndroidManifest.xml
+++ b/packages/SettingsProvider/AndroidManifest.xml
@@ -8,7 +8,7 @@
android:process="system"
android:backupAgent="SettingsBackupAgent"
android:killAfterRestore="false"
- android:icon="@drawable/ic_launcher_settings">
+ android:icon="@mipmap/ic_launcher_settings">
<!-- todo add: android:neverEncrypt="true" -->
diff --git a/packages/SettingsProvider/res/drawable-hdpi/ic_launcher_settings.png b/packages/SettingsProvider/res/drawable-hdpi/ic_launcher_settings.png
deleted file mode 100644
index 8a5a2f7..0000000
--- a/packages/SettingsProvider/res/drawable-hdpi/ic_launcher_settings.png
+++ /dev/null
Binary files differ
diff --git a/packages/SettingsProvider/res/drawable-mdpi/ic_launcher_settings.png b/packages/SettingsProvider/res/drawable-mdpi/ic_launcher_settings.png
deleted file mode 100644
index 803439f..0000000
--- a/packages/SettingsProvider/res/drawable-mdpi/ic_launcher_settings.png
+++ /dev/null
Binary files differ
diff --git a/packages/SettingsProvider/res/drawable-xhdpi/ic_launcher_settings.png b/packages/SettingsProvider/res/drawable-xhdpi/ic_launcher_settings.png
deleted file mode 100644
index ec3c8ea..0000000
--- a/packages/SettingsProvider/res/drawable-xhdpi/ic_launcher_settings.png
+++ /dev/null
Binary files differ
diff --git a/packages/SettingsProvider/res/mipmap-hdpi/ic_launcher_settings.png b/packages/SettingsProvider/res/mipmap-hdpi/ic_launcher_settings.png
new file mode 100644
index 0000000..a8ccc89
--- /dev/null
+++ b/packages/SettingsProvider/res/mipmap-hdpi/ic_launcher_settings.png
Binary files differ
diff --git a/packages/SettingsProvider/res/mipmap-mdpi/ic_launcher_settings.png b/packages/SettingsProvider/res/mipmap-mdpi/ic_launcher_settings.png
new file mode 100644
index 0000000..69709a8
--- /dev/null
+++ b/packages/SettingsProvider/res/mipmap-mdpi/ic_launcher_settings.png
Binary files differ
diff --git a/packages/SettingsProvider/res/mipmap-xhdpi/ic_launcher_settings.png b/packages/SettingsProvider/res/mipmap-xhdpi/ic_launcher_settings.png
new file mode 100644
index 0000000..c3adce61
--- /dev/null
+++ b/packages/SettingsProvider/res/mipmap-xhdpi/ic_launcher_settings.png
Binary files differ
diff --git a/packages/SettingsProvider/res/mipmap-xxhdpi/ic_launcher_settings.png b/packages/SettingsProvider/res/mipmap-xxhdpi/ic_launcher_settings.png
new file mode 100644
index 0000000..52fe978
--- /dev/null
+++ b/packages/SettingsProvider/res/mipmap-xxhdpi/ic_launcher_settings.png
Binary files differ
diff --git a/packages/SettingsProvider/res/mipmap-xxxhdpi/ic_launcher_settings.png b/packages/SettingsProvider/res/mipmap-xxxhdpi/ic_launcher_settings.png
new file mode 100644
index 0000000..6b92795
--- /dev/null
+++ b/packages/SettingsProvider/res/mipmap-xxxhdpi/ic_launcher_settings.png
Binary files differ
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
index bc02b0d..158227f 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
@@ -47,6 +47,7 @@
import android.os.DropBoxManager;
import android.os.FileObserver;
import android.os.ParcelFileDescriptor;
+import android.os.Process;
import android.os.SystemProperties;
import android.os.UserHandle;
import android.os.UserManager;
@@ -62,6 +63,8 @@
private static final String TAG = "SettingsProvider";
private static final boolean LOCAL_LOGV = false;
+ private static final boolean USER_CHECK_THROWS = true;
+
private static final String TABLE_SYSTEM = "system";
private static final String TABLE_SECURE = "secure";
private static final String TABLE_GLOBAL = "global";
@@ -522,6 +525,14 @@
// Lazy initialize the database helper and caches for this user, if necessary
private DatabaseHelper getOrEstablishDatabase(int callingUser) {
+ if (callingUser >= Process.SYSTEM_UID) {
+ if (USER_CHECK_THROWS) {
+ throw new IllegalArgumentException("Uid rather than user handle: " + callingUser);
+ } else {
+ Slog.wtf(TAG, "establish db for uid rather than user: " + callingUser);
+ }
+ }
+
long oldId = Binder.clearCallingIdentity();
try {
DatabaseHelper dbHelper = mOpenHelpers.get(callingUser);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickSettingsModel.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickSettingsModel.java
index e6823ac..2026102 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickSettingsModel.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickSettingsModel.java
@@ -310,6 +310,7 @@
refreshBrightnessTile();
refreshRotationLockTile();
refreshRssiTile();
+ refreshLocationTile();
}
// Settings
@@ -582,6 +583,12 @@
mLocationCallback.refreshView(mLocationTile, mLocationState);
}
+ void refreshLocationTile() {
+ if (mLocationTile != null) {
+ onLocationSettingsChanged(mLocationState.enabled);
+ }
+ }
+
@Override
public void onLocationSettingsChanged(boolean locationEnabled) {
int textResId = locationEnabled ? R.string.quick_settings_location_label
diff --git a/packages/WallpaperCropper/src/com/android/photos/views/TiledImageView.java b/packages/WallpaperCropper/src/com/android/photos/views/TiledImageView.java
index 36cb438..af4199c 100644
--- a/packages/WallpaperCropper/src/com/android/photos/views/TiledImageView.java
+++ b/packages/WallpaperCropper/src/com/android/photos/views/TiledImageView.java
@@ -63,7 +63,7 @@
// Guarded by locks
public float scale;
public int centerX, centerY;
- int rotation;
+ public int rotation;
public TileSource source;
Runnable isReadyCallback;
diff --git a/packages/WallpaperCropper/src/com/android/wallpapercropper/CropView.java b/packages/WallpaperCropper/src/com/android/wallpapercropper/CropView.java
index b4e715c..14f7c1d 100644
--- a/packages/WallpaperCropper/src/com/android/wallpapercropper/CropView.java
+++ b/packages/WallpaperCropper/src/com/android/wallpapercropper/CropView.java
@@ -17,9 +17,11 @@
package com.android.wallpapercropper;
import android.content.Context;
+import android.graphics.Matrix;
import android.graphics.Point;
import android.graphics.RectF;
import android.util.AttributeSet;
+import android.util.FloatMath;
import android.view.MotionEvent;
import android.view.ScaleGestureDetector;
import android.view.ScaleGestureDetector.OnScaleGestureListener;
@@ -36,10 +38,18 @@
private long mTouchDownTime;
private float mFirstX, mFirstY;
private float mLastX, mLastY;
+ private float mCenterX, mCenterY;
private float mMinScale;
private boolean mTouchEnabled = true;
private RectF mTempEdges = new RectF();
+ private float[] mTempPoint = new float[] { 0, 0 };
+ private float[] mTempCoef = new float[] { 0, 0 };
+ private float[] mTempAdjustment = new float[] { 0, 0 };
+ private float[] mTempImageDims = new float[] { 0, 0 };
+ private float[] mTempRendererCenter = new float[] { 0, 0 };
TouchCallback mTouchCallback;
+ Matrix mRotateMatrix;
+ Matrix mInverseRotateMatrix;
public interface TouchCallback {
void onTouchDown();
@@ -54,17 +64,43 @@
public CropView(Context context, AttributeSet attrs) {
super(context, attrs);
mScaleGestureDetector = new ScaleGestureDetector(context, this);
+ mRotateMatrix = new Matrix();
+ mInverseRotateMatrix = new Matrix();
+ }
+
+ private float[] getImageDims() {
+ final float imageWidth = mRenderer.source.getImageWidth();
+ final float imageHeight = mRenderer.source.getImageHeight();
+ float[] imageDims = mTempImageDims;
+ imageDims[0] = imageWidth;
+ imageDims[1] = imageHeight;
+ mRotateMatrix.mapPoints(imageDims);
+ imageDims[0] = Math.abs(imageDims[0]);
+ imageDims[1] = Math.abs(imageDims[1]);
+ return imageDims;
}
private void getEdgesHelper(RectF edgesOut) {
final float width = getWidth();
final float height = getHeight();
- final float imageWidth = mRenderer.source.getImageWidth();
- final float imageHeight = mRenderer.source.getImageHeight();
+ final float[] imageDims = getImageDims();
+ final float imageWidth = imageDims[0];
+ final float imageHeight = imageDims[1];
+
+ float initialCenterX = mRenderer.source.getImageWidth() / 2f;
+ float initialCenterY = mRenderer.source.getImageHeight() / 2f;
+
+ float[] rendererCenter = mTempRendererCenter;
+ rendererCenter[0] = mCenterX - initialCenterX;
+ rendererCenter[1] = mCenterY - initialCenterY;
+ mRotateMatrix.mapPoints(rendererCenter);
+ rendererCenter[0] += imageWidth / 2;
+ rendererCenter[1] += imageHeight / 2;
+
final float scale = mRenderer.scale;
- float centerX = (width / 2f - mRenderer.centerX + (imageWidth - width) / 2f)
+ float centerX = (width / 2f - rendererCenter[0] + (imageWidth - width) / 2f)
* scale + width / 2f;
- float centerY = (height / 2f - mRenderer.centerY + (imageHeight - height) / 2f)
+ float centerY = (height / 2f - rendererCenter[1] + (imageHeight - height) / 2f)
* scale + height / 2f;
float leftEdge = centerX - imageWidth / 2f * scale;
float rightEdge = centerX + imageWidth / 2f * scale;
@@ -77,6 +113,10 @@
edgesOut.bottom = bottomEdge;
}
+ public int getImageRotation() {
+ return mRenderer.rotation;
+ }
+
public RectF getCrop() {
final RectF edges = mTempEdges;
getEdgesHelper(edges);
@@ -96,6 +136,12 @@
public void setTileSource(TileSource source, Runnable isReadyCallback) {
super.setTileSource(source, isReadyCallback);
+ mCenterX = mRenderer.centerX;
+ mCenterY = mRenderer.centerY;
+ mRotateMatrix.reset();
+ mRotateMatrix.setRotate(mRenderer.rotation);
+ mInverseRotateMatrix.reset();
+ mInverseRotateMatrix.setRotate(-mRenderer.rotation);
updateMinScale(getWidth(), getHeight(), source, true);
}
@@ -115,8 +161,10 @@
mRenderer.scale = 1;
}
if (source != null) {
- mMinScale = Math.max(w / (float) source.getImageWidth(),
- h / (float) source.getImageHeight());
+ final float[] imageDims = getImageDims();
+ final float imageWidth = imageDims[0];
+ final float imageHeight = imageDims[1];
+ mMinScale = Math.max(w / imageWidth, h / imageHeight);
mRenderer.scale = Math.max(mMinScale, mRenderer.scale);
}
}
@@ -154,7 +202,13 @@
final RectF edges = mTempEdges;
getEdgesHelper(edges);
final float scale = mRenderer.scale;
- mRenderer.centerX += Math.ceil(edges.left / scale);
+ mCenterX += Math.ceil(edges.left / scale);
+ updateCenter();
+ }
+
+ private void updateCenter() {
+ mRenderer.centerX = Math.round(mCenterX);
+ mRenderer.centerY = Math.round(mCenterY);
}
public void setTouchEnabled(boolean enabled) {
@@ -200,7 +254,7 @@
if (mTouchCallback != null) {
// only do this if it's a small movement
if (squaredDist < slop &&
- now < mTouchDownTime + ViewConfiguration.getTapTimeout()) {
+ now < mTouchDownTime + ViewConfiguration.getTapTimeout()) {
mTouchCallback.onTap();
}
mTouchCallback.onTouchUp();
@@ -215,8 +269,13 @@
mScaleGestureDetector.onTouchEvent(event);
switch (action) {
case MotionEvent.ACTION_MOVE:
- mRenderer.centerX += (mLastX - x) / mRenderer.scale;
- mRenderer.centerY += (mLastY - y) / mRenderer.scale;
+ float[] point = mTempPoint;
+ point[0] = (mLastX - x) / mRenderer.scale;
+ point[1] = (mLastY - y) / mRenderer.scale;
+ mInverseRotateMatrix.mapPoints(point);
+ mCenterX += point[0];
+ mCenterY += point[1];
+ updateCenter();
invalidate();
break;
}
@@ -226,18 +285,32 @@
final RectF edges = mTempEdges;
getEdgesHelper(edges);
final float scale = mRenderer.scale;
+
+ float[] coef = mTempCoef;
+ coef[0] = 1;
+ coef[1] = 1;
+ mRotateMatrix.mapPoints(coef);
+ float[] adjustment = mTempAdjustment;
+ mTempAdjustment[0] = 0;
+ mTempAdjustment[1] = 0;
if (edges.left > 0) {
- mRenderer.centerX += Math.ceil(edges.left / scale);
- }
- if (edges.right < getWidth()) {
- mRenderer.centerX += (edges.right - getWidth()) / scale;
+ adjustment[0] = edges.left / scale;
+ } else if (edges.right < getWidth()) {
+ adjustment[0] = (edges.right - getWidth()) / scale;
}
if (edges.top > 0) {
- mRenderer.centerY += Math.ceil(edges.top / scale);
+ adjustment[1] = FloatMath.ceil(edges.top / scale);
+ } else if (edges.bottom < getHeight()) {
+ adjustment[1] = (edges.bottom - getHeight()) / scale;
}
- if (edges.bottom < getHeight()) {
- mRenderer.centerY += (edges.bottom - getHeight()) / scale;
+ for (int dim = 0; dim <= 1; dim++) {
+ if (coef[dim] > 0) adjustment[dim] = FloatMath.ceil(adjustment[dim]);
}
+
+ mInverseRotateMatrix.mapPoints(adjustment);
+ mCenterX += adjustment[0];
+ mCenterY += adjustment[1];
+ updateCenter();
}
}
diff --git a/packages/WallpaperCropper/src/com/android/wallpapercropper/WallpaperCropActivity.java b/packages/WallpaperCropper/src/com/android/wallpapercropper/WallpaperCropActivity.java
index 710e8e4..1209e56 100644
--- a/packages/WallpaperCropper/src/com/android/wallpapercropper/WallpaperCropActivity.java
+++ b/packages/WallpaperCropper/src/com/android/wallpapercropper/WallpaperCropActivity.java
@@ -37,12 +37,14 @@
import android.net.Uri;
import android.os.AsyncTask;
import android.os.Bundle;
+import android.util.FloatMath;
import android.util.Log;
import android.view.Display;
import android.view.View;
import android.view.WindowManager;
import com.android.gallery3d.common.Utils;
+import com.android.gallery3d.exif.ExifInterface;
import com.android.photos.BitmapRegionTileSource;
import java.io.BufferedInputStream;
@@ -85,10 +87,17 @@
mCropView = (CropView) findViewById(R.id.cropView);
- Intent cropIntent = this.getIntent();
+ Intent cropIntent = getIntent();
final Uri imageUri = cropIntent.getData();
- mCropView.setTileSource(new BitmapRegionTileSource(this, imageUri, 1024, 0), null);
+ if (imageUri == null) {
+ Log.e(LOGTAG, "No URI passed in intent, exiting WallpaperCropActivity");
+ finish();
+ return;
+ }
+
+ int rotation = getRotationFromExif(this, imageUri);
+ mCropView.setTileSource(new BitmapRegionTileSource(this, imageUri, 1024, rotation), null);
mCropView.setTouchEnabled(true);
// Action bar
// Show the custom action bar view
@@ -102,8 +111,6 @@
cropImageAndSetWallpaper(imageUri, null, finishActivityWhenDone);
}
});
- getWindow().addPrivateFlags(
- WindowManager.LayoutParams.PRIVATE_FLAG_INHERIT_TRANSLUCENT_DECOR);
}
public boolean enableRotation() {
@@ -170,9 +177,47 @@
return new Point(defaultWidth, defaultHeight);
}
+ public static int getRotationFromExif(String path) {
+ return getRotationFromExifHelper(path, null, 0, null, null);
+ }
+
+ public static int getRotationFromExif(Context context, Uri uri) {
+ return getRotationFromExifHelper(null, null, 0, context, uri);
+ }
+
+ public static int getRotationFromExif(Resources res, int resId) {
+ return getRotationFromExifHelper(null, res, resId, null, null);
+ }
+
+ private static int getRotationFromExifHelper(
+ String path, Resources res, int resId, Context context, Uri uri) {
+ ExifInterface ei = new ExifInterface();
+ try {
+ if (path != null) {
+ ei.readExif(path);
+ } else if (uri != null) {
+ InputStream is = context.getContentResolver().openInputStream(uri);
+ BufferedInputStream bis = new BufferedInputStream(is);
+ ei.readExif(bis);
+ } else {
+ InputStream is = res.openRawResource(resId);
+ BufferedInputStream bis = new BufferedInputStream(is);
+ ei.readExif(bis);
+ }
+ Integer ori = ei.getTagIntValue(ExifInterface.TAG_ORIENTATION);
+ if (ori != null) {
+ return ExifInterface.getRotationForOrientationValue(ori.shortValue());
+ }
+ } catch (IOException e) {
+ Log.w(LOGTAG, "Getting exif data failed", e);
+ }
+ return 0;
+ }
+
protected void setWallpaper(String filePath, final boolean finishActivityWhenDone) {
- BitmapCropTask cropTask = new BitmapCropTask(this,
- filePath, null, 0, 0, true, false, null);
+ int rotation = getRotationFromExif(filePath);
+ BitmapCropTask cropTask = new BitmapCropTask(
+ this, filePath, null, rotation, 0, 0, true, false, null);
final Point bounds = cropTask.getImageBounds();
Runnable onEndCrop = new Runnable() {
public void run() {
@@ -192,6 +237,7 @@
Resources res, int resId, final boolean finishActivityWhenDone) {
// crop this image and scale it down to the default wallpaper size for
// this device
+ int rotation = getRotationFromExif(res, resId);
Point inSize = mCropView.getSourceDimensions();
Point outSize = getDefaultWallpaperSize(getResources(),
getWindowManager());
@@ -209,8 +255,7 @@
}
};
BitmapCropTask cropTask = new BitmapCropTask(this, res, resId,
- crop, outSize.x, outSize.y,
- true, false, onEndCrop);
+ crop, rotation, outSize.x, outSize.y, true, false, onEndCrop);
cropTask.execute();
}
@@ -222,8 +267,6 @@
protected void cropImageAndSetWallpaper(Uri uri,
OnBitmapCroppedHandler onBitmapCroppedHandler, final boolean finishActivityWhenDone) {
// Get the crop
- Point inSize = mCropView.getSourceDimensions();
-
boolean ltr = mCropView.getLayoutDirection() == View.LAYOUT_DIRECTION_LTR;
Point minDims = new Point();
@@ -262,12 +305,21 @@
}
// Get the crop
RectF cropRect = mCropView.getCrop();
+ int cropRotation = mCropView.getImageRotation();
float cropScale = mCropView.getWidth() / (float) cropRect.width();
+ Point inSize = mCropView.getSourceDimensions();
+ Matrix rotateMatrix = new Matrix();
+ rotateMatrix.setRotate(cropRotation);
+ float[] rotatedInSize = new float[] { inSize.x, inSize.y };
+ rotateMatrix.mapPoints(rotatedInSize);
+ rotatedInSize[0] = Math.abs(rotatedInSize[0]);
+ rotatedInSize[1] = Math.abs(rotatedInSize[1]);
+
// ADJUST CROP WIDTH
// Extend the crop all the way to the right, for parallax
// (or all the way to the left, in RTL)
- float extraSpace = ltr ? inSize.x - cropRect.right : cropRect.left;
+ float extraSpace = ltr ? rotatedInSize[0] - cropRect.right : cropRect.left;
// Cap the amount of extra width
float maxExtraSpace = defaultWallpaperWidth / cropScale - cropRect.width();
extraSpace = Math.min(extraSpace, maxExtraSpace);
@@ -285,7 +337,7 @@
float extraPortraitHeight =
portraitHeight / cropScale - cropRect.height();
float expandHeight =
- Math.min(Math.min(inSize.y - cropRect.bottom, cropRect.top),
+ Math.min(Math.min(rotatedInSize[1] - cropRect.bottom, cropRect.top),
extraPortraitHeight / 2);
cropRect.top -= expandHeight;
cropRect.bottom += expandHeight;
@@ -303,7 +355,7 @@
}
};
BitmapCropTask cropTask = new BitmapCropTask(this, uri,
- cropRect, outWidth, outHeight, true, false, onEndCrop);
+ cropRect, cropRotation, outWidth, outHeight, true, false, onEndCrop);
if (onBitmapCroppedHandler != null) {
cropTask.setOnBitmapCropped(onBitmapCroppedHandler);
}
@@ -323,7 +375,7 @@
InputStream mInStream;
RectF mCropBounds = null;
int mOutWidth, mOutHeight;
- int mRotation = 0; // for now
+ int mRotation;
String mOutputFormat = "jpg"; // for now
boolean mSetWallpaper;
boolean mSaveCroppedBitmap;
@@ -334,40 +386,45 @@
boolean mNoCrop;
public BitmapCropTask(Context c, String filePath,
- RectF cropBounds, int outWidth, int outHeight,
+ RectF cropBounds, int rotation, int outWidth, int outHeight,
boolean setWallpaper, boolean saveCroppedBitmap, Runnable onEndRunnable) {
mContext = c;
mInFilePath = filePath;
- init(cropBounds, outWidth, outHeight, setWallpaper, saveCroppedBitmap, onEndRunnable);
+ init(cropBounds, rotation,
+ outWidth, outHeight, setWallpaper, saveCroppedBitmap, onEndRunnable);
}
public BitmapCropTask(byte[] imageBytes,
- RectF cropBounds, int outWidth, int outHeight,
+ RectF cropBounds, int rotation, int outWidth, int outHeight,
boolean setWallpaper, boolean saveCroppedBitmap, Runnable onEndRunnable) {
mInImageBytes = imageBytes;
- init(cropBounds, outWidth, outHeight, setWallpaper, saveCroppedBitmap, onEndRunnable);
+ init(cropBounds, rotation,
+ outWidth, outHeight, setWallpaper, saveCroppedBitmap, onEndRunnable);
}
public BitmapCropTask(Context c, Uri inUri,
- RectF cropBounds, int outWidth, int outHeight,
+ RectF cropBounds, int rotation, int outWidth, int outHeight,
boolean setWallpaper, boolean saveCroppedBitmap, Runnable onEndRunnable) {
mContext = c;
mInUri = inUri;
- init(cropBounds, outWidth, outHeight, setWallpaper, saveCroppedBitmap, onEndRunnable);
+ init(cropBounds, rotation,
+ outWidth, outHeight, setWallpaper, saveCroppedBitmap, onEndRunnable);
}
public BitmapCropTask(Context c, Resources res, int inResId,
- RectF cropBounds, int outWidth, int outHeight,
+ RectF cropBounds, int rotation, int outWidth, int outHeight,
boolean setWallpaper, boolean saveCroppedBitmap, Runnable onEndRunnable) {
mContext = c;
mInResId = inResId;
mResources = res;
- init(cropBounds, outWidth, outHeight, setWallpaper, saveCroppedBitmap, onEndRunnable);
+ init(cropBounds, rotation,
+ outWidth, outHeight, setWallpaper, saveCroppedBitmap, onEndRunnable);
}
- private void init(RectF cropBounds, int outWidth, int outHeight,
+ private void init(RectF cropBounds, int rotation, int outWidth, int outHeight,
boolean setWallpaper, boolean saveCroppedBitmap, Runnable onEndRunnable) {
mCropBounds = cropBounds;
+ mRotation = rotation;
mOutWidth = outWidth;
mOutHeight = outHeight;
mSetWallpaper = setWallpaper;
@@ -454,6 +511,29 @@
if (mInStream != null) {
// Find crop bounds (scaled to original image size)
Rect roundedTrueCrop = new Rect();
+ Matrix rotateMatrix = new Matrix();
+ Matrix inverseRotateMatrix = new Matrix();
+ if (mRotation > 0) {
+ rotateMatrix.setRotate(mRotation);
+ inverseRotateMatrix.setRotate(-mRotation);
+
+ mCropBounds.roundOut(roundedTrueCrop);
+ mCropBounds = new RectF(roundedTrueCrop);
+
+ Point bounds = getImageBounds();
+
+ float[] rotatedBounds = new float[] { bounds.x, bounds.y };
+ rotateMatrix.mapPoints(rotatedBounds);
+ rotatedBounds[0] = Math.abs(rotatedBounds[0]);
+ rotatedBounds[1] = Math.abs(rotatedBounds[1]);
+
+ mCropBounds.offset(-rotatedBounds[0]/2, -rotatedBounds[1]/2);
+ inverseRotateMatrix.mapRect(mCropBounds);
+ mCropBounds.offset(bounds.x/2, bounds.y/2);
+
+ regenerateInputStream();
+ }
+
mCropBounds.roundOut(roundedTrueCrop);
if (roundedTrueCrop.width() <= 0 || roundedTrueCrop.height() <= 0) {
@@ -497,6 +577,12 @@
fullSize = BitmapFactory.decodeStream(mInStream, null, options);
}
if (fullSize != null) {
+ mCropBounds.left /= scaleDownSampleSize;
+ mCropBounds.top /= scaleDownSampleSize;
+ mCropBounds.bottom /= scaleDownSampleSize;
+ mCropBounds.right /= scaleDownSampleSize;
+ mCropBounds.roundOut(roundedTrueCrop);
+
crop = Bitmap.createBitmap(fullSize, roundedTrueCrop.left,
roundedTrueCrop.top, roundedTrueCrop.width(),
roundedTrueCrop.height());
@@ -508,16 +594,40 @@
failure = true;
return false;
}
- if (mOutWidth > 0 && mOutHeight > 0) {
- Matrix m = new Matrix();
- RectF cropRect = new RectF(0, 0, crop.getWidth(), crop.getHeight());
- if (mRotation > 0) {
- m.setRotate(mRotation);
- m.mapRect(cropRect);
+ if (mOutWidth > 0 && mOutHeight > 0 || mRotation > 0) {
+ float[] dimsAfter = new float[] { crop.getWidth(), crop.getHeight() };
+ rotateMatrix.mapPoints(dimsAfter);
+ dimsAfter[0] = Math.abs(dimsAfter[0]);
+ dimsAfter[1] = Math.abs(dimsAfter[1]);
+
+ if (!(mOutWidth > 0 && mOutHeight > 0)) {
+ mOutWidth = Math.round(dimsAfter[0]);
+ mOutHeight = Math.round(dimsAfter[1]);
}
+
+ RectF cropRect = new RectF(0, 0, dimsAfter[0], dimsAfter[1]);
RectF returnRect = new RectF(0, 0, mOutWidth, mOutHeight);
- m.setRectToRect(cropRect, returnRect, Matrix.ScaleToFit.FILL);
- m.preRotate(mRotation);
+
+ Matrix m = new Matrix();
+ if (mRotation == 0) {
+ m.setRectToRect(cropRect, returnRect, Matrix.ScaleToFit.FILL);
+ } else {
+ Matrix m1 = new Matrix();
+ m1.setTranslate(-crop.getWidth() / 2f, -crop.getHeight() / 2f);
+ Matrix m2 = new Matrix();
+ m2.setRotate(mRotation);
+ Matrix m3 = new Matrix();
+ m3.setTranslate(dimsAfter[0] / 2f, dimsAfter[1] / 2f);
+ Matrix m4 = new Matrix();
+ m4.setRectToRect(cropRect, returnRect, Matrix.ScaleToFit.FILL);
+
+ Matrix c1 = new Matrix();
+ c1.setConcat(m2, m1);
+ Matrix c2 = new Matrix();
+ c2.setConcat(m4, m3);
+ m.setConcat(c2, c1);
+ }
+
Bitmap tmp = Bitmap.createBitmap((int) returnRect.width(),
(int) returnRect.height(), Bitmap.Config.ARGB_8888);
if (tmp != null) {
@@ -527,14 +637,6 @@
c.drawBitmap(crop, m, p);
crop = tmp;
}
- } else if (mRotation > 0) {
- Matrix m = new Matrix();
- m.setRotate(mRotation);
- Bitmap tmp = Bitmap.createBitmap(crop, 0, 0, crop.getWidth(),
- crop.getHeight(), m, true);
- if (tmp != null) {
- crop = tmp;
- }
}
if (mSaveCroppedBitmap) {
@@ -603,8 +705,7 @@
final SharedPreferences sharedPrefs,
WindowManager windowManager,
final WallpaperManager wallpaperManager) {
- final Point defaultWallpaperSize =
- WallpaperCropActivity.getDefaultWallpaperSize(res, windowManager);
+ final Point defaultWallpaperSize = getDefaultWallpaperSize(res, windowManager);
new Thread("suggestWallpaperDimension") {
public void run() {
@@ -616,7 +717,6 @@
}.start();
}
-
protected static RectF getMaxCropRect(
int inWidth, int inHeight, int outWidth, int outHeight, boolean leftAligned) {
RectF cropRect = new RectF();
diff --git a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
index 5ac3ed0..1c43014 100644
--- a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
+++ b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
@@ -297,6 +297,7 @@
int mCurrentAppOrientation = ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
boolean mHasSoftInput = false;
boolean mTouchExplorationEnabled = false;
+ boolean mTranslucentDecorEnabled = true;
int mPointerLocationMode = 0; // guarded by mLock
@@ -901,6 +902,8 @@
com.android.internal.R.integer.config_lidNavigationAccessibility);
mLidControlsSleep = mContext.getResources().getBoolean(
com.android.internal.R.bool.config_lidControlsSleep);
+ mTranslucentDecorEnabled = mContext.getResources().getBoolean(
+ com.android.internal.R.bool.config_enableTranslucentDecor);
readConfigurationDependentBehaviors();
// register for dock events
@@ -2703,7 +2706,7 @@
boolean immersiveSticky = (sysui & View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY) != 0;
boolean navAllowedHidden = immersive || immersiveSticky;
navTranslucent &= !immersiveSticky; // transient trumps translucent
- navTranslucent &= isTranslucentNavigationAllowed();
+ navTranslucent &= areTranslucentBarsAllowed();
// When the navigation bar isn't visible, we put up a fake
// input window to catch all touch events. This way we can
@@ -2824,6 +2827,7 @@
boolean statusBarTransient = (sysui & View.STATUS_BAR_TRANSIENT) != 0;
boolean statusBarTranslucent = (sysui & View.STATUS_BAR_TRANSLUCENT) != 0;
+ statusBarTranslucent &= areTranslucentBarsAllowed();
// If the status bar is hidden, we don't want to cause
// windows behind it to scroll.
@@ -3565,7 +3569,8 @@
}
public boolean allowAppAnimationsLw() {
- if (mKeyguard != null && mKeyguard.isVisibleLw() || mShowingDream) {
+ if (mKeyguard != null && mKeyguard.isVisibleLw() && !mKeyguard.isAnimatingLw()
+ || mShowingDream) {
// If keyguard or dreams is currently visible, no reason to animate behind it.
return false;
}
@@ -5116,8 +5121,8 @@
vis = (vis & ~flags) | (oldVis & flags);
}
- if (!isTranslucentNavigationAllowed()) {
- vis &= ~View.NAVIGATION_BAR_TRANSLUCENT;
+ if (!areTranslucentBarsAllowed()) {
+ vis &= ~(View.NAVIGATION_BAR_TRANSLUCENT | View.STATUS_BAR_TRANSLUCENT);
}
// update status bar
@@ -5182,11 +5187,13 @@
}
/**
- * @return whether the navigation bar can be made translucent, e.g. touch
- * exploration is not enabled
+ * @return whether the navigation or status bar can be made translucent
+ *
+ * This should return true unless touch exploration is not enabled or
+ * R.boolean.config_enableTranslucentDecor is false.
*/
- private boolean isTranslucentNavigationAllowed() {
- return !mTouchExplorationEnabled;
+ private boolean areTranslucentBarsAllowed() {
+ return mTranslucentDecorEnabled && !mTouchExplorationEnabled;
}
// Use this instead of checking config_showNavigationBar so that it can be consistently
diff --git a/services/java/com/android/server/am/ActiveServices.java b/services/java/com/android/server/am/ActiveServices.java
index b69a0c8..a64940c 100644
--- a/services/java/com/android/server/am/ActiveServices.java
+++ b/services/java/com/android/server/am/ActiveServices.java
@@ -1494,7 +1494,7 @@
} catch (Exception e) {
Slog.w(TAG, "Exception when unbinding service "
+ r.shortName, e);
- serviceDoneExecutingLocked(r, true, true);
+ serviceProcessGoneLocked(r);
}
}
}
@@ -1544,7 +1544,7 @@
} catch (Exception e) {
Slog.w(TAG, "Exception when destroying service "
+ r.shortName, e);
- serviceDoneExecutingLocked(r, true, true);
+ serviceProcessGoneLocked(r);
}
updateServiceForegroundLocked(r.app, false);
} else {
@@ -1570,7 +1570,7 @@
r.tracker.setStarted(false, memFactor, now);
r.tracker.setBound(false, memFactor, now);
if (r.executeNesting == 0) {
- r.tracker.clearCurrentOwner(r);
+ r.tracker.clearCurrentOwner(r, false);
r.tracker = null;
}
}
@@ -1629,7 +1629,7 @@
s.app.thread.scheduleUnbindService(s, b.intent.intent.getIntent());
} catch (Exception e) {
Slog.w(TAG, "Exception when unbinding service " + s.shortName, e);
- serviceDoneExecutingLocked(s, true, true);
+ serviceProcessGoneLocked(s);
}
}
@@ -1708,6 +1708,16 @@
}
}
+ private void serviceProcessGoneLocked(ServiceRecord r) {
+ if (r.tracker != null) {
+ int memFactor = mAm.mProcessStats.getMemFactorLocked();
+ long now = SystemClock.uptimeMillis();
+ r.tracker.setExecuting(false, memFactor, now);
+ r.tracker.setBound(false, memFactor, now);
+ }
+ serviceDoneExecutingLocked(r, true, true);
+ }
+
private void serviceDoneExecutingLocked(ServiceRecord r, boolean inDestroying,
boolean finishing) {
if (DEBUG_SERVICE) Slog.v(TAG, "<<< DONE EXECUTING " + r
@@ -1747,7 +1757,7 @@
r.tracker.setExecuting(false, mAm.mProcessStats.getMemFactorLocked(),
SystemClock.uptimeMillis());
if (finishing) {
- r.tracker.clearCurrentOwner(r);
+ r.tracker.clearCurrentOwner(r, false);
r.tracker = null;
}
}
diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java
index a510c64..f1c2025 100644
--- a/services/java/com/android/server/am/ActivityManagerService.java
+++ b/services/java/com/android/server/am/ActivityManagerService.java
@@ -6413,9 +6413,8 @@
final int callingUid = Binder.getCallingUid();
final UriPermission perm = findUriPermissionLocked(callingUid, uri);
if (perm == null) {
- Slog.w(TAG, "No permission grant found for UID " + callingUid + " and Uri "
- + uri.toSafeString());
- return;
+ throw new SecurityException("No permission grant found for UID " + callingUid
+ + " and Uri " + uri.toSafeString());
}
boolean persistChanged = perm.takePersistableModes(modeFlags);
diff --git a/services/java/com/android/server/am/ServiceRecord.java b/services/java/com/android/server/am/ServiceRecord.java
index c47c1ac..cc1172a 100644
--- a/services/java/com/android/server/am/ServiceRecord.java
+++ b/services/java/com/android/server/am/ServiceRecord.java
@@ -335,12 +335,7 @@
public void forceClearTracker() {
if (tracker != null) {
- int memFactor = ams.mProcessStats.getMemFactorLocked();
- long now = SystemClock.uptimeMillis();
- tracker.setStarted(false, memFactor, now);
- tracker.setBound(false, memFactor, now);
- tracker.setExecuting(false, memFactor, now);
- tracker.clearCurrentOwner(this);
+ tracker.clearCurrentOwner(this, true);
tracker = null;
}
}
diff --git a/services/java/com/android/server/am/UriPermission.java b/services/java/com/android/server/am/UriPermission.java
index 684f247..1f12b74 100644
--- a/services/java/com/android/server/am/UriPermission.java
+++ b/services/java/com/android/server/am/UriPermission.java
@@ -21,7 +21,6 @@
import android.os.UserHandle;
import android.util.Log;
-import com.android.internal.util.Preconditions;
import com.google.android.collect.Sets;
import java.io.PrintWriter;
@@ -131,7 +130,11 @@
* @return if mode changes should trigger persisting.
*/
boolean takePersistableModes(int modeFlags) {
- Preconditions.checkFlagsArgument(modeFlags, persistableModeFlags);
+ if ((modeFlags & persistableModeFlags) != modeFlags) {
+ throw new SecurityException("Requested flags 0x"
+ + Integer.toHexString(modeFlags) + ", but only 0x"
+ + Integer.toHexString(persistableModeFlags) + " are allowed");
+ }
final int before = persistedModeFlags;
persistedModeFlags |= (persistableModeFlags & modeFlags);
diff --git a/services/java/com/android/server/pm/Settings.java b/services/java/com/android/server/pm/Settings.java
index 377c390..92fc6a4 100644
--- a/services/java/com/android/server/pm/Settings.java
+++ b/services/java/com/android/server/pm/Settings.java
@@ -2473,7 +2473,8 @@
} else if (tagName.equals("signing-keyset")) {
long id = Long.parseLong(parser.getAttributeValue(null, "identifier"));
packageSetting.keySetData.addSigningKeySet(id);
- Slog.d(TAG, "Adding signing keyset " + Long.toString(id) + " to " + name);
+ if (false) Slog.d(TAG, "Adding signing keyset " + Long.toString(id)
+ + " to " + name);
} else if (tagName.equals("defined-keyset")) {
long id = Long.parseLong(parser.getAttributeValue(null, "identifier"));
String alias = parser.getAttributeValue(null, "alias");
diff --git a/services/java/com/android/server/wm/WindowManagerService.java b/services/java/com/android/server/wm/WindowManagerService.java
index 0908563..00a653b 100644
--- a/services/java/com/android/server/wm/WindowManagerService.java
+++ b/services/java/com/android/server/wm/WindowManagerService.java
@@ -187,7 +187,7 @@
static final boolean DEBUG_SURFACE_TRACE = false;
static final boolean DEBUG_WINDOW_TRACE = false;
static final boolean DEBUG_TASK_MOVEMENT = false;
- static final boolean DEBUG_STACK = true;
+ static final boolean DEBUG_STACK = false;
static final boolean SHOW_SURFACE_ALLOC = false;
static final boolean SHOW_TRANSACTIONS = false;
static final boolean SHOW_LIGHT_TRANSACTIONS = false || SHOW_TRANSACTIONS;
@@ -1852,13 +1852,21 @@
}
}
- // Now stick it in.
+ // Now stick it in. For apps over wallpaper keep the wallpaper at the bottommost
+ // layer. For keyguard over wallpaper put the wallpaper under the keyguard.
+ int insertionIndex = 0;
+ if (visible && foundW != null) {
+ final int type = foundW.mAttrs.type;
+ if (type == TYPE_KEYGUARD || type == TYPE_KEYGUARD_SCRIM) {
+ insertionIndex = windows.indexOf(foundW);
+ }
+ }
if (DEBUG_WALLPAPER_LIGHT || DEBUG_WINDOW_MOVEMENT || DEBUG_ADD_REMOVE) {
Slog.v(TAG, "Moving wallpaper " + wallpaper
- + " from " + oldIndex + " to " + 0);
+ + " from " + oldIndex + " to " + insertionIndex);
}
- windows.add(0, wallpaper);
+ windows.add(insertionIndex, wallpaper);
mWindowsChanged = true;
changed |= ADJUST_WALLPAPER_LAYERS_CHANGED;
}
diff --git a/telephony/java/android/telephony/CellSignalStrengthCdma.java b/telephony/java/android/telephony/CellSignalStrengthCdma.java
index 190fea2..c945094 100644
--- a/telephony/java/android/telephony/CellSignalStrengthCdma.java
+++ b/telephony/java/android/telephony/CellSignalStrengthCdma.java
@@ -331,10 +331,12 @@
@Override
public void writeToParcel(Parcel dest, int flags) {
if (DBG) log("writeToParcel(Parcel, int): " + toString());
- dest.writeInt(mCdmaDbm);
- dest.writeInt(mCdmaEcio);
- dest.writeInt(mEvdoDbm);
- dest.writeInt(mEvdoEcio);
+ // Need to multiply CdmaDbm, CdmaEcio, EvdoDbm and EvdoEcio by -1
+ // to ensure consistency when reading values written here
+ dest.writeInt(mCdmaDbm * -1);
+ dest.writeInt(mCdmaEcio * -1);
+ dest.writeInt(mEvdoDbm * -1);
+ dest.writeInt(mEvdoEcio * -1);
dest.writeInt(mEvdoSnr);
}
@@ -343,10 +345,13 @@
* where the TYPE_LTE token is already been processed.
*/
private CellSignalStrengthCdma(Parcel in) {
- mCdmaDbm = in.readInt();
- mCdmaEcio = in.readInt();
- mEvdoDbm = in.readInt();
- mEvdoEcio = in.readInt();
+ // CdmaDbm, CdmaEcio, EvdoDbm and EvdoEcio are written into
+ // the parcel as positive values.
+ // Need to convert into negative values
+ mCdmaDbm = in.readInt() * -1;
+ mCdmaEcio = in.readInt() * -1;
+ mEvdoDbm = in.readInt() * -1;
+ mEvdoEcio = in.readInt() * -1;
mEvdoSnr = in.readInt();
if (DBG) log("CellSignalStrengthCdma(Parcel): " + toString());
}
diff --git a/telephony/java/android/telephony/CellSignalStrengthLte.java b/telephony/java/android/telephony/CellSignalStrengthLte.java
index b456bb3..5a1559a 100644
--- a/telephony/java/android/telephony/CellSignalStrengthLte.java
+++ b/telephony/java/android/telephony/CellSignalStrengthLte.java
@@ -247,8 +247,10 @@
public void writeToParcel(Parcel dest, int flags) {
if (DBG) log("writeToParcel(Parcel, int): " + toString());
dest.writeInt(mSignalStrength);
- dest.writeInt(mRsrp);
- dest.writeInt(mRsrq);
+ // Need to multiply rsrp and rsrq by -1
+ // to ensure consistency when reading values written here
+ dest.writeInt(mRsrp * -1);
+ dest.writeInt(mRsrq * -1);
dest.writeInt(mRssnr);
dest.writeInt(mCqi);
dest.writeInt(mTimingAdvance);
@@ -260,8 +262,10 @@
*/
private CellSignalStrengthLte(Parcel in) {
mSignalStrength = in.readInt();
- mRsrp = in.readInt();
- mRsrq = in.readInt();
+ // rsrp and rsrq are written into the parcel as positive values.
+ // Need to convert into negative values
+ mRsrp = in.readInt() * -1;
+ mRsrq = in.readInt() * -1;
mRssnr = in.readInt();
mCqi = in.readInt();
mTimingAdvance = in.readInt();
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index ea0d220..8f17e72 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -127,19 +127,40 @@
/**
* The Phone app sends this intent when a user opts to respond-via-message during an incoming
- * call. By default, the MMS app consumes this message and sends a text message to the caller. A
- * third party app can provide this functionality in lieu of MMS app by consuming this Intent
- * and sending the message using their own messaging system. The intent contains a URI
- * describing the recipient, and an EXTRA containing the message itself.
- * <p class="note"><strong>Note:</strong>
- * The intent-filter which consumes this Intent needs to be in a service which requires the
- * permission {@link android.Manifest.permission#SEND_RESPOND_VIA_MESSAGE}.</p>
+ * call. By default, the device's default SMS app consumes this message and sends a text message
+ * to the caller. A third party app can also provide this functionality by consuming this Intent
+ * with a {@link android.app.Service} and sending the message using its own messaging system.
+ * <p>The intent contains a URI (available from {@link android.content.Intent#getData})
+ * describing the recipient, using either the {@code sms:}, {@code smsto:}, {@code mms:},
+ * or {@code mmsto:} URI schema. Each of these URI schema carry the recipient information the
+ * same way: the path part of the URI contains the recipient's phone number or a comma-separated
+ * set of phone numbers if there are multiple recipients. For example, {@code
+ * smsto:2065551234}.</p>
*
- * <p>
- * {@link android.content.Intent#getData} is a URI describing the recipient of the message.
- * <p>
- * The {@link android.content.Intent#EXTRA_TEXT} extra contains the message
- * to send.
+ * <p>The intent may also contain extras for the message text (in {@link
+ * android.content.Intent#EXTRA_TEXT}) and a message subject
+ * (in {@link android.content.Intent#EXTRA_SUBJECT}).</p>
+ *
+ * <p class="note"><strong>Note:</strong>
+ * The intent-filter that consumes this Intent needs to be in a {@link android.app.Service}
+ * that requires the
+ * permission {@link android.Manifest.permission#SEND_RESPOND_VIA_MESSAGE}.</p>
+ * <p>For example, the service that receives this intent can be declared in the manifest file
+ * with an intent filter like this:</p>
+ * <pre>
+ * <!-- Service that delivers SMS messages received from the phone "quick response" -->
+ * <service android:name=".HeadlessSmsSendService"
+ * android:permission="android.permission.SEND_RESPOND_VIA_MESSAGE"
+ * android:exported="true" >
+ * <intent-filter>
+ * <action android:name="android.intent.action.RESPOND_VIA_MESSAGE" />
+ * <category android:name="android.intent.category.DEFAULT" />
+ * <data android:scheme="sms" />
+ * <data android:scheme="smsto" />
+ * <data android:scheme="mms" />
+ * <data android:scheme="mmsto" />
+ * </intent-filter>
+ * </service></pre>
* <p>
* Output: nothing.
*/