diff options
187 files changed, 2565 insertions, 786 deletions
diff --git a/api/current.txt b/api/current.txt index e379f8b7ddf9..c4256afcbc2d 100644 --- a/api/current.txt +++ b/api/current.txt @@ -370,6 +370,7 @@ package android { field public static final int dialogTitle = 16843250; // 0x10101f2 field public static final int digits = 16843110; // 0x1010166 field public static final int direction = 16843217; // 0x10101d1 + field public static final int directionDescriptions = 16843695; // 0x10103af field public static final int directionPriority = 16843218; // 0x10101d2 field public static final int disableDependentsState = 16843249; // 0x10101f1 field public static final int disabledAlpha = 16842803; // 0x1010033 @@ -938,6 +939,7 @@ package android { field public static final int tag = 16842961; // 0x10100d1 field public static final int targetActivity = 16843266; // 0x1010202 field public static final int targetClass = 16842799; // 0x101002f + field public static final int targetDescriptions = 16843694; // 0x10103ae field public static final int targetDrawables = 16843654; // 0x1010386 field public static final int targetPackage = 16842785; // 0x1010021 field public static final int targetSdkVersion = 16843376; // 0x1010270 @@ -3277,6 +3279,7 @@ package android.app { method public void setArguments(android.os.Bundle); method public void setHasOptionsMenu(boolean); method public void setInitialSavedState(android.app.Fragment.SavedState); + method public void setMenuVisibility(boolean); method public void setRetainInstance(boolean); method public void setTargetFragment(android.app.Fragment, int); method public void startActivity(android.content.Intent); @@ -3342,6 +3345,7 @@ package android.app { method public abstract java.lang.CharSequence getBreadCrumbTitle(); method public abstract int getBreadCrumbTitleRes(); method public abstract int getId(); + method public abstract java.lang.String getName(); } public static abstract interface FragmentManager.OnBackStackChangedListener { @@ -4040,6 +4044,7 @@ package android.app.backup { public abstract class BackupAgent extends android.content.ContextWrapper { ctor public BackupAgent(); + method public final void fullBackupFile(java.io.File, android.app.backup.FullBackupDataOutput); method public abstract void onBackup(android.os.ParcelFileDescriptor, android.app.backup.BackupDataOutput, android.os.ParcelFileDescriptor) throws java.io.IOException; method public void onCreate(); method public void onDestroy(); @@ -10676,6 +10681,7 @@ package android.media { method public void setOnVideoSizeChangedListener(android.media.MediaPlayer.OnVideoSizeChangedListener); method public void setScreenOnWhilePlaying(boolean); method public void setTexture(android.graphics.SurfaceTexture); + method public void setSurface(android.view.Surface); method public void setVolume(float, float); method public void setWakeMode(android.content.Context, int); method public void start() throws java.lang.IllegalStateException; @@ -16052,7 +16058,7 @@ package android.provider { public final class ContactsContract { ctor public ContactsContract(); - field public static final java.lang.String ALLOW_PROFILE = "allow_profile"; + method public static boolean isProfileId(long); field public static final java.lang.String AUTHORITY = "com.android.contacts"; field public static final android.net.Uri AUTHORITY_URI; field public static final java.lang.String CALLER_IS_SYNCADAPTER = "caller_is_syncadapter"; @@ -16579,6 +16585,16 @@ package android.provider { field public static final android.net.Uri CONTENT_RAW_CONTACTS_URI; field public static final android.net.Uri CONTENT_URI; field public static final android.net.Uri CONTENT_VCARD_URI; + field public static final long MIN_ID = 9223372034707292160L; // 0x7fffffff80000000L + } + + public static final class ContactsContract.ProfileSyncState implements android.provider.SyncStateContract.Columns { + method public static byte[] get(android.content.ContentProviderClient, android.accounts.Account) throws android.os.RemoteException; + method public static android.util.Pair<android.net.Uri, byte[]> getWithUri(android.content.ContentProviderClient, android.accounts.Account) throws android.os.RemoteException; + method public static android.content.ContentProviderOperation newSetOperation(android.accounts.Account, byte[]); + method public static void set(android.content.ContentProviderClient, android.accounts.Account, byte[]) throws android.os.RemoteException; + field public static final java.lang.String CONTENT_DIRECTORY = "syncstate"; + field public static final android.net.Uri CONTENT_URI; } public static final class ContactsContract.QuickContact { @@ -16677,6 +16693,7 @@ package android.provider { field public static final java.lang.String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/status-update"; field public static final java.lang.String CONTENT_TYPE = "vnd.android.cursor.dir/status-update"; field public static final android.net.Uri CONTENT_URI; + field public static final android.net.Uri PROFILE_CONTENT_URI; } public static final class ContactsContract.StreamItemPhotos implements android.provider.BaseColumns android.provider.ContactsContract.StreamItemPhotosColumns { @@ -16714,6 +16731,7 @@ package android.provider { 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"; @@ -20671,6 +20689,14 @@ package android.text.style { field protected final int mVerticalAlignment; } + public class EasyEditSpan implements android.text.ParcelableSpan { + ctor public EasyEditSpan(); + ctor public EasyEditSpan(android.os.Parcel); + method public int describeContents(); + method public int getSpanTypeId(); + method public void writeToParcel(android.os.Parcel, int); + } + public class ForegroundColorSpan extends android.text.style.CharacterStyle implements android.text.ParcelableSpan android.text.style.UpdateAppearance { ctor public ForegroundColorSpan(int); ctor public ForegroundColorSpan(android.os.Parcel); @@ -22508,6 +22534,7 @@ package android.view { } public class Surface implements android.os.Parcelable { + ctor public Surface(android.graphics.SurfaceTexture); method public int describeContents(); method public boolean isValid(); method public android.graphics.Canvas lockCanvas(android.graphics.Rect) throws java.lang.IllegalArgumentException, android.view.Surface.OutOfResourcesException; diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java index 1271ddd68c83..0e3eaaa5ed55 100644 --- a/core/java/android/app/Activity.java +++ b/core/java/android/app/Activity.java @@ -4206,7 +4206,6 @@ public class Activity extends ContextThemeWrapper fragment.mContainerId = containerId; fragment.mTag = tag; fragment.mInLayout = true; - fragment.mImmediateActivity = this; fragment.mFragmentManager = mFragments; fragment.onInflate(this, attrs, fragment.mSavedFragmentState); mFragments.addFragment(fragment, true); @@ -4222,7 +4221,6 @@ public class Activity extends ContextThemeWrapper // This fragment was retained from a previous instance; get it // going now. fragment.mInLayout = true; - fragment.mImmediateActivity = this; // If this fragment is newly instantiated (either right now, or // from last saved state), then give it the attributes to // initialize itself. diff --git a/core/java/android/app/BackStackRecord.java b/core/java/android/app/BackStackRecord.java index 93330a798901..e9e8e1626a2a 100644 --- a/core/java/android/app/BackStackRecord.java +++ b/core/java/android/app/BackStackRecord.java @@ -344,10 +344,6 @@ final class BackStackRecord extends FragmentTransaction implements } private void doAddOp(int containerViewId, Fragment fragment, String tag, int opcmd) { - if (fragment.mImmediateActivity != null) { - throw new IllegalStateException("Fragment already added: " + fragment); - } - fragment.mImmediateActivity = mManager.mActivity; fragment.mFragmentManager = mManager; if (tag != null) { @@ -388,11 +384,6 @@ final class BackStackRecord extends FragmentTransaction implements } public FragmentTransaction remove(Fragment fragment) { - if (fragment.mImmediateActivity == null) { - throw new IllegalStateException("Fragment not added: " + fragment); - } - fragment.mImmediateActivity = null; - Op op = new Op(); op.cmd = OP_REMOVE; op.fragment = fragment; @@ -402,10 +393,6 @@ final class BackStackRecord extends FragmentTransaction implements } public FragmentTransaction hide(Fragment fragment) { - if (fragment.mImmediateActivity == null) { - throw new IllegalStateException("Fragment not added: " + fragment); - } - Op op = new Op(); op.cmd = OP_HIDE; op.fragment = fragment; @@ -415,10 +402,6 @@ final class BackStackRecord extends FragmentTransaction implements } public FragmentTransaction show(Fragment fragment) { - if (fragment.mImmediateActivity == null) { - throw new IllegalStateException("Fragment not added: " + fragment); - } - Op op = new Op(); op.cmd = OP_SHOW; op.fragment = fragment; @@ -428,10 +411,6 @@ final class BackStackRecord extends FragmentTransaction implements } public FragmentTransaction detach(Fragment fragment) { - //if (fragment.mImmediateActivity == null) { - // throw new IllegalStateException("Fragment not added: " + fragment); - //} - Op op = new Op(); op.cmd = OP_DETACH; op.fragment = fragment; @@ -441,10 +420,6 @@ final class BackStackRecord extends FragmentTransaction implements } public FragmentTransaction attach(Fragment fragment) { - //if (fragment.mImmediateActivity == null) { - // throw new IllegalStateException("Fragment not added: " + fragment); - //} - Op op = new Op(); op.cmd = OP_ATTACH; op.fragment = fragment; @@ -663,7 +638,6 @@ final class BackStackRecord extends FragmentTransaction implements case OP_ADD: { Fragment f = op.fragment; f.mNextAnim = op.popExitAnim; - f.mImmediateActivity = null; mManager.removeFragment(f, FragmentManagerImpl.reverseTransit(mTransition), mTransitionStyle); @@ -671,7 +645,6 @@ final class BackStackRecord extends FragmentTransaction implements case OP_REPLACE: { Fragment f = op.fragment; f.mNextAnim = op.popExitAnim; - f.mImmediateActivity = null; mManager.removeFragment(f, FragmentManagerImpl.reverseTransit(mTransition), mTransitionStyle); @@ -679,7 +652,6 @@ final class BackStackRecord extends FragmentTransaction implements for (int i=0; i<op.removed.size(); i++) { Fragment old = op.removed.get(i); old.mNextAnim = op.popEnterAnim; - f.mImmediateActivity = mManager.mActivity; mManager.addFragment(old, false); } } @@ -687,7 +659,6 @@ final class BackStackRecord extends FragmentTransaction implements case OP_REMOVE: { Fragment f = op.fragment; f.mNextAnim = op.popEnterAnim; - f.mImmediateActivity = mManager.mActivity; mManager.addFragment(f, false); } break; case OP_HIDE: { diff --git a/core/java/android/app/Fragment.java b/core/java/android/app/Fragment.java index a8621f895f8a..3a08e6d4ee17 100644 --- a/core/java/android/app/Fragment.java +++ b/core/java/android/app/Fragment.java @@ -402,10 +402,6 @@ public class Fragment implements ComponentCallbacks2, OnCreateContextMenuListene // from all transactions. FragmentManager mFragmentManager; - // Set as soon as a fragment is added to a transaction (or removed), - // to be able to do validation. - Activity mImmediateActivity; - // Activity this fragment is attached to. Activity mActivity; @@ -438,7 +434,10 @@ public class Fragment implements ComponentCallbacks2, OnCreateContextMenuListene // If set this fragment has menu items to contribute. boolean mHasMenu; - + + // Set to true to allow the fragment's menu to be shown. + boolean mMenuVisible = true; + // Used to verify that subclasses call through to super class. boolean mCalled; @@ -888,7 +887,25 @@ public class Fragment implements ComponentCallbacks2, OnCreateContextMenuListene } } } - + + /** + * Set a hint for whether this fragment's menu should be visible. This + * is useful if you know that a fragment has been placed in your view + * hierarchy so that the user can not currently seen it, so any menu items + * it has should also not be shown. + * + * @param menuVisible The default is true, meaning the fragment's menu will + * be shown as usual. If false, the user will not see the menu. + */ + public void setMenuVisibility(boolean menuVisible) { + if (mMenuVisible != menuVisible) { + mMenuVisible = menuVisible; + if (mHasMenu && isAdded() && !isHidden()) { + mFragmentManager.invalidateOptionsMenu(); + } + } + } + /** * Return the LoaderManager for this fragment, creating it if needed. */ @@ -1233,7 +1250,7 @@ public class Fragment implements ComponentCallbacks2, OnCreateContextMenuListene mRestored = false; mBackStackNesting = 0; mFragmentManager = null; - mActivity = mImmediateActivity = null; + mActivity = null; mFragmentId = 0; mContainerId = 0; mTag = null; @@ -1421,17 +1438,14 @@ public class Fragment implements ComponentCallbacks2, OnCreateContextMenuListene writer.print(" mInLayout="); writer.println(mInLayout); writer.print(prefix); writer.print("mHidden="); writer.print(mHidden); writer.print(" mDetached="); writer.print(mDetached); - writer.print(" mRetainInstance="); writer.print(mRetainInstance); - writer.print(" mRetaining="); writer.print(mRetaining); + writer.print(" mMenuVisible="); writer.print(mMenuVisible); writer.print(" mHasMenu="); writer.println(mHasMenu); + writer.print(prefix); writer.print("mRetainInstance="); writer.print(mRetainInstance); + writer.print(" mRetaining="); writer.println(mRetaining); if (mFragmentManager != null) { writer.print(prefix); writer.print("mFragmentManager="); writer.println(mFragmentManager); } - if (mImmediateActivity != null) { - writer.print(prefix); writer.print("mImmediateActivity="); - writer.println(mImmediateActivity); - } if (mActivity != null) { writer.print(prefix); writer.print("mActivity="); writer.println(mActivity); diff --git a/core/java/android/app/FragmentManager.java b/core/java/android/app/FragmentManager.java index 70e6866db03c..7a6759f9f084 100644 --- a/core/java/android/app/FragmentManager.java +++ b/core/java/android/app/FragmentManager.java @@ -67,6 +67,13 @@ public abstract class FragmentManager { public int getId(); /** + * Get the name that was supplied to + * {@link FragmentTransaction#addToBackStack(String) + * FragmentTransaction.addToBackStack(String)} when creating this entry. + */ + public String getName(); + + /** * Return the full bread crumb title resource identifier for the entry, * or 0 if it does not have one. */ @@ -949,7 +956,6 @@ final class FragmentManagerImpl extends FragmentManager { if (!f.mRetaining) { makeInactive(f); } else { - f.mImmediateActivity = null; f.mActivity = null; f.mFragmentManager = null; } @@ -1037,7 +1043,7 @@ final class FragmentManagerImpl extends FragmentManager { mAdded.add(fragment); fragment.mAdded = true; fragment.mRemoving = false; - if (fragment.mHasMenu) { + if (fragment.mHasMenu && fragment.mMenuVisible) { mNeedMenuInvalidate = true; } if (moveToStateNow) { @@ -1051,7 +1057,7 @@ final class FragmentManagerImpl extends FragmentManager { final boolean inactive = !fragment.isInBackStack(); if (!fragment.mDetached || inactive) { mAdded.remove(fragment); - if (fragment.mHasMenu) { + if (fragment.mHasMenu && fragment.mMenuVisible) { mNeedMenuInvalidate = true; } fragment.mAdded = false; @@ -1086,7 +1092,7 @@ final class FragmentManagerImpl extends FragmentManager { fragment.mView.setVisibility(View.GONE); } } - if (fragment.mAdded && fragment.mHasMenu) { + if (fragment.mAdded && fragment.mHasMenu && fragment.mMenuVisible) { mNeedMenuInvalidate = true; } fragment.onHiddenChanged(true); @@ -1106,7 +1112,7 @@ final class FragmentManagerImpl extends FragmentManager { } fragment.mView.setVisibility(View.VISIBLE); } - if (fragment.mAdded && fragment.mHasMenu) { + if (fragment.mAdded && fragment.mHasMenu && fragment.mMenuVisible) { mNeedMenuInvalidate = true; } fragment.onHiddenChanged(false); @@ -1120,7 +1126,7 @@ final class FragmentManagerImpl extends FragmentManager { if (fragment.mAdded) { // We are not already in back stack, so need to remove the fragment. mAdded.remove(fragment); - if (fragment.mHasMenu) { + if (fragment.mHasMenu && fragment.mMenuVisible) { mNeedMenuInvalidate = true; } fragment.mAdded = false; @@ -1136,7 +1142,7 @@ final class FragmentManagerImpl extends FragmentManager { if (!fragment.mAdded) { mAdded.add(fragment); fragment.mAdded = true; - if (fragment.mHasMenu) { + if (fragment.mHasMenu && fragment.mMenuVisible) { mNeedMenuInvalidate = true; } moveToState(fragment, mCurState, transition, transitionStyle); @@ -1640,7 +1646,6 @@ final class FragmentManagerImpl extends FragmentManager { "No instantiated fragment for index #" + fms.mAdded[i]); } f.mAdded = true; - f.mImmediateActivity = mActivity; if (DEBUG) Log.v(TAG, "restoreAllState: making added #" + i + ": " + f); mAdded.add(f); } @@ -1748,7 +1753,7 @@ final class FragmentManagerImpl extends FragmentManager { if (mActive != null) { for (int i=0; i<mAdded.size(); i++) { Fragment f = mAdded.get(i); - if (f != null && !f.mHidden && f.mHasMenu) { + if (f != null && !f.mHidden && f.mHasMenu && f.mMenuVisible) { show = true; f.onCreateOptionsMenu(menu, inflater); if (newMenus == null) { @@ -1778,7 +1783,7 @@ final class FragmentManagerImpl extends FragmentManager { if (mActive != null) { for (int i=0; i<mAdded.size(); i++) { Fragment f = mAdded.get(i); - if (f != null && !f.mHidden && f.mHasMenu) { + if (f != null && !f.mHidden && f.mHasMenu && f.mMenuVisible) { show = true; f.onPrepareOptionsMenu(menu); } @@ -1791,7 +1796,7 @@ final class FragmentManagerImpl extends FragmentManager { if (mActive != null) { for (int i=0; i<mAdded.size(); i++) { Fragment f = mAdded.get(i); - if (f != null && !f.mHidden && f.mHasMenu) { + if (f != null && !f.mHidden && f.mHasMenu && f.mMenuVisible) { if (f.onOptionsItemSelected(item)) { return true; } @@ -1819,7 +1824,7 @@ final class FragmentManagerImpl extends FragmentManager { if (mActive != null) { for (int i=0; i<mAdded.size(); i++) { Fragment f = mAdded.get(i); - if (f != null && !f.mHidden && f.mHasMenu) { + if (f != null && !f.mHidden && f.mHasMenu && f.mMenuVisible) { f.onOptionsMenuClosed(menu); } } diff --git a/core/java/android/app/backup/BackupAgent.java b/core/java/android/app/backup/BackupAgent.java index 58ea0c34e422..9542874902ca 100644 --- a/core/java/android/app/backup/BackupAgent.java +++ b/core/java/android/app/backup/BackupAgent.java @@ -255,10 +255,7 @@ public abstract class BackupAgent extends ContextWrapper { * will be delivered to the backup destination along with the metadata necessary * to place it with the proper location and permissions on the device where the * data is restored. - * @hide * - * @param context The BackupAgent that is calling this method. It is an error to - * call it from something other than a running BackupAgent instance. * @param file The file to be backed up. The file must exist and be readable by * the caller. * @param output The destination to which the backed-up file data will be sent. diff --git a/core/java/android/bluetooth/BluetoothAdapter.java b/core/java/android/bluetooth/BluetoothAdapter.java index 223692859d8a..254c98ff8cf0 100644 --- a/core/java/android/bluetooth/BluetoothAdapter.java +++ b/core/java/android/bluetooth/BluetoothAdapter.java @@ -22,6 +22,7 @@ import android.content.Context; import android.os.Binder; import android.os.Handler; import android.os.IBinder; +import android.os.Looper; import android.os.Message; import android.os.ParcelUuid; import android.os.RemoteException; @@ -348,6 +349,8 @@ public final class BluetoothAdapter { private final IBluetooth mService; + private Handler mServiceRecordHandler; + /** * Get a handle to the default local Bluetooth adapter. * <p>Currently Android only supports one Bluetooth adapter, but the API @@ -376,6 +379,7 @@ public final class BluetoothAdapter { throw new IllegalArgumentException("service is null"); } mService = service; + mServiceRecordHandler = null; } /** @@ -1011,7 +1015,21 @@ public final class BluetoothAdapter { } catch (IOException e) {} throw new IOException("Not able to register SDP record for " + name); } - socket.setCloseHandler(mHandler, handle); + + if (mServiceRecordHandler == null) { + mServiceRecordHandler = new Handler(Looper.getMainLooper()) { + public void handleMessage(Message msg) { + /* handle socket closing */ + int handle = msg.what; + try { + if (DBG) Log.d(TAG, "Removing service record " + + Integer.toHexString(handle)); + mService.removeServiceRecord(handle); + } catch (RemoteException e) {Log.e(TAG, "", e);} + } + }; + } + socket.setCloseHandler(mServiceRecordHandler, handle); return socket; } @@ -1243,17 +1261,6 @@ public final class BluetoothAdapter { return Collections.unmodifiableSet(devices); } - private Handler mHandler = new Handler() { - public void handleMessage(Message msg) { - /* handle socket closing */ - int handle = msg.what; - try { - if (DBG) Log.d(TAG, "Removing service record " + Integer.toHexString(handle)); - mService.removeServiceRecord(handle); - } catch (RemoteException e) {Log.e(TAG, "", e);} - } - }; - /** * Validate a Bluetooth address, such as "00:43:A8:23:10:F0" * <p>Alphabetic characters must be uppercase to be valid. diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java index 9c96883e9000..3441217026f8 100644 --- a/core/java/android/net/ConnectivityManager.java +++ b/core/java/android/net/ConnectivityManager.java @@ -23,6 +23,7 @@ import android.annotation.SdkConstant.SdkConstantType; import android.os.Binder; import android.os.Build.VERSION_CODES; import android.os.RemoteException; +import android.provider.Settings; import java.net.InetAddress; @@ -71,6 +72,15 @@ public class ConnectivityManager { public static final String CONNECTIVITY_ACTION = "android.net.conn.CONNECTIVITY_CHANGE"; /** + * Identical to {@link #CONNECTIVITY_ACTION} broadcast, but sent without any + * applicable {@link Settings.Secure#CONNECTIVITY_CHANGE_DELAY}. + * + * @hide + */ + public static final String CONNECTIVITY_ACTION_IMMEDIATE = + "android.net.conn.CONNECTIVITY_CHANGE_IMMEDIATE"; + + /** * The lookup key for a {@link NetworkInfo} object. Retrieve with * {@link android.content.Intent#getParcelableExtra(String)}. * diff --git a/core/java/android/provider/ContactsContract.java b/core/java/android/provider/ContactsContract.java index e9221fe98859..1f2b3429f3f8 100644 --- a/core/java/android/provider/ContactsContract.java +++ b/core/java/android/provider/ContactsContract.java @@ -125,19 +125,6 @@ public final class ContactsContract { public static final String CALLER_IS_SYNCADAPTER = "caller_is_syncadapter"; /** - * An optional URI parameter for selection queries that instructs the - * provider to allow the user's personal profile contact entry (if any) - * to appear in a list of contact results. It is only useful when issuing - * a query that may retrieve more than one contact. If present, the user's - * profile will always be the first entry returned. The default value is - * false. - * - * Specifying this parameter will result in a security error if the calling - * application does not have android.permission.READ_PROFILE permission. - */ - public static final String ALLOW_PROFILE = "allow_profile"; - - /** * Query parameter that should be used by the client to access a specific * {@link Directory}. The parameter value should be the _ID of the corresponding * directory, e.g. @@ -557,7 +544,7 @@ public final class ContactsContract { } /** - * A table provided for sync adapters to use for storing private sync state data. + * A table provided for sync adapters to use for storing private sync state data for contacts. * * @see SyncStateContract */ @@ -608,6 +595,60 @@ public final class ContactsContract { } } + + /** + * A table provided for sync adapters to use for storing private sync state data for the + * user's personal profile. + * + * @see SyncStateContract + */ + public static final class ProfileSyncState implements SyncStateContract.Columns { + /** + * This utility class cannot be instantiated + */ + private ProfileSyncState() {} + + public static final String CONTENT_DIRECTORY = + SyncStateContract.Constants.CONTENT_DIRECTORY; + + /** + * The content:// style URI for this table + */ + public static final Uri CONTENT_URI = + Uri.withAppendedPath(Profile.CONTENT_URI, CONTENT_DIRECTORY); + + /** + * @see android.provider.SyncStateContract.Helpers#get + */ + public static byte[] get(ContentProviderClient provider, Account account) + throws RemoteException { + return SyncStateContract.Helpers.get(provider, CONTENT_URI, account); + } + + /** + * @see android.provider.SyncStateContract.Helpers#get + */ + public static Pair<Uri, byte[]> getWithUri(ContentProviderClient provider, Account account) + throws RemoteException { + return SyncStateContract.Helpers.getWithUri(provider, CONTENT_URI, account); + } + + /** + * @see android.provider.SyncStateContract.Helpers#set + */ + public static void set(ContentProviderClient provider, Account account, byte[] data) + throws RemoteException { + SyncStateContract.Helpers.set(provider, CONTENT_URI, account, data); + } + + /** + * @see android.provider.SyncStateContract.Helpers#newSetOperation + */ + public static ContentProviderOperation newSetOperation(Account account, byte[] data) { + return SyncStateContract.Helpers.newSetOperation(CONTENT_URI, account, data); + } + } + /** * Generic columns for use by sync adapters. The specific functions of * these columns are private to the sync adapter. Other clients of the API @@ -1875,8 +1916,8 @@ public final class ContactsContract { * Constants for the user's profile data, which is represented as a single contact on * the device that represents the user. The profile contact is not aggregated * together automatically in the same way that normal contacts are; instead, each - * account on the device may contribute a single raw contact representing the user's - * personal profile data from that source. + * account (including data set, if applicable) on the device may contribute a single + * raw contact representing the user's personal profile data from that source. * </p> * <p> * Access to the profile entry through these URIs (or incidental access to parts of @@ -1950,6 +1991,31 @@ public final class ContactsContract { */ public static final Uri CONTENT_RAW_CONTACTS_URI = Uri.withAppendedPath(CONTENT_URI, "raw_contacts"); + + /** + * The minimum ID for any entity that belongs to the profile. This essentially + * defines an ID-space in which profile data is stored, and is used by the provider + * to determine whether a request via a non-profile-specific URI should be directed + * to the profile data rather than general contacts data, along with all the special + * permission checks that entails. + * + * Callers may use {@link #isProfileId} to check whether a specific ID falls into + * the set of data intended for the profile. + */ + public static final long MIN_ID = Long.MAX_VALUE - (long) Integer.MAX_VALUE; + } + + /** + * This method can be used to identify whether the given ID is associated with profile + * data. It does not necessarily indicate that the ID is tied to valid data, merely + * that accessing data using this ID will result in profile access checks and will only + * return data from the profile. + * + * @param id The ID to check. + * @return Whether the ID is associated with profile data. + */ + public static boolean isProfileId(long id) { + return id >= Profile.MIN_ID; } protected interface RawContactsColumns { @@ -3083,12 +3149,25 @@ public final class ContactsContract { /** * A reference to the {@link android.provider.ContactsContract.Contacts#_ID} * that this stream item belongs to. + * + * <p>Type: INTEGER</p> + * <p>read-only</p> */ public static final String CONTACT_ID = "contact_id"; /** + * A reference to the {@link android.provider.ContactsContract.Contacts#LOOKUP_KEY} + * that this stream item belongs to. + * + * <p>Type: TEXT</p> + * <p>read-only</p> + */ + public static final String CONTACT_LOOKUP_KEY = "contact_lookup"; + + /** * A reference to the {@link RawContacts#_ID} * that this stream item belongs to. + * <p>Type: INTEGER</p> */ public static final String RAW_CONTACT_ID = "raw_contact_id"; @@ -3104,7 +3183,7 @@ public final class ContactsContract { * The account type to which the raw_contact of this item is associated. See * {@link RawContacts#ACCOUNT_TYPE} * - * <p>TYPE: text</p> + * <p>Type: TEXT</p> * <p>read-only</p> */ public static final String ACCOUNT_TYPE = "account_type"; @@ -3113,7 +3192,7 @@ public final class ContactsContract { * The account name to which the raw_contact of this item is associated. See * {@link RawContacts#ACCOUNT_NAME} * - * <p>TYPE: text</p> + * <p>Type: TEXT</p> * <p>read-only</p> */ public static final String ACCOUNT_NAME = "account_name"; @@ -4529,6 +4608,12 @@ public final class ContactsContract { * either. * </p> * <p> + * Inserting or updating a status update for the user's profile requires either using + * the {@link #DATA_ID} to identify the data row to attach the update to, or + * {@link StatusUpdates#PROFILE_CONTENT_URI} to ensure that the change is scoped to the + * profile. + * </p> + * <p> * You cannot use {@link ContentResolver#update} to change a status, but * {@link ContentResolver#insert} will replace the latests status if it already * exists. @@ -4674,6 +4759,12 @@ public final class ContactsContract { public static final Uri CONTENT_URI = Uri.withAppendedPath(AUTHORITY_URI, "status_updates"); /** + * The content:// style URI for this table, specific to the user's profile. + */ + public static final Uri PROFILE_CONTENT_URI = + Uri.withAppendedPath(Profile.CONTENT_URI, "status_updates"); + + /** * Gets the resource ID for the proper presence icon. * * @param status the status to get the icon for diff --git a/core/java/android/server/BluetoothService.java b/core/java/android/server/BluetoothService.java index e942969e1372..55a06246a3b4 100755 --- a/core/java/android/server/BluetoothService.java +++ b/core/java/android/server/BluetoothService.java @@ -117,6 +117,7 @@ public class BluetoothService extends IBluetooth.Stub { private static final int MESSAGE_UUID_INTENT = 1; private static final int MESSAGE_AUTO_PAIRING_FAILURE_ATTEMPT_DELAY = 2; + private static final int MESSAGE_REMOVE_SERVICE_RECORD = 3; private static final int RFCOMM_RECORD_REAPER = 10; private static final int STATE_CHANGE_REAPER = 11; @@ -537,6 +538,10 @@ public class BluetoothService extends IBluetooth.Stub { } if (attempt > 0) mBondState.clearPinAttempts(address); break; + case MESSAGE_REMOVE_SERVICE_RECORD: + Pair<Integer, Integer> pair = (Pair<Integer, Integer>) msg.obj; + checkAndRemoveRecord(pair.first, pair.second); + break; } } }; @@ -1542,7 +1547,9 @@ public class BluetoothService extends IBluetooth.Stub { public void removeServiceRecord(int handle) { mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); - checkAndRemoveRecord(handle, Binder.getCallingPid()); + Message message = mHandler.obtainMessage(MESSAGE_REMOVE_SERVICE_RECORD); + message.obj = new Pair<Integer, Integer>(handle, Binder.getCallingPid()); + mHandler.sendMessage(message); } private synchronized void checkAndRemoveRecord(int handle, int pid) { diff --git a/core/java/android/service/wallpaper/WallpaperService.java b/core/java/android/service/wallpaper/WallpaperService.java index 4c563ce99e9b..39f9367097c2 100644 --- a/core/java/android/service/wallpaper/WallpaperService.java +++ b/core/java/android/service/wallpaper/WallpaperService.java @@ -139,6 +139,7 @@ public abstract class WallpaperService extends Service { boolean mSurfaceCreated; boolean mIsCreating; boolean mDrawingAllowed; + boolean mOffsetsChanged; int mWidth; int mHeight; int mFormat; @@ -604,12 +605,15 @@ public abstract class WallpaperService extends Service { if (DEBUG) Log.v(TAG, "Layout: Surface destroyed"); return; } - + + boolean didSurface = false; + try { mSurfaceHolder.ungetCallbacks(); if (surfaceCreating) { mIsCreating = true; + didSurface = true; if (DEBUG) Log.v(TAG, "onSurfaceCreated(" + mSurfaceHolder + "): " + this); onSurfaceCreated(mSurfaceHolder); @@ -637,6 +641,7 @@ public abstract class WallpaperService extends Service { + mSurfaceHolder + ", " + mFormat + ", " + mCurWidth + ", " + mCurHeight + "): " + this); + didSurface = true; onSurfaceChanged(mSurfaceHolder, mFormat, mCurWidth, mCurHeight); SurfaceHolder.Callback callbacks[] = mSurfaceHolder.getCallbacks(); @@ -661,6 +666,26 @@ public abstract class WallpaperService extends Service { } } + if (didSurface && !mReportedVisible) { + // This wallpaper is currently invisible, but its + // surface has changed. At this point let's tell it + // again that it is invisible in case the report about + // the surface caused it to start running. We really + // don't want wallpapers running when not visible. + if (mIsCreating) { + // Some wallpapers will ignore this call if they + // had previously been told they were invisble, + // so if we are creating a new surface then toggle + // the state to get them to notice. + if (DEBUG) Log.v(TAG, "onVisibilityChanged(true) at surface: " + + this); + onVisibilityChanged(true); + } + if (DEBUG) Log.v(TAG, "onVisibilityChanged(false) at surface: " + + this); + onVisibilityChanged(false); + } + } finally { mIsCreating = false; mSurfaceCreated = true; @@ -701,6 +726,7 @@ public abstract class WallpaperService extends Service { onCreate(mSurfaceHolder); mInitializing = false; + mReportedVisible = false; updateSurface(false, false, false); } @@ -711,7 +737,7 @@ public abstract class WallpaperService extends Service { mIWallpaperEngine.mReqWidth = desiredWidth; mIWallpaperEngine.mReqHeight = desiredHeight; onDesiredSizeChanged(desiredWidth, desiredHeight); - doOffsetsChanged(); + doOffsetsChanged(true); } } @@ -733,6 +759,7 @@ public abstract class WallpaperService extends Service { // If becoming visible, in preview mode the surface // may have been destroyed so now we need to make // sure it is re-created. + doOffsetsChanged(false); updateSurface(false, false, false); } onVisibilityChanged(visible); @@ -740,11 +767,15 @@ public abstract class WallpaperService extends Service { } } - void doOffsetsChanged() { + void doOffsetsChanged(boolean always) { if (mDestroyed) { return; } - + + if (!always && !mOffsetsChanged) { + return; + } + float xOffset; float yOffset; float xOffsetStep; @@ -759,15 +790,19 @@ public abstract class WallpaperService extends Service { mPendingSync = false; mOffsetMessageEnqueued = false; } - + if (mSurfaceCreated) { - if (DEBUG) Log.v(TAG, "Offsets change in " + this - + ": " + xOffset + "," + yOffset); - final int availw = mIWallpaperEngine.mReqWidth-mCurWidth; - final int xPixels = availw > 0 ? -(int)(availw*xOffset+.5f) : 0; - final int availh = mIWallpaperEngine.mReqHeight-mCurHeight; - final int yPixels = availh > 0 ? -(int)(availh*yOffset+.5f) : 0; - onOffsetsChanged(xOffset, yOffset, xOffsetStep, yOffsetStep, xPixels, yPixels); + if (mReportedVisible) { + if (DEBUG) Log.v(TAG, "Offsets change in " + this + + ": " + xOffset + "," + yOffset); + final int availw = mIWallpaperEngine.mReqWidth-mCurWidth; + final int xPixels = availw > 0 ? -(int)(availw*xOffset+.5f) : 0; + final int availh = mIWallpaperEngine.mReqHeight-mCurHeight; + final int yPixels = availh > 0 ? -(int)(availh*yOffset+.5f) : 0; + onOffsetsChanged(xOffset, yOffset, xOffsetStep, yOffsetStep, xPixels, yPixels); + } else { + mOffsetsChanged = true; + } } if (sync) { @@ -953,7 +988,7 @@ public abstract class WallpaperService extends Service { mEngine.doVisibilityChanged(message.arg1 != 0); break; case MSG_WALLPAPER_OFFSETS: { - mEngine.doOffsetsChanged(); + mEngine.doOffsetsChanged(true); } break; case MSG_WALLPAPER_COMMAND: { WallpaperCommand cmd = (WallpaperCommand)message.obj; @@ -962,7 +997,7 @@ public abstract class WallpaperService extends Service { case MSG_WINDOW_RESIZED: { final boolean reportDraw = message.arg1 != 0; mEngine.updateSurface(true, false, reportDraw); - mEngine.doOffsetsChanged(); + mEngine.doOffsetsChanged(true); } break; case MSG_TOUCH_EVENT: { boolean skip = false; diff --git a/core/java/android/speech/tts/AudioPlaybackHandler.java b/core/java/android/speech/tts/AudioPlaybackHandler.java index 89b6f321e756..f8d014232ba8 100644 --- a/core/java/android/speech/tts/AudioPlaybackHandler.java +++ b/core/java/android/speech/tts/AudioPlaybackHandler.java @@ -390,10 +390,10 @@ class AudioPlaybackHandler { audioTrack.play(); } int count = 0; - while (count < bufferCopy.mLength) { + while (count < bufferCopy.mBytes.length) { // Note that we don't take bufferCopy.mOffset into account because // it is guaranteed to be 0. - int written = audioTrack.write(bufferCopy.mBytes, count, bufferCopy.mLength); + int written = audioTrack.write(bufferCopy.mBytes, count, bufferCopy.mBytes.length); if (written <= 0) { break; } @@ -453,7 +453,7 @@ class AudioPlaybackHandler { } final AudioTrack audioTrack = params.mAudioTrack; - final int bytesPerFrame = getBytesPerFrame(params.mAudioFormat); + final int bytesPerFrame = params.mBytesPerFrame; final int lengthInBytes = params.mBytesWritten; final int lengthInFrames = lengthInBytes / bytesPerFrame; @@ -511,16 +511,6 @@ class AudioPlaybackHandler { return 0; } - static int getBytesPerFrame(int audioFormat) { - if (audioFormat == AudioFormat.ENCODING_PCM_8BIT) { - return 1; - } else if (audioFormat == AudioFormat.ENCODING_PCM_16BIT) { - return 2; - } - - return -1; - } - private static void setupVolume(AudioTrack audioTrack, float volume, float pan) { float vol = clip(volume, 0.0f, 1.0f); float panning = clip(pan, -1.0f, 1.0f); diff --git a/core/java/android/speech/tts/PlaybackSynthesisCallback.java b/core/java/android/speech/tts/PlaybackSynthesisCallback.java index 7dbf1acdaf1f..0cca06accd1f 100644 --- a/core/java/android/speech/tts/PlaybackSynthesisCallback.java +++ b/core/java/android/speech/tts/PlaybackSynthesisCallback.java @@ -85,6 +85,7 @@ class PlaybackSynthesisCallback extends AbstractSynthesisCallback { // Note that mLogger.mError might be true too at this point. mLogger.onStopped(); + SynthesisMessageParams token = null; synchronized (mStateLock) { if (mStopped) { Log.w(TAG, "stop() called twice"); @@ -97,9 +98,19 @@ class PlaybackSynthesisCallback extends AbstractSynthesisCallback { // In all other cases, mAudioTrackHandler.stop() will // result in onComplete being called. mLogger.onWriteData(); + } else { + token = mToken; } mStopped = true; } + + if (token != null) { + // This might result in the synthesis thread being woken up, at which + // point it will write an additional buffer to the token - but we + // won't worry about that because the audio playback queue will be cleared + // soon after (see SynthHandler#stop(String). + token.clearBuffers(); + } } @Override @@ -155,18 +166,22 @@ class PlaybackSynthesisCallback extends AbstractSynthesisCallback { + length + " bytes)"); } + SynthesisMessageParams token = null; synchronized (mStateLock) { if (mToken == null || mStopped) { return TextToSpeech.ERROR; } - - // Sigh, another copy. - final byte[] bufferCopy = new byte[length]; - System.arraycopy(buffer, offset, bufferCopy, 0, length); - mToken.addBuffer(bufferCopy); - mAudioTrackHandler.enqueueSynthesisDataAvailable(mToken); + token = mToken; } + // Sigh, another copy. + final byte[] bufferCopy = new byte[length]; + System.arraycopy(buffer, offset, bufferCopy, 0, length); + // Might block on mToken.this, if there are too many buffers waiting to + // be consumed. + token.addBuffer(bufferCopy); + mAudioTrackHandler.enqueueSynthesisDataAvailable(token); + mLogger.onEngineDataReceived(); return TextToSpeech.SUCCESS; @@ -176,6 +191,7 @@ class PlaybackSynthesisCallback extends AbstractSynthesisCallback { public int done() { if (DBG) Log.d(TAG, "done()"); + SynthesisMessageParams token = null; synchronized (mStateLock) { if (mDone) { Log.w(TAG, "Duplicate call to done()"); @@ -188,9 +204,12 @@ class PlaybackSynthesisCallback extends AbstractSynthesisCallback { return TextToSpeech.ERROR; } - mAudioTrackHandler.enqueueSynthesisDone(mToken); - mLogger.onEngineComplete(); + token = mToken; } + + mAudioTrackHandler.enqueueSynthesisDone(token); + mLogger.onEngineComplete(); + return TextToSpeech.SUCCESS; } diff --git a/core/java/android/speech/tts/SynthesisMessageParams.java b/core/java/android/speech/tts/SynthesisMessageParams.java index 7da5daabdb6d..3e905d6cc5dd 100644 --- a/core/java/android/speech/tts/SynthesisMessageParams.java +++ b/core/java/android/speech/tts/SynthesisMessageParams.java @@ -15,6 +15,7 @@ */ package android.speech.tts; +import android.media.AudioFormat; import android.media.AudioTrack; import android.speech.tts.TextToSpeechService.UtteranceCompletedDispatcher; @@ -24,6 +25,8 @@ import java.util.LinkedList; * Params required to play back a synthesis request. */ final class SynthesisMessageParams extends MessageParams { + private static final long MAX_UNCONSUMED_AUDIO_MS = 500; + final int mStreamType; final int mSampleRateInHz; final int mAudioFormat; @@ -32,10 +35,16 @@ final class SynthesisMessageParams extends MessageParams { final float mPan; final EventLogger mLogger; + final int mBytesPerFrame; + volatile AudioTrack mAudioTrack; - // Not volatile, accessed only from the synthesis thread. - int mBytesWritten; + // Written by the synthesis thread, but read on the audio playback + // thread. + volatile int mBytesWritten; + // Not volatile, accessed only from the audio playback thread. int mAudioBufferSize; + // Always synchronized on "this". + int mUnconsumedBytes; private final LinkedList<ListEntry> mDataBufferList = new LinkedList<ListEntry>(); @@ -53,6 +62,8 @@ final class SynthesisMessageParams extends MessageParams { mPan = pan; mLogger = logger; + mBytesPerFrame = getBytesPerFrame(mAudioFormat) * mChannelCount; + // initially null. mAudioTrack = null; mBytesWritten = 0; @@ -64,18 +75,36 @@ final class SynthesisMessageParams extends MessageParams { return TYPE_SYNTHESIS; } - synchronized void addBuffer(byte[] buffer, int offset, int length) { - mDataBufferList.add(new ListEntry(buffer, offset, length)); + synchronized void addBuffer(byte[] buffer) { + long unconsumedAudioMs = 0; + + while ((unconsumedAudioMs = getUnconsumedAudioLengthMs()) > MAX_UNCONSUMED_AUDIO_MS) { + try { + wait(); + } catch (InterruptedException ie) { + return; + } + } + + mDataBufferList.add(new ListEntry(buffer)); + mUnconsumedBytes += buffer.length; } - synchronized void addBuffer(byte[] buffer) { - mDataBufferList.add(new ListEntry(buffer, 0, buffer.length)); + synchronized void clearBuffers() { + mDataBufferList.clear(); + mUnconsumedBytes = 0; + notifyAll(); } synchronized ListEntry getNextBuffer() { - return mDataBufferList.poll(); - } + ListEntry entry = mDataBufferList.poll(); + if (entry != null) { + mUnconsumedBytes -= entry.mBytes.length; + notifyAll(); + } + return entry; + } void setAudioTrack(AudioTrack audioTrack) { mAudioTrack = audioTrack; @@ -85,15 +114,29 @@ final class SynthesisMessageParams extends MessageParams { return mAudioTrack; } + // Must be called synchronized on this. + private long getUnconsumedAudioLengthMs() { + final int unconsumedFrames = mUnconsumedBytes / mBytesPerFrame; + final long estimatedTimeMs = unconsumedFrames * 1000 / mSampleRateInHz; + + return estimatedTimeMs; + } + + private static int getBytesPerFrame(int audioFormat) { + if (audioFormat == AudioFormat.ENCODING_PCM_8BIT) { + return 1; + } else if (audioFormat == AudioFormat.ENCODING_PCM_16BIT) { + return 2; + } + + return -1; + } + static final class ListEntry { final byte[] mBytes; - final int mOffset; - final int mLength; - ListEntry(byte[] bytes, int offset, int length) { + ListEntry(byte[] bytes) { mBytes = bytes; - mOffset = offset; - mLength = length; } } } diff --git a/core/java/android/text/StaticLayout.java b/core/java/android/text/StaticLayout.java index 788711d9ea88..e8b2045ef828 100644 --- a/core/java/android/text/StaticLayout.java +++ b/core/java/android/text/StaticLayout.java @@ -729,12 +729,22 @@ public class StaticLayout extends Layout { start - widthStart, end - start); } - // If ellipsize is in marquee mode, do not apply ellipsis on the first line - if (ellipsize != null && (ellipsize != TextUtils.TruncateAt.MARQUEE || j != 0)) { + if (ellipsize != null) { + // If there is only one line, then do any type of ellipsis except when it is MARQUEE + // if there are multiple lines, just allow END ellipsis on the last line + boolean firstLine = (j == 0); + boolean currentLineIsTheLastVisibleOne = (j + 1 == mMaximumVisibleLineCount); boolean forceEllipsis = moreChars && (mLineCount + 1 == mMaximumVisibleLineCount); - calculateEllipsis(start, end, widths, widthStart, - ellipsisWidth, ellipsize, j, - textWidth, paint, forceEllipsis); + + boolean doEllipsis = (firstLine && !moreChars && + ellipsize != TextUtils.TruncateAt.MARQUEE) || + (!firstLine && (currentLineIsTheLastVisibleOne || !moreChars) && + ellipsize == TextUtils.TruncateAt.END); + if (doEllipsis) { + calculateEllipsis(start, end, widths, widthStart, + ellipsisWidth, ellipsize, j, + textWidth, paint, forceEllipsis); + } } mLineCount++; @@ -797,8 +807,8 @@ public class StaticLayout extends Layout { ellipsisStart = i; ellipsisCount = len - i; - if (forceEllipsis && ellipsisCount == 0 && i > 0) { - ellipsisStart = i - 1; + if (forceEllipsis && ellipsisCount == 0 && len > 0) { + ellipsisStart = len - 1; ellipsisCount = 1; } } else { diff --git a/core/java/android/text/TextLine.java b/core/java/android/text/TextLine.java index fcc372e36dfd..68a6b3e7823e 100644 --- a/core/java/android/text/TextLine.java +++ b/core/java/android/text/TextLine.java @@ -723,7 +723,7 @@ class TextLine { float ret = 0; int contextLen = contextEnd - contextStart; - if (needWidth || (c != null && (wp.bgColor != 0 || wp.underlineColor !=0 || runIsRtl))) { + if (needWidth || (c != null && (wp.bgColor != 0 || wp.underlineCount != 0 || runIsRtl))) { int flags = runIsRtl ? Paint.DIRECTION_RTL : Paint.DIRECTION_LTR; if (mCharsValid) { ret = wp.getTextRunAdvances(mChars, start, runLen, @@ -753,21 +753,26 @@ class TextLine { wp.setColor(previousColor); } - if (wp.underlineColor != 0) { + if (wp.underlineCount != 0) { // kStdUnderline_Offset = 1/9, defined in SkTextFormatParams.h - float middle = y + wp.baselineShift + (1.0f / 9.0f) * wp.getTextSize(); - // kStdUnderline_Thickness = 1/18, defined in SkTextFormatParams.h - float halfHeight = wp.underlineThickness * (1.0f / 18.0f / 2.0f) * wp.getTextSize(); + float underlineTop = y + wp.baselineShift + (1.0f / 9.0f) * wp.getTextSize(); int previousColor = wp.getColor(); Paint.Style previousStyle = wp.getStyle(); + boolean previousAntiAlias = wp.isAntiAlias(); - wp.setColor(wp.underlineColor); wp.setStyle(Paint.Style.FILL); - c.drawRect(x, middle - halfHeight, x + ret, middle + halfHeight, wp); + wp.setAntiAlias(true); + + for (int i = 0; i < wp.underlineCount; i++) { + wp.setColor(wp.underlineColors[i]); + c.drawRect(x, underlineTop, x + ret, underlineTop + wp.underlineThicknesses[i], + wp); + } wp.setStyle(previousStyle); wp.setColor(previousColor); + wp.setAntiAlias(previousAntiAlias); } drawTextRun(c, wp, start, end, contextStart, contextEnd, runIsRtl, diff --git a/core/java/android/text/TextPaint.java b/core/java/android/text/TextPaint.java index de57dfabdb5b..625d8693dbde 100644 --- a/core/java/android/text/TextPaint.java +++ b/core/java/android/text/TextPaint.java @@ -23,6 +23,9 @@ import android.graphics.Paint; * data used during text measuring and drawing. */ public class TextPaint extends Paint { + + private static final int DEFAULT_UNDERLINE_SIZE = 3; + // Special value 0 means no background paint public int bgColor; public int baselineShift; @@ -33,12 +36,17 @@ public class TextPaint extends Paint { * Special value 0 means no custom underline * @hide */ - public int underlineColor; + public int[] underlineColors; /** * Defined as a multiplier of the default underline thickness. Use 1.0f for default thickness. * @hide */ - public float underlineThickness; + public float[] underlineThicknesses; + /** + * The number of underlines currently stored in the array. If 0, no underline is drawn. + * @hide + */ + public int underlineCount; public TextPaint() { super(); @@ -64,24 +72,43 @@ public class TextPaint extends Paint { linkColor = tp.linkColor; drawableState = tp.drawableState; density = tp.density; - underlineColor = tp.underlineColor; - underlineThickness = tp.underlineThickness; + underlineColors = tp.underlineColors; + underlineThicknesses = tp.underlineThicknesses; + underlineCount = tp.underlineCount; } /** * Defines a custom underline for this Paint. * @param color underline solid color - * @param thickness underline thickness, defined as a multiplier of the default underline - * thickness. + * @param thickness underline thickness * @hide */ - public void setUnderlineText(boolean isUnderlined, int color, float thickness) { - setUnderlineText(false); - if (isUnderlined) { - underlineColor = color; - underlineThickness = thickness; + public void setUnderlineText(int color, float thickness) { + if (color == 0) { + // No underline + return; + } + + if (underlineCount == 0) { + underlineColors = new int[DEFAULT_UNDERLINE_SIZE]; + underlineThicknesses = new float[DEFAULT_UNDERLINE_SIZE]; + underlineColors[underlineCount] = color; + underlineThicknesses[underlineCount] = thickness; + underlineCount++; } else { - underlineColor = 0; + if (underlineCount == underlineColors.length) { + int[] newColors = new int[underlineColors.length + DEFAULT_UNDERLINE_SIZE]; + float[] newThickness = new float[underlineThicknesses.length + + DEFAULT_UNDERLINE_SIZE]; + System.arraycopy(underlineColors, 0, newColors, 0, underlineColors.length); + System.arraycopy( + underlineThicknesses, 0, newThickness, 0, underlineThicknesses.length); + underlineColors = newColors; + underlineThicknesses = newThickness; + } + underlineColors[underlineCount] = color; + underlineThicknesses[underlineCount] = thickness; + underlineCount++; } } } diff --git a/core/java/android/text/TextUtils.java b/core/java/android/text/TextUtils.java index b8b54f47bd98..e91431689776 100644 --- a/core/java/android/text/TextUtils.java +++ b/core/java/android/text/TextUtils.java @@ -25,6 +25,7 @@ import android.text.style.BackgroundColorSpan; import android.text.style.BulletSpan; import android.text.style.CharacterStyle; import android.text.style.ForegroundColorSpan; +import android.text.style.EasyEditSpan; import android.text.style.LeadingMarginSpan; import android.text.style.MetricAffectingSpan; import android.text.style.QuoteSpan; @@ -585,6 +586,8 @@ public class TextUtils { public static final int SPELL_CHECK_SPAN = 20; /** @hide */ public static final int SUGGESTION_RANGE_SPAN = 21; + /** @hide */ + public static final int EASY_EDIT_SPAN = 22; /** * Flatten a CharSequence and whatever styles can be copied across processes @@ -748,6 +751,10 @@ public class TextUtils { readSpan(p, sp, new SuggestionRangeSpan()); break; + case EASY_EDIT_SPAN: + readSpan(p, sp, new EasyEditSpan(p)); + break; + default: throw new RuntimeException("bogus span encoding " + kind); } diff --git a/core/java/android/text/style/EasyEditSpan.java b/core/java/android/text/style/EasyEditSpan.java new file mode 100644 index 000000000000..e6e4d2c89959 --- /dev/null +++ b/core/java/android/text/style/EasyEditSpan.java @@ -0,0 +1,54 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.text.style; + +import android.os.Parcel; +import android.text.ParcelableSpan; +import android.text.TextUtils; +import android.widget.TextView; + +/** + * Provides an easy way to edit a portion of text. + * <p> + * The {@link TextView} uses this span to allow the user to delete a chuck of text in one click. + * the text. {@link TextView} removes this span as soon as the text is edited, or the cursor moves. + */ +public class EasyEditSpan implements ParcelableSpan { + + public EasyEditSpan() { + // Empty + } + + public EasyEditSpan(Parcel src) { + this(); + } + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(Parcel dest, int flags) { + // Empty + } + + @Override + public int getSpanTypeId() { + return TextUtils.EASY_EDIT_SPAN; + } +} diff --git a/core/java/android/text/style/SuggestionSpan.java b/core/java/android/text/style/SuggestionSpan.java index ea57f917fc1a..86252578db79 100644 --- a/core/java/android/text/style/SuggestionSpan.java +++ b/core/java/android/text/style/SuggestionSpan.java @@ -61,12 +61,6 @@ public class SuggestionSpan extends CharacterStyle implements ParcelableSpan { public static final String SUGGESTION_SPAN_PICKED_BEFORE = "before"; public static final String SUGGESTION_SPAN_PICKED_HASHCODE = "hashcode"; - /** - * The default underline thickness as a percentage of the system's default underline thickness - * (i.e., 100 means the default thickness, and 200 is a double thickness). - */ - private static final int DEFAULT_UNDERLINE_PERCENTAGE = 100; - public static final int SUGGESTIONS_MAX_SIZE = 5; /* @@ -82,10 +76,8 @@ public class SuggestionSpan extends CharacterStyle implements ParcelableSpan { private final String mNotificationTargetClassName; private final int mHashCode; - private float mMisspelledUnderlineThickness; - private int mMisspelledUnderlineColor; - private float mEasyCorrectUnderlineThickness; - private int mEasyCorrectUnderlineColor; + private float mUnderlineThickness; + private int mUnderlineColor; /* * TODO: If switching IME is required, needs to add parameters for ids of InputMethodInfo @@ -140,31 +132,26 @@ public class SuggestionSpan extends CharacterStyle implements ParcelableSpan { } private void initStyle(Context context) { - // Read the colors. We need to store the color and the underline thickness, as the span - // does not have access to the context when it is read from a parcel. - TypedArray typedArray; + int defStyle = 0; + if ((getFlags() & FLAG_MISSPELLED) != 0) { + defStyle = com.android.internal.R.attr.textAppearanceMisspelledSuggestion; + } else if ((getFlags() & FLAG_EASY_CORRECT) != 0) { + defStyle = com.android.internal.R.attr.textAppearanceEasyCorrectSuggestion; + } else { + // No style is applied. + mUnderlineThickness = 0; + mUnderlineColor = 0; + return; + } - typedArray = context.obtainStyledAttributes(null, + TypedArray typedArray = context.obtainStyledAttributes(null, com.android.internal.R.styleable.SuggestionSpan, - com.android.internal.R.attr.textAppearanceEasyCorrectSuggestion, 0); + defStyle, 0); - mEasyCorrectUnderlineThickness = getThicknessPercentage(typedArray, - com.android.internal.R.styleable.SuggestionSpan_textUnderlineThicknessPercentage); - mEasyCorrectUnderlineColor = typedArray.getColor( + mUnderlineThickness = typedArray.getDimension( + com.android.internal.R.styleable.SuggestionSpan_textUnderlineThickness, 0); + mUnderlineColor = typedArray.getColor( com.android.internal.R.styleable.SuggestionSpan_textUnderlineColor, Color.BLACK); - - typedArray = context.obtainStyledAttributes(null, - com.android.internal.R.styleable.SuggestionSpan, - com.android.internal.R.attr.textAppearanceMisspelledSuggestion, 0); - mMisspelledUnderlineThickness = getThicknessPercentage(typedArray, - com.android.internal.R.styleable.SuggestionSpan_textUnderlineThicknessPercentage); - mMisspelledUnderlineColor = typedArray.getColor( - com.android.internal.R.styleable.SuggestionSpan_textUnderlineColor, Color.BLACK); - } - - private static float getThicknessPercentage(TypedArray typedArray, int index) { - int value = typedArray.getInteger(index, DEFAULT_UNDERLINE_PERCENTAGE); - return value / 100.0f; } public SuggestionSpan(Parcel src) { @@ -173,10 +160,8 @@ public class SuggestionSpan extends CharacterStyle implements ParcelableSpan { mLocaleString = src.readString(); mNotificationTargetClassName = src.readString(); mHashCode = src.readInt(); - mEasyCorrectUnderlineColor = src.readInt(); - mEasyCorrectUnderlineThickness = src.readFloat(); - mMisspelledUnderlineColor = src.readInt(); - mMisspelledUnderlineThickness = src.readFloat(); + mUnderlineColor = src.readInt(); + mUnderlineThickness = src.readFloat(); } /** @@ -226,10 +211,8 @@ public class SuggestionSpan extends CharacterStyle implements ParcelableSpan { dest.writeString(mLocaleString); dest.writeString(mNotificationTargetClassName); dest.writeInt(mHashCode); - dest.writeInt(mEasyCorrectUnderlineColor); - dest.writeFloat(mEasyCorrectUnderlineThickness); - dest.writeInt(mMisspelledUnderlineColor); - dest.writeFloat(mMisspelledUnderlineThickness); + dest.writeInt(mUnderlineColor); + dest.writeFloat(mUnderlineThickness); } @Override @@ -271,10 +254,6 @@ public class SuggestionSpan extends CharacterStyle implements ParcelableSpan { @Override public void updateDrawState(TextPaint tp) { - if ((getFlags() & FLAG_MISSPELLED) != 0) { - tp.setUnderlineText(true, mMisspelledUnderlineColor, mMisspelledUnderlineThickness); - } else if ((getFlags() & FLAG_EASY_CORRECT) != 0) { - tp.setUnderlineText(true, mEasyCorrectUnderlineColor, mEasyCorrectUnderlineThickness); - } + tp.setUnderlineText(mUnderlineColor, mUnderlineThickness); } } diff --git a/core/java/android/view/Surface.java b/core/java/android/view/Surface.java index 22e0f1e828a3..3880bc45b4f3 100644 --- a/core/java/android/view/Surface.java +++ b/core/java/android/view/Surface.java @@ -36,10 +36,14 @@ public class Surface implements Parcelable { public static final int ROTATION_270 = 3; /** - * Create Surface from a SurfaceTexture. + * Create Surface from a {@link SurfaceTexture}. * - * @param surfaceTexture The {@link SurfaceTexture} that is updated by this Surface. - * @hide + * Images drawn to the Surface will be made available to the {@link + * SurfaceTexture}, which can attach them an OpenGL ES texture via {@link + * SurfaceTexture#updateTexImage}. + * + * @param surfaceTexture The {@link SurfaceTexture} that is updated by this + * Surface. */ public Surface(SurfaceTexture surfaceTexture) { if (DEBUG_RELEASE) { diff --git a/core/java/android/webkit/HTML5VideoInline.java b/core/java/android/webkit/HTML5VideoInline.java index ef1906c1ea2c..1b9a25ec5982 100644 --- a/core/java/android/webkit/HTML5VideoInline.java +++ b/core/java/android/webkit/HTML5VideoInline.java @@ -5,6 +5,7 @@ import android.graphics.SurfaceTexture; import android.media.MediaPlayer; import android.webkit.HTML5VideoView; import android.webkit.HTML5VideoViewProxy; +import android.view.Surface; import android.opengl.GLES20; /** @@ -38,7 +39,10 @@ public class HTML5VideoInline extends HTML5VideoView{ @Override public void decideDisplayMode() { - mPlayer.setTexture(getSurfaceTexture(getVideoLayerId())); + SurfaceTexture surfaceTexture = getSurfaceTexture(getVideoLayerId()); + Surface surface = new Surface(surfaceTexture); + mPlayer.setSurface(surface); + surface.release(); } // Normally called immediately after setVideoURI. But for full screen, diff --git a/core/java/android/webkit/WebView.java b/core/java/android/webkit/WebView.java index 2aa481ce379a..47485222c4a6 100644 --- a/core/java/android/webkit/WebView.java +++ b/core/java/android/webkit/WebView.java @@ -9124,7 +9124,9 @@ public class WebView extends AbsoluteLayout /** @hide send content invalidate */ protected void contentInvalidateAll() { - mWebViewCore.sendMessage(EventHub.CONTENT_INVALIDATE_ALL); + if (mWebViewCore != null && !mBlockWebkitViewMessages) { + mWebViewCore.sendMessage(EventHub.CONTENT_INVALIDATE_ALL); + } } /** @hide call pageSwapCallback upon next page swap */ diff --git a/core/java/android/widget/SpellChecker.java b/core/java/android/widget/SpellChecker.java index ff13dcbf54f4..b89b8ec442c3 100644 --- a/core/java/android/widget/SpellChecker.java +++ b/core/java/android/widget/SpellChecker.java @@ -112,6 +112,8 @@ public class SpellChecker implements SpellCheckerSessionListener { private void scheduleSpellCheck() { if (mLength == 0) return; + if (spellCheckerSession == null) return; + if (mChecker != null) { mTextView.removeCallbacks(mChecker); } diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java index e9662aeb760e..4ce2d907ee3d 100644 --- a/core/java/android/widget/TextView.java +++ b/core/java/android/widget/TextView.java @@ -64,6 +64,7 @@ import android.text.TextDirectionHeuristics; import android.text.TextPaint; import android.text.TextUtils; import android.text.TextWatcher; +import android.text.TextUtils.TruncateAt; import android.text.method.AllCapsTransformationMethod; import android.text.method.ArrowKeyMovementMethod; import android.text.method.DateKeyListener; @@ -81,7 +82,9 @@ import android.text.method.TimeKeyListener; import android.text.method.TransformationMethod; import android.text.method.TransformationMethod2; import android.text.method.WordIterator; +import android.text.style.CharacterStyle; import android.text.style.ClickableSpan; +import android.text.style.EasyEditSpan; import android.text.style.ParagraphStyle; import android.text.style.SpellCheckSpan; import android.text.style.SuggestionRangeSpan; @@ -364,6 +367,35 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener private boolean mResolvedDrawables = false; + /** + * On some devices the fading edges add a performance penalty if used + * extensively in the same layout. This mode indicates how the marquee + * is currently being shown, if applicable. (mEllipsize will == MARQUEE) + */ + private int mMarqueeFadeMode = MARQUEE_FADE_NORMAL; + + /** + * When mMarqueeFadeMode is not MARQUEE_FADE_NORMAL, this stores + * the layout that should be used when the mode switches. + */ + private Layout mSavedMarqueeModeLayout; + + /** + * Draw marquee text with fading edges as usual + */ + private static final int MARQUEE_FADE_NORMAL = 0; + + /** + * Draw marquee text as ellipsize end while inactive instead of with the fade. + * (Useful for devices where the fade can be expensive if overdone) + */ + private static final int MARQUEE_FADE_SWITCH_SHOW_ELLIPSIS = 1; + + /** + * Draw marquee text with fading edges because it is currently active/animating. + */ + private static final int MARQUEE_FADE_SWITCH_SHOW_FADE = 2; + /* * Kick-start the font cache for the zygote process (to pay the cost of * initializing freetype for our default font only once). @@ -995,8 +1027,13 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener setEllipsize(TextUtils.TruncateAt.END); break; case 4: - setHorizontalFadingEdgeEnabled( - ViewConfiguration.get(context).isFadingMarqueeEnabled()); + if (ViewConfiguration.get(context).isFadingMarqueeEnabled()) { + setHorizontalFadingEdgeEnabled(true); + mMarqueeFadeMode = MARQUEE_FADE_NORMAL; + } else { + setHorizontalFadingEdgeEnabled(false); + mMarqueeFadeMode = MARQUEE_FADE_SWITCH_SHOW_ELLIPSIS; + } setEllipsize(TextUtils.TruncateAt.MARQUEE); break; } @@ -3067,8 +3104,13 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener if (text instanceof Spanned && ((Spanned) text).getSpanStart(TextUtils.TruncateAt.MARQUEE) >= 0) { - setHorizontalFadingEdgeEnabled( - ViewConfiguration.get(mContext).isFadingMarqueeEnabled()); + if (ViewConfiguration.get(mContext).isFadingMarqueeEnabled()) { + setHorizontalFadingEdgeEnabled(true); + mMarqueeFadeMode = MARQUEE_FADE_NORMAL; + } else { + setHorizontalFadingEdgeEnabled(false); + mMarqueeFadeMode = MARQUEE_FADE_SWITCH_SHOW_ELLIPSIS; + } setEllipsize(TextUtils.TruncateAt.MARQUEE); } @@ -4761,7 +4803,8 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener final int layoutDirection = getResolvedLayoutDirection(); final int absoluteGravity = Gravity.getAbsoluteGravity(mGravity, layoutDirection); - if (mEllipsize == TextUtils.TruncateAt.MARQUEE) { + if (mEllipsize == TextUtils.TruncateAt.MARQUEE && + mMarqueeFadeMode != MARQUEE_FADE_SWITCH_SHOW_ELLIPSIS) { if (!mSingleLine && getLineCount() == 1 && canMarquee() && (absoluteGravity & Gravity.HORIZONTAL_GRAVITY_MASK) != Gravity.LEFT) { canvas.translate(mLayout.getLineRight(0) - (mRight - mLeft - @@ -5945,7 +5988,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener mSavedHintLayout = (BoringLayout) mHintLayout; } - mLayout = mHintLayout = null; + mSavedMarqueeModeLayout = mLayout = mHintLayout = null; // Since it depends on the value of mLayout prepareCursorControllers(); @@ -6065,73 +6108,25 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener Layout.Alignment alignment = getLayoutAlignment(); boolean shouldEllipsize = mEllipsize != null && mInput == null; + final boolean switchEllipsize = mEllipsize == TruncateAt.MARQUEE && + mMarqueeFadeMode != MARQUEE_FADE_NORMAL; + TruncateAt effectiveEllipsize = mEllipsize; + if (mEllipsize == TruncateAt.MARQUEE && + mMarqueeFadeMode == MARQUEE_FADE_SWITCH_SHOW_ELLIPSIS) { + effectiveEllipsize = TruncateAt.END; + } if (mTextDir == null) { resolveTextDirection(); } - if (mText instanceof Spannable) { - mLayout = new DynamicLayout(mText, mTransformed, mTextPaint, w, - alignment, mTextDir, mSpacingMult, - mSpacingAdd, mIncludePad, mInput == null ? mEllipsize : null, - ellipsisWidth); - } else { - if (boring == UNKNOWN_BORING) { - boring = BoringLayout.isBoring(mTransformed, mTextPaint, mTextDir, mBoring); - if (boring != null) { - mBoring = boring; - } - } - - if (boring != null) { - if (boring.width <= w && - (mEllipsize == null || boring.width <= ellipsisWidth)) { - if (mSavedLayout != null) { - mLayout = mSavedLayout. - replaceOrMake(mTransformed, mTextPaint, - w, alignment, mSpacingMult, mSpacingAdd, - boring, mIncludePad); - } else { - mLayout = BoringLayout.make(mTransformed, mTextPaint, - w, alignment, mSpacingMult, mSpacingAdd, - boring, mIncludePad); - } - mSavedLayout = (BoringLayout) mLayout; - } else if (shouldEllipsize && boring.width <= w) { - if (mSavedLayout != null) { - mLayout = mSavedLayout. - replaceOrMake(mTransformed, mTextPaint, - w, alignment, mSpacingMult, mSpacingAdd, - boring, mIncludePad, mEllipsize, - ellipsisWidth); - } else { - mLayout = BoringLayout.make(mTransformed, mTextPaint, - w, alignment, mSpacingMult, mSpacingAdd, - boring, mIncludePad, mEllipsize, - ellipsisWidth); - } - } else if (shouldEllipsize) { - mLayout = new StaticLayout(mTransformed, - 0, mTransformed.length(), - mTextPaint, w, alignment, mTextDir, mSpacingMult, - mSpacingAdd, mIncludePad, mEllipsize, - ellipsisWidth, mMaxMode == LINES ? mMaximum : Integer.MAX_VALUE); - } else { - mLayout = new StaticLayout(mTransformed, mTextPaint, - w, alignment, mTextDir, mSpacingMult, mSpacingAdd, - mIncludePad); - } - } else if (shouldEllipsize) { - mLayout = new StaticLayout(mTransformed, - 0, mTransformed.length(), - mTextPaint, w, alignment, mTextDir, mSpacingMult, - mSpacingAdd, mIncludePad, mEllipsize, - ellipsisWidth, mMaxMode == LINES ? mMaximum : Integer.MAX_VALUE); - } else { - mLayout = new StaticLayout(mTransformed, mTextPaint, - w, alignment, mTextDir, mSpacingMult, mSpacingAdd, - mIncludePad); - } + mLayout = makeSingleLayout(w, boring, ellipsisWidth, alignment, shouldEllipsize, + effectiveEllipsize, effectiveEllipsize == mEllipsize); + if (switchEllipsize) { + TruncateAt oppositeEllipsize = effectiveEllipsize == TruncateAt.MARQUEE ? + TruncateAt.END : TruncateAt.MARQUEE; + mSavedMarqueeModeLayout = makeSingleLayout(w, boring, ellipsisWidth, alignment, + shouldEllipsize, oppositeEllipsize, effectiveEllipsize != mEllipsize); } shouldEllipsize = mEllipsize != null; @@ -6222,6 +6217,77 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener prepareCursorControllers(); } + private Layout makeSingleLayout(int w, BoringLayout.Metrics boring, int ellipsisWidth, + Layout.Alignment alignment, boolean shouldEllipsize, TruncateAt effectiveEllipsize, + boolean useSaved) { + Layout result = null; + if (mText instanceof Spannable) { + result = new DynamicLayout(mText, mTransformed, mTextPaint, w, + alignment, mTextDir, mSpacingMult, + mSpacingAdd, mIncludePad, mInput == null ? effectiveEllipsize : null, + ellipsisWidth); + } else { + if (boring == UNKNOWN_BORING) { + boring = BoringLayout.isBoring(mTransformed, mTextPaint, mTextDir, mBoring); + if (boring != null) { + mBoring = boring; + } + } + + if (boring != null) { + if (boring.width <= w && + (effectiveEllipsize == null || boring.width <= ellipsisWidth)) { + if (useSaved && mSavedLayout != null) { + result = mSavedLayout.replaceOrMake(mTransformed, mTextPaint, + w, alignment, mSpacingMult, mSpacingAdd, + boring, mIncludePad); + } else { + result = BoringLayout.make(mTransformed, mTextPaint, + w, alignment, mSpacingMult, mSpacingAdd, + boring, mIncludePad); + } + + if (useSaved) { + mSavedLayout = (BoringLayout) result; + } + } else if (shouldEllipsize && boring.width <= w) { + if (useSaved && mSavedLayout != null) { + result = mSavedLayout.replaceOrMake(mTransformed, mTextPaint, + w, alignment, mSpacingMult, mSpacingAdd, + boring, mIncludePad, effectiveEllipsize, + ellipsisWidth); + } else { + result = BoringLayout.make(mTransformed, mTextPaint, + w, alignment, mSpacingMult, mSpacingAdd, + boring, mIncludePad, effectiveEllipsize, + ellipsisWidth); + } + } else if (shouldEllipsize) { + result = new StaticLayout(mTransformed, + 0, mTransformed.length(), + mTextPaint, w, alignment, mTextDir, mSpacingMult, + mSpacingAdd, mIncludePad, effectiveEllipsize, + ellipsisWidth, mMaxMode == LINES ? mMaximum : Integer.MAX_VALUE); + } else { + result = new StaticLayout(mTransformed, mTextPaint, + w, alignment, mTextDir, mSpacingMult, mSpacingAdd, + mIncludePad); + } + } else if (shouldEllipsize) { + result = new StaticLayout(mTransformed, + 0, mTransformed.length(), + mTextPaint, w, alignment, mTextDir, mSpacingMult, + mSpacingAdd, mIncludePad, effectiveEllipsize, + ellipsisWidth, mMaxMode == LINES ? mMaximum : Integer.MAX_VALUE); + } else { + result = new StaticLayout(mTransformed, mTextPaint, + w, alignment, mTextDir, mSpacingMult, mSpacingAdd, + mIncludePad); + } + } + return result; + } + private boolean compressText(float width) { if (isHardwareAccelerated()) return false; @@ -7177,7 +7243,9 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener private boolean canMarquee() { int width = (mRight - mLeft - getCompoundPaddingLeft() - getCompoundPaddingRight()); - return width > 0 && mLayout.getLineWidth(0) > width; + return width > 0 && (mLayout.getLineWidth(0) > width || + (mMarqueeFadeMode != MARQUEE_FADE_NORMAL && mSavedMarqueeModeLayout != null && + mSavedMarqueeModeLayout.getLineWidth(0) > width)); } private void startMarquee() { @@ -7191,6 +7259,16 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener if ((mMarquee == null || mMarquee.isStopped()) && (isFocused() || isSelected()) && getLineCount() == 1 && canMarquee()) { + if (mMarqueeFadeMode == MARQUEE_FADE_SWITCH_SHOW_ELLIPSIS) { + mMarqueeFadeMode = MARQUEE_FADE_SWITCH_SHOW_FADE; + final Layout tmp = mLayout; + mLayout = mSavedMarqueeModeLayout; + mSavedMarqueeModeLayout = tmp; + setHorizontalFadingEdgeEnabled(true); + requestLayout(); + invalidate(); + } + if (mMarquee == null) mMarquee = new Marquee(this); mMarquee.start(mMarqueeRepeatLimit); } @@ -7200,6 +7278,16 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener if (mMarquee != null && !mMarquee.isStopped()) { mMarquee.stop(); } + + if (mMarqueeFadeMode == MARQUEE_FADE_SWITCH_SHOW_FADE) { + mMarqueeFadeMode = MARQUEE_FADE_SWITCH_SHOW_ELLIPSIS; + final Layout tmp = mSavedMarqueeModeLayout; + mSavedMarqueeModeLayout = mLayout; + mLayout = tmp; + setHorizontalFadingEdgeEnabled(false); + requestLayout(); + invalidate(); + } } private void startStopMarquee(boolean start) { @@ -7705,10 +7793,148 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener } } + /** + * Controls the {@link EasyEditSpan} monitoring when it is added, and when the related + * pop-up should be displayed. + */ + private class EditTextShortcutController { + + private EditTextShortcutPopupWindow mPopupWindow; + + private EasyEditSpan mEditTextShortcutSpan; + + private void hide() { + if (mEditTextShortcutSpan != null) { + mPopupWindow.hide(); + if (mText instanceof Spannable) { + ((Spannable) mText).removeSpan(mEditTextShortcutSpan); + } + mEditTextShortcutSpan = null; + } + } + + /** + * Monitors the changes in the text. + * + * <p>{@link ChangeWatcher#onSpanAdded(Spannable, Object, int, int)} cannot be used, + * as the notifications are not sent when a spannable (with spans) is inserted. + */ + public void onTextChange(CharSequence buffer) { + if (mEditTextShortcutSpan != null) { + hide(); + } + + if (buffer instanceof Spanned) { + mEditTextShortcutSpan = getSpan((Spanned) buffer); + if (mEditTextShortcutSpan != null) { + if (mPopupWindow == null) { + mPopupWindow = new EditTextShortcutPopupWindow(); + } + mPopupWindow.show(mEditTextShortcutSpan); + } + } + } + + private EasyEditSpan getSpan(Spanned spanned) { + EasyEditSpan[] inputMethodSpans = spanned.getSpans(0, spanned.length(), + EasyEditSpan.class); + + if (inputMethodSpans.length == 0) { + return null; + } else { + return inputMethodSpans[0]; + } + } + } + + /** + * Displays the actions associated to an {@link EasyEditSpan}. The pop-up is controlled + * by {@link EditTextShortcutController}. + */ + private class EditTextShortcutPopupWindow extends PinnedPopupWindow + implements OnClickListener { + private static final int POPUP_TEXT_LAYOUT = + com.android.internal.R.layout.text_edit_action_popup_text; + private TextView mDeleteTextView; + private EasyEditSpan mEditTextShortcutSpan; + + @Override + protected void createPopupWindow() { + mPopupWindow = new PopupWindow(TextView.this.mContext, null, + com.android.internal.R.attr.textSelectHandleWindowStyle); + mPopupWindow.setInputMethodMode(PopupWindow.INPUT_METHOD_NOT_NEEDED); + mPopupWindow.setClippingEnabled(true); + } + + @Override + protected void initContentView() { + mContentView.setOrientation(LinearLayout.HORIZONTAL); + mContentView.setBackgroundResource( + com.android.internal.R.drawable.text_edit_side_paste_window); + + LayoutInflater inflater = (LayoutInflater)TextView.this.mContext. + getSystemService(Context.LAYOUT_INFLATER_SERVICE); + + LayoutParams wrapContent = new LayoutParams( + ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT); + + mDeleteTextView = (TextView) inflater.inflate(POPUP_TEXT_LAYOUT, null); + mDeleteTextView.setLayoutParams(wrapContent); + mDeleteTextView.setText(com.android.internal.R.string.delete); + mDeleteTextView.setOnClickListener(this); + mContentView.addView(mDeleteTextView); + } + + public void show(EasyEditSpan inputMethodSpan) { + mEditTextShortcutSpan = inputMethodSpan; + super.show(); + } + + @Override + public void onClick(View view) { + if (view == mDeleteTextView) { + deleteText(); + } + } + + private void deleteText() { + Editable editable = (Editable) mText; + int start = editable.getSpanStart(mEditTextShortcutSpan); + int end = editable.getSpanEnd(mEditTextShortcutSpan); + if (start >= 0 && end >= 0) { + editable.delete(start, end); + } + } + + @Override + protected int getTextOffset() { + // Place the pop-up at the end of the span + Editable editable = (Editable) mText; + return editable.getSpanEnd(mEditTextShortcutSpan); + } + + @Override + protected int getVerticalLocalPosition(int line) { + return mLayout.getLineBottom(line); + } + + @Override + protected int clipVertically(int positionY) { + // As we display the pop-up below the span, no vertical clipping is required. + return positionY; + } + } + private class ChangeWatcher implements TextWatcher, SpanWatcher { private CharSequence mBeforeText; + private EditTextShortcutController mEditTextShortcutController; + + private ChangeWatcher() { + mEditTextShortcutController = new EditTextShortcutController(); + } + public void beforeTextChanged(CharSequence buffer, int start, int before, int after) { if (DEBUG_EXTRACT) Log.v(LOG_TAG, "beforeTextChanged start=" + start @@ -7729,6 +7955,8 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener + " before=" + before + " after=" + after + ": " + buffer); TextView.this.handleTextChanged(buffer, start, before, after); + mEditTextShortcutController.onTextChange(buffer); + if (AccessibilityManager.getInstance(mContext).isEnabled() && (isFocused() || isSelected() && isShown())) { sendAccessibilityEventTypeViewTextChanged(mBeforeText, start, before, after); @@ -7763,6 +7991,10 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener + " what=" + what + ": " + buf); TextView.this.spanChange(buf, what, s, -1, e, -1); } + + private void hideControllers() { + mEditTextShortcutController.hide(); + } } /** @@ -8261,7 +8493,8 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener @Override protected float getLeftFadingEdgeStrength() { if (mCurrentAlpha <= ViewConfiguration.ALPHA_THRESHOLD_INT) return 0.0f; - if (mEllipsize == TextUtils.TruncateAt.MARQUEE) { + if (mEllipsize == TextUtils.TruncateAt.MARQUEE && + mMarqueeFadeMode != MARQUEE_FADE_SWITCH_SHOW_ELLIPSIS) { if (mMarquee != null && !mMarquee.isStopped()) { final Marquee marquee = mMarquee; if (marquee.shouldDrawLeftFade()) { @@ -8290,7 +8523,8 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener @Override protected float getRightFadingEdgeStrength() { if (mCurrentAlpha <= ViewConfiguration.ALPHA_THRESHOLD_INT) return 0.0f; - if (mEllipsize == TextUtils.TruncateAt.MARQUEE) { + if (mEllipsize == TextUtils.TruncateAt.MARQUEE && + mMarqueeFadeMode != MARQUEE_FADE_SWITCH_SHOW_ELLIPSIS) { if (mMarquee != null && !mMarquee.isStopped()) { final Marquee marquee = mMarquee; return (marquee.mMaxFadeScroll - marquee.mScroll) / getHorizontalFadingEdgeLength(); @@ -8928,6 +9162,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener stopSelectionActionMode(); } else { selectCurrentWord(); + getSelectionController().show(); } handled = true; } @@ -9183,6 +9418,34 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener } } + private static class SuggestionRangeSpan extends CharacterStyle { + + private final int mTextColor; + private final int mBackgroundColor; + + public SuggestionRangeSpan(Context context) { + TypedArray typedArray = context.obtainStyledAttributes(null, + com.android.internal.R.styleable.SuggestionRangeSpan, + com.android.internal.R.attr.textAppearanceSuggestionRange, 0); + + mTextColor = typedArray.getColor( + com.android.internal.R.styleable.SuggestionRangeSpan_textColor, 0); + mBackgroundColor = typedArray.getColor( + com.android.internal.R.styleable.SuggestionRangeSpan_colorBackground, 0); + } + + @Override + public void updateDrawState(TextPaint tp) { + if (mTextColor != 0) { + tp.setColor(mTextColor); + } + + if (mBackgroundColor != 0) { + tp.bgColor = mBackgroundColor; + } + } + } + private class SuggestionsPopupWindow extends PinnedPopupWindow implements OnClickListener { private static final int MAX_NUMBER_SUGGESTIONS = SuggestionSpan.SUGGESTIONS_MAX_SIZE; private static final int NO_SUGGESTIONS = -1; @@ -9367,7 +9630,15 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener if (totalNbSuggestions == 0) return false; - if (mSuggestionRangeSpan == null) mSuggestionRangeSpan = new SuggestionRangeSpan(); + if (mSuggestionRangeSpan == null) { + mSuggestionRangeSpan = new SuggestionRangeSpan(getContext()); + } + + ((Editable) mText).setSpan(mSuggestionRangeSpan, spanUnionStart, spanUnionEnd, + Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); + + if (mSuggestionRangeSpan == null) mSuggestionRangeSpan = + new SuggestionRangeSpan(getContext()); ((Editable) mText).setSpan(mSuggestionRangeSpan, spanUnionStart, spanUnionEnd, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); @@ -10694,6 +10965,10 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener private void hideControllers() { hideInsertionPointCursorController(); stopSelectionActionMode(); + + if (mChangeWatcher != null) { + mChangeWatcher.hideControllers(); + } } /** diff --git a/core/java/com/android/internal/widget/TransportControlView.java b/core/java/com/android/internal/widget/TransportControlView.java index 3961de3195de..1c47ca88ab7d 100644 --- a/core/java/com/android/internal/widget/TransportControlView.java +++ b/core/java/com/android/internal/widget/TransportControlView.java @@ -16,88 +16,369 @@ package com.android.internal.widget; -import com.android.internal.R; +import java.lang.ref.WeakReference; + +import com.android.internal.widget.LockScreenWidgetCallback; +import com.android.internal.widget.LockScreenWidgetInterface; +import android.content.ComponentName; import android.content.Context; +import android.content.Intent; +import android.graphics.Bitmap; import android.media.AudioManager; +import android.media.MediaMetadataRetriever; +import android.media.RemoteControlClient; +import android.media.IRemoteControlDisplay; +import android.os.Bundle; import android.os.Handler; import android.os.Message; +import android.os.RemoteException; +import android.text.Spannable; +import android.text.TextUtils; +import android.text.style.ForegroundColorSpan; import android.util.AttributeSet; +import android.util.Log; +import android.view.KeyEvent; import android.view.View; import android.view.View.OnClickListener; -import android.widget.LinearLayout; +import android.widget.FrameLayout; +import android.widget.ImageView; +import android.widget.TextView; -/** - * A special widget for displaying audio playback ("transport controls") in LockScreen. - * - */ -public class TransportControlView extends LinearLayout implements LockScreenWidgetInterface, - OnClickListener { - private static final String TAG = "TransportControlView"; - static final int sViewIds[] = { R.id.control_prev, R.id.control_pauseplay, R.id.control_next }; - protected static final int AUDIO_FOCUS_CHANGED = 100; - private LockScreenWidgetCallback mCallback; +import com.android.internal.R; + +public class TransportControlView extends FrameLayout implements OnClickListener, + LockScreenWidgetInterface { + + private static final int MSG_UPDATE_STATE = 100; + private static final int MSG_SET_METADATA = 101; + private static final int MSG_SET_TRANSPORT_CONTROLS = 102; + private static final int MSG_SET_ARTWORK = 103; + private static final int MSG_SET_GENERATION_ID = 104; + private static final int MAXDIM = 512; + protected static final boolean DEBUG = true; + protected static final String TAG = "TransportControlView"; + + private ImageView mAlbumArt; + private TextView mTrackTitle; + private ImageView mBtnPrev; + private ImageView mBtnPlay; + private ImageView mBtnNext; + private int mClientGeneration; + private Metadata mMetadata = new Metadata(); + private boolean mAttached; + private ComponentName mClientName; + private int mTransportControlFlags; + private int mPlayState; + private AudioManager mAudioManager; + private LockScreenWidgetCallback mWidgetCallbacks; + private IRemoteControlDisplayWeak mIRCD; + + /** + * The metadata which should be populated into the view once we've been attached + */ + private Bundle mPopulateMetadataWhenAttached = null; + + // This handler is required to ensure messages from IRCD are handled in sequence and on + // the UI thread. private Handler mHandler = new Handler() { + @Override public void handleMessage(Message msg) { - switch (msg.what){ - case AUDIO_FOCUS_CHANGED: - handleAudioFocusChange(msg.arg1); + switch (msg.what) { + case MSG_UPDATE_STATE: + if (mClientGeneration == msg.arg1) updatePlayPauseState(msg.arg2); + break; + + case MSG_SET_METADATA: + if (mClientGeneration == msg.arg1) updateMetadata((Bundle) msg.obj); + break; + + case MSG_SET_TRANSPORT_CONTROLS: + if (mClientGeneration == msg.arg1) updateTransportControls(msg.arg2); + break; + + case MSG_SET_ARTWORK: + if (mClientGeneration == msg.arg1) { + mMetadata.bitmap = (Bitmap) msg.obj; + mAlbumArt.setImageBitmap(mMetadata.bitmap); + } + 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); + } + } + mClientGeneration = msg.arg1; + mClientName = (ComponentName) msg.obj; + break; + } } }; - AudioManager.OnAudioFocusChangeListener mAudioFocusChangeListener = - new AudioManager.OnAudioFocusChangeListener() { - public void onAudioFocusChange(final int focusChange) { - mHandler.obtainMessage(AUDIO_FOCUS_CHANGED, focusChange, 0).sendToTarget(); + /** + * This class is required to have weak linkage to the current TransportControlView + * because the remote process can hold a strong reference to this binder object and + * we can't predict when it will be GC'd in the remote process. Without this code, it + * would allow a heavyweight object to be held on this side of the binder when there's + * no requirement to run a GC on the other side. + */ + private static class IRemoteControlDisplayWeak extends IRemoteControlDisplay.Stub { + private WeakReference<Handler> mLocalHandler; + + IRemoteControlDisplayWeak(Handler handler) { + mLocalHandler = new WeakReference<Handler>(handler); + } + + public void setPlaybackState(int generationId, int state) { + Handler handler = mLocalHandler.get(); + if (handler != null) { + handler.obtainMessage(MSG_UPDATE_STATE, generationId, state).sendToTarget(); } - }; + } - public TransportControlView(Context context) { - this(context, null); - } + public void setMetadata(int generationId, Bundle metadata) { + Handler handler = mLocalHandler.get(); + if (handler != null) { + handler.obtainMessage(MSG_SET_METADATA, generationId, 0, metadata).sendToTarget(); + } + } + + public void setTransportControlFlags(int generationId, int flags) { + Handler handler = mLocalHandler.get(); + if (handler != null) { + handler.obtainMessage(MSG_SET_TRANSPORT_CONTROLS, generationId, flags) + .sendToTarget(); + } + } + + public void setArtwork(int generationId, Bitmap bitmap) { + Handler handler = mLocalHandler.get(); + if (handler != null) { + handler.obtainMessage(MSG_SET_ARTWORK, generationId, 0, bitmap).sendToTarget(); + } + } + + public void setAllMetadata(int generationId, Bundle metadata, Bitmap bitmap) { + Handler handler = mLocalHandler.get(); + if (handler != null) { + handler.obtainMessage(MSG_SET_METADATA, generationId, 0, metadata).sendToTarget(); + handler.obtainMessage(MSG_SET_ARTWORK, generationId, 0, bitmap).sendToTarget(); + } + } + + public void setCurrentClientId(int clientGeneration, ComponentName clientEventReceiver, + boolean clearing) throws RemoteException { + Handler handler = mLocalHandler.get(); + if (handler != null) { + handler.obtainMessage(MSG_SET_GENERATION_ID, + clientGeneration, (clearing ? 1 : 0), clientEventReceiver).sendToTarget(); + } + } + }; public TransportControlView(Context context, AttributeSet attrs) { super(context, attrs); + Log.v(TAG, "Create TCV " + this); + mAudioManager = new AudioManager(mContext); + mIRCD = new IRemoteControlDisplayWeak(mHandler); } - protected void handleAudioFocusChange(int focusChange) { - // TODO + private void updateTransportControls(int transportControlFlags) { + mTransportControlFlags = transportControlFlags; } - public void setCallback(LockScreenWidgetCallback callback) { - mCallback = callback; + @Override + public void onFinishInflate() { + super.onFinishInflate(); + mTrackTitle = (TextView) findViewById(R.id.title); + mTrackTitle.setSelected(true); // enable marquee + mAlbumArt = (ImageView) findViewById(R.id.albumart); + mBtnPrev = (ImageView) findViewById(R.id.btn_prev); + mBtnPlay = (ImageView) findViewById(R.id.btn_play); + mBtnNext = (ImageView) findViewById(R.id.btn_next); + final View buttons[] = { mBtnPrev, mBtnPlay, mBtnNext }; + for (View view : buttons) { + view.setOnClickListener(this); + } } @Override - public void onFinishInflate() { - for (int i = 0; i < sViewIds.length; i++) { - View view = findViewById(sViewIds[i]); - if (view != null) { - view.setOnClickListener(this); + public void onAttachedToWindow() { + super.onAttachedToWindow(); + if (mPopulateMetadataWhenAttached != null) { + updateMetadata(mPopulateMetadataWhenAttached); + mPopulateMetadataWhenAttached = null; + } + if (!mAttached) { + if (DEBUG) Log.v(TAG, "Registering TCV " + this); + mAudioManager.registerRemoteControlDisplay(mIRCD); + } + mAttached = true; + } + + @Override + public void onDetachedFromWindow() { + super.onDetachedFromWindow(); + if (mAttached) { + if (DEBUG) Log.v(TAG, "Unregistering TCV " + this); + mAudioManager.unregisterRemoteControlDisplay(mIRCD); + } + mAttached = false; + } + + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + super.onMeasure(widthMeasureSpec, heightMeasureSpec); + int dim = Math.min(MAXDIM, Math.max(getWidth(), getHeight())); +// Log.v(TAG, "setting max bitmap size: " + dim + "x" + dim); +// mAudioManager.remoteControlDisplayUsesBitmapSize(mIRCD, dim, dim); + } + + class Metadata { + private String artist; + private String trackTitle; + private String albumTitle; + private Bitmap bitmap; + + public String toString() { + return "Metadata[artist=" + artist + " trackTitle=" + trackTitle + " albumTitle=" + albumTitle + "]"; + } + } + + private String getMdString(Bundle data, int id) { + return data.getString(Integer.toString(id)); + } + + private void updateMetadata(Bundle data) { + if (mAttached) { + mMetadata.artist = getMdString(data, MediaMetadataRetriever.METADATA_KEY_ALBUMARTIST); + mMetadata.trackTitle = getMdString(data, MediaMetadataRetriever.METADATA_KEY_TITLE); + mMetadata.albumTitle = getMdString(data, MediaMetadataRetriever.METADATA_KEY_ALBUM); + populateMetadata(); + } else { + mPopulateMetadataWhenAttached = data; + } + } + + /** + * Populates the given metadata into the view + */ + private void populateMetadata() { + StringBuilder sb = new StringBuilder(); + int trackTitleLength = 0; + if (!TextUtils.isEmpty(mMetadata.trackTitle)) { + sb.append(mMetadata.trackTitle); + trackTitleLength = mMetadata.trackTitle.length(); + } + if (!TextUtils.isEmpty(mMetadata.artist)) { + if (sb.length() != 0) { + sb.append(" - "); + } + sb.append(mMetadata.artist); + } + if (!TextUtils.isEmpty(mMetadata.albumTitle)) { + if (sb.length() != 0) { + sb.append(" - "); } + sb.append(mMetadata.albumTitle); + } + mTrackTitle.setText(sb.toString(), TextView.BufferType.SPANNABLE); + Spannable str = (Spannable) mTrackTitle.getText(); + if (trackTitleLength != 0) { + str.setSpan(new ForegroundColorSpan(0xffffffff), 0, trackTitleLength, + Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); + trackTitleLength++; + } + if (sb.length() > trackTitleLength) { + str.setSpan(new ForegroundColorSpan(0x7fffffff), trackTitleLength, sb.length(), + Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); } + + mAlbumArt.setImageBitmap(mMetadata.bitmap); + final int flags = mTransportControlFlags; + setVisibilityBasedOnFlag(mBtnPrev, flags, RemoteControlClient.FLAG_KEY_MEDIA_PREVIOUS); + setVisibilityBasedOnFlag(mBtnNext, flags, RemoteControlClient.FLAG_KEY_MEDIA_NEXT); + setVisibilityBasedOnFlag(mBtnPrev, flags, + RemoteControlClient.FLAG_KEY_MEDIA_PLAY + | RemoteControlClient.FLAG_KEY_MEDIA_PAUSE + | RemoteControlClient.FLAG_KEY_MEDIA_PLAY_PAUSE + | RemoteControlClient.FLAG_KEY_MEDIA_STOP); + + updatePlayPauseState(mPlayState); } - public void onClick(View v) { - switch (v.getId()) { - case R.id.control_prev: - // TODO + private static void setVisibilityBasedOnFlag(View view, int flags, int flag) { + if ((flags & flag) != 0) { + view.setVisibility(View.VISIBLE); + } else { + view.setVisibility(View.GONE); + } + } + + private void updatePlayPauseState(int state) { + if (DEBUG) Log.v(TAG, + "updatePlayPauseState(), old=" + mPlayState + ", state=" + state); + if (state == mPlayState) { + return; + } + switch (state) { + case RemoteControlClient.PLAYSTATE_PLAYING: + mBtnPlay.setImageResource(com.android.internal.R.drawable.ic_media_pause); break; - case R.id.control_pauseplay: - // TODO + case RemoteControlClient.PLAYSTATE_BUFFERING: + mBtnPlay.setImageResource(com.android.internal.R.drawable.ic_media_stop); break; - case R.id.control_next: - // TODO + case RemoteControlClient.PLAYSTATE_PAUSED: + default: + mBtnPlay.setImageResource(com.android.internal.R.drawable.ic_media_play); break; } - // Have any button click extend lockscreen's timeout. - if (mCallback != null) { - mCallback.userActivity(this); + mPlayState = state; + } + + public void onClick(View v) { + int keyCode = -1; + if (v == mBtnPrev) { + keyCode = KeyEvent.KEYCODE_MEDIA_PREVIOUS; + } else if (v == mBtnNext) { + keyCode = KeyEvent.KEYCODE_MEDIA_NEXT; + } else if (v == mBtnPlay) { + keyCode = KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE; + + } + if (keyCode != -1) { + sendMediaButtonClick(keyCode); + if (mWidgetCallbacks != null) { + mWidgetCallbacks.userActivity(this); + } } } + private void sendMediaButtonClick(int keyCode) { + // TODO: target to specific player based on mClientName + KeyEvent keyEvent = new KeyEvent(KeyEvent.ACTION_DOWN, keyCode); + Intent intent = new Intent(Intent.ACTION_MEDIA_BUTTON); + intent.putExtra(Intent.EXTRA_KEY_EVENT, keyEvent); + getContext().sendOrderedBroadcast(intent, null); + + keyEvent = new KeyEvent(KeyEvent.ACTION_UP, keyCode); + intent = new Intent(Intent.ACTION_MEDIA_BUTTON); + intent.putExtra(Intent.EXTRA_KEY_EVENT, keyEvent); + getContext().sendOrderedBroadcast(intent, null); + } + + public void setCallback(LockScreenWidgetCallback callback) { + mWidgetCallbacks = callback; + } + } diff --git a/core/java/com/android/internal/widget/multiwaveview/MultiWaveView.java b/core/java/com/android/internal/widget/multiwaveview/MultiWaveView.java index ec926e4fdfe9..76bc535e865c 100644 --- a/core/java/com/android/internal/widget/multiwaveview/MultiWaveView.java +++ b/core/java/com/android/internal/widget/multiwaveview/MultiWaveView.java @@ -16,8 +16,6 @@ package com.android.internal.widget.multiwaveview; -import java.util.ArrayList; - import android.animation.Animator; import android.animation.Animator.AnimatorListener; import android.animation.AnimatorListenerAdapter; @@ -31,15 +29,20 @@ import android.graphics.Canvas; import android.graphics.RectF; import android.graphics.drawable.Drawable; import android.os.Vibrator; +import android.text.TextUtils; import android.util.AttributeSet; import android.util.Log; import android.util.TypedValue; import android.view.MotionEvent; import android.view.View; -import android.view.View.MeasureSpec; +import android.view.ViewConfiguration; +import android.view.accessibility.AccessibilityEvent; +import android.view.accessibility.AccessibilityManager; import com.android.internal.R; +import java.util.ArrayList; + /** * A special widget containing a center and outer ring. Moving the center ring to the outer ring * causes an event that can be caught by implementing OnTriggerListener. @@ -82,6 +85,8 @@ public class MultiWaveView extends View { private ArrayList<TargetDrawable> mChevronDrawables = new ArrayList<TargetDrawable>(); private ArrayList<Tweener> mChevronAnimations = new ArrayList<Tweener>(); private ArrayList<Tweener> mTargetAnimations = new ArrayList<Tweener>(); + private ArrayList<String> mTargetDescriptions; + private ArrayList<String> mDirectionDescriptions; private Tweener mHandleAnimation; private OnTriggerListener mOnTriggerListener; private TargetDrawable mHandleDrawable; @@ -103,6 +108,9 @@ public class MultiWaveView extends View { private boolean mDragging; private int mNewTargetResources; + private boolean mWaveHovered = false; + private long mLastHoverExitTimeMillis = 0; + private AnimatorListener mResetListener = new AnimatorListenerAdapter() { public void onAnimationEnd(Animator animator) { switchToState(STATE_IDLE, mWaveCenterX, mWaveCenterY); @@ -128,6 +136,8 @@ public class MultiWaveView extends View { } }; private int mTargetResourceId; + private int mTargetDescriptionsResourceId; + private int mDirectionDescriptionsResourceId; public MultiWaveView(Context context) { this(context, null); @@ -177,6 +187,25 @@ public class MultiWaveView extends View { throw new IllegalStateException("Must specify at least one target drawable"); } + // Read array of target descriptions + if (a.getValue(R.styleable.MultiWaveView_targetDescriptions, outValue)) { + final int resourceId = outValue.resourceId; + if (resourceId == 0) { + throw new IllegalStateException("Must specify target descriptions"); + } + setTargetDescriptionsResourceId(resourceId); + } + + // Read array of direction descriptions + if (a.getValue(R.styleable.MultiWaveView_directionDescriptions, outValue)) { + final int resourceId = outValue.resourceId; + if (resourceId == 0) { + throw new IllegalStateException("Must specify direction descriptions"); + } + setDirectionDescriptionsResourceId(resourceId); + } + + a.recycle(); setVibrateEnabled(mVibrationDuration > 0); } @@ -247,6 +276,9 @@ public class MultiWaveView extends View { showTargets(true); mHandleDrawable.setState(TargetDrawable.STATE_ACTIVE); setGrabbedState(OnTriggerListener.CENTER_HANDLE); + if (AccessibilityManager.getInstance(mContext).isEnabled()) { + announceTargets(); + } break; case STATE_TRACKING: @@ -347,6 +379,13 @@ public class MultiWaveView extends View { } } + private void dispatchGrabbedEvent(int whichHandler) { + vibrate(); + if (mOnTriggerListener != null) { + mOnTriggerListener.onGrabbed(this, whichHandler); + } + } + private void doFinish() { final int activeTarget = mActiveTarget; boolean targetHit = activeTarget != -1; @@ -475,6 +514,7 @@ public class MultiWaveView extends View { Drawable drawable = array.getDrawable(i); targetDrawables.add(new TargetDrawable(res, drawable)); } + array.recycle(); mTargetResourceId = resourceId; mTargetDrawables = targetDrawables; updateTargetPositions(); @@ -499,6 +539,48 @@ public class MultiWaveView extends View { } /** + * Sets the resource id specifying the target descriptions for accessibility. + * + * @param resourceId The resource id. + */ + public void setTargetDescriptionsResourceId(int resourceId) { + mTargetDescriptionsResourceId = resourceId; + if (mTargetDescriptions != null) { + mTargetDescriptions.clear(); + } + } + + /** + * Gets the resource id specifying the target descriptions for accessibility. + * + * @return The resource id. + */ + public int getTargetDescriptionsResourceId() { + return mTargetDescriptionsResourceId; + } + + /** + * Sets the resource id specifying the target direction descriptions for accessibility. + * + * @param resourceId The resource id. + */ + public void setDirectionDescriptionsResourceId(int resourceId) { + mDirectionDescriptionsResourceId = resourceId; + if (mDirectionDescriptions != null) { + mDirectionDescriptions.clear(); + } + } + + /** + * Gets the resource id specifying the target direction descriptions. + * + * @return The resource id. + */ + public int getDirectionDescriptionsResourceId() { + return mDirectionDescriptionsResourceId; + } + + /** * Enable or disable vibrate on touch. * * @param enabled @@ -593,6 +675,43 @@ public class MultiWaveView extends View { } } + @Override + public boolean onHoverEvent(MotionEvent event) { + if (AccessibilityManager.getInstance(mContext).isTouchExplorationEnabled()) { + final int action = event.getAction(); + switch (action) { + case MotionEvent.ACTION_HOVER_ENTER: + case MotionEvent.ACTION_HOVER_MOVE: + final float dx = event.getX() - mWaveCenterX; + final float dy = event.getY() - mWaveCenterY; + if (dist2(dx,dy) <= square(mTapRadius)) { + if (!mWaveHovered) { + mWaveHovered = true; + final long timeSinceLastHoverExitMillis = + event.getEventTime() - mLastHoverExitTimeMillis; + final long recurringEventsInterval = + ViewConfiguration.getSendRecurringAccessibilityEventsInterval(); + if (timeSinceLastHoverExitMillis > recurringEventsInterval) { + String text = + mContext.getString(R.string.content_description_sliding_handle); + announceText(text); + } + } + } else { + mWaveHovered = false; + } + break; + case MotionEvent.ACTION_HOVER_EXIT: + mLastHoverExitTimeMillis = event.getEventTime(); + mWaveHovered = false; + break; + default: + mWaveHovered = false; + } + } + return super.onHoverEvent(event); + } + private void handleUp(MotionEvent event) { if (DEBUG && mDragging) Log.v(TAG, "** Handle RELEASE"); switchToState(STATE_FINISH, event.getX(), event.getY()); @@ -663,7 +782,11 @@ public class MultiWaveView extends View { invalidateGlobalRegion(mHandleDrawable); if (mActiveTarget != activeTarget && activeTarget != -1) { - vibrate(); + dispatchGrabbedEvent(activeTarget); + if (AccessibilityManager.getInstance(mContext).isEnabled()) { + String targetContentDescription = getTargetDescription(activeTarget); + announceText(targetContentDescription); + } } mActiveTarget = activeTarget; } @@ -771,4 +894,62 @@ public class MultiWaveView extends View { return dx*dx + dy*dy; } -}
\ No newline at end of file + private void announceTargets() { + StringBuilder utterance = new StringBuilder(); + final int targetCount = mTargetDrawables.size(); + for (int i = 0; i < targetCount; i++) { + String targetDescription = getTargetDescription(i); + String directionDescription = getDirectionDescription(i); + if (!TextUtils.isEmpty(targetDescription) + && !TextUtils.isEmpty(directionDescription)) { + utterance.append(targetDescription); + utterance.append(" "); + utterance.append(directionDescription); + utterance.append("."); + } + } + announceText(utterance.toString()); + } + + private void announceText(String text) { + setContentDescription(text); + sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_FOCUSED); + setContentDescription(null); + } + + private String getTargetDescription(int index) { + if (mTargetDescriptions == null || mTargetDescriptions.isEmpty()) { + mTargetDescriptions = loadDescriptions(mTargetDescriptionsResourceId); + if (mTargetDrawables.size() != mTargetDescriptions.size()) { + Log.w(TAG, "The number of target drawables must be" + + " euqal to the number of target descriptions."); + return null; + } + } + return mTargetDescriptions.get(index); + } + + private String getDirectionDescription(int index) { + if (mDirectionDescriptions == null || mDirectionDescriptions.isEmpty()) { + mDirectionDescriptions = loadDescriptions(mDirectionDescriptionsResourceId); + if (mTargetDrawables.size() != mDirectionDescriptions.size()) { + Log.w(TAG, "The number of target drawables must be" + + " euqal to the number of direction descriptions."); + return null; + } + } + return mDirectionDescriptions.get(index); + } + + private ArrayList<String> loadDescriptions(int resourceId) { + TypedArray array = getContext().getResources().obtainTypedArray(resourceId); + final int count = array.length(); + ArrayList<String> targetContentDescriptions = new ArrayList<String>(count); + for (int i = 0; i < count; i++) { + String contentDescription = array.getString(i); + targetContentDescriptions.add(contentDescription); + } + array.recycle(); + return targetContentDescriptions; + } +} diff --git a/core/jni/android_net_wifi_Wifi.cpp b/core/jni/android_net_wifi_Wifi.cpp index 3cbd9124d8cd..84a50f029e67 100644 --- a/core/jni/android_net_wifi_Wifi.cpp +++ b/core/jni/android_net_wifi_Wifi.cpp @@ -124,6 +124,11 @@ static jboolean android_net_wifi_startSupplicant(JNIEnv* env, jobject) return (jboolean)(::wifi_start_supplicant() == 0); } +static jboolean android_net_wifi_startP2pSupplicant(JNIEnv* env, jobject) +{ + return (jboolean)(::wifi_start_p2p_supplicant() == 0); +} + static jboolean android_net_wifi_stopSupplicant(JNIEnv* env, jobject) { return doBooleanCommand("OK", "TERMINATE"); @@ -581,6 +586,7 @@ static JNINativeMethod gWifiMethods[] = { { "isDriverLoaded", "()Z", (void *)android_net_wifi_isDriverLoaded}, { "unloadDriver", "()Z", (void *)android_net_wifi_unloadDriver }, { "startSupplicant", "()Z", (void *)android_net_wifi_startSupplicant }, + { "startP2pSupplicant", "()Z", (void *)android_net_wifi_startP2pSupplicant }, { "stopSupplicant", "()Z", (void*) android_net_wifi_stopSupplicant }, { "killSupplicant", "()Z", (void *)android_net_wifi_killSupplicant }, { "connectToSupplicant", "()Z", (void *)android_net_wifi_connectToSupplicant }, diff --git a/core/jni/android_util_Binder.cpp b/core/jni/android_util_Binder.cpp index 4cf4afabec14..494a2b33ade2 100644 --- a/core/jni/android_util_Binder.cpp +++ b/core/jni/android_util_Binder.cpp @@ -119,6 +119,11 @@ static struct binderproxy_offsets_t } gBinderProxyOffsets; +static struct class_offsets_t +{ + jmethodID mGetName; +} gClassOffsets; + // ---------------------------------------------------------------------------- static struct parcel_offsets_t @@ -452,22 +457,18 @@ public: // Okay, something is wrong -- we have a hard reference to a live death // recipient on the VM side, but the list is being torn down. JNIEnv* env = javavm_to_jnienv(mVM); - ScopedLocalRef<jclass> classRef(env, env->GetObjectClass(mObject)); - jmethodID getnameMethod = env->GetMethodID(classRef.get(), - "getName", "()Ljava/lang/String;"); - if (getnameMethod) { - ScopedLocalRef<jstring> nameRef(env, - (jstring) env->CallObjectMethod(classRef.get(), getnameMethod)); - ScopedUtfChars nameUtf(env, nameRef.get()); - if (nameUtf.c_str() != NULL) { - LOGW("BinderProxy is being destroyed but the application did not call " - "unlinkToDeath to unlink all of its death recipients beforehand. " - "Releasing leaked death recipient: %s", nameUtf.c_str()); - } else { - LOGW("BinderProxy being destroyed; unable to get DR object name"); - env->ExceptionClear(); - } - } else LOGW("BinderProxy being destroyed; unable to find DR class getName"); + ScopedLocalRef<jclass> objClassRef(env, env->GetObjectClass(mObject)); + ScopedLocalRef<jstring> nameRef(env, + (jstring) env->CallObjectMethod(objClassRef.get(), gClassOffsets.mGetName)); + ScopedUtfChars nameUtf(env, nameRef.get()); + if (nameUtf.c_str() != NULL) { + LOGW("BinderProxy is being destroyed but the application did not call " + "unlinkToDeath to unlink all of its death recipients beforehand. " + "Releasing leaked death recipient: %s", nameUtf.c_str()); + } else { + LOGW("BinderProxy being destroyed; unable to get DR object name"); + env->ExceptionClear(); + } } } @@ -1230,6 +1231,11 @@ static int int_register_android_os_BinderProxy(JNIEnv* env) = env->GetFieldID(clazz, "mOrgue", "I"); assert(gBinderProxyOffsets.mOrgue); + clazz = env->FindClass("java/lang/Class"); + LOG_FATAL_IF(clazz == NULL, "Unable to find java.lang.Class"); + gClassOffsets.mGetName = env->GetMethodID(clazz, "getName", "()Ljava/lang/String;"); + assert(gClassOffsets.mGetName); + return AndroidRuntime::registerNativeMethods( env, kBinderProxyPathName, gBinderProxyMethods, NELEM(gBinderProxyMethods)); diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml index 540c65a7812d..01f2a8f578a2 100644 --- a/core/res/AndroidManifest.xml +++ b/core/res/AndroidManifest.xml @@ -93,6 +93,9 @@ <protected-broadcast android:name="android.hardware.usb.action.USB_DEVICE_ATTACHED" /> <protected-broadcast android:name="android.hardware.usb.action.USB_DEVICE_DETACHED" /> + <protected-broadcast android:name="android.net.conn.CONNECTIVITY_CHANGE" /> + <protected-broadcast android:name="android.net.conn.CONNECTIVITY_CHANGE_IMMEDIATE" /> + <protected-broadcast android:name="android.nfc.action.LLCP_LINK_STATE_CHANGED" /> <protected-broadcast android:name="com.android.nfc_extras.action.RF_FIELD_ON_DETECTED" /> <protected-broadcast android:name="com.android.nfc_extras.action.RF_FIELD_OFF_DETECTED" /> diff --git a/core/res/res/drawable-hdpi/ab_bottom_solid_dark_holo.9.png b/core/res/res/drawable-hdpi/ab_bottom_solid_dark_holo.9.png Binary files differindex 81829bbb4c9a..769463b369a5 100644 --- a/core/res/res/drawable-hdpi/ab_bottom_solid_dark_holo.9.png +++ b/core/res/res/drawable-hdpi/ab_bottom_solid_dark_holo.9.png diff --git a/core/res/res/drawable-hdpi/ab_bottom_solid_inverse_holo.9.png b/core/res/res/drawable-hdpi/ab_bottom_solid_inverse_holo.9.png Binary files differindex 04368018440f..88f11dcb91ee 100644 --- a/core/res/res/drawable-hdpi/ab_bottom_solid_inverse_holo.9.png +++ b/core/res/res/drawable-hdpi/ab_bottom_solid_inverse_holo.9.png diff --git a/core/res/res/drawable-hdpi/ab_bottom_solid_light_holo.9.png b/core/res/res/drawable-hdpi/ab_bottom_solid_light_holo.9.png Binary files differindex 6574c8c40141..73050476e77a 100644 --- a/core/res/res/drawable-hdpi/ab_bottom_solid_light_holo.9.png +++ b/core/res/res/drawable-hdpi/ab_bottom_solid_light_holo.9.png diff --git a/core/res/res/drawable-hdpi/ab_bottom_transparent_dark_holo.9.png b/core/res/res/drawable-hdpi/ab_bottom_transparent_dark_holo.9.png Binary files differindex 1565ac26dd2a..712a551ece87 100644 --- a/core/res/res/drawable-hdpi/ab_bottom_transparent_dark_holo.9.png +++ b/core/res/res/drawable-hdpi/ab_bottom_transparent_dark_holo.9.png diff --git a/core/res/res/drawable-hdpi/ab_bottom_transparent_light_holo.9.png b/core/res/res/drawable-hdpi/ab_bottom_transparent_light_holo.9.png Binary files differindex 77d4c4b7c971..bf3b9438b165 100644 --- a/core/res/res/drawable-hdpi/ab_bottom_transparent_light_holo.9.png +++ b/core/res/res/drawable-hdpi/ab_bottom_transparent_light_holo.9.png diff --git a/core/res/res/drawable-hdpi/ab_solid_dark_holo.9.png b/core/res/res/drawable-hdpi/ab_solid_dark_holo.9.png Binary files differindex 0fc8632310ff..cbbaec588ec9 100644 --- a/core/res/res/drawable-hdpi/ab_solid_dark_holo.9.png +++ b/core/res/res/drawable-hdpi/ab_solid_dark_holo.9.png diff --git a/core/res/res/drawable-hdpi/ab_solid_light_holo.9.png b/core/res/res/drawable-hdpi/ab_solid_light_holo.9.png Binary files differindex 74540c194edc..af917e5b6f7d 100644 --- a/core/res/res/drawable-hdpi/ab_solid_light_holo.9.png +++ b/core/res/res/drawable-hdpi/ab_solid_light_holo.9.png diff --git a/core/res/res/drawable-hdpi/ab_solid_shadow_holo.9.png b/core/res/res/drawable-hdpi/ab_solid_shadow_holo.9.png Binary files differindex 69bcd7acd9d2..2d59f354eed3 100644 --- a/core/res/res/drawable-hdpi/ab_solid_shadow_holo.9.png +++ b/core/res/res/drawable-hdpi/ab_solid_shadow_holo.9.png diff --git a/core/res/res/drawable-hdpi/ab_stacked_solid_dark_holo.9.png b/core/res/res/drawable-hdpi/ab_stacked_solid_dark_holo.9.png Binary files differindex 9f8829f98e74..0520e5a2f681 100644 --- a/core/res/res/drawable-hdpi/ab_stacked_solid_dark_holo.9.png +++ b/core/res/res/drawable-hdpi/ab_stacked_solid_dark_holo.9.png diff --git a/core/res/res/drawable-hdpi/ab_stacked_solid_inverse_holo.9.png b/core/res/res/drawable-hdpi/ab_stacked_solid_inverse_holo.9.png Binary files differindex d63e85eb6605..42528b157a80 100644 --- a/core/res/res/drawable-hdpi/ab_stacked_solid_inverse_holo.9.png +++ b/core/res/res/drawable-hdpi/ab_stacked_solid_inverse_holo.9.png diff --git a/core/res/res/drawable-hdpi/ab_stacked_solid_light_holo.9.png b/core/res/res/drawable-hdpi/ab_stacked_solid_light_holo.9.png Binary files differindex 9cff5d851dd1..e3e3f93b9f3f 100644 --- a/core/res/res/drawable-hdpi/ab_stacked_solid_light_holo.9.png +++ b/core/res/res/drawable-hdpi/ab_stacked_solid_light_holo.9.png diff --git a/core/res/res/drawable-hdpi/ab_stacked_transparent_dark_holo.9.png b/core/res/res/drawable-hdpi/ab_stacked_transparent_dark_holo.9.png Binary files differindex 12a6454b321d..1e39572224b2 100644 --- a/core/res/res/drawable-hdpi/ab_stacked_transparent_dark_holo.9.png +++ b/core/res/res/drawable-hdpi/ab_stacked_transparent_dark_holo.9.png diff --git a/core/res/res/drawable-hdpi/ab_stacked_transparent_light_holo.9.png b/core/res/res/drawable-hdpi/ab_stacked_transparent_light_holo.9.png Binary files differindex 3355d300039c..a16db853e94a 100644 --- a/core/res/res/drawable-hdpi/ab_stacked_transparent_light_holo.9.png +++ b/core/res/res/drawable-hdpi/ab_stacked_transparent_light_holo.9.png diff --git a/core/res/res/drawable-hdpi/ab_transparent_dark_holo.9.png b/core/res/res/drawable-hdpi/ab_transparent_dark_holo.9.png Binary files differindex a5e857071831..0eff695d8291 100644 --- a/core/res/res/drawable-hdpi/ab_transparent_dark_holo.9.png +++ b/core/res/res/drawable-hdpi/ab_transparent_dark_holo.9.png diff --git a/core/res/res/drawable-hdpi/ab_transparent_light_holo.9.png b/core/res/res/drawable-hdpi/ab_transparent_light_holo.9.png Binary files differindex c49412a7c87e..219b170fa67a 100644 --- a/core/res/res/drawable-hdpi/ab_transparent_light_holo.9.png +++ b/core/res/res/drawable-hdpi/ab_transparent_light_holo.9.png diff --git a/core/res/res/drawable-hdpi/btn_cab_done_default_holo_dark.9.png b/core/res/res/drawable-hdpi/btn_cab_done_default_holo_dark.9.png Binary files differindex fabc252691d4..0d165bb801de 100644 --- a/core/res/res/drawable-hdpi/btn_cab_done_default_holo_dark.9.png +++ b/core/res/res/drawable-hdpi/btn_cab_done_default_holo_dark.9.png diff --git a/core/res/res/drawable-hdpi/btn_cab_done_default_holo_light.9.png b/core/res/res/drawable-hdpi/btn_cab_done_default_holo_light.9.png Binary files differindex f59ef4eb15e5..73c7e255311a 100644 --- a/core/res/res/drawable-hdpi/btn_cab_done_default_holo_light.9.png +++ b/core/res/res/drawable-hdpi/btn_cab_done_default_holo_light.9.png diff --git a/core/res/res/drawable-hdpi/btn_cab_done_focused_holo_dark.9.png b/core/res/res/drawable-hdpi/btn_cab_done_focused_holo_dark.9.png Binary files differindex c87c5a6d3473..1459eee266ad 100644 --- a/core/res/res/drawable-hdpi/btn_cab_done_focused_holo_dark.9.png +++ b/core/res/res/drawable-hdpi/btn_cab_done_focused_holo_dark.9.png diff --git a/core/res/res/drawable-hdpi/btn_cab_done_focused_holo_light.9.png b/core/res/res/drawable-hdpi/btn_cab_done_focused_holo_light.9.png Binary files differindex 6e4cae2644da..04de53056401 100644 --- a/core/res/res/drawable-hdpi/btn_cab_done_focused_holo_light.9.png +++ b/core/res/res/drawable-hdpi/btn_cab_done_focused_holo_light.9.png diff --git a/core/res/res/drawable-hdpi/btn_cab_done_pressed_holo_dark.9.png b/core/res/res/drawable-hdpi/btn_cab_done_pressed_holo_dark.9.png Binary files differindex e6f83cc7f286..bab70fa702b5 100644 --- a/core/res/res/drawable-hdpi/btn_cab_done_pressed_holo_dark.9.png +++ b/core/res/res/drawable-hdpi/btn_cab_done_pressed_holo_dark.9.png diff --git a/core/res/res/drawable-hdpi/btn_cab_done_pressed_holo_light.9.png b/core/res/res/drawable-hdpi/btn_cab_done_pressed_holo_light.9.png Binary files differindex 5c97e3ffb559..b46adfaa0cdf 100644 --- a/core/res/res/drawable-hdpi/btn_cab_done_pressed_holo_light.9.png +++ b/core/res/res/drawable-hdpi/btn_cab_done_pressed_holo_light.9.png diff --git a/core/res/res/drawable-hdpi/cab_background_bottom_holo_dark.9.png b/core/res/res/drawable-hdpi/cab_background_bottom_holo_dark.9.png Binary files differindex 269def426e71..1d836f65a1ff 100644 --- a/core/res/res/drawable-hdpi/cab_background_bottom_holo_dark.9.png +++ b/core/res/res/drawable-hdpi/cab_background_bottom_holo_dark.9.png diff --git a/core/res/res/drawable-hdpi/cab_background_bottom_holo_light.9.png b/core/res/res/drawable-hdpi/cab_background_bottom_holo_light.9.png Binary files differindex 49bcfb49272a..5818666d4e64 100644 --- a/core/res/res/drawable-hdpi/cab_background_bottom_holo_light.9.png +++ b/core/res/res/drawable-hdpi/cab_background_bottom_holo_light.9.png diff --git a/core/res/res/drawable-hdpi/cab_background_top_holo_dark.9.png b/core/res/res/drawable-hdpi/cab_background_top_holo_dark.9.png Binary files differindex b7ddc14b7bc2..564fb34b4308 100644 --- a/core/res/res/drawable-hdpi/cab_background_top_holo_dark.9.png +++ b/core/res/res/drawable-hdpi/cab_background_top_holo_dark.9.png diff --git a/core/res/res/drawable-hdpi/cab_background_top_holo_light.9.png b/core/res/res/drawable-hdpi/cab_background_top_holo_light.9.png Binary files differindex af80ad522f3f..ae21b760fb1e 100644 --- a/core/res/res/drawable-hdpi/cab_background_top_holo_light.9.png +++ b/core/res/res/drawable-hdpi/cab_background_top_holo_light.9.png diff --git a/core/res/res/drawable-hdpi/ic_lockscreen_player_background.9.png b/core/res/res/drawable-hdpi/ic_lockscreen_player_background.9.png Binary files differnew file mode 100644 index 000000000000..b18735871884 --- /dev/null +++ b/core/res/res/drawable-hdpi/ic_lockscreen_player_background.9.png diff --git a/core/res/res/drawable-hdpi/ic_media_embed_play.png b/core/res/res/drawable-hdpi/ic_media_embed_play.png Binary files differindex 05778c181f6f..23ac7e45e426 100644 --- a/core/res/res/drawable-hdpi/ic_media_embed_play.png +++ b/core/res/res/drawable-hdpi/ic_media_embed_play.png diff --git a/core/res/res/drawable-hdpi/ic_menu_moreoverflow_normal_holo_dark.png b/core/res/res/drawable-hdpi/ic_menu_moreoverflow_normal_holo_dark.png Binary files differindex 1e69eac31b89..5f2f60433d20 100644 --- a/core/res/res/drawable-hdpi/ic_menu_moreoverflow_normal_holo_dark.png +++ b/core/res/res/drawable-hdpi/ic_menu_moreoverflow_normal_holo_dark.png diff --git a/core/res/res/drawable-hdpi/ic_menu_moreoverflow_normal_holo_light.png b/core/res/res/drawable-hdpi/ic_menu_moreoverflow_normal_holo_light.png Binary files differindex 2f6acccdf735..7f3459c8688d 100644 --- a/core/res/res/drawable-hdpi/ic_menu_moreoverflow_normal_holo_light.png +++ b/core/res/res/drawable-hdpi/ic_menu_moreoverflow_normal_holo_light.png diff --git a/core/res/res/drawable-mdpi/ab_bottom_solid_dark_holo.9.png b/core/res/res/drawable-mdpi/ab_bottom_solid_dark_holo.9.png Binary files differindex b3d51ed6aeb3..b2293670b7fd 100644 --- a/core/res/res/drawable-mdpi/ab_bottom_solid_dark_holo.9.png +++ b/core/res/res/drawable-mdpi/ab_bottom_solid_dark_holo.9.png diff --git a/core/res/res/drawable-mdpi/ab_bottom_solid_inverse_holo.9.png b/core/res/res/drawable-mdpi/ab_bottom_solid_inverse_holo.9.png Binary files differindex abae537bede6..c65f443e338f 100644 --- a/core/res/res/drawable-mdpi/ab_bottom_solid_inverse_holo.9.png +++ b/core/res/res/drawable-mdpi/ab_bottom_solid_inverse_holo.9.png diff --git a/core/res/res/drawable-mdpi/ab_bottom_solid_light_holo.9.png b/core/res/res/drawable-mdpi/ab_bottom_solid_light_holo.9.png Binary files differindex 4c98afb7393c..0706c8af658b 100644 --- a/core/res/res/drawable-mdpi/ab_bottom_solid_light_holo.9.png +++ b/core/res/res/drawable-mdpi/ab_bottom_solid_light_holo.9.png diff --git a/core/res/res/drawable-mdpi/ab_bottom_transparent_dark_holo.9.png b/core/res/res/drawable-mdpi/ab_bottom_transparent_dark_holo.9.png Binary files differindex de8010a1425c..d814d02d3118 100644 --- a/core/res/res/drawable-mdpi/ab_bottom_transparent_dark_holo.9.png +++ b/core/res/res/drawable-mdpi/ab_bottom_transparent_dark_holo.9.png diff --git a/core/res/res/drawable-mdpi/ab_bottom_transparent_light_holo.9.png b/core/res/res/drawable-mdpi/ab_bottom_transparent_light_holo.9.png Binary files differindex ecb2a0e5ed39..b139c8e49168 100644 --- a/core/res/res/drawable-mdpi/ab_bottom_transparent_light_holo.9.png +++ b/core/res/res/drawable-mdpi/ab_bottom_transparent_light_holo.9.png diff --git a/core/res/res/drawable-mdpi/ab_solid_dark_holo.9.png b/core/res/res/drawable-mdpi/ab_solid_dark_holo.9.png Binary files differindex 56d27a8e79cd..743d00b6cd7e 100644 --- a/core/res/res/drawable-mdpi/ab_solid_dark_holo.9.png +++ b/core/res/res/drawable-mdpi/ab_solid_dark_holo.9.png diff --git a/core/res/res/drawable-mdpi/ab_solid_light_holo.9.png b/core/res/res/drawable-mdpi/ab_solid_light_holo.9.png Binary files differindex 98b4956cc741..17c1fb921f9b 100644 --- a/core/res/res/drawable-mdpi/ab_solid_light_holo.9.png +++ b/core/res/res/drawable-mdpi/ab_solid_light_holo.9.png diff --git a/core/res/res/drawable-mdpi/ab_solid_shadow_holo.9.png b/core/res/res/drawable-mdpi/ab_solid_shadow_holo.9.png Binary files differindex dcd3703ba1bc..ddfc8e3d5c41 100644 --- a/core/res/res/drawable-mdpi/ab_solid_shadow_holo.9.png +++ b/core/res/res/drawable-mdpi/ab_solid_shadow_holo.9.png diff --git a/core/res/res/drawable-mdpi/ab_stacked_solid_dark_holo.9.png b/core/res/res/drawable-mdpi/ab_stacked_solid_dark_holo.9.png Binary files differindex aa0a3a0ed54e..007a4b239244 100644 --- a/core/res/res/drawable-mdpi/ab_stacked_solid_dark_holo.9.png +++ b/core/res/res/drawable-mdpi/ab_stacked_solid_dark_holo.9.png diff --git a/core/res/res/drawable-mdpi/ab_stacked_solid_inverse_holo.9.png b/core/res/res/drawable-mdpi/ab_stacked_solid_inverse_holo.9.png Binary files differindex cf1796741178..a823841c5e16 100644 --- a/core/res/res/drawable-mdpi/ab_stacked_solid_inverse_holo.9.png +++ b/core/res/res/drawable-mdpi/ab_stacked_solid_inverse_holo.9.png diff --git a/core/res/res/drawable-mdpi/ab_stacked_solid_light_holo.9.png b/core/res/res/drawable-mdpi/ab_stacked_solid_light_holo.9.png Binary files differindex ab0003b69178..ad6e1a4d9f3c 100644 --- a/core/res/res/drawable-mdpi/ab_stacked_solid_light_holo.9.png +++ b/core/res/res/drawable-mdpi/ab_stacked_solid_light_holo.9.png diff --git a/core/res/res/drawable-mdpi/ab_stacked_transparent_dark_holo.9.png b/core/res/res/drawable-mdpi/ab_stacked_transparent_dark_holo.9.png Binary files differindex 5f1eb1e29bad..0ad6c888b4c7 100644 --- a/core/res/res/drawable-mdpi/ab_stacked_transparent_dark_holo.9.png +++ b/core/res/res/drawable-mdpi/ab_stacked_transparent_dark_holo.9.png diff --git a/core/res/res/drawable-mdpi/ab_stacked_transparent_light_holo.9.png b/core/res/res/drawable-mdpi/ab_stacked_transparent_light_holo.9.png Binary files differindex 89822b633f41..19b50abcb536 100644 --- a/core/res/res/drawable-mdpi/ab_stacked_transparent_light_holo.9.png +++ b/core/res/res/drawable-mdpi/ab_stacked_transparent_light_holo.9.png diff --git a/core/res/res/drawable-mdpi/ab_transparent_dark_holo.9.png b/core/res/res/drawable-mdpi/ab_transparent_dark_holo.9.png Binary files differindex bd9921f5d2fa..ad980b13fc81 100644 --- a/core/res/res/drawable-mdpi/ab_transparent_dark_holo.9.png +++ b/core/res/res/drawable-mdpi/ab_transparent_dark_holo.9.png diff --git a/core/res/res/drawable-mdpi/ab_transparent_light_holo.9.png b/core/res/res/drawable-mdpi/ab_transparent_light_holo.9.png Binary files differindex 8d93926fe1b8..60e6c52786e1 100644 --- a/core/res/res/drawable-mdpi/ab_transparent_light_holo.9.png +++ b/core/res/res/drawable-mdpi/ab_transparent_light_holo.9.png diff --git a/core/res/res/drawable-mdpi/btn_cab_done_default_holo_dark.9.png b/core/res/res/drawable-mdpi/btn_cab_done_default_holo_dark.9.png Binary files differindex d00d2352966f..9e936b33fcf2 100644 --- a/core/res/res/drawable-mdpi/btn_cab_done_default_holo_dark.9.png +++ b/core/res/res/drawable-mdpi/btn_cab_done_default_holo_dark.9.png diff --git a/core/res/res/drawable-mdpi/btn_cab_done_default_holo_light.9.png b/core/res/res/drawable-mdpi/btn_cab_done_default_holo_light.9.png Binary files differindex d7b20493f736..03601044a3c3 100644 --- a/core/res/res/drawable-mdpi/btn_cab_done_default_holo_light.9.png +++ b/core/res/res/drawable-mdpi/btn_cab_done_default_holo_light.9.png diff --git a/core/res/res/drawable-mdpi/btn_cab_done_focused_holo_dark.9.png b/core/res/res/drawable-mdpi/btn_cab_done_focused_holo_dark.9.png Binary files differindex 59c1580536bb..dd947d231e34 100644 --- a/core/res/res/drawable-mdpi/btn_cab_done_focused_holo_dark.9.png +++ b/core/res/res/drawable-mdpi/btn_cab_done_focused_holo_dark.9.png diff --git a/core/res/res/drawable-mdpi/btn_cab_done_focused_holo_light.9.png b/core/res/res/drawable-mdpi/btn_cab_done_focused_holo_light.9.png Binary files differindex 143564abe012..51cfca27d20c 100644 --- a/core/res/res/drawable-mdpi/btn_cab_done_focused_holo_light.9.png +++ b/core/res/res/drawable-mdpi/btn_cab_done_focused_holo_light.9.png diff --git a/core/res/res/drawable-mdpi/btn_cab_done_pressed_holo_dark.9.png b/core/res/res/drawable-mdpi/btn_cab_done_pressed_holo_dark.9.png Binary files differindex e5b9cfd9c973..fd6e6c7bbcce 100644 --- a/core/res/res/drawable-mdpi/btn_cab_done_pressed_holo_dark.9.png +++ b/core/res/res/drawable-mdpi/btn_cab_done_pressed_holo_dark.9.png diff --git a/core/res/res/drawable-mdpi/btn_cab_done_pressed_holo_light.9.png b/core/res/res/drawable-mdpi/btn_cab_done_pressed_holo_light.9.png Binary files differindex ec43f8513e92..5db212cf45ef 100644 --- a/core/res/res/drawable-mdpi/btn_cab_done_pressed_holo_light.9.png +++ b/core/res/res/drawable-mdpi/btn_cab_done_pressed_holo_light.9.png diff --git a/core/res/res/drawable-mdpi/cab_background_bottom_holo_dark.9.png b/core/res/res/drawable-mdpi/cab_background_bottom_holo_dark.9.png Binary files differindex 0e4b28e4dd24..d8f1c8bd54f4 100644 --- a/core/res/res/drawable-mdpi/cab_background_bottom_holo_dark.9.png +++ b/core/res/res/drawable-mdpi/cab_background_bottom_holo_dark.9.png diff --git a/core/res/res/drawable-mdpi/cab_background_bottom_holo_light.9.png b/core/res/res/drawable-mdpi/cab_background_bottom_holo_light.9.png Binary files differindex e449090cc3cd..31e49894adac 100644 --- a/core/res/res/drawable-mdpi/cab_background_bottom_holo_light.9.png +++ b/core/res/res/drawable-mdpi/cab_background_bottom_holo_light.9.png diff --git a/core/res/res/drawable-mdpi/cab_background_top_holo_dark.9.png b/core/res/res/drawable-mdpi/cab_background_top_holo_dark.9.png Binary files differindex d0ebc1a67e33..7c2cbe5356e4 100644 --- a/core/res/res/drawable-mdpi/cab_background_top_holo_dark.9.png +++ b/core/res/res/drawable-mdpi/cab_background_top_holo_dark.9.png diff --git a/core/res/res/drawable-mdpi/cab_background_top_holo_light.9.png b/core/res/res/drawable-mdpi/cab_background_top_holo_light.9.png Binary files differindex c2dd608a9e47..30cbdc174aab 100644 --- a/core/res/res/drawable-mdpi/cab_background_top_holo_light.9.png +++ b/core/res/res/drawable-mdpi/cab_background_top_holo_light.9.png diff --git a/core/res/res/drawable-mdpi/ic_lockscreen_player_background.9.png b/core/res/res/drawable-mdpi/ic_lockscreen_player_background.9.png Binary files differnew file mode 100644 index 000000000000..8cfd1afbeff8 --- /dev/null +++ b/core/res/res/drawable-mdpi/ic_lockscreen_player_background.9.png diff --git a/core/res/res/drawable-mdpi/ic_media_embed_play.png b/core/res/res/drawable-mdpi/ic_media_embed_play.png Binary files differindex 3576ce53e421..fc5d8c622f6a 100644 --- a/core/res/res/drawable-mdpi/ic_media_embed_play.png +++ b/core/res/res/drawable-mdpi/ic_media_embed_play.png diff --git a/core/res/res/drawable-mdpi/ic_media_ff.png b/core/res/res/drawable-mdpi/ic_media_ff.png Binary files differindex 170dd2daaa75..892772eb13e4 100644 --- a/core/res/res/drawable-mdpi/ic_media_ff.png +++ b/core/res/res/drawable-mdpi/ic_media_ff.png diff --git a/core/res/res/drawable-mdpi/ic_media_fullscreen.png b/core/res/res/drawable-mdpi/ic_media_fullscreen.png Binary files differindex 960aa851053e..1c60e1586477 100644 --- a/core/res/res/drawable-mdpi/ic_media_fullscreen.png +++ b/core/res/res/drawable-mdpi/ic_media_fullscreen.png diff --git a/core/res/res/drawable-mdpi/ic_media_next.png b/core/res/res/drawable-mdpi/ic_media_next.png Binary files differindex a6feed0e9e38..bbe311b76fda 100644 --- a/core/res/res/drawable-mdpi/ic_media_next.png +++ b/core/res/res/drawable-mdpi/ic_media_next.png diff --git a/core/res/res/drawable-mdpi/ic_media_pause.png b/core/res/res/drawable-mdpi/ic_media_pause.png Binary files differindex 548ba0219311..e4e8d86b62a6 100644 --- a/core/res/res/drawable-mdpi/ic_media_pause.png +++ b/core/res/res/drawable-mdpi/ic_media_pause.png diff --git a/core/res/res/drawable-mdpi/ic_media_play.png b/core/res/res/drawable-mdpi/ic_media_play.png Binary files differindex 0fe680647e94..8eaf96240ed2 100644 --- a/core/res/res/drawable-mdpi/ic_media_play.png +++ b/core/res/res/drawable-mdpi/ic_media_play.png diff --git a/core/res/res/drawable-mdpi/ic_media_previous.png b/core/res/res/drawable-mdpi/ic_media_previous.png Binary files differindex 0163d094596d..e9abc7f3bd81 100644 --- a/core/res/res/drawable-mdpi/ic_media_previous.png +++ b/core/res/res/drawable-mdpi/ic_media_previous.png diff --git a/core/res/res/drawable-mdpi/ic_media_rew.png b/core/res/res/drawable-mdpi/ic_media_rew.png Binary files differindex 5489180eb16e..a5eb94a25460 100644 --- a/core/res/res/drawable-mdpi/ic_media_rew.png +++ b/core/res/res/drawable-mdpi/ic_media_rew.png diff --git a/core/res/res/drawable-mdpi/ic_menu_moreoverflow_normal_holo_dark.png b/core/res/res/drawable-mdpi/ic_menu_moreoverflow_normal_holo_dark.png Binary files differindex 135ca6e86028..1d2592a9eeaa 100644 --- a/core/res/res/drawable-mdpi/ic_menu_moreoverflow_normal_holo_dark.png +++ b/core/res/res/drawable-mdpi/ic_menu_moreoverflow_normal_holo_dark.png diff --git a/core/res/res/drawable-mdpi/ic_menu_moreoverflow_normal_holo_light.png b/core/res/res/drawable-mdpi/ic_menu_moreoverflow_normal_holo_light.png Binary files differindex ccbf143b02b1..4060afe2362f 100644 --- a/core/res/res/drawable-mdpi/ic_menu_moreoverflow_normal_holo_light.png +++ b/core/res/res/drawable-mdpi/ic_menu_moreoverflow_normal_holo_light.png diff --git a/core/res/res/drawable-xhdpi/ab_bottom_solid_dark_holo.9.png b/core/res/res/drawable-xhdpi/ab_bottom_solid_dark_holo.9.png Binary files differindex 506cd68ffc55..575334699663 100644 --- a/core/res/res/drawable-xhdpi/ab_bottom_solid_dark_holo.9.png +++ b/core/res/res/drawable-xhdpi/ab_bottom_solid_dark_holo.9.png diff --git a/core/res/res/drawable-xhdpi/ab_bottom_solid_inverse_holo.9.png b/core/res/res/drawable-xhdpi/ab_bottom_solid_inverse_holo.9.png Binary files differindex c185112e4c61..7e6c047d6651 100644 --- a/core/res/res/drawable-xhdpi/ab_bottom_solid_inverse_holo.9.png +++ b/core/res/res/drawable-xhdpi/ab_bottom_solid_inverse_holo.9.png diff --git a/core/res/res/drawable-xhdpi/ab_bottom_solid_light_holo.9.png b/core/res/res/drawable-xhdpi/ab_bottom_solid_light_holo.9.png Binary files differindex 8ed7f9b718c2..8155fe840532 100644 --- a/core/res/res/drawable-xhdpi/ab_bottom_solid_light_holo.9.png +++ b/core/res/res/drawable-xhdpi/ab_bottom_solid_light_holo.9.png diff --git a/core/res/res/drawable-xhdpi/ab_bottom_transparent_dark_holo.9.png b/core/res/res/drawable-xhdpi/ab_bottom_transparent_dark_holo.9.png Binary files differindex c4694cdb5403..6cee9a128d77 100644 --- a/core/res/res/drawable-xhdpi/ab_bottom_transparent_dark_holo.9.png +++ b/core/res/res/drawable-xhdpi/ab_bottom_transparent_dark_holo.9.png diff --git a/core/res/res/drawable-xhdpi/ab_bottom_transparent_light_holo.9.png b/core/res/res/drawable-xhdpi/ab_bottom_transparent_light_holo.9.png Binary files differindex 57f5cfa2b67e..fa4d76af93de 100644 --- a/core/res/res/drawable-xhdpi/ab_bottom_transparent_light_holo.9.png +++ b/core/res/res/drawable-xhdpi/ab_bottom_transparent_light_holo.9.png diff --git a/core/res/res/drawable-xhdpi/ab_solid_dark_holo.9.png b/core/res/res/drawable-xhdpi/ab_solid_dark_holo.9.png Binary files differindex d16e50cc351d..6622cbad3440 100644 --- a/core/res/res/drawable-xhdpi/ab_solid_dark_holo.9.png +++ b/core/res/res/drawable-xhdpi/ab_solid_dark_holo.9.png diff --git a/core/res/res/drawable-xhdpi/ab_solid_light_holo.9.png b/core/res/res/drawable-xhdpi/ab_solid_light_holo.9.png Binary files differindex 45cc8074e9c7..c4272978338a 100644 --- a/core/res/res/drawable-xhdpi/ab_solid_light_holo.9.png +++ b/core/res/res/drawable-xhdpi/ab_solid_light_holo.9.png diff --git a/core/res/res/drawable-xhdpi/ab_solid_shadow_holo.9.png b/core/res/res/drawable-xhdpi/ab_solid_shadow_holo.9.png Binary files differindex a9e0d4d5bc66..d0df29d8b3fe 100644 --- a/core/res/res/drawable-xhdpi/ab_solid_shadow_holo.9.png +++ b/core/res/res/drawable-xhdpi/ab_solid_shadow_holo.9.png diff --git a/core/res/res/drawable-xhdpi/ab_stacked_solid_dark_holo.9.png b/core/res/res/drawable-xhdpi/ab_stacked_solid_dark_holo.9.png Binary files differindex 5ea235dea8e1..a0d9c1b957ea 100644 --- a/core/res/res/drawable-xhdpi/ab_stacked_solid_dark_holo.9.png +++ b/core/res/res/drawable-xhdpi/ab_stacked_solid_dark_holo.9.png diff --git a/core/res/res/drawable-xhdpi/ab_stacked_solid_inverse_holo.9.png b/core/res/res/drawable-xhdpi/ab_stacked_solid_inverse_holo.9.png Binary files differindex 0220c8dbab61..16b9bef1267a 100644 --- a/core/res/res/drawable-xhdpi/ab_stacked_solid_inverse_holo.9.png +++ b/core/res/res/drawable-xhdpi/ab_stacked_solid_inverse_holo.9.png diff --git a/core/res/res/drawable-xhdpi/ab_stacked_solid_light_holo.9.png b/core/res/res/drawable-xhdpi/ab_stacked_solid_light_holo.9.png Binary files differindex be13077ac2df..d36f99fecf22 100644 --- a/core/res/res/drawable-xhdpi/ab_stacked_solid_light_holo.9.png +++ b/core/res/res/drawable-xhdpi/ab_stacked_solid_light_holo.9.png diff --git a/core/res/res/drawable-xhdpi/ab_stacked_transparent_dark_holo.9.png b/core/res/res/drawable-xhdpi/ab_stacked_transparent_dark_holo.9.png Binary files differindex ab02e7a371c3..5ad475dc3f47 100644 --- a/core/res/res/drawable-xhdpi/ab_stacked_transparent_dark_holo.9.png +++ b/core/res/res/drawable-xhdpi/ab_stacked_transparent_dark_holo.9.png diff --git a/core/res/res/drawable-xhdpi/ab_stacked_transparent_light_holo.9.png b/core/res/res/drawable-xhdpi/ab_stacked_transparent_light_holo.9.png Binary files differindex 0b5a24e06e67..6ade5eeb37d8 100644 --- a/core/res/res/drawable-xhdpi/ab_stacked_transparent_light_holo.9.png +++ b/core/res/res/drawable-xhdpi/ab_stacked_transparent_light_holo.9.png diff --git a/core/res/res/drawable-xhdpi/ab_transparent_dark_holo.9.png b/core/res/res/drawable-xhdpi/ab_transparent_dark_holo.9.png Binary files differindex 6d21429b60fb..719b9234df6f 100644 --- a/core/res/res/drawable-xhdpi/ab_transparent_dark_holo.9.png +++ b/core/res/res/drawable-xhdpi/ab_transparent_dark_holo.9.png diff --git a/core/res/res/drawable-xhdpi/ab_transparent_light_holo.9.png b/core/res/res/drawable-xhdpi/ab_transparent_light_holo.9.png Binary files differindex c34c46f94c74..6da264db26b5 100644 --- a/core/res/res/drawable-xhdpi/ab_transparent_light_holo.9.png +++ b/core/res/res/drawable-xhdpi/ab_transparent_light_holo.9.png diff --git a/core/res/res/drawable-xhdpi/btn_cab_done_default_holo_dark.9.png b/core/res/res/drawable-xhdpi/btn_cab_done_default_holo_dark.9.png Binary files differindex a338924ed538..01efef4b7ce4 100644 --- a/core/res/res/drawable-xhdpi/btn_cab_done_default_holo_dark.9.png +++ b/core/res/res/drawable-xhdpi/btn_cab_done_default_holo_dark.9.png diff --git a/core/res/res/drawable-xhdpi/btn_cab_done_default_holo_light.9.png b/core/res/res/drawable-xhdpi/btn_cab_done_default_holo_light.9.png Binary files differindex 6f2d3e59375a..c28760571132 100644 --- a/core/res/res/drawable-xhdpi/btn_cab_done_default_holo_light.9.png +++ b/core/res/res/drawable-xhdpi/btn_cab_done_default_holo_light.9.png diff --git a/core/res/res/drawable-xhdpi/btn_cab_done_focused_holo_dark.9.png b/core/res/res/drawable-xhdpi/btn_cab_done_focused_holo_dark.9.png Binary files differindex faa36b0f2ab8..9a496e8ca148 100644 --- a/core/res/res/drawable-xhdpi/btn_cab_done_focused_holo_dark.9.png +++ b/core/res/res/drawable-xhdpi/btn_cab_done_focused_holo_dark.9.png diff --git a/core/res/res/drawable-xhdpi/btn_cab_done_focused_holo_light.9.png b/core/res/res/drawable-xhdpi/btn_cab_done_focused_holo_light.9.png Binary files differindex c57f3ff6c97b..e2a38b4680f9 100644 --- a/core/res/res/drawable-xhdpi/btn_cab_done_focused_holo_light.9.png +++ b/core/res/res/drawable-xhdpi/btn_cab_done_focused_holo_light.9.png diff --git a/core/res/res/drawable-xhdpi/btn_cab_done_pressed_holo_dark.9.png b/core/res/res/drawable-xhdpi/btn_cab_done_pressed_holo_dark.9.png Binary files differindex 9d6402f296ee..911722f21c0c 100644 --- a/core/res/res/drawable-xhdpi/btn_cab_done_pressed_holo_dark.9.png +++ b/core/res/res/drawable-xhdpi/btn_cab_done_pressed_holo_dark.9.png diff --git a/core/res/res/drawable-xhdpi/btn_cab_done_pressed_holo_light.9.png b/core/res/res/drawable-xhdpi/btn_cab_done_pressed_holo_light.9.png Binary files differindex bfd966c2ff8d..da169bf42f5f 100644 --- a/core/res/res/drawable-xhdpi/btn_cab_done_pressed_holo_light.9.png +++ b/core/res/res/drawable-xhdpi/btn_cab_done_pressed_holo_light.9.png diff --git a/core/res/res/drawable-xhdpi/cab_background_bottom_holo_dark.9.png b/core/res/res/drawable-xhdpi/cab_background_bottom_holo_dark.9.png Binary files differindex 2bd8cee41cd8..0bd09806f5c8 100644 --- a/core/res/res/drawable-xhdpi/cab_background_bottom_holo_dark.9.png +++ b/core/res/res/drawable-xhdpi/cab_background_bottom_holo_dark.9.png diff --git a/core/res/res/drawable-xhdpi/cab_background_bottom_holo_light.9.png b/core/res/res/drawable-xhdpi/cab_background_bottom_holo_light.9.png Binary files differindex d254e77541e0..43ed26d4784a 100644 --- a/core/res/res/drawable-xhdpi/cab_background_bottom_holo_light.9.png +++ b/core/res/res/drawable-xhdpi/cab_background_bottom_holo_light.9.png diff --git a/core/res/res/drawable-xhdpi/cab_background_top_holo_dark.9.png b/core/res/res/drawable-xhdpi/cab_background_top_holo_dark.9.png Binary files differindex 919eac07d15d..6b3157985ea5 100644 --- a/core/res/res/drawable-xhdpi/cab_background_top_holo_dark.9.png +++ b/core/res/res/drawable-xhdpi/cab_background_top_holo_dark.9.png diff --git a/core/res/res/drawable-xhdpi/cab_background_top_holo_light.9.png b/core/res/res/drawable-xhdpi/cab_background_top_holo_light.9.png Binary files differindex 1357105786e4..df0121bb353f 100644 --- a/core/res/res/drawable-xhdpi/cab_background_top_holo_light.9.png +++ b/core/res/res/drawable-xhdpi/cab_background_top_holo_light.9.png diff --git a/core/res/res/drawable-xhdpi/ic_lockscreen_player_background.9.png b/core/res/res/drawable-xhdpi/ic_lockscreen_player_background.9.png Binary files differnew file mode 100644 index 000000000000..7fb0cbc91b95 --- /dev/null +++ b/core/res/res/drawable-xhdpi/ic_lockscreen_player_background.9.png diff --git a/core/res/res/drawable-xhdpi/ic_menu_moreoverflow_normal_holo_dark.png b/core/res/res/drawable-xhdpi/ic_menu_moreoverflow_normal_holo_dark.png Binary files differindex 81306cae6aa4..1ce25e2e419c 100644 --- a/core/res/res/drawable-xhdpi/ic_menu_moreoverflow_normal_holo_dark.png +++ b/core/res/res/drawable-xhdpi/ic_menu_moreoverflow_normal_holo_dark.png diff --git a/core/res/res/drawable-xhdpi/ic_menu_moreoverflow_normal_holo_light.png b/core/res/res/drawable-xhdpi/ic_menu_moreoverflow_normal_holo_light.png Binary files differindex 1f46e7afc84e..dcd6514a9bf7 100644 --- a/core/res/res/drawable-xhdpi/ic_menu_moreoverflow_normal_holo_light.png +++ b/core/res/res/drawable-xhdpi/ic_menu_moreoverflow_normal_holo_light.png diff --git a/core/res/res/layout-sw600dp/keyguard_screen_status_land.xml b/core/res/res/layout-sw600dp/keyguard_screen_status_land.xml index f3850d5d02d4..3a7c1e1c4bf9 100644 --- a/core/res/res/layout-sw600dp/keyguard_screen_status_land.xml +++ b/core/res/res/layout-sw600dp/keyguard_screen_status_land.xml @@ -42,11 +42,8 @@ <com.android.internal.widget.DigitalClock android:id="@+id/time" android:layout_width="wrap_content" android:layout_height="wrap_content" - android:layout_alignParentTop="true" - android:layout_alignParentLeft="true" android:layout_marginTop="8dip" android:layout_marginBottom="8dip" - android:layout_marginLeft="-10dip" > <!-- Because we can't have multi-tone fonts, we render two TextViews, one on diff --git a/core/res/res/layout-sw600dp/keyguard_screen_status_port.xml b/core/res/res/layout-sw600dp/keyguard_screen_status_port.xml index f4c99f106403..c02341e4bc23 100644 --- a/core/res/res/layout-sw600dp/keyguard_screen_status_port.xml +++ b/core/res/res/layout-sw600dp/keyguard_screen_status_port.xml @@ -45,8 +45,7 @@ android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginTop="8dip" - android:layout_marginBottom="8dip" - android_layout_marginLeft="-10dip"> + android:layout_marginBottom="8dip"> <!-- Because we can't have multi-tone fonts, we render two TextViews, one on top of the other. Hence the redundant layout... --> diff --git a/core/res/res/layout/keyguard_screen_password_landscape.xml b/core/res/res/layout/keyguard_screen_password_landscape.xml index 12df99ef414a..694db50a84ee 100644 --- a/core/res/res/layout/keyguard_screen_password_landscape.xml +++ b/core/res/res/layout/keyguard_screen_password_landscape.xml @@ -186,6 +186,8 @@ android:layout_rowSpan="6" android:layout_columnSpan="1" android:layout_gravity="fill" + android:layout_width="0dip" + android:layout_height="0dip" /> </GridLayout> diff --git a/core/res/res/layout/keyguard_screen_password_portrait.xml b/core/res/res/layout/keyguard_screen_password_portrait.xml index 6145e47fb871..cf3bd4239a06 100644 --- a/core/res/res/layout/keyguard_screen_password_portrait.xml +++ b/core/res/res/layout/keyguard_screen_password_portrait.xml @@ -174,6 +174,8 @@ android:layout_rowSpan="3" android:layout_columnSpan="1" android:layout_gravity="fill" + android:layout_width="0dip" + android:layout_height="0dip" /> </GridLayout> diff --git a/core/res/res/layout/keyguard_screen_tab_unlock.xml b/core/res/res/layout/keyguard_screen_tab_unlock.xml index 6016d4e3dc6a..4c8c0d1ef340 100644 --- a/core/res/res/layout/keyguard_screen_tab_unlock.xml +++ b/core/res/res/layout/keyguard_screen_tab_unlock.xml @@ -130,6 +130,8 @@ android:layout_alignParentBottom="true" android:targetDrawables="@array/lockscreen_targets_with_camera" + android:targetDescriptions="@array/lockscreen_target_descriptions_with_camera" + android:directionDescriptions="@array/lockscreen_direction_descriptions_with_camera" android:handleDrawable="@drawable/ic_lockscreen_handle" android:waveDrawable="@drawable/ic_lockscreen_outerring" android:outerRadius="@dimen/multiwaveview_target_placement_radius" @@ -188,6 +190,8 @@ android:layout_rowSpan="4" android:layout_columnSpan="1" android:layout_gravity="fill" + android:layout_width="0dip" + android:layout_height="0dip" /> </GridLayout> diff --git a/core/res/res/layout/keyguard_screen_tab_unlock_land.xml b/core/res/res/layout/keyguard_screen_tab_unlock_land.xml index 0568dd9ba82d..ba55f0c078d4 100644 --- a/core/res/res/layout/keyguard_screen_tab_unlock_land.xml +++ b/core/res/res/layout/keyguard_screen_tab_unlock_land.xml @@ -135,6 +135,8 @@ android:layout_rowSpan="7" android:targetDrawables="@array/lockscreen_targets_with_camera" + android:targetDescriptions="@array/lockscreen_target_descriptions_with_camera" + android:directionDescriptions="@array/lockscreen_direction_descriptions_with_camera" android:handleDrawable="@drawable/ic_lockscreen_handle" android:waveDrawable="@drawable/ic_lockscreen_outerring" android:outerRadius="@dimen/multiwaveview_target_placement_radius" @@ -155,6 +157,8 @@ android:layout_rowSpan="5" android:layout_columnSpan="1" android:layout_gravity="fill" + android:layout_width="0dip" + android:layout_height="0dip" /> </GridLayout> diff --git a/core/res/res/layout/keyguard_screen_unlock_landscape.xml b/core/res/res/layout/keyguard_screen_unlock_landscape.xml index 9b287310696d..d71dbffd8f9d 100644 --- a/core/res/res/layout/keyguard_screen_unlock_landscape.xml +++ b/core/res/res/layout/keyguard_screen_unlock_landscape.xml @@ -156,6 +156,8 @@ android:layout_rowSpan="5" android:layout_columnSpan="1" android:layout_gravity="fill" + android:layout_width="0dip" + android:layout_height="0dip" /> </GridLayout> diff --git a/core/res/res/layout/keyguard_screen_unlock_portrait.xml b/core/res/res/layout/keyguard_screen_unlock_portrait.xml index 433dda7c4eff..64c479f32c52 100644 --- a/core/res/res/layout/keyguard_screen_unlock_portrait.xml +++ b/core/res/res/layout/keyguard_screen_unlock_portrait.xml @@ -167,6 +167,8 @@ android:layout_rowSpan="4" android:layout_columnSpan="1" android:layout_gravity="fill" + android:layout_width="0dip" + android:layout_height="0dip" /> </GridLayout> diff --git a/core/res/res/layout/keyguard_transport_control.xml b/core/res/res/layout/keyguard_transport_control.xml index 6308b02dff79..2ebe5fceddc2 100644 --- a/core/res/res/layout/keyguard_transport_control.xml +++ b/core/res/res/layout/keyguard_transport_control.xml @@ -1,53 +1,102 @@ <?xml version="1.0" encoding="utf-8"?> -<!-- -** -** Copyright 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. -*/ +<!-- Copyright (C) 2011 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. --> +<!-- Note: This file is meant to be included in various password unlock screens. As such, + LayoutParams (layout_*) for TransportControlView should *NOT* be specified here, + but rather as include tags for this file or the layout will break. --> <com.android.internal.widget.TransportControlView xmlns:android="http://schemas.android.com/apk/res/android" - android:gravity="bottom" - android:orientation="horizontal" - android:background="#a0808080" - android:visibility="gone"> + android:id="@+id/transport_controls" + android:background="@drawable/ic_lockscreen_player_background"> - <Button android:id="@+id/control_prev" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:background="#80ff0000" + <ImageView + android:id="@+id/albumart" + android:layout_width="match_parent" + android:layout_height="match_parent" + android:layout_gravity="fill" + android:scaleType="centerCrop" + android:adjustViewBounds="false" /> - <Space android:layout_width="0dip" - android:layout_height="0dip" - android:layout_weight="1"/> - - <Button android:id="@+id/control_pauseplay" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:background="#8000ff00" - /> - - <Space android:layout_width="0dip" - android:layout_height="0dip" - android:layout_weight="1"/> - - <Button android:id="@+id/control_next" - android:layout_width="wrap_content" + <LinearLayout + android:orientation="vertical" + android:layout_width="match_parent" android:layout_height="wrap_content" - android:background="#800000ff" + android:background="#c8000000" + android:layout_gravity="bottom"> + <TextView + android:id="@+id/title" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_marginTop="8dip" + android:layout_marginLeft="16dip" + android:layout_marginRight="16dip" + android:gravity="center_horizontal" + android:singleLine="true" + android:ellipsize="end" + android:textAppearance="?android:attr/textAppearanceMedium" /> + <LinearLayout + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:orientation="horizontal" + android:layout_marginTop="5dip"> + <FrameLayout + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_weight="1"> + <ImageView + android:id="@+id/btn_prev" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_gravity="center" + android:src="@drawable/ic_media_rew" + android:clickable="true" + android:background="?android:attr/selectableItemBackground" + android:padding="10dip"/> + </FrameLayout> + <FrameLayout + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_weight="1"> + <ImageView + android:id="@+id/btn_play" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_gravity="center" + android:clickable="true" + android:src="@drawable/ic_media_play" + android:background="?android:attr/selectableItemBackground" + android:padding="10dip"/> + </FrameLayout> + <FrameLayout + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_weight="1"> + <ImageView + android:id="@+id/btn_next" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_gravity="center" + android:clickable="true" + android:src="@drawable/ic_media_ff" + android:background="?android:attr/selectableItemBackground" + android:padding="10dip"/> + </FrameLayout> + </LinearLayout> + </LinearLayout> </com.android.internal.widget.TransportControlView> diff --git a/core/res/res/values-land/arrays.xml b/core/res/res/values-land/arrays.xml index fd492ec081fe..57aafc8cf790 100644 --- a/core/res/res/values-land/arrays.xml +++ b/core/res/res/values-land/arrays.xml @@ -27,13 +27,41 @@ <item>@drawable/ic_lockscreen_soundon</item> </array> + <array name="lockscreen_target_descriptions_when_silent"> + <item>@null</item> + <item>@string/description_target_unlock</item> + <item>@null</item> + <item>@string/description_target_soundon</item> + </array> + + <array name="lockscreen_direction_descriptions_when_silent"> + <item>@null</item> + <item>@string/description_direction_up</item> + <item>@null</item> + <item>@string/description_direction_down</item> + </array> + <array name="lockscreen_targets_when_soundon"> - <item>@null</item>" + <item>@null</item> <item>@drawable/ic_lockscreen_unlock</item> <item>@null</item> <item>@drawable/ic_lockscreen_silent</item> </array> + <array name="lockscreen_target_descriptions_when_soundon"> + <item>@null</item> + <item>@string/description_target_unlock</item> + <item>@null</item> + <item>@string/description_target_silent</item> + </array> + + <array name="lockscreen_direction_descriptions_when_soundon"> + <item>@null</item> + <item>@string/description_direction_up</item> + <item>@null</item> + <item>@string/description_direction_down</item> + </array> + <array name="lockscreen_targets_with_camera"> <item>@null</item> <item>@drawable/ic_lockscreen_unlock</item> @@ -41,4 +69,18 @@ <item>@drawable/ic_lockscreen_camera</item> </array> + <array name="lockscreen_target_descriptions_with_camera"> + <item>@null</item> + <item>@string/description_target_unlock</item> + <item>@null</item> + <item>@string/description_target_camera</item> + </array> + + <array name="lockscreen_direction_descriptions_with_camera"> + <item>@null</item> + <item>@string/description_direction_up</item> + <item>@null</item> + <item>@string/description_direction_down</item> + </array> + </resources> diff --git a/core/res/res/values-sw600dp/colors.xml b/core/res/res/values-sw600dp/colors.xml index 6b5a55a3a0d5..edd2712ecfb0 100644 --- a/core/res/res/values-sw600dp/colors.xml +++ b/core/res/res/values-sw600dp/colors.xml @@ -21,7 +21,7 @@ <!-- keyguard clock --> <color name="lockscreen_clock_background">#b3ffffff</color> <color name="lockscreen_clock_foreground">#7affffff</color> - <color name="lockscreen_clock_am_pm">#ff9a9a9a</color> + <color name="lockscreen_clock_am_pm">#ffffffff</color> <color name="lockscreen_owner_info">#ff9a9a9a</color> </resources> diff --git a/core/res/res/values/arrays.xml b/core/res/res/values/arrays.xml index 57e9bbfec50e..c9043ba26889 100644 --- a/core/res/res/values/arrays.xml +++ b/core/res/res/values/arrays.xml @@ -349,18 +349,60 @@ <item>@null</item> </array> + <array name="lockscreen_target_descriptions_when_silent"> + <item>@string/description_target_unlock</item> + <item>@null</item> + <item>@string/description_target_soundon</item> + <item>@null</item> + </array> + + <array name="lockscreen_direction_descriptions_when_silent"> + <item>@string/description_direction_right</item> + <item>@null</item> + <item>@string/description_direction_left</item> + <item>@null</item> + </array> + <array name="lockscreen_targets_when_soundon"> <item>@drawable/ic_lockscreen_unlock</item> <item>@null</item> <item>@drawable/ic_lockscreen_silent</item> - <item>@null</item>" + <item>@null</item> + </array> + + <array name="lockscreen_target_descriptions_when_soundon"> + <item>@string/description_target_unlock</item> + <item>@null</item> + <item>@string/description_target_silent</item> + <item>@null</item> + </array> + + <array name="lockscreen_direction_descriptions_when_soundon"> + <item>@string/description_direction_right</item> + <item>@null</item> + <item>@string/description_direction_left</item> + <item>@null</item> </array> <array name="lockscreen_targets_with_camera"> <item>@drawable/ic_lockscreen_unlock</item> <item>@null</item> <item>@drawable/ic_lockscreen_camera</item> - <item>@null</item>" + <item>@null</item> + </array> + + <array name="lockscreen_target_descriptions_with_camera"> + <item>@string/description_target_unlock</item> + <item>@null</item> + <item>@string/description_target_camera</item> + <item>@null</item> + </array> + + <array name="lockscreen_direction_descriptions_with_camera"> + <item>@string/description_direction_right</item> + <item>@null</item> + <item>@string/description_direction_left</item> + <item>@null</item> </array> </resources> diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml index dae9f70d4fea..fed56511372e 100755 --- a/core/res/res/values/attrs.xml +++ b/core/res/res/values/attrs.xml @@ -158,11 +158,14 @@ <!-- The underline color and thickness for misspelled suggestion --> <attr name="textAppearanceMisspelledSuggestion" format="reference" /> + <!-- The text color and the background for suggestion range span. This span identifies the + portion of text the suggestions refer to). --> + <attr name="textAppearanceSuggestionRange" format="reference" /> + <!-- The underline color --> <attr name="textUnderlineColor" format="reference|color" /> - <!-- The underline thickness, expressed as a percentage of the default underline thickness - (i.e., 100 means default thickness, and 200 means double thickness). --> - <attr name="textUnderlineThicknessPercentage" format="reference|integer" /> + <!-- The underline thickness --> + <attr name="textUnderlineThickness" format="reference|dimension" /> <!-- EditText text foreground color. --> <attr name="editTextColor" format="reference|color" /> @@ -3149,7 +3152,11 @@ </declare-styleable> <declare-styleable name="SuggestionSpan"> <attr name="textUnderlineColor" /> - <attr name="textUnderlineThicknessPercentage" /> + <attr name="textUnderlineThickness" /> + </declare-styleable> + <declare-styleable name="SuggestionRangeSpan"> + <attr name="textColor" /> + <attr name="colorBackground" /> </declare-styleable> <!-- An <code>input-extras</code> is a container for extra data to supply to an input method. Contains @@ -5169,6 +5176,12 @@ <!-- Reference to an array resource that be shown as targets around a circle. --> <attr name="targetDrawables" format="reference"/> + <!-- Reference to an array resource that be used as description for the targets around the circle. --> + <attr name="targetDescriptions" format="reference"/> + + <!-- Reference to an array resource that be used to announce the directions with targets around the circle. --> + <attr name="directionDescriptions" format="reference"/> + <!-- Sets a drawable as the drag center. --> <attr name="handleDrawable" format="reference" /> diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml index b155b8036d20..051ed140f63d 100755 --- a/core/res/res/values/config.xml +++ b/core/res/res/values/config.xml @@ -189,6 +189,9 @@ <!-- Boolean indicating whether the wifi chipset has p2p support --> <bool translatable="false" name="config_wifi_p2p_support">false</bool> + <!-- Device type information conforming to Annex B format in WiFi Direct specification. + The default represents a dual-mode smartphone --> + <string translatable="false" name="config_wifi_p2p_device_type">10-0050F204-5</string> <!-- Boolean indicating whether the wifi chipset supports background scanning mechanism. This mechanism allows the host to remain in suspend state and the dongle to actively diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml index fcd3bbae0f79..6988f6bacf26 100644 --- a/core/res/res/values/public.xml +++ b/core/res/res/values/public.xml @@ -2006,4 +2006,8 @@ <public type="color" name="holo_orange_dark" /> <public type="color" name="holo_purple" /> <public type="color" name="holo_blue_bright" /> + + <public type="attr" name="targetDescriptions" /> + <public type="attr" name="directionDescriptions" /> + </resources> diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml index 8e0f30007201..a9e2971d6e46 100755 --- a/core/res/res/values/strings.xml +++ b/core/res/res/values/strings.xml @@ -1763,7 +1763,7 @@ --> <skip /> <!-- On the keyguard screen, it shows the carrier the phone is connected to. This is displayed if the phone is not connected to a carrier.--> - <string name="lockscreen_carrier_default">(No service)</string> + <string name="lockscreen_carrier_default">No service.</string> <!-- Shown in the lock screen to tell the user that the screen is locked. --> <string name="lockscreen_screen_locked">Screen locked.</string> @@ -2472,6 +2472,9 @@ <!-- Item on EditText context menu. This action is used to replace the current word by other suggested words, suggested by the IME or the spell checker --> <string name="replace">Replace\u2026</string> + <!-- Item on EditText pop-up window. This action is used to delete the text that the user recently added. [CHAR LIMIT=15] --> + <string name="delete">Delete</string> + <!-- Item on EditText context menu. This action is used to copy a URL from the edit field into the clipboard. --> <string name="copyUrl">Copy URL</string> @@ -3129,6 +3132,29 @@ <!-- Description of the Enter button in a KeyboardView. [CHAR LIMIT=NONE] --> <string name="keyboardview_keycode_enter">Enter</string> + <!-- Slide lock screen --> + + <!-- Description of the sliding handle in the Slide unlock screen. [CHAR LIMIT=NONE] --> + <string name="content_description_sliding_handle">"Sliding handle. Tap and hold."</string> + + <!-- Description of the up direction in which one can to slide the handle in the Slide unlock screen. [CHAR LIMIT=NONE] --> + <string name="description_direction_up">"Up</string> + <!-- Description of the down direction in which one can to slide the handle in the Slide unlock screen. [CHAR LIMIT=NONE] --> + <string name="description_direction_down">Down</string> + <!-- Description of the left direction in which one can to slide the handle in the Slide unlock screen. [CHAR LIMIT=NONE] --> + <string name="description_direction_left">"Left</string> + <!-- Description of the right direction in which one can to slide the handle in the Slide unlock screen. [CHAR LIMIT=NONE] --> + <string name="description_direction_right">Right</string> + + <!-- Description of the unlock target in the Slide unlock screen. [CHAR LIMIT=NONE] --> + <string name="description_target_unlock">Unlock</string> + <!-- Description of the camera target in the Slide unlock screen. [CHAR LIMIT=NONE] --> + <string name="description_target_camera">Camera</string> + <!-- Description of the silent target in the Slide unlock screen. [CHAR LIMIT=NONE] --> + <string name="description_target_silent">Silent</string> + <!-- Description of the sound on target in the Slide unlock screen. [CHAR LIMIT=NONE] --> + <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> diff --git a/core/res/res/values/styles.xml b/core/res/res/values/styles.xml index 052a040b09e3..1a2ad05bb2d8 100644 --- a/core/res/res/values/styles.xml +++ b/core/res/res/values/styles.xml @@ -244,7 +244,7 @@ please see styles_device_defaults.xml. </style> <style name="TextAppearance.Suggestion"> - <item name="android:textUnderlineThicknessPercentage">200</item> + <item name="android:textUnderlineThickness">2dip</item> </style> <style name="TextAppearance.EasyCorrectSuggestion" parent="TextAppearance.Suggestion"> @@ -255,6 +255,11 @@ please see styles_device_defaults.xml. <item name="android:textUnderlineColor">@color/holo_red_light</item> </style> + <style name="TextAppearance.SuggestionRange"> + <item name="android:textColor">@color/white</item> + <item name="android:colorBackground">@color/holo_blue_dark</item> + </style> + <!-- Widget Styles --> <style name="Widget"> diff --git a/core/res/res/values/themes.xml b/core/res/res/values/themes.xml index f434ce8af06f..899c9d52eb44 100644 --- a/core/res/res/values/themes.xml +++ b/core/res/res/values/themes.xml @@ -91,6 +91,7 @@ please see themes_device_defaults.xml. <item name="textAppearanceEasyCorrectSuggestion">@android:style/TextAppearance.EasyCorrectSuggestion</item> <item name="textAppearanceMisspelledSuggestion">@android:style/TextAppearance.MisspelledSuggestion</item> + <item name="textAppearanceSuggestionRange">@android:style/TextAppearance.SuggestionRange</item> <item name="textAppearanceButton">@android:style/TextAppearance.Widget.Button</item> diff --git a/data/fonts/DroidSansFallback.ttf b/data/fonts/DroidSansFallback.ttf Binary files differindex 03ceae5df855..ba9d76f0c8fa 100644 --- a/data/fonts/DroidSansFallback.ttf +++ b/data/fonts/DroidSansFallback.ttf diff --git a/data/fonts/DroidSansFallbackFull.ttf b/data/fonts/DroidSansFallbackFull.ttf Binary files differnew file mode 100644 index 000000000000..03ceae5df855 --- /dev/null +++ b/data/fonts/DroidSansFallbackFull.ttf diff --git a/docs/html/sdk/ndk/index.jd b/docs/html/sdk/ndk/index.jd index 97df84f1df49..f87e1f6be976 100644 --- a/docs/html/sdk/ndk/index.jd +++ b/docs/html/sdk/ndk/index.jd @@ -1,16 +1,16 @@ ndk=true -ndk.win_download=android-ndk-r6-windows.zip -ndk.win_bytes=67642809 -ndk.win_checksum=9c7d5ccc02151a3e5e950c70dc05ac6d +ndk.win_download=android-ndk-r6b-windows.zip +ndk.win_bytes=67670219 +ndk.win_checksum=f496b48fffb6d341303de170a081b812 -ndk.mac_download=android-ndk-r6-darwin-x86.tar.bz2 -ndk.mac_bytes=52682746 -ndk.mac_checksum=a154905e49a6246abd823b75b6eda738 +ndk.mac_download=android-ndk-r6b-darwin-x86.tar.bz2 +ndk.mac_bytes=52798843 +ndk.mac_checksum=65f2589ac1b08aabe3183f9ed1a8ce8e -ndk.linux_download=android-ndk-r6-linux-x86.tar.bz2 -ndk.linux_bytes=46425290 -ndk.linux_checksum=ff0a43085fe206696d5cdcef3f4f4637 +ndk.linux_download=android-ndk-r6b-linux-x86.tar.bz2 +ndk.linux_bytes=46532436 +ndk.linux_checksum=309f35e49b64313cfb20ac428df4cec2 page.title=Android NDK @jd:body @@ -58,10 +58,42 @@ padding: .25em 1em; } </style> - <div class="toggleable open"> <a href="#" onclick="return toggleDiv(this)"><img src= "{@docRoot}assets/images/triangle-opened.png" class="toggle-img" height="9px" width="9px"> + Android NDK, Revision 6b</a> <em>(August 2011)</em> + + <div class="toggleme"> + <p>This release of the NDK does not include any new features compared to r6. The r6b release + addresses the following issues in the r6 release:</p> + <dl> + <dt>Important bug fixes</dt> + <dd> + <ul> + <li>Fixed the build when <code>APP_ABI="armeabi x86"</code> is used for + multi-architecture builds.</li> + <li>Fixed the location of prebuilt STLport binaries in the NDK release package. + A bug in the packaging script placed them in the wrong location.</li> + <li>Fixed <code>atexit()</code> usage in shared libraries with the x86standalone + toolchain.</li> + <li>Fixed <code>make-standalone-toolchain.sh --arch=x86</code>. It used to fail + to copy the proper GNU libstdc++ binaries to the right location.</li> + <li>Fixed the standalone toolchain linker warnings about missing the definition and + size for the <code>__dso_handle</code> symbol (ARM only).</li> + <li>Fixed the inclusion order of <code>$(SYSROOT)/usr/include</code> for x86 builds. + See the <a href="http://code.google.com/p/android/issues/detail?id=18540">bug</a> for + more information.</li> + <li>Fixed the definitions of <code>ptrdiff_t</code> and <code>size_t</code> in + x86-specific systems when they are used with the x86 standalone toolchain.</li> + </ul> + </dd> + </dl> + </div> +</div> + +<div class="toggleable closed"> + <a href="#" onclick="return toggleDiv(this)"><img src= + "{@docRoot}assets/images/triangle-closed.png" class="toggle-img" height="9px" width="9px"> Android NDK, Revision 6</a> <em>(July 2011)</em> <div class="toggleme"> diff --git a/docs/html/sdk/sdk_toc.cs b/docs/html/sdk/sdk_toc.cs index 1b1fc8d3dbf0..a00ca125a6cf 100644 --- a/docs/html/sdk/sdk_toc.cs +++ b/docs/html/sdk/sdk_toc.cs @@ -183,7 +183,7 @@ r3</a> <span class="new">new!</span></li> <span style="display:none" class="zh-TW"></span> </h2> <ul> - <li><a href="<?cs var:toroot ?>sdk/ndk/index.html">Android NDK, r6</a> + <li><a href="<?cs var:toroot ?>sdk/ndk/index.html">Android NDK, r6b</a> <span class="new">new!</span> </li> <li><a href="<?cs var:toroot ?>sdk/ndk/overview.html">What is the NDK?</a></li> diff --git a/graphics/java/android/graphics/Paint.java b/graphics/java/android/graphics/Paint.java index cde997e9dd8e..b4d94f3e7177 100644 --- a/graphics/java/android/graphics/Paint.java +++ b/graphics/java/android/graphics/Paint.java @@ -358,22 +358,7 @@ public class Paint { */ public Paint(Paint paint) { mNativePaint = native_initWithPaint(paint.mNativePaint); - mHasCompatScaling = paint.mHasCompatScaling; - mCompatScaling = paint.mCompatScaling; - mInvCompatScaling = paint.mInvCompatScaling; - mBidiFlags = paint.mBidiFlags; - hasShadow = paint.hasShadow; - mColorFilter = paint.mColorFilter; - mMaskFilter = paint.mMaskFilter; - mPathEffect = paint.mPathEffect; - mRasterizer = paint.mRasterizer; - mShader = paint.mShader; - mTypeface = paint.mTypeface; - mXfermode = paint.mXfermode; - shadowColor = paint.shadowColor; - shadowDx = paint.shadowDx; - shadowDy = paint.shadowDy; - shadowRadius = paint.shadowRadius; + setClassVariablesFrom(paint); } /** Restores the paint to its default settings. */ @@ -396,21 +381,36 @@ public class Paint { if (this != src) { // copy over the native settings native_set(mNativePaint, src.mNativePaint); - // copy over our java settings - mColorFilter = src.mColorFilter; - mMaskFilter = src.mMaskFilter; - mPathEffect = src.mPathEffect; - mRasterizer = src.mRasterizer; - mShader = src.mShader; - mTypeface = src.mTypeface; - mXfermode = src.mXfermode; - mHasCompatScaling = src.mHasCompatScaling; - mCompatScaling = src.mCompatScaling; - mInvCompatScaling = src.mInvCompatScaling; - mBidiFlags = src.mBidiFlags; + setClassVariablesFrom(src); } } + /** + * Set all class variables using current values from the given + * {@link Paint}. + */ + private void setClassVariablesFrom(Paint paint) { + mColorFilter = paint.mColorFilter; + mMaskFilter = paint.mMaskFilter; + mPathEffect = paint.mPathEffect; + mRasterizer = paint.mRasterizer; + mShader = paint.mShader; + mTypeface = paint.mTypeface; + mXfermode = paint.mXfermode; + + mHasCompatScaling = paint.mHasCompatScaling; + mCompatScaling = paint.mCompatScaling; + mInvCompatScaling = paint.mInvCompatScaling; + + hasShadow = paint.hasShadow; + shadowDx = paint.shadowDx; + shadowDy = paint.shadowDy; + shadowRadius = paint.shadowRadius; + shadowColor = paint.shadowColor; + + mBidiFlags = paint.mBidiFlags; + } + /** @hide */ public void setCompatibilityScaling(float factor) { if (factor == 1.0) { diff --git a/include/media/AudioSystem.h b/include/media/AudioSystem.h index e0d78980a8ce..6a15f6ec90a6 100644 --- a/include/media/AudioSystem.h +++ b/include/media/AudioSystem.h @@ -185,6 +185,10 @@ public: static status_t unregisterEffect(int id); static status_t setEffectEnabled(int id, bool enabled); + // clear stream to output mapping cache (gStreamOutputMap) + // and output configuration cache (gOutputs) + static void clearAudioConfigCache(); + static const sp<IAudioPolicyService>& get_audio_policy_service(); // ---------------------------------------------------------------------------- @@ -236,7 +240,8 @@ private: // mapping between stream types and outputs static DefaultKeyedVector<int, audio_io_handle_t> gStreamOutputMap; - // list of output descritor containing cached parameters (sampling rate, framecount, channel count...) + // list of output descriptors containing cached parameters + // (sampling rate, framecount, channel count...) static DefaultKeyedVector<audio_io_handle_t, OutputDescriptor *> gOutputs; }; diff --git a/libs/hwui/FontRenderer.cpp b/libs/hwui/FontRenderer.cpp index 9acf99be1a15..dd05e61b41e9 100644 --- a/libs/hwui/FontRenderer.cpp +++ b/libs/hwui/FontRenderer.cpp @@ -394,14 +394,14 @@ void FontRenderer::flushAllAndInvalidate() { bool FontRenderer::cacheBitmap(const SkGlyph& glyph, uint32_t* retOriginX, uint32_t* retOriginY) { // If the glyph is too tall, don't cache it - if (glyph.fHeight > mCacheLines[mCacheLines.size() - 1]->mMaxHeight) { + if (glyph.fHeight + 2 > mCacheLines[mCacheLines.size() - 1]->mMaxHeight) { if (mCacheHeight < MAX_TEXT_CACHE_HEIGHT) { // Default cache not large enough for large glyphs - resize cache to // max size and try again flushAllAndInvalidate(); initTextTexture(true); } - if (glyph.fHeight > mCacheLines[mCacheLines.size() - 1]->mMaxHeight) { + if (glyph.fHeight + 2 > mCacheLines[mCacheLines.size() - 1]->mMaxHeight) { LOGE("Font size to large to fit in cache. width, height = %i, %i", (int) glyph.fWidth, (int) glyph.fHeight); return false; diff --git a/media/java/android/media/AudioService.java b/media/java/android/media/AudioService.java index dbe4115e0c90..bfc6b5d81c59 100644 --- a/media/java/android/media/AudioService.java +++ b/media/java/android/media/AudioService.java @@ -2637,7 +2637,7 @@ public class AudioService extends IAudioService.Stub { notifyTopOfAudioFocusStack(); // there's a new top of the stack, let the remote control know synchronized(mRCStack) { - checkUpdateRemoteControlDisplay(RC_INFO_ALL); + checkUpdateRemoteControlDisplay_syncRcs(RC_INFO_ALL); } } } else { @@ -2680,7 +2680,7 @@ public class AudioService extends IAudioService.Stub { notifyTopOfAudioFocusStack(); // there's a new top of the stack, let the remote control know synchronized(mRCStack) { - checkUpdateRemoteControlDisplay(RC_INFO_ALL); + checkUpdateRemoteControlDisplay_syncRcs(RC_INFO_ALL); } } } @@ -2784,7 +2784,7 @@ public class AudioService extends IAudioService.Stub { // there's a new top of the stack, let the remote control know synchronized(mRCStack) { - checkUpdateRemoteControlDisplay(RC_INFO_ALL); + checkUpdateRemoteControlDisplay_syncRcs(RC_INFO_ALL); } }//synchronized(mAudioFocusLock) @@ -3182,7 +3182,7 @@ public class AudioService extends IAudioService.Stub { * Helper function: * Called synchronized on mRCStack */ - private void clearRemoteControlDisplay() { + private void clearRemoteControlDisplay_syncRcs() { synchronized(mCurrentRcLock) { mCurrentRcClient = null; } @@ -3195,14 +3195,14 @@ public class AudioService extends IAudioService.Stub { * Called synchronized on mRCStack * mRCStack.empty() is false */ - private void updateRemoteControlDisplay(int infoChangedFlags) { + private void updateRemoteControlDisplay_syncRcs(int infoChangedFlags) { RemoteControlStackEntry rcse = mRCStack.peek(); int infoFlagsAboutToBeUsed = infoChangedFlags; // this is where we enforce opt-in for information display on the remote controls // with the new AudioManager.registerRemoteControlClient() API if (rcse.mRcClient == null) { //Log.w(TAG, "Can't update remote control display with null remote control client"); - clearRemoteControlDisplay(); + clearRemoteControlDisplay_syncRcs(); return; } synchronized(mCurrentRcLock) { @@ -3225,11 +3225,11 @@ public class AudioService extends IAudioService.Stub { * that has changed, if applicable (checking for the update conditions might trigger a * clear, rather than an update event). */ - private void checkUpdateRemoteControlDisplay(int infoChangedFlags) { + private void checkUpdateRemoteControlDisplay_syncRcs(int infoChangedFlags) { // determine whether the remote control display should be refreshed // if either stack is empty, there is a mismatch, so clear the RC display if (mRCStack.isEmpty() || mFocusStack.isEmpty()) { - clearRemoteControlDisplay(); + clearRemoteControlDisplay_syncRcs(); return; } // if the top of the two stacks belong to different packages, there is a mismatch, clear @@ -3237,17 +3237,17 @@ public class AudioService extends IAudioService.Stub { && (mFocusStack.peek().mPackageName != null) && !(mRCStack.peek().mCallingPackageName.compareTo( mFocusStack.peek().mPackageName) == 0)) { - clearRemoteControlDisplay(); + clearRemoteControlDisplay_syncRcs(); return; } // if the audio focus didn't originate from the same Uid as the one in which the remote // control information will be retrieved, clear if (mRCStack.peek().mCallingUid != mFocusStack.peek().mCallingUid) { - clearRemoteControlDisplay(); + clearRemoteControlDisplay_syncRcs(); return; } // refresh conditions were verified: update the remote controls - updateRemoteControlDisplay(infoChangedFlags); + updateRemoteControlDisplay_syncRcs(infoChangedFlags); } /** see AudioManager.registerMediaButtonEventReceiver(ComponentName eventReceiver) */ @@ -3258,7 +3258,7 @@ public class AudioService extends IAudioService.Stub { synchronized(mRCStack) { pushMediaButtonReceiver(eventReceiver); // new RC client, assume every type of information shall be queried - checkUpdateRemoteControlDisplay(RC_INFO_ALL); + checkUpdateRemoteControlDisplay_syncRcs(RC_INFO_ALL); } } } @@ -3273,7 +3273,7 @@ public class AudioService extends IAudioService.Stub { removeMediaButtonReceiver(eventReceiver); if (topOfStackWillChange) { // current RC client will change, assume every type of info needs to be queried - checkUpdateRemoteControlDisplay(RC_INFO_ALL); + checkUpdateRemoteControlDisplay_syncRcs(RC_INFO_ALL); } } } @@ -3329,7 +3329,7 @@ public class AudioService extends IAudioService.Stub { // if the eventReceiver is at the top of the stack // then check for potential refresh of the remote controls if (isCurrentRcController(eventReceiver)) { - checkUpdateRemoteControlDisplay(RC_INFO_ALL); + checkUpdateRemoteControlDisplay_syncRcs(RC_INFO_ALL); } } } @@ -3426,7 +3426,9 @@ public class AudioService extends IAudioService.Stub { } /** - * Register an IRemoteControlDisplay and notify all IRemoteControlClient of the new display. + * Register an IRemoteControlDisplay. + * Notify all IRemoteControlClient of the new display and cause the RemoteControlClient + * at the top of the stack to update the new display with its information. * Since only one IRemoteControlDisplay is supported, this will unregister the previous display. * @param rcd the IRemoteControlDisplay to register. No effect if null. */ @@ -3458,20 +3460,8 @@ public class AudioService extends IAudioService.Stub { } } - // we have a new display, tell the current client that it needs to send info - // (following lock order: mRCStack then mCurrentRcLock) - synchronized(mCurrentRcLock) { - if (mCurrentRcClient != null) { - // tell the current client that it needs to send info - try { - mCurrentRcClient.onInformationRequested(mCurrentRcClientGen, - RC_INFO_ALL, mArtworkExpectedWidth, mArtworkExpectedHeight); - } catch (RemoteException e) { - Log.e(TAG, "Current valid remote client is dead: "+e); - mCurrentRcClient = null; - } - } - } + // we have a new display, of which all the clients are now aware: have it be updated + updateRemoteControlDisplay_syncRcs(RC_INFO_ALL); } } diff --git a/media/java/android/media/MediaPlayer.java b/media/java/android/media/MediaPlayer.java index 66bd56a01b3b..1ee9a1fcc52b 100644 --- a/media/java/android/media/MediaPlayer.java +++ b/media/java/android/media/MediaPlayer.java @@ -381,7 +381,7 @@ import java.lang.ref.WeakReference; * <td>{} </p></td> * <td>This method can be called in any state and calling it does not change * the object state. </p></td></tr> - * <tr><td>setTexture </p></td> + * <tr><td>setSurface </p></td> * <td>any </p></td> * <td>{} </p></td> * <td>This method can be called in any state and calling it does not change @@ -608,7 +608,7 @@ public class MediaPlayer * portion of the media. * * Either a surface holder or surface must be set if a display or video sink - * is needed. Not calling this method or {@link #setTexture(SurfaceTexture)} + * is needed. Not calling this method or {@link #setSurface(Surface)} * when playing back a video will result in only the audio track being played. * A null surface holder or surface will result in only the audio track being * played. @@ -629,14 +629,21 @@ public class MediaPlayer /** * Sets the {@link Surface} to be used as the sink for the video portion of - * the media. This is similar to {@link #setDisplay(SurfaceHolder)}, but does not - * support {@link #setScreenOnWhilePlaying(boolean)} or {@link #updateSurfaceScreenOn()}. - * Setting a Surface will un-set any Surface or SurfaceHolder that was previously set. + * the media. This is similar to {@link #setDisplay(SurfaceHolder)}, but + * does not support {@link #setScreenOnWhilePlaying(boolean)}. Setting a + * Surface will un-set any Surface or SurfaceHolder that was previously set. * A null surface will result in only the audio track being played. * - * @param surface The {@link Surface} to be used for the video portion of the media. + * If the Surface sends frames to a {@link SurfaceTexture}, the timestamps + * returned from {@link SurfaceTexture#getTimestamp()} will have an + * unspecified zero point. These timestamps cannot be directly compared + * between different media sources, different instances of the same media + * source, or multiple runs of the same program. The timestamp is normally + * monotonically increasing and is unaffected by time-of-day adjustments, + * but it is reset when the position is set. * - * @hide Pending review by API council. + * @param surface The {@link Surface} to be used for the video portion of + * the media. */ public void setSurface(Surface surface) { if (mScreenOnWhilePlaying && surface != null) { diff --git a/media/java/android/media/videoeditor/VideoEditorProfile.java b/media/java/android/media/videoeditor/VideoEditorProfile.java index ecdcdfbd0324..202a2dfaba51 100755 --- a/media/java/android/media/videoeditor/VideoEditorProfile.java +++ b/media/java/android/media/videoeditor/VideoEditorProfile.java @@ -91,7 +91,7 @@ public class VideoEditorProfile case MediaProperties.VCODEC_H263: case MediaProperties.VCODEC_H264: case MediaProperties.VCODEC_MPEG4: - level = native_get_videoeditor_export_profile(vidCodec); + level = native_get_videoeditor_export_level(vidCodec); break; default : throw new IllegalArgumentException("Unsupported video codec" + vidCodec); diff --git a/media/libmedia/AudioSystem.cpp b/media/libmedia/AudioSystem.cpp index bb91fa96b4d7..853a5f6b4b51 100644 --- a/media/libmedia/AudioSystem.cpp +++ b/media/libmedia/AudioSystem.cpp @@ -727,6 +727,14 @@ status_t AudioSystem::isStreamActive(int stream, bool* state, uint32_t inPastMs) } +void AudioSystem::clearAudioConfigCache() +{ + Mutex::Autolock _l(gLock); + LOGV("clearAudioConfigCache()"); + gStreamOutputMap.clear(); + gOutputs.clear(); +} + // --------------------------------------------------------------------------- void AudioSystem::AudioPolicyServiceClient::binderDied(const wp<IBinder>& who) { diff --git a/media/libmedia/AudioTrack.cpp b/media/libmedia/AudioTrack.cpp index cecedb517d64..3b6c64d5fb51 100644 --- a/media/libmedia/AudioTrack.cpp +++ b/media/libmedia/AudioTrack.cpp @@ -1164,6 +1164,10 @@ status_t AudioTrack::restoreTrack_l(audio_track_cblk_t*& cblk, bool fromStart) cblk->cv.broadcast(); cblk->lock.unlock(); + // refresh the audio configuration cache in this process to make sure we get new + // output parameters in getOutput_l() and createTrack_l() + AudioSystem::clearAudioConfigCache(); + // if the new IAudioTrack is created, createTrack_l() will modify the // following member variables: mAudioTrack, mCblkMemory and mCblk. // It will also delete the strong references on previous IAudioTrack and IMemory diff --git a/media/libstagefright/AACExtractor.cpp b/media/libstagefright/AACExtractor.cpp index a5a6b64bff82..52b120002827 100644 --- a/media/libstagefright/AACExtractor.cpp +++ b/media/libstagefright/AACExtractor.cpp @@ -33,8 +33,6 @@ namespace android { -#define ADTS_HEADER_LENGTH 7 - class AACSource : public MediaSource { public: AACSource(const sp<DataSource> &source, @@ -88,7 +86,16 @@ uint32_t get_sample_rate(const uint8_t sf_index) return 0; } -static size_t getFrameSize(const sp<DataSource> &source, off64_t offset) { +// Returns the frame length in bytes as described in an ADTS header starting at the given offset, +// or 0 if the size can't be read due to an error in the header or a read failure. +// The returned value is the AAC frame size with the ADTS header length (regardless of +// the presence of the CRC). +// If headerSize is non-NULL, it will be used to return the size of the header of this ADTS frame. +static size_t getAdtsFrameLength(const sp<DataSource> &source, off64_t offset, size_t* headerSize) { + + const size_t kAdtsHeaderLengthNoCrc = 7; + const size_t kAdtsHeaderLengthWithCrc = 9; + size_t frameSize = 0; uint8_t syncword[2]; @@ -111,7 +118,15 @@ static size_t getFrameSize(const sp<DataSource> &source, off64_t offset) { } frameSize = (header[0] & 0x3) << 11 | header[1] << 3 | header[2] >> 5; - frameSize += ADTS_HEADER_LENGTH + protectionAbsent ? 0 : 2; + + // protectionAbsent is 0 if there is CRC + size_t headSize = protectionAbsent ? kAdtsHeaderLengthNoCrc : kAdtsHeaderLengthWithCrc; + if (headSize > frameSize) { + return 0; + } + if (headerSize != NULL) { + *headerSize = headSize; + } return frameSize; } @@ -148,7 +163,7 @@ AACExtractor::AACExtractor(const sp<DataSource> &source) if (mDataSource->getSize(&streamSize) == OK) { while (offset < streamSize) { - if ((frameSize = getFrameSize(source, offset)) == 0) { + if ((frameSize = getAdtsFrameLength(source, offset, NULL)) == 0) { return; } @@ -268,8 +283,8 @@ status_t AACSource::read( } } - size_t frameSize, frameSizeWithoutHeader; - if ((frameSize = getFrameSize(mDataSource, mOffset)) == 0) { + size_t frameSize, frameSizeWithoutHeader, headerSize; + if ((frameSize = getAdtsFrameLength(mDataSource, mOffset, &headerSize)) == 0) { return ERROR_END_OF_STREAM; } @@ -279,8 +294,8 @@ status_t AACSource::read( return err; } - frameSizeWithoutHeader = frameSize - ADTS_HEADER_LENGTH; - if (mDataSource->readAt(mOffset + ADTS_HEADER_LENGTH, buffer->data(), + frameSizeWithoutHeader = frameSize - headerSize; + if (mDataSource->readAt(mOffset + headerSize, buffer->data(), frameSizeWithoutHeader) != (ssize_t)frameSizeWithoutHeader) { buffer->release(); buffer = NULL; diff --git a/media/tests/MediaDump/src/com/android/mediadump/VideoDumpView.java b/media/tests/MediaDump/src/com/android/mediadump/VideoDumpView.java index 809ee8208dfc..f76cf37b9763 100644 --- a/media/tests/MediaDump/src/com/android/mediadump/VideoDumpView.java +++ b/media/tests/MediaDump/src/com/android/mediadump/VideoDumpView.java @@ -49,6 +49,7 @@ import android.opengl.Matrix; import android.os.Bundle; import android.util.Log; import android.view.MotionEvent; +import android.view.Surface; import android.view.SurfaceHolder; import android.view.View; import android.widget.MediaController; @@ -569,7 +570,9 @@ class VideoDumpView extends GLSurfaceView implements MediaPlayerControl { mSurface = new SurfaceTexture(mTextureID); mSurface.setOnFrameAvailableListener(this); - mMediaPlayer.setTexture(mSurface); + Surface surface = new Surface(mSurface); + mMediaPlayer.setSurface(surface); + surface.release(); try { mMediaPlayer.prepare(); diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/performance/MediaPlayerPerformance.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/performance/MediaPlayerPerformance.java index b396223a9fbf..081064349ede 100644 --- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/performance/MediaPlayerPerformance.java +++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/performance/MediaPlayerPerformance.java @@ -181,9 +181,10 @@ public class MediaPlayerPerformance extends ActivityInstrumentationTestCase2<Med } // Note: This test is to assume the mediaserver's pid is 34 - private void stressVideoRecord(int frameRate, int width, int height, int videoFormat, + private boolean stressVideoRecord(int frameRate, int width, int height, int videoFormat, int outFormat, String outFile, boolean videoOnly) { // Video recording + boolean doesTestFail = false; for (int i = 0; i < NUM_PLAYBACk_IN_EACH_LOOP; i++) { MediaRecorder mRecorder = new MediaRecorder(); try { @@ -212,8 +213,11 @@ public class MediaPlayerPerformance extends ActivityInstrumentationTestCase2<Med } catch (Exception e) { Log.v("record video failed ", e.toString()); mRecorder.release(); + doesTestFail = true; + break; } } + return !doesTestFail; } public void stressAudioRecord(String filePath) { @@ -366,8 +370,8 @@ public class MediaPlayerPerformance extends ActivityInstrumentationTestCase2<Med Writer output = new BufferedWriter(new FileWriter(videoH263RecordOnlyMemoryOut, true)); output.write("H263 video record only\n"); for (int i = 0; i < NUM_STRESS_LOOP; i++) { - stressVideoRecord(20, 352, 288, MediaRecorder.VideoEncoder.H263, - MediaRecorder.OutputFormat.MPEG_4, MediaNames.RECORDED_VIDEO_3GP, true); + assertTrue(stressVideoRecord(20, 352, 288, MediaRecorder.VideoEncoder.H263, + MediaRecorder.OutputFormat.MPEG_4, MediaNames.RECORDED_VIDEO_3GP, true)); getMemoryWriteToLog(output, i); } output.write("\n"); @@ -386,8 +390,8 @@ public class MediaPlayerPerformance extends ActivityInstrumentationTestCase2<Med Writer output = new BufferedWriter(new FileWriter(videoMp4RecordOnlyMemoryOut, true)); output.write("MPEG4 video record only\n"); for (int i = 0; i < NUM_STRESS_LOOP; i++) { - stressVideoRecord(20, 352, 288, MediaRecorder.VideoEncoder.MPEG_4_SP, - MediaRecorder.OutputFormat.MPEG_4, MediaNames.RECORDED_VIDEO_3GP, true); + assertTrue(stressVideoRecord(20, 352, 288, MediaRecorder.VideoEncoder.MPEG_4_SP, + MediaRecorder.OutputFormat.MPEG_4, MediaNames.RECORDED_VIDEO_3GP, true)); getMemoryWriteToLog(output, i); } output.write("\n"); @@ -407,8 +411,8 @@ public class MediaPlayerPerformance extends ActivityInstrumentationTestCase2<Med Writer output = new BufferedWriter(new FileWriter(videoRecordAudioMemoryOut, true)); output.write("Audio and h263 video record\n"); for (int i = 0; i < NUM_STRESS_LOOP; i++) { - stressVideoRecord(20, 352, 288, MediaRecorder.VideoEncoder.H263, - MediaRecorder.OutputFormat.MPEG_4, MediaNames.RECORDED_VIDEO_3GP, false); + assertTrue(stressVideoRecord(20, 352, 288, MediaRecorder.VideoEncoder.H263, + MediaRecorder.OutputFormat.MPEG_4, MediaNames.RECORDED_VIDEO_3GP, false)); getMemoryWriteToLog(output, i); } output.write("\n"); diff --git a/policy/src/com/android/internal/policy/impl/KeyguardStatusViewManager.java b/policy/src/com/android/internal/policy/impl/KeyguardStatusViewManager.java index 9629702bbb1f..40cc7d898acd 100644 --- a/policy/src/com/android/internal/policy/impl/KeyguardStatusViewManager.java +++ b/policy/src/com/android/internal/policy/impl/KeyguardStatusViewManager.java @@ -20,6 +20,7 @@ import com.android.internal.R; import com.android.internal.telephony.IccCard; import com.android.internal.telephony.IccCard.State; import com.android.internal.widget.LockPatternUtils; +import com.android.internal.widget.TransportControlView; import com.android.internal.policy.impl.KeyguardUpdateMonitor.SimStateCallback; import java.util.ArrayList; @@ -52,8 +53,6 @@ class KeyguardStatusViewManager implements OnClickListener { public static final int BATTERY_LOW_ICON = 0; //R.drawable.ic_lock_idle_low_battery; private static final long INSTRUCTION_RESET_DELAY = 2000; // time until instruction text resets - private static final int SHOW_WIDGET = 8; - private static final int HIDE_WIDGET = 9; private static final int INSTRUCTION_TEXT = 10; private static final int CARRIER_TEXT = 11; private static final int CARRIER_HELP_TEXT = 12; @@ -71,7 +70,7 @@ class KeyguardStatusViewManager implements OnClickListener { private TextView mStatus1View; private TextView mOwnerInfoView; private TextView mAlarmStatusView; - private View mTransportView; + private TransportControlView mTransportView; // Top-level container view for above views private View mContainer; @@ -162,7 +161,7 @@ class KeyguardStatusViewManager implements OnClickListener { mStatus1View = (TextView) findViewById(R.id.status1); mAlarmStatusView = (TextView) findViewById(R.id.alarm_status); mOwnerInfoView = (TextView) findViewById(R.id.propertyOf); - mTransportView = findViewById(R.id.transport); + mTransportView = (TransportControlView) findViewById(R.id.transport); mEmergencyCallButton = (Button) findViewById(R.id.emergencyCallButton); if (mEmergencyCallButton != null) { mEmergencyCallButton.setText(R.string.lockscreen_emergency_call); @@ -192,20 +191,6 @@ class KeyguardStatusViewManager implements OnClickListener { mUpdateMonitor.getTelephonyPlmn(), mUpdateMonitor.getTelephonySpn())); } - public void enterWidgetMode() { - if (mTransportView != null) { - mTransportView.setVisibility(View.VISIBLE); - update(SHOW_WIDGET, null); - } - } - - public void leaveWidgetMode() { - if (mTransportView != null) { - mTransportView.setVisibility(View.GONE); - update(HIDE_WIDGET, null); - } - } - private boolean inWidgetMode() { return mTransportView != null && mTransportView.getVisibility() == View.VISIBLE; } @@ -248,7 +233,8 @@ class KeyguardStatusViewManager implements OnClickListener { * @param lockIcon */ public void setHelpMessage(int textResId, int lockIcon) { - mHelpMessageText = getText(textResId).toString(); + final CharSequence tmp = getText(textResId); + mHelpMessageText = tmp == null ? null : tmp.toString(); update(HELP_MESSAGE_TEXT, mHelpMessageText); } @@ -603,15 +589,6 @@ class KeyguardStatusViewManager implements OnClickListener { public void onPhoneStateChanged(String newState) { updateEmergencyCallButtonState(); } - - public void onTransportControlStateChanged(int state) { - // TODO: define what state means - if (state == 0) { - leaveWidgetMode(); - } else { - enterWidgetMode(); - } - } }; private SimStateCallback mSimStateCallback = new SimStateCallback() { diff --git a/policy/src/com/android/internal/policy/impl/KeyguardUpdateMonitor.java b/policy/src/com/android/internal/policy/impl/KeyguardUpdateMonitor.java index 77f19324a9ec..2955de31e831 100644 --- a/policy/src/com/android/internal/policy/impl/KeyguardUpdateMonitor.java +++ b/policy/src/com/android/internal/policy/impl/KeyguardUpdateMonitor.java @@ -25,6 +25,7 @@ import static android.os.BatteryManager.BATTERY_STATUS_CHARGING; import static android.os.BatteryManager.BATTERY_STATUS_FULL; import static android.os.BatteryManager.BATTERY_STATUS_UNKNOWN; import android.media.AudioManager; +import android.media.IRemoteControlClient; import android.os.BatteryManager; import android.os.Handler; import android.os.Message; @@ -93,8 +94,6 @@ public class KeyguardUpdateMonitor { private static final int MSG_SIM_STATE_CHANGE = 304; private static final int MSG_RINGER_MODE_CHANGED = 305; private static final int MSG_PHONE_STATE_CHANGED = 306; - private static final int MSG_TRANSPORT_CONTROL_STATE_CHANGED = 307; - /** * When we receive a @@ -171,9 +170,6 @@ public class KeyguardUpdateMonitor { case MSG_PHONE_STATE_CHANGED: handlePhoneStateChanged((String)msg.obj); break; - case MSG_TRANSPORT_CONTROL_STATE_CHANGED: - handleTransportControlStateChanged(msg.arg1); - break; } } }; @@ -263,23 +259,10 @@ public class KeyguardUpdateMonitor { String state = intent.getStringExtra(TelephonyManager.EXTRA_STATE); mHandler.sendMessage(mHandler.obtainMessage(MSG_PHONE_STATE_CHANGED, state)); } - // TODO - else if ("android.media.TRANSPORT_CONTROL_CHANGED".equals(action)) { - int state = intent.getIntExtra("state", 0); - mHandler.sendMessage(mHandler.obtainMessage(MSG_TRANSPORT_CONTROL_STATE_CHANGED, - state)); - } } }, filter); } - protected void handleTransportControlStateChanged(int state) { - if (DEBUG) Log.d(TAG, "handleTransportControlStateChanged()"); - for (int i = 0; i < mInfoCallbacks.size(); i++) { - mInfoCallbacks.get(i).onTransportControlStateChanged(state); - } - } - protected void handlePhoneStateChanged(String newState) { if (DEBUG) Log.d(TAG, "handlePhoneStateChanged(" + newState + ")"); for (int i = 0; i < mInfoCallbacks.size(); i++) { @@ -465,11 +448,6 @@ public class KeyguardUpdateMonitor { */ void onPhoneStateChanged(String newState); - /** - * Called when AudioService informs us of a change to the transport control client. - * - */ - void onTransportControlStateChanged(int state); } /** @@ -567,4 +545,5 @@ public class KeyguardUpdateMonitor { public void reportFailedAttempt() { mFailedAttempts++; } + } diff --git a/policy/src/com/android/internal/policy/impl/LockPatternKeyguardView.java b/policy/src/com/android/internal/policy/impl/LockPatternKeyguardView.java index 70772eb553b2..9c14734e4d29 100644 --- a/policy/src/com/android/internal/policy/impl/LockPatternKeyguardView.java +++ b/policy/src/com/android/internal/policy/impl/LockPatternKeyguardView.java @@ -17,8 +17,11 @@ package com.android.internal.policy.impl; import com.android.internal.R; +import com.android.internal.policy.impl.LockPatternKeyguardView.UnlockMode; import com.android.internal.telephony.IccCard; import com.android.internal.widget.LockPatternUtils; +import com.android.internal.widget.LockScreenWidgetCallback; +import com.android.internal.widget.TransportControlView; import android.accounts.Account; import android.accounts.AccountManager; @@ -31,6 +34,7 @@ import android.app.admin.DevicePolicyManager; import android.content.Context; import android.content.Intent; import android.content.res.Configuration; +import android.content.res.Resources; import android.graphics.Bitmap; import android.graphics.Canvas; import android.graphics.ColorFilter; @@ -64,6 +68,8 @@ import java.io.IOException; */ public class LockPatternKeyguardView extends KeyguardViewBase { + private static final int TRANSPORT_USERACTIVITY_TIMEOUT = 10000; + static final boolean DEBUG_CONFIGURATION = false; // time after launching EmergencyDialer before the screen goes blank. @@ -84,6 +90,8 @@ public class LockPatternKeyguardView extends KeyguardViewBase { private boolean mScreenOn = false; private boolean mEnableFallback = false; // assume no fallback UI until we know better + private boolean mShowLockBeforeUnlock = false; + /** * The current {@link KeyguardScreen} will use this to communicate back to us. */ @@ -148,7 +156,7 @@ public class LockPatternKeyguardView extends KeyguardViewBase { * Keeps track of what mode the current unlock screen is (cached from most recent computation in * {@link #getUnlockMode}). */ - private UnlockMode mUnlockScreenMode; + private UnlockMode mUnlockScreenMode = UnlockMode.Unknown; private boolean mForgotPattern; @@ -164,8 +172,6 @@ public class LockPatternKeyguardView extends KeyguardViewBase { */ private final LockPatternUtils mLockPatternUtils; - private UnlockMode mCurrentUnlockMode = UnlockMode.Unknown; - /** * The current configuration. */ @@ -173,7 +179,23 @@ public class LockPatternKeyguardView extends KeyguardViewBase { private Runnable mRecreateRunnable = new Runnable() { public void run() { - recreateScreens(); + updateScreen(mMode, false); + } + }; + + private LockScreenWidgetCallback mWidgetCallback = new LockScreenWidgetCallback() { + public void userActivity(View self) { + mKeyguardScreenCallback.pokeWakelock(TRANSPORT_USERACTIVITY_TIMEOUT); + } + + public void requestShow(View view) { + if (DEBUG) Log.v(TAG, "View " + view + " requested show transports"); + view.setVisibility(View.VISIBLE); + } + + public void requestHide(View view) { + if (DEBUG) Log.v(TAG, "View " + view + " requested hide transports"); + view.setVisibility(View.GONE); } }; @@ -204,16 +226,11 @@ public class LockPatternKeyguardView extends KeyguardViewBase { mConfiguration = context.getResources().getConfiguration(); mEnableFallback = false; - - mRequiresSim = - TextUtils.isEmpty(SystemProperties.get("keyguard.no_require_sim")); - + mRequiresSim = TextUtils.isEmpty(SystemProperties.get("keyguard.no_require_sim")); mUpdateMonitor = updateMonitor; mLockPatternUtils = lockPatternUtils; mWindowController = controller; - mMode = getInitialMode(); - mKeyguardScreenCallback = new KeyguardScreenCallback() { public void goToLockScreen() { @@ -224,7 +241,7 @@ public class LockPatternKeyguardView extends KeyguardViewBase { mIsVerifyUnlockOnly = false; getCallback().keyguardDone(false); } else { - updateScreen(Mode.LockScreen); + updateScreen(Mode.LockScreen, false); } } @@ -240,14 +257,14 @@ public class LockPatternKeyguardView extends KeyguardViewBase { if (!isSecure()) { getCallback().keyguardDone(true); } else { - updateScreen(Mode.UnlockScreen); + updateScreen(Mode.UnlockScreen, false); } } public void forgotPattern(boolean isForgotten) { if (mEnableFallback) { mForgotPattern = isForgotten; - updateScreen(Mode.UnlockScreen); + updateScreen(Mode.UnlockScreen, false); } } @@ -260,7 +277,6 @@ public class LockPatternKeyguardView extends KeyguardViewBase { } public void recreateMe(Configuration config) { - mConfiguration = config; removeCallbacks(mRecreateRunnable); post(mRecreateRunnable); } @@ -330,7 +346,7 @@ public class LockPatternKeyguardView extends KeyguardViewBase { showAlmostAtAccountLoginDialog(); } else if (failedAttempts >= LockPatternUtils.FAILED_ATTEMPTS_BEFORE_RESET) { mLockPatternUtils.setPermanentlyLocked(true); - updateScreen(mMode); + updateScreen(mMode, false); } } else { final boolean showTimeout = @@ -358,21 +374,8 @@ public class LockPatternKeyguardView extends KeyguardViewBase { setFocusableInTouchMode(true); setDescendantFocusability(FOCUS_AFTER_DESCENDANTS); - // create both the lock and unlock screen so they are quickly available - // when the screen turns on - mLockScreen = createLockScreen(); - addView(mLockScreen); - final UnlockMode unlockMode = getUnlockMode(); - if (DEBUG) Log.d(TAG, - "LockPatternKeyguardView ctor: about to createUnlockScreenFor; mEnableFallback=" - + mEnableFallback); - mUnlockScreen = createUnlockScreenFor(unlockMode); - mUnlockScreenMode = unlockMode; - + updateScreen(getInitialMode(), false); maybeEnableFallback(context); - - addView(mUnlockScreen); - updateScreen(mMode); } private class AccountAnalyzer implements AccountManagerCallback<Bundle> { @@ -449,7 +452,7 @@ public class LockPatternKeyguardView extends KeyguardViewBase { public void reset() { mIsVerifyUnlockOnly = false; mForgotPattern = false; - updateScreen(getInitialMode()); + updateScreen(getInitialMode(), false); } @Override @@ -457,7 +460,7 @@ public class LockPatternKeyguardView extends KeyguardViewBase { mScreenOn = false; mForgotPattern = false; if (mMode == Mode.LockScreen) { - ((KeyguardScreen) mLockScreen).onPause(); + ((KeyguardScreen) mLockScreen).onPause(); } else { ((KeyguardScreen) mUnlockScreen).onPause(); } @@ -467,50 +470,54 @@ public class LockPatternKeyguardView extends KeyguardViewBase { public void onScreenTurnedOn() { mScreenOn = true; if (mMode == Mode.LockScreen) { - ((KeyguardScreen) mLockScreen).onResume(); + ((KeyguardScreen) mLockScreen).onResume(); } else { ((KeyguardScreen) mUnlockScreen).onResume(); } } private void recreateLockScreen() { - if (mLockScreen.getVisibility() == View.VISIBLE) { - ((KeyguardScreen) mLockScreen).onPause(); + if (mLockScreen != null) { + if (mLockScreen.getVisibility() == View.VISIBLE) { + ((KeyguardScreen) mLockScreen).onPause(); + } + ((KeyguardScreen) mLockScreen).cleanUp(); + removeView(mLockScreen); } - ((KeyguardScreen) mLockScreen).cleanUp(); - removeView(mLockScreen); mLockScreen = createLockScreen(); mLockScreen.setVisibility(View.INVISIBLE); addView(mLockScreen); } - private void recreateUnlockScreen() { - if (mUnlockScreen.getVisibility() == View.VISIBLE) { - ((KeyguardScreen) mUnlockScreen).onPause(); + private void recreateUnlockScreen(UnlockMode unlockMode) { + if (mUnlockScreen != null) { + if (mUnlockScreen.getVisibility() == View.VISIBLE) { + ((KeyguardScreen) mUnlockScreen).onPause(); + } + ((KeyguardScreen) mUnlockScreen).cleanUp(); + removeView(mUnlockScreen); } - ((KeyguardScreen) mUnlockScreen).cleanUp(); - removeView(mUnlockScreen); - final UnlockMode unlockMode = getUnlockMode(); mUnlockScreen = createUnlockScreenFor(unlockMode); mUnlockScreen.setVisibility(View.INVISIBLE); - mUnlockScreenMode = unlockMode; addView(mUnlockScreen); } - private void recreateScreens() { - recreateLockScreen(); - recreateUnlockScreen(); - updateScreen(mMode); - } - @Override protected void onDetachedFromWindow() { removeCallbacks(mRecreateRunnable); super.onDetachedFromWindow(); } + protected void onConfigurationChanged(Configuration newConfig) { + Resources resources = getResources(); + mShowLockBeforeUnlock = resources.getBoolean(R.bool.config_enableLockBeforeUnlockScreen); + mConfiguration = newConfig; + if (DEBUG_CONFIGURATION) Log.v(TAG, "**** re-creating lock screen since config changed"); + updateScreen(mMode, true /* force */); + } + @Override protected boolean dispatchHoverEvent(MotionEvent event) { // Do not let the screen to get locked while the user is disabled and touch @@ -529,7 +536,7 @@ public class LockPatternKeyguardView extends KeyguardViewBase { if (keyCode == KeyEvent.KEYCODE_MENU && isSecure() && (mMode == Mode.LockScreen) && (mUpdateMonitor.getSimState() != IccCard.State.PUK_REQUIRED)) { if (DEBUG) Log.d(TAG, "switching screens to unlock screen because wake key was MENU"); - updateScreen(Mode.UnlockScreen); + updateScreen(Mode.UnlockScreen, false); getCallback().pokeWakelock(); } else { if (DEBUG) Log.d(TAG, "poking wake lock immediately"); @@ -542,24 +549,31 @@ public class LockPatternKeyguardView extends KeyguardViewBase { if (!isSecure()) { // non-secure keyguard screens are successfull by default getCallback().keyguardDone(true); - } else if (mUnlockScreenMode != UnlockMode.Pattern) { - // can only verify unlock when in pattern mode + } else if (mUnlockScreenMode != UnlockMode.Pattern + && mUnlockScreenMode != UnlockMode.Password) { + // can only verify unlock when in pattern/password mode getCallback().keyguardDone(false); } else { // otherwise, go to the unlock screen, see if they can verify it mIsVerifyUnlockOnly = true; - updateScreen(Mode.UnlockScreen); + updateScreen(Mode.UnlockScreen, false); } } @Override public void cleanUp() { - ((KeyguardScreen) mLockScreen).onPause(); - ((KeyguardScreen) mLockScreen).cleanUp(); - this.removeView(mLockScreen); - ((KeyguardScreen) mUnlockScreen).onPause(); - ((KeyguardScreen) mUnlockScreen).cleanUp(); - this.removeView(mUnlockScreen); + if (mLockScreen != null) { + ((KeyguardScreen) mLockScreen).onPause(); + ((KeyguardScreen) mLockScreen).cleanUp(); + this.removeView(mLockScreen); + mLockScreen = null; + } + if (mUnlockScreen != null) { + ((KeyguardScreen) mUnlockScreen).onPause(); + ((KeyguardScreen) mUnlockScreen).cleanUp(); + this.removeView(mUnlockScreen); + mUnlockScreen = null; + } } private boolean isSecure() { @@ -587,19 +601,30 @@ public class LockPatternKeyguardView extends KeyguardViewBase { return secure; } - private void updateScreen(final Mode mode) { + private void updateScreen(Mode mode, boolean force) { if (DEBUG_CONFIGURATION) Log.v(TAG, "**** UPDATE SCREEN: mode=" + mode + " last mode=" + mMode, new RuntimeException()); mMode = mode; + // Re-create the lock screen if necessary + if (mode == Mode.LockScreen || mShowLockBeforeUnlock) { + if (force || mLockScreen == null) { + recreateLockScreen(); + } + } + // Re-create the unlock screen if necessary. This is primarily required to properly handle // SIM state changes. This typically happens when this method is called by reset() - if (mode == Mode.UnlockScreen && mCurrentUnlockMode != getUnlockMode()) { - recreateUnlockScreen(); + if (mode == Mode.UnlockScreen) { + final UnlockMode unlockMode = getUnlockMode(); + if (force || mUnlockScreen == null || unlockMode != mUnlockScreenMode) { + recreateUnlockScreen(unlockMode); + } } + // visibleScreen should never be null final View goneScreen = (mode == Mode.LockScreen) ? mUnlockScreen : mLockScreen; final View visibleScreen = (mode == Mode.LockScreen) ? mLockScreen : mUnlockScreen; @@ -613,7 +638,7 @@ public class LockPatternKeyguardView extends KeyguardViewBase { } if (mScreenOn) { - if (goneScreen.getVisibility() == View.VISIBLE) { + if (goneScreen != null && goneScreen.getVisibility() == View.VISIBLE) { ((KeyguardScreen) goneScreen).onPause(); } if (visibleScreen.getVisibility() != View.VISIBLE) { @@ -621,7 +646,9 @@ public class LockPatternKeyguardView extends KeyguardViewBase { } } - goneScreen.setVisibility(View.GONE); + if (goneScreen != null) { + goneScreen.setVisibility(View.GONE); + } visibleScreen.setVisibility(View.VISIBLE); requestLayout(); @@ -632,12 +659,14 @@ public class LockPatternKeyguardView extends KeyguardViewBase { } View createLockScreen() { - return new LockScreen( + View lockView = new LockScreen( mContext, mConfiguration, mLockPatternUtils, mUpdateMonitor, mKeyguardScreenCallback); + initializeTransportControlView(lockView); + return lockView; } View createUnlockScreenFor(UnlockMode unlockMode) { @@ -691,7 +720,7 @@ public class LockPatternKeyguardView extends KeyguardViewBase { // regular pattern unlock UI, regardless of the value of // mUnlockScreenMode or whether or not we're in the // "permanently locked" state.) - unlockView = createUnlockScreenFor(UnlockMode.Pattern); + return createUnlockScreenFor(UnlockMode.Pattern); } } else if (unlockMode == UnlockMode.Password) { unlockView = new PasswordUnlockScreen( @@ -703,10 +732,22 @@ public class LockPatternKeyguardView extends KeyguardViewBase { } else { throw new IllegalArgumentException("unknown unlock mode " + unlockMode); } - mCurrentUnlockMode = unlockMode; + initializeTransportControlView(unlockView); + mUnlockScreenMode = unlockMode; return unlockView; } + private void initializeTransportControlView(View view) { + com.android.internal.widget.TransportControlView tcv = + (TransportControlView) view.findViewById(R.id.transport); + if (tcv == null) { + if (DEBUG) Log.w(TAG, "Couldn't find transport control widget"); + } else { + tcv.setVisibility(View.GONE); // hide tcv until we get the callback below to show it. + tcv.setCallback(mWidgetCallback); + } + } + /** * Given the current state of things, what should be the initial mode of * the lock screen (lock or unlock). @@ -718,16 +759,10 @@ public class LockPatternKeyguardView extends KeyguardViewBase { !mLockPatternUtils.isPukUnlockScreenEnable())) { return Mode.LockScreen; } else { - // Show LockScreen first for any screen other than Pattern unlock. - final boolean usingLockPattern = mLockPatternUtils.getKeyguardStoredPasswordQuality() - == DevicePolicyManager.PASSWORD_QUALITY_SOMETHING; - - boolean showLockBeforeUnlock = getResources() - .getBoolean(R.bool.config_enableLockBeforeUnlockScreen); - if (isSecure() && (usingLockPattern || !showLockBeforeUnlock)) { - return Mode.UnlockScreen; - } else { + if (!isSecure() || mShowLockBeforeUnlock) { return Mode.LockScreen; + } else { + return Mode.UnlockScreen; } } } diff --git a/policy/src/com/android/internal/policy/impl/PasswordUnlockScreen.java b/policy/src/com/android/internal/policy/impl/PasswordUnlockScreen.java index ce3bc74852be..2f2d3b7c635d 100644 --- a/policy/src/com/android/internal/policy/impl/PasswordUnlockScreen.java +++ b/policy/src/com/android/internal/policy/impl/PasswordUnlockScreen.java @@ -347,7 +347,8 @@ public class PasswordUnlockScreen extends LinearLayout implements KeyguardScreen public boolean onEditorAction(TextView v, int actionId, KeyEvent event) { // Check if this was the result of hitting the enter key - if (actionId == EditorInfo.IME_NULL || actionId == EditorInfo.IME_ACTION_DONE) { + if (actionId == EditorInfo.IME_NULL || actionId == EditorInfo.IME_ACTION_DONE + || actionId == EditorInfo.IME_ACTION_NEXT) { verifyPasswordAndUnlock(); return true; } diff --git a/services/audioflinger/AudioFlinger.cpp b/services/audioflinger/AudioFlinger.cpp index 744fa50879e0..94efa749e08f 100644 --- a/services/audioflinger/AudioFlinger.cpp +++ b/services/audioflinger/AudioFlinger.cpp @@ -151,7 +151,7 @@ static const char *audio_interfaces[] = { AudioFlinger::AudioFlinger() : BnAudioFlinger(), mPrimaryHardwareDev(0), mMasterVolume(1.0f), mMasterMute(false), mNextUniqueId(1), - mBtNrec(false) + mBtNrecIsOff(false) { } @@ -751,15 +751,15 @@ status_t AudioFlinger::setParameters(int ioHandle, const String8& keyValuePairs) String8 value; if (param.get(String8(AUDIO_PARAMETER_KEY_BT_NREC), value) == NO_ERROR) { Mutex::Autolock _l(mLock); - bool btNrec = (value == AUDIO_PARAMETER_VALUE_ON); - if (mBtNrec != btNrec) { + bool btNrecIsOff = (value == AUDIO_PARAMETER_VALUE_OFF); + if (mBtNrecIsOff != btNrecIsOff) { for (size_t i = 0; i < mRecordThreads.size(); i++) { sp<RecordThread> thread = mRecordThreads.valueAt(i); RecordThread::RecordTrack *track = thread->track(); if (track != NULL) { audio_devices_t device = (audio_devices_t)( thread->device() & AUDIO_DEVICE_IN_ALL); - bool suspend = audio_is_bluetooth_sco_device(device) && btNrec; + bool suspend = audio_is_bluetooth_sco_device(device) && btNrecIsOff; thread->setEffectSuspended(FX_IID_AEC, suspend, track->sessionId()); @@ -768,7 +768,7 @@ status_t AudioFlinger::setParameters(int ioHandle, const String8& keyValuePairs) track->sessionId()); } } - mBtNrec = btNrec; + mBtNrecIsOff = btNrecIsOff; } } return final_result; @@ -1362,6 +1362,7 @@ AudioFlinger::PlaybackThread::PlaybackThread(const sp<AudioFlinger>& audioFlinge for (int stream = 0; stream < AUDIO_STREAM_CNT; stream++) { mStreamTypes[stream].volume = mAudioFlinger->streamVolumeInternal(stream); mStreamTypes[stream].mute = mAudioFlinger->streamMute(stream); + mStreamTypes[stream].valid = true; } } @@ -1530,6 +1531,14 @@ sp<AudioFlinger::PlaybackThread::Track> AudioFlinger::PlaybackThread::createTra chain->setStrategy(AudioSystem::getStrategyForStream((audio_stream_type_t)track->type())); chain->incTrackCnt(); } + + // invalidate track immediately if the stream type was moved to another thread since + // createTrack() was called by the client process. + if (!mStreamTypes[streamType].valid) { + LOGW("createTrack_l() on thread %p: invalidating track on stream %d", + this, streamType); + android_atomic_or(CBLK_INVALID_ON, &track->mCblk->flags); + } } lStatus = NO_ERROR; @@ -2219,6 +2228,14 @@ void AudioFlinger::MixerThread::invalidateTracks(int streamType) } } +void AudioFlinger::PlaybackThread::setStreamValid(int streamType, bool valid) +{ + LOGV ("PlaybackThread::setStreamValid() thread %p, streamType %d, valid %d", + this, streamType, valid); + Mutex::Autolock _l(mLock); + + mStreamTypes[streamType].valid = valid; +} // getTrackName_l() must be called with ThreadBase::mLock held int AudioFlinger::MixerThread::getTrackName_l() @@ -4394,7 +4411,7 @@ sp<AudioFlinger::RecordThread::RecordTrack> AudioFlinger::RecordThread::createR mTrack = track.get(); // disable AEC and NS if the device is a BT SCO headset supporting those pre processings bool suspend = audio_is_bluetooth_sco_device( - (audio_devices_t)(mDevice & AUDIO_DEVICE_IN_ALL)) && mAudioFlinger->btNrec(); + (audio_devices_t)(mDevice & AUDIO_DEVICE_IN_ALL)) && mAudioFlinger->btNrecIsOff(); setEffectSuspended_l(FX_IID_AEC, suspend, sessionId); setEffectSuspended_l(FX_IID_NS, suspend, sessionId); } @@ -4619,7 +4636,7 @@ bool AudioFlinger::RecordThread::checkForNewParameters_l() // disable AEC and NS if the device is a BT SCO headset supporting those pre processings if (mTrack != NULL) { bool suspend = audio_is_bluetooth_sco_device( - (audio_devices_t)value) && mAudioFlinger->btNrec(); + (audio_devices_t)value) && mAudioFlinger->btNrecIsOff(); setEffectSuspended_l(FX_IID_AEC, suspend, mTrack->sessionId()); setEffectSuspended_l(FX_IID_NS, suspend, mTrack->sessionId()); } @@ -5074,11 +5091,14 @@ status_t AudioFlinger::setStreamOutput(uint32_t stream, int output) LOGV("setStreamOutput() stream %d to output %d", stream, output); audioConfigChanged_l(AudioSystem::STREAM_CONFIG_CHANGED, output, &stream); + dstThread->setStreamValid(stream, true); + for (size_t i = 0; i < mPlaybackThreads.size(); i++) { PlaybackThread *thread = mPlaybackThreads.valueAt(i).get(); if (thread != dstThread && thread->type() != ThreadBase::DIRECT) { MixerThread *srcThread = (MixerThread *)thread; + srcThread->setStreamValid(stream, false); srcThread->invalidateTracks(stream); } } diff --git a/services/audioflinger/AudioFlinger.h b/services/audioflinger/AudioFlinger.h index 1141f6c98e27..2e055934bd75 100644 --- a/services/audioflinger/AudioFlinger.h +++ b/services/audioflinger/AudioFlinger.h @@ -210,7 +210,7 @@ public: uint32_t getMode() { return mMode; } - bool btNrec() { return mBtNrec; } + bool btNrecIsOff() { return mBtNrecIsOff; } private: AudioFlinger(); @@ -751,14 +751,18 @@ private: virtual uint32_t hasAudioSession(int sessionId); virtual uint32_t getStrategyForSession_l(int sessionId); + void setStreamValid(int streamType, bool valid); + struct stream_type_t { stream_type_t() : volume(1.0f), - mute(false) + mute(false), + valid(true) { } float volume; bool mute; + bool valid; }; protected: @@ -1389,7 +1393,7 @@ private: DefaultKeyedVector< pid_t, sp<NotificationClient> > mNotificationClients; volatile int32_t mNextUniqueId; uint32_t mMode; - bool mBtNrec; + bool mBtNrecIsOff; Vector<AudioSessionRef*> mAudioSessionRefs; }; diff --git a/services/input/EventHub.cpp b/services/input/EventHub.cpp index 1d7cc19c02b8..06dea36b3ff7 100644 --- a/services/input/EventHub.cpp +++ b/services/input/EventHub.cpp @@ -1094,9 +1094,8 @@ void EventHub::clearKeyboardPropertiesLocked(Device* device, bool builtInKeyboar bool EventHub::isExternalDeviceLocked(Device* device) { if (device->configuration) { bool value; - if (device->configuration->tryGetProperty(String8("device.internal"), value) - && value) { - return false; + if (device->configuration->tryGetProperty(String8("device.internal"), value)) { + return !value; } } return device->identifier.bus == BUS_USB || device->identifier.bus == BUS_BLUETOOTH; diff --git a/services/java/com/android/server/BackupManagerService.java b/services/java/com/android/server/BackupManagerService.java index b3309e539690..997318a0de8f 100644 --- a/services/java/com/android/server/BackupManagerService.java +++ b/services/java/com/android/server/BackupManagerService.java @@ -197,14 +197,14 @@ class BackupManagerService extends IBackupManager.Stub { = new SparseArray<HashSet<ApplicationInfo>>(); // set of backup services that have pending changes class BackupRequest { - public ApplicationInfo appInfo; + public String packageName; - BackupRequest(ApplicationInfo app) { - appInfo = app; + BackupRequest(String pkgName) { + packageName = pkgName; } public String toString() { - return "BackupRequest{app=" + appInfo + "}"; + return "BackupRequest{pkg=" + packageName + "}"; } } // Backups that we haven't started yet. Keys are package names. @@ -877,6 +877,7 @@ class BackupManagerService extends IBackupManager.Stub { IntentFilter filter = new IntentFilter(); filter.addAction(Intent.ACTION_PACKAGE_ADDED); filter.addAction(Intent.ACTION_PACKAGE_REMOVED); + filter.addAction(Intent.ACTION_PACKAGE_REPLACED); filter.addDataScheme("package"); mContext.registerReceiver(mBroadcastReceiver, filter); // Register for events related to sdcard installation. @@ -1174,7 +1175,8 @@ class BackupManagerService extends IBackupManager.Stub { Bundle extras = intent.getExtras(); String pkgList[] = null; if (Intent.ACTION_PACKAGE_ADDED.equals(action) || - Intent.ACTION_PACKAGE_REMOVED.equals(action)) { + Intent.ACTION_PACKAGE_REMOVED.equals(action) || + Intent.ACTION_PACKAGE_REPLACED.equals(action)) { Uri uri = intent.getData(); if (uri == null) { return; @@ -1183,8 +1185,14 @@ class BackupManagerService extends IBackupManager.Stub { if (pkgName != null) { pkgList = new String[] { pkgName }; } - added = Intent.ACTION_PACKAGE_ADDED.equals(action); - replacing = extras.getBoolean(Intent.EXTRA_REPLACING, false); + if (Intent.ACTION_PACKAGE_REPLACED.equals(action)) { + // use the existing "add with replacement" logic + if (MORE_DEBUG) Slog.d(TAG, "PACKAGE_REPLACED, updating package " + pkgName); + added = replacing = true; + } else { + added = Intent.ACTION_PACKAGE_ADDED.equals(action); + replacing = extras.getBoolean(Intent.EXTRA_REPLACING, false); + } } else if (Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE.equals(action)) { added = true; pkgList = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST); @@ -1192,6 +1200,7 @@ class BackupManagerService extends IBackupManager.Stub { added = false; pkgList = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST); } + if (pkgList == null || pkgList.length == 0) { return; } @@ -1665,9 +1674,7 @@ class BackupManagerService extends IBackupManager.Stub { if (status == BackupConstants.TRANSPORT_OK) { PackageManagerBackupAgent pmAgent = new PackageManagerBackupAgent( mPackageManager, allAgentPackages()); - BackupRequest pmRequest = new BackupRequest(new ApplicationInfo()); - pmRequest.appInfo.packageName = PACKAGE_MANAGER_SENTINEL; - status = processOneBackup(pmRequest, + status = processOneBackup(PACKAGE_MANAGER_SENTINEL, IBackupAgent.Stub.asInterface(pmAgent.onBind()), mTransport); } @@ -1716,7 +1723,7 @@ class BackupManagerService extends IBackupManager.Stub { if (status != BackupConstants.TRANSPORT_OK) { Slog.w(TAG, "Backup pass unsuccessful, restaging"); for (BackupRequest req : mQueue) { - dataChangedImpl(req.appInfo.packageName); + dataChangedImpl(req.packageName); } // We also want to reset the backup schedule based on whatever @@ -1750,9 +1757,11 @@ class BackupManagerService extends IBackupManager.Stub { // Verify that the requested app exists; it might be something that // requested a backup but was then uninstalled. The request was // journalled and rather than tamper with the journal it's safer - // to sanity-check here. + // to sanity-check here. This also gives us the classname of the + // package's backup agent. + PackageInfo pkg; try { - mPackageManager.getPackageInfo(request.appInfo.packageName, 0); + pkg = mPackageManager.getPackageInfo(request.packageName, 0); } catch (NameNotFoundException e) { Slog.d(TAG, "Package does not exist; skipping"); continue; @@ -1760,11 +1769,11 @@ class BackupManagerService extends IBackupManager.Stub { IBackupAgent agent = null; try { - mWakelock.setWorkSource(new WorkSource(request.appInfo.uid)); - agent = bindToAgentSynchronous(request.appInfo, + mWakelock.setWorkSource(new WorkSource(pkg.applicationInfo.uid)); + agent = bindToAgentSynchronous(pkg.applicationInfo, IApplicationThread.BACKUP_MODE_INCREMENTAL); if (agent != null) { - int result = processOneBackup(request, agent, transport); + int result = processOneBackup(request.packageName, agent, transport); if (result != BackupConstants.TRANSPORT_OK) return result; } } catch (SecurityException ex) { @@ -1772,7 +1781,7 @@ class BackupManagerService extends IBackupManager.Stub { Slog.d(TAG, "error in bind/backup", ex); } finally { try { // unbind even on timeout, just in case - mActivityManager.unbindBackupAgent(request.appInfo); + mActivityManager.unbindBackupAgent(pkg.applicationInfo); } catch (RemoteException e) {} } } @@ -1782,9 +1791,8 @@ class BackupManagerService extends IBackupManager.Stub { return BackupConstants.TRANSPORT_OK; } - private int processOneBackup(BackupRequest request, IBackupAgent agent, + private int processOneBackup(String packageName, IBackupAgent agent, IBackupTransport transport) { - final String packageName = request.appInfo.packageName; if (DEBUG) Slog.d(TAG, "processOneBackup doBackup() on " + packageName); File savedStateName = new File(mStateDir, packageName); @@ -4207,7 +4215,7 @@ class BackupManagerService extends IBackupManager.Stub { if (app.packageName.equals(packageName)) { // Add the caller to the set of pending backups. If there is // one already there, then overwrite it, but no harm done. - BackupRequest req = new BackupRequest(app); + BackupRequest req = new BackupRequest(packageName); if (mPendingBackups.put(app.packageName, req) == null) { // Journal this request in case of crash. The put() // operation returned null when this package was not already @@ -4218,7 +4226,7 @@ class BackupManagerService extends IBackupManager.Stub { int numKeys = mPendingBackups.size(); Slog.d(TAG, "Now awaiting backup for " + numKeys + " participants:"); for (BackupRequest b : mPendingBackups.values()) { - Slog.d(TAG, " + " + b + " agent=" + b.appInfo.backupAgentName); + Slog.d(TAG, " + " + b); } } } diff --git a/services/java/com/android/server/ConnectivityService.java b/services/java/com/android/server/ConnectivityService.java index bfca851dcaca..3815c3b39b53 100644 --- a/services/java/com/android/server/ConnectivityService.java +++ b/services/java/com/android/server/ConnectivityService.java @@ -17,6 +17,8 @@ package com.android.server; import static android.Manifest.permission.MANAGE_NETWORK_POLICY; +import static android.net.ConnectivityManager.CONNECTIVITY_ACTION; +import static android.net.ConnectivityManager.CONNECTIVITY_ACTION_IMMEDIATE; import static android.net.ConnectivityManager.isNetworkTypeValid; import static android.net.NetworkPolicyManager.RULE_ALLOW_ALL; import static android.net.NetworkPolicyManager.RULE_REJECT_METERED; @@ -1418,6 +1420,9 @@ public class ConnectivityService extends IConnectivityManager.Stub { // do this before we broadcast the change handleConnectivityChange(prevNetType, doReset); + final Intent immediateIntent = new Intent(intent); + immediateIntent.setAction(CONNECTIVITY_ACTION_IMMEDIATE); + sendStickyBroadcast(immediateIntent); sendStickyBroadcastDelayed(intent, getConnectivityChangeDelay()); /* * If the failover network is already connected, then immediately send @@ -1476,11 +1481,13 @@ public class ConnectivityService extends IConnectivityManager.Stub { } private void sendConnectedBroadcast(NetworkInfo info) { - sendGeneralBroadcast(info, ConnectivityManager.CONNECTIVITY_ACTION); + sendGeneralBroadcast(info, CONNECTIVITY_ACTION_IMMEDIATE); + sendGeneralBroadcast(info, CONNECTIVITY_ACTION); } private void sendConnectedBroadcastDelayed(NetworkInfo info, int delayMs) { - sendGeneralBroadcastDelayed(info, ConnectivityManager.CONNECTIVITY_ACTION, delayMs); + sendGeneralBroadcast(info, CONNECTIVITY_ACTION_IMMEDIATE); + sendGeneralBroadcastDelayed(info, CONNECTIVITY_ACTION, delayMs); } private void sendInetConditionBroadcast(NetworkInfo info) { @@ -1559,6 +1566,10 @@ public class ConnectivityService extends IConnectivityManager.Stub { } intent.putExtra(ConnectivityManager.EXTRA_INET_CONDITION, mDefaultInetConditionPublished); + + final Intent immediateIntent = new Intent(intent); + immediateIntent.setAction(CONNECTIVITY_ACTION_IMMEDIATE); + sendStickyBroadcast(immediateIntent); sendStickyBroadcast(intent); /* * If the failover network is already connected, then immediately send @@ -1576,8 +1587,7 @@ public class ConnectivityService extends IConnectivityManager.Stub { } intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); if (DBG) { - log("sendStickyBroadcast: NetworkInfo=" + - intent.getParcelableExtra(ConnectivityManager.EXTRA_NETWORK_INFO)); + log("sendStickyBroadcast: action=" + intent.getAction()); } mContext.sendStickyBroadcast(intent); @@ -1588,7 +1598,10 @@ public class ConnectivityService extends IConnectivityManager.Stub { if (delayMs <= 0) { sendStickyBroadcast(intent); } else { - if (DBG) log("sendStickyBroadcastDelayed: delayMs=" + delayMs + " intent=" + intent); + if (DBG) { + log("sendStickyBroadcastDelayed: delayMs=" + delayMs + ", action=" + + intent.getAction()); + } mHandler.sendMessageDelayed(mHandler.obtainMessage( EVENT_SEND_STICKY_BROADCAST_INTENT, intent), delayMs); } @@ -2281,7 +2294,6 @@ public class ConnectivityService extends IConnectivityManager.Stub { case EVENT_SEND_STICKY_BROADCAST_INTENT: { Intent intent = (Intent)msg.obj; - log("EVENT_SEND_STICKY_BROADCAST_INTENT: sendStickyBroadcast intent=" + intent); sendStickyBroadcast(intent); break; } diff --git a/services/java/com/android/server/NotificationManagerService.java b/services/java/com/android/server/NotificationManagerService.java index 7a3a344c0a76..6ee20bbb32bd 100755 --- a/services/java/com/android/server/NotificationManagerService.java +++ b/services/java/com/android/server/NotificationManagerService.java @@ -101,6 +101,7 @@ public class NotificationManagerService extends INotificationManager.Stub private Vibrator mVibrator = new Vibrator(); // for enabling and disabling notification pulse behavior + private boolean mScreenOn = true; private boolean mInCall = false; private boolean mNotificationPulseEnabled; @@ -344,9 +345,19 @@ public class NotificationManagerService extends INotificationManager.Stub cancelAllNotificationsInt(pkgName, 0, 0, !queryRestart); } } + } else if (action.equals(Intent.ACTION_SCREEN_ON)) { + // Keep track of screen on/off state, but do not turn off the notification light + // until user passes through the lock screen or views the notification. + mScreenOn = true; + } else if (action.equals(Intent.ACTION_SCREEN_OFF)) { + mScreenOn = false; } else if (action.equals(TelephonyManager.ACTION_PHONE_STATE_CHANGED)) { - mInCall = (intent.getStringExtra(TelephonyManager.EXTRA_STATE).equals(TelephonyManager.EXTRA_STATE_OFFHOOK)); + mInCall = (intent.getStringExtra(TelephonyManager.EXTRA_STATE).equals( + TelephonyManager.EXTRA_STATE_OFFHOOK)); updateNotificationPulse(); + } else if (action.equals(Intent.ACTION_USER_PRESENT)) { + // turn off LED when user passes through lock screen + mNotificationLight.turnOff(); } } }; @@ -417,6 +428,7 @@ public class NotificationManagerService extends INotificationManager.Stub filter.addAction(Intent.ACTION_SCREEN_ON); filter.addAction(Intent.ACTION_SCREEN_OFF); filter.addAction(TelephonyManager.ACTION_PHONE_STATE_CHANGED); + filter.addAction(Intent.ACTION_USER_PRESENT); mContext.registerReceiver(mIntentReceiver, filter); IntentFilter pkgFilter = new IntentFilter(); pkgFilter.addAction(Intent.ACTION_PACKAGE_REMOVED); @@ -1057,8 +1069,8 @@ public class NotificationManagerService extends INotificationManager.Stub } } - // Don't flash while we are in a call - if (mLedNotification == null || mInCall) { + // Don't flash while we are in a call or screen is on + if (mLedNotification == null || mInCall || mScreenOn) { mNotificationLight.turnOff(); } else { int ledARGB = mLedNotification.notification.ledARGB; diff --git a/services/java/com/android/server/net/NetworkPolicyManagerService.java b/services/java/com/android/server/net/NetworkPolicyManagerService.java index 77f53c25926d..8af90ff44ed7 100644 --- a/services/java/com/android/server/net/NetworkPolicyManagerService.java +++ b/services/java/com/android/server/net/NetworkPolicyManagerService.java @@ -26,7 +26,7 @@ import static android.Manifest.permission.READ_PHONE_STATE; import static android.content.Intent.ACTION_PACKAGE_ADDED; import static android.content.Intent.ACTION_UID_REMOVED; import static android.content.Intent.EXTRA_UID; -import static android.net.ConnectivityManager.CONNECTIVITY_ACTION; +import static android.net.ConnectivityManager.CONNECTIVITY_ACTION_IMMEDIATE; import static android.net.ConnectivityManager.TYPE_ETHERNET; import static android.net.ConnectivityManager.TYPE_MOBILE; import static android.net.ConnectivityManager.TYPE_WIFI; @@ -51,6 +51,7 @@ import static android.net.NetworkTemplate.MATCH_WIFI; import static android.net.NetworkTemplate.buildTemplateMobileAll; import static android.text.format.DateUtils.DAY_IN_MILLIS; import static com.android.internal.util.Preconditions.checkNotNull; +import static com.android.server.NetworkManagementService.LIMIT_GLOBAL_ALERT; import static com.android.server.net.NetworkPolicyManagerService.XmlUtils.readBooleanAttribute; import static com.android.server.net.NetworkPolicyManagerService.XmlUtils.readIntAttribute; import static com.android.server.net.NetworkPolicyManagerService.XmlUtils.readLongAttribute; @@ -60,7 +61,6 @@ import static com.android.server.net.NetworkPolicyManagerService.XmlUtils.writeL import static com.android.server.net.NetworkStatsService.ACTION_NETWORK_STATS_UPDATED; import static org.xmlpull.v1.XmlPullParser.END_DOCUMENT; import static org.xmlpull.v1.XmlPullParser.START_TAG; -import static com.android.server.NetworkManagementService.LIMIT_GLOBAL_ALERT; import android.app.IActivityManager; import android.app.INotificationManager; @@ -321,7 +321,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { mContext.registerReceiver(mScreenReceiver, screenFilter, null, mHandler); // watch for network interfaces to be claimed - final IntentFilter connFilter = new IntentFilter(CONNECTIVITY_ACTION); + final IntentFilter connFilter = new IntentFilter(CONNECTIVITY_ACTION_IMMEDIATE); mContext.registerReceiver(mConnReceiver, connFilter, CONNECTIVITY_INTERNAL, mHandler); // listen for package/uid changes to update policy diff --git a/services/java/com/android/server/net/NetworkStatsService.java b/services/java/com/android/server/net/NetworkStatsService.java index bb0a0d132b44..e0dc96f99842 100644 --- a/services/java/com/android/server/net/NetworkStatsService.java +++ b/services/java/com/android/server/net/NetworkStatsService.java @@ -24,7 +24,7 @@ import static android.Manifest.permission.READ_NETWORK_USAGE_HISTORY; import static android.content.Intent.ACTION_SHUTDOWN; import static android.content.Intent.ACTION_UID_REMOVED; import static android.content.Intent.EXTRA_UID; -import static android.net.ConnectivityManager.CONNECTIVITY_ACTION; +import static android.net.ConnectivityManager.CONNECTIVITY_ACTION_IMMEDIATE; import static android.net.NetworkStats.IFACE_ALL; import static android.net.NetworkStats.SET_ALL; import static android.net.NetworkStats.SET_DEFAULT; @@ -239,7 +239,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { } // watch for network interfaces to be claimed - final IntentFilter connFilter = new IntentFilter(CONNECTIVITY_ACTION); + final IntentFilter connFilter = new IntentFilter(CONNECTIVITY_ACTION_IMMEDIATE); mContext.registerReceiver(mConnReceiver, connFilter, CONNECTIVITY_INTERNAL, mHandler); // listen for periodic polling events diff --git a/services/java/com/android/server/wm/WindowManagerService.java b/services/java/com/android/server/wm/WindowManagerService.java index 192d32b1c973..1a4caa7b1488 100644 --- a/services/java/com/android/server/wm/WindowManagerService.java +++ b/services/java/com/android/server/wm/WindowManagerService.java @@ -2533,6 +2533,7 @@ public class WindowManagerService extends IWindowManager.Stub boolean wallpaperMayMove = win.mViewVisibility != viewVisibility && (win.mAttrs.flags & FLAG_SHOW_WALLPAPER) != 0; + wallpaperMayMove |= (flagChanges & FLAG_SHOW_WALLPAPER) != 0; win.mRelayoutCalled = true; final int oldVisibility = win.mViewVisibility; @@ -7925,11 +7926,26 @@ public class WindowManagerService extends IWindowManager.Stub } if (windowAnimationBackgroundColor != 0) { + // If this window that wants black is the current wallpaper + // target, then the black goes *below* the wallpaper so we + // don't cause the wallpaper to suddenly disappear. + WindowState target = windowAnimationBackground; + if (mWallpaperTarget == windowAnimationBackground + || mLowerWallpaperTarget == windowAnimationBackground + || mUpperWallpaperTarget == windowAnimationBackground) { + for (i=0; i<mWindows.size(); i++) { + WindowState w = mWindows.get(i); + if (w.mIsWallpaper) { + target = w; + break; + } + } + } if (mWindowAnimationBackgroundSurface == null) { mWindowAnimationBackgroundSurface = new DimSurface(mFxSession); } mWindowAnimationBackgroundSurface.show(dw, dh, - windowAnimationBackground.mAnimLayer - LAYER_OFFSET_DIM, + target.mAnimLayer - LAYER_OFFSET_DIM, windowAnimationBackgroundColor); } else if (mWindowAnimationBackgroundSurface != null) { mWindowAnimationBackgroundSurface.hide(); diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp index f8925b840f7a..edbc7b023503 100644 --- a/services/surfaceflinger/Layer.cpp +++ b/services/surfaceflinger/Layer.cpp @@ -212,19 +212,6 @@ void Layer::setGeometry(hwc_layer_t* hwcl) } else { hwcl->transform = finalTransform; } -} - -void Layer::setPerFrameData(hwc_layer_t* hwcl) { - const sp<GraphicBuffer>& buffer(mActiveBuffer); - if (buffer == NULL) { - // this can happen if the client never drew into this layer yet, - // or if we ran out of memory. In that case, don't let - // HWC handle it. - hwcl->flags |= HWC_SKIP_LAYER; - hwcl->handle = NULL; - } else { - hwcl->handle = buffer->handle; - } if (isCropped()) { hwcl->sourceCrop.left = mCurrentCrop.left; @@ -232,6 +219,7 @@ void Layer::setPerFrameData(hwc_layer_t* hwcl) { hwcl->sourceCrop.right = mCurrentCrop.right; hwcl->sourceCrop.bottom = mCurrentCrop.bottom; } else { + const sp<GraphicBuffer>& buffer(mActiveBuffer); hwcl->sourceCrop.left = 0; hwcl->sourceCrop.top = 0; if (buffer != NULL) { @@ -244,6 +232,19 @@ void Layer::setPerFrameData(hwc_layer_t* hwcl) { } } +void Layer::setPerFrameData(hwc_layer_t* hwcl) { + const sp<GraphicBuffer>& buffer(mActiveBuffer); + if (buffer == NULL) { + // this can happen if the client never drew into this layer yet, + // or if we ran out of memory. In that case, don't let + // HWC handle it. + hwcl->flags |= HWC_SKIP_LAYER; + hwcl->handle = NULL; + } else { + hwcl->handle = buffer->handle; + } +} + void Layer::onDraw(const Region& clip) const { if (CC_UNLIKELY(mActiveBuffer == 0)) { @@ -416,8 +417,7 @@ void Layer::lockPageFlip(bool& recomputeVisibleRegions) return; } - mActiveBuffer = mSurfaceTexture->getCurrentBuffer(); - mSurfaceTexture->getTransformMatrix(mTextureMatrix); + sp<GraphicBuffer> newFrontBuffer(mSurfaceTexture->getCurrentBuffer()); const Rect crop(mSurfaceTexture->getCurrentCrop()); const uint32_t transform(mSurfaceTexture->getCurrentTransform()); @@ -432,7 +432,23 @@ void Layer::lockPageFlip(bool& recomputeVisibleRegions) mFlinger->invalidateHwcGeometry(); } - mCurrentOpacity = getOpacityForFormat(mActiveBuffer->format); + GLfloat textureMatrix[16]; + mSurfaceTexture->getTransformMatrix(textureMatrix); + if (memcmp(textureMatrix, mTextureMatrix, sizeof(textureMatrix))) { + memcpy(mTextureMatrix, textureMatrix, sizeof(textureMatrix)); + mFlinger->invalidateHwcGeometry(); + } + + uint32_t bufWidth = newFrontBuffer->getWidth(); + uint32_t bufHeight = newFrontBuffer->getHeight(); + if (mActiveBuffer != NULL) { + if (bufWidth != uint32_t(mActiveBuffer->width) || + bufHeight != uint32_t(mActiveBuffer->height)) { + mFlinger->invalidateHwcGeometry(); + } + } + + mCurrentOpacity = getOpacityForFormat(newFrontBuffer->format); if (oldOpacity != isOpaque()) { recomputeVisibleRegions = true; } @@ -446,15 +462,14 @@ void Layer::lockPageFlip(bool& recomputeVisibleRegions) // FIXME: mPostedDirtyRegion = dirty & bounds mPostedDirtyRegion.set(front.w, front.h); + // update active buffer + mActiveBuffer = newFrontBuffer; if ((front.w != front.requested_w) || (front.h != front.requested_h)) { // check that we received a buffer of the right size // (Take the buffer's orientation into account) - sp<GraphicBuffer> newFrontBuffer(mActiveBuffer); - uint32_t bufWidth = newFrontBuffer->getWidth(); - uint32_t bufHeight = newFrontBuffer->getHeight(); if (mCurrentTransform & Transform::ROT_90) { swap(bufWidth, bufHeight); } diff --git a/services/surfaceflinger/LayerBase.cpp b/services/surfaceflinger/LayerBase.cpp index c56836e75a9a..603fb607bae1 100644 --- a/services/surfaceflinger/LayerBase.cpp +++ b/services/surfaceflinger/LayerBase.cpp @@ -332,17 +332,18 @@ void LayerBase::setGeometry(hwc_layer_t* hwcl) reinterpret_cast<hwc_rect_t const *>( visibleRegionScreen.getArray( &hwcl->visibleRegionScreen.numRects)); -} -void LayerBase::setPerFrameData(hwc_layer_t* hwcl) { - hwcl->compositionType = HWC_FRAMEBUFFER; - hwcl->handle = NULL; hwcl->sourceCrop.left = 0; hwcl->sourceCrop.top = 0; hwcl->sourceCrop.right = mTransformedBounds.width(); hwcl->sourceCrop.bottom = mTransformedBounds.height(); } +void LayerBase::setPerFrameData(hwc_layer_t* hwcl) { + hwcl->compositionType = HWC_FRAMEBUFFER; + hwcl->handle = NULL; +} + void LayerBase::setFiltering(bool filtering) { mFiltering = filtering; diff --git a/services/tests/servicestests/src/com/android/server/NetworkPolicyManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/NetworkPolicyManagerServiceTest.java index f67d25191bf1..e892b5ebb393 100644 --- a/services/tests/servicestests/src/com/android/server/NetworkPolicyManagerServiceTest.java +++ b/services/tests/servicestests/src/com/android/server/NetworkPolicyManagerServiceTest.java @@ -18,7 +18,7 @@ package com.android.server; import static android.content.Intent.ACTION_UID_REMOVED; import static android.content.Intent.EXTRA_UID; -import static android.net.ConnectivityManager.CONNECTIVITY_ACTION; +import static android.net.ConnectivityManager.CONNECTIVITY_ACTION_IMMEDIATE; import static android.net.ConnectivityManager.TYPE_WIFI; import static android.net.NetworkPolicy.LIMIT_DISABLED; import static android.net.NetworkPolicy.SNOOZE_NEVER; @@ -511,7 +511,7 @@ public class NetworkPolicyManagerServiceTest extends AndroidTestCase { future = expectMeteredIfacesChanged(); replay(); - mServiceContext.sendBroadcast(new Intent(CONNECTIVITY_ACTION)); + mServiceContext.sendBroadcast(new Intent(CONNECTIVITY_ACTION_IMMEDIATE)); future.get(); verifyAndReset(); @@ -615,7 +615,7 @@ public class NetworkPolicyManagerServiceTest extends AndroidTestCase { future = expectMeteredIfacesChanged(TEST_IFACE); replay(); - mServiceContext.sendBroadcast(new Intent(CONNECTIVITY_ACTION)); + mServiceContext.sendBroadcast(new Intent(CONNECTIVITY_ACTION_IMMEDIATE)); future.get(); verifyAndReset(); } diff --git a/services/tests/servicestests/src/com/android/server/NetworkStatsServiceTest.java b/services/tests/servicestests/src/com/android/server/NetworkStatsServiceTest.java index 6dd8cd6d58bf..54f3bb0ed4c0 100644 --- a/services/tests/servicestests/src/com/android/server/NetworkStatsServiceTest.java +++ b/services/tests/servicestests/src/com/android/server/NetworkStatsServiceTest.java @@ -18,7 +18,7 @@ package com.android.server; import static android.content.Intent.ACTION_UID_REMOVED; import static android.content.Intent.EXTRA_UID; -import static android.net.ConnectivityManager.CONNECTIVITY_ACTION; +import static android.net.ConnectivityManager.CONNECTIVITY_ACTION_IMMEDIATE; import static android.net.ConnectivityManager.TYPE_MOBILE; import static android.net.ConnectivityManager.TYPE_WIFI; import static android.net.ConnectivityManager.TYPE_WIMAX; @@ -180,7 +180,7 @@ public class NetworkStatsServiceTest extends AndroidTestCase { expectNetworkStatsSummary(buildEmptyStats()); replay(); - mServiceContext.sendBroadcast(new Intent(CONNECTIVITY_ACTION)); + mServiceContext.sendBroadcast(new Intent(CONNECTIVITY_ACTION_IMMEDIATE)); // verify service has empty history for wifi assertNetworkTotal(sTemplateWifi, 0L, 0L, 0L, 0L, 0); @@ -232,7 +232,7 @@ public class NetworkStatsServiceTest extends AndroidTestCase { expectNetworkStatsSummary(buildEmptyStats()); replay(); - mServiceContext.sendBroadcast(new Intent(CONNECTIVITY_ACTION)); + mServiceContext.sendBroadcast(new Intent(CONNECTIVITY_ACTION_IMMEDIATE)); // verify service has empty history for wifi assertNetworkTotal(sTemplateWifi, 0L, 0L, 0L, 0L, 0); @@ -322,7 +322,7 @@ public class NetworkStatsServiceTest extends AndroidTestCase { expectNetworkStatsSummary(buildEmptyStats()); replay(); - mServiceContext.sendBroadcast(new Intent(CONNECTIVITY_ACTION)); + mServiceContext.sendBroadcast(new Intent(CONNECTIVITY_ACTION_IMMEDIATE)); verifyAndReset(); // modify some number on wifi, and trigger poll event @@ -372,7 +372,7 @@ public class NetworkStatsServiceTest extends AndroidTestCase { expectNetworkStatsSummary(buildEmptyStats()); replay(); - mServiceContext.sendBroadcast(new Intent(CONNECTIVITY_ACTION)); + mServiceContext.sendBroadcast(new Intent(CONNECTIVITY_ACTION_IMMEDIATE)); verifyAndReset(); // create some traffic on first network @@ -410,7 +410,7 @@ public class NetworkStatsServiceTest extends AndroidTestCase { expectNetworkStatsPoll(); replay(); - mServiceContext.sendBroadcast(new Intent(CONNECTIVITY_ACTION)); + mServiceContext.sendBroadcast(new Intent(CONNECTIVITY_ACTION_IMMEDIATE)); mServiceContext.sendBroadcast(new Intent(ACTION_NETWORK_STATS_POLL)); verifyAndReset(); @@ -452,7 +452,7 @@ public class NetworkStatsServiceTest extends AndroidTestCase { expectNetworkStatsSummary(buildEmptyStats()); replay(); - mServiceContext.sendBroadcast(new Intent(CONNECTIVITY_ACTION)); + mServiceContext.sendBroadcast(new Intent(CONNECTIVITY_ACTION_IMMEDIATE)); verifyAndReset(); // create some traffic @@ -509,7 +509,7 @@ public class NetworkStatsServiceTest extends AndroidTestCase { expectNetworkStatsSummary(buildEmptyStats()); replay(); - mServiceContext.sendBroadcast(new Intent(CONNECTIVITY_ACTION)); + mServiceContext.sendBroadcast(new Intent(CONNECTIVITY_ACTION_IMMEDIATE)); verifyAndReset(); // create some traffic @@ -541,7 +541,7 @@ public class NetworkStatsServiceTest extends AndroidTestCase { expectNetworkStatsPoll(); replay(); - mServiceContext.sendBroadcast(new Intent(CONNECTIVITY_ACTION)); + mServiceContext.sendBroadcast(new Intent(CONNECTIVITY_ACTION_IMMEDIATE)); mServiceContext.sendBroadcast(new Intent(ACTION_NETWORK_STATS_POLL)); verifyAndReset(); @@ -575,7 +575,7 @@ public class NetworkStatsServiceTest extends AndroidTestCase { expectNetworkStatsSummary(buildEmptyStats()); replay(); - mServiceContext.sendBroadcast(new Intent(CONNECTIVITY_ACTION)); + mServiceContext.sendBroadcast(new Intent(CONNECTIVITY_ACTION_IMMEDIATE)); verifyAndReset(); // create some traffic for two apps @@ -637,7 +637,7 @@ public class NetworkStatsServiceTest extends AndroidTestCase { expectNetworkStatsSummary(buildEmptyStats()); replay(); - mServiceContext.sendBroadcast(new Intent(CONNECTIVITY_ACTION)); + mServiceContext.sendBroadcast(new Intent(CONNECTIVITY_ACTION_IMMEDIATE)); verifyAndReset(); // create some initial traffic diff --git a/telephony/java/com/android/internal/telephony/IccCard.java b/telephony/java/com/android/internal/telephony/IccCard.java index bce99916662c..955849d4699c 100644 --- a/telephony/java/com/android/internal/telephony/IccCard.java +++ b/telephony/java/com/android/internal/telephony/IccCard.java @@ -470,19 +470,6 @@ public abstract class IccCard { } else if (isIccCardAdded) { mHandler.sendMessage(mHandler.obtainMessage(EVENT_CARD_ADDED, null)); } - - - - /* - * TODO: We need to try to remove this, maybe if the RIL sends up a RIL_UNSOL_SIM_REFRESH? - */ - if (oldState != State.READY && newState == State.READY && - mPhone.getLteOnCdmaMode() == Phone.LTE_ON_CDMA_TRUE) { - if (mPhone.mIccRecords instanceof SIMRecords) { - ((SIMRecords)mPhone.mIccRecords).onSimReady(); - } - } - } private void onIccSwap(boolean isAdded) { @@ -720,17 +707,14 @@ public abstract class IccCard { currentRadioState == RadioState.SIM_NOT_READY || currentRadioState == RadioState.RUIM_NOT_READY || currentRadioState == RadioState.NV_NOT_READY || - (currentRadioState == RadioState.NV_READY && - (mPhone.getLteOnCdmaMode() != Phone.LTE_ON_CDMA_TRUE))) { + currentRadioState == RadioState.NV_READY) { return IccCard.State.NOT_READY; } if( currentRadioState == RadioState.SIM_LOCKED_OR_ABSENT || currentRadioState == RadioState.SIM_READY || currentRadioState == RadioState.RUIM_LOCKED_OR_ABSENT || - currentRadioState == RadioState.RUIM_READY || - (currentRadioState == RadioState.NV_READY && - (mPhone.getLteOnCdmaMode() == Phone.LTE_ON_CDMA_TRUE))) { + currentRadioState == RadioState.RUIM_READY) { State csimState = getAppState(mIccCardStatus.getCdmaSubscriptionAppIndex()); diff --git a/telephony/java/com/android/internal/telephony/cdma/CdmaLteServiceStateTracker.java b/telephony/java/com/android/internal/telephony/cdma/CdmaLteServiceStateTracker.java index 134227a781f2..e92a276221ae 100644 --- a/telephony/java/com/android/internal/telephony/cdma/CdmaLteServiceStateTracker.java +++ b/telephony/java/com/android/internal/telephony/cdma/CdmaLteServiceStateTracker.java @@ -39,6 +39,7 @@ public class CdmaLteServiceStateTracker extends CdmaServiceStateTracker { CDMALTEPhone mCdmaLtePhone; private ServiceState mLteSS; // The last LTE state from Voice Registration + private boolean mNeedToRegForSimLoaded = true; public CdmaLteServiceStateTracker(CDMALTEPhone phone) { super(phone); @@ -71,7 +72,10 @@ public class CdmaLteServiceStateTracker extends CdmaServiceStateTracker { isSubscriptionFromRuim = false; // Register SIM_RECORDS_LOADED dynamically. // This is to avoid confilct with RUIM_READY scenario) - phone.mIccRecords.registerForRecordsLoaded(this, EVENT_SIM_RECORDS_LOADED, null); + if (mNeedToRegForSimLoaded) { + phone.mIccRecords.registerForRecordsLoaded(this, EVENT_SIM_RECORDS_LOADED, null); + mNeedToRegForSimLoaded = false; + } pollState(); // Signal strength polling stops when radio is off. queueNextSignalStrengthPoll(); diff --git a/telephony/java/com/android/internal/telephony/cdma/sms/BearerData.java b/telephony/java/com/android/internal/telephony/cdma/sms/BearerData.java index e17d98d0f5c5..6743da01f1d3 100755 --- a/telephony/java/com/android/internal/telephony/cdma/sms/BearerData.java +++ b/telephony/java/com/android/internal/telephony/cdma/sms/BearerData.java @@ -36,6 +36,7 @@ import com.android.internal.util.BitwiseOutputStream; import android.content.res.Resources; +import java.util.TimeZone; /** @@ -231,7 +232,7 @@ public final class BearerData { public static class TimeStamp extends Time { public TimeStamp() { - super(Time.TIMEZONE_UTC); + super(TimeZone.getDefault().getID()); // 3GPP2 timestamps use the local timezone } public static TimeStamp fromByteArray(byte[] data) { diff --git a/telephony/java/com/android/internal/telephony/gsm/SIMRecords.java b/telephony/java/com/android/internal/telephony/gsm/SIMRecords.java index 28034ccccf21..d84715ef9510 100755 --- a/telephony/java/com/android/internal/telephony/gsm/SIMRecords.java +++ b/telephony/java/com/android/internal/telephony/gsm/SIMRecords.java @@ -181,11 +181,7 @@ public class SIMRecords extends IccRecords { // recordsToLoad is set to 0 because no requests are made yet recordsToLoad = 0; - // SIMRecord is used by CDMA+LTE mode, and SIM_READY event - // will be subscribed by CdmaLteServiceStateTracker. - if (phone.getLteOnCdmaMode() != Phone.LTE_ON_CDMA_TRUE) { - p.mCM.registerForSIMReady(this, EVENT_SIM_READY, null); - } + p.mCM.registerForSIMReady(this, EVENT_SIM_READY, null); p.mCM.registerForOffOrNotAvailable( this, EVENT_RADIO_OFF_OR_NOT_AVAILABLE, null); p.mCM.setOnSmsOnSim(this, EVENT_SMS_ON_SIM, null); @@ -199,9 +195,7 @@ public class SIMRecords extends IccRecords { @Override public void dispose() { //Unregister for all events - if (phone.getLteOnCdmaMode() != Phone.LTE_ON_CDMA_TRUE) { - phone.mCM.unregisterForSIMReady(this); - } + phone.mCM.unregisterForSIMReady(this); phone.mCM.unregisterForOffOrNotAvailable( this); phone.mCM.unregisterForIccRefresh(this); } diff --git a/telephony/java/com/android/internal/telephony/gsm/SimCard.java b/telephony/java/com/android/internal/telephony/gsm/SimCard.java index 643f70917137..1fa278ac4a7a 100644 --- a/telephony/java/com/android/internal/telephony/gsm/SimCard.java +++ b/telephony/java/com/android/internal/telephony/gsm/SimCard.java @@ -49,7 +49,6 @@ public final class SimCard extends IccCard { updateStateProperty(); if(mPhone.getLteOnCdmaMode() == Phone.LTE_ON_CDMA_TRUE) { - mPhone.mCM.registerForNVReady(mHandler, EVENT_ICC_READY, null); mPhone.mCM.registerForIccStatusChanged(mHandler, EVENT_ICC_LOCKED_OR_ABSENT, null); } } @@ -63,7 +62,6 @@ public final class SimCard extends IccCard { mPhone.mCM.unregisterForSIMReady(mHandler); if(mPhone.getLteOnCdmaMode() == Phone.LTE_ON_CDMA_TRUE) { - mPhone.mCM.unregisterForNVReady(mHandler); mPhone.mCM.unregisterForIccStatusChanged(mHandler); } } diff --git a/tests/BandwidthTests/Android.mk b/tests/BandwidthTests/Android.mk new file mode 100644 index 000000000000..2cc2009147b3 --- /dev/null +++ b/tests/BandwidthTests/Android.mk @@ -0,0 +1,22 @@ +# +# Copyright (C) 2011 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. +# +LOCAL_PATH := $(call my-dir) +include $(CLEAR_VARS) + +LOCAL_PACKAGE_NAME := BandwidthEnforcementTest +LOCAL_SRC_FILES := $(call all-java-files-under, src) + +include $(BUILD_PACKAGE)
\ No newline at end of file diff --git a/tests/BandwidthTests/AndroidManifest.xml b/tests/BandwidthTests/AndroidManifest.xml new file mode 100644 index 000000000000..19f38cabf23e --- /dev/null +++ b/tests/BandwidthTests/AndroidManifest.xml @@ -0,0 +1,31 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Copyright (C) 2011 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. +--> +<manifest xmlns:android="http://schemas.android.com/apk/res/android" + package="com.android.tests.bandwidthenforcement"> + <uses-permission android:name="android.permission.INTERNET" /> + <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" /> + <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> + <application> + <activity android:name=".BandwidthEnforcementTestActivity"> + <intent-filter> + <action android:name="android.intent.action.MAIN" /> + <category android:name="android.intent.category.LAUNCHER" /> + </intent-filter> + </activity> + <!-- adb shell am startservice -n com.android.tests.bandwidthenforcement/.BandwidthEnforcementTestService --> + <service android:name=".BandwidthEnforcementTestService" android:exported="true" /> + </application> +</manifest> diff --git a/tests/BandwidthTests/res/layout/main.xml b/tests/BandwidthTests/res/layout/main.xml new file mode 100644 index 000000000000..3392b21a9728 --- /dev/null +++ b/tests/BandwidthTests/res/layout/main.xml @@ -0,0 +1,29 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Copyright (C) 2011 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. +--> +<LinearLayout + xmlns:android="http://schemas.android.com/apk/res/android" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:orientation="horizontal"> + <TextView + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:text="@string/app_name" /> + <TextView + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:text="@string/app_desc" /> +</LinearLayout> diff --git a/tests/BandwidthTests/res/values/strings.xml b/tests/BandwidthTests/res/values/strings.xml new file mode 100644 index 000000000000..a4a78c2642f6 --- /dev/null +++ b/tests/BandwidthTests/res/values/strings.xml @@ -0,0 +1,21 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Copyright (C) 2011 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> +<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="app_name">BandwidthEnforcementTest</string> + <string name="app_desc">Tries several tricks to get Internet access.</string> + <string name="start">Start</string> + <string name="stop">Stop</string> +</resources> diff --git a/tests/BandwidthTests/src/com/android/tests/bandwidthenforcement/BandwidthEnforcementTestActivity.java b/tests/BandwidthTests/src/com/android/tests/bandwidthenforcement/BandwidthEnforcementTestActivity.java new file mode 100644 index 000000000000..f0e43ace6f9e --- /dev/null +++ b/tests/BandwidthTests/src/com/android/tests/bandwidthenforcement/BandwidthEnforcementTestActivity.java @@ -0,0 +1,27 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.android.tests.bandwidthenforcement; + +import android.app.Activity; +import android.os.Bundle; + +public class BandwidthEnforcementTestActivity extends Activity { + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.main); + } +} diff --git a/tests/BandwidthTests/src/com/android/tests/bandwidthenforcement/BandwidthEnforcementTestService.java b/tests/BandwidthTests/src/com/android/tests/bandwidthenforcement/BandwidthEnforcementTestService.java new file mode 100644 index 000000000000..a2427f514e17 --- /dev/null +++ b/tests/BandwidthTests/src/com/android/tests/bandwidthenforcement/BandwidthEnforcementTestService.java @@ -0,0 +1,210 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.android.tests.bandwidthenforcement; + +import android.app.IntentService; +import android.content.Intent; +import android.net.SntpClient; +import android.os.Environment; +import android.util.Log; + +import java.io.BufferedWriter; +import java.io.ByteArrayOutputStream; +import java.io.File; +import java.io.FileWriter; +import java.io.IOException; +import java.io.InputStreamReader; +import java.net.DatagramPacket; +import java.net.DatagramSocket; +import java.net.HttpURLConnection; +import java.net.InetAddress; +import java.net.URL; +import java.util.Random; + +import libcore.io.Streams; + +/* + * Test Service that tries to connect to the web via different methods and outputs the results to + * the log and a output file. + */ +public class BandwidthEnforcementTestService extends IntentService { + private static final String TAG = "BandwidthEnforcementTestService"; + private static final String OUTPUT_FILE = "BandwidthEnforcementTestServiceOutputFile"; + + public BandwidthEnforcementTestService() { + super(TAG); + } + + @Override + protected void onHandleIntent(Intent intent) { + Log.d(TAG, "Trying to establish a connection."); + // Read output file path from intent. + String outputFile = intent.getStringExtra(OUTPUT_FILE); + dumpResult("testUrlConnection", testUrlConnection(), outputFile); + dumpResult("testUrlConnectionv6", testUrlConnectionv6(), outputFile); + dumpResult("testSntp", testSntp(), outputFile); + dumpResult("testDns", testDns(), outputFile); + } + + public static void dumpResult(String tag, boolean result, String outputFile) { + Log.d(TAG, "Test output file: " + outputFile); + try { + if (outputFile != null){ + File extStorage = Environment.getExternalStorageDirectory(); + File outFile = new File(extStorage, outputFile); + FileWriter writer = new FileWriter(outFile, true); + BufferedWriter out = new BufferedWriter(writer); + if (result) { + out.append(tag + ":fail\n"); + } else { + out.append(tag + ":pass\n"); + } + out.close(); + } + if (result) { + Log.e(TAG, tag + " FAILURE ===================="); + Log.e(TAG, tag + " FAILURE was able to use data"); + Log.e(TAG, tag + " FAILURE ===================="); + } else { + Log.d(TAG, tag + " success; unable to use data"); + } + } catch (IOException e) { + Log.e(TAG, "Could not write file " + e.getMessage()); + } + } + + /** + * Tests a normal http url connection. + * @return true if it was able to connect, false otherwise. + */ + public static boolean testUrlConnection() { + try { + final HttpURLConnection conn = (HttpURLConnection) new URL("http://www.google.com/") + .openConnection(); + try { + conn.connect(); + final String content = Streams.readFully( + new InputStreamReader(conn.getInputStream())); + if (content.contains("Google")) { + return true; + } + } finally { + conn.disconnect(); + } + } catch (IOException e) { + Log.d(TAG, "error: " + e); + } + return false; + } + + /** + * Tests a ipv6 http url connection. + * @return true if it was able to connect, false otherwise. + */ + public static boolean testUrlConnectionv6() { + try { + final HttpURLConnection conn = (HttpURLConnection) new URL("http://ipv6.google.com/") + .openConnection(); + try { + conn.connect(); + final String content = Streams.readFully( + new InputStreamReader(conn.getInputStream())); + if (content.contains("Google")) { + return true; + } + } finally { + conn.disconnect(); + } + } catch (IOException e) { + Log.d(TAG, "error: " + e); + } + return false; + } + + /** + * Tests to connect via sntp. + * @return true if it was able to connect, false otherwise. + */ + public static boolean testSntp() { + final SntpClient client = new SntpClient(); + if (client.requestTime("0.pool.ntp.org", 10000)) { + return true; + } + return false; + } + + /** + * Tests dns query. + * @return true if it was able to connect, false otherwise. + */ + public static boolean testDns() { + try { + final DatagramSocket socket = new DatagramSocket(); + try { + socket.setSoTimeout(10000); + + final byte[] query = buildDnsQuery("www", "android", "com"); + final DatagramPacket queryPacket = new DatagramPacket( + query, query.length, InetAddress.parseNumericAddress("8.8.8.8"), 53); + socket.send(queryPacket); + + final byte[] reply = new byte[query.length]; + final DatagramPacket replyPacket = new DatagramPacket(reply, reply.length); + socket.receive(replyPacket); + return true; + + } finally { + socket.close(); + } + } catch (IOException e) { + Log.d(TAG, "error: " + e); + } + return false; + } + + /** + * Helper method to build a dns query + * @param query the dns strings of the server + * @return the byte array of the dns query to send + * @throws IOException + */ + private static byte[] buildDnsQuery(String... query) throws IOException { + final Random random = new Random(); + final ByteArrayOutputStream out = new ByteArrayOutputStream(); + + final byte[] id = new byte[2]; + random.nextBytes(id); + + out.write(id); + out.write(new byte[] { 0x01, 0x00 }); + out.write(new byte[] { 0x00, 0x01 }); + out.write(new byte[] { 0x00, 0x00 }); + out.write(new byte[] { 0x00, 0x00 }); + out.write(new byte[] { 0x00, 0x00 }); + + for (String phrase : query) { + final byte[] bytes = phrase.getBytes("US-ASCII"); + out.write(bytes.length); + out.write(bytes); + } + out.write(0x00); + + out.write(new byte[] { 0x00, 0x01 }); + out.write(new byte[] { 0x00, 0x01 }); + + return out.toByteArray(); + } +} diff --git a/voip/java/com/android/server/sip/SipSessionGroup.java b/voip/java/com/android/server/sip/SipSessionGroup.java index 3b3cbf3e5516..49effa864905 100644 --- a/voip/java/com/android/server/sip/SipSessionGroup.java +++ b/voip/java/com/android/server/sip/SipSessionGroup.java @@ -72,6 +72,7 @@ import javax.sip.TransactionUnavailableException; import javax.sip.address.Address; import javax.sip.address.SipURI; import javax.sip.header.CSeqHeader; +import javax.sip.header.ContactHeader; import javax.sip.header.ExpiresHeader; import javax.sip.header.FromHeader; import javax.sip.header.HeaderAddress; @@ -873,16 +874,21 @@ class SipSessionGroup implements SipListener { } private int getExpiryTime(Response response) { - int expires = EXPIRY_TIME; - ExpiresHeader expiresHeader = (ExpiresHeader) - response.getHeader(ExpiresHeader.NAME); - if (expiresHeader != null) expires = expiresHeader.getExpires(); - expiresHeader = (ExpiresHeader) - response.getHeader(MinExpiresHeader.NAME); - if (expiresHeader != null) { - expires = Math.max(expires, expiresHeader.getExpires()); - } - return expires; + int time = -1; + ContactHeader contact = (ContactHeader) response.getHeader(ContactHeader.NAME); + if (contact != null) { + time = contact.getExpires(); + } + ExpiresHeader expires = (ExpiresHeader) response.getHeader(ExpiresHeader.NAME); + if (expires != null && (time < 0 || time > expires.getExpires())) { + time = expires.getExpires(); + } + expires = (ExpiresHeader) response.getHeader(MinExpiresHeader.NAME); + if (expires != null && time < expires.getExpires()) { + time = expires.getExpires(); + } + Log.v(TAG, "Expiry time = " + time); + return (time > 0) ? time : EXPIRY_TIME; } private boolean registeringToReady(EventObject evt) diff --git a/wifi/java/android/net/wifi/WifiNative.java b/wifi/java/android/net/wifi/WifiNative.java index c1f67853ccf2..2cd54d920bbe 100644 --- a/wifi/java/android/net/wifi/WifiNative.java +++ b/wifi/java/android/net/wifi/WifiNative.java @@ -60,7 +60,9 @@ public class WifiNative { public native static boolean startSupplicant(); - /* Does a graceful shutdown of supplicant. + public native static boolean startP2pSupplicant(); + + /* Does a graceful shutdown of supplicant. Is a common stop function for both p2p and sta. * * Note that underneath we use a harsh-sounding "terminate" supplicant command * for a graceful stop and a mild-sounding "stop" interface @@ -215,6 +217,19 @@ public class WifiNative { return doBooleanCommand("WPS_PIN any " + pin); } + public static boolean setPersistentReconnect(boolean enabled) { + int value = (enabled == true) ? 1 : 0; + return WifiNative.doBooleanCommand("SET persistent_reconnect " + value); + } + + public static boolean setDeviceName(String name) { + return WifiNative.doBooleanCommand("SET device_name " + name); + } + + public static boolean setDeviceType(String type) { + return WifiNative.doBooleanCommand("SET device_type " + type); + } + public static boolean p2pFind() { return doBooleanCommand("P2P_FIND"); } diff --git a/wifi/java/android/net/wifi/p2p/WifiP2pService.java b/wifi/java/android/net/wifi/p2p/WifiP2pService.java index adf13be41cb0..f67680d6a04f 100644 --- a/wifi/java/android/net/wifi/p2p/WifiP2pService.java +++ b/wifi/java/android/net/wifi/p2p/WifiP2pService.java @@ -50,6 +50,7 @@ import android.os.Message; import android.os.Messenger; import android.os.ServiceManager; import android.os.SystemProperties; +import android.provider.Settings; import android.util.Slog; import android.view.LayoutInflater; import android.view.View; @@ -126,6 +127,8 @@ public class WifiP2pService extends IWifiP2pManager.Stub { private static final int WIFI_DISABLE_USER_ACCEPT = BASE + 11; private final boolean mP2pSupported; + private final String mDeviceType; + private String mDeviceName; private NetworkInfo mNetworkInfo; @@ -142,6 +145,9 @@ public class WifiP2pService extends IWifiP2pManager.Stub { mP2pSupported = mContext.getResources().getBoolean( com.android.internal.R.bool.config_wifi_p2p_support); + mDeviceType = mContext.getResources().getString( + com.android.internal.R.string.config_wifi_p2p_device_type); + mDeviceName = getDefaultDeviceName(); mP2pStateMachine = new P2pStateMachine(TAG, mP2pSupported); mP2pStateMachine.start(); @@ -182,6 +188,14 @@ public class WifiP2pService extends IWifiP2pManager.Stub { "WifiP2pService"); } + /* We use the 4 digits of the ANDROID_ID to have a friendly + * default that has low likelihood of collision with a peer */ + private String getDefaultDeviceName() { + String id = Settings.Secure.getString(mContext.getContentResolver(), + Settings.Secure.ANDROID_ID); + return "Android_" + id.substring(0,4); + } + /** * Get a reference to handler. This is used by a client to establish * an AsyncChannel communication with WifiP2pService @@ -514,7 +528,7 @@ public class WifiP2pService extends IWifiP2pManager.Stub { if (DBG) Slog.w(TAG, "Unable to bring down wlan interface: " + e); } - if (WifiNative.startSupplicant()) { + if (WifiNative.startP2pSupplicant()) { mWifiMonitor.startMonitoring(); transitionTo(mP2pEnablingState); } else { @@ -577,6 +591,7 @@ public class WifiP2pService extends IWifiP2pManager.Stub { mNetworkInfo.setIsAvailable(true); //Start listening for new connections WifiNative.p2pListen(); + initializeP2pSettings(); } @Override @@ -637,6 +652,22 @@ public class WifiP2pService extends IWifiP2pManager.Stub { if (mPeers.clear()) sendP2pPeersChangedBroadcast(); transitionTo(mP2pDisabledState); sendMessageDelayed(WifiP2pManager.ENABLE_P2P, P2P_RESTART_INTERVAL_MSECS); + break; + case WifiMonitor.P2P_GROUP_STARTED_EVENT: + mGroup = (WifiP2pGroup) message.obj; + if (DBG) logd(getName() + " group started"); + if (mGroup.isGroupOwner()) { + startDhcpServer(mGroup.getInterface()); + } else { + mDhcpStateMachine = DhcpStateMachine.makeDhcpStateMachine(mContext, + P2pStateMachine.this, mGroup.getInterface()); + mDhcpStateMachine.sendMessage(DhcpStateMachine.CMD_START_DHCP); + WifiP2pDevice groupOwner = mGroup.getOwner(); + updateDeviceStatus(groupOwner.deviceAddress, Status.CONNECTED); + sendP2pPeersChangedBroadcast(); + } + transitionTo(mGroupCreatedState); + break; default: return NOT_HANDLED; } @@ -708,21 +739,6 @@ public class WifiP2pService extends IWifiP2pManager.Stub { sendP2pPeersChangedBroadcast(); transitionTo(mInactiveState); break; - case WifiMonitor.P2P_GROUP_STARTED_EVENT: - mGroup = (WifiP2pGroup) message.obj; - if (DBG) logd(getName() + " group started"); - if (mGroup.isGroupOwner()) { - startDhcpServer(mGroup.getInterface()); - } else { - mDhcpStateMachine = DhcpStateMachine.makeDhcpStateMachine(mContext, - P2pStateMachine.this, mGroup.getInterface()); - mDhcpStateMachine.sendMessage(DhcpStateMachine.CMD_START_DHCP); - WifiP2pDevice groupOwner = mGroup.getOwner(); - updateDeviceStatus(groupOwner.deviceAddress, Status.CONNECTED); - sendP2pPeersChangedBroadcast(); - } - transitionTo(mGroupCreatedState); - break; case GROUP_NEGOTIATION_TIMED_OUT: if (mGroupNegotiationTimeoutIndex == message.arg1) { if (DBG) logd("Group negotiation timed out"); @@ -760,25 +776,33 @@ public class WifiP2pService extends IWifiP2pManager.Stub { //After a GO setup, STA connected event comes with interface address String interfaceAddress = (String) message.obj; String deviceAddress = getDeviceAddress(interfaceAddress); - mGroup.addClient(deviceAddress); - updateDeviceStatus(deviceAddress, Status.CONNECTED); - if (DBG) logd(getName() + " ap sta connected"); - sendP2pPeersChangedBroadcast(); + if (deviceAddress != null) { + mGroup.addClient(deviceAddress); + updateDeviceStatus(deviceAddress, Status.CONNECTED); + if (DBG) logd(getName() + " ap sta connected"); + sendP2pPeersChangedBroadcast(); + } else { + loge("Connect on unknown device address : " + interfaceAddress); + } break; case WifiMonitor.AP_STA_DISCONNECTED_EVENT: interfaceAddress = (String) message.obj; deviceAddress = getDeviceAddress(interfaceAddress); - updateDeviceStatus(deviceAddress, Status.AVAILABLE); - if (mGroup.removeClient(deviceAddress)) { - if (DBG) logd("Removed client " + deviceAddress); - sendP2pPeersChangedBroadcast(); - } else { - if (DBG) logd("Failed to remove client " + deviceAddress); - for (WifiP2pDevice c : mGroup.getClientList()) { - if (DBG) logd("client " + c.deviceAddress); + if (deviceAddress != null) { + updateDeviceStatus(deviceAddress, Status.AVAILABLE); + if (mGroup.removeClient(deviceAddress)) { + if (DBG) logd("Removed client " + deviceAddress); + sendP2pPeersChangedBroadcast(); + } else { + if (DBG) logd("Failed to remove client " + deviceAddress); + for (WifiP2pDevice c : mGroup.getClientList()) { + if (DBG) logd("client " + c.deviceAddress); + } } + if (DBG) loge(getName() + " ap sta disconnected"); + } else { + loge("Disconnect on unknown device address : " + interfaceAddress); } - if (DBG) loge(getName() + " ap sta disconnected"); break; case DhcpStateMachine.CMD_POST_DHCP_ACTION: DhcpInfoInternal dhcpInfo = (DhcpInfoInternal) message.obj; @@ -857,6 +881,9 @@ public class WifiP2pService extends IWifiP2pManager.Stub { case WifiMonitor.P2P_PROV_DISC_ENTER_PIN_EVENT: notifyP2pProvDiscPinRequest((WifiP2pDevice) message.obj); break; + case WifiMonitor.P2P_GROUP_STARTED_EVENT: + Slog.e(TAG, "Duplicate group creation event notice, ignore"); + break; case WifiP2pManager.WPS_PBC: WifiNative.wpsPbc(); break; @@ -1117,6 +1144,12 @@ public class WifiP2pService extends IWifiP2pManager.Stub { return null; } + private void initializeP2pSettings() { + WifiNative.setPersistentReconnect(true); + WifiNative.setDeviceName(mDeviceName); + WifiNative.setDeviceType(mDeviceType); + } + //State machine initiated requests can have replyTo set to null indicating //there are no recepients, we ignore those reply actions private void replyToMessage(Message msg, int what) { |