diff options
33 files changed, 712 insertions, 378 deletions
diff --git a/core/java/android/nfc/cardemulation/CardEmulation.java b/core/java/android/nfc/cardemulation/CardEmulation.java index 3cd7863ff424..58d9616c72c4 100644 --- a/core/java/android/nfc/cardemulation/CardEmulation.java +++ b/core/java/android/nfc/cardemulation/CardEmulation.java @@ -33,6 +33,18 @@ import android.util.Log; 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 @@ public final class CardEmulation { "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 @@ public final class CardEmulation { * 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 @@ public final class CardEmulation { /** * 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 @@ public final class CardEmulation { 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 @@ public final class CardEmulation { * 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 @@ public final class CardEmulation { * * @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 @@ public final class CardEmulation { } /** - * 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 @@ public final class CardEmulation { } } } + /** * @hide */ diff --git a/core/java/android/nfc/cardemulation/HostApduService.java b/core/java/android/nfc/cardemulation/HostApduService.java index e2c3ca6c5735..ad34e61db910 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; 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.os.RemoteException; 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 @@ public abstract class HostApduService extends Service { * 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 15f63f9fed53..0d01762ae8e2 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; 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 76627deb4e10..8901f287c47a 100644 --- a/core/java/android/nfc/tech/NfcBarcode.java +++ b/core/java/android/nfc/tech/NfcBarcode.java @@ -102,15 +102,21 @@ public final class NfcBarcode extends BasicTagTechnology { * </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/view/View.java b/core/java/android/view/View.java index 9c388ddeaafe..e2d98edafc49 100644 --- a/core/java/android/view/View.java +++ b/core/java/android/view/View.java @@ -18,6 +18,7 @@ package android.view; 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 class View implements Drawable.Callback, KeyEvent.Callback, */ 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 @@ public class View implements Drawable.Callback, KeyEvent.Callback, 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 @@ public class View implements Drawable.Callback, KeyEvent.Callback, 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/res/res/values-mcc208-mnc01/config.xml b/core/res/res/values-mcc208-mnc01/config.xml deleted file mode 100644 index 3b84ff231e68..000000000000 --- 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 4a51a2ffd03e..000000000000 --- 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 b49ad74c36c6..000000000000 --- 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 6bb1196b5775..000000000000 --- 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 175f76e0473a..776b5702a0d0 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-mnc00/config.xml b/core/res/res/values-mcc268-mnc03/config.xml index c92b9c71da2b..0d5fe5717d2d 100644 --- a/core/res/res/values-mcc454-mnc00/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">1O1O tethering,lte.internet,,,,,,,,,454,00,3,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 index c7dc960ae854..00c415551f8b 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 fb71f3bc894b..bbab4ad35bfa 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/config.xml b/core/res/res/values/config.xml index 196be743da15..42ea384bcdbb 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 0b050c76af88..611c08558008 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 a581e08bad41..19d2ebebaa97 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/Keyguard/res/values-mcc262-mnc08/bools.xml b/packages/Keyguard/res/values-mcc262-mnc08/bools.xml new file mode 100644 index 000000000000..6cd4c55ca940 --- /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 000000000000..6cd4c55ca940 --- /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 Binary files differnew file mode 100644 index 000000000000..09ab1a2bae1d --- /dev/null +++ b/packages/PrintSpooler/res/drawable-hdpi/ic_menu_print.png diff --git a/packages/PrintSpooler/res/drawable-mdpi/ic_menu_print.png b/packages/PrintSpooler/res/drawable-mdpi/ic_menu_print.png Binary files differnew file mode 100644 index 000000000000..637d94ecfb0e --- /dev/null +++ b/packages/PrintSpooler/res/drawable-mdpi/ic_menu_print.png diff --git a/packages/PrintSpooler/res/drawable-xhdpi/ic_menu_print.png b/packages/PrintSpooler/res/drawable-xhdpi/ic_menu_print.png Binary files differnew file mode 100644 index 000000000000..4d4b3cc1a119 --- /dev/null +++ b/packages/PrintSpooler/res/drawable-xhdpi/ic_menu_print.png 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 83019b9ef79a..02740a308fa5 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 22a9950d0313..3a23b3ec5516 100644 --- a/packages/PrintSpooler/src/com/android/printspooler/PrintJobConfigActivity.java +++ b/packages/PrintSpooler/src/com/android/printspooler/PrintJobConfigActivity.java @@ -1248,13 +1248,20 @@ public class PrintJobConfigActivity extends Activity { 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 @@ public class PrintJobConfigActivity extends Activity { && printer.getCapabilities() == null)) { if (!mCapabilitiesTimeout.isPosted()) { mCapabilitiesTimeout.post(); - mCurrentPrinter.copyFrom(printer); - updateUi(); - return; } + mCurrentPrinter.copyFrom(printer); + updateUi(); + return; } // We just refreshed the current printer. diff --git a/packages/PrintSpooler/src/com/android/printspooler/SelectPrinterFragment.java b/packages/PrintSpooler/src/com/android/printspooler/SelectPrinterFragment.java index d68893236ca8..be94ba4c9418 100644 --- a/packages/PrintSpooler/src/com/android/printspooler/SelectPrinterFragment.java +++ b/packages/PrintSpooler/src/com/android/printspooler/SelectPrinterFragment.java @@ -93,6 +93,7 @@ public final class SelectPrinterFragment extends ListFragment { public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setHasOptionsMenu(true); + getActivity().getActionBar().setIcon(R.drawable.ic_menu_print); } @Override diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java index bc02b0db1e43..158227fe78af 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.Bundle; 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 @@ public class SettingsProvider extends ContentProvider { 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 @@ public class SettingsProvider extends ContentProvider { // 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/WallpaperCropper/src/com/android/photos/views/TiledImageView.java b/packages/WallpaperCropper/src/com/android/photos/views/TiledImageView.java index 36cb4384d78c..af4199c91eea 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 @@ public class TiledImageView extends FrameLayout { // 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 b4e715ca24d5..14f7c1d1f7cf 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 @@ public class CropView extends TiledImageView implements OnScaleGestureListener { 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 class CropView extends TiledImageView implements OnScaleGestureListener { 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 @@ public class CropView extends TiledImageView implements OnScaleGestureListener { edgesOut.bottom = bottomEdge; } + public int getImageRotation() { + return mRenderer.rotation; + } + public RectF getCrop() { final RectF edges = mTempEdges; getEdgesHelper(edges); @@ -96,6 +136,12 @@ public class CropView extends TiledImageView implements OnScaleGestureListener { 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 @@ public class CropView extends TiledImageView implements OnScaleGestureListener { 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 @@ public class CropView extends TiledImageView implements OnScaleGestureListener { 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 @@ public class CropView extends TiledImageView implements OnScaleGestureListener { 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 @@ public class CropView extends TiledImageView implements OnScaleGestureListener { 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 @@ public class CropView extends TiledImageView implements OnScaleGestureListener { 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 710e8e470d4d..1209e56c193c 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.graphics.RectF; 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 @@ public class WallpaperCropActivity extends Activity { 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 @@ public class WallpaperCropActivity extends Activity { cropImageAndSetWallpaper(imageUri, null, finishActivityWhenDone); } }); - getWindow().addPrivateFlags( - WindowManager.LayoutParams.PRIVATE_FLAG_INHERIT_TRANSLUCENT_DECOR); } public boolean enableRotation() { @@ -170,9 +177,47 @@ public class WallpaperCropActivity extends Activity { 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 @@ public class WallpaperCropActivity extends Activity { 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 @@ public class WallpaperCropActivity extends Activity { } }; 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 @@ public class WallpaperCropActivity extends Activity { 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 @@ public class WallpaperCropActivity extends Activity { } // 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 @@ public class WallpaperCropActivity extends Activity { 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 @@ public class WallpaperCropActivity extends Activity { } }; 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 @@ public class WallpaperCropActivity extends Activity { 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 @@ public class WallpaperCropActivity extends Activity { 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 @@ public class WallpaperCropActivity extends Activity { 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 @@ public class WallpaperCropActivity extends Activity { 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 @@ public class WallpaperCropActivity extends Activity { 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 @@ public class WallpaperCropActivity extends Activity { 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 @@ public class WallpaperCropActivity extends Activity { 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 @@ public class WallpaperCropActivity extends Activity { }.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 5ac3ed0b690d..1c43014e54c8 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 @@ public class PhoneWindowManager implements WindowManagerPolicy { 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 @@ public class PhoneWindowManager implements WindowManagerPolicy { 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 @@ public class PhoneWindowManager implements WindowManagerPolicy { 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 @@ public class PhoneWindowManager implements WindowManagerPolicy { 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 class PhoneWindowManager implements WindowManagerPolicy { } 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 @@ public class PhoneWindowManager implements WindowManagerPolicy { 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 @@ public class PhoneWindowManager implements WindowManagerPolicy { } /** - * @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/wm/WindowManagerService.java b/services/java/com/android/server/wm/WindowManagerService.java index 0908563c957c..00a653bba18d 100644 --- a/services/java/com/android/server/wm/WindowManagerService.java +++ b/services/java/com/android/server/wm/WindowManagerService.java @@ -187,7 +187,7 @@ public class WindowManagerService extends IWindowManager.Stub 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 @@ public class WindowManagerService extends IWindowManager.Stub } } - // 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 190fea2b13ab..c94509459e34 100644 --- a/telephony/java/android/telephony/CellSignalStrengthCdma.java +++ b/telephony/java/android/telephony/CellSignalStrengthCdma.java @@ -331,10 +331,12 @@ public final class CellSignalStrengthCdma extends CellSignalStrength implements @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 @@ public final class CellSignalStrengthCdma extends CellSignalStrength implements * 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 b456bb35b2d2..5a1559aa7e65 100644 --- a/telephony/java/android/telephony/CellSignalStrengthLte.java +++ b/telephony/java/android/telephony/CellSignalStrengthLte.java @@ -247,8 +247,10 @@ public final class CellSignalStrengthLte extends CellSignalStrength implements P 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 @@ public final class CellSignalStrengthLte extends CellSignalStrength implements P */ 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 ea0d220deb9d..8f17e7279924 100644 --- a/telephony/java/android/telephony/TelephonyManager.java +++ b/telephony/java/android/telephony/TelephonyManager.java @@ -127,19 +127,40 @@ public class TelephonyManager { /** * 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. + * 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>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 which consumes this Intent needs to be in a service which requires the + * 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> - * {@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>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. */ |