diff options
Diffstat (limited to 'core/java')
37 files changed, 801 insertions, 235 deletions
diff --git a/core/java/android/accounts/ChooseAccountTypeActivity.java b/core/java/android/accounts/ChooseAccountTypeActivity.java index 448b2c0..acc8549 100644 --- a/core/java/android/accounts/ChooseAccountTypeActivity.java +++ b/core/java/android/accounts/ChooseAccountTypeActivity.java @@ -43,7 +43,7 @@ import java.util.Set; * @hide */ public class ChooseAccountTypeActivity extends Activity { - private static final String TAG = "AccountManager"; + private static final String TAG = "AccountChooser"; private HashMap<String, AuthInfo> mTypeToAuthenticatorInfo = new HashMap<String, AuthInfo>(); private ArrayList<AuthInfo> mAuthenticatorInfosToDisplay; @@ -52,6 +52,11 @@ public class ChooseAccountTypeActivity extends Activity { public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); + if (Log.isLoggable(TAG, Log.VERBOSE)) { + Log.v(TAG, "ChooseAccountTypeActivity.onCreate(savedInstanceState=" + + savedInstanceState + ")"); + } + // Read the validAccountTypes, if present, and add them to the setOfAllowableAccountTypes Set<String> setOfAllowableAccountTypes = null; String[] validAccountTypes = getIntent().getStringArrayExtra( @@ -111,8 +116,10 @@ public class ChooseAccountTypeActivity extends Activity { Bundle bundle = new Bundle(); bundle.putString(AccountManager.KEY_ACCOUNT_TYPE, type); setResult(Activity.RESULT_OK, new Intent().putExtras(bundle)); - Log.d(TAG, "ChooseAccountTypeActivity.setResultAndFinish: " - + "selected account type " + type); + if (Log.isLoggable(TAG, Log.VERBOSE)) { + Log.v(TAG, "ChooseAccountTypeActivity.setResultAndFinish: " + + "selected account type " + type); + } finish(); } diff --git a/core/java/android/accounts/ChooseTypeAndAccountActivity.java b/core/java/android/accounts/ChooseTypeAndAccountActivity.java index 8cc2002..5f38eb4 100644 --- a/core/java/android/accounts/ChooseTypeAndAccountActivity.java +++ b/core/java/android/accounts/ChooseTypeAndAccountActivity.java @@ -47,7 +47,7 @@ import java.util.Set; */ public class ChooseTypeAndAccountActivity extends Activity implements AccountManagerCallback<Bundle> { - private static final String TAG = "AccountManager"; + private static final String TAG = "AccountChooser"; /** * A Parcelable ArrayList of Account objects that limits the choosable accounts to those @@ -100,13 +100,39 @@ public class ChooseTypeAndAccountActivity extends Activity public static final String EXTRA_DESCRIPTION_TEXT_OVERRIDE = "descriptionTextOverride"; + public static final int REQUEST_NULL = 0; + public static final int REQUEST_CHOOSE_TYPE = 1; + public static final int REQUEST_ADD_ACCOUNT = 2; + + private static final String KEY_INSTANCE_STATE_PENDING_REQUEST = "pendingRequest"; + private static final String KEY_INSTANCE_STATE_EXISTING_ACCOUNTS = "existingAccounts"; + private ArrayList<AccountInfo> mAccountInfos; + private int mPendingRequest = REQUEST_NULL; + private Parcelable[] mExistingAccounts = null; + private Parcelable[] mSavedAccounts = null; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); + if (Log.isLoggable(TAG, Log.VERBOSE)) { + Log.v(TAG, "ChooseTypeAndAccountActivity.onCreate(savedInstanceState=" + + savedInstanceState + ")"); + } + setContentView(R.layout.choose_type_and_account); + if (savedInstanceState != null) { + mPendingRequest = savedInstanceState.getInt(KEY_INSTANCE_STATE_PENDING_REQUEST); + mSavedAccounts = + savedInstanceState.getParcelableArray(KEY_INSTANCE_STATE_EXISTING_ACCOUNTS); + mExistingAccounts = null; + } else { + mPendingRequest = REQUEST_NULL; + mSavedAccounts = null; + mExistingAccounts = null; + } + // save some items we use frequently final AccountManager accountManager = AccountManager.get(this); final Intent intent = getIntent(); @@ -171,20 +197,6 @@ public class ChooseTypeAndAccountActivity extends Activity account.equals(selectedAccount))); } - // If there are no allowable accounts go directly to add account - if (mAccountInfos.isEmpty()) { - startChooseAccountTypeActivity(); - return; - } - - // if there is only one allowable account return it - if (!intent.getBooleanExtra(EXTRA_ALWAYS_PROMPT_FOR_ACCOUNT, false) - && mAccountInfos.size() == 1) { - Account account = mAccountInfos.get(0).account; - setResultAndFinish(account.name, account.type); - return; - } - // there is more than one allowable account. initialize the list adapter to allow // the user to select an account. ListView list = (ListView) findViewById(android.R.id.list); @@ -204,6 +216,37 @@ public class ChooseTypeAndAccountActivity extends Activity startChooseAccountTypeActivity(); } }); + + if (mPendingRequest == REQUEST_NULL) { + // If there are no allowable accounts go directly to add account + if (mAccountInfos.isEmpty()) { + startChooseAccountTypeActivity(); + return; + } + + // if there is only one allowable account return it + if (!intent.getBooleanExtra(EXTRA_ALWAYS_PROMPT_FOR_ACCOUNT, false) + && mAccountInfos.size() == 1) { + Account account = mAccountInfos.get(0).account; + setResultAndFinish(account.name, account.type); + return; + } + } + } + + @Override + protected void onDestroy() { + if (Log.isLoggable(TAG, Log.VERBOSE)) { + Log.v(TAG, "ChooseTypeAndAccountActivity.onDestroy()"); + } + super.onDestroy(); + } + + @Override + protected void onSaveInstanceState(final Bundle outState) { + super.onSaveInstanceState(outState); + outState.putInt(KEY_INSTANCE_STATE_PENDING_REQUEST, mPendingRequest); + outState.putParcelableArray(KEY_INSTANCE_STATE_EXISTING_ACCOUNTS, mExistingAccounts); } // Called when the choose account type activity (for adding an account) returns. @@ -212,20 +255,75 @@ public class ChooseTypeAndAccountActivity extends Activity @Override protected void onActivityResult(final int requestCode, final int resultCode, final Intent data) { - if (resultCode == RESULT_OK && data != null) { - String accountType = data.getStringExtra(AccountManager.KEY_ACCOUNT_TYPE); - if (accountType != null) { - runAddAccountForAuthenticator(accountType); - return; + if (Log.isLoggable(TAG, Log.VERBOSE)) { + if (data != null && data.getExtras() != null) data.getExtras().keySet(); + Bundle extras = data != null ? data.getExtras() : null; + Log.v(TAG, "ChooseTypeAndAccountActivity.onActivityResult(reqCode=" + requestCode + + ", resCode=" + resultCode + ", extras=" + extras + ")"); + } + + // we got our result, so clear the fact that we had a pending request + mPendingRequest = REQUEST_NULL; + mExistingAccounts = null; + + if (resultCode == RESULT_CANCELED) { + return; + } + + if (resultCode == RESULT_OK) { + if (requestCode == REQUEST_CHOOSE_TYPE) { + if (data != null) { + String accountType = data.getStringExtra(AccountManager.KEY_ACCOUNT_TYPE); + if (accountType != null) { + runAddAccountForAuthenticator(accountType); + return; + } + } + Log.d(TAG, "ChooseTypeAndAccountActivity.onActivityResult: unable to find account " + + "type, pretending the request was canceled"); + } else if (requestCode == REQUEST_ADD_ACCOUNT) { + String accountName = null; + String accountType = null; + + if (data != null) { + accountName = data.getStringExtra(AccountManager.KEY_ACCOUNT_NAME); + accountType = data.getStringExtra(AccountManager.KEY_ACCOUNT_TYPE); + } + + if (accountName == null || accountType == null) { + Account[] currentAccounts = AccountManager.get(this).getAccounts(); + Set<Account> preExistingAccounts = new HashSet<Account>(); + for (Parcelable accountParcel : mSavedAccounts) { + preExistingAccounts.add((Account) accountParcel); + } + for (Account account : currentAccounts) { + if (!preExistingAccounts.contains(account)) { + accountName = account.name; + accountType = account.type; + break; + } + } + } + + if (accountName != null || accountType != null) { + setResultAndFinish(accountName, accountType); + return; + } } + Log.d(TAG, "ChooseTypeAndAccountActivity.onActivityResult: unable to find added " + + "account, pretending the request was canceled"); + } + if (Log.isLoggable(TAG, Log.VERBOSE)) { + Log.v(TAG, "ChooseTypeAndAccountActivity.onActivityResult: canceled"); } - Log.d(TAG, "ChooseTypeAndAccountActivity.onActivityResult: canceled"); setResult(Activity.RESULT_CANCELED); finish(); } protected void runAddAccountForAuthenticator(String type) { - Log.d(TAG, "selected account type " + type); + if (Log.isLoggable(TAG, Log.VERBOSE)) { + Log.v(TAG, "runAddAccountForAuthenticator: " + type); + } final Bundle options = getIntent().getBundleExtra( ChooseTypeAndAccountActivity.EXTRA_ADD_ACCOUNT_OPTIONS_BUNDLE); final String[] requiredFeatures = getIntent().getStringArrayExtra( @@ -233,20 +331,19 @@ public class ChooseTypeAndAccountActivity extends Activity final String authTokenType = getIntent().getStringExtra( ChooseTypeAndAccountActivity.EXTRA_ADD_ACCOUNT_AUTH_TOKEN_TYPE_STRING); AccountManager.get(this).addAccount(type, authTokenType, requiredFeatures, - options, this, this, null /* Handler */); + options, null /* activity */, this /* callback */, null /* Handler */); } public void run(final AccountManagerFuture<Bundle> accountManagerFuture) { try { final Bundle accountManagerResult = accountManagerFuture.getResult(); - final String name = accountManagerResult.getString(AccountManager.KEY_ACCOUNT_NAME); - final String type = accountManagerResult.getString(AccountManager.KEY_ACCOUNT_TYPE); - if (name != null && type != null) { - final Bundle bundle = new Bundle(); - bundle.putString(AccountManager.KEY_ACCOUNT_NAME, name); - bundle.putString(AccountManager.KEY_ACCOUNT_TYPE, type); - setResult(Activity.RESULT_OK, new Intent().putExtras(bundle)); - finish(); + final Intent intent = (Intent)accountManagerResult.getParcelable( + AccountManager.KEY_INTENT); + if (intent != null) { + mPendingRequest = REQUEST_ADD_ACCOUNT; + mExistingAccounts = AccountManager.get(this).getAccounts(); + intent.setFlags(intent.getFlags() & ~Intent.FLAG_ACTIVITY_NEW_TASK); + startActivityForResult(intent, REQUEST_ADD_ACCOUNT); return; } } catch (OperationCanceledException e) { @@ -297,12 +394,17 @@ public class ChooseTypeAndAccountActivity extends Activity bundle.putString(AccountManager.KEY_ACCOUNT_NAME, accountName); bundle.putString(AccountManager.KEY_ACCOUNT_TYPE, accountType); setResult(Activity.RESULT_OK, new Intent().putExtras(bundle)); - Log.d(TAG, "ChooseTypeAndAccountActivity.setResultAndFinish: " - + "selected account " + accountName + ", " + accountType); + if (Log.isLoggable(TAG, Log.VERBOSE)) { + Log.v(TAG, "ChooseTypeAndAccountActivity.setResultAndFinish: " + + "selected account " + accountName + ", " + accountType); + } finish(); } private void startChooseAccountTypeActivity() { + if (Log.isLoggable(TAG, Log.VERBOSE)) { + Log.v(TAG, "ChooseAccountTypeActivity.startChooseAccountTypeActivity()"); + } final Intent intent = new Intent(this, ChooseAccountTypeActivity.class); intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET); intent.putExtra(EXTRA_ALLOWABLE_ACCOUNT_TYPES_STRING_ARRAY, @@ -313,7 +415,8 @@ public class ChooseTypeAndAccountActivity extends Activity getIntent().getStringArrayExtra(EXTRA_ADD_ACCOUNT_REQUIRED_FEATURES_STRING_ARRAY)); intent.putExtra(EXTRA_ADD_ACCOUNT_AUTH_TOKEN_TYPE_STRING, getIntent().getStringExtra(EXTRA_ADD_ACCOUNT_AUTH_TOKEN_TYPE_STRING)); - startActivityForResult(intent, 0); + startActivityForResult(intent, REQUEST_CHOOSE_TYPE); + mPendingRequest = REQUEST_CHOOSE_TYPE; } private static class AccountInfo { diff --git a/core/java/android/app/AlertDialog.java b/core/java/android/app/AlertDialog.java index c09e87f..e37b3fa 100644 --- a/core/java/android/app/AlertDialog.java +++ b/core/java/android/app/AlertDialog.java @@ -54,6 +54,12 @@ import android.widget.ListView; * without text editors, so that it will be placed on top of the current * input method UI. You can modify this behavior by forcing the flag to your * desired mode after calling {@link #onCreate}. + * + * <div class="special reference"> + * <h3>Developer Guides</h3> + * <p>For more information about creating dialogs, read the + * <a href="{@docRoot}guide/topics/ui/dialogs.html">Dialogs</a> developer guide.</p> + * </div> */ public class AlertDialog extends Dialog implements DialogInterface { private AlertController mAlert; diff --git a/core/java/android/app/Dialog.java b/core/java/android/app/Dialog.java index 82186dd..7a69419 100644 --- a/core/java/android/app/Dialog.java +++ b/core/java/android/app/Dialog.java @@ -66,9 +66,14 @@ import java.lang.ref.WeakReference; * your Dialog takes input focus, as it the default) with the following code: * * <pre> - * getWindow().setFlags(WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM, - * WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM); - * </pre> + * getWindow().setFlags(WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM, + * WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM);</pre> + * + * <div class="special reference"> + * <h3>Developer Guides</h3> + * <p>For more information about creating dialogs, read the + * <a href="{@docRoot}guide/topics/ui/dialogs.html">Dialogs</a> developer guide.</p> + * </div> */ public class Dialog implements DialogInterface, Window.Callback, KeyEvent.Callback, OnCreateContextMenuListener { diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java index 9490b96..f5add25 100644 --- a/core/java/android/app/Notification.java +++ b/core/java/android/app/Notification.java @@ -38,9 +38,12 @@ import java.text.NumberFormat; * <p>The {@link Notification.Builder Notification.Builder} has been added to make it * easier to construct Notifications.</p> * - * <p>For a guide to creating notifications, see the - * <a href="{@docRoot}guide/topics/ui/notifiers/notifications.html">Creating Status - * Bar Notifications</a> document in the Dev Guide.</p> + * <div class="special reference"> + * <h3>Developer Guides</h3> + * <p>For a guide to creating notifications, read the + * <a href="{@docRoot}guide/topics/ui/notifiers/notifications.html">Status Bar Notifications</a> + * developer guide.</p> + * </div> */ public class Notification implements Parcelable { diff --git a/core/java/android/app/NotificationManager.java b/core/java/android/app/NotificationManager.java index 4913e78..bf83f5e 100644 --- a/core/java/android/app/NotificationManager.java +++ b/core/java/android/app/NotificationManager.java @@ -55,6 +55,13 @@ import android.util.Log; * You do not instantiate this class directly; instead, retrieve it through * {@link android.content.Context#getSystemService}. * + * <div class="special reference"> + * <h3>Developer Guides</h3> + * <p>For a guide to creating notifications, read the + * <a href="{@docRoot}guide/topics/ui/notifiers/notifications.html">Status Bar Notifications</a> + * developer guide.</p> + * </div> + * * @see android.app.Notification * @see android.content.Context#getSystemService */ diff --git a/core/java/android/app/StatusBarManager.java b/core/java/android/app/StatusBarManager.java index ca64c88..c5ee48d 100644 --- a/core/java/android/app/StatusBarManager.java +++ b/core/java/android/app/StatusBarManager.java @@ -40,15 +40,20 @@ public class StatusBarManager { public static final int DISABLE_NOTIFICATION_TICKER = View.STATUS_BAR_DISABLE_NOTIFICATION_TICKER; public static final int DISABLE_SYSTEM_INFO = View.STATUS_BAR_DISABLE_SYSTEM_INFO; - public static final int DISABLE_NAVIGATION = View.STATUS_BAR_DISABLE_NAVIGATION; + public static final int DISABLE_HOME = View.STATUS_BAR_DISABLE_HOME; + public static final int DISABLE_RECENT = View.STATUS_BAR_DISABLE_RECENT; public static final int DISABLE_BACK = View.STATUS_BAR_DISABLE_BACK; public static final int DISABLE_CLOCK = View.STATUS_BAR_DISABLE_CLOCK; + @Deprecated + public static final int DISABLE_NAVIGATION = + View.STATUS_BAR_DISABLE_HOME | View.STATUS_BAR_DISABLE_RECENT; + public static final int DISABLE_NONE = 0x00000000; public static final int DISABLE_MASK = DISABLE_EXPAND | DISABLE_NOTIFICATION_ICONS | DISABLE_NOTIFICATION_ALERTS | DISABLE_NOTIFICATION_TICKER - | DISABLE_SYSTEM_INFO| DISABLE_NAVIGATION | DISABLE_BACK | DISABLE_CLOCK; + | DISABLE_SYSTEM_INFO | DISABLE_RECENT | DISABLE_HOME | DISABLE_BACK | DISABLE_CLOCK; private Context mContext; private IStatusBarService mService; diff --git a/core/java/android/content/ContentProvider.java b/core/java/android/content/ContentProvider.java index e452f1f..092a0c8 100644 --- a/core/java/android/content/ContentProvider.java +++ b/core/java/android/content/ContentProvider.java @@ -45,9 +45,6 @@ import java.util.ArrayList; * multiple applications you can use a database directly via * {@link android.database.sqlite.SQLiteDatabase}. * - * <p>For more information, read <a href="{@docRoot}guide/topics/providers/content-providers.html">Content - * Providers</a>.</p> - * * <p>When a request is made via * a {@link ContentResolver} the system inspects the authority of the given URI and passes the * request to the content provider registered with the authority. The content provider can interpret @@ -73,6 +70,12 @@ import java.util.ArrayList; * <p>Requests to {@link ContentResolver} are automatically forwarded to the appropriate * ContentProvider instance, so subclasses don't have to worry about the details of * cross-process calls.</p> + * + * <div class="special reference"> + * <h3>Developer Guides</h3> + * <p>For more information about using content providers, read the + * <a href="{@docRoot}guide/topics/providers/content-providers.html">Content Providers</a> + * developer guide.</p> */ public abstract class ContentProvider implements ComponentCallbacks2 { private static final String TAG = "ContentProvider"; diff --git a/core/java/android/content/ContentResolver.java b/core/java/android/content/ContentResolver.java index 0d25926..e923349 100644 --- a/core/java/android/content/ContentResolver.java +++ b/core/java/android/content/ContentResolver.java @@ -54,6 +54,12 @@ import java.util.Random; /** * This class provides applications access to the content model. + * + * <div class="special reference"> + * <h3>Developer Guides</h3> + * <p>For more information about using a ContentResolver with content providers, read the + * <a href="{@docRoot}guide/topics/providers/content-providers.html">Content Providers</a> + * developer guide.</p> */ public abstract class ContentResolver { /** diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java index 2be5153..45a42e4 100644 --- a/core/java/android/content/Intent.java +++ b/core/java/android/content/Intent.java @@ -57,8 +57,8 @@ import java.util.Set; * * <p>An Intent provides a facility for performing late runtime binding between the code in * different applications. Its most significant use is in the launching of activities, where it - * can be thought of as the glue between activities. It is basically a passive data structure - * holding an abstract description of an action to be performed.</p> + * can be thought of as the glue between activities. It is basically a passive data structure + * holding an abstract description of an action to be performed.</p> * * <div class="special reference"> * <h3>Developer Guides</h3> @@ -2566,7 +2566,7 @@ public class Intent implements Parcelable, Cloneable { */ public static final String EXTRA_LOCAL_ONLY = "android.intent.extra.LOCAL_ONLY"; - + // --------------------------------------------------------------------- // --------------------------------------------------------------------- // Intent flags (see mFlags variable). @@ -5291,7 +5291,7 @@ public class Intent implements Parcelable, Cloneable { if (r != null) { mSourceBounds = new Rect(r); } else { - r = null; + mSourceBounds = null; } } diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java index 7a7e4f4..3eb7647 100644 --- a/core/java/android/content/pm/PackageManager.java +++ b/core/java/android/content/pm/PackageManager.java @@ -2124,6 +2124,9 @@ public abstract class PackageManager { if (pkg == null) { return null; } + if ((flags & GET_SIGNATURES) != 0) { + packageParser.collectCertificates(pkg, 0); + } return PackageParser.generatePackageInfo(pkg, null, flags, 0, 0); } diff --git a/core/java/android/hardware/Camera.java b/core/java/android/hardware/Camera.java index d65e6df..d338764 100644 --- a/core/java/android/hardware/Camera.java +++ b/core/java/android/hardware/Camera.java @@ -337,7 +337,7 @@ public class Camera { * Camera objects are locked by default unless {@link #unlock()} is * called. Normally {@link #reconnect()} is used instead. * - * <p>Since API level 13, camera is automatically locked for applications in + * <p>Since API level 14, camera is automatically locked for applications in * {@link android.media.MediaRecorder#start()}. Applications can use the * camera (ex: zoom) after recording starts. There is no need to call this * after recording starts or stops. @@ -356,7 +356,7 @@ public class Camera { * which will re-acquire the lock and allow you to continue using the * camera. * - * <p>Since API level 13, camera is automatically locked for applications in + * <p>Since API level 14, camera is automatically locked for applications in * {@link android.media.MediaRecorder#start()}. Applications can use the * camera (ex: zoom) after recording starts. There is no need to call this * after recording starts or stops. @@ -781,7 +781,7 @@ public class Camera { * @see android.hardware.Camera.Parameters#setAutoWhiteBalanceLock(boolean) */ void onAutoFocus(boolean success, Camera camera); - }; + } /** * Starts camera auto-focus and registers a callback function to run when @@ -804,11 +804,17 @@ public class Camera { * {@link android.hardware.Camera.Parameters#FLASH_MODE_OFF}, flash may be * fired during auto-focus, depending on the driver and camera hardware.<p> * - * Auto-exposure lock {@link android.hardware.Camera.Parameters#getAutoExposureLock()} + * <p>Auto-exposure lock {@link android.hardware.Camera.Parameters#getAutoExposureLock()} * and auto-white balance locks {@link android.hardware.Camera.Parameters#getAutoWhiteBalanceLock()} * do not change during and after autofocus. But auto-focus routine may stop * auto-exposure and auto-white balance transiently during focusing. * + * <p>Stopping preview with {@link #stopPreview()}, or triggering still + * image capture with {@link #takePicture(Camera.ShutterCallback, + * Camera.PictureCallback, Camera.PictureCallback)}, will not change the + * the focus position. Applications must call cancelAutoFocus to reset the + * focus.</p> + * * @param cb the callback to run * @see #cancelAutoFocus() * @see android.hardware.Camera.Parameters#setAutoExposureLock(boolean) @@ -1059,8 +1065,7 @@ public class Camera { /** * Notify the listener of the detected faces in the preview frame. * - * @param faces The detected faces in a list sorted by the confidence score. - * The highest scored face is the first element. + * @param faces The detected faces in a list * @param camera The {@link Camera} service object */ void onFaceDetection(Face[] faces, Camera camera); @@ -1121,7 +1126,7 @@ public class Camera { /** * 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> * @@ -1140,7 +1145,9 @@ public class Camera { * the field of view. For example, suppose the size of the viewfinder UI * is 800x480. The rect passed from the driver is (-1000, -1000, 0, 0). * The corresponding viewfinder rect should be (0, 0, 400, 240). The - * width and height of the rect will not be 0 or negative. + * width and height of the rect will not be 0 or negative. The + * coordinates can be smaller than -1000 or bigger than 1000. But at + * least one vertex will be within (-1000, -1000) and (1000, 1000). * * <p>The direction is relative to the sensor orientation, that is, what * the sensor sees. The direction is not affected by the rotation or @@ -1464,6 +1471,8 @@ public class Camera { private static final String KEY_MAX_NUM_DETECTED_FACES_SW = "max-num-detected-faces-sw"; private static final String KEY_RECORDING_HINT = "recording-hint"; private static final String KEY_VIDEO_SNAPSHOT_SUPPORTED = "video-snapshot-supported"; + private static final String KEY_VIDEO_STABILIZATION = "video-stabilization"; + private static final String KEY_VIDEO_STABILIZATION_SUPPORTED = "video-stabilization-supported"; // Parameter key suffix for supported values. private static final String SUPPORTED_VALUES_SUFFIX = "-values"; @@ -1651,9 +1660,18 @@ public class Camera { * call {@link #takePicture(Camera.ShutterCallback, * Camera.PictureCallback, Camera.PictureCallback)} in this mode but the * subject may not be in focus. Auto focus starts when the parameter is - * set. Applications should not call {@link - * #autoFocus(AutoFocusCallback)} in this mode. To stop continuous - * focus, applications should change the focus mode to other modes. + * set. + * + * <p>Since API level 14, applications can call {@link + * #autoFocus(AutoFocusCallback)} in this mode. The focus callback will + * immediately return with a boolean that indicates whether the focus is + * sharp or not. The focus position is locked after autoFocus call. If + * applications want to resume the continuous focus, cancelAutoFocus + * must be called. Restarting the preview will not resume the continuous + * autofocus. To stop continuous focus, applications should change the + * focus mode to other modes. + * + * @see #FOCUS_MODE_CONTINUOUS_PICTURE */ public static final String FOCUS_MODE_CONTINUOUS_VIDEO = "continuous-video"; @@ -1661,13 +1679,17 @@ public class Camera { * Continuous auto focus mode intended for taking pictures. The camera * continuously tries to focus. The speed of focus change is more * aggressive than {@link #FOCUS_MODE_CONTINUOUS_VIDEO}. Auto focus - * starts when the parameter is set. If applications call {@link - * #autoFocus(AutoFocusCallback)} in this mode, the focus callback will - * immediately return with a boolean that indicates whether the focus is - * sharp or not. The apps can then decide if they want to take a picture - * immediately or to change the focus mode to auto, and run a full - * autofocus cycle. To stop continuous focus, applications should change - * the focus mode to other modes. + * starts when the parameter is set. + * + * <p>If applications call {@link #autoFocus(AutoFocusCallback)} in this + * mode, the focus callback will immediately return with a boolean that + * indicates whether the focus is sharp or not. The apps can then decide + * if they want to take a picture immediately or to change the focus + * mode to auto, and run a full autofocus cycle. The focus position is + * locked after autoFocus call. If applications want to resume the + * continuous focus, cancelAutoFocus must be called. Restarting the + * preview will not resume the continuous autofocus. To stop continuous + * focus, applications should change the focus mode to other modes. * * @see #FOCUS_MODE_CONTINUOUS_VIDEO */ @@ -2443,7 +2465,7 @@ public class Camera { * * @param value new white balance. * @see #getWhiteBalance() - * @see #setAutoWhiteBalanceLock() + * @see #setAutoWhiteBalanceLock(boolean) */ public void setWhiteBalance(String value) { set(KEY_WHITE_BALANCE, value); @@ -3059,8 +3081,9 @@ public class Camera { * when using zoom.</p> * * <p>Focus area only has effect if the current focus mode is - * {@link #FOCUS_MODE_AUTO}, {@link #FOCUS_MODE_MACRO}, or - * {@link #FOCUS_MODE_CONTINUOUS_VIDEO}.</p> + * {@link #FOCUS_MODE_AUTO}, {@link #FOCUS_MODE_MACRO}, + * {@link #FOCUS_MODE_CONTINUOUS_VIDEO}, or + * {@link #FOCUS_MODE_CONTINUOUS_PICTURE}.</p> * * @return a list of current focus areas */ @@ -3208,6 +3231,59 @@ public class Camera { return TRUE.equals(str); } + /** + * <p>Enables and disables video stabilization. Use + * {@link #isVideoStabilizationSupported} to determine if calling this + * method is valid.</p> + * + * <p>Video stabilization reduces the shaking due to the motion of the + * camera in both the preview stream and in recorded videos, including + * data received from the preview callback. It does not reduce motion + * blur in images captured with + * {@link Camera#takePicture takePicture}.</p> + * + * <p>Video stabilization can be enabled and disabled while preview or + * recording is active, but toggling it may cause a jump in the video + * stream that may be undesirable in a recorded video.</p> + * + * @param toggle Set to true to enable video stabilization, and false to + * disable video stabilization. + * @see #isVideoStabilizationSupported() + * @see #getVideoStabilization() + * @hide + */ + public void setVideoStabilization(boolean toggle) { + set(KEY_VIDEO_STABILIZATION, toggle ? TRUE : FALSE); + } + + /** + * Get the current state of video stabilization. See + * {@link #setVideoStabilization} for details of video stabilization. + * + * @return true if video stabilization is enabled + * @see #isVideoStabilizationSupported() + * @see #setVideoStabilization(boolean) + * @hide + */ + public boolean getVideoStabilization() { + String str = get(KEY_VIDEO_STABILIZATION); + return TRUE.equals(str); + } + + /** + * Returns true if video stabilization is supported. See + * {@link #setVideoStabilization} for details of video stabilization. + * + * @return true if video stabilization is supported + * @see #setVideoStabilization(boolean) + * @see #getVideoStabilization() + * @hide + */ + public boolean isVideoStabilizationSupported() { + String str = get(KEY_VIDEO_STABILIZATION_SUPPORTED); + return TRUE.equals(str); + } + // Splits a comma delimited string to an ArrayList of String. // Return null if the passing string is null or the size is 0. private ArrayList<String> split(String str) { diff --git a/core/java/android/os/storage/IMountService.java b/core/java/android/os/storage/IMountService.java index d1dc6e5..0640d7e 100644 --- a/core/java/android/os/storage/IMountService.java +++ b/core/java/android/os/storage/IMountService.java @@ -658,6 +658,24 @@ public interface IMountService extends IInterface { return _result; } + @Override + public int verifyEncryptionPassword(String password) throws RemoteException { + Parcel _data = Parcel.obtain(); + Parcel _reply = Parcel.obtain(); + int _result; + try { + _data.writeInterfaceToken(DESCRIPTOR); + _data.writeString(password); + mRemote.transact(Stub.TRANSACTION_verifyEncryptionPassword, _data, _reply, 0); + _reply.readException(); + _result = _reply.readInt(); + } finally { + _reply.recycle(); + _data.recycle(); + } + return _result; + } + public Parcelable[] getVolumeList() throws RemoteException { Parcel _data = Parcel.obtain(); Parcel _reply = Parcel.obtain(); @@ -761,6 +779,8 @@ public interface IMountService extends IInterface { static final int TRANSACTION_getEncryptionState = IBinder.FIRST_CALL_TRANSACTION + 31; + static final int TRANSACTION_verifyEncryptionPassword = IBinder.FIRST_CALL_TRANSACTION + 32; + /** * Cast an IBinder object into an IMountService interface, generating a * proxy if needed. @@ -1286,6 +1306,12 @@ public interface IMountService extends IInterface { public int changeEncryptionPassword(String password) throws RemoteException; /** + * Verify the encryption password against the stored volume. This method + * may only be called by the system process. + */ + public int verifyEncryptionPassword(String password) throws RemoteException; + + /** * Returns list of all mountable volumes. */ public Parcelable[] getVolumeList() throws RemoteException; diff --git a/core/java/android/provider/ContactsContract.java b/core/java/android/provider/ContactsContract.java index 8483b4f..4bc0892 100644 --- a/core/java/android/provider/ContactsContract.java +++ b/core/java/android/provider/ContactsContract.java @@ -187,6 +187,59 @@ public final class ContactsContract { public static final String DEFERRED_SNIPPETING_QUERY = "deferred_snippeting_query"; /** + * <p> + * API for obtaining a pre-authorized version of a URI that normally requires special + * permission (beyond READ_CONTACTS) to read. The caller obtaining the pre-authorized URI + * must already have the necessary permissions to access the URI; otherwise a + * {@link SecurityException} will be thrown. + * </p> + * <p> + * The authorized URI returned in the bundle contains an expiring token that allows the + * caller to execute the query without having the special permissions that would normally + * be required. + * </p> + * <p> + * This API does not access disk, and should be safe to invoke from the UI thread. + * </p> + * <p> + * Example usage: + * <pre> + * Uri profileUri = ContactsContract.Profile.CONTENT_VCARD_URI; + * Bundle uriBundle = new Bundle(); + * uriBundle.putParcelable(ContactsContract.Authorization.KEY_URI_TO_AUTHORIZE, uri); + * Bundle authResponse = getContext().getContentResolver().call( + * ContactsContract.AUTHORITY_URI, + * ContactsContract.Authorization.AUTHORIZATION_METHOD, + * null, // String arg, not used. + * uriBundle); + * if (authResponse != null) { + * Uri preauthorizedProfileUri = (Uri) authResponse.getParcelable( + * ContactsContract.Authorization.KEY_AUTHORIZED_URI); + * // This pre-authorized URI can be queried by a caller without READ_PROFILE + * // permission. + * } + * </pre> + * </p> + * @hide + */ + public static final class Authorization { + /** + * The method to invoke to create a pre-authorized URI out of the input argument. + */ + public static final String AUTHORIZATION_METHOD = "authorize"; + + /** + * The key to set in the outbound Bundle with the URI that should be authorized. + */ + public static final String KEY_URI_TO_AUTHORIZE = "uri_to_authorize"; + + /** + * The key to retrieve from the returned Bundle to obtain the pre-authorized URI. + */ + public static final String KEY_AUTHORIZED_URI = "authorized_uri"; + } + + /** * @hide */ public static final class Preferences { diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java index 3d2a3ce..5754e60 100644 --- a/core/java/android/provider/Settings.java +++ b/core/java/android/provider/Settings.java @@ -4053,6 +4053,14 @@ public final class Settings { public static final String PACKAGE_VERIFIER_TIMEOUT = "verifier_timeout"; /** + * Duration in milliseconds before pre-authorized URIs for the contacts + * provider should expire. + * @hide + */ + public static final String CONTACTS_PREAUTH_URI_EXPIRATION = + "contacts_preauth_uri_expiration"; + + /** * This are the settings to be backed up. * * NOTE: Settings are backed up and restored in the order they appear diff --git a/core/java/android/view/ContextMenu.java b/core/java/android/view/ContextMenu.java index dd1d7db..decabcb 100644 --- a/core/java/android/view/ContextMenu.java +++ b/core/java/android/view/ContextMenu.java @@ -29,6 +29,12 @@ import android.widget.AdapterView; * To show a context menu on long click, most clients will want to call * {@link Activity#registerForContextMenu} and override * {@link Activity#onCreateContextMenu}. + * + * <div class="special reference"> + * <h3>Developer Guides</h3> + * <p>For information about creating menus, read the + * <a href="{@docRoot}guide/topics/ui/menus.html">Menus</a> developer guide.</p> + * </div> */ public interface ContextMenu extends Menu { /** diff --git a/core/java/android/view/Display.java b/core/java/android/view/Display.java index 3bd0f76..ad2283e 100644 --- a/core/java/android/view/Display.java +++ b/core/java/android/view/Display.java @@ -117,6 +117,11 @@ public class Display { outSize.x = getRawWidth(); outSize.y = getRawHeight(); } + if (false) { + RuntimeException here = new RuntimeException("here"); + here.fillInStackTrace(); + Slog.v(TAG, "Returning display size: " + outSize, here); + } if (DEBUG_DISPLAY_SIZE && doCompat) Slog.v( TAG, "Returning display size: " + outSize); } catch (RemoteException e) { diff --git a/core/java/android/view/DragEvent.java b/core/java/android/view/DragEvent.java index 8f491ef..f559e21 100644 --- a/core/java/android/view/DragEvent.java +++ b/core/java/android/view/DragEvent.java @@ -114,6 +114,12 @@ import android.os.Parcelable; * {@link android.view.DragEvent#writeToParcel(Parcel,int)}, and * {@link android.view.DragEvent#toString()} methods always return valid data. * </p> + * + * <div class="special reference"> + * <h3>Developer Guides</h3> + * <p>For a guide to implementing drag and drop features, read the + * <a href="{@docRoot}guide/topics/ui/drag-drop.html">Drag and Drop</a> developer guide.</p> + * </div> */ public class DragEvent implements Parcelable { private static final boolean TRACK_RECYCLED_LOCATION = false; diff --git a/core/java/android/view/Menu.java b/core/java/android/view/Menu.java index 97825e6..7157bc5 100644 --- a/core/java/android/view/Menu.java +++ b/core/java/android/view/Menu.java @@ -41,6 +41,12 @@ import android.content.Intent; * item check marks are discouraged. * <li><b>Sub menus</b>: Do not support item icons, or nested sub menus. * </ol> + * + * <div class="special reference"> + * <h3>Developer Guides</h3> + * <p>For more information about creating menus, read the + * <a href="{@docRoot}guide/topics/ui/menus.html">Menus</a> developer guide.</p> + * </div> */ public interface Menu { diff --git a/core/java/android/view/MenuItem.java b/core/java/android/view/MenuItem.java index ccd8353..2dfbcb5 100644 --- a/core/java/android/view/MenuItem.java +++ b/core/java/android/view/MenuItem.java @@ -29,6 +29,12 @@ import android.view.View.OnCreateContextMenuListener; * methods. * <p> * For a feature set of specific menu types, see {@link Menu}. + * + * <div class="special reference"> + * <h3>Developer Guides</h3> + * <p>For information about creating menus, read the + * <a href="{@docRoot}guide/topics/ui/menus.html">Menus</a> developer guide.</p> + * </div> */ public interface MenuItem { /* diff --git a/core/java/android/view/SubMenu.java b/core/java/android/view/SubMenu.java index e981486..196a183 100644 --- a/core/java/android/view/SubMenu.java +++ b/core/java/android/view/SubMenu.java @@ -22,6 +22,12 @@ import android.graphics.drawable.Drawable; * Subclass of {@link Menu} for sub menus. * <p> * Sub menus do not support item icons, or nested sub menus. + * + * <div class="special reference"> + * <h3>Developer Guides</h3> + * <p>For information about creating menus, read the + * <a href="{@docRoot}guide/topics/ui/menus.html">Menus</a> developer guide.</p> + * </div> */ public interface SubMenu extends Menu { diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java index 86be28a..d5f18cc 100644 --- a/core/java/android/view/View.java +++ b/core/java/android/view/View.java @@ -418,7 +418,7 @@ import java.util.concurrent.CopyOnWriteArrayList; * <h3>Drawing</h3> * <p> * Drawing is handled by walking the tree and rendering each view that - * intersects the the invalid region. Because the tree is traversed in-order, + * intersects the invalid region. Because the tree is traversed in-order, * this means that parents will draw before (i.e., behind) their children, with * siblings drawn in the order they appear in the tree. * If you set a background drawable for a View, then the View will draw it for you @@ -1891,12 +1891,10 @@ public class View implements Drawable.Callback, Drawable.Callback2, KeyEvent.Cal * NOTE: This flag may only be used in subtreeSystemUiVisibility. It is masked * out of the public fields to keep the undefined bits out of the developer's way. * - * Flag to hide only the navigation buttons. Don't use this + * Flag to hide only the home button. Don't use this * unless you're a special part of the system UI (i.e., setup wizard, keyguard). - * - * THIS DOES NOT DISABLE THE BACK BUTTON */ - public static final int STATUS_BAR_DISABLE_NAVIGATION = 0x00200000; + public static final int STATUS_BAR_DISABLE_HOME = 0x00200000; /** * @hide @@ -1904,7 +1902,7 @@ public class View implements Drawable.Callback, Drawable.Callback2, KeyEvent.Cal * NOTE: This flag may only be used in subtreeSystemUiVisibility. It is masked * out of the public fields to keep the undefined bits out of the developer's way. * - * Flag to hide only the back button. Don't use this + * Flag to hide only the back button. Don't use this * unless you're a special part of the system UI (i.e., setup wizard, keyguard). */ public static final int STATUS_BAR_DISABLE_BACK = 0x00400000; @@ -1922,6 +1920,28 @@ public class View implements Drawable.Callback, Drawable.Callback2, KeyEvent.Cal /** * @hide + * + * NOTE: This flag may only be used in subtreeSystemUiVisibility. It is masked + * out of the public fields to keep the undefined bits out of the developer's way. + * + * Flag to hide only the recent apps button. Don't use this + * unless you're a special part of the system UI (i.e., setup wizard, keyguard). + */ + public static final int STATUS_BAR_DISABLE_RECENT = 0x01000000; + + /** + * @hide + * + * NOTE: This flag may only be used in subtreeSystemUiVisibility, etc. etc. + * + * This hides HOME and RECENT and is provided for compatibility with interim implementations. + */ + @Deprecated + public static final int STATUS_BAR_DISABLE_NAVIGATION = + STATUS_BAR_DISABLE_HOME | STATUS_BAR_DISABLE_RECENT; + + /** + * @hide */ public static final int PUBLIC_STATUS_BAR_VISIBILITY_MASK = 0x0000FFFF; @@ -8344,7 +8364,7 @@ public class View implements Drawable.Callback, Drawable.Callback2, KeyEvent.Cal !((ViewGroup) mParent).isViewTransitioning(this)); } /** - * Mark the the area defined by dirty as needing to be drawn. If the view is + * Mark the area defined by dirty as needing to be drawn. If the view is * visible, {@link #onDraw(android.graphics.Canvas)} will be called at some point * in the future. This must be called from a UI thread. To call from a non-UI * thread, call {@link #postInvalidate()}. @@ -8389,7 +8409,7 @@ public class View implements Drawable.Callback, Drawable.Callback2, KeyEvent.Cal } /** - * Mark the the area defined by the rect (l,t,r,b) as needing to be drawn. + * Mark the area defined by the rect (l,t,r,b) as needing to be drawn. * The coordinates of the dirty rect are relative to the view. * If the view is visible, {@link #onDraw(android.graphics.Canvas)} * will be called at some point in the future. This must be called from @@ -13075,6 +13095,12 @@ public class View implements Drawable.Callback, Drawable.Callback2, KeyEvent.Cal * {@link android.graphics.Canvas} object, then it calls {@link #onDrawShadow(Canvas) onDrawShadow()} * so that your application can draw the shadow image in the Canvas. * </p> + * + * <div class="special reference"> + * <h3>Developer Guides</h3> + * <p>For a guide to implementing drag and drop features, read the + * <a href="{@docRoot}guide/topics/ui/drag-drop.html">Drag and Drop</a> developer guide.</p> + * </div> */ public static class DragShadowBuilder { private final WeakReference<View> mView; @@ -14066,6 +14092,12 @@ public class View implements Drawable.Callback, Drawable.Callback2, KeyEvent.Cal * to this view. The callback will be invoked before the hosting view's own * onDrag(event) method. If the listener wants to fall back to the hosting view's * onDrag(event) behavior, it should return 'false' from this callback. + * + * <div class="special reference"> + * <h3>Developer Guides</h3> + * <p>For a guide to implementing drag and drop features, read the + * <a href="{@docRoot}guide/topics/ui/drag-drop.html">Drag and Drop</a> developer guide.</p> + * </div> */ public interface OnDragListener { /** diff --git a/core/java/android/view/ViewGroup.java b/core/java/android/view/ViewGroup.java index 9266ae2..62b20b3 100644 --- a/core/java/android/view/ViewGroup.java +++ b/core/java/android/view/ViewGroup.java @@ -60,6 +60,12 @@ import java.util.HashSet; * Also see {@link LayoutParams} for layout attributes. * </p> * + * <div class="special reference"> + * <h3>Developer Guides</h3> + * <p>For more information about creating user interface layouts, read the + * <a href="{@docRoot}guide/topics/ui/declaring-layout.html">XML Layouts</a> developer + * guide.</p></div> + * * @attr ref android.R.styleable#ViewGroup_clipChildren * @attr ref android.R.styleable#ViewGroup_clipToPadding * @attr ref android.R.styleable#ViewGroup_layoutAnimation @@ -5158,7 +5164,13 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager * </ul> * There are subclasses of LayoutParams for different subclasses of * ViewGroup. For example, AbsoluteLayout has its own subclass of - * LayoutParams which adds an X and Y value. + * LayoutParams which adds an X and Y value.</p> + * + * <div class="special reference"> + * <h3>Developer Guides</h3> + * <p>For more information about creating user interface layouts, read the + * <a href="{@docRoot}guide/topics/ui/declaring-layout.html">XML Layouts</a> developer + * guide.</p></div> * * @attr ref android.R.styleable#ViewGroup_Layout_layout_height * @attr ref android.R.styleable#ViewGroup_Layout_layout_width diff --git a/core/java/android/view/VolumePanel.java b/core/java/android/view/VolumePanel.java index 122865e..cdf1f8d 100644 --- a/core/java/android/view/VolumePanel.java +++ b/core/java/android/view/VolumePanel.java @@ -97,6 +97,7 @@ public class VolumePanel extends Handler implements OnSeekBarChangeListener, Vie protected AudioService mAudioService; private boolean mRingIsSilent; private boolean mShowCombinedVolumes; + private boolean mVoiceCapable; /** Dialog containing all the sliders */ private final Dialog mDialog; @@ -117,40 +118,56 @@ public class VolumePanel extends Handler implements OnSeekBarChangeListener, Vie /** All the slider controls mapped by stream type */ private HashMap<Integer,StreamControl> mStreamControls; - // List of stream types and their order - // RING, VOICE_CALL & BLUETOOTH_SCO are hidden unless explicitly requested - private static final int [] STREAM_TYPES = { - AudioManager.STREAM_BLUETOOTH_SCO, - AudioManager.STREAM_RING, - AudioManager.STREAM_VOICE_CALL, - AudioManager.STREAM_MUSIC, - AudioManager.STREAM_NOTIFICATION - }; + private enum StreamResources { + BluetoothSCOStream(AudioManager.STREAM_BLUETOOTH_SCO, + R.string.volume_icon_description_bluetooth, + R.drawable.ic_audio_bt, + R.drawable.ic_audio_bt, + false), + RingerStream(AudioManager.STREAM_RING, + R.string.volume_icon_description_ringer, + R.drawable.ic_audio_ring_notif, + R.drawable.ic_audio_ring_notif_mute, + false), + VoiceStream(AudioManager.STREAM_VOICE_CALL, + R.string.volume_icon_description_incall, + R.drawable.ic_audio_phone, + R.drawable.ic_audio_phone, + false), + MediaStream(AudioManager.STREAM_MUSIC, + R.string.volume_icon_description_media, + R.drawable.ic_audio_vol, + R.drawable.ic_audio_vol_mute, + true), + NotificationStream(AudioManager.STREAM_NOTIFICATION, + R.string.volume_icon_description_notification, + R.drawable.ic_audio_notification, + R.drawable.ic_audio_notification_mute, + true); - private static final int [] CONTENT_DESCRIPTIONS = { - R.string.volume_icon_description_bluetooth, - R.string.volume_icon_description_ringer, - R.string.volume_icon_description_incall, - R.string.volume_icon_description_media, - R.string.volume_icon_description_notification - }; - - // These icons need to correspond to the ones above. - private static final int [] STREAM_ICONS_NORMAL = { - R.drawable.ic_audio_bt, - R.drawable.ic_audio_ring_notif, - R.drawable.ic_audio_phone, - R.drawable.ic_audio_vol, - R.drawable.ic_audio_notification, + int streamType; + int descRes; + int iconRes; + int iconMuteRes; + // RING, VOICE_CALL & BLUETOOTH_SCO are hidden unless explicitly requested + boolean show; + + StreamResources(int streamType, int descRes, int iconRes, int iconMuteRes, boolean show) { + this.streamType = streamType; + this.descRes = descRes; + this.iconRes = iconRes; + this.iconMuteRes = iconMuteRes; + this.show = show; + } }; - // These icons need to correspond to the ones above. - private static final int [] STREAM_ICONS_MUTED = { - R.drawable.ic_audio_bt, - R.drawable.ic_audio_ring_notif_mute, - R.drawable.ic_audio_phone, - R.drawable.ic_audio_vol_mute, - R.drawable.ic_audio_notification_mute, + // List of stream types and their order + private static final StreamResources[] STREAMS = { + StreamResources.BluetoothSCOStream, + StreamResources.RingerStream, + StreamResources.VoiceStream, + StreamResources.MediaStream, + StreamResources.NotificationStream }; /** Object that contains data for each slider */ @@ -221,7 +238,8 @@ public class VolumePanel extends Handler implements OnSeekBarChangeListener, Vie mToneGenerators = new ToneGenerator[AudioSystem.getNumStreamTypes()]; mVibrator = new Vibrator(); - mShowCombinedVolumes = !context.getResources().getBoolean(R.bool.config_voice_capable); + mVoiceCapable = context.getResources().getBoolean(R.bool.config_voice_capable); + mShowCombinedVolumes = !mVoiceCapable; // If we don't want to show multiple volumes, hide the settings button and divider if (!mShowCombinedVolumes) { mMoreButton.setVisibility(View.GONE); @@ -260,10 +278,14 @@ public class VolumePanel extends Handler implements OnSeekBarChangeListener, Vie LayoutInflater inflater = (LayoutInflater) mContext .getSystemService(Context.LAYOUT_INFLATER_SERVICE); - mStreamControls = new HashMap<Integer,StreamControl>(STREAM_TYPES.length); + mStreamControls = new HashMap<Integer, StreamControl>(STREAMS.length); Resources res = mContext.getResources(); - for (int i = 0; i < STREAM_TYPES.length; i++) { - final int streamType = STREAM_TYPES[i]; + for (int i = 0; i < STREAMS.length; i++) { + StreamResources streamRes = STREAMS[i]; + int streamType = streamRes.streamType; + if (mVoiceCapable && streamRes == StreamResources.NotificationStream) { + streamRes = StreamResources.RingerStream; + } StreamControl sc = new StreamControl(); sc.streamType = streamType; sc.group = (ViewGroup) inflater.inflate(R.layout.volume_adjust_item, null); @@ -273,9 +295,9 @@ public class VolumePanel extends Handler implements OnSeekBarChangeListener, Vie sc.icon.setOnClickListener(this); } sc.icon.setTag(sc); - sc.icon.setContentDescription(res.getString(CONTENT_DESCRIPTIONS[i])); - sc.iconRes = STREAM_ICONS_NORMAL[i]; - sc.iconMuteRes = STREAM_ICONS_MUTED[i]; + sc.icon.setContentDescription(res.getString(streamRes.descRes)); + sc.iconRes = streamRes.iconRes; + sc.iconMuteRes = streamRes.iconMuteRes; sc.icon.setImageResource(sc.iconRes); sc.seekbarView = (SeekBar) sc.group.findViewById(R.id.seekbar); int plusOne = (streamType == AudioSystem.STREAM_BLUETOOTH_SCO || @@ -307,13 +329,10 @@ public class VolumePanel extends Handler implements OnSeekBarChangeListener, Vie private void addOtherVolumes() { if (!mShowCombinedVolumes) return; - for (int i = 0; i < STREAM_TYPES.length; i++) { + for (int i = 0; i < STREAMS.length; i++) { // Skip the phone specific ones and the active one - final int streamType = STREAM_TYPES[i]; - if (streamType == AudioManager.STREAM_RING - || streamType == AudioManager.STREAM_VOICE_CALL - || streamType == AudioManager.STREAM_BLUETOOTH_SCO - || streamType == mActiveStreamType) { + final int streamType = STREAMS[i].streamType; + if (!STREAMS[i].show || streamType == mActiveStreamType) { continue; } StreamControl sc = mStreamControls.get(streamType); diff --git a/core/java/android/view/WindowManagerPolicy.java b/core/java/android/view/WindowManagerPolicy.java index bfd2959..17bdff2 100644 --- a/core/java/android/view/WindowManagerPolicy.java +++ b/core/java/android/view/WindowManagerPolicy.java @@ -104,23 +104,23 @@ public interface WindowManagerPolicy { */ public final static String EXTRA_HDMI_PLUGGED_STATE = "state"; - // flags for interceptKeyTq /** - * Pass this event to the user / app. To be returned from {@link #interceptKeyTq}. + * Pass this event to the user / app. To be returned from + * {@link #interceptKeyBeforeQueueing}. */ public final static int ACTION_PASS_TO_USER = 0x00000001; /** * This key event should extend the user activity timeout and turn the lights on. - * To be returned from {@link #interceptKeyTq}. Do not return this and - * {@link #ACTION_GO_TO_SLEEP} or {@link #ACTION_PASS_TO_USER}. + * To be returned from {@link #interceptKeyBeforeQueueing}. + * Do not return this and {@link #ACTION_GO_TO_SLEEP} or {@link #ACTION_PASS_TO_USER}. */ public final static int ACTION_POKE_USER_ACTIVITY = 0x00000002; /** * This key event should put the device to sleep (and engage keyguard if necessary) - * To be returned from {@link #interceptKeyTq}. Do not return this and - * {@link #ACTION_POKE_USER_ACTIVITY} or {@link #ACTION_PASS_TO_USER}. + * To be returned from {@link #interceptKeyBeforeQueueing}. + * Do not return this and {@link #ACTION_POKE_USER_ACTIVITY} or {@link #ACTION_PASS_TO_USER}. */ public final static int ACTION_GO_TO_SLEEP = 0x00000004; @@ -677,10 +677,12 @@ public interface WindowManagerPolicy { * event will normally go. * @param event The key event. * @param policyFlags The policy flags associated with the key. - * @return Returns true if the policy consumed the event and it should - * not be further dispatched. + * @return 0 if the key should be dispatched immediately, -1 if the key should + * not be dispatched ever, or a positive value indicating the number of + * milliseconds by which the key dispatch should be delayed before trying + * again. */ - public boolean interceptKeyBeforeDispatching(WindowState win, KeyEvent event, int policyFlags); + public long interceptKeyBeforeDispatching(WindowState win, KeyEvent event, int policyFlags); /** * Called from the input dispatcher thread when an application did not handle diff --git a/core/java/android/webkit/WebSettings.java b/core/java/android/webkit/WebSettings.java index 9c44138..f1c2bde 100644 --- a/core/java/android/webkit/WebSettings.java +++ b/core/java/android/webkit/WebSettings.java @@ -211,6 +211,7 @@ public class WebSettings { private ZoomDensity mDefaultZoom = ZoomDensity.MEDIUM; private RenderPriority mRenderPriority = RenderPriority.NORMAL; private int mOverrideCacheMode = LOAD_DEFAULT; + private int mDoubleTapZoom = 100; private boolean mSaveFormData = true; private boolean mAutoFillEnabled = false; private boolean mSavePassword = true; @@ -769,6 +770,27 @@ public class WebSettings { } /** + * Set the double-tap zoom of the page in percent. Default is 100. + * @param doubleTapZoom A percent value for increasing or decreasing the double-tap zoom. + * @hide + */ + public void setDoubleTapZoom(int doubleTapZoom) { + if (mDoubleTapZoom != doubleTapZoom) { + mDoubleTapZoom = doubleTapZoom; + mWebView.updateDoubleTapZoom(); + } + } + + /** + * Get the double-tap zoom of the page in percent. + * @return A percent value describing the double-tap zoom. + * @hide + */ + public int getDoubleTapZoom() { + return mDoubleTapZoom; + } + + /** * Set the default zoom density of the page. This should be called from UI * thread. * @param zoom A ZoomDensity value diff --git a/core/java/android/webkit/WebView.java b/core/java/android/webkit/WebView.java index 9648cd0..48615bd 100644 --- a/core/java/android/webkit/WebView.java +++ b/core/java/android/webkit/WebView.java @@ -2079,10 +2079,12 @@ public class WebView extends AbsoluteLayout * <p> * The 'data' scheme URL formed by this method uses the default US-ASCII * charset. If you need need to set a different charset, you should form a - * 'data' scheme URL which specifies a charset parameter and call - * {@link #loadUrl(String)} instead. + * 'data' scheme URL which explicitly specifies a charset parameter in the + * mediatype portion of the URL and call {@link #loadUrl(String)} instead. + * Note that the charset obtained from the mediatype portion of a data URL + * always overrides that specified in the HTML or XML document itself. * @param data A String of data in the given encoding. - * @param mimeType The MIMEType of the data, e.g. 'text/html'. + * @param mimeType The MIME type of the data, e.g. 'text/html'. * @param encoding The encoding of the data. */ public void loadData(String data, String mimeType, String encoding) { @@ -2986,6 +2988,13 @@ public class WebView extends AbsoluteLayout return false; } + /** + * Update the double-tap zoom. + */ + /* package */ void updateDoubleTapZoom() { + mZoomManager.updateDoubleTapZoom(); + } + private int computeRealHorizontalScrollRange() { if (mDrawHistory) { return mHistoryWidth; @@ -4505,7 +4514,7 @@ public class WebView extends AbsoluteLayout boolean UIAnimationsRunning = false; // Currently for each draw we compute the animation values; // We may in the future decide to do that independently. - if (mNativeClass != 0 && nativeEvaluateLayersAnimations()) { + if (mNativeClass != 0 && nativeEvaluateLayersAnimations(mNativeClass)) { UIAnimationsRunning = true; // If we have unfinished (or unstarted) animations, // we ask for a repaint. We only need to do this in software @@ -4521,9 +4530,9 @@ public class WebView extends AbsoluteLayout extras = DRAW_EXTRAS_FIND; } else if (mSelectingText && !USE_JAVA_TEXT_SELECTION) { extras = DRAW_EXTRAS_SELECTION; - nativeSetSelectionPointer(mDrawSelectionPointer, - mZoomManager.getInvScale(), - mSelectX, mSelectY - getTitleHeight()); + nativeSetSelectionPointer(mNativeClass, + mDrawSelectionPointer, + mZoomManager.getInvScale(), mSelectX, mSelectY - getTitleHeight()); } else if (drawCursorRing) { extras = DRAW_EXTRAS_CURSOR_RING; } @@ -4537,8 +4546,8 @@ public class WebView extends AbsoluteLayout } if (canvas.isHardwareAccelerated()) { - int functor = nativeGetDrawGLFunction(mGLViewportEmpty ? null : mGLRectViewport, - mGLViewportEmpty ? null : mViewRectViewport, getScale(), extras); + int functor = nativeGetDrawGLFunction(mNativeClass, + mGLViewportEmpty ? null : mGLRectViewport, mGLViewportEmpty ? null : mViewRectViewport, getScale(), extras); ((HardwareCanvas) canvas).callDrawGLFunction(functor); if (mHardwareAccelSkia != getSettings().getHardwareAccelSkiaEnabled()) { @@ -9407,9 +9416,9 @@ public class WebView extends AbsoluteLayout // We never want to change button state if we are hardware accelerated, // but we DO want to invalidate as necessary so that the GL ring // can be drawn - nativeRecordButtons(false, false, inval); + nativeRecordButtons(mNativeClass, false, false, inval); } else { - nativeRecordButtons(focus, pressed, inval); + nativeRecordButtons(mNativeClass, focus, pressed, inval); } } @@ -9444,9 +9453,9 @@ public class WebView extends AbsoluteLayout private native int nativeDraw(Canvas canvas, int color, int extra, boolean splitIfNeeded); private native void nativeDumpDisplayTree(String urlOrNull); - private native boolean nativeEvaluateLayersAnimations(); - private native int nativeGetDrawGLFunction(Rect rect, Rect viewRect, - float scale, int extras); + private native boolean nativeEvaluateLayersAnimations(int nativeInstance); + private native int nativeGetDrawGLFunction(int nativeInstance, Rect rect, + Rect viewRect, float scale, int extras); private native void nativeUpdateDrawGLFunction(Rect rect, Rect viewRect); private native void nativeExtendSelection(int x, int y); private native int nativeFindAll(String findLower, String findUpper, @@ -9509,8 +9518,8 @@ public class WebView extends AbsoluteLayout private native boolean nativePointInNavCache(int x, int y, int slop); // Like many other of our native methods, you must make sure that // mNativeClass is not null before calling this method. - private native void nativeRecordButtons(boolean focused, - boolean pressed, boolean invalidate); + private native void nativeRecordButtons(int nativeInstance, + boolean focused, boolean pressed, boolean invalidate); private native void nativeResetSelection(); private native Point nativeSelectableText(); private native void nativeSelectAll(); @@ -9531,8 +9540,8 @@ public class WebView extends AbsoluteLayout private native void nativeReplaceBaseContent(int content); private native void nativeCopyBaseContentToPicture(Picture pict); private native boolean nativeHasContent(); - private native void nativeSetSelectionPointer(boolean set, - float scale, int x, int y); + private native void nativeSetSelectionPointer(int nativeInstance, + boolean set, float scale, int x, int y); private native boolean nativeStartSelection(int x, int y); private native void nativeStopGL(); private native Rect nativeSubtractLayers(Rect content); diff --git a/core/java/android/webkit/ZoomManager.java b/core/java/android/webkit/ZoomManager.java index 7f526e7..206142a 100644 --- a/core/java/android/webkit/ZoomManager.java +++ b/core/java/android/webkit/ZoomManager.java @@ -145,11 +145,11 @@ class ZoomManager { private float mInvDefaultScale; /* - * The scale factor that is used to determine the zoom level for reading text. - * The value is initially set to equal the display density. - * TODO: Support changing this in WebSettings + * The logical density of the display. This is a scaling factor for the + * Density Independent Pixel unit, where one DIP is one pixel on an + * approximately 160 dpi screen (see android.util.DisplayMetrics.density) */ - private float mReadingLevelScale; + private float mDisplayDensity; /* * The scale factor that is used as the minimum increment when going from @@ -233,11 +233,11 @@ class ZoomManager { public void init(float density) { assert density > 0; + mDisplayDensity = density; setDefaultZoomScale(density); mActualScale = density; mInvActualScale = 1 / density; - mReadingLevelScale = density; - mTextWrapScale = density; + mTextWrapScale = getReadingLevelScale(); } /** @@ -310,8 +310,11 @@ class ZoomManager { return mInitialScale > 0 ? mInitialScale : mDefaultScale; } + /** + * Returns the zoom scale used for reading text on a double-tap. + */ public final float getReadingLevelScale() { - return mReadingLevelScale; + return mDisplayDensity * mWebView.getSettings().getDoubleTapZoom() / 100.0f; } public final float getInvDefaultScale() { @@ -510,6 +513,13 @@ class ZoomManager { return mZoomScale != 0 || mInHWAcceleratedZoom; } + public void updateDoubleTapZoom() { + if (mInZoomOverview) { + mTextWrapScale = getReadingLevelScale(); + refreshZoomScale(true); + } + } + public void refreshZoomScale(boolean reflowText) { setZoomScale(mActualScale, reflowText, true); } diff --git a/core/java/android/widget/AbsSeekBar.java b/core/java/android/widget/AbsSeekBar.java index 475b8ee..bdaf89e 100644 --- a/core/java/android/widget/AbsSeekBar.java +++ b/core/java/android/widget/AbsSeekBar.java @@ -335,7 +335,9 @@ public abstract class AbsSeekBar extends ProgressBar { mTouchDownX = event.getX(); } else { setPressed(true); - invalidate(mThumb.getBounds()); // This may be within the padding region + if (mThumb != null) { + invalidate(mThumb.getBounds()); // This may be within the padding region + } onStartTrackingTouch(); trackTouchEvent(event); attemptClaimDrag(); @@ -349,7 +351,9 @@ public abstract class AbsSeekBar extends ProgressBar { final float x = event.getX(); if (Math.abs(x - mTouchDownX) > mScaledTouchSlop) { setPressed(true); - invalidate(mThumb.getBounds()); // This may be within the padding region + if (mThumb != null) { + invalidate(mThumb.getBounds()); // This may be within the padding region + } onStartTrackingTouch(); trackTouchEvent(event); attemptClaimDrag(); diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java index 12bc014..a21a087 100644 --- a/core/java/android/widget/TextView.java +++ b/core/java/android/widget/TextView.java @@ -2476,6 +2476,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener if (gravity != mGravity) { invalidate(); + mLayoutAlignment = null; } mGravity = gravity; diff --git a/core/java/android/widget/Toast.java b/core/java/android/widget/Toast.java index bb23173..88d7e05 100644 --- a/core/java/android/widget/Toast.java +++ b/core/java/android/widget/Toast.java @@ -48,6 +48,13 @@ import android.view.accessibility.AccessibilityManager; * <p> * The easiest way to use this class is to call one of the static methods that constructs * everything you need and returns a new Toast object. + * + * <div class="special reference"> + * <h3>Developer Guides</h3> + * <p>For information about creating Toast notifications, read the + * <a href="{@docRoot}guide/topics/ui/notifiers/toasts.html">Toast Notifications</a> developer + * guide.</p> + * </div> */ public class Toast { static final String TAG = "Toast"; diff --git a/core/java/com/android/internal/app/PlatLogoActivity.java b/core/java/com/android/internal/app/PlatLogoActivity.java index 9fbbb3d..a0e125a 100644 --- a/core/java/com/android/internal/app/PlatLogoActivity.java +++ b/core/java/com/android/internal/app/PlatLogoActivity.java @@ -17,32 +17,79 @@ package com.android.internal.app; import android.app.Activity; +import android.content.ActivityNotFoundException; +import android.content.Intent; import android.os.Bundle; +import android.os.Handler; +import android.os.Vibrator; import android.view.MotionEvent; +import android.view.View; +import android.view.ViewConfiguration; import android.widget.ImageView; import android.widget.Toast; public class PlatLogoActivity extends Activity { Toast mToast; + ImageView mContent; + Vibrator mZzz = new Vibrator(); + int mCount; + final Handler mHandler = new Handler(); + + Runnable mSuperLongPress = new Runnable() { + public void run() { + mCount++; + mZzz.vibrate(50 * mCount); + final float scale = 1f + 0.25f * mCount * mCount; + mContent.setScaleX(scale); + mContent.setScaleY(scale); + + if (mCount <= 3) { + mHandler.postDelayed(mSuperLongPress, ViewConfiguration.getLongPressTimeout()); + } else { + try { + startActivity(new Intent(Intent.ACTION_MAIN) + .setFlags(Intent.FLAG_ACTIVITY_NEW_TASK + | Intent.FLAG_ACTIVITY_CLEAR_TASK + | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS) + .setClassName("com.android.systemui","com.android.systemui.Nyandroid")); + } catch (ActivityNotFoundException ex) { + android.util.Log.e("PlatLogoActivity", "Couldn't find platlogo screensaver."); + } + finish(); + } + } + }; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); - mToast = Toast.makeText(this, "REZZZZZZZ...", Toast.LENGTH_SHORT); + mToast = Toast.makeText(this, "Android 4.0: Ice Cream Sandwich", Toast.LENGTH_SHORT); - ImageView content = new ImageView(this); - content.setImageResource(com.android.internal.R.drawable.platlogo); - content.setScaleType(ImageView.ScaleType.CENTER_INSIDE); - - setContentView(content); - } + mContent = new ImageView(this); + mContent.setImageResource(com.android.internal.R.drawable.platlogo); + mContent.setScaleType(ImageView.ScaleType.CENTER_INSIDE); - @Override - public boolean dispatchTouchEvent(MotionEvent ev) { - if (ev.getAction() == MotionEvent.ACTION_UP) { - mToast.show(); - } - return super.dispatchTouchEvent(ev); + mContent.setOnTouchListener(new View.OnTouchListener() { + @Override + public boolean onTouch(View v, MotionEvent event) { + final int action = event.getAction(); + if (action == MotionEvent.ACTION_DOWN) { + mContent.setPressed(true); + mHandler.removeCallbacks(mSuperLongPress); + mCount = 0; + mHandler.postDelayed(mSuperLongPress, 2*ViewConfiguration.getLongPressTimeout()); + } else if (action == MotionEvent.ACTION_UP) { + if (mContent.isPressed()) { + mContent.setPressed(false); + mHandler.removeCallbacks(mSuperLongPress); + mToast.show(); + } + } + return true; + } + }); + + setContentView(mContent); } } diff --git a/core/java/com/android/internal/view/menu/IconMenuPresenter.java b/core/java/com/android/internal/view/menu/IconMenuPresenter.java index 3b1decd..2439b5d 100644 --- a/core/java/com/android/internal/view/menu/IconMenuPresenter.java +++ b/core/java/com/android/internal/view/menu/IconMenuPresenter.java @@ -22,7 +22,6 @@ import android.os.Bundle; import android.os.Parcelable; import android.util.SparseArray; import android.view.ContextThemeWrapper; -import android.view.LayoutInflater; import android.view.MenuItem; import android.view.View; import android.view.ViewGroup; @@ -44,15 +43,14 @@ public class IconMenuPresenter extends BaseMenuPresenter { private static final String OPEN_SUBMENU_KEY = "android:menu:icon:submenu"; public IconMenuPresenter(Context context) { - super(context, com.android.internal.R.layout.icon_menu_layout, + super(new ContextThemeWrapper(context, com.android.internal.R.style.Theme_IconMenu), + com.android.internal.R.layout.icon_menu_layout, com.android.internal.R.layout.icon_menu_item_layout); } @Override public void initForMenu(Context context, MenuBuilder menu) { - mContext = new ContextThemeWrapper(context, com.android.internal.R.style.Theme_IconMenu); - mInflater = LayoutInflater.from(mContext); - mMenu = menu; + super.initForMenu(context, menu); mMaxItems = -1; } diff --git a/core/java/com/android/internal/widget/LockPatternView.java b/core/java/com/android/internal/widget/LockPatternView.java index 5b49bff..a2fc6e2 100644 --- a/core/java/com/android/internal/widget/LockPatternView.java +++ b/core/java/com/android/internal/widget/LockPatternView.java @@ -32,9 +32,9 @@ import android.os.Debug; import android.os.Parcel; import android.os.Parcelable; import android.os.SystemClock; -import android.os.Vibrator; import android.util.AttributeSet; import android.util.Log; +import android.view.HapticFeedbackConstants; import android.view.MotionEvent; import android.view.View; import android.view.accessibility.AccessibilityEvent; @@ -59,9 +59,6 @@ public class LockPatternView extends View { private static final int ASPECT_LOCK_WIDTH = 1; // Fixed width; height will be minimum of (w,h) private static final int ASPECT_LOCK_HEIGHT = 2; // Fixed height; width will be minimum of (w,h) - // Vibrator pattern for creating a tactile bump - private static final long[] DEFAULT_VIBE_PATTERN = {0, 1, 40, 41}; - private static final boolean PROFILE_DRAWING = false; private boolean mDrawingProfilingStarted = false; @@ -102,7 +99,7 @@ public class LockPatternView extends View { private DisplayMode mPatternDisplayMode = DisplayMode.Correct; private boolean mInputEnabled = true; private boolean mInStealthMode = false; - private boolean mTactileFeedbackEnabled = true; + private boolean mEnableHapticFeedback = true; private boolean mPatternInProgress = false; private float mDiameterFactor = 0.10f; // TODO: move to attrs @@ -127,11 +124,6 @@ public class LockPatternView extends View { private int mBitmapWidth; private int mBitmapHeight; - - private Vibrator vibe; // Vibrator for creating tactile feedback - - private long[] mVibePattern; - private int mAspect; private final Matrix mArrowMatrix = new Matrix(); private final Matrix mCircleMatrix = new Matrix(); @@ -250,7 +242,6 @@ public class LockPatternView extends View { public LockPatternView(Context context, AttributeSet attrs) { super(context, attrs); - vibe = new Vibrator(); TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.LockPatternView); @@ -295,26 +286,6 @@ public class LockPatternView extends View { mBitmapHeight = Math.max(mBitmapHeight, bitmap.getHeight()); } - // allow vibration pattern to be customized - mVibePattern = loadVibratePattern(com.android.internal.R.array.config_virtualKeyVibePattern); - } - - private long[] loadVibratePattern(int id) { - int[] pattern = null; - try { - pattern = getResources().getIntArray(id); - } catch (Resources.NotFoundException e) { - Log.e(TAG, "Vibrate pattern missing, using default", e); - } - if (pattern == null) { - return DEFAULT_VIBE_PATTERN; - } - - long[] tmpPattern = new long[pattern.length]; - for (int i = 0; i < pattern.length; i++) { - tmpPattern[i] = pattern[i]; - } - return tmpPattern; } private Bitmap getBitmapFor(int resId) { @@ -332,7 +303,7 @@ public class LockPatternView extends View { * @return Whether the view has tactile feedback enabled. */ public boolean isTactileFeedbackEnabled() { - return mTactileFeedbackEnabled; + return mEnableHapticFeedback; } /** @@ -352,7 +323,7 @@ public class LockPatternView extends View { * @param tactileFeedbackEnabled Whether tactile feedback is enabled */ public void setTactileFeedbackEnabled(boolean tactileFeedbackEnabled) { - mTactileFeedbackEnabled = tactileFeedbackEnabled; + mEnableHapticFeedback = tactileFeedbackEnabled; } /** @@ -573,8 +544,10 @@ public class LockPatternView extends View { addCellToPattern(fillInGapCell); } addCellToPattern(cell); - if (mTactileFeedbackEnabled){ - vibe.vibrate(mVibePattern, -1); // Generate tactile feedback + if (mEnableHapticFeedback) { + performHapticFeedback(HapticFeedbackConstants.VIRTUAL_KEY, + HapticFeedbackConstants.FLAG_IGNORE_VIEW_SETTING + | HapticFeedbackConstants.FLAG_IGNORE_GLOBAL_SETTING); } return cell; } @@ -1114,7 +1087,7 @@ public class LockPatternView extends View { return new SavedState(superState, LockPatternUtils.patternToString(mPattern), mPatternDisplayMode.ordinal(), - mInputEnabled, mInStealthMode, mTactileFeedbackEnabled); + mInputEnabled, mInStealthMode, mEnableHapticFeedback); } @Override @@ -1127,7 +1100,7 @@ public class LockPatternView extends View { mPatternDisplayMode = DisplayMode.values()[ss.getDisplayMode()]; mInputEnabled = ss.isInputEnabled(); mInStealthMode = ss.isInStealthMode(); - mTactileFeedbackEnabled = ss.isTactileFeedbackEnabled(); + mEnableHapticFeedback = ss.isTactileFeedbackEnabled(); } /** diff --git a/core/java/com/android/internal/widget/LockScreenWidgetCallback.java b/core/java/com/android/internal/widget/LockScreenWidgetCallback.java index d6403e9..d7ad6c0 100644 --- a/core/java/com/android/internal/widget/LockScreenWidgetCallback.java +++ b/core/java/com/android/internal/widget/LockScreenWidgetCallback.java @@ -29,6 +29,9 @@ public interface LockScreenWidgetCallback { // Sends a message to lock screen requesting the view to be hidden. public void requestHide(View self); + // Whether or not this view is currently visible on LockScreen + public boolean isVisible(View self); + // Sends a message to lock screen that user has interacted with widget. This should be used // exclusively in response to user activity, i.e. user hits a button in the view. public void userActivity(View self); diff --git a/core/java/com/android/internal/widget/PasswordEntryKeyboardHelper.java b/core/java/com/android/internal/widget/PasswordEntryKeyboardHelper.java index 01df48a..2e7810f 100644 --- a/core/java/com/android/internal/widget/PasswordEntryKeyboardHelper.java +++ b/core/java/com/android/internal/widget/PasswordEntryKeyboardHelper.java @@ -26,6 +26,7 @@ import android.os.SystemClock; import android.os.Vibrator; import android.provider.Settings; import android.util.Log; +import android.view.HapticFeedbackConstants; import android.view.KeyCharacterMap; import android.view.KeyEvent; import android.view.View; @@ -52,7 +53,7 @@ public class PasswordEntryKeyboardHelper implements OnKeyboardActionListener { private final View mTargetView; private final KeyboardView mKeyboardView; private long[] mVibratePattern; - private final Vibrator mVibrator; + private boolean mEnableHaptics = false; public PasswordEntryKeyboardHelper(Context context, KeyboardView keyboardView, View targetView) { this(context, keyboardView, targetView, true); @@ -71,7 +72,10 @@ public class PasswordEntryKeyboardHelper implements OnKeyboardActionListener { mKeyboardView.getLayoutParams().height); } mKeyboardView.setOnKeyboardActionListener(this); - mVibrator = new Vibrator(); + } + + public void setEnableHaptics(boolean enabled) { + mEnableHaptics = enabled; } public boolean isAlpha() { @@ -230,6 +234,7 @@ public class PasswordEntryKeyboardHelper implements OnKeyboardActionListener { public void handleBackspace() { sendDownUpKeyEvents(KeyEvent.KEYCODE_DEL); + performHapticFeedback(); } private void handleShift() { @@ -272,8 +277,14 @@ public class PasswordEntryKeyboardHelper implements OnKeyboardActionListener { } public void onPress(int primaryCode) { - if (mVibratePattern != null) { - mVibrator.vibrate(mVibratePattern, -1); + performHapticFeedback(); + } + + private void performHapticFeedback() { + if (mEnableHaptics) { + mKeyboardView.performHapticFeedback(HapticFeedbackConstants.VIRTUAL_KEY, + HapticFeedbackConstants.FLAG_IGNORE_VIEW_SETTING + | HapticFeedbackConstants.FLAG_IGNORE_GLOBAL_SETTING); } } diff --git a/core/java/com/android/internal/widget/TransportControlView.java b/core/java/com/android/internal/widget/TransportControlView.java index 73d9f10..63a3aa5 100644 --- a/core/java/com/android/internal/widget/TransportControlView.java +++ b/core/java/com/android/internal/widget/TransportControlView.java @@ -34,6 +34,8 @@ import android.media.IRemoteControlDisplay; import android.os.Bundle; import android.os.Handler; import android.os.Message; +import android.os.Parcel; +import android.os.Parcelable; import android.os.RemoteException; import android.os.SystemClock; import android.text.Spannable; @@ -61,7 +63,7 @@ public class TransportControlView extends FrameLayout implements OnClickListener private static final int MSG_SET_GENERATION_ID = 104; private static final int MAXDIM = 512; private static final int DISPLAY_TIMEOUT_MS = 5000; // 5s - protected static final boolean DEBUG = true; + protected static final boolean DEBUG = false; protected static final String TAG = "TransportControlView"; private ImageView mAlbumArt; @@ -74,7 +76,7 @@ public class TransportControlView extends FrameLayout implements OnClickListener private boolean mAttached; private PendingIntent mClientIntent; private int mTransportControlFlags; - private int mPlayState; + private int mCurrentPlayState; private AudioManager mAudioManager; private LockScreenWidgetCallback mWidgetCallbacks; private IRemoteControlDisplayWeak mIRCD; @@ -84,6 +86,11 @@ public class TransportControlView extends FrameLayout implements OnClickListener */ private Bundle mPopulateMetadataWhenAttached = null; + /** + * Whether to clear the interface next time it is shown (i.e. the generation id changed) + */ + private boolean mClearOnNextShow; + // This handler is required to ensure messages from IRCD are handled in sequence and on // the UI thread. private Handler mHandler = new Handler() { @@ -113,15 +120,10 @@ public class TransportControlView extends FrameLayout implements OnClickListener break; case MSG_SET_GENERATION_ID: - if (mWidgetCallbacks != null) { - boolean clearing = msg.arg2 != 0; - if (DEBUG) Log.v(TAG, "New genId = " + msg.arg1 + ", clearing = " + clearing); - if (!clearing) { - mWidgetCallbacks.requestShow(TransportControlView.this); - } else { - mWidgetCallbacks.requestHide(TransportControlView.this); - } + if (msg.arg2 != 0) { + mClearOnNextShow = true; // TODO: handle this } + if (DEBUG) Log.v(TAG, "New genId = " + msg.arg1 + ", clearing = " + msg.arg2); mClientGeneration = msg.arg1; mClientIntent = (PendingIntent) msg.obj; break; @@ -195,6 +197,7 @@ public class TransportControlView extends FrameLayout implements OnClickListener super(context, attrs); Log.v(TAG, "Create TCV " + this); mAudioManager = new AudioManager(mContext); + mCurrentPlayState = RemoteControlClient.PLAYSTATE_NONE; // until we get a callback mIRCD = new IRemoteControlDisplayWeak(mHandler); } @@ -319,7 +322,7 @@ public class TransportControlView extends FrameLayout implements OnClickListener | RemoteControlClient.FLAG_KEY_MEDIA_PLAY_PAUSE | RemoteControlClient.FLAG_KEY_MEDIA_STOP); - updatePlayPauseState(mPlayState); + updatePlayPauseState(mCurrentPlayState); } private static void setVisibilityBasedOnFlag(View view, int flags, int flag) { @@ -332,32 +335,99 @@ public class TransportControlView extends FrameLayout implements OnClickListener private void updatePlayPauseState(int state) { if (DEBUG) Log.v(TAG, - "updatePlayPauseState(), old=" + mPlayState + ", state=" + state); - if (state == mPlayState) { + "updatePlayPauseState(), old=" + mCurrentPlayState + ", state=" + state); + if (state == mCurrentPlayState) { return; } final int imageResId; final int imageDescId; + boolean showIfHidden = false; switch (state) { + case RemoteControlClient.PLAYSTATE_ERROR: + imageResId = com.android.internal.R.drawable.stat_sys_warning; + // TODO use more specific image description string for warning, but here the "play" + // message is still valid because this button triggers a play command. + imageDescId = com.android.internal.R.string.lockscreen_transport_play_description; + break; + case RemoteControlClient.PLAYSTATE_PLAYING: imageResId = com.android.internal.R.drawable.ic_media_pause; imageDescId = com.android.internal.R.string.lockscreen_transport_pause_description; + showIfHidden = true; break; case RemoteControlClient.PLAYSTATE_BUFFERING: imageResId = com.android.internal.R.drawable.ic_media_stop; imageDescId = com.android.internal.R.string.lockscreen_transport_stop_description; + showIfHidden = true; break; case RemoteControlClient.PLAYSTATE_PAUSED: default: imageResId = com.android.internal.R.drawable.ic_media_play; imageDescId = com.android.internal.R.string.lockscreen_transport_play_description; + showIfHidden = false; break; } mBtnPlay.setImageResource(imageResId); mBtnPlay.setContentDescription(getResources().getString(imageDescId)); - mPlayState = state; + if (showIfHidden && mWidgetCallbacks != null && !mWidgetCallbacks.isVisible(this)) { + mWidgetCallbacks.requestShow(this); + } + mCurrentPlayState = state; + } + + static class SavedState extends BaseSavedState { + boolean wasShowing; + + SavedState(Parcelable superState) { + super(superState); + } + + private SavedState(Parcel in) { + super(in); + this.wasShowing = in.readInt() != 0; + } + + @Override + public void writeToParcel(Parcel out, int flags) { + super.writeToParcel(out, flags); + out.writeInt(this.wasShowing ? 1 : 0); + } + + public static final Parcelable.Creator<SavedState> CREATOR + = new Parcelable.Creator<SavedState>() { + public SavedState createFromParcel(Parcel in) { + return new SavedState(in); + } + + public SavedState[] newArray(int size) { + return new SavedState[size]; + } + }; + } + + @Override + public Parcelable onSaveInstanceState() { + if (DEBUG) Log.v(TAG, "onSaveInstanceState()"); + Parcelable superState = super.onSaveInstanceState(); + SavedState ss = new SavedState(superState); + ss.wasShowing = mWidgetCallbacks.isVisible(this); + return ss; + } + + @Override + public void onRestoreInstanceState(Parcelable state) { + if (DEBUG) Log.v(TAG, "onRestoreInstanceState()"); + if (!(state instanceof SavedState)) { + super.onRestoreInstanceState(state); + return; + } + SavedState ss = (SavedState) state; + super.onRestoreInstanceState(ss.getSuperState()); + if (ss.wasShowing) { + mWidgetCallbacks.requestShow(this); + } } public void onClick(View v) { |