diff options
32 files changed, 569 insertions, 566 deletions
diff --git a/Android.mk b/Android.mk index be8c25b714a1..c8b2555487ca 100644 --- a/Android.mk +++ b/Android.mk @@ -400,6 +400,8 @@ web_docs_sample_code_flags := \ resources/samples/AccessibilityService "Accessibility Service" \ -samplecode $(sample_dir)/AccelerometerPlay \ resources/samples/AccelerometerPlay "Accelerometer Play" \ + -samplecode $(sample_dir)/AndroidBeam \ + resources/samples/AndroidBeam "Android Beam" \ -samplecode $(sample_dir)/ApiDemos \ resources/samples/ApiDemos "API Demos" \ -samplecode $(sample_dir)/Support4Demos \ diff --git a/api/14.txt b/api/14.txt index 9f2a6dfc3855..e26311f42882 100644 --- a/api/14.txt +++ b/api/14.txt @@ -16583,10 +16583,6 @@ package android.provider { field public static final java.lang.String PHOTO_FILE_ID = "data14"; } - public static final class ContactsContract.Contacts.StreamItems implements android.provider.ContactsContract.StreamItemsColumns { - field public static final java.lang.String CONTENT_DIRECTORY = "stream_items"; - } - protected static abstract interface ContactsContract.ContactsColumns { field public static final java.lang.String DISPLAY_NAME = "display_name"; field public static final java.lang.String HAS_PHONE_NUMBER = "has_phone_number"; @@ -16844,10 +16840,6 @@ package android.provider { field public static final java.lang.String DATA_ID = "data_id"; } - public static final class ContactsContract.RawContacts.StreamItems implements android.provider.BaseColumns android.provider.ContactsContract.StreamItemsColumns { - field public static final java.lang.String CONTENT_DIRECTORY = "stream_items"; - } - protected static abstract interface ContactsContract.RawContactsColumns { field public static final java.lang.String AGGREGATION_MODE = "aggregation_mode"; field public static final java.lang.String CONTACT_ID = "contact_id"; @@ -16911,56 +16903,6 @@ package android.provider { field public static final android.net.Uri PROFILE_CONTENT_URI; } - public static final class ContactsContract.StreamItemPhotos implements android.provider.BaseColumns android.provider.ContactsContract.StreamItemPhotosColumns { - field public static final java.lang.String PHOTO = "photo"; - } - - protected static abstract interface ContactsContract.StreamItemPhotosColumns { - field public static final java.lang.String PHOTO_FILE_ID = "photo_file_id"; - field public static final java.lang.String PHOTO_URI = "photo_uri"; - field public static final java.lang.String SORT_INDEX = "sort_index"; - field public static final java.lang.String STREAM_ITEM_ID = "stream_item_id"; - field public static final java.lang.String SYNC1 = "stream_item_photo_sync1"; - field public static final java.lang.String SYNC2 = "stream_item_photo_sync2"; - field public static final java.lang.String SYNC3 = "stream_item_photo_sync3"; - field public static final java.lang.String SYNC4 = "stream_item_photo_sync4"; - } - - public static final class ContactsContract.StreamItems implements android.provider.BaseColumns android.provider.ContactsContract.StreamItemsColumns { - field public static final java.lang.String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/stream_item"; - field public static final android.net.Uri CONTENT_LIMIT_URI; - field public static final android.net.Uri CONTENT_PHOTO_URI; - field public static final java.lang.String CONTENT_TYPE = "vnd.android.cursor.dir/stream_item"; - field public static final android.net.Uri CONTENT_URI; - field public static final java.lang.String MAX_ITEMS = "max_items"; - } - - public static final class ContactsContract.StreamItems.StreamItemPhotos implements android.provider.BaseColumns android.provider.ContactsContract.StreamItemPhotosColumns { - field public static final java.lang.String CONTENT_DIRECTORY = "photo"; - field public static final java.lang.String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/stream_item_photo"; - field public static final java.lang.String CONTENT_TYPE = "vnd.android.cursor.dir/stream_item_photo"; - } - - protected static abstract interface ContactsContract.StreamItemsColumns { - field public static final java.lang.String ACCOUNT_NAME = "account_name"; - field public static final java.lang.String ACCOUNT_TYPE = "account_type"; - field public static final java.lang.String COMMENTS = "comments"; - field public static final java.lang.String CONTACT_ID = "contact_id"; - field public static final java.lang.String CONTACT_LOOKUP_KEY = "contact_lookup"; - field public static final java.lang.String DATA_SET = "data_set"; - field public static final java.lang.String RAW_CONTACT_ID = "raw_contact_id"; - field public static final java.lang.String RAW_CONTACT_SOURCE_ID = "raw_contact_source_id"; - field public static final java.lang.String RES_ICON = "icon"; - field public static final java.lang.String RES_LABEL = "label"; - field public static final java.lang.String RES_PACKAGE = "res_package"; - field public static final java.lang.String SYNC1 = "stream_item_sync1"; - field public static final java.lang.String SYNC2 = "stream_item_sync2"; - field public static final java.lang.String SYNC3 = "stream_item_sync3"; - field public static final java.lang.String SYNC4 = "stream_item_sync4"; - field public static final java.lang.String TEXT = "text"; - field public static final java.lang.String TIMESTAMP = "timestamp"; - } - protected static abstract interface ContactsContract.SyncColumns implements android.provider.ContactsContract.BaseSyncColumns { field public static final java.lang.String ACCOUNT_NAME = "account_name"; field public static final java.lang.String ACCOUNT_TYPE = "account_type"; diff --git a/api/current.txt b/api/current.txt index 9f2a6dfc3855..e26311f42882 100644 --- a/api/current.txt +++ b/api/current.txt @@ -16583,10 +16583,6 @@ package android.provider { field public static final java.lang.String PHOTO_FILE_ID = "data14"; } - public static final class ContactsContract.Contacts.StreamItems implements android.provider.ContactsContract.StreamItemsColumns { - field public static final java.lang.String CONTENT_DIRECTORY = "stream_items"; - } - protected static abstract interface ContactsContract.ContactsColumns { field public static final java.lang.String DISPLAY_NAME = "display_name"; field public static final java.lang.String HAS_PHONE_NUMBER = "has_phone_number"; @@ -16844,10 +16840,6 @@ package android.provider { field public static final java.lang.String DATA_ID = "data_id"; } - public static final class ContactsContract.RawContacts.StreamItems implements android.provider.BaseColumns android.provider.ContactsContract.StreamItemsColumns { - field public static final java.lang.String CONTENT_DIRECTORY = "stream_items"; - } - protected static abstract interface ContactsContract.RawContactsColumns { field public static final java.lang.String AGGREGATION_MODE = "aggregation_mode"; field public static final java.lang.String CONTACT_ID = "contact_id"; @@ -16911,56 +16903,6 @@ package android.provider { field public static final android.net.Uri PROFILE_CONTENT_URI; } - public static final class ContactsContract.StreamItemPhotos implements android.provider.BaseColumns android.provider.ContactsContract.StreamItemPhotosColumns { - field public static final java.lang.String PHOTO = "photo"; - } - - protected static abstract interface ContactsContract.StreamItemPhotosColumns { - field public static final java.lang.String PHOTO_FILE_ID = "photo_file_id"; - field public static final java.lang.String PHOTO_URI = "photo_uri"; - field public static final java.lang.String SORT_INDEX = "sort_index"; - field public static final java.lang.String STREAM_ITEM_ID = "stream_item_id"; - field public static final java.lang.String SYNC1 = "stream_item_photo_sync1"; - field public static final java.lang.String SYNC2 = "stream_item_photo_sync2"; - field public static final java.lang.String SYNC3 = "stream_item_photo_sync3"; - field public static final java.lang.String SYNC4 = "stream_item_photo_sync4"; - } - - public static final class ContactsContract.StreamItems implements android.provider.BaseColumns android.provider.ContactsContract.StreamItemsColumns { - field public static final java.lang.String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/stream_item"; - field public static final android.net.Uri CONTENT_LIMIT_URI; - field public static final android.net.Uri CONTENT_PHOTO_URI; - field public static final java.lang.String CONTENT_TYPE = "vnd.android.cursor.dir/stream_item"; - field public static final android.net.Uri CONTENT_URI; - field public static final java.lang.String MAX_ITEMS = "max_items"; - } - - public static final class ContactsContract.StreamItems.StreamItemPhotos implements android.provider.BaseColumns android.provider.ContactsContract.StreamItemPhotosColumns { - field public static final java.lang.String CONTENT_DIRECTORY = "photo"; - field public static final java.lang.String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/stream_item_photo"; - field public static final java.lang.String CONTENT_TYPE = "vnd.android.cursor.dir/stream_item_photo"; - } - - protected static abstract interface ContactsContract.StreamItemsColumns { - field public static final java.lang.String ACCOUNT_NAME = "account_name"; - field public static final java.lang.String ACCOUNT_TYPE = "account_type"; - field public static final java.lang.String COMMENTS = "comments"; - field public static final java.lang.String CONTACT_ID = "contact_id"; - field public static final java.lang.String CONTACT_LOOKUP_KEY = "contact_lookup"; - field public static final java.lang.String DATA_SET = "data_set"; - field public static final java.lang.String RAW_CONTACT_ID = "raw_contact_id"; - field public static final java.lang.String RAW_CONTACT_SOURCE_ID = "raw_contact_source_id"; - field public static final java.lang.String RES_ICON = "icon"; - field public static final java.lang.String RES_LABEL = "label"; - field public static final java.lang.String RES_PACKAGE = "res_package"; - field public static final java.lang.String SYNC1 = "stream_item_sync1"; - field public static final java.lang.String SYNC2 = "stream_item_sync2"; - field public static final java.lang.String SYNC3 = "stream_item_sync3"; - field public static final java.lang.String SYNC4 = "stream_item_sync4"; - field public static final java.lang.String TEXT = "text"; - field public static final java.lang.String TIMESTAMP = "timestamp"; - } - protected static abstract interface ContactsContract.SyncColumns implements android.provider.ContactsContract.BaseSyncColumns { field public static final java.lang.String ACCOUNT_NAME = "account_name"; field public static final java.lang.String ACCOUNT_TYPE = "account_type"; diff --git a/cmds/bu/src/com/android/commands/bu/Backup.java b/cmds/bu/src/com/android/commands/bu/Backup.java index 4c4bf9863aea..046ccca9b02a 100644 --- a/cmds/bu/src/com/android/commands/bu/Backup.java +++ b/cmds/bu/src/com/android/commands/bu/Backup.java @@ -66,6 +66,7 @@ public final class Backup { boolean saveApks = false; boolean saveShared = false; boolean doEverything = false; + boolean allIncludesSystem = true; String arg; while ((arg = nextArg()) != null) { @@ -78,6 +79,10 @@ public final class Backup { saveShared = true; } else if ("-noshared".equals(arg)) { saveShared = false; + } else if ("-system".equals(arg)) { + allIncludesSystem = true; + } else if ("-nosystem".equals(arg)) { + allIncludesSystem = false; } else if ("-all".equals(arg)) { doEverything = true; } else { @@ -102,7 +107,7 @@ public final class Backup { try { ParcelFileDescriptor fd = ParcelFileDescriptor.adoptFd(socketFd); String[] packArray = new String[packages.size()]; - mBackupManager.fullBackup(fd, saveApks, saveShared, doEverything, + mBackupManager.fullBackup(fd, saveApks, saveShared, doEverything, allIncludesSystem, packages.toArray(packArray)); } catch (RemoteException e) { Log.e(TAG, "Unable to invoke backup manager for backup"); diff --git a/core/java/android/app/backup/IBackupManager.aidl b/core/java/android/app/backup/IBackupManager.aidl index c154296fbf03..acdd0b54559a 100644 --- a/core/java/android/app/backup/IBackupManager.aidl +++ b/core/java/android/app/backup/IBackupManager.aidl @@ -157,11 +157,15 @@ interface IBackupManager { * @param allApps If <code>true</code>, the resulting tar stream will include all * installed applications' data, not just those named in the <code>packageNames</code> * parameter. + * @param allIncludesSystem If {@code true}, then {@code allApps} will be interpreted + * as including packages pre-installed as part of the system. If {@code false}, + * then setting {@code allApps} to {@code true} will mean only that all 3rd-party + * applications will be included in the dataset. * @param packageNames The package names of the apps whose data (and optionally .apk files) * are to be backed up. The <code>allApps</code> parameter supersedes this. */ void fullBackup(in ParcelFileDescriptor fd, boolean includeApks, boolean includeShared, - boolean allApps, in String[] packageNames); + boolean allApps, boolean allIncludesSystem, in String[] packageNames); /** * Restore device content from the data stream passed through the given socket. The diff --git a/core/java/android/hardware/Camera.java b/core/java/android/hardware/Camera.java index e40de266606c..c3a14ca537f3 100644 --- a/core/java/android/hardware/Camera.java +++ b/core/java/android/hardware/Camera.java @@ -201,7 +201,7 @@ public class Camera { public static final int CAMERA_FACING_FRONT = 1; /** - * The direction that the camera faces to. It should be + * The direction that the camera faces. It should be * CAMERA_FACING_BACK or CAMERA_FACING_FRONT. */ public int facing; @@ -1055,9 +1055,9 @@ public class Camera { /** * Notify the listener of the detected faces in the preview frame. * - * @param faces the detected faces. The list is sorted by the score. - * The highest score is the first element. - * @param camera the Camera service object + * @param faces The detected faces in a list sorted by the confidence score. + * The highest scored face is the first element. + * @param camera The {@link Camera} service object */ void onFaceDetection(Face[] faces, Camera camera); } @@ -1105,7 +1105,7 @@ public class Camera { /** * Stops the face detection. * - * @see #startFaceDetection(int) + * @see #startFaceDetection() */ public final void stopFaceDetection() { _stopFaceDetection(); @@ -1116,8 +1116,12 @@ public class Camera { private native final void _stopFaceDetection(); /** - * The information of a face from camera face detection. + * Information about a face identified through camera face detection. + * + * <p>When face detection is used with a camera, the {@link FaceDetectionListener} returns a + * list of face objects for use in focusing and metering.</p> * + * @see FaceDetectionListener */ public static class Face { /** @@ -1138,15 +1142,15 @@ public class Camera { * the sensor sees. The direction is not affected by the rotation or * mirroring of {@link #setDisplayOrientation(int)}.</p> * - * @see #startFaceDetection(int) + * @see #startFaceDetection() */ public Rect rect; /** - * The confidence level of the face. The range is 1 to 100. 100 is the + * The confidence level for the detection of the face. The range is 1 to 100. 100 is the * highest confidence. * - * @see #startFaceDetection(int) + * @see #startFaceDetection() */ public int score; @@ -3144,7 +3148,7 @@ public class Camera { * supported. * * @return the maximum number of detected face supported by the camera. - * @see #startFaceDetection(int) + * @see #startFaceDetection() */ public int getMaxNumDetectedFaces() { return getInt(KEY_MAX_NUM_DETECTED_FACES_HW, 0); diff --git a/core/java/android/inputmethodservice/KeyboardView.java b/core/java/android/inputmethodservice/KeyboardView.java index 1119c1eb1b31..5343e2a5f1bc 100644 --- a/core/java/android/inputmethodservice/KeyboardView.java +++ b/core/java/android/inputmethodservice/KeyboardView.java @@ -248,6 +248,8 @@ public class KeyboardView extends View implements View.OnClickListener { private AccessibilityManager mAccessibilityManager; /** The audio manager for accessibility support */ private AudioManager mAudioManager; + /** Whether the requirement of a headset to hear passwords if accessibility is enabled is announced. */ + private boolean mHeadsetRequiredToHearPasswordsAnnounced; Handler mHandler = new Handler() { @Override @@ -852,13 +854,15 @@ public class KeyboardView extends View implements View.OnClickListener { Key oldKey = keys[oldKeyIndex]; oldKey.onReleased(mCurrentKeyIndex == NOT_A_KEY); invalidateKey(oldKeyIndex); - sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_HOVER_EXIT, oldKey.codes[0]); + sendAccessibilityEventForUnicodeCharacter(AccessibilityEvent.TYPE_VIEW_HOVER_EXIT, + oldKey.codes[0]); } if (mCurrentKeyIndex != NOT_A_KEY && keys.length > mCurrentKeyIndex) { Key newKey = keys[mCurrentKeyIndex]; newKey.onPressed(); invalidateKey(mCurrentKeyIndex); - sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_HOVER_ENTER, newKey.codes[0]); + sendAccessibilityEventForUnicodeCharacter(AccessibilityEvent.TYPE_VIEW_HOVER_ENTER, + newKey.codes[0]); } } // If key changed and preview is on ... @@ -958,13 +962,13 @@ public class KeyboardView extends View implements View.OnClickListener { mPreviewText.setVisibility(VISIBLE); } - private void sendAccessibilityEvent(int eventType, int code) { + private void sendAccessibilityEventForUnicodeCharacter(int eventType, int code) { if (mAccessibilityManager.isEnabled()) { AccessibilityEvent event = AccessibilityEvent.obtain(eventType); onInitializeAccessibilityEvent(event); + String text = null; // Add text only if headset is used to avoid leaking passwords. if (mAudioManager.isBluetoothA2dpOn() || mAudioManager.isWiredHeadsetOn()) { - String text = null; switch (code) { case Keyboard.KEYCODE_ALT: text = mContext.getString(R.string.keyboardview_keycode_alt); @@ -990,11 +994,17 @@ public class KeyboardView extends View implements View.OnClickListener { default: text = String.valueOf((char) code); } - event.getText().add(text); + } else if (!mHeadsetRequiredToHearPasswordsAnnounced) { + // We want the waring for required head set to be send with both the + // hover enter and hover exit event, so set the flag after the exit. + if (eventType == AccessibilityEvent.TYPE_VIEW_HOVER_EXIT) { + mHeadsetRequiredToHearPasswordsAnnounced = true; + } + text = mContext.getString(R.string.keyboard_headset_required_to_hear_password); } else { - event.getText().add(mContext.getString( - R.string.keyboard_headset_required_to_hear_password)); + text = mContext.getString(R.string.keyboard_password_character_no_headset); } + event.getText().add(text); mAccessibilityManager.sendAccessibilityEvent(event); } } @@ -1134,15 +1144,13 @@ public class KeyboardView extends View implements View.OnClickListener { } @Override - protected boolean dispatchHoverEvent(MotionEvent event) { + public boolean onHoverEvent(MotionEvent event) { // If touch exploring is enabled we ignore touch events and transform // the stream of hover events as touch events. This allows one consistent // event stream to drive the keyboard since during touch exploring the // first touch generates only hover events and tapping on the same // location generates hover and touch events. - if (mAccessibilityManager.isEnabled() - && mAccessibilityManager.isTouchExplorationEnabled() - && event.getPointerCount() == 1) { + if (mAccessibilityManager.isTouchExplorationEnabled() && event.getPointerCount() == 1) { final int action = event.getAction(); switch (action) { case MotionEvent.ACTION_HOVER_ENTER: @@ -1156,9 +1164,9 @@ public class KeyboardView extends View implements View.OnClickListener { break; } onTouchEventInternal(event); - return true; + event.setAction(action); } - return super.dispatchHoverEvent(event); + return super.onHoverEvent(event); } @Override @@ -1168,8 +1176,7 @@ public class KeyboardView extends View implements View.OnClickListener { // event stream to drive the keyboard since during touch exploring the // first touch generates only hover events and tapping on the same // location generates hover and touch events. - if (mAccessibilityManager.isEnabled() - && mAccessibilityManager.isTouchExplorationEnabled()) { + if (mAccessibilityManager.isTouchExplorationEnabled()) { return true; } return onTouchEventInternal(event); diff --git a/core/java/android/net/http/SslError.java b/core/java/android/net/http/SslError.java index 08c669232c5d..5998f5f9ed6e 100644 --- a/core/java/android/net/http/SslError.java +++ b/core/java/android/net/http/SslError.java @@ -19,7 +19,8 @@ package android.net.http; import java.security.cert.X509Certificate; /** - * One or more individual SSL errors and the associated SSL certificate + * This class represents a set of one or more SSL errors and the associated SSL + * certificate. */ public class SslError { @@ -48,16 +49,17 @@ public class SslError { */ public static final int SSL_DATE_INVALID = 4; /** - * The certificate is invalid + * A generic error occurred */ public static final int SSL_INVALID = 5; /** - * The number of different SSL errors (update if you add a new SSL error!!!) + * The number of different SSL errors. * @deprecated This constant is not necessary for using the SslError API and * can change from release to release. */ + // Update if you add a new SSL error!!! @Deprecated public static final int SSL_MAX_ERROR = 6; @@ -78,56 +80,56 @@ public class SslError { final String mUrl; /** - * Creates a new SSL error set object + * Creates a new SslError object using the supplied error and certificate. + * The URL will be set to the empty string. * @param error The SSL error * @param certificate The associated SSL certificate * @deprecated Use {@link #SslError(int, SslCertificate, String)} */ @Deprecated public SslError(int error, SslCertificate certificate) { - addError(error); - if (certificate == null) { - throw new NullPointerException("certificate is null."); - } - mCertificate = certificate; - mUrl = ""; + this(error, certificate, ""); } /** - * Creates a new SSL error set object + * Creates a new SslError object using the supplied error and certificate. + * The URL will be set to the empty string. * @param error The SSL error * @param certificate The associated SSL certificate * @deprecated Use {@link #SslError(int, X509Certificate, String)} */ @Deprecated public SslError(int error, X509Certificate certificate) { - addError(error); - if (certificate == null) { - throw new NullPointerException("certificate is null."); - } - mCertificate = new SslCertificate(certificate); - mUrl = ""; + this(error, certificate, ""); } /** - * Creates a new SSL error set object + * Creates a new SslError object using the supplied error, certificate and + * URL. * @param error The SSL error * @param certificate The associated SSL certificate - * @param url The associated URL. + * @param url The associated URL */ public SslError(int error, SslCertificate certificate, String url) { + assert certificate != null; + assert url != null; addError(error); - if (certificate == null) { - throw new NullPointerException("certificate is null."); - } mCertificate = certificate; - if (url == null) { - throw new NullPointerException("url is null."); - } mUrl = url; } /** + * Creates a new SslError object using the supplied error, certificate and + * URL. + * @param error The SSL error + * @param certificate The associated SSL certificate + * @param url The associated URL + */ + public SslError(int error, X509Certificate certificate, String url) { + this(error, new SslCertificate(certificate), url); + } + + /** * Creates an SslError object from a chromium error code. * @param error The chromium error code * @param certificate The associated SSL certificate @@ -138,56 +140,38 @@ public class SslError { int error, SslCertificate cert, String url) { // The chromium error codes are in: // external/chromium/net/base/net_error_list.h - if (error > -200 || error < -299) { - throw new NullPointerException("Not a valid chromium SSL error code."); - } + assert (error >= -299 && error <= -200); if (error == -200) return new SslError(SSL_IDMISMATCH, cert, url); if (error == -201) return new SslError(SSL_DATE_INVALID, cert, url); if (error == -202) return new SslError(SSL_UNTRUSTED, cert, url); - // Map all other errors to SSL_INVALID + // Map all other codes to SSL_INVALID. return new SslError(SSL_INVALID, cert, url); } /** - * Creates a new SSL error set object - * @param error The SSL error - * @param certificate The associated SSL certificate - * @param url The associated URL. - */ - public SslError(int error, X509Certificate certificate, String url) { - addError(error); - if (certificate == null) { - throw new NullPointerException("certificate is null."); - } - mCertificate = new SslCertificate(certificate); - if (url == null) { - throw new NullPointerException("url is null."); - } - mUrl = url; - } - - /** - * @return The SSL certificate associated with the error set, non-null. + * Gets the SSL certificate associated with this object. + * @return The SSL certificate, non-null. */ public SslCertificate getCertificate() { return mCertificate; } /** - * @return The URL associated with the error set, non-null. - * "" if one of the deprecated constructors is used. + * Gets the URL associated with this object. + * @return The URL, non-null. */ public String getUrl() { return mUrl; } /** - * Adds the SSL error to the error set + * Adds the supplied SSL error to the set. * @param error The SSL error to add - * @return True iff the error being added is a known SSL error + * @return True if the error being added is a known SSL error, otherwise + * false. */ public boolean addError(int error) { boolean rval = (0 <= error && error < SslError.SSL_MAX_ERROR); @@ -199,8 +183,9 @@ public class SslError { } /** - * @param error The SSL error to check - * @return True iff the set includes the error + * Determines whether this object includes the supplied error. + * @param error The SSL error to check for + * @return True if this object includes the error, otherwise false. */ public boolean hasError(int error) { boolean rval = (0 <= error && error < SslError.SSL_MAX_ERROR); @@ -212,7 +197,8 @@ public class SslError { } /** - * @return The primary, most severe, SSL error in the set + * Gets the most severe SSL error in this object's set of errors. + * @return The most severe SSL error. */ public int getPrimaryError() { if (mErrors != 0) { @@ -228,12 +214,12 @@ public class SslError { } /** - * @return A String representation of this SSL error object - * (used mostly for debugging). + * Returns a string representation of this object. + * @return A String representation of this object. */ public String toString() { return "primary error: " + getPrimaryError() + - " certificate: " + getCertificate() + - " on URL: " + getUrl(); + " certificate: " + getCertificate() + + " on URL: " + getUrl(); } } diff --git a/core/java/android/provider/ContactsContract.java b/core/java/android/provider/ContactsContract.java index fb119b343abd..8483b4f0cf44 100644 --- a/core/java/android/provider/ContactsContract.java +++ b/core/java/android/provider/ContactsContract.java @@ -1611,9 +1611,16 @@ public final class ContactsContract { } /** + * <p> * A sub-directory of a single contact that contains all of the constituent raw contact * {@link ContactsContract.StreamItems} rows. This directory can be used either * with a {@link #CONTENT_URI} or {@link #CONTENT_LOOKUP_URI}. + * </p> + * <p> + * Querying for social stream data requires android.permission.READ_SOCIAL_STREAM + * permission. + * </p> + * @hide */ public static final class StreamItems implements StreamItemsColumns { /** @@ -2669,6 +2676,14 @@ public final class ContactsContract { * {@link ContactsContract.StreamItems} for a stand-alone table containing the * same data. * </p> + * <p> + * Access to the social stream through this sub-directory requires additional permissions + * beyond the read/write contact permissions required by the provider. Querying for + * social stream data requires android.permission.READ_SOCIAL_STREAM permission, and + * inserting or updating social stream items requires android.permission.WRITE_SOCIAL_STREAM + * permission. + * </p> + * @hide */ public static final class StreamItems implements BaseColumns, StreamItemsColumns { /** @@ -2963,6 +2978,12 @@ public final class ContactsContract { * transaction correspondingly. Insertion of more items beyond the limit will * automatically lead to deletion of the oldest items, by {@link StreamItems#TIMESTAMP}. * </p> + * <p> + * Access to the social stream through these URIs requires additional permissions beyond the + * read/write contact permissions required by the provider. Querying for social stream data + * requires android.permission.READ_SOCIAL_STREAM permission, and inserting or updating social + * stream items requires android.permission.WRITE_SOCIAL_STREAM permission. + * </p> * <h3>Operations</h3> * <dl> * <dt><b>Insert</b></dt> @@ -3075,6 +3096,7 @@ public final class ContactsContract { * </pre> * </dd> * </dl> + * @hide */ public static final class StreamItems implements BaseColumns, StreamItemsColumns { /** @@ -3135,6 +3157,12 @@ public final class ContactsContract { * directory append {@link StreamItems.StreamItemPhotos#CONTENT_DIRECTORY} to * an individual stream item URI. * </p> + * <p> + * Access to social stream photos requires additional permissions beyond the read/write + * contact permissions required by the provider. Querying for social stream photos + * requires android.permission.READ_SOCIAL_STREAM permission, and inserting or updating + * social stream photos requires android.permission.WRITE_SOCIAL_STREAM permission. + * </p> */ public static final class StreamItemPhotos implements BaseColumns, StreamItemPhotosColumns { @@ -3166,6 +3194,7 @@ public final class ContactsContract { * Columns in the StreamItems table. * * @see ContactsContract.StreamItems + * @hide */ protected interface StreamItemsColumns { /** @@ -3312,6 +3341,12 @@ public final class ContactsContract { * Constants for the stream_item_photos table, which contains photos associated with * social stream updates. * </p> + * <p> + * Access to social stream photos requires additional permissions beyond the read/write + * contact permissions required by the provider. Querying for social stream photos + * requires android.permission.READ_SOCIAL_STREAM permission, and inserting or updating + * social stream photos requires android.permission.WRITE_SOCIAL_STREAM permission. + * </p> * <h3>Operations</h3> * <dl> * <dt><b>Insert</b></dt> @@ -3450,6 +3485,7 @@ public final class ContactsContract { * <pre> * </dd> * </dl> + * @hide */ public static final class StreamItemPhotos implements BaseColumns, StreamItemPhotosColumns { /** @@ -3477,6 +3513,7 @@ public final class ContactsContract { * Columns in the StreamItemPhotos table. * * @see ContactsContract.StreamItemPhotos + * @hide */ protected interface StreamItemPhotosColumns { /** diff --git a/core/java/android/speech/tts/TextToSpeech.java b/core/java/android/speech/tts/TextToSpeech.java index 5126e482894d..98ab31081225 100755 --- a/core/java/android/speech/tts/TextToSpeech.java +++ b/core/java/android/speech/tts/TextToSpeech.java @@ -440,6 +440,9 @@ public class TextToSpeech { private final Context mContext; private Connection mServiceConnection; private OnInitListener mInitListener; + // Written from an unspecified application thread, read from + // a binder thread. + private volatile OnUtteranceCompletedListener mUtteranceCompletedListener; private final Object mStartLock = new Object(); private String mRequestedEngine; @@ -1071,20 +1074,8 @@ public class TextToSpeech { * @return {@link #ERROR} or {@link #SUCCESS}. */ public int setOnUtteranceCompletedListener(final OnUtteranceCompletedListener listener) { - return runAction(new Action<Integer>() { - @Override - public Integer run(ITextToSpeechService service) throws RemoteException { - ITextToSpeechCallback.Stub callback = new ITextToSpeechCallback.Stub() { - public void utteranceCompleted(String utteranceId) { - if (listener != null) { - listener.onUtteranceCompleted(utteranceId); - } - } - }; - service.setCallback(getPackageName(), callback); - return SUCCESS; - } - }, ERROR, "setOnUtteranceCompletedListener"); + mUtteranceCompletedListener = listener; + return TextToSpeech.SUCCESS; } /** @@ -1137,6 +1128,15 @@ public class TextToSpeech { private class Connection implements ServiceConnection { private ITextToSpeechService mService; + private final ITextToSpeechCallback.Stub mCallback = new ITextToSpeechCallback.Stub() { + @Override + public void utteranceCompleted(String utteranceId) { + OnUtteranceCompletedListener listener = mUtteranceCompletedListener; + if (listener != null) { + listener.onUtteranceCompleted(utteranceId); + } + } + }; public void onServiceConnected(ComponentName name, IBinder service) { Log.i(TAG, "Connected to " + name); @@ -1147,7 +1147,13 @@ public class TextToSpeech { } mServiceConnection = this; mService = ITextToSpeechService.Stub.asInterface(service); - dispatchOnInit(SUCCESS); + try { + mService.setCallback(getPackageName(), mCallback); + dispatchOnInit(SUCCESS); + } catch (RemoteException re) { + Log.e(TAG, "Error connecting to service, setCallback() failed"); + dispatchOnInit(ERROR); + } } } diff --git a/core/java/android/text/DynamicLayout.java b/core/java/android/text/DynamicLayout.java index c3a2308d9df7..f82c9c4f06e8 100644 --- a/core/java/android/text/DynamicLayout.java +++ b/core/java/android/text/DynamicLayout.java @@ -76,7 +76,7 @@ extends Layout boolean includepad, TextUtils.TruncateAt ellipsize, int ellipsizedWidth) { this(base, display, paint, width, align, TextDirectionHeuristics.FIRSTSTRONG_LTR, - spacingmult, spacingadd, includepad, ellipsize, ellipsizedWidth, Integer.MAX_VALUE); + spacingmult, spacingadd, includepad, ellipsize, ellipsizedWidth); } /** @@ -93,7 +93,7 @@ extends Layout int width, Alignment align, TextDirectionHeuristic textDir, float spacingmult, float spacingadd, boolean includepad, - TextUtils.TruncateAt ellipsize, int ellipsizedWidth, int maxLines) { + TextUtils.TruncateAt ellipsize, int ellipsizedWidth) { super((ellipsize == null) ? display : (display instanceof Spanned) @@ -135,8 +135,6 @@ extends Layout mEllipsize = true; } - mMaxLines = maxLines; - // Initial state is a single line with 0 characters (0 to 0), // with top at 0 and bottom at whatever is natural, and // undefined ellipsis. @@ -285,7 +283,7 @@ extends Layout reflowed.generate(text, where, where + after, getPaint(), getWidth(), getAlignment(), getTextDirectionHeuristic(), getSpacingMultiplier(), getSpacingAdd(), - false, true, mEllipsizedWidth, mEllipsizeAt, mMaxLines); + false, true, mEllipsizedWidth, mEllipsizeAt); int n = reflowed.getLineCount(); // If the new layout has a blank line at the end, but it is not @@ -490,8 +488,6 @@ extends Layout private int mTopPadding, mBottomPadding; - private int mMaxLines; - private static StaticLayout sStaticLayout = new StaticLayout(null); private static final Object[] sLock = new Object[0]; diff --git a/core/java/android/text/StaticLayout.java b/core/java/android/text/StaticLayout.java index 7c273964fa5d..583cbe615fa4 100644 --- a/core/java/android/text/StaticLayout.java +++ b/core/java/android/text/StaticLayout.java @@ -139,7 +139,7 @@ public class StaticLayout extends Layout { generate(source, bufstart, bufend, paint, outerwidth, align, textDir, spacingmult, spacingadd, includepad, includepad, - ellipsizedWidth, ellipsize, mMaximumVisibleLineCount); + ellipsizedWidth, ellipsize); mMeasured = MeasuredText.recycle(mMeasured); mFontMetricsInt = null; @@ -160,7 +160,7 @@ public class StaticLayout extends Layout { Alignment align, TextDirectionHeuristic textDir, float spacingmult, float spacingadd, boolean includepad, boolean trackpad, - float ellipsizedWidth, TextUtils.TruncateAt ellipsize, int maxLines) { + float ellipsizedWidth, TextUtils.TruncateAt ellipsize) { mLineCount = 0; int v = 0; @@ -477,13 +477,13 @@ public class StaticLayout extends Layout { width = restWidth; } } - if (mLineCount >= maxLines) { + if (mLineCount >= mMaximumVisibleLineCount) { break; } } } - if (paraEnd != here && mLineCount < maxLines) { + if (paraEnd != here && mLineCount < mMaximumVisibleLineCount) { if ((fitTop | fitBottom | fitDescent | fitAscent) == 0) { paint.getFontMetricsInt(fm); @@ -514,7 +514,7 @@ public class StaticLayout extends Layout { } if ((bufEnd == bufStart || source.charAt(bufEnd - 1) == CHAR_NEW_LINE) && - mLineCount < maxLines) { + mLineCount < mMaximumVisibleLineCount) { // Log.e("text", "output last " + bufEnd); paint.getFontMetricsInt(fm); diff --git a/core/java/android/webkit/BrowserFrame.java b/core/java/android/webkit/BrowserFrame.java index 28f54aa08e7c..8c22da09c15c 100644 --- a/core/java/android/webkit/BrowserFrame.java +++ b/core/java/android/webkit/BrowserFrame.java @@ -43,7 +43,6 @@ import junit.framework.Assert; import java.io.IOException; import java.io.InputStream; import java.lang.ref.WeakReference; -import java.net.URL; import java.net.URLEncoder; import java.nio.charset.Charsets; import java.security.PrivateKey; @@ -472,8 +471,6 @@ class BrowserFrame extends Handler { /** * We have received an SSL certificate for the main top-level page. - * - * !!!Called from the network thread!!! */ void certificate(SslCertificate certificate) { if (mIsMainFrame) { @@ -1171,12 +1168,7 @@ class BrowserFrame extends Handler { try { X509Certificate cert = new X509CertImpl(certDER); SslCertificate sslCert = new SslCertificate(cert); - if (JniUtil.useChromiumHttpStack()) { - sslError = SslError.SslErrorFromChromiumErrorCode(certError, sslCert, - new URL(url).getHost()); - } else { - sslError = new SslError(certError, cert, url); - } + sslError = SslError.SslErrorFromChromiumErrorCode(certError, sslCert, url); } catch (IOException e) { // Can't get the certificate, not much to do. Log.e(LOGTAG, "Can't get the certificate from WebKit, canceling"); @@ -1192,12 +1184,11 @@ class BrowserFrame extends Handler { SslErrorHandler handler = new SslErrorHandler() { @Override public void proceed() { - SslCertLookupTable.getInstance().setIsAllowed(sslError, true); + SslCertLookupTable.getInstance().setIsAllowed(sslError); nativeSslCertErrorProceed(handle); } @Override public void cancel() { - SslCertLookupTable.getInstance().setIsAllowed(sslError, false); nativeSslCertErrorCancel(handle, certError); } }; diff --git a/core/java/android/webkit/SslCertLookupTable.java b/core/java/android/webkit/SslCertLookupTable.java index 052244f95f89..a06836cfaa68 100644 --- a/core/java/android/webkit/SslCertLookupTable.java +++ b/core/java/android/webkit/SslCertLookupTable.java @@ -19,10 +19,14 @@ package android.webkit; import android.os.Bundle; import android.net.http.SslError; +import java.net.MalformedURLException; +import java.net.URL; + /** * Stores the user's decision of whether to allow or deny an invalid certificate. * - * This class is not threadsafe. It is used only on the WebCore thread. + * This class is not threadsafe. It is used only on the WebCore thread. Also, it + * is used only by the Chromium HTTP stack. */ final class SslCertLookupTable { private static SslCertLookupTable sTable; @@ -39,15 +43,33 @@ final class SslCertLookupTable { table = new Bundle(); } - public void setIsAllowed(SslError sslError, boolean allow) { - table.putBoolean(sslError.toString(), allow); + public void setIsAllowed(SslError sslError) { + // TODO: We should key on just the host. See http://b/5409251. + String errorString = sslErrorToString(sslError); + if (errorString != null) { + table.putBoolean(errorString, true); + } } public boolean isAllowed(SslError sslError) { - return table.getBoolean(sslError.toString()); + // TODO: We should key on just the host. See http://b/5409251. + String errorString = sslErrorToString(sslError); + return errorString == null ? false : table.getBoolean(errorString); } public void clear() { table.clear(); } + + private static String sslErrorToString(SslError error) { + String host; + try { + host = new URL(error.getUrl()).getHost(); + } catch(MalformedURLException e) { + return null; + } + return "primary error: " + error.getPrimaryError() + + " certificate: " + error.getCertificate() + + " on host: " + host; + } } diff --git a/core/java/android/webkit/SslErrorHandlerImpl.java b/core/java/android/webkit/SslErrorHandlerImpl.java index e029e372c141..82cd3e80448a 100644 --- a/core/java/android/webkit/SslErrorHandlerImpl.java +++ b/core/java/android/webkit/SslErrorHandlerImpl.java @@ -16,8 +16,6 @@ package android.webkit; -import junit.framework.Assert; - import android.net.http.SslError; import android.os.Bundle; import android.os.Handler; @@ -54,7 +52,7 @@ class SslErrorHandlerImpl extends SslErrorHandler { private final SslErrorHandler mOriginHandler; private final LoadListener mLoadListener; - // Message id for handling the response + // Message id for handling the response from the client. private static final int HANDLE_RESPONSE = 100; @Override @@ -130,7 +128,9 @@ class SslErrorHandlerImpl extends SslErrorHandler { } /** - * Handles SSL error(s) on the way up to the user. + * Handles requests from the network stack about whether to proceed with a + * load given an SSL error(s). We may ask the client what to do, or use a + * cached response. */ /* package */ synchronized void handleSslErrorRequest(LoadListener loader) { if (DebugFlags.SSL_ERROR_HANDLER) { @@ -147,8 +147,10 @@ class SslErrorHandlerImpl extends SslErrorHandler { } /** - * Check the preference table for a ssl error that has already been shown - * to the user. + * Check the preference table to see if we already have a 'proceed' decision + * from the client for this host and for an error of equal or greater + * severity than the supplied error. If so, instruct the loader to proceed + * and return true. Otherwise return false. */ /* package */ synchronized boolean checkSslPrefTable(LoadListener loader, SslError error) { @@ -156,21 +158,22 @@ class SslErrorHandlerImpl extends SslErrorHandler { final int primary = error.getPrimaryError(); if (DebugFlags.SSL_ERROR_HANDLER) { - Assert.assertTrue(host != null && primary != 0); + assert host != null; + assert primary != 0; } - if (mSslPrefTable.containsKey(host)) { - if (primary <= mSslPrefTable.getInt(host)) { - handleSslErrorResponse(loader, error, true); - return true; + if (mSslPrefTable.containsKey(host) && primary <= mSslPrefTable.getInt(host)) { + if (!loader.cancelled()) { + loader.handleSslErrorResponse(true); } + return true; } return false; } /** * Processes queued SSL-error confirmation requests in - * a tight loop while there is no need to ask the user. + * a tight loop while there is no need to ask the client. */ /* package */void fastProcessQueuedSslErrors() { while (processNextLoader()); @@ -195,19 +198,18 @@ class SslErrorHandlerImpl extends SslErrorHandler { SslError error = loader.sslError(); if (DebugFlags.SSL_ERROR_HANDLER) { - Assert.assertNotNull(error); + assert error != null; } - // checkSslPrefTable will handle the ssl error response if the - // answer is available. It does not remove the loader from the - // queue. + // checkSslPrefTable() will instruct the loader to proceed if we + // have a cached 'proceed' decision. It does not remove the loader + // from the queue. if (checkSslPrefTable(loader, error)) { mLoaderQueue.remove(loader); return true; } - // if we do not have information on record, ask - // the user (display a dialog) + // If we can not proceed based on a cached decision, ask the client. CallbackProxy proxy = loader.getFrame().getCallbackProxy(); proxy.onReceivedSslError(new SslErrorHandlerImpl(this, loader), error); } @@ -217,32 +219,31 @@ class SslErrorHandlerImpl extends SslErrorHandler { } /** - * Proceed with the SSL certificate. + * Proceed with this load. */ public void proceed() { - mOriginHandler.sendMessage( - mOriginHandler.obtainMessage( - HANDLE_RESPONSE, 1, 0, mLoadListener)); + mOriginHandler.sendMessage(mOriginHandler.obtainMessage( + HANDLE_RESPONSE, 1, 0, mLoadListener)); } /** - * Cancel this request and all pending requests for the WebView that had - * the error. + * Cancel this load and all pending loads for the WebView that had the + * error. */ public void cancel() { - mOriginHandler.sendMessage( - mOriginHandler.obtainMessage( - HANDLE_RESPONSE, 0, 0, mLoadListener)); + mOriginHandler.sendMessage(mOriginHandler.obtainMessage( + HANDLE_RESPONSE, 0, 0, mLoadListener)); } /** - * Handles SSL error(s) on the way down from the user. + * Handles the response from the client about whether to proceed with this + * load. We save the response to be re-used in the future. */ /* package */ synchronized void handleSslErrorResponse(LoadListener loader, SslError error, boolean proceed) { if (DebugFlags.SSL_ERROR_HANDLER) { - Assert.assertNotNull(loader); - Assert.assertNotNull(error); + assert loader != null; + assert error != null; } if (DebugFlags.SSL_ERROR_HANDLER) { @@ -253,16 +254,16 @@ class SslErrorHandlerImpl extends SslErrorHandler { if (!loader.cancelled()) { if (proceed) { - // update the user's SSL error preference table + // Update the SSL error preference table int primary = error.getPrimaryError(); String host = loader.host(); if (DebugFlags.SSL_ERROR_HANDLER) { - Assert.assertTrue(host != null && primary != 0); + assert host != null; + assert primary != 0; } boolean hasKey = mSslPrefTable.containsKey(host); - if (!hasKey || - primary > mSslPrefTable.getInt(host)) { + if (!hasKey || primary > mSslPrefTable.getInt(host)) { mSslPrefTable.putInt(host, primary); } } diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java index 17f0e0585690..f7a9dc1f6b85 100644 --- a/core/java/android/widget/TextView.java +++ b/core/java/android/widget/TextView.java @@ -6262,7 +6262,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener result = new DynamicLayout(mText, mTransformed, mTextPaint, w, alignment, mTextDir, mSpacingMult, mSpacingAdd, mIncludePad, mInput == null ? effectiveEllipsize : null, - ellipsisWidth, mMaxMode == LINES ? mMaximum : Integer.MAX_VALUE); + ellipsisWidth); } else { if (boring == UNKNOWN_BORING) { boring = BoringLayout.isBoring(mTransformed, mTextPaint, mTextDir, mBoring); diff --git a/core/java/com/android/internal/widget/LockPatternUtils.java b/core/java/com/android/internal/widget/LockPatternUtils.java index 2694aa21cf77..d5450e4ab9bf 100644 --- a/core/java/com/android/internal/widget/LockPatternUtils.java +++ b/core/java/com/android/internal/widget/LockPatternUtils.java @@ -119,6 +119,8 @@ public class LockPatternUtils { private final static String LOCKSCREEN_OPTIONS = "lockscreen.options"; public final static String LOCKSCREEN_BIOMETRIC_WEAK_FALLBACK = "lockscreen.biometric_weak_fallback"; + public final static String BIOMETRIC_WEAK_EVER_CHOSEN_KEY + = "lockscreen.biometricweakeverchosen"; private final static String PASSWORD_HISTORY_KEY = "lockscreen.passwordhistory"; @@ -341,6 +343,16 @@ public class LockPatternUtils { } /** + * Return true if the user has ever chosen biometric weak. This is true even if biometric + * weak is not current set. + * + * @return True if the user has ever chosen biometric weak. + */ + public boolean isBiometricWeakEverChosen() { + return getBoolean(BIOMETRIC_WEAK_EVER_CHOSEN_KEY); + } + + /** * Used by device policy manager to validate the current password * information it has. */ @@ -489,6 +501,7 @@ public class LockPatternUtils { setLong(PASSWORD_TYPE_KEY, DevicePolicyManager.PASSWORD_QUALITY_BIOMETRIC_WEAK); setLong(PASSWORD_TYPE_ALTERNATE_KEY, DevicePolicyManager.PASSWORD_QUALITY_SOMETHING); + setBoolean(BIOMETRIC_WEAK_EVER_CHOSEN_KEY, true); moveTempGallery(); } dpm.setActivePasswordState(DevicePolicyManager.PASSWORD_QUALITY_SOMETHING, pattern @@ -606,6 +619,7 @@ public class LockPatternUtils { } else { setLong(PASSWORD_TYPE_KEY, DevicePolicyManager.PASSWORD_QUALITY_BIOMETRIC_WEAK); setLong(PASSWORD_TYPE_ALTERNATE_KEY, Math.max(quality, computedQuality)); + setBoolean(BIOMETRIC_WEAK_EVER_CHOSEN_KEY, true); moveTempGallery(); } if (computedQuality != DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED) { diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml index 9755f227a63f..18194ee0f298 100644 --- a/core/res/AndroidManifest.xml +++ b/core/res/AndroidManifest.xml @@ -263,6 +263,23 @@ android:label="@string/permlab_writeProfile" android:description="@string/permdesc_writeProfile" /> + <!-- Allows an application to read from the user's social stream. + @hide --> + <permission android:name="android.permission.READ_SOCIAL_STREAM" + android:permissionGroup="android.permission-group.PERSONAL_INFO" + android:protectionLevel="dangerous" + android:label="@string/permlab_readSocialStream" + android:description="@string/permdesc_readSocialStream" /> + + <!-- Allows an application to write (but not read) the user's + social stream data. + @hide --> + <permission android:name="android.permission.WRITE_SOCIAL_STREAM" + android:permissionGroup="android.permission-group.PERSONAL_INFO" + android:protectionLevel="dangerous" + android:label="@string/permlab_writeSocialStream" + android:description="@string/permdesc_writeSocialStream" /> + <!-- Allows an application to read the user's calendar data. --> <permission android:name="android.permission.READ_CALENDAR" android:permissionGroup="android.permission-group.PERSONAL_INFO" diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml index 1e0151afee7a..b1dc252d16dc 100755 --- a/core/res/res/values/strings.xml +++ b/core/res/res/values/strings.xml @@ -941,6 +941,19 @@ information. This means other applications can identify you and send your profile information to others.</string> + <!-- Title of the read social stream permission, listed so the user can decide whether to allow the application to read information from the user's social stream. [CHAR LIMIT=30] --> + <string name="permlab_readSocialStream" product="default">read your social stream</string> + <string name="permdesc_readSocialStream" product="default">Allows the application to access + and sync social updates from you and your friends. Malicious apps can use this to read + private communications between you and your friends on social networks.</string> + + <!-- Title of the write social stream permission, listed so the user can decide whether to allow the application to write information to the user's social stream. [CHAR LIMIT=30] --> + <string name="permlab_writeSocialStream" product="default">write to your social stream</string> + <string name="permdesc_writeSocialStream" product="default">Allows the application to display + social updates from your friends. Malicious apps can use this to pretend to be a friend + and trick you into revealing passwords or other confidential information.</string> + + <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. --> <string name="permlab_readCalendar">read calendar events plus confidential information</string> <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. --> @@ -3216,8 +3229,9 @@ <string name="description_target_soundon">Sound on</string> <!-- Announce that a headset is required to hear keyboard keys while typing a password. [CHAR LIMIT=NONE] --> - <string name="keyboard_headset_required_to_hear_password">Key. Headset required to hear - keys while typing a password.</string> + <string name="keyboard_headset_required_to_hear_password">Plug in a headset to hear password keys spoken aloud.</string> + <!-- The value of a keyboard key announced when accessibility is enabled and no headsed is used. [CHAR LIMIT=NONE] --> + <string name="keyboard_password_character_no_headset">Dot.</string> <!-- Content description for the action bar "home" affordance. [CHAR LIMIT=NONE] --> <string name="action_bar_home_description">Navigate home</string> @@ -3316,4 +3330,4 @@ <!-- Delimeter used between each item in a textual list; for example "Alpha, Beta". [CHAR LIMIT=3] --> <string name="list_delimeter">", "</string> -</resources>
\ No newline at end of file +</resources> diff --git a/data/fonts/fonts.xml b/data/fonts/fonts.xml deleted file mode 100644 index 1fd7bba2ef3c..000000000000 --- a/data/fonts/fonts.xml +++ /dev/null @@ -1,48 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<!-- Copyright (C) 2008 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. ---> -<!-- - This is only used by the layoutlib to display - layouts in ADT. ---> -<fonts> - <font ttf="DroidSans"> - <name>sans-serif</name> - <name>arial</name> - <name>helvetica</name> - <name>tahoma</name> - <name>verdana</name> - </font> - <font ttf="DroidSerif"> - <name>serif</name> - <name>times</name> - <name>times new roman</name> - <name>palatino</name> - <name>georgia</name> - <name>baskerville</name> - <name>goudy</name> - <name>fantasy</name> - <name>cursive</name> - <name>ITC Stone Serif</name> - </font> - <font ttf="DroidSansMono"> - <name>monospace</name> - <name>courier</name> - <name>courier new</name> - <name>monaco</name> - </font> - <fallback ttf="DroidSansFallback" /> - <fallback ttf="MTLmr3m" /> -</fonts> diff --git a/docs/html/resources/resources-data.js b/docs/html/resources/resources-data.js index 6c5d882908d0..d7700eecd8dc 100644 --- a/docs/html/resources/resources-data.js +++ b/docs/html/resources/resources-data.js @@ -408,6 +408,16 @@ var ANDROID_RESOURCES = [ } }, { + tags: ['sample', 'new'], + path: 'samples/AndroidBeam/index.html', + title: { + en: 'Android Beam' + }, + description: { + en: 'An example of how to use the Android Beam feature to send messages between two Android-powered devices (API level 14 or later) that support NFC.' + } + }, + { tags: ['sample', 'layout', 'ui'], path: 'samples/ApiDemos/index.html', title: { diff --git a/include/media/stagefright/OMXCodec.h b/include/media/stagefright/OMXCodec.h index 21b8c7443916..0d5a72638686 100644 --- a/include/media/stagefright/OMXCodec.h +++ b/include/media/stagefright/OMXCodec.h @@ -319,6 +319,8 @@ private: void initOutputFormat(const sp<MetaData> &inputFormat); status_t initNativeWindow(); + void initNativeWindowCrop(); + void dumpPortStatus(OMX_U32 portIndex); status_t configureCodec(const sp<MetaData> &meta); diff --git a/libs/hwui/Snapshot.h b/libs/hwui/Snapshot.h index bd7031927b5e..d51154d0710f 100644 --- a/libs/hwui/Snapshot.h +++ b/libs/hwui/Snapshot.h @@ -70,13 +70,6 @@ public: clipRect = s->clipRect; } - if ((s->flags & Snapshot::kFlagClipSet) && - !(s->flags & Snapshot::kFlagDirtyLocalClip)) { - mLocalClip.set(s->mLocalClip); - } else { - flags |= Snapshot::kFlagDirtyLocalClip; - } - if (s->flags & Snapshot::kFlagFboTarget) { flags |= Snapshot::kFlagFboTarget; region = s->region; @@ -106,18 +99,14 @@ public: */ kFlagIsFboLayer = 0x4, /** - * Indicates that the local clip should be recomputed. - */ - kFlagDirtyLocalClip = 0x8, - /** * Indicates that this snapshot has changed the ortho matrix. */ - kFlagDirtyOrtho = 0x10, + kFlagDirtyOrtho = 0x8, /** * Indicates that this snapshot or an ancestor snapshot is * an FBO layer. */ - kFlagFboTarget = 0x20 + kFlagFboTarget = 0x10 }; /** @@ -169,7 +158,7 @@ public: } if (clipped) { - flags |= Snapshot::kFlagClipSet | Snapshot::kFlagDirtyLocalClip; + flags |= Snapshot::kFlagClipSet; } return clipped; @@ -180,19 +169,16 @@ public: */ void setClip(float left, float top, float right, float bottom) { clipRect->set(left, top, right, bottom); - flags |= Snapshot::kFlagClipSet | Snapshot::kFlagDirtyLocalClip; + flags |= Snapshot::kFlagClipSet; } const Rect& getLocalClip() { - if (flags & Snapshot::kFlagDirtyLocalClip) { - mat4 inverse; - inverse.loadInverse(*transform); + mat4 inverse; + inverse.loadInverse(*transform); - mLocalClip.set(*clipRect); - inverse.mapRect(mLocalClip); + mLocalClip.set(*clipRect); + inverse.mapRect(mLocalClip); - flags &= ~Snapshot::kFlagDirtyLocalClip; - } return mLocalClip; } @@ -204,7 +190,7 @@ public: void resetClip(float left, float top, float right, float bottom) { clipRect = &mClipRectRoot; clipRect->set(left, top, right, bottom); - flags |= Snapshot::kFlagClipSet | Snapshot::kFlagDirtyLocalClip; + flags |= Snapshot::kFlagClipSet; } bool isIgnored() const { diff --git a/libs/rs/driver/rsdBcc.cpp b/libs/rs/driver/rsdBcc.cpp index 0755fb7dfc03..5fd5c35168c7 100644 --- a/libs/rs/driver/rsdBcc.cpp +++ b/libs/rs/driver/rsdBcc.cpp @@ -302,7 +302,10 @@ void rsdScriptInvokeForEach(const Context *rsc, DrvScript *drv = (DrvScript *)s->mHal.drv; // We only support slot 0 (root) at this point in time. rsAssert(slot == 0); - mtls.sig = drv->mExportForEachSignatureList[slot]; + mtls.sig = 0x1f; // temp fix for old apps, full table in slang_rs_export_foreach.cpp + if (drv->mExportForEachSignatureList) { + mtls.sig = drv->mExportForEachSignatureList[slot]; + } if (ain) { mtls.dimX = ain->getType()->getDimX(); mtls.dimY = ain->getType()->getDimY(); diff --git a/media/libstagefright/OMXCodec.cpp b/media/libstagefright/OMXCodec.cpp index ccc8a18aa673..7c34257a383d 100755 --- a/media/libstagefright/OMXCodec.cpp +++ b/media/libstagefright/OMXCodec.cpp @@ -2351,22 +2351,6 @@ void OMXCodec::onEvent(OMX_EVENTTYPE event, OMX_U32 data1, OMX_U32 data2) { formatHasNotablyChanged(oldOutputFormat, mOutputFormat)) { mOutputPortSettingsHaveChanged = true; - if (mNativeWindow != NULL) { - int32_t left, top, right, bottom; - CHECK(mOutputFormat->findRect( - kKeyCropRect, - &left, &top, &right, &bottom)); - - android_native_rect_t crop; - crop.left = left; - crop.top = top; - crop.right = right + 1; - crop.bottom = bottom + 1; - - // We'll ignore any errors here, if the surface is - // already invalid, we'll know soon enough. - native_window_set_crop(mNativeWindow.get(), &crop); - } } else if (data2 == OMX_IndexConfigCommonScale) { OMX_CONFIG_SCALEFACTORTYPE scale; InitOMXParams(&scale); @@ -4183,6 +4167,24 @@ status_t OMXCodec::initNativeWindow() { return OK; } +void OMXCodec::initNativeWindowCrop() { + int32_t left, top, right, bottom; + + CHECK(mOutputFormat->findRect( + kKeyCropRect, + &left, &top, &right, &bottom)); + + android_native_rect_t crop; + crop.left = left; + crop.top = top; + crop.right = right + 1; + crop.bottom = bottom + 1; + + // We'll ignore any errors here, if the surface is + // already invalid, we'll know soon enough. + native_window_set_crop(mNativeWindow.get(), &crop); +} + void OMXCodec::initOutputFormat(const sp<MetaData> &inputFormat) { mOutputFormat = new MetaData; mOutputFormat->setCString(kKeyDecoderComponent, mComponentName); @@ -4366,6 +4368,10 @@ void OMXCodec::initOutputFormat(const sp<MetaData> &inputFormat) { video_def->nFrameWidth - 1, video_def->nFrameHeight - 1); } + + if (mNativeWindow != NULL) { + initNativeWindowCrop(); + } } break; } diff --git a/policy/src/com/android/internal/policy/impl/LockPatternKeyguardView.java b/policy/src/com/android/internal/policy/impl/LockPatternKeyguardView.java index ca5d27467b3d..899a7610b40c 100644 --- a/policy/src/com/android/internal/policy/impl/LockPatternKeyguardView.java +++ b/policy/src/com/android/internal/policy/impl/LockPatternKeyguardView.java @@ -231,6 +231,8 @@ public class LockPatternKeyguardView extends KeyguardViewBase implements Handler } }; + private TransportControlView mTransportControlView; + /** * @return Whether we are stuck on the lock screen because the sim is * missing. @@ -516,7 +518,10 @@ public class LockPatternKeyguardView extends KeyguardViewBase implements Handler // When screen is turned on, need to bind to FaceLock service if we are using FaceLock // But only if not dealing with a call - if (mUpdateMonitor.getPhoneState() == TelephonyManager.CALL_STATE_IDLE) { + final boolean transportInvisible = mTransportControlView == null ? true : + mTransportControlView.getVisibility() != View.VISIBLE; + if (mUpdateMonitor.getPhoneState() == TelephonyManager.CALL_STATE_IDLE + && transportInvisible) { bindToFaceLock(); } else { mHandler.sendEmptyMessage(MSG_HIDE_FACELOCK_AREA_VIEW); @@ -805,14 +810,13 @@ public class LockPatternKeyguardView extends KeyguardViewBase implements Handler } private void initializeTransportControlView(View view) { - com.android.internal.widget.TransportControlView tcv = - (TransportControlView) view.findViewById(R.id.transport); - if (tcv == null) { + mTransportControlView = (TransportControlView) view.findViewById(R.id.transport); + if (mTransportControlView == null) { if (DEBUG) Log.w(TAG, "Couldn't find transport control widget"); } else { mUpdateMonitor.reportClockVisible(true); - tcv.setVisibility(View.GONE); // hide tcv until we get the callback below to show it. - tcv.setCallback(mWidgetCallback); + mTransportControlView.setVisibility(View.GONE); // hide until it requests being shown. + mTransportControlView.setCallback(mWidgetCallback); } } diff --git a/services/java/com/android/server/BackupManagerService.java b/services/java/com/android/server/BackupManagerService.java index fe49cd2bd4c8..7b8657a03f26 100644 --- a/services/java/com/android/server/BackupManagerService.java +++ b/services/java/com/android/server/BackupManagerService.java @@ -325,14 +325,16 @@ class BackupManagerService extends IBackupManager.Stub { public boolean includeApks; public boolean includeShared; public boolean allApps; + public boolean includeSystem; public String[] packages; FullBackupParams(ParcelFileDescriptor output, boolean saveApks, boolean saveShared, - boolean doAllApps, String[] pkgList) { + boolean doAllApps, boolean doSystem, String[] pkgList) { fd = output; includeApks = saveApks; includeShared = saveShared; allApps = doAllApps; + includeSystem = doSystem; packages = pkgList; } } @@ -504,7 +506,7 @@ class BackupManagerService extends IBackupManager.Stub { PerformFullBackupTask task = new PerformFullBackupTask(params.fd, params.observer, params.includeApks, params.includeShared, params.curPassword, params.encryptPassword, - params.allApps, params.packages, params.latch); + params.allApps, params.includeSystem, params.packages, params.latch); (new Thread(task)).start(); break; } @@ -2161,6 +2163,7 @@ class BackupManagerService extends IBackupManager.Stub { boolean mIncludeApks; boolean mIncludeShared; boolean mAllApps; + final boolean mIncludeSystem; String[] mPackages; String mCurrentPassword; String mEncryptPassword; @@ -2219,13 +2222,14 @@ class BackupManagerService extends IBackupManager.Stub { PerformFullBackupTask(ParcelFileDescriptor fd, IFullBackupRestoreObserver observer, boolean includeApks, boolean includeShared, String curPassword, - String encryptPassword, boolean doAllApps, String[] packages, + String encryptPassword, boolean doAllApps, boolean doSystem, String[] packages, AtomicBoolean latch) { mOutputFile = fd; mObserver = observer; mIncludeApks = includeApks; mIncludeShared = includeShared; mAllApps = doAllApps; + mIncludeSystem = doSystem; mPackages = packages; mCurrentPassword = curPassword; // when backing up, if there is a current backup password, we require that @@ -2245,7 +2249,7 @@ class BackupManagerService extends IBackupManager.Stub { @Override public void run() { - final List<PackageInfo> packagesToBackup; + List<PackageInfo> packagesToBackup = new ArrayList<PackageInfo>(); Slog.i(TAG, "--- Performing full-dataset backup ---"); sendStartBackup(); @@ -2254,8 +2258,23 @@ class BackupManagerService extends IBackupManager.Stub { if (mAllApps) { packagesToBackup = mPackageManager.getInstalledPackages( PackageManager.GET_SIGNATURES); - } else { - packagesToBackup = new ArrayList<PackageInfo>(); + // Exclude system apps if we've been asked to do so + if (mIncludeSystem == false) { + for (int i = 0; i < packagesToBackup.size(); ) { + PackageInfo pkg = packagesToBackup.get(i); + if ((pkg.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0) { + packagesToBackup.remove(i); + } else { + i++; + } + } + } + } + + // Now process the command line argument packages, if any. Note that explicitly- + // named system-partition packages will be included even if includeSystem was + // set to false. + if (mPackages != null) { for (String pkgName : mPackages) { try { packagesToBackup.add(mPackageManager.getPackageInfo(pkgName, @@ -2268,8 +2287,8 @@ class BackupManagerService extends IBackupManager.Stub { // Cull any packages that have indicated that backups are not permitted. for (int i = 0; i < packagesToBackup.size(); ) { - PackageInfo info = packagesToBackup.get(i); - if ((info.applicationInfo.flags & ApplicationInfo.FLAG_ALLOW_BACKUP) == 0) { + PackageInfo pkg = packagesToBackup.get(i); + if ((pkg.applicationInfo.flags & ApplicationInfo.FLAG_ALLOW_BACKUP) == 0) { packagesToBackup.remove(i); } else { i++; @@ -4781,7 +4800,7 @@ class BackupManagerService extends IBackupManager.Stub { // to the supplied file descriptor. This method is synchronous and does not return // to the caller until the backup has been completed. public void fullBackup(ParcelFileDescriptor fd, boolean includeApks, boolean includeShared, - boolean doAllApps, String[] pkgList) { + boolean doAllApps, boolean includeSystem, String[] pkgList) { mContext.enforceCallingPermission(android.Manifest.permission.BACKUP, "fullBackup"); // Validate @@ -4811,7 +4830,7 @@ class BackupManagerService extends IBackupManager.Stub { Slog.i(TAG, "Beginning full backup..."); FullBackupParams params = new FullBackupParams(fd, includeApks, includeShared, - doAllApps, pkgList); + doAllApps, includeSystem, pkgList); final int token = generateToken(); synchronized (mFullConfirmations) { mFullConfirmations.put(token, params); diff --git a/services/java/com/android/server/wm/WindowManagerService.java b/services/java/com/android/server/wm/WindowManagerService.java index 3ea9e817a1d8..73ac29612ea9 100644 --- a/services/java/com/android/server/wm/WindowManagerService.java +++ b/services/java/com/android/server/wm/WindowManagerService.java @@ -5704,6 +5704,7 @@ public class WindowManagerService extends IWindowManager.Stub Configuration computeNewConfigurationLocked() { Configuration config = new Configuration(); + config.fontScale = 0; if (!computeNewConfigurationLocked(config)) { return null; } diff --git a/tools/layoutlib/bridge/src/android/graphics/Paint_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/Paint_Delegate.java index e60a61c9fd97..1523823029c9 100644 --- a/tools/layoutlib/bridge/src/android/graphics/Paint_Delegate.java +++ b/tools/layoutlib/bridge/src/android/graphics/Paint_Delegate.java @@ -1166,7 +1166,7 @@ public class Paint_Delegate { if (mTextScaleX != 1.0 || mTextSkewX != 0) { // TODO: support skew info.mFont = info.mFont.deriveFont(new AffineTransform( - mTextScaleX, mTextSkewX, 0, 0, 1, 0)); + mTextScaleX, mTextSkewX, 0, 1, 0, 0)); } info.mMetrics = Toolkit.getDefaultToolkit().getFontMetrics(info.mFont); diff --git a/tools/layoutlib/bridge/src/android/graphics/Typeface_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/Typeface_Delegate.java index 0f084f7d7fc7..2414d705be8a 100644 --- a/tools/layoutlib/bridge/src/android/graphics/Typeface_Delegate.java +++ b/tools/layoutlib/bridge/src/android/graphics/Typeface_Delegate.java @@ -25,8 +25,8 @@ import com.android.tools.layoutlib.annotations.LayoutlibDelegate; import android.content.res.AssetManager; import java.awt.Font; +import java.io.File; import java.util.ArrayList; -import java.util.Collections; import java.util.List; /** @@ -44,13 +44,14 @@ import java.util.List; */ public final class Typeface_Delegate { + private static final String SYSTEM_FONTS = "/system/fonts/"; + // ---- delegate manager ---- private static final DelegateManager<Typeface_Delegate> sManager = new DelegateManager<Typeface_Delegate>(Typeface_Delegate.class); // ---- delegate helper data ---- private static final String DEFAULT_FAMILY = "sans-serif"; - private static final int[] STYLE_BUFFER = new int[1]; private static FontLoader sFontLoader; private static final List<Typeface_Delegate> sPostInitDelegate = @@ -145,9 +146,31 @@ public final class Typeface_Delegate { @LayoutlibDelegate /*package*/ static synchronized int nativeCreateFromFile(String path) { - Bridge.getLog().fidelityWarning(LayoutLog.TAG_UNSUPPORTED, - "Typeface.createFromFile() is not supported.", null /*throwable*/, null /*data*/); - return 0; + if (path.startsWith(SYSTEM_FONTS) ) { + String relativePath = path.substring(SYSTEM_FONTS.length()); + File f = new File(sFontLoader.getOsFontsLocation(), relativePath); + + try { + Font font = Font.createFont(Font.TRUETYPE_FONT, f); + if (font != null) { + Typeface_Delegate newDelegate = new Typeface_Delegate(font); + return sManager.addNewDelegate(newDelegate); + } + } catch (Exception e) { + Bridge.getLog().fidelityWarning(LayoutLog.TAG_BROKEN, + String.format("Unable to load font %1$s", relativePath), + null /*throwable*/, null /*data*/); + } + } else { + Bridge.getLog().fidelityWarning(LayoutLog.TAG_UNSUPPORTED, + "Typeface.createFromFile() can only work with platform fonts located in " + + SYSTEM_FONTS, + null /*throwable*/, null /*data*/); + } + + + // return a copy of the base font + return nativeCreate(null, 0); } @LayoutlibDelegate @@ -177,15 +200,17 @@ public final class Typeface_Delegate { mStyle = style; } + private Typeface_Delegate(Font font) { + mFamily = font.getFamily(); + mStyle = Typeface.NORMAL; + + mFonts = sFontLoader.getFallbackFonts(mStyle); + + // insert the font glyph first. + mFonts.add(0, font); + } + private void init() { - STYLE_BUFFER[0] = mStyle; - Font font = sFontLoader.getFont(mFamily, STYLE_BUFFER); - if (font != null) { - List<Font> list = new ArrayList<Font>(); - list.add(font); - list.addAll(sFontLoader.getFallBackFonts()); - mFonts = Collections.unmodifiableList(list); - mStyle = STYLE_BUFFER[0]; - } + mFonts = sFontLoader.getFont(mFamily, mStyle); } } diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/FontLoader.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/FontLoader.java index f62fad298bdd..081ce67c7950 100644 --- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/FontLoader.java +++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/FontLoader.java @@ -23,17 +23,13 @@ import org.xml.sax.helpers.DefaultHandler; import android.graphics.Typeface; import java.awt.Font; -import java.awt.FontFormatException; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.IOException; import java.util.ArrayList; -import java.util.Collections; -import java.util.HashMap; import java.util.HashSet; import java.util.List; -import java.util.Map; import java.util.Set; import javax.xml.parsers.ParserConfigurationException; @@ -47,49 +43,55 @@ import javax.xml.parsers.SAXParserFactory; * fonts.xml file located alongside the ttf files. */ public final class FontLoader { - private static final String FONTS_DEFINITIONS = "fonts.xml"; + private static final String FONTS_SYSTEM = "system_fonts.xml"; + private static final String FONTS_VENDOR = "vendor_fonts.xml"; + private static final String FONTS_FALLBACK = "fallback_fonts.xml"; - private static final String NODE_FONTS = "fonts"; - private static final String NODE_FONT = "font"; + private static final String NODE_FAMILYSET = "familyset"; + private static final String NODE_FAMILY = "family"; private static final String NODE_NAME = "name"; - private static final String NODE_FALLBACK = "fallback"; - - private static final String ATTR_TTF = "ttf"; - - private static final String FONT_EXT = ".ttf"; - - private static final String[] FONT_STYLE_DEFAULT = { "", "-Regular" }; - private static final String[] FONT_STYLE_BOLD = { "-Bold" }; - private static final String[] FONT_STYLE_ITALIC = { "-Italic" }; - private static final String[] FONT_STYLE_BOLDITALIC = { "-BoldItalic" }; - - // list of font style, in the order matching the Typeface Font style - private static final String[][] FONT_STYLES = { - FONT_STYLE_DEFAULT, - FONT_STYLE_BOLD, - FONT_STYLE_ITALIC, - FONT_STYLE_BOLDITALIC + private static final String NODE_FILE = "file"; + + private static final String FONT_SUFFIX_NONE = ".ttf"; + private static final String FONT_SUFFIX_REGULAR = "-Regular.ttf"; + private static final String FONT_SUFFIX_BOLD = "-Bold.ttf"; + private static final String FONT_SUFFIX_ITALIC = "-Italic.ttf"; + private static final String FONT_SUFFIX_BOLDITALIC = "-BoldItalic.ttf"; + + // This must match the values of Typeface styles so that we can use them for indices in this + // array. + private static final int[] AWT_STYLES = new int[] { + Font.PLAIN, + Font.BOLD, + Font.ITALIC, + Font.BOLD | Font.ITALIC + }; + private static int[] DERIVE_BOLD_ITALIC = new int[] { + Typeface.ITALIC, Typeface.BOLD, Typeface.NORMAL }; + private static int[] DERIVE_ITALIC = new int[] { Typeface.NORMAL }; + private static int[] DERIVE_BOLD = new int[] { Typeface.NORMAL }; - private final Map<String, String> mFamilyToTtf = new HashMap<String, String>(); - private final Map<String, Map<Integer, Font>> mTtfToFontMap = - new HashMap<String, Map<Integer, Font>>(); + private static final List<FontInfo> mMainFonts = new ArrayList<FontInfo>(); + private static final List<FontInfo> mFallbackFonts = new ArrayList<FontInfo>(); - private List<Font> mFallBackFonts = null; + private final String mOsFontsLocation; public static FontLoader create(String fontOsLocation) { try { SAXParserFactory parserFactory = SAXParserFactory.newInstance(); parserFactory.setNamespaceAware(true); - SAXParser parser = parserFactory.newSAXParser(); - File f = new File(fontOsLocation + File.separator + FONTS_DEFINITIONS); + // parse the system fonts + FontHandler handler = parseFontFile(parserFactory, fontOsLocation, FONTS_SYSTEM); + List<FontInfo> systemFonts = handler.getFontList(); - FontDefinitionParser definitionParser = new FontDefinitionParser( - fontOsLocation + File.separator); - parser.parse(new FileInputStream(f), definitionParser); - return definitionParser.getFontLoader(); + // parse the fallback fonts + handler = parseFontFile(parserFactory, fontOsLocation, FONTS_FALLBACK); + List<FontInfo> fallbackFonts = handler.getFontList(); + + return new FontLoader(fontOsLocation, systemFonts, fallbackFonts); } catch (ParserConfigurationException e) { // return null below } catch (SAXException e) { @@ -103,35 +105,29 @@ public final class FontLoader { return null; } - private FontLoader(List<FontInfo> fontList, List<String> fallBackList) { - for (FontInfo info : fontList) { - for (String family : info.families) { - mFamilyToTtf.put(family, info.ttf); - } - } + private static FontHandler parseFontFile(SAXParserFactory parserFactory, + String fontOsLocation, String fontFileName) + throws ParserConfigurationException, SAXException, IOException, FileNotFoundException { - ArrayList<Font> list = new ArrayList<Font>(); - for (String path : fallBackList) { - File f = new File(path + FONT_EXT); - if (f.isFile()) { - try { - Font font = Font.createFont(Font.TRUETYPE_FONT, f); - if (font != null) { - list.add(font); - } - } catch (FontFormatException e) { - // skip this font name - } catch (IOException e) { - // skip this font name - } - } - } + SAXParser parser = parserFactory.newSAXParser(); + File f = new File(fontOsLocation, fontFileName); - mFallBackFonts = Collections.unmodifiableList(list); + FontHandler definitionParser = new FontHandler( + fontOsLocation + File.separator); + parser.parse(new FileInputStream(f), definitionParser); + return definitionParser; } - public List<Font> getFallBackFonts() { - return mFallBackFonts; + private FontLoader(String fontOsLocation, + List<FontInfo> fontList, List<FontInfo> fallBackList) { + mOsFontsLocation = fontOsLocation; + mMainFonts.addAll(fontList); + mFallbackFonts.addAll(fallBackList); + } + + + public String getOsFontsLocation() { + return mOsFontsLocation; } /** @@ -143,96 +139,43 @@ public final class FontLoader { * the method returns. * @return the font object or null if no match could be found. */ - public synchronized Font getFont(String family, int[] style) { - if (family == null) { - return null; - } + public synchronized List<Font> getFont(String family, int style) { + List<Font> result = new ArrayList<Font>(); - // get the ttf name from the family - String ttf = mFamilyToTtf.get(family); - - if (ttf == null) { - return null; - } - - // get the font from the ttf - Map<Integer, Font> styleMap = mTtfToFontMap.get(ttf); - - if (styleMap == null) { - styleMap = new HashMap<Integer, Font>(); - mTtfToFontMap.put(ttf, styleMap); + if (family == null) { + return result; } - Font f = styleMap.get(style[0]); - - if (f != null) { - return f; - } - // if it doesn't exist, we create it, and we can't, we try with a simpler style - switch (style[0]) { - case Typeface.NORMAL: - f = getFont(ttf, FONT_STYLES[Typeface.NORMAL]); - break; - case Typeface.BOLD: - case Typeface.ITALIC: - f = getFont(ttf, FONT_STYLES[style[0]]); - if (f == null) { - f = getFont(ttf, FONT_STYLES[Typeface.NORMAL]); - style[0] = Typeface.NORMAL; - } - break; - case Typeface.BOLD_ITALIC: - f = getFont(ttf, FONT_STYLES[style[0]]); - if (f == null) { - f = getFont(ttf, FONT_STYLES[Typeface.BOLD]); - if (f != null) { - style[0] = Typeface.BOLD; - } else { - f = getFont(ttf, FONT_STYLES[Typeface.ITALIC]); - if (f != null) { - style[0] = Typeface.ITALIC; - } else { - f = getFont(ttf, FONT_STYLES[Typeface.NORMAL]); - style[0] = Typeface.NORMAL; - } - } - } + // get the font objects from the main list based on family. + for (FontInfo info : mMainFonts) { + if (info.families.contains(family)) { + result.add(info.font[style]); break; + } } - if (f != null) { - styleMap.put(style[0], f); - return f; + // add all the fallback fonts for the given style + for (FontInfo info : mFallbackFonts) { + result.add(info.font[style]); } - return null; + return result; } - private Font getFont(String ttf, String[] fontFileSuffix) { - for (String suffix : fontFileSuffix) { - String name = ttf + suffix + FONT_EXT; - File f = new File(name); - if (f.isFile()) { - try { - Font font = Font.createFont(Font.TRUETYPE_FONT, f); - if (font != null) { - return font; - } - } catch (FontFormatException e) { - // skip this font name - } catch (IOException e) { - // skip this font name - } - } + public synchronized List<Font> getFallbackFonts(int style) { + List<Font> result = new ArrayList<Font>(); + // add all the fallback fonts + for (FontInfo info : mFallbackFonts) { + result.add(info.font[style]); } - - return null; + return result; } + private final static class FontInfo { - String ttf; + final Font[] font = new Font[4]; // Matches the 4 type-face styles. final Set<String> families; FontInfo() { @@ -240,21 +183,20 @@ public final class FontLoader { } } - private final static class FontDefinitionParser extends DefaultHandler { + private final static class FontHandler extends DefaultHandler { private final String mOsFontsLocation; private FontInfo mFontInfo = null; private final StringBuilder mBuilder = new StringBuilder(); - private List<FontInfo> mFontList; - private List<String> mFallBackList; + private List<FontInfo> mFontList = new ArrayList<FontInfo>(); - private FontDefinitionParser(String osFontsLocation) { + private FontHandler(String osFontsLocation) { super(); mOsFontsLocation = osFontsLocation; } - FontLoader getFontLoader() { - return new FontLoader(mFontList, mFallBackList); + public List<FontInfo> getFontList() { + return mFontList; } /* (non-Javadoc) @@ -263,26 +205,11 @@ public final class FontLoader { @Override public void startElement(String uri, String localName, String name, Attributes attributes) throws SAXException { - if (NODE_FONTS.equals(localName)) { + if (NODE_FAMILYSET.equals(localName)) { mFontList = new ArrayList<FontInfo>(); - mFallBackList = new ArrayList<String>(); - } else if (NODE_FONT.equals(localName)) { + } else if (NODE_FAMILY.equals(localName)) { if (mFontList != null) { - String ttf = attributes.getValue(ATTR_TTF); - if (ttf != null) { - mFontInfo = new FontInfo(); - mFontInfo.ttf = mOsFontsLocation + ttf; - mFontList.add(mFontInfo); - } - } - } else if (NODE_NAME.equals(localName)) { - // do nothing, we'll handle the name in the endElement - } else if (NODE_FALLBACK.equals(localName)) { - if (mFallBackList != null) { - String ttf = attributes.getValue(ATTR_TTF); - if (ttf != null) { - mFallBackList.add(mOsFontsLocation + ttf); - } + mFontInfo = new FontInfo(); } } @@ -304,19 +231,78 @@ public final class FontLoader { */ @Override public void endElement(String uri, String localName, String name) throws SAXException { - if (NODE_FONTS.equals(localName)) { - // top level, do nothing - } else if (NODE_FONT.equals(localName)) { - mFontInfo = null; + if (NODE_FAMILY.equals(localName)) { + if (mFontInfo != null) { + // if has a normal font file, add to the list + if (mFontInfo.font[Typeface.NORMAL] != null) { + mFontList.add(mFontInfo); + + // create missing font styles, order is important. + if (mFontInfo.font[Typeface.BOLD_ITALIC] == null) { + computeDerivedFont(Typeface.BOLD_ITALIC, DERIVE_BOLD_ITALIC); + } + if (mFontInfo.font[Typeface.ITALIC] == null) { + computeDerivedFont(Typeface.ITALIC, DERIVE_ITALIC); + } + if (mFontInfo.font[Typeface.BOLD] == null) { + computeDerivedFont(Typeface.BOLD, DERIVE_BOLD); + } + } + + mFontInfo = null; + } } else if (NODE_NAME.equals(localName)) { // handle a new name for an existing Font Info if (mFontInfo != null) { String family = trimXmlWhitespaces(mBuilder.toString()); mFontInfo.families.add(family); } - } else if (NODE_FALLBACK.equals(localName)) { - // nothing to do here. + } else if (NODE_FILE.equals(localName)) { + // handle a new file for an existing Font Info + if (mFontInfo != null) { + String fileName = trimXmlWhitespaces(mBuilder.toString()); + Font font = getFont(fileName); + if (font != null) { + if (fileName.endsWith(FONT_SUFFIX_REGULAR)) { + mFontInfo.font[Typeface.NORMAL] = font; + } else if (fileName.endsWith(FONT_SUFFIX_BOLD)) { + mFontInfo.font[Typeface.BOLD] = font; + } else if (fileName.endsWith(FONT_SUFFIX_ITALIC)) { + mFontInfo.font[Typeface.ITALIC] = font; + } else if (fileName.endsWith(FONT_SUFFIX_BOLDITALIC)) { + mFontInfo.font[Typeface.BOLD_ITALIC] = font; + } else if (fileName.endsWith(FONT_SUFFIX_NONE)) { + mFontInfo.font[Typeface.NORMAL] = font; + } + } + } + } + } + + private Font getFont(String fileName) { + try { + File file = new File(mOsFontsLocation, fileName); + if (file.exists()) { + return Font.createFont(Font.TRUETYPE_FONT, file); + } + } catch (Exception e) { + } + + return null; + } + + private void computeDerivedFont( int toCompute, int[] basedOnList) { + for (int basedOn : basedOnList) { + if (mFontInfo.font[basedOn] != null) { + mFontInfo.font[toCompute] = + mFontInfo.font[basedOn].deriveFont(AWT_STYLES[toCompute]); + return; + } + } + + // we really shouldn't stop there. This means we don't have a NORMAL font... + assert false; } private String trimXmlWhitespaces(String value) { diff --git a/wifi/java/android/net/wifi/WifiStateMachine.java b/wifi/java/android/net/wifi/WifiStateMachine.java index 5ca7aff4d773..1e45f684d459 100644 --- a/wifi/java/android/net/wifi/WifiStateMachine.java +++ b/wifi/java/android/net/wifi/WifiStateMachine.java @@ -2597,6 +2597,15 @@ public class WifiStateMachine extends StateMachine { public boolean processMessage(Message message) { if (DBG) log(getName() + message.toString() + "\n"); switch (message.what) { + case WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT: + StateChangeResult stateChangeResult = (StateChangeResult) message.obj; + SupplicantState state = stateChangeResult.state; + // A WEXT bug means that we can be back to driver started state + // unexpectedly + if (SupplicantState.isDriverActive(state)) { + transitionTo(mDriverStartedState); + } + break; case CMD_START_DRIVER: mWakeLock.acquire(); WifiNative.startDriverCommand(); @@ -2667,8 +2676,18 @@ public class WifiStateMachine extends StateMachine { sendErrorBroadcast(WifiManager.WPS_OVERLAP_ERROR); break; case WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT: - handleSupplicantStateChange(message); - break; + SupplicantState state = handleSupplicantStateChange(message); + // Due to a WEXT bug, during the time of driver start/stop + // we can go into a driver stopped state in an unexpected way. + // The sequence eventually puts interface + // up and we should be back to a connected state + if (!SupplicantState.isDriverActive(state)) { + if (mNetworkInfo.getState() != NetworkInfo.State.DISCONNECTED) { + handleNetworkDisconnect(); + } + transitionTo(mDriverStoppedState); + } + break; /* Do a redundant disconnect without transition */ case CMD_DISCONNECT: WifiNative.disconnectCommand(); |