Merge "Make the SyncManager timeout syncs if it takes too long to bind to them."
diff --git a/api/current.txt b/api/current.txt
index e379f8b..21ee1f1 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -370,6 +370,7 @@
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 @@
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 @@
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 @@
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 @@
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();
@@ -8643,6 +8648,7 @@
method public void setEmpty();
method public boolean setIntersect(android.graphics.RectF, android.graphics.RectF);
method public void sort();
+ method public java.lang.String toShortString();
method public void union(float, float, float, float);
method public void union(android.graphics.RectF);
method public void union(float, float);
@@ -10675,6 +10681,7 @@
method public void setOnSeekCompleteListener(android.media.MediaPlayer.OnSeekCompleteListener);
method public void setOnVideoSizeChangedListener(android.media.MediaPlayer.OnVideoSizeChangedListener);
method public void setScreenOnWhilePlaying(boolean);
+ method public void setSurface(android.view.Surface);
method public void setTexture(android.graphics.SurfaceTexture);
method public void setVolume(float, float);
method public void setWakeMode(android.content.Context, int);
@@ -12391,6 +12398,7 @@
public final class NdefRecord implements android.os.Parcelable {
ctor public NdefRecord(short, byte[], byte[], byte[]);
ctor public NdefRecord(byte[]) throws android.nfc.FormatException;
+ method public static android.nfc.NdefRecord createApplicationRecord(java.lang.String);
method public static android.nfc.NdefRecord createUri(android.net.Uri);
method public static android.nfc.NdefRecord createUri(java.lang.String);
method public int describeContents();
@@ -12425,9 +12433,9 @@
method public static android.nfc.NfcAdapter getDefaultAdapter(android.content.Context);
method public static deprecated android.nfc.NfcAdapter getDefaultAdapter();
method public boolean isEnabled();
- method public void setNdefPushMessage(android.nfc.NdefMessage, android.app.Activity...);
- method public void setNdefPushMessageCallback(android.nfc.NfcAdapter.CreateNdefMessageCallback, android.app.Activity...);
- method public void setOnNdefPushCompleteCallback(android.nfc.NfcAdapter.OnNdefPushCompleteCallback, android.app.Activity...);
+ method public void setNdefPushMessage(android.nfc.NdefMessage, android.app.Activity, android.app.Activity...);
+ method public void setNdefPushMessageCallback(android.nfc.NfcAdapter.CreateNdefMessageCallback, android.app.Activity, android.app.Activity...);
+ method public void setOnNdefPushCompleteCallback(android.nfc.NfcAdapter.OnNdefPushCompleteCallback, android.app.Activity, android.app.Activity...);
field public static final java.lang.String ACTION_NDEF_DISCOVERED = "android.nfc.action.NDEF_DISCOVERED";
field public static final java.lang.String ACTION_TAG_DISCOVERED = "android.nfc.action.TAG_DISCOVERED";
field public static final java.lang.String ACTION_TECH_DISCOVERED = "android.nfc.action.TECH_DISCOVERED";
@@ -12481,6 +12489,7 @@
method public byte[] getHiLayerResponse();
method public byte[] getHistoricalBytes();
method public int getMaxTransceiveLength();
+ method public int getTimeout();
method public void setTimeout(int);
method public byte[] transceive(byte[]) throws java.io.IOException;
}
@@ -12496,11 +12505,13 @@
method public int getMaxTransceiveLength();
method public int getSectorCount();
method public int getSize();
+ method public int getTimeout();
method public int getType();
method public void increment(int, int) throws java.io.IOException;
method public byte[] readBlock(int) throws java.io.IOException;
method public void restore(int) throws java.io.IOException;
method public int sectorToBlock(int);
+ method public void setTimeout(int);
method public byte[] transceive(byte[]) throws java.io.IOException;
method public void transfer(int) throws java.io.IOException;
method public void writeBlock(int, byte[]) throws java.io.IOException;
@@ -12521,8 +12532,10 @@
public final class MifareUltralight extends android.nfc.tech.BasicTagTechnology {
method public static android.nfc.tech.MifareUltralight get(android.nfc.Tag);
method public int getMaxTransceiveLength();
+ method public int getTimeout();
method public int getType();
method public byte[] readPages(int) throws java.io.IOException;
+ method public void setTimeout(int);
method public byte[] transceive(byte[]) throws java.io.IOException;
method public void writePage(int, byte[]) throws java.io.IOException;
field public static final int PAGE_SIZE = 4; // 0x4
@@ -12559,6 +12572,8 @@
method public byte[] getAtqa();
method public int getMaxTransceiveLength();
method public short getSak();
+ method public int getTimeout();
+ method public void setTimeout(int);
method public byte[] transceive(byte[]) throws java.io.IOException;
}
@@ -12575,6 +12590,8 @@
method public byte[] getManufacturer();
method public int getMaxTransceiveLength();
method public byte[] getSystemCode();
+ method public int getTimeout();
+ method public void setTimeout(int);
method public byte[] transceive(byte[]) throws java.io.IOException;
}
@@ -15593,7 +15610,7 @@
public static final class CalendarContract.Calendars implements android.provider.BaseColumns android.provider.CalendarContract.CalendarColumns android.provider.CalendarContract.SyncColumns {
field public static final java.lang.String CALENDAR_LOCATION = "calendar_location";
field public static final android.net.Uri CONTENT_URI;
- field public static final java.lang.String DEFAULT_SORT_ORDER = "displayName";
+ field public static final java.lang.String DEFAULT_SORT_ORDER = "calendar_displayName";
field public static final java.lang.String NAME = "name";
}
@@ -16052,7 +16069,7 @@
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 +16596,16 @@
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 +16704,7 @@
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 +16742,7 @@
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 +20700,13 @@
field protected final int mVerticalAlignment;
}
+ public class EasyEditSpan implements android.text.ParcelableSpan {
+ ctor public EasyEditSpan();
+ 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 +22544,7 @@
}
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;
@@ -23008,7 +23045,6 @@
method public boolean willNotDraw();
field public static android.util.Property ALPHA;
field protected static int DEFAULT_TEXT_DIRECTION;
- field protected static float DEFAULT_TEXT_DIRECTION_CHAR_COUNT_THRESHOLD;
field public static final int DRAWING_CACHE_QUALITY_AUTO = 0; // 0x0
field public static final int DRAWING_CACHE_QUALITY_HIGH = 1048576; // 0x100000
field public static final int DRAWING_CACHE_QUALITY_LOW = 524288; // 0x80000
@@ -25749,6 +25785,17 @@
ctor public DigitalClock(android.content.Context, android.util.AttributeSet);
}
+ public class EdgeEffect {
+ ctor public EdgeEffect(android.content.Context);
+ method public boolean draw(android.graphics.Canvas);
+ method public void finish();
+ method public boolean isFinished();
+ method public void onAbsorb(int);
+ method public void onPull(float);
+ method public void onRelease();
+ method public void setSize(int, int);
+ }
+
public class EditText extends android.widget.TextView {
ctor public EditText(android.content.Context);
ctor public EditText(android.content.Context, android.util.AttributeSet);
@@ -26334,6 +26381,7 @@
method public void fling(int, int, int, int, int, int, int, int);
method public void fling(int, int, int, int, int, int, int, int, int, int);
method public final void forceFinished(boolean);
+ method public float getCurrVelocity();
method public final int getCurrX();
method public final int getCurrY();
method public final int getFinalX();
@@ -26676,6 +26724,7 @@
method public void extendDuration(int);
method public void fling(int, int, int, int, int, int, int, int);
method public final void forceFinished(boolean);
+ method public float getCurrVelocity();
method public final int getCurrX();
method public final int getCurrY();
method public final int getDuration();
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java
index 1271ddd..41e3fdf 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -4206,7 +4206,6 @@
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 @@
// 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.
@@ -4473,9 +4471,12 @@
ManagedCursor mc = mManagedCursors.get(i);
if (mc.mReleased || mc.mUpdated) {
if (!mc.mCursor.requery()) {
- throw new IllegalStateException(
- "trying to requery an already closed cursor "
- + mc.mCursor);
+ if (getApplicationInfo().targetSdkVersion
+ >= android.os.Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
+ throw new IllegalStateException(
+ "trying to requery an already closed cursor "
+ + mc.mCursor);
+ }
}
mc.mReleased = false;
mc.mUpdated = false;
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index e3075d7..8275cbd 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -1291,7 +1291,8 @@
public final boolean queueIdle() {
ActivityClientRecord a = mNewActivities;
boolean stopProfiling = false;
- if (mBoundApplication.profileFd != null && mBoundApplication.autoStopProfiler) {
+ if (mBoundApplication != null && mBoundApplication.profileFd != null
+ && mBoundApplication.autoStopProfiler) {
stopProfiling = true;
}
if (a != null) {
diff --git a/core/java/android/app/BackStackRecord.java b/core/java/android/app/BackStackRecord.java
index 93330a7..e9e8e16 100644
--- a/core/java/android/app/BackStackRecord.java
+++ b/core/java/android/app/BackStackRecord.java
@@ -344,10 +344,6 @@
}
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 @@
}
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 @@
}
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 @@
}
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 @@
}
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 @@
}
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 @@
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 @@
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 @@
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 @@
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 a8621f8..3a08e6d 100644
--- a/core/java/android/app/Fragment.java
+++ b/core/java/android/app/Fragment.java
@@ -402,10 +402,6 @@
// 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 @@
// 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 @@
}
}
}
-
+
+ /**
+ * 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 @@
mRestored = false;
mBackStackNesting = 0;
mFragmentManager = null;
- mActivity = mImmediateActivity = null;
+ mActivity = null;
mFragmentId = 0;
mContainerId = 0;
mTag = null;
@@ -1421,17 +1438,14 @@
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 70e6866..7a6759f 100644
--- a/core/java/android/app/FragmentManager.java
+++ b/core/java/android/app/FragmentManager.java
@@ -67,6 +67,13 @@
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 @@
if (!f.mRetaining) {
makeInactive(f);
} else {
- f.mImmediateActivity = null;
f.mActivity = null;
f.mFragmentManager = null;
}
@@ -1037,7 +1043,7 @@
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 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 @@
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 @@
}
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 @@
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 @@
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 @@
"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 @@
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 @@
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 @@
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 @@
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 58ea0c3..9542874 100644
--- a/core/java/android/app/backup/BackupAgent.java
+++ b/core/java/android/app/backup/BackupAgent.java
@@ -255,10 +255,7 @@
* 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 2236928..254c98f 100644
--- a/core/java/android/bluetooth/BluetoothAdapter.java
+++ b/core/java/android/bluetooth/BluetoothAdapter.java
@@ -22,6 +22,7 @@
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 @@
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 @@
throw new IllegalArgumentException("service is null");
}
mService = service;
+ mServiceRecordHandler = null;
}
/**
@@ -1011,7 +1015,21 @@
} 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 @@
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/content/Intent.java b/core/java/android/content/Intent.java
index 8d6cee1..c7698bf 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -5627,6 +5627,10 @@
if (scheme != null) {
if (scheme.equalsIgnoreCase("tel")) {
b.append("tel:xxx-xxx-xxxx");
+ } else if (scheme.equalsIgnoreCase("sip")) {
+ b.append("sip:xxxxxxxxxx");
+ } else if (scheme.equalsIgnoreCase("sms")) {
+ b.append("sms:xxx-xxx-xxxx");
} else if (scheme.equalsIgnoreCase("smsto")) {
b.append("smsto:xxx-xxx-xxxx");
} else {
diff --git a/core/java/android/database/AbstractCursor.java b/core/java/android/database/AbstractCursor.java
index b6487bd..5fe42db 100644
--- a/core/java/android/database/AbstractCursor.java
+++ b/core/java/android/database/AbstractCursor.java
@@ -36,6 +36,8 @@
DataSetObservable mDataSetObservable = new DataSetObservable();
ContentObservable mContentObservable = new ContentObservable();
+ Bundle mExtras = Bundle.EMPTY;
+
/* -------------------------------------------------------- */
/* These need to be implemented by subclasses */
abstract public int getCount();
@@ -71,11 +73,11 @@
public int getColumnCount() {
return getColumnNames().length;
}
-
+
public void deactivate() {
deactivateInternal();
}
-
+
/**
* @hide
*/
@@ -99,7 +101,7 @@
public boolean isClosed() {
return mClosed;
}
-
+
public void close() {
mClosed = true;
mContentObservable.unregisterAll();
@@ -120,7 +122,7 @@
return true;
}
-
+
public void copyStringToBuffer(int columnIndex, CharArrayBuffer buffer) {
// Default implementation, uses getString
String result = getString(columnIndex);
@@ -136,7 +138,7 @@
buffer.sizeCopied = 0;
}
}
-
+
/* -------------------------------------------------------- */
/* Implementation */
public AbstractCursor() {
@@ -181,7 +183,7 @@
return result;
}
-
+
/**
* Copy data from cursor to CursorWindow
* @param position start position of data
@@ -199,7 +201,7 @@
window.setStartPosition(position);
int columnNum = getColumnCount();
window.setNumColumns(columnNum);
- while (moveToNext() && window.allocRow()) {
+ while (moveToNext() && window.allocRow()) {
for (int i = 0; i < columnNum; i++) {
String field = getString(i);
if (field != null) {
@@ -215,7 +217,7 @@
}
}
}
-
+
mPos = oldpos;
} catch (IllegalStateException e){
// simply ignore it
@@ -314,7 +316,7 @@
mContentObservable.unregisterObserver(observer);
}
}
-
+
/**
* This is hidden until the data set change model has been re-evaluated.
* @hide
@@ -322,14 +324,14 @@
protected void notifyDataSetChange() {
mDataSetObservable.notifyChanged();
}
-
+
/**
* This is hidden until the data set change model has been re-evaluated.
* @hide
*/
protected DataSetObservable getDataSetObservable() {
return mDataSetObservable;
-
+
}
public void registerDataSetObserver(DataSetObserver observer) {
@@ -383,8 +385,19 @@
return false;
}
+ /**
+ * Sets a {@link Bundle} that will be returned by {@link #getExtras()}. <code>null</code> will
+ * be converted into {@link Bundle#EMPTY}.
+ *
+ * @param extras {@link Bundle} to set.
+ * @hide
+ */
+ public void setExtras(Bundle extras) {
+ mExtras = (extras == null) ? Bundle.EMPTY : extras;
+ }
+
public Bundle getExtras() {
- return Bundle.EMPTY;
+ return mExtras;
}
public Bundle respond(Bundle extras) {
diff --git a/core/java/android/hardware/Camera.java b/core/java/android/hardware/Camera.java
index bc45945..63f2244 100644
--- a/core/java/android/hardware/Camera.java
+++ b/core/java/android/hardware/Camera.java
@@ -1468,6 +1468,7 @@
private static final String KEY_MAX_NUM_DETECTED_FACES_HW = "max-num-detected-faces-hw";
private static final String KEY_MAX_NUM_DETECTED_FACES_SW = "max-num-detected-faces-sw";
private static final String KEY_RECORDING_HINT = "recording-hint";
+ private static final String KEY_VIDEO_SNAPSHOT_SUPPORTED = "video-snapshot-supported";
// Parameter key suffix for supported values.
private static final String SUPPORTED_VALUES_SUFFIX = "-values";
@@ -3210,6 +3211,35 @@
set(KEY_RECORDING_HINT, hint ? TRUE : FALSE);
}
+ /**
+ * Returns true if video snapshot is supported. That is, applications
+ * can call {@link #takePicture(Camera.ShutterCallback,
+ * Camera.PictureCallback, Camera.PictureCallback, Camera.PictureCallback)}
+ * during recording. Applications do not need to call {@link
+ * #startPreview()} after taking a picture. The preview will be still
+ * active. Other than that, taking a picture during recording is
+ * identical to taking a picture normally. All settings and methods
+ * related to takePicture work identically. Ex: {@link
+ * #getPictureSize()}, {@link #getSupportedPictureSizes()}, {@link
+ * #setJpegQuality(int)}, {@link #setRotation(int)}, and etc. The
+ * picture will have an EXIF header. {@link #FLASH_MODE_AUTO} and {@link
+ * #FLASH_MODE_ON} also still work, but the video will record the flash.
+ *
+ * Applications can set shutter callback as null to avoid the shutter
+ * sound. It is also recommended to set raw picture and post view
+ * callbacks to null to avoid the interrupt of preview display.
+ *
+ * Field-of-view of the recorded video may be different from that of the
+ * captured pictures.
+ *
+ * @return true if video snapshot is supported.
+ * @hide
+ */
+ public boolean isVideoSnapshotSupported() {
+ String str = get(KEY_VIDEO_SNAPSHOT_SUPPORTED);
+ return TRUE.equals(str);
+ }
+
// Splits a comma delimited string to an ArrayList of String.
// Return null if the passing string is null or the size is 0.
private ArrayList<String> split(String str) {
diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java
index 9c96883..530122c 100644
--- a/core/java/android/net/ConnectivityManager.java
+++ b/core/java/android/net/ConnectivityManager.java
@@ -23,6 +23,7 @@
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 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)}.
*
@@ -804,4 +814,22 @@
} catch (RemoteException e) {
}
}
+
+ /**
+ * Returns true if the hardware supports the given network type
+ * else it returns false. This doesn't indicate we have coverage
+ * or are authorized onto a network, just whether or not the
+ * hardware supports it. For example a gsm phone without a sim
+ * should still return true for mobile data, but a wifi only tablet
+ * would return false.
+ * @param networkType The nework type we'd like to check
+ * @return true if supported, else false
+ * @hide
+ */
+ public boolean isNetworkSupported(int networkType) {
+ try {
+ return mService.isNetworkSupported(networkType);
+ } catch (RemoteException e) {}
+ return false;
+ }
}
diff --git a/core/java/android/net/IConnectivityManager.aidl b/core/java/android/net/IConnectivityManager.aidl
index c9553c0..eef658e 100644
--- a/core/java/android/net/IConnectivityManager.aidl
+++ b/core/java/android/net/IConnectivityManager.aidl
@@ -43,6 +43,8 @@
NetworkInfo getNetworkInfo(int networkType);
NetworkInfo[] getAllNetworkInfo();
+ boolean isNetworkSupported(int networkType);
+
LinkProperties getActiveLinkProperties();
LinkProperties getLinkProperties(int networkType);
diff --git a/core/java/android/nfc/NdefRecord.java b/core/java/android/nfc/NdefRecord.java
index 6ba3451..26571ff 100644
--- a/core/java/android/nfc/NdefRecord.java
+++ b/core/java/android/nfc/NdefRecord.java
@@ -152,8 +152,6 @@
* RTD_ANDROID_APP records.
* @hide
*/
- // TODO unhide for ICS
- // TODO recheck docs
public static final byte[] RTD_ANDROID_APP = "android.com:pkg".getBytes();
private static final byte FLAG_MB = (byte) 0x80;
@@ -352,21 +350,29 @@
/**
* Creates an Android application NDEF record.
* <p>
+ * This record indicates to other Android devices the package
+ * that should be used to handle the rest of the NDEF message.
+ * You can embed this record anywhere into your NDEF message
+ * to ensure that the intended package receives the message.
+ * <p>
* When an Android device dispatches an {@link NdefMessage}
* containing one or more Android application records,
* the applications contained in those records will be the
* preferred target for the NDEF_DISCOVERED intent, in
* the order in which they appear in the {@link NdefMessage}.
+ * This dispatch behavior was first added to Android in
+ * Ice Cream Sandwich.
* <p>
* If none of the applications are installed on the device,
* a Market link will be opened to the first application.
* <p>
* Note that Android application records do not overrule
- * applications that have called {@link NfcAdapter#enableForegroundDispatch}.
- * @hide
+ * applications that have called
+ * {@link NfcAdapter#enableForegroundDispatch}.
+ *
+ * @param packageName Android package name
+ * @return Android application NDEF record
*/
- // TODO unhide for ICS
- // TODO recheck javadoc - should mention this works from ICS only
public static NdefRecord createApplicationRecord(String packageName) {
return new NdefRecord(TNF_EXTERNAL_TYPE, RTD_ANDROID_APP, new byte[] {},
packageName.getBytes(Charsets.US_ASCII));
diff --git a/core/java/android/nfc/NfcAdapter.java b/core/java/android/nfc/NfcAdapter.java
index d58b249..e392bca 100644
--- a/core/java/android/nfc/NfcAdapter.java
+++ b/core/java/android/nfc/NfcAdapter.java
@@ -507,16 +507,24 @@
* <p>Pass a null NDEF message to disable foreground NDEF push in the
* specified activities.
*
+ * <p>One or more activities must be specified.
+ *
* <p class="note">Requires the {@link android.Manifest.permission#NFC} permission.
*
* @param message NDEF message to push over NFC, or null to disable
- * @param activities one or more {@link Activity} to enable for NDEF push
+ * @param activity an activity to enable for NDEF push (at least one is required)
+ * @param activities zero or more additional activities to enable for NDEF Push
*/
- public void setNdefPushMessage(NdefMessage message, Activity ... activities) {
- if (activities.length == 0) {
- throw new NullPointerException("Must specificy one or more activities");
+ public void setNdefPushMessage(NdefMessage message, Activity activity,
+ Activity ... activities) {
+ if (activity == null) {
+ throw new NullPointerException("activity cannot be null");
}
+ mNfcActivityManager.setNdefPushMessage(activity, message);
for (Activity a : activities) {
+ if (a == null) {
+ throw new NullPointerException("activities cannot contain null");
+ }
mNfcActivityManager.setNdefPushMessage(a, message);
}
}
@@ -536,17 +544,24 @@
* <p>Pass a null callback to disable the callback in the
* specified activities.
*
+ * <p>One or more activities must be specified.
+ *
* <p class="note">Requires the {@link android.Manifest.permission#NFC} permission.
*
* @param callback callback, or null to disable
- * @param activities one or more {@link Activity} to enable for NDEF push
+ * @param activity an activity to enable for NDEF push (at least one is required)
+ * @param activities zero or more additional activities to enable for NDEF Push
*/
- public void setNdefPushMessageCallback(CreateNdefMessageCallback callback,
+ public void setNdefPushMessageCallback(CreateNdefMessageCallback callback, Activity activity,
Activity ... activities) {
- if (activities.length == 0) {
- throw new NullPointerException("Must specificy one or more activities");
+ if (activity == null) {
+ throw new NullPointerException("activity cannot be null");
}
+ mNfcActivityManager.setNdefPushMessageCallback(activity, callback);
for (Activity a : activities) {
+ if (a == null) {
+ throw new NullPointerException("activities cannot contain null");
+ }
mNfcActivityManager.setNdefPushMessageCallback(a, callback);
}
}
@@ -558,17 +573,24 @@
* can only occur when one of the specified activities is in resumed
* (foreground) state.
*
+ * <p>One or more activities must be specified.
+ *
* <p class="note">Requires the {@link android.Manifest.permission#NFC} permission.
*
* @param callback callback, or null to disable
- * @param activities one or more {@link Activity} to enable the callback
+ * @param activity an activity to enable the callback (at least one is required)
+ * @param activities zero or more additional activities to enable to callback
*/
public void setOnNdefPushCompleteCallback(OnNdefPushCompleteCallback callback,
- Activity ... activities) {
- if (activities.length == 0) {
- throw new NullPointerException("Must specificy one or more activities");
+ Activity activity, Activity ... activities) {
+ if (activity == null) {
+ throw new NullPointerException("activity cannot be null");
}
+ mNfcActivityManager.setOnNdefPushCompleteCallback(activity, callback);
for (Activity a : activities) {
+ if (a == null) {
+ throw new NullPointerException("activities cannot contain null");
+ }
mNfcActivityManager.setOnNdefPushCompleteCallback(a, callback);
}
}
diff --git a/core/java/android/nfc/tech/IsoDep.java b/core/java/android/nfc/tech/IsoDep.java
index 6054fe8..1859877 100644
--- a/core/java/android/nfc/tech/IsoDep.java
+++ b/core/java/android/nfc/tech/IsoDep.java
@@ -101,14 +101,12 @@
}
/**
- * Gets the currently set timeout of {@link #transceive} in milliseconds.
+ * Get the current timeout for {@link #transceive} in milliseconds.
*
* <p class="note">Requires the {@link android.Manifest.permission#NFC} permission.
*
* @return timeout value in milliseconds
- * @hide
*/
- // TODO Unhide for ICS
public int getTimeout() {
try {
return mTag.getTagService().getTimeout(TagTechnology.ISO_DEP);
diff --git a/core/java/android/nfc/tech/MifareClassic.java b/core/java/android/nfc/tech/MifareClassic.java
index ce923ae..9d1e6a1 100644
--- a/core/java/android/nfc/tech/MifareClassic.java
+++ b/core/java/android/nfc/tech/MifareClassic.java
@@ -584,9 +584,11 @@
}
/**
- * Set the timeout of {@link #transceive} in milliseconds.
- * <p>The timeout only applies to MifareUltralight {@link #transceive},
+ * Set the {@link #transceive} timeout in milliseconds.
+ *
+ * <p>The timeout only applies to {@link #transceive} on this object,
* and is reset to a default value when {@link #close} is called.
+ *
* <p>Setting a longer timeout may be useful when performing
* transactions that require a long processing time on the tag
* such as key generation.
@@ -594,9 +596,7 @@
* <p class="note">Requires the {@link android.Manifest.permission#NFC} permission.
*
* @param timeout timeout value in milliseconds
- * @hide
*/
- // TODO Unhide for ICS
public void setTimeout(int timeout) {
try {
int err = mTag.getTagService().setTimeout(TagTechnology.MIFARE_CLASSIC, timeout);
@@ -609,14 +609,12 @@
}
/**
- * Gets the currently set timeout of {@link #transceive} in milliseconds.
+ * Get the current {@link #transceive} timeout in milliseconds.
*
* <p class="note">Requires the {@link android.Manifest.permission#NFC} permission.
*
* @return timeout value in milliseconds
- * @hide
*/
- // TODO Unhide for ICS
public int getTimeout() {
try {
return mTag.getTagService().getTimeout(TagTechnology.MIFARE_CLASSIC);
diff --git a/core/java/android/nfc/tech/MifareUltralight.java b/core/java/android/nfc/tech/MifareUltralight.java
index 890b735..dec2c65 100644
--- a/core/java/android/nfc/tech/MifareUltralight.java
+++ b/core/java/android/nfc/tech/MifareUltralight.java
@@ -224,9 +224,11 @@
}
/**
- * Set the timeout of {@link #transceive} in milliseconds.
- * <p>The timeout only applies to MifareUltralight {@link #transceive},
+ * Set the {@link #transceive} timeout in milliseconds.
+ *
+ * <p>The timeout only applies to {@link #transceive} on this object,
* and is reset to a default value when {@link #close} is called.
+ *
* <p>Setting a longer timeout may be useful when performing
* transactions that require a long processing time on the tag
* such as key generation.
@@ -234,9 +236,7 @@
* <p class="note">Requires the {@link android.Manifest.permission#NFC} permission.
*
* @param timeout timeout value in milliseconds
- * @hide
*/
- // TODO Unhide for ICS
public void setTimeout(int timeout) {
try {
int err = mTag.getTagService().setTimeout(
@@ -250,14 +250,12 @@
}
/**
- * Gets the currently set timeout of {@link #transceive} in milliseconds.
+ * Get the current {@link #transceive} timeout in milliseconds.
*
* <p class="note">Requires the {@link android.Manifest.permission#NFC} permission.
*
* @return timeout value in milliseconds
- * @hide
*/
- // TODO Unhide for ICS
public int getTimeout() {
try {
return mTag.getTagService().getTimeout(TagTechnology.MIFARE_ULTRALIGHT);
diff --git a/core/java/android/nfc/tech/NfcA.java b/core/java/android/nfc/tech/NfcA.java
index bb8aec9..88730f9 100644
--- a/core/java/android/nfc/tech/NfcA.java
+++ b/core/java/android/nfc/tech/NfcA.java
@@ -129,9 +129,11 @@
}
/**
- * Set the timeout of {@link #transceive} in milliseconds.
- * <p>The timeout only applies to NfcA {@link #transceive}, and is
- * reset to a default value when {@link #close} is called.
+ * Set the {@link #transceive} timeout in milliseconds.
+ *
+ * <p>The timeout only applies to {@link #transceive} on this object,
+ * and is reset to a default value when {@link #close} is called.
+ *
* <p>Setting a longer timeout may be useful when performing
* transactions that require a long processing time on the tag
* such as key generation.
@@ -139,9 +141,7 @@
* <p class="note">Requires the {@link android.Manifest.permission#NFC} permission.
*
* @param timeout timeout value in milliseconds
- * @hide
*/
- // TODO Unhide for ICS
public void setTimeout(int timeout) {
try {
int err = mTag.getTagService().setTimeout(TagTechnology.NFC_A, timeout);
@@ -154,14 +154,12 @@
}
/**
- * Gets the currently set timeout of {@link #transceive} in milliseconds.
+ * Get the current {@link #transceive} timeout in milliseconds.
*
* <p class="note">Requires the {@link android.Manifest.permission#NFC} permission.
*
* @return timeout value in milliseconds
- * @hide
*/
- // TODO Unhide for ICS
public int getTimeout() {
try {
return mTag.getTagService().getTimeout(TagTechnology.NFC_A);
diff --git a/core/java/android/nfc/tech/NfcF.java b/core/java/android/nfc/tech/NfcF.java
index 0938fb4..b3e3ab6 100644
--- a/core/java/android/nfc/tech/NfcF.java
+++ b/core/java/android/nfc/tech/NfcF.java
@@ -128,9 +128,11 @@
}
/**
- * Set the timeout of {@link #transceive} in milliseconds.
- * <p>The timeout only applies to NfcF {@link #transceive}, and is
- * reset to a default value when {@link #close} is called.
+ * Set the {@link #transceive} timeout in milliseconds.
+ *
+ * <p>The timeout only applies to {@link #transceive} on this object,
+ * and is reset to a default value when {@link #close} is called.
+ *
* <p>Setting a longer timeout may be useful when performing
* transactions that require a long processing time on the tag
* such as key generation.
@@ -138,9 +140,7 @@
* <p class="note">Requires the {@link android.Manifest.permission#NFC} permission.
*
* @param timeout timeout value in milliseconds
- * @hide
*/
- // TODO Unhide for ICS
public void setTimeout(int timeout) {
try {
int err = mTag.getTagService().setTimeout(TagTechnology.NFC_F, timeout);
@@ -153,14 +153,12 @@
}
/**
- * Gets the currently set timeout of {@link #transceive} in milliseconds.
+ * Get the current {@link #transceive} timeout in milliseconds.
*
* <p class="note">Requires the {@link android.Manifest.permission#NFC} permission.
*
* @return timeout value in milliseconds
- * @hide
*/
- // TODO Unhide for ICS
public int getTimeout() {
try {
return mTag.getTagService().getTimeout(TagTechnology.NFC_F);
diff --git a/core/java/android/provider/CalendarContract.java b/core/java/android/provider/CalendarContract.java
index 6fe5124..9ba1fdb 100644
--- a/core/java/android/provider/CalendarContract.java
+++ b/core/java/android/provider/CalendarContract.java
@@ -599,7 +599,7 @@
/**
* The default sort order for this table
*/
- public static final String DEFAULT_SORT_ORDER = "displayName";
+ public static final String DEFAULT_SORT_ORDER = CALENDAR_DISPLAY_NAME;
/**
* The name of the calendar. Column name.
diff --git a/core/java/android/provider/ContactsContract.java b/core/java/android/provider/ContactsContract.java
index e9221fe..1f2b342 100644
--- a/core/java/android/provider/ContactsContract.java
+++ b/core/java/android/provider/ContactsContract.java
@@ -125,19 +125,6 @@
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 @@
}
/**
- * 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 @@
}
}
+
+ /**
+ * 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 @@
* 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 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 @@
/**
* 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 @@
* 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 @@
* 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 @@
* 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 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/provider/Settings.java b/core/java/android/provider/Settings.java
index 0c791e1..efdb79e 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -1738,6 +1738,14 @@
public static final String POINTER_LOCATION = "pointer_location";
/**
+ * Show touch positions on screen?
+ * 0 = no
+ * 1 = yes
+ * @hide
+ */
+ public static final String SHOW_TOUCHES = "show_touches";
+
+ /**
* Log raw orientation data from {@link WindowOrientationListener} for use with the
* orientationplot.py tool.
* 0 = no
diff --git a/core/java/android/server/BluetoothService.java b/core/java/android/server/BluetoothService.java
index e942969..55a0624 100755
--- a/core/java/android/server/BluetoothService.java
+++ b/core/java/android/server/BluetoothService.java
@@ -117,6 +117,7 @@
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 @@
}
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 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 4c563ce..39f9367 100644
--- a/core/java/android/service/wallpaper/WallpaperService.java
+++ b/core/java/android/service/wallpaper/WallpaperService.java
@@ -139,6 +139,7 @@
boolean mSurfaceCreated;
boolean mIsCreating;
boolean mDrawingAllowed;
+ boolean mOffsetsChanged;
int mWidth;
int mHeight;
int mFormat;
@@ -604,12 +605,15 @@
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 @@
+ mSurfaceHolder + ", " + mFormat
+ ", " + mCurWidth + ", " + mCurHeight
+ "): " + this);
+ didSurface = true;
onSurfaceChanged(mSurfaceHolder, mFormat,
mCurWidth, mCurHeight);
SurfaceHolder.Callback callbacks[] = mSurfaceHolder.getCallbacks();
@@ -661,6 +666,26 @@
}
}
+ 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 @@
onCreate(mSurfaceHolder);
mInitializing = false;
+ mReportedVisible = false;
updateSurface(false, false, false);
}
@@ -711,7 +737,7 @@
mIWallpaperEngine.mReqWidth = desiredWidth;
mIWallpaperEngine.mReqHeight = desiredHeight;
onDesiredSizeChanged(desiredWidth, desiredHeight);
- doOffsetsChanged();
+ doOffsetsChanged(true);
}
}
@@ -733,6 +759,7 @@
// 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 @@
}
}
- void doOffsetsChanged() {
+ void doOffsetsChanged(boolean always) {
if (mDestroyed) {
return;
}
-
+
+ if (!always && !mOffsetsChanged) {
+ return;
+ }
+
float xOffset;
float yOffset;
float xOffsetStep;
@@ -759,15 +790,19 @@
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 @@
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 @@
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 89b6f32..75dcd6e 100644
--- a/core/java/android/speech/tts/AudioPlaybackHandler.java
+++ b/core/java/android/speech/tts/AudioPlaybackHandler.java
@@ -390,10 +390,10 @@
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;
}
@@ -415,6 +415,9 @@
}
if (params.mBytesWritten < params.mAudioBufferSize) {
+ if (DBG) Log.d(TAG, "Stopping audio track to flush audio, state was : " +
+ audioTrack.getPlayState());
+ params.mIsShortUtterance = true;
audioTrack.stop();
}
@@ -452,10 +455,40 @@
return;
}
+ if (params.mIsShortUtterance) {
+ // In this case we would have called AudioTrack#stop() to flush
+ // buffers to the mixer. This makes the playback head position
+ // unobservable and notification markers do not work reliably. We
+ // have no option but to wait until we think the track would finish
+ // playing and release it after.
+ //
+ // This isn't as bad as it looks because (a) We won't end up waiting
+ // for much longer than we should because even at 4khz mono, a short
+ // utterance weighs in at about 2 seconds, and (b) such short utterances
+ // are expected to be relatively infrequent and in a stream of utterances
+ // this shows up as a slightly longer pause.
+ blockUntilEstimatedCompletion(params);
+ } else {
+ blockUntilCompletion(params);
+ }
+ }
+
+ private static void blockUntilEstimatedCompletion(SynthesisMessageParams params) {
+ final int lengthInFrames = params.mBytesWritten / params.mBytesPerFrame;
+ final long estimatedTimeMs = (lengthInFrames * 1000 / params.mSampleRateInHz);
+
+ if (DBG) Log.d(TAG, "About to sleep for: " + estimatedTimeMs + "ms for a short utterance");
+
+ try {
+ Thread.sleep(estimatedTimeMs);
+ } catch (InterruptedException ie) {
+ // Do nothing.
+ }
+ }
+
+ private static void blockUntilCompletion(SynthesisMessageParams params) {
final AudioTrack audioTrack = params.mAudioTrack;
- final int bytesPerFrame = getBytesPerFrame(params.mAudioFormat);
- final int lengthInBytes = params.mBytesWritten;
- final int lengthInFrames = lengthInBytes / bytesPerFrame;
+ final int lengthInFrames = params.mBytesWritten / params.mBytesPerFrame;
int currentPosition = 0;
while ((currentPosition = audioTrack.getPlaybackHeadPosition()) < lengthInFrames) {
@@ -511,16 +544,6 @@
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 7dbf1ac..0cca06a 100644
--- a/core/java/android/speech/tts/PlaybackSynthesisCallback.java
+++ b/core/java/android/speech/tts/PlaybackSynthesisCallback.java
@@ -85,6 +85,7 @@
// 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 @@
// 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 @@
+ 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 @@
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 @@
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 7da5daa..779721e 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 @@
* 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,22 @@
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;
+ // A "short utterance" is one that uses less bytes than the audio
+ // track buffer size (mAudioBufferSize). In this case, we need to call
+ // AudioTrack#stop() to send pending buffers to the mixer, and slightly
+ // different logic is required to wait for the track to finish.
+ //
+ // Not volatile, accessed only from the audio playback thread.
+ boolean mIsShortUtterance;
int mAudioBufferSize;
+ // Always synchronized on "this".
+ int mUnconsumedBytes;
private final LinkedList<ListEntry> mDataBufferList = new LinkedList<ListEntry>();
@@ -53,6 +68,8 @@
mPan = pan;
mLogger = logger;
+ mBytesPerFrame = getBytesPerFrame(mAudioFormat) * mChannelCount;
+
// initially null.
mAudioTrack = null;
mBytesWritten = 0;
@@ -64,18 +81,36 @@
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 +120,29 @@
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/Layout.java b/core/java/android/text/Layout.java
index 421e995..768071f 100644
--- a/core/java/android/text/Layout.java
+++ b/core/java/android/text/Layout.java
@@ -1296,7 +1296,10 @@
float h1 = getHorizontal(st, false, line);
float h2 = getHorizontal(en, true, line);
- dest.addRect(h1, top, h2, bottom, Path.Direction.CW);
+ float left = Math.min(h1, h2);
+ float right = Math.max(h1, h2);
+
+ dest.addRect(left, top, right, bottom, Path.Direction.CW);
}
}
}
diff --git a/core/java/android/text/StaticLayout.java b/core/java/android/text/StaticLayout.java
index 788711d..e8b2045 100644
--- a/core/java/android/text/StaticLayout.java
+++ b/core/java/android/text/StaticLayout.java
@@ -729,12 +729,22 @@
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 @@
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 fcc372e..68a6b3e 100644
--- a/core/java/android/text/TextLine.java
+++ b/core/java/android/text/TextLine.java
@@ -723,7 +723,7 @@
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 @@
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 de57dfa..625d869 100644
--- a/core/java/android/text/TextPaint.java
+++ b/core/java/android/text/TextPaint.java
@@ -23,6 +23,9 @@
* 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 @@
* 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 @@
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 b8b54f4..355d467 100644
--- a/core/java/android/text/TextUtils.java
+++ b/core/java/android/text/TextUtils.java
@@ -24,6 +24,7 @@
import android.text.style.BackgroundColorSpan;
import android.text.style.BulletSpan;
import android.text.style.CharacterStyle;
+import android.text.style.EasyEditSpan;
import android.text.style.ForegroundColorSpan;
import android.text.style.LeadingMarginSpan;
import android.text.style.MetricAffectingSpan;
@@ -585,6 +586,8 @@
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
@@ -745,9 +748,13 @@
break;
case SUGGESTION_RANGE_SPAN:
- readSpan(p, sp, new SuggestionRangeSpan());
+ readSpan(p, sp, new SuggestionRangeSpan(p));
break;
+ case EASY_EDIT_SPAN:
+ readSpan(p, sp, new EasyEditSpan());
+ 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 0000000..2feb719
--- /dev/null
+++ b/core/java/android/text/style/EasyEditSpan.java
@@ -0,0 +1,50 @@
+/*
+ * 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
+ }
+
+ @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/SuggestionRangeSpan.java b/core/java/android/text/style/SuggestionRangeSpan.java
index fc91697..a637b1c 100644
--- a/core/java/android/text/style/SuggestionRangeSpan.java
+++ b/core/java/android/text/style/SuggestionRangeSpan.java
@@ -16,7 +16,6 @@
package android.text.style;
-import android.graphics.Color;
import android.os.Parcel;
import android.text.ParcelableSpan;
import android.text.TextPaint;
@@ -29,12 +28,20 @@
* @hide
*/
public class SuggestionRangeSpan extends CharacterStyle implements ParcelableSpan {
+ private final int mBackgroundColor;
+
@Override
public void updateDrawState(TextPaint tp) {
- tp.setColor(Color.GREEN);
+ tp.bgColor = mBackgroundColor;
}
- public SuggestionRangeSpan() { /* Nothing to do*/ }
+ public SuggestionRangeSpan(int color) {
+ mBackgroundColor = color;
+ }
+
+ public SuggestionRangeSpan(Parcel src) {
+ mBackgroundColor = src.readInt();
+ }
@Override
public int describeContents() {
@@ -42,7 +49,9 @@
}
@Override
- public void writeToParcel(Parcel dest, int flags) { /* Nothing to do*/ }
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeInt(mBackgroundColor);
+ }
@Override
public int getSpanTypeId() {
diff --git a/core/java/android/text/style/SuggestionSpan.java b/core/java/android/text/style/SuggestionSpan.java
index ea57f91..8625257 100644
--- a/core/java/android/text/style/SuggestionSpan.java
+++ b/core/java/android/text/style/SuggestionSpan.java
@@ -61,12 +61,6 @@
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 @@
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 @@
}
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 @@
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 @@
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 @@
@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/HardwareRenderer.java b/core/java/android/view/HardwareRenderer.java
index 2bf16d8..1fcde3d 100644
--- a/core/java/android/view/HardwareRenderer.java
+++ b/core/java/android/view/HardwareRenderer.java
@@ -344,9 +344,9 @@
static final int EGL_SURFACE_TYPE = 0x3033;
static final int EGL_SWAP_BEHAVIOR_PRESERVED_BIT = 0x0400;
- private static final int SURFACE_STATE_ERROR = 0;
- private static final int SURFACE_STATE_SUCCESS = 1;
- private static final int SURFACE_STATE_UPDATED = 2;
+ static final int SURFACE_STATE_ERROR = 0;
+ static final int SURFACE_STATE_SUCCESS = 1;
+ static final int SURFACE_STATE_UPDATED = 2;
static EGL10 sEgl;
static EGLDisplay sEglDisplay;
@@ -913,8 +913,7 @@
@Override
void destroyLayers(View view) {
- if (view != null && isEnabled()) {
- checkCurrent();
+ if (view != null && isEnabled() && checkCurrent() != SURFACE_STATE_ERROR) {
destroyHardwareLayer(view);
GLES20Canvas.flushCaches(GLES20Canvas.FLUSH_CACHES_LAYERS);
}
diff --git a/core/java/android/view/Surface.java b/core/java/android/view/Surface.java
index ef3d3fa5..3880bc45 100644
--- a/core/java/android/view/Surface.java
+++ b/core/java/android/view/Surface.java
@@ -36,10 +36,14 @@
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) {
@@ -442,7 +446,9 @@
/** @hide */
public native void setLayer(int zorder);
/** @hide */
- public native void setPosition(int x, int y);
+ public void setPosition(int x, int y) { setPosition((float)x, (float)y); }
+ /** @hide */
+ public native void setPosition(float x, float y);
/** @hide */
public native void setSize(int w, int h);
/** @hide */
diff --git a/core/java/android/view/TextureView.java b/core/java/android/view/TextureView.java
index 9d959fb..c735d6b 100644
--- a/core/java/android/view/TextureView.java
+++ b/core/java/android/view/TextureView.java
@@ -286,6 +286,11 @@
}
@Override
+ boolean destroyLayer() {
+ return false;
+ }
+
+ @Override
HardwareLayer getHardwareLayer() {
if (mLayer == null) {
if (mAttachInfo == null || mAttachInfo.mHardwareRenderer == null) {
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 7713bd8..fa1d249 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -2595,11 +2595,6 @@
protected static int DEFAULT_TEXT_DIRECTION = TEXT_DIRECTION_INHERIT;
/**
- * Default threshold for "char count" heuristic.
- */
- protected static float DEFAULT_TEXT_DIRECTION_CHAR_COUNT_THRESHOLD = 0.6f;
-
- /**
* The text direction that has been defined by {@link #setTextDirection(int)}.
*
* {@hide}
@@ -6052,23 +6047,29 @@
* @see #onHoverChanged
*/
public boolean onHoverEvent(MotionEvent event) {
- switch (event.getAction()) {
- case MotionEvent.ACTION_HOVER_ENTER:
- if (!hasHoveredChild() && !mSendingHoverAccessibilityEvents) {
- mSendingHoverAccessibilityEvents = true;
- sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_HOVER_ENTER);
- }
- break;
- case MotionEvent.ACTION_HOVER_EXIT:
- if (mSendingHoverAccessibilityEvents) {
- mSendingHoverAccessibilityEvents = false;
- sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_HOVER_EXIT);
- }
- break;
+ // The root view may receive hover (or touch) events that are outside the bounds of
+ // the window. This code ensures that we only send accessibility events for
+ // hovers that are actually within the bounds of the root view.
+ final int action = event.getAction();
+ if (!mSendingHoverAccessibilityEvents) {
+ if ((action == MotionEvent.ACTION_HOVER_ENTER
+ || action == MotionEvent.ACTION_HOVER_MOVE)
+ && !hasHoveredChild()
+ && pointInView(event.getX(), event.getY())) {
+ mSendingHoverAccessibilityEvents = true;
+ sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_HOVER_ENTER);
+ }
+ } else {
+ if (action == MotionEvent.ACTION_HOVER_EXIT
+ || (action == MotionEvent.ACTION_HOVER_MOVE
+ && !pointInView(event.getX(), event.getY()))) {
+ mSendingHoverAccessibilityEvents = false;
+ sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_HOVER_EXIT);
+ }
}
if (isHoverable()) {
- switch (event.getAction()) {
+ switch (action) {
case MotionEvent.ACTION_HOVER_ENTER:
setHovered(true);
break;
@@ -6497,6 +6498,8 @@
if (mParent instanceof ViewGroup) {
((ViewGroup) mParent).onChildVisibilityChanged(this, (flags & VISIBILITY_MASK));
((View) mParent).invalidate(true);
+ } else if (mParent != null) {
+ mParent.invalidateChild(this, null);
}
dispatchVisibilityChanged(this, (flags & VISIBILITY_MASK));
}
@@ -9359,7 +9362,6 @@
if (mAttachInfo != null) {
mAttachInfo.mHandler.removeMessages(AttachInfo.INVALIDATE_MSG, this);
- mAttachInfo.mHandler.removeMessages(AttachInfo.INVALIDATE_RECT_MSG, this);
}
mCurrentAnimation = null;
@@ -13907,6 +13909,7 @@
}
public void onReleased(InvalidateInfo element) {
+ element.target = null;
}
}, POOL_LIMIT)
);
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index a0cc287..7db1b32 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -454,7 +454,10 @@
// manager, to make sure we do the relayout before receiving
// any other events from the system.
requestLayout();
- mInputChannel = new InputChannel();
+ if ((mWindowAttributes.inputFeatures
+ & WindowManager.LayoutParams.INPUT_FEATURE_NO_INPUT_CHANNEL) == 0) {
+ mInputChannel = new InputChannel();
+ }
try {
res = sWindowSession.add(mWindow, mWindowAttributes,
getHostVisibility(), mAttachInfo.mContentInsets,
@@ -524,12 +527,14 @@
mInputQueueCallback =
((RootViewSurfaceTaker)view).willYouTakeTheInputQueue();
}
- if (mInputQueueCallback != null) {
- mInputQueue = new InputQueue(mInputChannel);
- mInputQueueCallback.onInputQueueCreated(mInputQueue);
- } else {
- InputQueue.registerInputChannel(mInputChannel, mInputHandler,
- Looper.myQueue());
+ if (mInputChannel != null) {
+ if (mInputQueueCallback != null) {
+ mInputQueue = new InputQueue(mInputChannel);
+ mInputQueueCallback.onInputQueueCreated(mInputQueue);
+ } else {
+ InputQueue.registerInputChannel(mInputChannel, mInputHandler,
+ Looper.myQueue());
+ }
}
view.assignParent(this);
@@ -2136,6 +2141,10 @@
void dispatchDetachedFromWindow() {
if (mView != null && mView.mAttachInfo != null) {
+ if (mAttachInfo.mHardwareRenderer != null &&
+ mAttachInfo.mHardwareRenderer.isEnabled()) {
+ mAttachInfo.mHardwareRenderer.validate();
+ }
mView.dispatchDetachedFromWindow();
}
@@ -2152,13 +2161,12 @@
mSurface.release();
- if (mInputChannel != null) {
- if (mInputQueueCallback != null) {
- mInputQueueCallback.onInputQueueDestroyed(mInputQueue);
- mInputQueueCallback = null;
- } else {
- InputQueue.unregisterInputChannel(mInputChannel);
- }
+ if (mInputQueueCallback != null && mInputQueue != null) {
+ mInputQueueCallback.onInputQueueDestroyed(mInputQueue);
+ mInputQueueCallback = null;
+ mInputQueue = null;
+ } else if (mInputChannel != null) {
+ InputQueue.unregisterInputChannel(mInputChannel);
}
try {
sWindowSession.remove(mWindow);
@@ -3564,6 +3572,11 @@
checkThread();
if (LOCAL_LOGV) Log.v(TAG, "DIE in " + this + " of " + mSurface);
synchronized (this) {
+ if (mAdded) {
+ mAdded = false;
+ dispatchDetachedFromWindow();
+ }
+
if (mAdded && !mFirst) {
destroyHardwareRenderer();
@@ -3584,10 +3597,6 @@
mSurface.release();
}
- if (mAdded) {
- mAdded = false;
- dispatchDetachedFromWindow();
- }
}
}
diff --git a/core/java/android/view/WindowManager.java b/core/java/android/view/WindowManager.java
index fdd9b2c..52d25d9 100644
--- a/core/java/android/view/WindowManager.java
+++ b/core/java/android/view/WindowManager.java
@@ -1029,9 +1029,18 @@
public static final int INPUT_FEATURE_DISABLE_POINTER_GESTURES = 0x00000001;
/**
+ * Does not construct an input channel for this window. The channel will therefore
+ * be incapable of receiving input.
+ *
+ * @hide
+ */
+ public static final int INPUT_FEATURE_NO_INPUT_CHANNEL = 0x00000002;
+
+ /**
* Control special features of the input subsystem.
*
* @see #INPUT_FEATURE_DISABLE_TOUCH_PAD_GESTURES
+ * @see #INPUT_FEATURE_NO_INPUT_CHANNEL
* @hide
*/
public int inputFeatures;
diff --git a/core/java/android/view/WindowManagerPolicy.java b/core/java/android/view/WindowManagerPolicy.java
index 1b4edf1..dc1bbd7 100644
--- a/core/java/android/view/WindowManagerPolicy.java
+++ b/core/java/android/view/WindowManagerPolicy.java
@@ -20,6 +20,7 @@
import android.content.res.CompatibilityInfo;
import android.content.res.Configuration;
import android.graphics.Rect;
+import android.graphics.RectF;
import android.os.IBinder;
import android.os.LocalPowerManager;
import android.view.animation.Animation;
@@ -165,7 +166,7 @@
*
* @return Rect The rectangle holding the shown window frame.
*/
- public Rect getShownFrameLw();
+ public RectF getShownFrameLw();
/**
* Retrieve the frame of the display that this window was last
@@ -871,6 +872,12 @@
public void systemReady();
/**
+ * Called when the system is done booting to the point where the
+ * user can start interacting with it.
+ */
+ public void systemBooted();
+
+ /**
* Show boot time message to the user.
*/
public void showBootMessage(final CharSequence msg, final boolean always);
diff --git a/core/java/android/view/WindowOrientationListener.java b/core/java/android/view/WindowOrientationListener.java
index 5d4fbbe..76b47ca 100755
--- a/core/java/android/view/WindowOrientationListener.java
+++ b/core/java/android/view/WindowOrientationListener.java
@@ -332,7 +332,7 @@
// we perform an orientation change under ideal conditions. It will take
// proportionally longer than this to effect an orientation change when
// the proposed orientation confidence is low.
- private static final float ORIENTATION_SETTLE_TIME_MS = 100;
+ private static final float ORIENTATION_SETTLE_TIME_MS = 250;
// The confidence that we have abount effecting each orientation change.
// When one of these values exceeds 1.0, we have determined our new orientation!
diff --git a/core/java/android/view/inputmethod/InputMethodManager.java b/core/java/android/view/inputmethod/InputMethodManager.java
index da5baf8..302be57 100644
--- a/core/java/android/view/inputmethod/InputMethodManager.java
+++ b/core/java/android/view/inputmethod/InputMethodManager.java
@@ -1583,6 +1583,14 @@
/**
* Set additional input method subtypes. Only a process which shares the same uid with the IME
* can add additional input method subtypes to the IME.
+ * Please note that a subtype's status is stored in the system.
+ * For example, enabled subtypes are remembered by the framework even after they are removed
+ * by using this method. If you re-add the same subtypes again,
+ * they will just get enabled. If you want to avoid such conflicts, for instance, you may
+ * want to create a "different" new subtype even with the same locale and mode,
+ * by changing its extra value. The different subtype won't get affected by the stored past
+ * status. (You may want to take a look at {@link InputMethodSubtype#hashCode()} to refer
+ * to the current implementation.)
* @param imiId Id of InputMethodInfo which additional input method subtypes will be added to.
* @param subtypes subtypes will be added as additional subtypes of the current input method.
* @return true if the additional input method subtypes are successfully added.
diff --git a/core/java/android/view/textservice/TextServicesManager.java b/core/java/android/view/textservice/TextServicesManager.java
index c85b2d9..01587aa 100644
--- a/core/java/android/view/textservice/TextServicesManager.java
+++ b/core/java/android/view/textservice/TextServicesManager.java
@@ -66,7 +66,13 @@
/**
* Get a spell checker session for the specified spell checker
- * @param locale the locale for the spell checker
+ * @param locale the locale for the spell checker. If {@param locale} is null and
+ * referToSpellCheckerLanguageSettings is true, the locale specified in Settings will be
+ * returned. If {@param locale} is not null and referToSpellCheckerLanguageSettings is true,
+ * the locale specified in Settings will be returned only when it is same as {@param locale}.
+ * Exceptionally, when referToSpellCheckerLanguageSettings is true and {@param locale} is
+ * only language (e.g. "en"), the specified locale in Settings (e.g. "en_US") will be
+ * selected.
* @param listener a spell checker session lister for getting results from a spell checker.
* @param referToSpellCheckerLanguageSettings if true, the session for one of enabled
* languages in settings will be returned.
@@ -81,6 +87,11 @@
throw new IllegalArgumentException("Locale should not be null if you don't refer"
+ " settings.");
}
+
+ if (referToSpellCheckerLanguageSettings && !isSpellCheckerEnabled()) {
+ return null;
+ }
+
final SpellCheckerInfo sci;
try {
sci = sService.getCurrentSpellChecker(null);
@@ -108,7 +119,12 @@
final String localeStr = locale.toString();
for (int i = 0; i < sci.getSubtypeCount(); ++i) {
final SpellCheckerSubtype subtype = sci.getSubtypeAt(i);
- if (subtype.getLocale().equals(localeStr)) {
+ final String tempSubtypeLocale = subtype.getLocale();
+ if (tempSubtypeLocale.equals(localeStr)) {
+ subtypeInUse = subtype;
+ break;
+ } else if (localeStr.length() >= 2 && tempSubtypeLocale.length() >= 2
+ && localeStr.startsWith(tempSubtypeLocale)) {
subtypeInUse = subtype;
}
}
diff --git a/core/java/android/webkit/HTML5VideoInline.java b/core/java/android/webkit/HTML5VideoInline.java
index ef1906c..1b9a25e 100644
--- a/core/java/android/webkit/HTML5VideoInline.java
+++ b/core/java/android/webkit/HTML5VideoInline.java
@@ -5,6 +5,7 @@
import android.media.MediaPlayer;
import android.webkit.HTML5VideoView;
import android.webkit.HTML5VideoViewProxy;
+import android.view.Surface;
import android.opengl.GLES20;
/**
@@ -38,7 +39,10 @@
@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/JniUtil.java b/core/java/android/webkit/JniUtil.java
index 4264e9d..ef1641d 100644
--- a/core/java/android/webkit/JniUtil.java
+++ b/core/java/android/webkit/JniUtil.java
@@ -28,6 +28,7 @@
static {
System.loadLibrary("webcore");
+ System.loadLibrary("chromium_net");
}
private static final String LOGTAG = "webkit";
private JniUtil() {} // Utility class, do not instantiate.
diff --git a/core/java/android/webkit/OverScrollGlow.java b/core/java/android/webkit/OverScrollGlow.java
index ff5b30b..e906f7f 100644
--- a/core/java/android/webkit/OverScrollGlow.java
+++ b/core/java/android/webkit/OverScrollGlow.java
@@ -22,7 +22,7 @@
import android.graphics.Canvas;
import android.graphics.drawable.Drawable;
import android.view.View;
-import android.widget.EdgeGlow;
+import android.widget.EdgeEffect;
/**
* This class manages the edge glow effect when a WebView is flung or pulled beyond the edges.
@@ -31,10 +31,10 @@
public class OverScrollGlow {
private WebView mHostView;
- private EdgeGlow mEdgeGlowTop;
- private EdgeGlow mEdgeGlowBottom;
- private EdgeGlow mEdgeGlowLeft;
- private EdgeGlow mEdgeGlowRight;
+ private EdgeEffect mEdgeGlowTop;
+ private EdgeEffect mEdgeGlowBottom;
+ private EdgeEffect mEdgeGlowLeft;
+ private EdgeEffect mEdgeGlowRight;
private int mOverScrollDeltaX;
private int mOverScrollDeltaY;
@@ -42,13 +42,10 @@
public OverScrollGlow(WebView host) {
mHostView = host;
Context context = host.getContext();
- final Resources res = context.getResources();
- final Drawable edge = res.getDrawable(R.drawable.overscroll_edge);
- final Drawable glow = res.getDrawable(R.drawable.overscroll_glow);
- mEdgeGlowTop = new EdgeGlow(context, edge, glow);
- mEdgeGlowBottom = new EdgeGlow(context, edge, glow);
- mEdgeGlowLeft = new EdgeGlow(context, edge, glow);
- mEdgeGlowRight = new EdgeGlow(context, edge, glow);
+ mEdgeGlowTop = new EdgeEffect(context);
+ mEdgeGlowBottom = new EdgeEffect(context);
+ mEdgeGlowLeft = new EdgeEffect(context);
+ mEdgeGlowRight = new EdgeEffect(context);
}
/**
diff --git a/core/java/android/webkit/ViewStateSerializer.java b/core/java/android/webkit/ViewStateSerializer.java
index 0fc76fa..5f91ed3 100644
--- a/core/java/android/webkit/ViewStateSerializer.java
+++ b/core/java/android/webkit/ViewStateSerializer.java
@@ -36,11 +36,15 @@
static boolean serializeViewState(OutputStream stream, WebView web)
throws IOException {
+ int baseLayer = web.getBaseLayer();
+ if (baseLayer == 0) {
+ return false;
+ }
DataOutputStream dos = new DataOutputStream(stream);
dos.writeInt(VERSION);
dos.writeInt(web.getContentWidth());
dos.writeInt(web.getContentHeight());
- return nativeSerializeViewState(web.getBaseLayer(), dos,
+ return nativeSerializeViewState(baseLayer, dos,
new byte[WORKING_STREAM_STORAGE]);
}
diff --git a/core/java/android/webkit/WebView.java b/core/java/android/webkit/WebView.java
index 2aa481c..2e7f923 100644
--- a/core/java/android/webkit/WebView.java
+++ b/core/java/android/webkit/WebView.java
@@ -34,7 +34,6 @@
import android.graphics.BitmapShader;
import android.graphics.Canvas;
import android.graphics.Color;
-import android.graphics.CornerPathEffect;
import android.graphics.DrawFilter;
import android.graphics.Paint;
import android.graphics.PaintFlagsDrawFilter;
@@ -58,8 +57,6 @@
import android.os.StrictMode;
import android.provider.Settings;
import android.speech.tts.TextToSpeech;
-import android.text.Selection;
-import android.text.Spannable;
import android.util.AttributeSet;
import android.util.EventLog;
import android.util.Log;
@@ -606,9 +603,15 @@
// know to handle Shift and arrows natively first
private boolean mAccessibilityScriptInjected;
+ static final boolean USE_JAVA_TEXT_SELECTION = true;
+ private Region mTextSelectionRegion = new Region();
+ private Paint mTextSelectionPaint;
+ private Drawable mSelectHandleLeft;
+ private Drawable mSelectHandleRight;
+
static final boolean USE_WEBKIT_RINGS = true;
// the color used to highlight the touch rectangles
- private static final int mHightlightColor = 0x6633b5e5;
+ private static final int HIGHLIGHT_COLOR = 0x6633b5e5;
// the round corner for the highlight path
private static final float TOUCH_HIGHLIGHT_ARC = 5.0f;
// the region indicating where the user touched on the screen
@@ -4004,12 +4007,9 @@
// state.
// If mNativeClass is 0, we should not reach here, so we do not
// need to check it again.
- if (mDrawCursorRing && drawRings) {
- // Only update if we are actually going to use the result
- nativeRecordButtons(hasFocus() && hasWindowFocus(),
- mTouchMode == TOUCH_SHORTPRESS_START_MODE
- || mTrackballDown || mGotCenterDown, false);
- }
+ nativeRecordButtons(hasFocus() && hasWindowFocus(),
+ (mTouchMode == TOUCH_SHORTPRESS_START_MODE && !USE_WEBKIT_RINGS)
+ || mTrackballDown || mGotCenterDown, false);
drawCoreAndCursorRing(canvas, mBackgroundColor,
mDrawCursorRing && drawRings);
}
@@ -4050,8 +4050,10 @@
@Override
protected void onDraw(Canvas canvas) {
- // if mNativeClass is 0, the WebView has been destroyed. Do nothing.
+ // if mNativeClass is 0, the WebView is either destroyed or not
+ // initialized. In either case, just draw the background color and return
if (mNativeClass == 0) {
+ canvas.drawColor(mBackgroundColor);
return;
}
@@ -4105,7 +4107,7 @@
} else {
if (mTouchHightlightPaint == null) {
mTouchHightlightPaint = new Paint();
- mTouchHightlightPaint.setColor(mHightlightColor);
+ mTouchHightlightPaint.setColor(HIGHLIGHT_COLOR);
}
RegionIterator iter = new RegionIterator(mTouchHighlightRegion);
Rect r = new Rect();
@@ -4306,6 +4308,9 @@
}
int getBaseLayer() {
+ if (mNativeClass == 0) {
+ return 0;
+ }
return nativeGetBaseLayer();
}
@@ -4400,7 +4405,7 @@
int extras = DRAW_EXTRAS_NONE;
if (mFindIsUp) {
extras = DRAW_EXTRAS_FIND;
- } else if (mSelectingText) {
+ } else if (mSelectingText && !USE_JAVA_TEXT_SELECTION) {
extras = DRAW_EXTRAS_SELECTION;
nativeSetSelectionPointer(mDrawSelectionPointer,
mZoomManager.getInvScale(),
@@ -4427,6 +4432,10 @@
nativeUseHardwareAccelSkia(mHardwareAccelSkia);
}
+ if (mSelectingText && USE_JAVA_TEXT_SELECTION) {
+ drawTextSelectionHandles(canvas);
+ }
+
} else {
DrawFilter df = null;
if (mZoomManager.isZoomAnimating() || UIAnimationsRunning) {
@@ -4461,6 +4470,56 @@
}
}
+ private void drawTextSelectionHandles(Canvas canvas) {
+ if (mTextSelectionPaint == null) {
+ mTextSelectionPaint = new Paint();
+ mTextSelectionPaint.setColor(HIGHLIGHT_COLOR);
+ }
+ mTextSelectionRegion.setEmpty();
+ nativeGetTextSelectionRegion(mTextSelectionRegion);
+ Rect r = new Rect();
+ RegionIterator iter = new RegionIterator(mTextSelectionRegion);
+ int start_x = -1;
+ int start_y = -1;
+ int end_x = -1;
+ int end_y = -1;
+ while (iter.next(r)) {
+ r = new Rect(
+ contentToViewDimension(r.left),
+ contentToViewDimension(r.top),
+ contentToViewDimension(r.right),
+ contentToViewDimension(r.bottom));
+ // Regions are in order. First one is where selection starts,
+ // last one is where it ends
+ if (start_x < 0 || start_y < 0) {
+ start_x = r.left;
+ start_y = r.bottom;
+ }
+ end_x = r.right;
+ end_y = r.bottom;
+ canvas.drawRect(r, mTextSelectionPaint);
+ }
+ if (mSelectHandleLeft == null) {
+ mSelectHandleLeft = mContext.getResources().getDrawable(
+ com.android.internal.R.drawable.text_select_handle_left);
+ }
+ // Magic formula copied from TextView
+ start_x -= (mSelectHandleLeft.getIntrinsicWidth() * 3) / 4;
+ mSelectHandleLeft.setBounds(start_x, start_y,
+ start_x + mSelectHandleLeft.getIntrinsicWidth(),
+ start_y + mSelectHandleLeft.getIntrinsicHeight());
+ if (mSelectHandleRight == null) {
+ mSelectHandleRight = mContext.getResources().getDrawable(
+ com.android.internal.R.drawable.text_select_handle_right);
+ }
+ end_x -= mSelectHandleRight.getIntrinsicWidth() / 4;
+ mSelectHandleRight.setBounds(end_x, end_y,
+ end_x + mSelectHandleRight.getIntrinsicWidth(),
+ end_y + mSelectHandleRight.getIntrinsicHeight());
+ mSelectHandleLeft.draw(canvas);
+ mSelectHandleRight.draw(canvas);
+ }
+
// draw history
private boolean mDrawHistory = false;
private Picture mHistoryPicture = null;
@@ -9124,7 +9183,9 @@
/** @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 */
@@ -9327,4 +9388,5 @@
private native int nativeGetBackgroundColor();
native boolean nativeSetProperty(String key, String value);
native String nativeGetProperty(String key);
+ private native void nativeGetTextSelectionRegion(Region region);
}
diff --git a/core/java/android/webkit/WebViewCore.java b/core/java/android/webkit/WebViewCore.java
index 3ca3eaa..73a30c4 100644
--- a/core/java/android/webkit/WebViewCore.java
+++ b/core/java/android/webkit/WebViewCore.java
@@ -57,13 +57,14 @@
private static final String LOGTAG = "webcore";
static {
- // Load libwebcore during static initialization. This happens in the
- // zygote process so it will be shared read-only across all app
- // processes.
+ // Load libwebcore and libchromium_net during static initialization.
+ // This happens in the zygote process so they will be shared read-only
+ // across all app processes.
try {
System.loadLibrary("webcore");
+ System.loadLibrary("chromium_net");
} catch (UnsatisfiedLinkError e) {
- Log.e(LOGTAG, "Unable to load webcore library");
+ Log.e(LOGTAG, "Unable to load native support libraries.");
}
}
@@ -1040,6 +1041,7 @@
// Flag for blocking messages. This is used during DESTROY to avoid
// posting more messages to the EventHub or to WebView's event handler.
private boolean mBlockMessages;
+ private boolean mDestroying;
private int mTid;
private int mSavedPriority;
@@ -1071,12 +1073,20 @@
+ " arg1=" + msg.arg1 + " arg2=" + msg.arg2
+ " obj=" + msg.obj);
}
- if (mWebView == null
+ if (mWebView == null || mNativeClass == 0) {
+ if (DebugFlags.WEB_VIEW_CORE) {
+ Log.w(LOGTAG, "Rejecting message " + msg.what
+ + " because we are destroyed");
+ }
+ return;
+ }
+ if (mDestroying == true
&& msg.what != EventHub.RESUME_TIMERS
- && msg.what != EventHub.PAUSE_TIMERS) {
+ && msg.what != EventHub.PAUSE_TIMERS
+ && msg.what != EventHub.DESTROY) {
if (DebugFlags.WEB_VIEW_CORE) {
Log.v(LOGTAG, "Rejecting message " + msg.what
- + " because we are destroyed");
+ + " because we are being destroyed");
}
return;
}
@@ -1780,7 +1790,8 @@
// or RESUME_TIMERS messages, which we must still handle as they
// are per process. DESTROY will instead trigger a white list in
// mEventHub, skipping any remaining messages in the queue
- mEventHub.sendMessageAtFrontOfQueue(
+ mEventHub.mDestroying = true;
+ mEventHub.sendMessage(
Message.obtain(null, EventHub.DESTROY));
mEventHub.blockMessages();
}
diff --git a/core/java/android/widget/AbsListView.java b/core/java/android/widget/AbsListView.java
index 80cbbfb..05d4f05 100644
--- a/core/java/android/widget/AbsListView.java
+++ b/core/java/android/widget/AbsListView.java
@@ -594,12 +594,12 @@
/**
* Tracks the state of the top edge glow.
*/
- private EdgeGlow mEdgeGlowTop;
+ private EdgeEffect mEdgeGlowTop;
/**
* Tracks the state of the bottom edge glow.
*/
- private EdgeGlow mEdgeGlowBottom;
+ private EdgeEffect mEdgeGlowBottom;
/**
* An estimate of how many pixels are between the top of the list and
@@ -788,11 +788,8 @@
if (mode != OVER_SCROLL_NEVER) {
if (mEdgeGlowTop == null) {
Context context = getContext();
- final Resources res = context.getResources();
- final Drawable edge = res.getDrawable(R.drawable.overscroll_edge);
- final Drawable glow = res.getDrawable(R.drawable.overscroll_glow);
- mEdgeGlowTop = new EdgeGlow(context, edge, glow);
- mEdgeGlowBottom = new EdgeGlow(context, edge, glow);
+ mEdgeGlowTop = new EdgeEffect(context);
+ mEdgeGlowBottom = new EdgeEffect(context);
}
} else {
mEdgeGlowTop = null;
diff --git a/core/java/android/widget/EdgeGlow.java b/core/java/android/widget/EdgeEffect.java
similarity index 77%
rename from core/java/android/widget/EdgeGlow.java
rename to core/java/android/widget/EdgeEffect.java
index 75cef38..fd2abc2 100644
--- a/core/java/android/widget/EdgeGlow.java
+++ b/core/java/android/widget/EdgeEffect.java
@@ -16,7 +16,10 @@
package android.widget;
+import com.android.internal.R;
+
import android.content.Context;
+import android.content.res.Resources;
import android.graphics.Canvas;
import android.graphics.drawable.Drawable;
import android.view.animation.AnimationUtils;
@@ -24,19 +27,33 @@
import android.view.animation.Interpolator;
/**
- * This class performs the glow effect used at the edges of scrollable widgets.
- * @hide
+ * This class performs the graphical effect used at the edges of scrollable widgets
+ * when the user scrolls beyond the content bounds in 2D space.
+ *
+ * <p>EdgeEffect is stateful. Custom widgets using EdgeEffect should create an
+ * instance for each edge that should show the effect, feed it input data using
+ * the methods {@link #onAbsorb(int)}, {@link #onPull(float)}, and {@link #onRelease()},
+ * and draw the effect using {@link #draw(Canvas)} in the widget's overridden
+ * {@link android.view.View#draw(Canvas)} method. If {@link #isFinished()} returns
+ * false after drawing, the edge effect's animation is not yet complete and the widget
+ * should schedule another drawing pass to continue the animation.</p>
+ *
+ * <p>When drawing, widgets should draw their main content and child views first,
+ * usually by invoking <code>super.draw(canvas)</code> from an overridden <code>draw</code>
+ * method. (This will invoke onDraw and dispatch drawing to child views as needed.)
+ * The edge effect may then be drawn on top of the view's content using the
+ * {@link #draw(Canvas)} method.</p>
*/
-public class EdgeGlow {
- private static final String TAG = "EdgeGlow";
+public class EdgeEffect {
+ private static final String TAG = "EdgeEffect";
// Time it will take the effect to fully recede in ms
private static final int RECEDE_TIME = 1000;
- // Time it will take before a pulled glow begins receding
+ // Time it will take before a pulled glow begins receding in ms
private static final int PULL_TIME = 167;
- // Time it will take for a pulled glow to decay to partial strength before release
+ // Time it will take in ms for a pulled glow to decay to partial strength before release
private static final int PULL_DECAY_TIME = 1000;
private static final float MAX_ALPHA = 0.8f;
@@ -103,31 +120,58 @@
private float mPullDistance;
- public EdgeGlow(Context context, Drawable edge, Drawable glow) {
- mEdge = edge;
- mGlow = glow;
+ /**
+ * Construct a new EdgeEffect with a theme appropriate for the provided context.
+ * @param context Context used to provide theming and resource information for the EdgeEffect
+ */
+ public EdgeEffect(Context context) {
+ final Resources res = context.getResources();
+ mEdge = res.getDrawable(R.drawable.overscroll_edge);
+ mGlow = res.getDrawable(R.drawable.overscroll_glow);
mMinWidth = (int) (context.getResources().getDisplayMetrics().density * MIN_WIDTH + 0.5f);
mInterpolator = new DecelerateInterpolator();
}
+ /**
+ * Set the size of this edge effect in pixels.
+ *
+ * @param width Effect width in pixels
+ * @param height Effect height in pixels
+ */
public void setSize(int width, int height) {
mWidth = width;
mHeight = height;
}
+ /**
+ * Reports if this EdgeEffect's animation is finished. If this method returns false
+ * after a call to {@link #draw(Canvas)} the host widget should schedule another
+ * drawing pass to continue the animation.
+ *
+ * @return true if animation is finished, false if drawing should continue on the next frame.
+ */
public boolean isFinished() {
return mState == STATE_IDLE;
}
+ /**
+ * Immediately finish the current animation.
+ * After this call {@link #isFinished()} will return true.
+ */
public void finish() {
mState = STATE_IDLE;
}
/**
- * Call when the object is pulled by the user.
+ * A view should call this when content is pulled away from an edge by the user.
+ * This will update the state of the current visual effect and its associated animation.
+ * The host view should always {@link android.view.View#invalidate()} after this
+ * and draw the results accordingly.
*
- * @param deltaDistance Change in distance since the last call
+ * @param deltaDistance Change in distance since the last call. Values may be 0 (no change) to
+ * 1.f (full length of the view) or negative values to express change
+ * back toward the edge reached to initiate the effect.
*/
public void onPull(float deltaDistance) {
final long now = AnimationUtils.currentAnimationTimeMillis();
@@ -173,6 +217,9 @@
/**
* Call when the object is released after being pulled.
+ * This will begin the "decay" phase of the effect. After calling this method
+ * the host view should {@link android.view.View#invalidate()} and thereby
+ * draw the results accordingly.
*/
public void onRelease() {
mPullDistance = 0;
@@ -198,6 +245,11 @@
/**
* Call when the effect absorbs an impact at the given velocity.
+ * Used when a fling reaches the scroll boundary.
+ *
+ * <p>When using a {@link android.widget.Scroller} or {@link android.widget.OverScroller},
+ * the method <code>getCurrVelocity</code> will provide a reasonable approximation
+ * to use here.</p>
*
* @param velocity Velocity at impact in pixels per second.
*/
@@ -238,7 +290,7 @@
/**
* Draw into the provided canvas. Assumes that the canvas has been rotated
* accordingly and the size has been set. The effect will be drawn the full
- * width of X=0 to X=width, emitting from Y=0 and extending to some factor <
+ * width of X=0 to X=width, beginning from Y=0 and extending to some factor <
* 1.f of height.
*
* @param canvas Canvas to draw into
diff --git a/core/java/android/widget/HorizontalScrollView.java b/core/java/android/widget/HorizontalScrollView.java
index d638732..a7a05be 100644
--- a/core/java/android/widget/HorizontalScrollView.java
+++ b/core/java/android/widget/HorizontalScrollView.java
@@ -75,8 +75,8 @@
private final Rect mTempRect = new Rect();
private OverScroller mScroller;
- private EdgeGlow mEdgeGlowLeft;
- private EdgeGlow mEdgeGlowRight;
+ private EdgeEffect mEdgeGlowLeft;
+ private EdgeEffect mEdgeGlowRight;
/**
* Position of the last motion event.
@@ -1477,11 +1477,8 @@
if (mode != OVER_SCROLL_NEVER) {
if (mEdgeGlowLeft == null) {
Context context = getContext();
- final Resources res = context.getResources();
- final Drawable edge = res.getDrawable(R.drawable.overscroll_edge);
- final Drawable glow = res.getDrawable(R.drawable.overscroll_glow);
- mEdgeGlowLeft = new EdgeGlow(context, edge, glow);
- mEdgeGlowRight = new EdgeGlow(context, edge, glow);
+ mEdgeGlowLeft = new EdgeEffect(context);
+ mEdgeGlowRight = new EdgeEffect(context);
}
} else {
mEdgeGlowLeft = null;
diff --git a/core/java/android/widget/OverScroller.java b/core/java/android/widget/OverScroller.java
index 0ba7889..542a1ef 100644
--- a/core/java/android/widget/OverScroller.java
+++ b/core/java/android/widget/OverScroller.java
@@ -166,7 +166,6 @@
}
/**
- * @hide
* Returns the absolute value of the current velocity.
*
* @return The original velocity less the deceleration, norm of the X and Y velocity vector.
diff --git a/core/java/android/widget/ScrollView.java b/core/java/android/widget/ScrollView.java
index 09c875b..6a6bc23 100644
--- a/core/java/android/widget/ScrollView.java
+++ b/core/java/android/widget/ScrollView.java
@@ -69,8 +69,8 @@
private final Rect mTempRect = new Rect();
private OverScroller mScroller;
- private EdgeGlow mEdgeGlowTop;
- private EdgeGlow mEdgeGlowBottom;
+ private EdgeEffect mEdgeGlowTop;
+ private EdgeEffect mEdgeGlowBottom;
/**
* Position of the last motion event.
@@ -1511,11 +1511,8 @@
if (mode != OVER_SCROLL_NEVER) {
if (mEdgeGlowTop == null) {
Context context = getContext();
- final Resources res = context.getResources();
- final Drawable edge = res.getDrawable(R.drawable.overscroll_edge);
- final Drawable glow = res.getDrawable(R.drawable.overscroll_glow);
- mEdgeGlowTop = new EdgeGlow(context, edge, glow);
- mEdgeGlowBottom = new EdgeGlow(context, edge, glow);
+ mEdgeGlowTop = new EdgeEffect(context);
+ mEdgeGlowBottom = new EdgeEffect(context);
}
} else {
mEdgeGlowTop = null;
diff --git a/core/java/android/widget/Scroller.java b/core/java/android/widget/Scroller.java
index f00640e..a6e83f0 100644
--- a/core/java/android/widget/Scroller.java
+++ b/core/java/android/widget/Scroller.java
@@ -196,7 +196,6 @@
}
/**
- * @hide
* Returns the current velocity.
*
* @return The original velocity less the deceleration. Result may be
diff --git a/core/java/android/widget/SpellChecker.java b/core/java/android/widget/SpellChecker.java
index ff13dcb..14cbf6f 100644
--- a/core/java/android/widget/SpellChecker.java
+++ b/core/java/android/widget/SpellChecker.java
@@ -1,4 +1,18 @@
-// Copyright 2011 Google Inc. All Rights Reserved.
+/*
+ * 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.widget;
@@ -32,7 +46,7 @@
private final TextView mTextView;
- final SpellCheckerSession spellCheckerSession;
+ final SpellCheckerSession mSpellCheckerSession;
final int mCookie;
// Paired arrays for the (id, spellCheckSpan) pair. mIndex is the next available position
@@ -49,7 +63,7 @@
final TextServicesManager textServicesManager = (TextServicesManager) textView.getContext().
getSystemService(Context.TEXT_SERVICES_MANAGER_SERVICE);
- spellCheckerSession = textServicesManager.newSpellCheckerSession(
+ mSpellCheckerSession = textServicesManager.newSpellCheckerSession(
null /* not currently used by the textServicesManager */, Locale.getDefault(),
this, true /* means use the languages defined in Settings */);
mCookie = hashCode();
@@ -112,6 +126,8 @@
private void scheduleSpellCheck() {
if (mLength == 0) return;
+ if (mSpellCheckerSession == null) return;
+
if (mChecker != null) {
mTextView.removeCallbacks(mChecker);
}
@@ -155,7 +171,7 @@
System.arraycopy(textInfos, 0, textInfosCopy, 0, textInfosCount);
textInfos = textInfosCopy;
}
- spellCheckerSession.getSuggestions(textInfos, SuggestionSpan.SUGGESTIONS_MAX_SIZE,
+ mSpellCheckerSession.getSuggestions(textInfos, SuggestionSpan.SUGGESTIONS_MAX_SIZE,
false /* TODO Set sequentialWords to true for initial spell check */);
}
}
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index e9662ae..1aa009b 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -63,6 +63,7 @@
import android.text.TextDirectionHeuristics;
import android.text.TextPaint;
import android.text.TextUtils;
+import android.text.TextUtils.TruncateAt;
import android.text.TextWatcher;
import android.text.method.AllCapsTransformationMethod;
import android.text.method.ArrowKeyMovementMethod;
@@ -82,6 +83,7 @@
import android.text.method.TransformationMethod2;
import android.text.method.WordIterator;
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;
@@ -128,6 +130,7 @@
import android.view.inputmethod.ExtractedTextRequest;
import android.view.inputmethod.InputConnection;
import android.view.inputmethod.InputMethodManager;
+import android.widget.AdapterView.OnItemClickListener;
import android.widget.RemoteViews.RemoteView;
import com.android.internal.util.FastMath;
@@ -364,6 +367,35 @@
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 @@
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 @@
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 @@
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 @@
mSavedHintLayout = (BoringLayout) mHintLayout;
}
- mLayout = mHintLayout = null;
+ mSavedMarqueeModeLayout = mLayout = mHintLayout = null;
// Since it depends on the value of mLayout
prepareCursorControllers();
@@ -6065,73 +6108,25 @@
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 @@
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 @@
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 @@
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 @@
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,150 @@
}
}
+ /**
+ * 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() {
+ LinearLayout linearLayout = new LinearLayout(TextView.this.getContext());
+ linearLayout.setOrientation(LinearLayout.HORIZONTAL);
+ mContentView = linearLayout;
+ 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 +7957,8 @@
+ " 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 +7993,10 @@
+ " what=" + what + ": " + buf);
TextView.this.spanChange(buf, what, s, -1, e, -1);
}
+
+ private void hideControllers() {
+ mEditTextShortcutController.hide();
+ }
}
/**
@@ -7945,17 +8179,6 @@
startStopMarquee(hasWindowFocus);
}
- private void removeSpans(int start, int end, Class<?> type) {
- if (mText instanceof Editable) {
- Editable editable = ((Editable) mText);
- Object[] spans = editable.getSpans(start, end, type);
- final int length = spans.length;
- for (int i = 0; i < length; i++) {
- editable.removeSpan(spans[i]);
- }
- }
- }
-
@Override
protected void onVisibilityChanged(View changedView, int visibility) {
super.onVisibilityChanged(changedView, visibility);
@@ -8261,7 +8484,8 @@
@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 +8514,8 @@
@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 +9153,7 @@
stopSelectionActionMode();
} else {
selectCurrentWord();
+ getSelectionController().show();
}
handled = true;
}
@@ -9091,7 +9317,7 @@
private abstract class PinnedPopupWindow implements TextViewPositionListener {
protected PopupWindow mPopupWindow;
- protected LinearLayout mContentView;
+ protected ViewGroup mContentView;
int mPositionX, mPositionY;
protected abstract void createPopupWindow();
@@ -9107,23 +9333,16 @@
mPopupWindow.setWidth(ViewGroup.LayoutParams.WRAP_CONTENT);
mPopupWindow.setHeight(ViewGroup.LayoutParams.WRAP_CONTENT);
- mContentView = new LinearLayout(TextView.this.getContext());
- LayoutParams wrapContent = new LayoutParams(
- ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
+ initContentView();
+
+ LayoutParams wrapContent = new LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT,
+ ViewGroup.LayoutParams.WRAP_CONTENT);
mContentView.setLayoutParams(wrapContent);
- initContentView();
mPopupWindow.setContentView(mContentView);
}
public void show() {
- final DisplayMetrics displayMetrics = mContext.getResources().getDisplayMetrics();
- mContentView.measure(
- View.MeasureSpec.makeMeasureSpec(displayMetrics.widthPixels,
- View.MeasureSpec.AT_MOST),
- View.MeasureSpec.makeMeasureSpec(displayMetrics.heightPixels,
- View.MeasureSpec.AT_MOST));
-
TextView.this.getPositionListener().addSubscriber(this, false);
computeLocalPosition();
@@ -9131,11 +9350,24 @@
final PositionListener positionListener = TextView.this.getPositionListener();
updatePosition(positionListener.getPositionX(), positionListener.getPositionY());
}
+
+ protected void measureContent() {
+ final DisplayMetrics displayMetrics = mContext.getResources().getDisplayMetrics();
+ mContentView.measure(
+ View.MeasureSpec.makeMeasureSpec(displayMetrics.widthPixels,
+ View.MeasureSpec.AT_MOST),
+ View.MeasureSpec.makeMeasureSpec(displayMetrics.heightPixels,
+ View.MeasureSpec.AT_MOST));
+ }
+ /* The popup window will be horizontally centered on the getTextOffset() and vertically
+ * positioned according to viewportToContentHorizontalOffset.
+ *
+ * This method assumes that mContentView has properly been measured from its content. */
private void computeLocalPosition() {
- final int offset = getTextOffset();
-
+ measureContent();
final int width = mContentView.getMeasuredWidth();
+ final int offset = getTextOffset();
mPositionX = (int) (mLayout.getPrimaryHorizontal(offset) - width / 2.0f);
mPositionX += viewportToContentHorizontalOffset();
@@ -9183,14 +9415,17 @@
}
}
- private class SuggestionsPopupWindow extends PinnedPopupWindow implements OnClickListener {
+ private class SuggestionsPopupWindow extends PinnedPopupWindow implements OnItemClickListener {
private static final int MAX_NUMBER_SUGGESTIONS = SuggestionSpan.SUGGESTIONS_MAX_SIZE;
private static final int NO_SUGGESTIONS = -1;
private static final float AVERAGE_HIGHLIGHTS_PER_SUGGESTION = 1.4f;
private WordIterator mSuggestionWordIterator;
private TextAppearanceSpan[] mHighlightSpans = new TextAppearanceSpan
[(int) (AVERAGE_HIGHLIGHTS_PER_SUGGESTION * MAX_NUMBER_SUGGESTIONS)];
+ private SuggestionInfo[] mSuggestionInfos;
+ private int mNumberOfSuggestions;
private boolean mCursorWasVisibleBeforeSuggestions;
+ private SuggestionAdapter mSuggestionsAdapter;
private class CustomPopupWindow extends PopupWindow {
public CustomPopupWindow(Context context, int defStyle) {
@@ -9231,29 +9466,16 @@
@Override
protected void initContentView() {
- mContentView.setOrientation(LinearLayout.VERTICAL);
-
- LayoutInflater inflater = (LayoutInflater) TextView.this.mContext.
- getSystemService(Context.LAYOUT_INFLATER_SERVICE);
-
- if (inflater == null) {
- throw new IllegalArgumentException(
- "Unable to create inflater for TextEdit suggestions");
- }
+ ListView listView = new ListView(TextView.this.getContext());
+ mSuggestionsAdapter = new SuggestionAdapter();
+ listView.setAdapter(mSuggestionsAdapter);
+ listView.setOnItemClickListener(this);
+ mContentView = listView;
// Inflate the suggestion items once and for all.
+ mSuggestionInfos = new SuggestionInfo[MAX_NUMBER_SUGGESTIONS];
for (int i = 0; i < MAX_NUMBER_SUGGESTIONS; i++) {
- View childView = inflater.inflate(mTextEditSuggestionItemLayout,
- mContentView, false);
-
- if (! (childView instanceof TextView)) {
- throw new IllegalArgumentException(
- "Inflated TextEdit suggestion item is not a TextView: " + childView);
- }
-
- childView.setTag(new SuggestionInfo());
- mContentView.addView(childView);
- childView.setOnClickListener(this);
+ mSuggestionInfos[i] = new SuggestionInfo();
}
}
@@ -9262,6 +9484,40 @@
int spanStart, spanEnd; // range in TextView where text should be inserted
SuggestionSpan suggestionSpan; // the SuggestionSpan that this TextView represents
int suggestionIndex; // the index of the suggestion inside suggestionSpan
+ SpannableStringBuilder text = new SpannableStringBuilder();
+ }
+
+ private class SuggestionAdapter extends BaseAdapter {
+ private LayoutInflater mInflater = (LayoutInflater) TextView.this.mContext.
+ getSystemService(Context.LAYOUT_INFLATER_SERVICE);
+
+ @Override
+ public int getCount() {
+ return mNumberOfSuggestions;
+ }
+
+ @Override
+ public Object getItem(int position) {
+ return mSuggestionInfos[position];
+ }
+
+ @Override
+ public long getItemId(int position) {
+ return position;
+ }
+
+ @Override
+ public View getView(int position, View convertView, ViewGroup parent) {
+ TextView textView = (TextView) convertView;
+
+ if (textView == null) {
+ textView = (TextView) mInflater.inflate(mTextEditSuggestionItemLayout, parent,
+ false);
+ }
+
+ textView.setText(mSuggestionInfos[position].text);
+ return textView;
+ }
}
/**
@@ -9306,6 +9562,36 @@
}
@Override
+ protected void measureContent() {
+ final DisplayMetrics displayMetrics = mContext.getResources().getDisplayMetrics();
+ final int horizontalMeasure = View.MeasureSpec.makeMeasureSpec(
+ displayMetrics.widthPixels, View.MeasureSpec.AT_MOST);
+ final int verticalMeasure = View.MeasureSpec.makeMeasureSpec(
+ displayMetrics.heightPixels, View.MeasureSpec.AT_MOST);
+
+ int width = 0;
+ View view = null;
+ for (int i = 0; i < mNumberOfSuggestions; i++) {
+ view = mSuggestionsAdapter.getView(i, view, mContentView);
+ view.measure(horizontalMeasure, verticalMeasure);
+ width = Math.max(width, view.getMeasuredWidth());
+ }
+
+ // Enforce the width based on actual text widths
+ mContentView.measure(
+ View.MeasureSpec.makeMeasureSpec(width, View.MeasureSpec.EXACTLY),
+ verticalMeasure);
+
+ Drawable popupBackground = mPopupWindow.getBackground();
+ if (popupBackground != null) {
+ if (mTempRect == null) mTempRect = new Rect();
+ popupBackground.getPadding(mTempRect);
+ width += mTempRect.left + mTempRect.right;
+ }
+ mPopupWindow.setWidth(width);
+ }
+
+ @Override
protected int getTextOffset() {
return getSelectionStart();
}
@@ -9333,7 +9619,7 @@
final int nbSpans = suggestionSpans.length;
- int totalNbSuggestions = 0;
+ mNumberOfSuggestions = 0;
int spanUnionStart = mText.length();
int spanUnionEnd = 0;
@@ -9347,17 +9633,15 @@
String[] suggestions = suggestionSpan.getSuggestions();
int nbSuggestions = suggestions.length;
for (int suggestionIndex = 0; suggestionIndex < nbSuggestions; suggestionIndex++) {
- TextView textView = (TextView) mContentView.getChildAt(
- totalNbSuggestions);
- textView.setText(suggestions[suggestionIndex]);
- SuggestionInfo suggestionInfo = (SuggestionInfo) textView.getTag();
+ SuggestionInfo suggestionInfo = mSuggestionInfos[mNumberOfSuggestions];
suggestionInfo.spanStart = spanStart;
suggestionInfo.spanEnd = spanEnd;
suggestionInfo.suggestionSpan = suggestionSpan;
suggestionInfo.suggestionIndex = suggestionIndex;
+ suggestionInfo.text = new SpannableStringBuilder(suggestions[suggestionIndex]);
- totalNbSuggestions++;
- if (totalNbSuggestions == MAX_NUMBER_SUGGESTIONS) {
+ mNumberOfSuggestions++;
+ if (mNumberOfSuggestions == MAX_NUMBER_SUGGESTIONS) {
// Also end outer for loop
spanIndex = nbSpans;
break;
@@ -9365,23 +9649,18 @@
}
}
- if (totalNbSuggestions == 0) return false;
+ if (mNumberOfSuggestions == 0) return false;
- if (mSuggestionRangeSpan == null) mSuggestionRangeSpan = new SuggestionRangeSpan();
+ if (mSuggestionRangeSpan == null) mSuggestionRangeSpan =
+ new SuggestionRangeSpan(mHighlightColor);
+
((Editable) mText).setSpan(mSuggestionRangeSpan, spanUnionStart, spanUnionEnd,
Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
- for (int i = 0; i < totalNbSuggestions; i++) {
- final TextView textView = (TextView) mContentView.getChildAt(i);
- highlightTextDifferences(textView, spanUnionStart, spanUnionEnd);
+ for (int i = 0; i < mNumberOfSuggestions; i++) {
+ highlightTextDifferences(mSuggestionInfos[i], spanUnionStart, spanUnionEnd);
}
-
- for (int i = 0; i < totalNbSuggestions; i++) {
- mContentView.getChildAt(i).setVisibility(VISIBLE);
- }
- for (int i = totalNbSuggestions; i < MAX_NUMBER_SUGGESTIONS; i++) {
- mContentView.getChildAt(i).setVisibility(GONE);
- }
+ mSuggestionsAdapter.notifyDataSetChanged();
return true;
}
@@ -9448,13 +9727,13 @@
return highlightSpan;
}
- private void highlightTextDifferences(TextView textView, int unionStart, int unionEnd) {
- SuggestionInfo suggestionInfo = (SuggestionInfo) textView.getTag();
+ private void highlightTextDifferences(SuggestionInfo suggestionInfo,
+ int unionStart, int unionEnd) {
final int spanStart = suggestionInfo.spanStart;
final int spanEnd = suggestionInfo.spanEnd;
// Remove all text formating by converting to Strings
- final String text = textView.getText().toString();
+ final String text = suggestionInfo.text.toString();
final String sourceText = mText.subSequence(spanStart, spanEnd).toString();
long[] sourceWordLimits = getWordLimits(sourceText);
@@ -9529,7 +9808,7 @@
if (previousCommonWordIndex < words.length - 1) {
int firstDifferentPosition = previousCommonWordIndex < 0 ? 0 :
extractRangeEndFromLong(wordLimits[previousCommonWordIndex]);
- int lastDifferentPosition = textView.length();
+ int lastDifferentPosition = text.length();
ssb.setSpan(highlightSpan(nbHighlightSpans++),
shift + firstDifferentPosition, shift + lastDifferentPosition,
Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
@@ -9540,25 +9819,24 @@
int lastCommonTextWordEnd = previousCommonWordIndex < 0 ? 0 :
extractRangeEndFromLong(wordLimits[previousCommonWordIndex]);
- String textSpaces = text.substring(lastCommonTextWordEnd, textView.length());
+ String textSpaces = text.substring(lastCommonTextWordEnd, text.length());
if (!sourceSpaces.equals(textSpaces) && textSpaces.length() > 0) {
ssb.setSpan(highlightSpan(nbHighlightSpans++),
- shift + lastCommonTextWordEnd, shift + textView.length(),
+ shift + lastCommonTextWordEnd, shift + text.length(),
Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
}
}
// Final part, text after the current suggestion range.
ssb.append(mText.subSequence(spanEnd, unionEnd).toString());
- textView.setText(ssb);
}
@Override
- public void onClick(View view) {
+ public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
if (view instanceof TextView) {
TextView textView = (TextView) view;
- SuggestionInfo suggestionInfo = (SuggestionInfo) textView.getTag();
+ SuggestionInfo suggestionInfo = mSuggestionInfos[position];
final int spanStart = suggestionInfo.spanStart;
final int spanEnd = suggestionInfo.spanEnd;
if (spanStart != NO_SUGGESTIONS) {
@@ -9919,9 +10197,11 @@
@Override
protected void initContentView() {
- mContentView.setOrientation(LinearLayout.HORIZONTAL);
+ LinearLayout linearLayout = new LinearLayout(TextView.this.getContext());
+ linearLayout.setOrientation(LinearLayout.HORIZONTAL);
+ mContentView = linearLayout;
mContentView.setBackgroundResource(
- com.android.internal.R.drawable.text_edit_side_paste_window);
+ com.android.internal.R.drawable.text_edit_paste_window);
LayoutInflater inflater = (LayoutInflater)TextView.this.mContext.
getSystemService(Context.LAYOUT_INFLATER_SERVICE);
@@ -10694,6 +10974,10 @@
private void hideControllers() {
hideInsertionPointCursorController();
stopSelectionActionMode();
+
+ if (mChangeWatcher != null) {
+ mChangeWatcher.hideControllers();
+ }
}
/**
@@ -11007,7 +11291,7 @@
private final TextPaint mTextPaint;
private boolean mUserSetTextScaleX;
private final Paint mHighlightPaint;
- private int mHighlightColor = 0xCC475925;
+ private int mHighlightColor = 0x4C33B5E5;
/**
* This is temporarily visible to fix bug 3085564 in webView. Do not rely on
* this field being protected. Will be restored as private when lineHeight
diff --git a/core/java/com/android/internal/widget/ActionBarView.java b/core/java/com/android/internal/widget/ActionBarView.java
index ff26d50..63b0274 100644
--- a/core/java/com/android/internal/widget/ActionBarView.java
+++ b/core/java/com/android/internal/widget/ActionBarView.java
@@ -266,6 +266,17 @@
if (mActionMenuPresenter != null) {
mActionMenuPresenter.onConfigurationChanged(newConfig);
}
+
+ mTitleView = null;
+ mSubtitleView = null;
+ mTitleUpView = null;
+ if (mTitleLayout != null && mTitleLayout.getParent() == this) {
+ removeView(mTitleLayout);
+ }
+ mTitleLayout = null;
+ if ((mDisplayOptions & ActionBar.DISPLAY_SHOW_TITLE) != 0) {
+ initTitle();
+ }
}
@Override
diff --git a/core/java/com/android/internal/widget/TransportControlView.java b/core/java/com/android/internal/widget/TransportControlView.java
index 3961de3..1c47ca88a 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;
- public TransportControlView(Context context) {
- this(context, null);
- }
+ 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 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
- }
-
- public void setCallback(LockScreenWidgetCallback callback) {
- mCallback = callback;
+ private void updateTransportControls(int transportControlFlags) {
+ mTransportControlFlags = transportControlFlags;
}
@Override
public void onFinishInflate() {
- for (int i = 0; i < sViewIds.length; i++) {
- View view = findViewById(sViewIds[i]);
- if (view != null) {
- view.setOnClickListener(this);
+ 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 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);
+ }
+
+ 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 RemoteControlClient.PLAYSTATE_BUFFERING:
+ mBtnPlay.setImageResource(com.android.internal.R.drawable.ic_media_stop);
+ break;
+
+ case RemoteControlClient.PLAYSTATE_PAUSED:
+ default:
+ mBtnPlay.setImageResource(com.android.internal.R.drawable.ic_media_play);
+ break;
+ }
+ 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);
}
}
}
- public void onClick(View v) {
- switch (v.getId()) {
- case R.id.control_prev:
- // TODO
- break;
+ 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);
- case R.id.control_pauseplay:
- // TODO
- break;
+ 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);
+ }
- case R.id.control_next:
- // TODO
- break;
- }
- // Have any button click extend lockscreen's timeout.
- if (mCallback != null) {
- mCallback.userActivity(this);
- }
+ 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 ec926e4..cd1f8ba 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.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 @@
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 @@
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 @@
}
};
private int mTargetResourceId;
+ private int mTargetDescriptionsResourceId;
+ private int mDirectionDescriptionsResourceId;
public MultiWaveView(Context context) {
this(context, null);
@@ -177,6 +187,25 @@
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 @@
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 @@
}
}
+ 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 @@
Drawable drawable = array.getDrawable(i);
targetDrawables.add(new TargetDrawable(res, drawable));
}
+ array.recycle();
mTargetResourceId = resourceId;
mTargetDrawables = targetDrawables;
updateTargetPositions();
@@ -499,6 +539,48 @@
}
/**
+ * 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 @@
}
}
+ @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 @@
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 @@
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)) {
+ String text = String.format(directionDescription, targetDescription);
+ utterance.append(text);
+ }
+ if (utterance.length() > 0) {
+ 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_database_CursorWindow.cpp b/core/jni/android_database_CursorWindow.cpp
index ddac820..419e464 100644
--- a/core/jni/android_database_CursorWindow.cpp
+++ b/core/jni/android_database_CursorWindow.cpp
@@ -352,7 +352,6 @@
char buf[32];
int len;
snprintf(buf, sizeof(buf), "%lld", value);
- jchar* dst = env->GetCharArrayElements(buffer, NULL);
sizeCopied = charToJchar(buf, dst, bufferSize);
}
} else if (type == FIELD_TYPE_FLOAT) {
@@ -360,7 +359,6 @@
if (window->getDouble(row, column, &value)) {
char tempbuf[32];
snprintf(tempbuf, sizeof(tempbuf), "%g", value);
- jchar* dst = env->GetCharArrayElements(buffer, NULL);
sizeCopied = charToJchar(tempbuf, dst, bufferSize);
}
} else if (type == FIELD_TYPE_NULL) {
diff --git a/core/jni/android_net_wifi_Wifi.cpp b/core/jni/android_net_wifi_Wifi.cpp
index 3cbd912..84a50f0 100644
--- a/core/jni/android_net_wifi_Wifi.cpp
+++ b/core/jni/android_net_wifi_Wifi.cpp
@@ -124,6 +124,11 @@
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 @@
{ "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 4cf4afa..494a2b3 100644
--- a/core/jni/android_util_Binder.cpp
+++ b/core/jni/android_util_Binder.cpp
@@ -119,6 +119,11 @@
} gBinderProxyOffsets;
+static struct class_offsets_t
+{
+ jmethodID mGetName;
+} gClassOffsets;
+
// ----------------------------------------------------------------------------
static struct parcel_offsets_t
@@ -452,22 +457,18 @@
// 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 @@
= 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/jni/android_view_InputChannel.cpp b/core/jni/android_view_InputChannel.cpp
index 0c2801c..5fcf8fa 100644
--- a/core/jni/android_view_InputChannel.cpp
+++ b/core/jni/android_view_InputChannel.cpp
@@ -111,7 +111,9 @@
NativeInputChannel* nativeInputChannel) {
jobject inputChannelObj = env->NewObject(gInputChannelClassInfo.clazz,
gInputChannelClassInfo.ctor);
- android_view_InputChannel_setNativeInputChannel(env, inputChannelObj, nativeInputChannel);
+ if (inputChannelObj) {
+ android_view_InputChannel_setNativeInputChannel(env, inputChannelObj, nativeInputChannel);
+ }
return inputChannelObj;
}
@@ -126,18 +128,29 @@
status_t result = InputChannel::openInputChannelPair(name, serverChannel, clientChannel);
if (result) {
- LOGE("Could not open input channel pair. status=%d", result);
- jniThrowRuntimeException(env, "Could not open input channel pair.");
+ String8 message;
+ message.appendFormat("Could not open input channel pair. status=%d", result);
+ jniThrowRuntimeException(env, message.string());
return NULL;
}
- // TODO more robust error checking
+ jobjectArray channelPair = env->NewObjectArray(2, gInputChannelClassInfo.clazz, NULL);
+ if (env->ExceptionCheck()) {
+ return NULL;
+ }
+
jobject serverChannelObj = android_view_InputChannel_createInputChannel(env,
new NativeInputChannel(serverChannel));
+ if (env->ExceptionCheck()) {
+ return NULL;
+ }
+
jobject clientChannelObj = android_view_InputChannel_createInputChannel(env,
new NativeInputChannel(clientChannel));
+ if (env->ExceptionCheck()) {
+ return NULL;
+ }
- jobjectArray channelPair = env->NewObjectArray(2, gInputChannelClassInfo.clazz, NULL);
env->SetObjectArrayElement(channelPair, 0, serverChannelObj);
env->SetObjectArrayElement(channelPair, 1, clientChannelObj);
return channelPair;
@@ -161,7 +174,7 @@
static void android_view_InputChannel_nativeTransferTo(JNIEnv* env, jobject obj,
jobject otherObj) {
- if (android_view_InputChannel_getInputChannel(env, otherObj) != NULL) {
+ if (android_view_InputChannel_getNativeInputChannel(env, otherObj) != NULL) {
jniThrowException(env, "java/lang/IllegalStateException",
"Other object already has a native input channel.");
return;
@@ -175,7 +188,7 @@
static void android_view_InputChannel_nativeReadFromParcel(JNIEnv* env, jobject obj,
jobject parcelObj) {
- if (android_view_InputChannel_getInputChannel(env, obj) != NULL) {
+ if (android_view_InputChannel_getNativeInputChannel(env, obj) != NULL) {
jniThrowException(env, "java/lang/IllegalStateException",
"This object already has a native input channel.");
return;
diff --git a/core/jni/android_view_InputQueue.cpp b/core/jni/android_view_InputQueue.cpp
index 80c4871..300c04a 100644
--- a/core/jni/android_view_InputQueue.cpp
+++ b/core/jni/android_view_InputQueue.cpp
@@ -455,8 +455,9 @@
env, inputChannelObj, inputHandlerObj, messageQueueObj);
if (status) {
- jniThrowRuntimeException(env, "Failed to register input channel. "
- "Check logs for details.");
+ String8 message;
+ message.appendFormat("Failed to register input channel. status=%d", status);
+ jniThrowRuntimeException(env, message.string());
}
}
@@ -465,8 +466,9 @@
status_t status = gNativeInputQueue.unregisterInputChannel(env, inputChannelObj);
if (status) {
- jniThrowRuntimeException(env, "Failed to unregister input channel. "
- "Check logs for details.");
+ String8 message;
+ message.appendFormat("Failed to unregister input channel. status=%d", status);
+ jniThrowRuntimeException(env, message.string());
}
}
@@ -479,8 +481,9 @@
// was no longer registered (DEAD_OBJECT) since it is a common race that can occur
// during application shutdown. The input dispatcher recovers gracefully anyways.
if (status != OK && status != DEAD_OBJECT) {
- jniThrowRuntimeException(env, "Failed to finish input event. "
- "Check logs for details.");
+ String8 message;
+ message.appendFormat("Failed to finish input event. status=%d", status);
+ jniThrowRuntimeException(env, message.string());
}
}
diff --git a/core/jni/android_view_Surface.cpp b/core/jni/android_view_Surface.cpp
index 4c1ca31..49441eb 100644
--- a/core/jni/android_view_Surface.cpp
+++ b/core/jni/android_view_Surface.cpp
@@ -589,7 +589,7 @@
}
static void Surface_setPosition(
- JNIEnv* env, jobject clazz, jint x, jint y)
+ JNIEnv* env, jobject clazz, jfloat x, jfloat y)
{
const sp<SurfaceControl>& surface(getSurfaceControl(env, clazz));
if (surface == 0) return;
@@ -832,7 +832,7 @@
{"screenshot", "(II)Landroid/graphics/Bitmap;", (void*)Surface_screenshotAll },
{"screenshot", "(IIII)Landroid/graphics/Bitmap;", (void*)Surface_screenshot },
{"setLayer", "(I)V", (void*)Surface_setLayer },
- {"setPosition", "(II)V",(void*)Surface_setPosition },
+ {"setPosition", "(FF)V",(void*)Surface_setPosition },
{"setSize", "(II)V",(void*)Surface_setSize },
{"hide", "()V", (void*)Surface_hide },
{"show", "()V", (void*)Surface_show },
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 540c65a..f50cecd 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" />
@@ -917,7 +920,7 @@
<!-- Allows applications to write the apn settings -->
<permission android:name="android.permission.WRITE_APN_SETTINGS"
android:permissionGroup="android.permission-group.SYSTEM_TOOLS"
- android:protectionLevel="dangerous"
+ android:protectionLevel="signatureOrSystem"
android:description="@string/permdesc_writeApnSettings"
android:label="@string/permlab_writeApnSettings" />
diff --git a/core/res/res/anim/wallpaper_close_exit.xml b/core/res/res/anim/wallpaper_close_exit.xml
index 7e0e05f..987fd89 100644
--- a/core/res/res/anim/wallpaper_close_exit.xml
+++ b/core/res/res/anim/wallpaper_close_exit.xml
@@ -29,4 +29,7 @@
android:fillEnabled="true" android:fillAfter="true"
android:interpolator="@interpolator/decelerate_quint"
android:duration="300" />
+ <!-- This is needed to keep the animation running while wallpaper_close_enter completes -->
+ <alpha android:fromAlpha="1.0" android:toAlpha="1.0"
+ android:duration="600" />
</set>
\ No newline at end of file
diff --git a/core/res/res/anim/wallpaper_open_exit.xml b/core/res/res/anim/wallpaper_open_exit.xml
index 075831b..1804fa8 100644
--- a/core/res/res/anim/wallpaper_open_exit.xml
+++ b/core/res/res/anim/wallpaper_open_exit.xml
@@ -29,5 +29,7 @@
android:interpolator="@interpolator/accelerate_quint"
android:fillEnabled="true" android:fillBefore="true" android:fillAfter="true"
android:duration="200" />
-
+ <!-- This is needed to keep the animation running while wallpaper_open_enter completes -->
+ <alpha android:fromAlpha="1.0" android:toAlpha="1.0"
+ android:duration="500" />
</set>
\ No newline at end of file
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
index 81829bb..769463b 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
Binary files differ
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
index 0436801..88f11dc 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
Binary files differ
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
index 6574c8c..7305047 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
Binary files differ
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
index 1565ac2..712a551 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
Binary files differ
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
index 77d4c4b..bf3b943 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
Binary files differ
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
index 0fc8632..cbbaec5 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
Binary files differ
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
index 74540c1..af917e5 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
Binary files differ
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
index 69bcd7a..2d59f35 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
Binary files differ
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
index 9f8829f..0520e5a 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
Binary files differ
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
index d63e85e..42528b1 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
Binary files differ
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
index 9cff5d8..e3e3f93 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
Binary files differ
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
index 12a6454..1e39572 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
Binary files differ
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
index 3355d30..a16db85 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
Binary files differ
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
index a5e8570..0eff695 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
Binary files differ
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
index c49412a..219b170 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
Binary files differ
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
index fabc252..0d165bb 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
Binary files differ
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
index f59ef4e..73c7e25 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
Binary files differ
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
index c87c5a6..1459eee 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
Binary files differ
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
index 6e4cae2..04de530 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
Binary files differ
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
index e6f83cc..bab70fa 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
Binary files differ
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
index 5c97e3f..b46adfa 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
Binary files differ
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
index 269def4..1d836f6 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
Binary files differ
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
index 49bcfb4..5818666 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
Binary files differ
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
index b7ddc14..564fb34 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
Binary files differ
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
index af80ad5..ae21b76 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
Binary files differ
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
new file mode 100644
index 0000000..b187358
--- /dev/null
+++ b/core/res/res/drawable-hdpi/ic_lockscreen_player_background.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_media_embed_play.png b/core/res/res/drawable-hdpi/ic_media_embed_play.png
index 05778c1..23ac7e4 100644
--- a/core/res/res/drawable-hdpi/ic_media_embed_play.png
+++ b/core/res/res/drawable-hdpi/ic_media_embed_play.png
Binary files differ
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
index 1e69eac..5f2f604 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
Binary files differ
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
index 2f6accc..7f3459c 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
Binary files differ
diff --git a/core/res/res/drawable-hdpi/text_edit_paste_window.9.png b/core/res/res/drawable-hdpi/text_edit_paste_window.9.png
index 6654e4d..b74f37b 100644
--- a/core/res/res/drawable-hdpi/text_edit_paste_window.9.png
+++ b/core/res/res/drawable-hdpi/text_edit_paste_window.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/text_edit_suggestions_window.9.png b/core/res/res/drawable-hdpi/text_edit_suggestions_window.9.png
index c97514f..b74f37b 100644
--- a/core/res/res/drawable-hdpi/text_edit_suggestions_window.9.png
+++ b/core/res/res/drawable-hdpi/text_edit_suggestions_window.9.png
Binary files differ
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
index b3d51ed..b229367 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
Binary files differ
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
index abae537..c65f443 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
Binary files differ
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
index 4c98afb..0706c8a 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
Binary files differ
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
index de8010a..d814d02 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
Binary files differ
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
index ecb2a0e..b139c8e 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
Binary files differ
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
index 56d27a8..743d00b 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
Binary files differ
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
index 98b4956..17c1fb9 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
Binary files differ
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
index dcd3703..ddfc8e3 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
Binary files differ
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
index aa0a3a0..007a4b2 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
Binary files differ
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
index cf17967..a823841 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
Binary files differ
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
index ab0003b..ad6e1a4 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
Binary files differ
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
index 5f1eb1e..0ad6c88 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
Binary files differ
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
index 89822b6..19b50ab 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
Binary files differ
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
index bd9921f..ad980b1 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
Binary files differ
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
index 8d93926..60e6c52 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
Binary files differ
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
index d00d235..9e936b3 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
Binary files differ
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
index d7b20493..0360104 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
Binary files differ
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
index 59c1580..dd947d2 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
Binary files differ
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
index 143564a..51cfca2 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
Binary files differ
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
index e5b9cfd..fd6e6c7 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
Binary files differ
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
index ec43f85..5db212c 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
Binary files differ
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
index 0e4b28e..d8f1c8b 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
Binary files differ
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
index e449090..31e4989 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
Binary files differ
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
index d0ebc1a..7c2cbe5 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
Binary files differ
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
index c2dd608..30cbdc1 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
Binary files differ
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
new file mode 100644
index 0000000..8cfd1af
--- /dev/null
+++ b/core/res/res/drawable-mdpi/ic_lockscreen_player_background.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_media_embed_play.png b/core/res/res/drawable-mdpi/ic_media_embed_play.png
index 3576ce5..fc5d8c6 100644
--- a/core/res/res/drawable-mdpi/ic_media_embed_play.png
+++ b/core/res/res/drawable-mdpi/ic_media_embed_play.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_media_ff.png b/core/res/res/drawable-mdpi/ic_media_ff.png
index 170dd2d..892772e 100644
--- a/core/res/res/drawable-mdpi/ic_media_ff.png
+++ b/core/res/res/drawable-mdpi/ic_media_ff.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_media_fullscreen.png b/core/res/res/drawable-mdpi/ic_media_fullscreen.png
index 960aa85..1c60e15 100644
--- a/core/res/res/drawable-mdpi/ic_media_fullscreen.png
+++ b/core/res/res/drawable-mdpi/ic_media_fullscreen.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_media_next.png b/core/res/res/drawable-mdpi/ic_media_next.png
index a6feed0..bbe311b 100644
--- a/core/res/res/drawable-mdpi/ic_media_next.png
+++ b/core/res/res/drawable-mdpi/ic_media_next.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_media_pause.png b/core/res/res/drawable-mdpi/ic_media_pause.png
index 548ba02..e4e8d86 100644
--- a/core/res/res/drawable-mdpi/ic_media_pause.png
+++ b/core/res/res/drawable-mdpi/ic_media_pause.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_media_play.png b/core/res/res/drawable-mdpi/ic_media_play.png
index 0fe6806..8eaf962 100644
--- a/core/res/res/drawable-mdpi/ic_media_play.png
+++ b/core/res/res/drawable-mdpi/ic_media_play.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_media_previous.png b/core/res/res/drawable-mdpi/ic_media_previous.png
index 0163d09..e9abc7f 100644
--- a/core/res/res/drawable-mdpi/ic_media_previous.png
+++ b/core/res/res/drawable-mdpi/ic_media_previous.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_media_rew.png b/core/res/res/drawable-mdpi/ic_media_rew.png
index 5489180..a5eb94a 100644
--- a/core/res/res/drawable-mdpi/ic_media_rew.png
+++ b/core/res/res/drawable-mdpi/ic_media_rew.png
Binary files differ
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
index 135ca6e..1d2592a 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
Binary files differ
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
index ccbf143..4060afe 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
Binary files differ
diff --git a/core/res/res/drawable-mdpi/text_edit_paste_window.9.png b/core/res/res/drawable-mdpi/text_edit_paste_window.9.png
index 41886eb..16f623d 100644
--- a/core/res/res/drawable-mdpi/text_edit_paste_window.9.png
+++ b/core/res/res/drawable-mdpi/text_edit_paste_window.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/text_edit_suggestions_window.9.png b/core/res/res/drawable-mdpi/text_edit_suggestions_window.9.png
index 88be6e1..16f623d 100644
--- a/core/res/res/drawable-mdpi/text_edit_suggestions_window.9.png
+++ b/core/res/res/drawable-mdpi/text_edit_suggestions_window.9.png
Binary files differ
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
index 506cd68ff..5753346 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
Binary files differ
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
index c185112..7e6c047 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
Binary files differ
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
index 8ed7f9b..8155fe8 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
Binary files differ
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
index c4694cd..6cee9a1 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
Binary files differ
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
index 57f5cfa..fa4d76a 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
Binary files differ
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
index d16e50cc..6622cba 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
Binary files differ
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
index 45cc807..c427297 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
Binary files differ
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
index a9e0d4d..d0df29d 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
Binary files differ
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
index 5ea235d..a0d9c1b 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
Binary files differ
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
index 0220c8d..16b9bef 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
Binary files differ
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
index be13077..d36f99f 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
Binary files differ
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
index ab02e7a..5ad475d 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
Binary files differ
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
index 0b5a24e..6ade5ee 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
Binary files differ
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
index 6d21429..719b923 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
Binary files differ
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
index c34c46f..6da264d 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
Binary files differ
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
index a338924..01efef4 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
Binary files differ
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
index 6f2d3e5..c287605 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
Binary files differ
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
index faa36b0..9a496e8 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
Binary files differ
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
index c57f3ff..e2a38b4 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
Binary files differ
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
index 9d6402f..911722f 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
Binary files differ
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
index bfd966c2..da169bf 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
Binary files differ
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
index 2bd8cee..0bd0980 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
Binary files differ
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
index d254e77..43ed26d 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
Binary files differ
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
index 919eac0..6b31579 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
Binary files differ
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
index 1357105..df0121b 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
Binary files differ
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
new file mode 100644
index 0000000..7fb0cbc
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/ic_lockscreen_player_background.9.png
Binary files differ
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
index 81306ca..1ce25e2 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
Binary files differ
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
index 1f46e7a..dcd6514 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
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/text_edit_paste_window.9.png b/core/res/res/drawable-xhdpi/text_edit_paste_window.9.png
new file mode 100644
index 0000000..5c043b6
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/text_edit_paste_window.9.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/text_edit_suggestions_window.9.png b/core/res/res/drawable-xhdpi/text_edit_suggestions_window.9.png
new file mode 100644
index 0000000..5c043b6
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/text_edit_suggestions_window.9.png
Binary files differ
diff --git a/core/res/res/drawable/switch_inner_holo_dark.xml b/core/res/res/drawable/switch_inner_holo_dark.xml
index 3eb55ee..67584bc 100644
--- a/core/res/res/drawable/switch_inner_holo_dark.xml
+++ b/core/res/res/drawable/switch_inner_holo_dark.xml
@@ -17,5 +17,6 @@
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_enabled="false" android:drawable="@drawable/switch_thumb_disabled_holo_dark" />
<item android:state_pressed="true" android:drawable="@drawable/switch_thumb_pressed_holo_dark" />
+ <item android:state_checked="true" android:drawable="@drawable/switch_thumb_activated_holo_dark" />
<item android:drawable="@drawable/switch_thumb_holo_dark" />
</selector>
diff --git a/core/res/res/drawable/switch_inner_holo_light.xml b/core/res/res/drawable/switch_inner_holo_light.xml
index 9b287cf..95df0e88 100644
--- a/core/res/res/drawable/switch_inner_holo_light.xml
+++ b/core/res/res/drawable/switch_inner_holo_light.xml
@@ -17,5 +17,6 @@
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_enabled="false" android:drawable="@drawable/switch_thumb_disabled_holo_light" />
<item android:state_pressed="true" android:drawable="@drawable/switch_thumb_pressed_holo_light" />
+ <item android:state_checked="true" android:drawable="@drawable/switch_thumb_activated_holo_light" />
<item android:drawable="@drawable/switch_thumb_holo_light" />
</selector>
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 f3850d5..3a7c1e1 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 f4c99f1..c02341e 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/action_bar_title_item.xml b/core/res/res/layout/action_bar_title_item.xml
index 0828402..4c74f6a 100644
--- a/core/res/res/layout/action_bar_title_item.xml
+++ b/core/res/res/layout/action_bar_title_item.xml
@@ -16,7 +16,7 @@
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
- android:layout_height="match_parent"
+ android:layout_height="wrap_content"
android:orientation="horizontal"
android:paddingRight="16dip"
android:background="?android:attr/actionBarItemBackground"
@@ -41,6 +41,8 @@
<TextView android:id="@+id/action_bar_subtitle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
+ android:layout_marginTop="@dimen/action_bar_subtitle_top_margin"
+ android:layout_marginBottom="@dimen/action_bar_subtitle_bottom_margin"
android:singleLine="true"
android:ellipsize="end"
android:visibility="gone" />
diff --git a/core/res/res/layout/keyguard_screen_password_landscape.xml b/core/res/res/layout/keyguard_screen_password_landscape.xml
index 12df99e..694db50 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 6145e47..cf3bd42 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 6016d4e..0368530 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"
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 0568dd9..2849376 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"
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 9b28731..d71dbff 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 433dda7..64c479f 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 6308b02..2ebe5fc 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"
+ <LinearLayout
+ android:orientation="vertical"
+ android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:background="#8000ff00"
+ 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"
/>
-
- <Space android:layout_width="0dip"
- android:layout_height="0dip"
- android:layout_weight="1"/>
-
- <Button android:id="@+id/control_next"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:background="#800000ff"
- />
+ <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/layout/text_edit_action_popup_text.xml b/core/res/res/layout/text_edit_action_popup_text.xml
index aa6a5e1..42e6f2e 100644
--- a/core/res/res/layout/text_edit_action_popup_text.xml
+++ b/core/res/res/layout/text_edit_action_popup_text.xml
@@ -25,4 +25,5 @@
android:textAppearance="?android:attr/textAppearanceSmallInverse"
android:textColor="@android:color/black"
android:textAllCaps="true"
+ android:textStyle="bold"
/>
diff --git a/core/res/res/values-land/arrays.xml b/core/res/res/values-land/arrays.xml
index fd492ec..68e5cfd 100644
--- a/core/res/res/values-land/arrays.xml
+++ b/core/res/res/values-land/arrays.xml
@@ -27,13 +27,34 @@
<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">
+ <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_targets_with_camera">
<item>@null</item>
<item>@drawable/ic_lockscreen_unlock</item>
@@ -41,4 +62,11 @@
<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>
+
</resources>
diff --git a/core/res/res/values-land/dimens.xml b/core/res/res/values-land/dimens.xml
index 02bb3c8..6f96852 100644
--- a/core/res/res/values-land/dimens.xml
+++ b/core/res/res/values-land/dimens.xml
@@ -35,6 +35,10 @@
<dimen name="action_bar_title_text_size">16dp</dimen>
<!-- Text size for action bar subtitles -->
<dimen name="action_bar_subtitle_text_size">12dp</dimen>
+ <!-- Top margin for action bar subtitles -->
+ <dimen name="action_bar_subtitle_top_margin">-2dp</dimen>
+ <!-- Bottom margin for action bar subtitles -->
+ <dimen name="action_bar_subtitle_bottom_margin">4dip</dimen>
<!-- Size of clock font in LockScreen on Unsecure unlock screen. -->
<dimen name="keyguard_lockscreen_clock_font_size">70sp</dimen>
diff --git a/core/res/res/values-sw600dp/colors.xml b/core/res/res/values-sw600dp/colors.xml
index 6b5a55a..edd2712 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-sw600dp/dimens.xml b/core/res/res/values-sw600dp/dimens.xml
index 792066e..2daaaa2 100644
--- a/core/res/res/values-sw600dp/dimens.xml
+++ b/core/res/res/values-sw600dp/dimens.xml
@@ -37,6 +37,10 @@
<dimen name="action_bar_title_text_size">18dp</dimen>
<!-- Text size for action bar subtitles -->
<dimen name="action_bar_subtitle_text_size">14dp</dimen>
+ <!-- Top margin for action bar subtitles -->
+ <dimen name="action_bar_subtitle_top_margin">-3dp</dimen>
+ <!-- Bottom margin for action bar subtitles -->
+ <dimen name="action_bar_subtitle_bottom_margin">9dip</dimen>
<!-- Size of clock font in LockScreen. -->
<dimen name="keyguard_pattern_unlock_clock_font_size">98sp</dimen>
diff --git a/core/res/res/values/arrays.xml b/core/res/res/values/arrays.xml
index 57e9bbf..8d5bd0b 100644
--- a/core/res/res/values/arrays.xml
+++ b/core/res/res/values/arrays.xml
@@ -349,18 +349,46 @@
<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">
+ <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_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>
</resources>
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index dae9f70..b50c063 100755
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -160,9 +160,8 @@
<!-- 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 +3148,7 @@
</declare-styleable>
<declare-styleable name="SuggestionSpan">
<attr name="textUnderlineColor" />
- <attr name="textUnderlineThicknessPercentage" />
+ <attr name="textUnderlineThickness" />
</declare-styleable>
<!-- An <code>input-extras</code> is a container for extra data to supply to
an input method. Contains
@@ -5169,6 +5168,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/colors.xml b/core/res/res/values/colors.xml
index aee7ea4..fd525f3 100644
--- a/core/res/res/values/colors.xml
+++ b/core/res/res/values/colors.xml
@@ -54,8 +54,6 @@
<color name="dim_foreground_light_inverse">#bebebe</color>
<color name="dim_foreground_light_inverse_disabled">#80bebebe</color>
<color name="hint_foreground_light">#808080</color>
- <color name="highlight_background">#cc475925</color>
- <color name="highlight_background_inverse">#ccd2e461</color>
<color name="highlighted_text_dark">#9983CC39</color>
<color name="highlighted_text_light">#9983CC39</color>
<color name="link_text_dark">#5c5cff</color>
@@ -135,10 +133,8 @@
<color name="dim_foreground_inverse_holo_light">#bebebe</color>
<color name="dim_foreground_inverse_disabled_holo_light">#80bebebe</color>
<color name="hint_foreground_holo_light">#808080</color>
- <color name="highlight_background_holo">#cc475925</color>
- <color name="highlight_background_inverse_holo">#ccd2e461</color>
- <color name="highlighted_text_holo_dark">#9983CC39</color>
- <color name="highlighted_text_holo_light">#9983CC39</color>
+ <color name="highlighted_text_holo_dark">#4c33b5e5</color>
+ <color name="highlighted_text_holo_light">#4c33b5e5</color>
<color name="link_text_holo_dark">#5c5cff</color>
<color name="link_text_holo_light">#0000ee</color>
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index b155b803..051ed14 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/dimens.xml b/core/res/res/values/dimens.xml
index 62a2187..2753eab 100644
--- a/core/res/res/values/dimens.xml
+++ b/core/res/res/values/dimens.xml
@@ -146,6 +146,10 @@
<dimen name="action_bar_title_text_size">18dp</dimen>
<!-- Text size for action bar subtitles -->
<dimen name="action_bar_subtitle_text_size">14dp</dimen>
+ <!-- Top margin for action bar subtitles -->
+ <dimen name="action_bar_subtitle_top_margin">-3dp</dimen>
+ <!-- Bottom margin for action bar subtitles -->
+ <dimen name="action_bar_subtitle_bottom_margin">5dip</dimen>
<!-- Size of clock font in LockScreen on Unsecure unlock screen. -->
<dimen name="keyguard_lockscreen_clock_font_size">80sp</dimen>
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index fcd3bba..6988f6b 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 8e0f300..32e8827 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 for <xliff:g id="target_description" example="Unlock">%s</xliff:g>.</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 for <xliff:g id="target_description" example="Unlock">%s</xliff:g>.</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 for <xliff:g id="target_description" example="Unlock">%s</xliff:g>.</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 for <xliff:g id="target_description" example="Unlock">%s</xliff:g>.</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 052a040..fba1cd1 100644
--- a/core/res/res/values/styles.xml
+++ b/core/res/res/values/styles.xml
@@ -244,7 +244,7 @@
</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">
diff --git a/data/fonts/DroidSansArmenian.ttf b/data/fonts/DroidSansArmenian.ttf
new file mode 100644
index 0000000..62f67e0
--- /dev/null
+++ b/data/fonts/DroidSansArmenian.ttf
Binary files differ
diff --git a/data/fonts/DroidSansFallback.ttf b/data/fonts/DroidSansFallback.ttf
index 03ceae5..ba9d76f 100644
--- a/data/fonts/DroidSansFallback.ttf
+++ b/data/fonts/DroidSansFallback.ttf
Binary files differ
diff --git a/data/fonts/DroidSansFallbackFull.ttf b/data/fonts/DroidSansFallbackFull.ttf
new file mode 100644
index 0000000..03ceae5
--- /dev/null
+++ b/data/fonts/DroidSansFallbackFull.ttf
Binary files differ
diff --git a/data/fonts/DroidSansGeorgian.ttf b/data/fonts/DroidSansGeorgian.ttf
new file mode 100644
index 0000000..743ae66
--- /dev/null
+++ b/data/fonts/DroidSansGeorgian.ttf
Binary files differ
diff --git a/data/fonts/fonts.mk b/data/fonts/fonts.mk
index d8c1fa2..56bd2ce 100644
--- a/data/fonts/fonts.mk
+++ b/data/fonts/fonts.mk
@@ -14,15 +14,14 @@
# Warning: this is actually a product definition, to be inherited from
+# On space-constrained devices, we include a subset of fonts:
+# First, core/required fonts
PRODUCT_COPY_FILES := \
- frameworks/base/data/fonts/Roboto-Regular.ttf:system/fonts/Roboto-Regular.ttf \
- frameworks/base/data/fonts/Roboto-Bold.ttf:system/fonts/Roboto-Bold.ttf \
- frameworks/base/data/fonts/Roboto-Italic.ttf:system/fonts/Roboto-Italic.ttf \
- frameworks/base/data/fonts/Roboto-BoldItalic.ttf:system/fonts/Roboto-BoldItalic.ttf \
- frameworks/base/data/fonts/DroidSans.ttf:system/fonts/DroidSans.ttf \
- frameworks/base/data/fonts/DroidSans-Bold.ttf:system/fonts/DroidSans-Bold.ttf \
+ frameworks/base/data/fonts/Roboto-Regular.ttf:system/fonts/Roboto-Regular.ttf \
+ frameworks/base/data/fonts/Roboto-Bold.ttf:system/fonts/Roboto-Bold.ttf \
+ frameworks/base/data/fonts/Roboto-Italic.ttf:system/fonts/Roboto-Italic.ttf \
+ frameworks/base/data/fonts/Roboto-BoldItalic.ttf:system/fonts/Roboto-BoldItalic.ttf \
frameworks/base/data/fonts/DroidNaskh-Regular.ttf:system/fonts/DroidNaskh-Regular.ttf \
- frameworks/base/data/fonts/DroidSansEthiopic-Regular.ttf:system/fonts/DroidSansEthiopic-Regular.ttf \
frameworks/base/data/fonts/DroidSansHebrew-Regular.ttf:system/fonts/DroidSansHebrew-Regular.ttf \
frameworks/base/data/fonts/DroidSansHebrew-Bold.ttf:system/fonts/DroidSansHebrew-Bold.ttf \
frameworks/base/data/fonts/DroidSansThai.ttf:system/fonts/DroidSansThai.ttf \
@@ -33,9 +32,22 @@
frameworks/base/data/fonts/DroidSansMono.ttf:system/fonts/DroidSansMono.ttf \
frameworks/base/data/fonts/Lohit_Hindi.ttf:system/fonts/Lohit_Hindi.ttf \
frameworks/base/data/fonts/Clockopia.ttf:system/fonts/Clockopia.ttf \
- frameworks/base/data/fonts/DroidSansFallback.ttf:system/fonts/DroidSansFallback.ttf \
frameworks/base/data/fonts/AndroidClock.ttf:system/fonts/AndroidClock.ttf \
frameworks/base/data/fonts/AndroidClock_Highlight.ttf:system/fonts/AndroidClock_Highlight.ttf \
frameworks/base/data/fonts/AndroidClock_Solid.ttf:system/fonts/AndroidClock_Solid.ttf \
frameworks/base/data/fonts/system_fonts.xml:system/etc/system_fonts.xml \
frameworks/base/data/fonts/fallback_fonts.xml:system/etc/fallback_fonts.xml
+
+# Next, include additional fonts, depending on how much space we have
+ifeq ($(SMALLER_FONT_FOOTPRINT),true)
+# Smaller fonts alternatives
+PRODUCT_COPY_FILES += \
+ frameworks/base/data/fonts/DroidSansFallback.ttf:system/fonts/DroidSansFallback.ttf
+else
+# Full font set alternatives
+PRODUCT_COPY_FILES += \
+ frameworks/base/data/fonts/DroidSansFallbackFull.ttf:system/fonts/DroidSansFallback.ttf \
+ frameworks/base/data/fonts/DroidSans.ttf:system/fonts/DroidSans.ttf \
+ frameworks/base/data/fonts/DroidSans-Bold.ttf:system/fonts/DroidSans-Bold.ttf \
+ frameworks/base/data/fonts/DroidSansEthiopic-Regular.ttf:system/fonts/DroidSansEthiopic-Regular.ttf
+endif
diff --git a/data/sounds/AudioPackage6.mk b/data/sounds/AudioPackage6.mk
index fd6bf17..610e821 100755
--- a/data/sounds/AudioPackage6.mk
+++ b/data/sounds/AudioPackage6.mk
@@ -41,29 +41,4 @@
$(LOCAL_PATH)/notifications/ogg/Thallium.ogg:system/media/audio/notifications/Thallium.ogg \
$(LOCAL_PATH)/notifications/ogg/Xenon.ogg:system/media/audio/notifications/Xenon.ogg \
$(LOCAL_PATH)/notifications/ogg/Zirconium.ogg:system/media/audio/notifications/Zirconium.ogg \
- $(LOCAL_PATH)/ringtones/ogg/Andromeda.ogg:system/media/audio/ringtones/Andromeda.ogg \
- $(LOCAL_PATH)/ringtones/ogg/Aquila.ogg:system/media/audio/ringtones/Aquila.ogg \
- $(LOCAL_PATH)/ringtones/ogg/ArgoNavis.ogg:system/media/audio/ringtones/ArgoNavis.ogg \
- $(LOCAL_PATH)/ringtones/ogg/Bootes.ogg:system/media/audio/ringtones/Bootes.ogg \
- $(LOCAL_PATH)/ringtones/ogg/CanisMajor.ogg:system/media/audio/ringtones/CanisMajor.ogg \
- $(LOCAL_PATH)/ringtones/ogg/Carina.ogg:system/media/audio/ringtones/Carina.ogg \
- $(LOCAL_PATH)/ringtones/ogg/Cassiopeia.ogg:system/media/audio/ringtones/Cassiopeia.ogg \
- $(LOCAL_PATH)/ringtones/ogg/Centaurus.ogg:system/media/audio/ringtones/Centaurus.ogg \
- $(LOCAL_PATH)/ringtones/ogg/Cygnus.ogg:system/media/audio/ringtones/Cygnus.ogg \
- $(LOCAL_PATH)/ringtones/ogg/Draco.ogg:system/media/audio/ringtones/Draco.ogg \
- $(LOCAL_PATH)/ringtones/ogg/Eridani.ogg:system/media/audio/ringtones/Eridani.ogg \
- $(LOCAL_PATH)/ringtones/ogg/Hydra.ogg:system/media/audio/ringtones/hydra.ogg \
- $(LOCAL_PATH)/ringtones/ogg/Iridium.ogg:system/media/audio/ringtones/Iridium.ogg \
- $(LOCAL_PATH)/ringtones/ogg/Lyra.ogg:system/media/audio/ringtones/Lyra.ogg \
- $(LOCAL_PATH)/ringtones/ogg/Machina.ogg:system/media/audio/ringtones/Machina.ogg \
- $(LOCAL_PATH)/ringtones/ogg/Orion.ogg:system/media/audio/ringtones/Orion.ogg \
- $(LOCAL_PATH)/ringtones/ogg/Pegasus.ogg:system/media/audio/ringtones/Pegasus.ogg \
- $(LOCAL_PATH)/ringtones/ogg/Perseus.ogg:system/media/audio/ringtones/Perseus.ogg \
- $(LOCAL_PATH)/ringtones/ogg/Pyxis.ogg:system/media/audio/ringtones/Pyxis.ogg \
- $(LOCAL_PATH)/ringtones/ogg/Rigel.ogg:system/media/audio/ringtones/Rigel.ogg \
- $(LOCAL_PATH)/ringtones/ogg/Scarabaeus.ogg:system/media/audio/ringtones/Scarabaeus.ogg \
$(LOCAL_PATH)/ringtones/ogg/Sceptrum.ogg:system/media/audio/ringtones/Sceptrum.ogg \
- $(LOCAL_PATH)/ringtones/ogg/Solarium.ogg:system/media/audio/ringtones/Solarium.ogg \
- $(LOCAL_PATH)/ringtones/ogg/Testudo.ogg:system/media/audio/ringtones/Testudo.ogg \
- $(LOCAL_PATH)/ringtones/ogg/UrsaMinor.ogg:system/media/audio/ringtones/UrsaMinor.ogg \
- $(LOCAL_PATH)/ringtones/ogg/Vespa.ogg:system/media/audio/ringtones/Vespa.ogg
diff --git a/data/sounds/alarms/ogg/Copernicium.ogg b/data/sounds/alarms/ogg/Copernicium.ogg
index c619e8b..65d2867 100644
--- a/data/sounds/alarms/ogg/Copernicium.ogg
+++ b/data/sounds/alarms/ogg/Copernicium.ogg
Binary files differ
diff --git a/data/sounds/alarms/ogg/Curium.ogg b/data/sounds/alarms/ogg/Curium.ogg
index ebce391..125a236 100644
--- a/data/sounds/alarms/ogg/Curium.ogg
+++ b/data/sounds/alarms/ogg/Curium.ogg
Binary files differ
diff --git a/data/sounds/alarms/ogg/Fermium.ogg b/data/sounds/alarms/ogg/Fermium.ogg
index 6132565..6940442 100644
--- a/data/sounds/alarms/ogg/Fermium.ogg
+++ b/data/sounds/alarms/ogg/Fermium.ogg
Binary files differ
diff --git a/data/sounds/alarms/ogg/Hassium.ogg b/data/sounds/alarms/ogg/Hassium.ogg
index 408b7c2..86b2b71 100644
--- a/data/sounds/alarms/ogg/Hassium.ogg
+++ b/data/sounds/alarms/ogg/Hassium.ogg
Binary files differ
diff --git a/data/sounds/alarms/ogg/Neptunium.ogg b/data/sounds/alarms/ogg/Neptunium.ogg
index 058e2db..1a99141 100644
--- a/data/sounds/alarms/ogg/Neptunium.ogg
+++ b/data/sounds/alarms/ogg/Neptunium.ogg
Binary files differ
diff --git a/data/sounds/alarms/ogg/Nobelium.ogg b/data/sounds/alarms/ogg/Nobelium.ogg
index 33878c9..4309bc6 100644
--- a/data/sounds/alarms/ogg/Nobelium.ogg
+++ b/data/sounds/alarms/ogg/Nobelium.ogg
Binary files differ
diff --git a/data/sounds/notifications/ogg/Altair.ogg b/data/sounds/notifications/ogg/Altair.ogg
old mode 100755
new mode 100644
index d84b59e..407aeb9
--- a/data/sounds/notifications/ogg/Altair.ogg
+++ b/data/sounds/notifications/ogg/Altair.ogg
Binary files differ
diff --git a/data/sounds/notifications/ogg/Antares.ogg b/data/sounds/notifications/ogg/Antares.ogg
old mode 100755
new mode 100644
index 9d60917..409c684
--- a/data/sounds/notifications/ogg/Antares.ogg
+++ b/data/sounds/notifications/ogg/Antares.ogg
Binary files differ
diff --git a/data/sounds/notifications/ogg/Betelgeuse.ogg b/data/sounds/notifications/ogg/Betelgeuse.ogg
index 83c7722..488d1e8 100644
--- a/data/sounds/notifications/ogg/Betelgeuse.ogg
+++ b/data/sounds/notifications/ogg/Betelgeuse.ogg
Binary files differ
diff --git a/data/sounds/notifications/ogg/Deneb.ogg b/data/sounds/notifications/ogg/Deneb.ogg
old mode 100755
new mode 100644
index e58b3b6..b84eae3
--- a/data/sounds/notifications/ogg/Deneb.ogg
+++ b/data/sounds/notifications/ogg/Deneb.ogg
Binary files differ
diff --git a/data/sounds/notifications/ogg/Hojus.ogg b/data/sounds/notifications/ogg/Hojus.ogg
index fc8f73f..65b780c 100644
--- a/data/sounds/notifications/ogg/Hojus.ogg
+++ b/data/sounds/notifications/ogg/Hojus.ogg
Binary files differ
diff --git a/data/sounds/notifications/ogg/Lalande.ogg b/data/sounds/notifications/ogg/Lalande.ogg
old mode 100755
new mode 100644
index b6e253a..eda9c9d
--- a/data/sounds/notifications/ogg/Lalande.ogg
+++ b/data/sounds/notifications/ogg/Lalande.ogg
Binary files differ
diff --git a/data/sounds/notifications/ogg/Mira.ogg b/data/sounds/notifications/ogg/Mira.ogg
index f21e3c4..f5a6e94 100644
--- a/data/sounds/notifications/ogg/Mira.ogg
+++ b/data/sounds/notifications/ogg/Mira.ogg
Binary files differ
diff --git a/data/sounds/notifications/ogg/Proxima.ogg b/data/sounds/notifications/ogg/Proxima.ogg
index 235b5ca..53bf899 100644
--- a/data/sounds/notifications/ogg/Proxima.ogg
+++ b/data/sounds/notifications/ogg/Proxima.ogg
Binary files differ
diff --git a/data/sounds/notifications/ogg/Upsilon.ogg b/data/sounds/notifications/ogg/Upsilon.ogg
index 036dcad..e970422 100644
--- a/data/sounds/notifications/ogg/Upsilon.ogg
+++ b/data/sounds/notifications/ogg/Upsilon.ogg
Binary files differ
diff --git a/data/sounds/ringtones/ogg/Cassiopeia.ogg b/data/sounds/ringtones/ogg/Cassiopeia.ogg
index 61c4d27..b871940 100644
--- a/data/sounds/ringtones/ogg/Cassiopeia.ogg
+++ b/data/sounds/ringtones/ogg/Cassiopeia.ogg
Binary files differ
diff --git a/data/sounds/ringtones/ogg/Lyra.ogg b/data/sounds/ringtones/ogg/Lyra.ogg
index b7f740d..d170bc0 100644
--- a/data/sounds/ringtones/ogg/Lyra.ogg
+++ b/data/sounds/ringtones/ogg/Lyra.ogg
Binary files differ
diff --git a/data/sounds/ringtones/ogg/Sceptrum.ogg b/data/sounds/ringtones/ogg/Sceptrum.ogg
index 89d64d70..e94abe0 100644
--- a/data/sounds/ringtones/ogg/Sceptrum.ogg
+++ b/data/sounds/ringtones/ogg/Sceptrum.ogg
Binary files differ
diff --git a/data/sounds/ringtones/ogg/Solarium.ogg b/data/sounds/ringtones/ogg/Solarium.ogg
index 361367a..8dac71e 100644
--- a/data/sounds/ringtones/ogg/Solarium.ogg
+++ b/data/sounds/ringtones/ogg/Solarium.ogg
Binary files differ
diff --git a/data/sounds/ringtones/ogg/UrsaMinor.ogg b/data/sounds/ringtones/ogg/UrsaMinor.ogg
index a80801d..a90d1de 100644
--- a/data/sounds/ringtones/ogg/UrsaMinor.ogg
+++ b/data/sounds/ringtones/ogg/UrsaMinor.ogg
Binary files differ
diff --git a/data/sounds/ringtones/ogg/Vespa.ogg b/data/sounds/ringtones/ogg/Vespa.ogg
index 1f75ec8..f637831 100644
--- a/data/sounds/ringtones/ogg/Vespa.ogg
+++ b/data/sounds/ringtones/ogg/Vespa.ogg
Binary files differ
diff --git a/docs/html/guide/topics/usb/index.jd b/docs/html/guide/topics/usb/index.jd
index 3e2a18b..6dc8ec5 100644
--- a/docs/html/guide/topics/usb/index.jd
+++ b/docs/html/guide/topics/usb/index.jd
@@ -6,9 +6,9 @@
<h2>Topics</h2>
<ol>
- <li><a href="{@docRoot}guide/topics/USB/accessory.jd">USB Accessory</a></li>
+ <li><a href="{@docRoot}guide/topics/usb/accessory.html">USB Accessory</a></li>
- <li><a href="{@docRoot}guide/topics/USB/host.jd">USB Host</a></li>
+ <li><a href="{@docRoot}guide/topics/usb/host.html">USB Host</a></li>
</ol>
</div>
</div>
diff --git a/docs/html/sdk/ndk/index.jd b/docs/html/sdk/ndk/index.jd
index 97df84f..f87e1f6 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 @@
}
</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 1b1fc8d..a00ca12 100644
--- a/docs/html/sdk/sdk_toc.cs
+++ b/docs/html/sdk/sdk_toc.cs
@@ -183,7 +183,7 @@
<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 cde997e..ee65223 100644
--- a/graphics/java/android/graphics/Paint.java
+++ b/graphics/java/android/graphics/Paint.java
@@ -358,22 +358,7 @@
*/
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 @@
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) {
@@ -1349,7 +1349,7 @@
if (text == null) {
throw new IllegalArgumentException("text cannot be null");
}
- if ((index | count) < 0 || index + count > text.length) {
+ if (index < 0 || text.length - index < Math.abs(count)) {
throw new ArrayIndexOutOfBoundsException();
}
@@ -1594,7 +1594,7 @@
}
/**
- * Return the glypth Ids for the characters in the string.
+ * Return the glyph Ids for the characters in the string.
*
* @param text The text to measure
* @param start The index of the first char to to measure
@@ -1613,7 +1613,7 @@
*
* Used only for BiDi / RTL Tests
*/
- public int getTextGlypths(String text, int start, int end, int contextStart, int contextEnd,
+ public int getTextGlyphs(String text, int start, int end, int contextStart, int contextEnd,
int flags, char[] glyphs) {
if (text == null) {
throw new IllegalArgumentException("text cannot be null");
diff --git a/graphics/java/android/graphics/RectF.java b/graphics/java/android/graphics/RectF.java
index 2b3aa33..00e9609 100644
--- a/graphics/java/android/graphics/RectF.java
+++ b/graphics/java/android/graphics/RectF.java
@@ -16,6 +16,8 @@
package android.graphics;
+import java.io.PrintWriter;
+
import android.os.Parcel;
import android.os.Parcelable;
import android.util.FloatMath;
@@ -81,8 +83,37 @@
return "RectF(" + left + ", " + top + ", "
+ right + ", " + bottom + ")";
}
+
+ /**
+ * Return a string representation of the rectangle in a compact form.
+ */
+ public String toShortString() {
+ return toShortString(new StringBuilder(32));
+ }
/**
+ * Return a string representation of the rectangle in a compact form.
+ * @hide
+ */
+ public String toShortString(StringBuilder sb) {
+ sb.setLength(0);
+ sb.append('['); sb.append(left); sb.append(',');
+ sb.append(top); sb.append("]["); sb.append(right);
+ sb.append(','); sb.append(bottom); sb.append(']');
+ return sb.toString();
+ }
+
+ /**
+ * Print short representation to given writer.
+ * @hide
+ */
+ public void printShortString(PrintWriter pw) {
+ pw.print('['); pw.print(left); pw.print(',');
+ pw.print(top); pw.print("]["); pw.print(right);
+ pw.print(','); pw.print(bottom); pw.print(']');
+ }
+
+ /**
* Returns true if the rectangle is empty (left >= right or top >= bottom)
*/
public final boolean isEmpty() {
diff --git a/graphics/java/android/graphics/drawable/AnimatedRotateDrawable.java b/graphics/java/android/graphics/drawable/AnimatedRotateDrawable.java
index 94a8488..7c4e147 100644
--- a/graphics/java/android/graphics/drawable/AnimatedRotateDrawable.java
+++ b/graphics/java/android/graphics/drawable/AnimatedRotateDrawable.java
@@ -55,7 +55,7 @@
private void init() {
final AnimatedRotateState state = mState;
- mIncrement = 360.0f / (float) state.mFramesCount;
+ mIncrement = 360.0f / state.mFramesCount;
final Drawable drawable = state.mDrawable;
if (drawable != null) {
drawable.setFilterBitmap(true);
@@ -65,6 +65,7 @@
}
}
+ @Override
public void draw(Canvas canvas) {
int saveCount = canvas.save();
@@ -146,14 +147,17 @@
| mState.mDrawable.getChangingConfigurations();
}
+ @Override
public void setAlpha(int alpha) {
mState.mDrawable.setAlpha(alpha);
}
+ @Override
public void setColorFilter(ColorFilter cf) {
mState.mDrawable.setColorFilter(cf);
}
+ @Override
public int getOpacity() {
return mState.mDrawable.getOpacity();
}
@@ -228,10 +232,10 @@
tv = a.peekValue(R.styleable.AnimatedRotateDrawable_pivotY);
final boolean pivotYRel = tv.type == TypedValue.TYPE_FRACTION;
final float pivotY = pivotYRel ? tv.getFraction(1.0f, 1.0f) : tv.getFloat();
-
- final int framesCount = a.getInt(R.styleable.AnimatedRotateDrawable_framesCount, 12);
- final int frameDuration = a.getInt(R.styleable.AnimatedRotateDrawable_frameDuration, 150);
-
+
+ setFramesCount(a.getInt(R.styleable.AnimatedRotateDrawable_framesCount, 12));
+ setFramesDuration(a.getInt(R.styleable.AnimatedRotateDrawable_frameDuration, 150));
+
final int res = a.getResourceId(R.styleable.AnimatedRotateDrawable_drawable, 0);
Drawable drawable = null;
if (res > 0) {
@@ -265,8 +269,6 @@
rotateState.mPivotX = pivotX;
rotateState.mPivotYRel = pivotYRel;
rotateState.mPivotY = pivotY;
- rotateState.mFramesCount = framesCount;
- rotateState.mFrameDuration = frameDuration;
init();
@@ -275,6 +277,15 @@
}
}
+ public void setFramesCount(int framesCount) {
+ mState.mFramesCount = framesCount;
+ mIncrement = 360.0f / mState.mFramesCount;
+ }
+
+ public void setFramesDuration(int framesDuration) {
+ mState.mFrameDuration = framesDuration;
+ }
+
@Override
public Drawable mutate() {
if (!mMutated && super.mutate() == this) {
diff --git a/include/camera/CameraParameters.h b/include/camera/CameraParameters.h
index 6c91dfc..4a4bcfb 100644
--- a/include/camera/CameraParameters.h
+++ b/include/camera/CameraParameters.h
@@ -495,6 +495,25 @@
// Example value: "true" or "false". Read/write.
static const char KEY_RECORDING_HINT[];
+ // Returns true if video snapshot is supported. That is, applications
+ // can call Camera.takePicture during recording. Applications do not need to
+ // call Camera.startPreview after taking a picture. The preview will be
+ // still active. Other than that, taking a picture during recording is
+ // identical to taking a picture normally. All settings and methods related
+ // to takePicture work identically. Ex: KEY_PICTURE_SIZE,
+ // KEY_SUPPORTED_PICTURE_SIZES, KEY_JPEG_QUALITY, KEY_ROTATION, and etc.
+ // The picture will have an EXIF header. FLASH_MODE_AUTO and FLASH_MODE_ON
+ // also still work, but the video will record the flash.
+ //
+ // Applications can set shutter callback as null to avoid the shutter
+ // sound. It is also recommended to set raw picture and post view callbacks
+ // to null to avoid the interrupt of preview display.
+ //
+ // Field-of-view of the recorded video may be different from that of the
+ // captured pictures.
+ // Example value: "true" or "false". Read only.
+ static const char KEY_VIDEO_SNAPSHOT_SUPPORTED[];
+
// Value for KEY_ZOOM_SUPPORTED or KEY_SMOOTH_ZOOM_SUPPORTED.
static const char TRUE[];
static const char FALSE[];
diff --git a/include/media/AudioSystem.h b/include/media/AudioSystem.h
index e0d7898..6a15f6e 100644
--- a/include/media/AudioSystem.h
+++ b/include/media/AudioSystem.h
@@ -185,6 +185,10 @@
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 @@
// 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/include/media/stagefright/SurfaceMediaSource.h b/include/media/stagefright/SurfaceMediaSource.h
index 74d54d1..d0940bb 100644
--- a/include/media/stagefright/SurfaceMediaSource.h
+++ b/include/media/stagefright/SurfaceMediaSource.h
@@ -34,7 +34,7 @@
class SurfaceMediaSource : public BnSurfaceTexture, public MediaSource,
public MediaBufferObserver {
public:
- enum { MIN_UNDEQUEUED_BUFFERS = 3 };
+ enum { MIN_UNDEQUEUED_BUFFERS = 4 };
enum {
MIN_ASYNC_BUFFER_SLOTS = MIN_UNDEQUEUED_BUFFERS + 1,
MIN_SYNC_BUFFER_SLOTS = MIN_UNDEQUEUED_BUFFERS
@@ -347,6 +347,13 @@
// encoder
int mNumFramesEncoded;
+ // mFirstFrameTimestamp is the timestamp of the first received frame.
+ // It is used to offset the output timestamps so recording starts at time 0.
+ int64_t mFirstFrameTimestamp;
+ // mStartTimeNs is the start time passed into the source at start, used to
+ // offset timestamps.
+ int64_t mStartTimeNs;
+
// mFrameAvailableCondition condition used to indicate whether there
// is a frame available for dequeuing
Condition mFrameAvailableCondition;
diff --git a/include/private/surfaceflinger/LayerState.h b/include/private/surfaceflinger/LayerState.h
index d2fed41..3eb5c99 100644
--- a/include/private/surfaceflinger/LayerState.h
+++ b/include/private/surfaceflinger/LayerState.h
@@ -54,8 +54,8 @@
};
SurfaceID surface;
uint32_t what;
- int32_t x;
- int32_t y;
+ float x;
+ float y;
uint32_t z;
uint32_t w;
uint32_t h;
diff --git a/include/surfaceflinger/SurfaceComposerClient.h b/include/surfaceflinger/SurfaceComposerClient.h
index 7fbbfb24..ace0735 100644
--- a/include/surfaceflinger/SurfaceComposerClient.h
+++ b/include/surfaceflinger/SurfaceComposerClient.h
@@ -145,7 +145,7 @@
status_t setAlpha(SurfaceID id, float alpha=1.0f);
status_t setFreezeTint(SurfaceID id, uint32_t tint);
status_t setMatrix(SurfaceID id, float dsdx, float dtdx, float dsdy, float dtdy);
- status_t setPosition(SurfaceID id, int32_t x, int32_t y);
+ status_t setPosition(SurfaceID id, float x, float y);
status_t setSize(SurfaceID id, uint32_t w, uint32_t h);
status_t destroySurface(SurfaceID sid);
diff --git a/include/utils/threads.h b/include/utils/threads.h
index c84a9b4..c685625 100644
--- a/include/utils/threads.h
+++ b/include/utils/threads.h
@@ -143,6 +143,13 @@
// in either case errno is set. Thread ID zero means current thread.
extern int androidSetThreadPriority(pid_t tid, int prio);
+// Get the current scheduling group of a particular thread. Normally returns
+// one of the ANDROID_TGROUP constants other than ANDROID_TGROUP_DEFAULT.
+// Returns ANDROID_TGROUP_DEFAULT if no pthread support (e.g. on host) or if
+// scheduling groups are disabled. Returns INVALID_OPERATION if unexpected error.
+// Thread ID zero means current thread.
+extern int androidGetThreadSchedulingGroup(pid_t tid);
+
#ifdef __cplusplus
}
#endif
diff --git a/libs/camera/CameraParameters.cpp b/libs/camera/CameraParameters.cpp
index 0eb5d50..0dcab6b 100644
--- a/libs/camera/CameraParameters.cpp
+++ b/libs/camera/CameraParameters.cpp
@@ -87,6 +87,7 @@
const char CameraParameters::KEY_MAX_NUM_DETECTED_FACES_HW[] = "max-num-detected-faces-hw";
const char CameraParameters::KEY_MAX_NUM_DETECTED_FACES_SW[] = "max-num-detected-faces-sw";
const char CameraParameters::KEY_RECORDING_HINT[] = "recording-hint";
+const char CameraParameters::KEY_VIDEO_SNAPSHOT_SUPPORTED[] = "video-snapshot-supported";
const char CameraParameters::TRUE[] = "true";
const char CameraParameters::FALSE[] = "false";
diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp
index 3b0ffea..00a4bf6 100644
--- a/libs/gui/SurfaceComposerClient.cpp
+++ b/libs/gui/SurfaceComposerClient.cpp
@@ -102,7 +102,7 @@
public:
status_t setPosition(const sp<SurfaceComposerClient>& client, SurfaceID id,
- int32_t x, int32_t y);
+ float x, float y);
status_t setSize(const sp<SurfaceComposerClient>& client, SurfaceID id,
uint32_t w, uint32_t h);
status_t setLayer(const sp<SurfaceComposerClient>& client, SurfaceID id,
@@ -161,7 +161,7 @@
}
status_t Composer::setPosition(const sp<SurfaceComposerClient>& client,
- SurfaceID id, int32_t x, int32_t y) {
+ SurfaceID id, float x, float y) {
Mutex::Autolock _l(mLock);
layer_state_t* s = getLayerStateLocked(client, id);
if (!s)
@@ -372,7 +372,7 @@
return getComposer().setFreezeTint(this, id, tint);
}
-status_t SurfaceComposerClient::setPosition(SurfaceID id, int32_t x, int32_t y) {
+status_t SurfaceComposerClient::setPosition(SurfaceID id, float x, float y) {
return getComposer().setPosition(this, id, x, y);
}
diff --git a/libs/gui/tests/Android.mk b/libs/gui/tests/Android.mk
index 0308af3..55ac133 100644
--- a/libs/gui/tests/Android.mk
+++ b/libs/gui/tests/Android.mk
@@ -1,4 +1,4 @@
-# Build the unit tests.
+# Build the unit tests,
LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS)
@@ -22,17 +22,15 @@
libui \
libutils \
-LOCAL_STATIC_LIBRARIES := \
- libgtest \
- libgtest_main \
-
LOCAL_C_INCLUDES := \
bionic \
bionic/libstdc++/include \
external/gtest/include \
external/stlport/stlport \
-include $(BUILD_EXECUTABLE)
+# Build the binary to $(TARGET_OUT_DATA_NATIVE_TESTS)/$(LOCAL_MODULE)
+# to integrate with auto-test framework.
+include $(BUILD_NATIVE_TEST)
# Include subdirectory makefiles
# ============================================================
diff --git a/libs/hwui/FontRenderer.cpp b/libs/hwui/FontRenderer.cpp
index 9acf99b..dd05e61 100644
--- a/libs/hwui/FontRenderer.cpp
+++ b/libs/hwui/FontRenderer.cpp
@@ -394,14 +394,14 @@
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/libs/rs/driver/rsdBcc.cpp b/libs/rs/driver/rsdBcc.cpp
index 44ea79c..0755fb7 100644
--- a/libs/rs/driver/rsdBcc.cpp
+++ b/libs/rs/driver/rsdBcc.cpp
@@ -37,6 +37,7 @@
struct DrvScript {
int (*mRoot)();
void (*mInit)();
+ void (*mFreeChildren)();
BCCScriptRef mBccScript;
@@ -125,6 +126,7 @@
drv->mRoot = reinterpret_cast<int (*)()>(bccGetFuncAddr(drv->mBccScript, "root"));
drv->mInit = reinterpret_cast<void (*)()>(bccGetFuncAddr(drv->mBccScript, "init"));
+ drv->mFreeChildren = reinterpret_cast<void (*)()>(bccGetFuncAddr(drv->mBccScript, ".rs.dtor"));
exportFuncCount = drv->ME->getExportFuncCount();
if (exportFuncCount > 0) {
@@ -430,6 +432,13 @@
}
}
+void rsdScriptInvokeFreeChildren(const Context *dc, Script *script) {
+ DrvScript *drv = (DrvScript *)script->mHal.drv;
+
+ if (drv->mFreeChildren) {
+ drv->mFreeChildren();
+ }
+}
void rsdScriptInvokeFunction(const Context *dc, Script *script,
uint32_t slot,
diff --git a/libs/rs/driver/rsdBcc.h b/libs/rs/driver/rsdBcc.h
index 67929bc..5f83ed2 100644
--- a/libs/rs/driver/rsdBcc.h
+++ b/libs/rs/driver/rsdBcc.h
@@ -43,6 +43,8 @@
android::renderscript::Script *script);
void rsdScriptInvokeInit(const android::renderscript::Context *dc,
android::renderscript::Script *script);
+void rsdScriptInvokeFreeChildren(const android::renderscript::Context *dc,
+ android::renderscript::Script *script);
void rsdScriptSetGlobalVar(const android::renderscript::Context *,
const android::renderscript::Script *,
diff --git a/libs/rs/driver/rsdCore.cpp b/libs/rs/driver/rsdCore.cpp
index 171d045..a38fff77 100644
--- a/libs/rs/driver/rsdCore.cpp
+++ b/libs/rs/driver/rsdCore.cpp
@@ -60,6 +60,7 @@
rsdScriptInvokeRoot,
rsdScriptInvokeForEach,
rsdScriptInvokeInit,
+ rsdScriptInvokeFreeChildren,
rsdScriptSetGlobalVar,
rsdScriptSetGlobalBind,
rsdScriptSetGlobalObj,
diff --git a/libs/rs/rsScript.cpp b/libs/rs/rsScript.cpp
index f62c72e..93513fe 100644
--- a/libs/rs/rsScript.cpp
+++ b/libs/rs/rsScript.cpp
@@ -72,6 +72,12 @@
mRSC->mHal.funcs.script.setGlobalObj(mRSC, this, slot, val);
}
+bool Script::freeChildren() {
+ incSysRef();
+ mRSC->mHal.funcs.script.invokeFreeChildren(mRSC, this);
+ return decSysRef();
+}
+
namespace android {
namespace renderscript {
diff --git a/libs/rs/rsScript.h b/libs/rs/rsScript.h
index c0324dd..d645421 100644
--- a/libs/rs/rsScript.h
+++ b/libs/rs/rsScript.h
@@ -73,6 +73,8 @@
void setVar(uint32_t slot, const void *val, size_t len);
void setVarObj(uint32_t slot, ObjectBase *val);
+ virtual bool freeChildren();
+
virtual void runForEach(Context *rsc,
const Allocation * ain,
Allocation * aout,
diff --git a/libs/rs/rs_hal.h b/libs/rs/rs_hal.h
index 21dff218..b8d7351 100644
--- a/libs/rs/rs_hal.h
+++ b/libs/rs/rs_hal.h
@@ -90,6 +90,7 @@
uint32_t usrLen,
const RsScriptCall *sc);
void (*invokeInit)(const Context *rsc, Script *s);
+ void (*invokeFreeChildren)(const Context *rsc, Script *s);
void (*setGlobalVar)(const Context *rsc, const Script *s,
uint32_t slot,
diff --git a/libs/rs/scriptc/rs_cl.rsh b/libs/rs/scriptc/rs_cl.rsh
index e402b86..bbc8fc5 100644
--- a/libs/rs/scriptc/rs_cl.rsh
+++ b/libs/rs/scriptc/rs_cl.rsh
@@ -15,7 +15,7 @@
*/
/** @file rs_cl.rsh
- * \brief Additional compute routines
+ * \brief Basic math functions
*
*
*/
@@ -111,225 +111,555 @@
fnc(float4 v1, float4 v2, int4 *v3);
+/**
+ * Return the inverse cosine.
+ *
+ * Supports float, float2, float3, float4
+ */
extern float __attribute__((overloadable)) acos(float);
FN_FUNC_FN(acos)
+/**
+ * Return the inverse hyperbolic cosine.
+ *
+ * Supports float, float2, float3, float4
+ */
extern float __attribute__((overloadable)) acosh(float);
FN_FUNC_FN(acosh)
+/**
+ * Return the inverse cosine divided by PI.
+ *
+ * Supports float, float2, float3, float4
+ */
_RS_RUNTIME float __attribute__((overloadable)) acospi(float v);
-
-
FN_FUNC_FN(acospi)
+/**
+ * Return the inverse sine.
+ *
+ * Supports float, float2, float3, float4
+ */
extern float __attribute__((overloadable)) asin(float);
FN_FUNC_FN(asin)
+/**
+ * Return the inverse hyperbolic sine.
+ *
+ * Supports float, float2, float3, float4
+ */
extern float __attribute__((overloadable)) asinh(float);
FN_FUNC_FN(asinh)
+/**
+ * Return the inverse sine divided by PI.
+ *
+ * Supports float, float2, float3, float4
+ */
_RS_RUNTIME float __attribute__((overloadable)) asinpi(float v);
FN_FUNC_FN(asinpi)
+/**
+ * Return the inverse tangent.
+ *
+ * Supports float, float2, float3, float4
+ */
extern float __attribute__((overloadable)) atan(float);
FN_FUNC_FN(atan)
-extern float __attribute__((overloadable)) atan2(float, float);
+/**
+ * Return the inverse tangent of y / x.
+ *
+ * Supports float, float2, float3, float4. Both arguments must be of the same
+ * type.
+ *
+ * @param y
+ * @param x
+ */
+extern float __attribute__((overloadable)) atan2(float y, float x);
FN_FUNC_FN_FN(atan2)
+/**
+ * Return the inverse hyperbolic tangent.
+ *
+ * Supports float, float2, float3, float4
+ */
extern float __attribute__((overloadable)) atanh(float);
FN_FUNC_FN(atanh)
-
+/**
+ * Return the inverse tangent divided by PI.
+ *
+ * Supports float, float2, float3, float4
+ */
_RS_RUNTIME float __attribute__((overloadable)) atanpi(float v);
FN_FUNC_FN(atanpi)
-
+/**
+ * Return the inverse tangent of y / x, divided by PI.
+ *
+ * Supports float, float2, float3, float4. Both arguments must be of the same
+ * type.
+ *
+ * @param y
+ * @param x
+ */
_RS_RUNTIME float __attribute__((overloadable)) atan2pi(float y, float x);
FN_FUNC_FN_FN(atan2pi)
+
+/**
+ * Return the cube root.
+ *
+ * Supports float, float2, float3, float4.
+ */
extern float __attribute__((overloadable)) cbrt(float);
FN_FUNC_FN(cbrt)
+/**
+ * Return the smallest integer not less than a value.
+ *
+ * Supports float, float2, float3, float4.
+ */
extern float __attribute__((overloadable)) ceil(float);
FN_FUNC_FN(ceil)
-extern float __attribute__((overloadable)) copysign(float, float);
+/**
+ * Copy the sign bit from y to x.
+ *
+ * Supports float, float2, float3, float4. Both arguments must be of the same
+ * type.
+ *
+ * @param x
+ * @param y
+ */
+extern float __attribute__((overloadable)) copysign(float x, float y);
FN_FUNC_FN_FN(copysign)
+/**
+ * Return the cosine.
+ *
+ * Supports float, float2, float3, float4.
+ */
extern float __attribute__((overloadable)) cos(float);
FN_FUNC_FN(cos)
+/**
+ * Return the hypebolic cosine.
+ *
+ * Supports float, float2, float3, float4.
+ */
extern float __attribute__((overloadable)) cosh(float);
FN_FUNC_FN(cosh)
-
+/**
+ * Return the cosine of the value * PI.
+ *
+ * Supports float, float2, float3, float4.
+ */
_RS_RUNTIME float __attribute__((overloadable)) cospi(float v);
FN_FUNC_FN(cospi)
+/**
+ * Return the complementary error function.
+ *
+ * Supports float, float2, float3, float4.
+ */
extern float __attribute__((overloadable)) erfc(float);
FN_FUNC_FN(erfc)
+/**
+ * Return the error function.
+ *
+ * Supports float, float2, float3, float4.
+ */
extern float __attribute__((overloadable)) erf(float);
FN_FUNC_FN(erf)
+/**
+ * Return e ^ value.
+ *
+ * Supports float, float2, float3, float4.
+ */
extern float __attribute__((overloadable)) exp(float);
FN_FUNC_FN(exp)
+/**
+ * Return 2 ^ value.
+ *
+ * Supports float, float2, float3, float4.
+ */
extern float __attribute__((overloadable)) exp2(float);
FN_FUNC_FN(exp2)
-extern float __attribute__((overloadable)) pow(float, float);
+/**
+ * Return x ^ y.
+ *
+ * Supports float, float2, float3, float4. Both arguments must be of the same
+ * type.
+ */
+extern float __attribute__((overloadable)) pow(float x, float y);
+FN_FUNC_FN_FN(pow)
+/**
+ * Return 10 ^ value.
+ *
+ * Supports float, float2, float3, float4.
+ */
_RS_RUNTIME float __attribute__((overloadable)) exp10(float v);
FN_FUNC_FN(exp10)
+/**
+ * Return (e ^ value) - 1.
+ *
+ * Supports float, float2, float3, float4.
+ */
extern float __attribute__((overloadable)) expm1(float);
FN_FUNC_FN(expm1)
+/**
+ * Return the absolute value of a value.
+ *
+ * Supports float, float2, float3, float4.
+ */
extern float __attribute__((overloadable)) fabs(float);
FN_FUNC_FN(fabs)
+/**
+ * Return the positive difference between two values.
+ *
+ * Supports float, float2, float3, float4. Both arguments must be of the same
+ * type.
+ */
extern float __attribute__((overloadable)) fdim(float, float);
FN_FUNC_FN_FN(fdim)
+/**
+ * Return the smallest integer not greater than a value.
+ *
+ * Supports float, float2, float3, float4.
+ */
extern float __attribute__((overloadable)) floor(float);
FN_FUNC_FN(floor)
-extern float __attribute__((overloadable)) fma(float, float, float);
+/**
+ * Return a*b + c.
+ *
+ * Supports float, float2, float3, float4.
+ */
+extern float __attribute__((overloadable)) fma(float a, float b, float c);
FN_FUNC_FN_FN_FN(fma)
-extern float __attribute__((overloadable)) fmax(float, float);
+/**
+ * Return (x < y ? y : x)
+ *
+ * Supports float, float2, float3, float4.
+ * @param x: may be float, float2, float3, float4
+ * @param y: may be float or vector. If vector must match type of x.
+ */
+extern float __attribute__((overloadable)) fmax(float x, float y);
FN_FUNC_FN_FN(fmax);
FN_FUNC_FN_F(fmax);
-extern float __attribute__((overloadable)) fmin(float, float);
+/**
+ * Return (x > y ? y : x)
+ *
+ * @param x: may be float, float2, float3, float4
+ * @param y: may be float or vector. If vector must match type of x.
+ */
+extern float __attribute__((overloadable)) fmin(float x, float y);
FN_FUNC_FN_FN(fmin);
FN_FUNC_FN_F(fmin);
-extern float __attribute__((overloadable)) fmod(float, float);
+/**
+ * Return the remainder from x / y
+ *
+ * Supports float, float2, float3, float4.
+ */
+extern float __attribute__((overloadable)) fmod(float x, float y);
FN_FUNC_FN_FN(fmod)
+/**
+ * Return fractional part of v
+ *
+ * @param iptr iptr[0] will be set to the floor of the input value.
+ * Supports float, float2, float3, float4.
+ */
_RS_RUNTIME float __attribute__((overloadable)) fract(float v, float *iptr);
FN_FUNC_FN_PFN(fract)
-extern float __attribute__((overloadable)) frexp(float, int *);
+/**
+ * Return the mantissa and place the exponent into iptr[0]
+ *
+ * @param v Supports float, float2, float3, float4.
+ * @param iptr Must have the same vector size as v.
+ */
+extern float __attribute__((overloadable)) frexp(float v, int *iptr);
FN_FUNC_FN_PIN(frexp)
-extern float __attribute__((overloadable)) hypot(float, float);
+/**
+ * Return sqrt(x*x + y*y)
+ *
+ * Supports float, float2, float3, float4.
+ */
+extern float __attribute__((overloadable)) hypot(float x, float y);
FN_FUNC_FN_FN(hypot)
+/**
+ * Return the integer exponent of a value
+ *
+ * Supports 1,2,3,4 components
+ */
extern int __attribute__((overloadable)) ilogb(float);
IN_FUNC_FN(ilogb)
-extern float __attribute__((overloadable)) ldexp(float, int);
+/**
+ * Return (x * 2^y)
+ *
+ * @param x Supports 1,2,3,4 components
+ * @param y Supports single component or matching vector.
+ */
+extern float __attribute__((overloadable)) ldexp(float x, int y);
FN_FUNC_FN_IN(ldexp)
FN_FUNC_FN_I(ldexp)
+/**
+ * Return the log gamma
+ *
+ * Supports 1,2,3,4 components
+ */
extern float __attribute__((overloadable)) lgamma(float);
FN_FUNC_FN(lgamma)
-extern float __attribute__((overloadable)) lgamma(float, int*);
+
+/**
+ * Return the log gamma and sign
+ *
+ * @param x Supports 1,2,3,4 components
+ * @param y Supports matching vector.
+ */
+extern float __attribute__((overloadable)) lgamma(float x, int* y);
FN_FUNC_FN_PIN(lgamma)
+/**
+ * Return the natural logarithm
+ *
+ * Supports 1,2,3,4 components
+ */
extern float __attribute__((overloadable)) log(float);
FN_FUNC_FN(log)
-
+/**
+ * Return the base 10 logarithm
+ *
+ * Supports 1,2,3,4 components
+ */
extern float __attribute__((overloadable)) log10(float);
FN_FUNC_FN(log10)
-
+/**
+ * Return the base 2 logarithm
+ *
+ * Supports 1,2,3,4 components
+ */
_RS_RUNTIME float __attribute__((overloadable)) log2(float v);
FN_FUNC_FN(log2)
-extern float __attribute__((overloadable)) log1p(float);
+/**
+ * Return the natural logarithm of (v + 1.0f)
+ *
+ * Supports 1,2,3,4 components
+ */
+extern float __attribute__((overloadable)) log1p(float v);
FN_FUNC_FN(log1p)
+/**
+ * Compute the exponent of the value.
+ *
+ * Supports 1,2,3,4 components
+ */
extern float __attribute__((overloadable)) logb(float);
FN_FUNC_FN(logb)
-extern float __attribute__((overloadable)) mad(float, float, float);
+/**
+ * Compute (a * b) + c
+ *
+ * Supports 1,2,3,4 components
+ */
+extern float __attribute__((overloadable)) mad(float a, float b, float c);
FN_FUNC_FN_FN_FN(mad)
-extern float __attribute__((overloadable)) modf(float, float *);
+/**
+ * Return the integral and fractional components of a number
+ * Supports 1,2,3,4 components
+ *
+ * @param x Source value
+ * @param iret iret[0] will be set to the integral portion of the number.
+ * @return The floating point portion of the value.
+ */
+extern float __attribute__((overloadable)) modf(float x, float *iret);
FN_FUNC_FN_PFN(modf);
//extern float __attribute__((overloadable)) nan(uint);
-extern float __attribute__((overloadable)) nextafter(float, float);
+/**
+ * Return the next floating point number from x towards y.
+ *
+ * Supports 1,2,3,4 components
+ */
+extern float __attribute__((overloadable)) nextafter(float x, float y);
FN_FUNC_FN_FN(nextafter)
-FN_FUNC_FN_FN(pow)
-
+/**
+ * Return (v ^ p).
+ *
+ * Supports 1,2,3,4 components
+ */
_RS_RUNTIME float __attribute__((overloadable)) pown(float v, int p);
-_RS_RUNTIME float2 __attribute__((overloadable)) pown(float2 v, int2 p);
-_RS_RUNTIME float3 __attribute__((overloadable)) pown(float3 v, int3 p);
-_RS_RUNTIME float4 __attribute__((overloadable)) pown(float4 v, int4 p);
+FN_FUNC_FN_IN(pown)
+/**
+ * Return (v ^ p).
+ * @param v must be greater than 0.
+ *
+ * Supports 1,2,3,4 components
+ */
_RS_RUNTIME float __attribute__((overloadable)) powr(float v, float p);
-_RS_RUNTIME float2 __attribute__((overloadable)) powr(float2 v, float2 p);
-_RS_RUNTIME float3 __attribute__((overloadable)) powr(float3 v, float3 p);
-_RS_RUNTIME float4 __attribute__((overloadable)) powr(float4 v, float4 p);
+FN_FUNC_FN_FN(powr)
-extern float __attribute__((overloadable)) remainder(float, float);
+/**
+ * Return round x/y to the nearest integer then compute the remander.
+ *
+ * Supports 1,2,3,4 components
+ */
+extern float __attribute__((overloadable)) remainder(float x, float y);
FN_FUNC_FN_FN(remainder)
+// document once we know the precision of bionic
extern float __attribute__((overloadable)) remquo(float, float, int *);
FN_FUNC_FN_FN_PIN(remquo)
+/**
+ * Round to the nearest integral value.
+ *
+ * Supports 1,2,3,4 components
+ */
extern float __attribute__((overloadable)) rint(float);
FN_FUNC_FN(rint)
+/**
+ * Compute the Nth root of a value.
+ *
+ * Supports 1,2,3,4 components
+ */
+_RS_RUNTIME float __attribute__((overloadable)) rootn(float v, int n);
+FN_FUNC_FN_IN(rootn)
-_RS_RUNTIME float __attribute__((overloadable)) rootn(float v, int r);
-_RS_RUNTIME float2 __attribute__((overloadable)) rootn(float2 v, int2 r);
-_RS_RUNTIME float3 __attribute__((overloadable)) rootn(float3 v, int3 r);
-_RS_RUNTIME float4 __attribute__((overloadable)) rootn(float4 v, int4 r);
-
-
+/**
+ * Round to the nearest integral value. Half values are rounded away from zero.
+ *
+ * Supports 1,2,3,4 components
+ */
extern float __attribute__((overloadable)) round(float);
FN_FUNC_FN(round)
-
+/**
+ * Return the square root of a value.
+ *
+ * Supports 1,2,3,4 components
+ */
extern float __attribute__((overloadable)) sqrt(float);
+FN_FUNC_FN(sqrt)
+
+/**
+ * Return (1 / sqrt(value)).
+ *
+ * @param v The incoming value in radians
+ * Supports 1,2,3,4 components
+ */
_RS_RUNTIME float __attribute__((overloadable)) rsqrt(float v);
FN_FUNC_FN(rsqrt)
-extern float __attribute__((overloadable)) sin(float);
+/**
+ * Return the sine of a value specified in radians.
+ *
+ * @param v The incoming value in radians
+ * Supports 1,2,3,4 components
+ */
+extern float __attribute__((overloadable)) sin(float v);
FN_FUNC_FN(sin)
+/**
+ * Return the sine and cosine of a value.
+ *
+ * @return sine
+ * @param v The incoming value in radians
+ * @param *cosptr cosptr[0] will be set to the cosine value.
+ *
+ * Supports 1,2,3,4 components
+ */
_RS_RUNTIME float __attribute__((overloadable)) sincos(float v, float *cosptr);
-_RS_RUNTIME float2 __attribute__((overloadable)) sincos(float2 v, float2 *cosptr);
-_RS_RUNTIME float3 __attribute__((overloadable)) sincos(float3 v, float3 *cosptr);
-_RS_RUNTIME float4 __attribute__((overloadable)) sincos(float4 v, float4 *cosptr);
+FN_FUNC_FN_PFN(sincos);
+/**
+ * Return the hyperbolic sine of a value specified in radians.
+ *
+ * Supports 1,2,3,4 components
+ */
extern float __attribute__((overloadable)) sinh(float);
FN_FUNC_FN(sinh)
+/**
+ * Return the sin(v * PI).
+ *
+ * Supports 1,2,3,4 components
+ */
_RS_RUNTIME float __attribute__((overloadable)) sinpi(float v);
FN_FUNC_FN(sinpi)
-FN_FUNC_FN(sqrt)
-
-extern float __attribute__((overloadable)) tan(float);
+/**
+ * Return the tangent of a value.
+ *
+ * Supports 1,2,3,4 components
+ * @param v The incoming value in radians
+ */
+extern float __attribute__((overloadable)) tan(float v);
FN_FUNC_FN(tan)
+/**
+ * Return the hyperbolic tangent of a value.
+ *
+ * Supports 1,2,3,4 components
+ * @param v The incoming value in radians
+ */
extern float __attribute__((overloadable)) tanh(float);
FN_FUNC_FN(tanh)
+/**
+ * Return tan(v * PI)
+ *
+ * Supports 1,2,3,4 components
+ */
_RS_RUNTIME float __attribute__((overloadable)) tanpi(float v);
FN_FUNC_FN(tanpi)
-
+/**
+ * Compute the gamma function of a value.
+ *
+ * Supports 1,2,3,4 components
+ */
extern float __attribute__((overloadable)) tgamma(float);
FN_FUNC_FN(tgamma)
+/**
+ * Round to integral using truncation.
+ *
+ * Supports 1,2,3,4 components
+ */
extern float __attribute__((overloadable)) trunc(float);
FN_FUNC_FN(trunc)
-// Int ops (partial), 6.11.3
#define XN_FUNC_YN(typeout, fnc, typein) \
extern typeout __attribute__((overloadable)) fnc(typein); \
@@ -373,14 +703,29 @@
UIN_FUNC_IN(abs)
IN_FUNC_IN(clz)
+/**
+ * Return the minimum of two values.
+ *
+ * Supports 1,2,3,4 components of uchar, char, ushort, short, uint, int, float.
+ */
IN_FUNC_IN_IN_BODY(min, (v1 < v2 ? v1 : v2))
FN_FUNC_FN_F(min)
+/**
+ * Return the maximum of two values.
+ *
+ * Supports 1,2,3,4 components of uchar, char, ushort, short, uint, int, float.
+ */
IN_FUNC_IN_IN_BODY(max, (v1 > v2 ? v1 : v2))
FN_FUNC_FN_F(max)
-// 6.11.4
-
+/**
+ * Clamp a value to a specified high and low bound.
+ *
+ * @param amount value to be clamped. Supports 1,2,3,4 components
+ * @param low Lower bound, must be scalar or matching vector.
+ * @param high High bound, must match type of low
+ */
_RS_RUNTIME float __attribute__((overloadable)) clamp(float amount, float low, float high);
_RS_RUNTIME float2 __attribute__((overloadable)) clamp(float2 amount, float2 low, float2 high);
_RS_RUNTIME float3 __attribute__((overloadable)) clamp(float3 amount, float3 low, float3 high);
@@ -389,9 +734,19 @@
_RS_RUNTIME float3 __attribute__((overloadable)) clamp(float3 amount, float low, float high);
_RS_RUNTIME float4 __attribute__((overloadable)) clamp(float4 amount, float low, float high);
+/**
+ * Convert from radians to degrees.
+ *
+ * Supports 1,2,3,4 components
+ */
_RS_RUNTIME float __attribute__((overloadable)) degrees(float radians);
FN_FUNC_FN(degrees)
+/**
+ * return start + ((stop - start) * amount);
+ *
+ * Supports 1,2,3,4 components
+ */
_RS_RUNTIME float __attribute__((overloadable)) mix(float start, float stop, float amount);
_RS_RUNTIME float2 __attribute__((overloadable)) mix(float2 start, float2 stop, float2 amount);
_RS_RUNTIME float3 __attribute__((overloadable)) mix(float3 start, float3 stop, float3 amount);
@@ -400,9 +755,22 @@
_RS_RUNTIME float3 __attribute__((overloadable)) mix(float3 start, float3 stop, float amount);
_RS_RUNTIME float4 __attribute__((overloadable)) mix(float4 start, float4 stop, float amount);
+/**
+ * Convert from degrees to radians.
+ *
+ * Supports 1,2,3,4 components
+ */
_RS_RUNTIME float __attribute__((overloadable)) radians(float degrees);
FN_FUNC_FN(radians)
+/**
+ * if (v < edge)
+ * return 0.f;
+ * else
+ * return 1.f;
+ *
+ * Supports 1,2,3,4 components
+ */
_RS_RUNTIME float __attribute__((overloadable)) step(float edge, float v);
_RS_RUNTIME float2 __attribute__((overloadable)) step(float2 edge, float2 v);
_RS_RUNTIME float3 __attribute__((overloadable)) step(float3 edge, float3 v);
@@ -411,6 +779,7 @@
_RS_RUNTIME float3 __attribute__((overloadable)) step(float3 edge, float v);
_RS_RUNTIME float4 __attribute__((overloadable)) step(float4 edge, float v);
+// not implemented
extern float __attribute__((overloadable)) smoothstep(float, float, float);
extern float2 __attribute__((overloadable)) smoothstep(float2, float2, float2);
extern float3 __attribute__((overloadable)) smoothstep(float3, float3, float3);
@@ -419,29 +788,59 @@
extern float3 __attribute__((overloadable)) smoothstep(float, float, float3);
extern float4 __attribute__((overloadable)) smoothstep(float, float, float4);
+/**
+ * if (v < 0) return -1.f;
+ * else if (v > 0) return 1.f;
+ * else return 0.f;
+ *
+ * Supports 1,2,3,4 components
+ */
_RS_RUNTIME float __attribute__((overloadable)) sign(float v);
FN_FUNC_FN(sign)
-// 6.11.5
+/**
+ * Compute the cross product of two vectors.
+ *
+ * Supports 3,4 components
+ */
_RS_RUNTIME float3 __attribute__((overloadable)) cross(float3 lhs, float3 rhs);
-
_RS_RUNTIME float4 __attribute__((overloadable)) cross(float4 lhs, float4 rhs);
+/**
+ * Compute the dot product of two vectors.
+ *
+ * Supports 1,2,3,4 components
+ */
_RS_RUNTIME float __attribute__((overloadable)) dot(float lhs, float rhs);
_RS_RUNTIME float __attribute__((overloadable)) dot(float2 lhs, float2 rhs);
_RS_RUNTIME float __attribute__((overloadable)) dot(float3 lhs, float3 rhs);
_RS_RUNTIME float __attribute__((overloadable)) dot(float4 lhs, float4 rhs);
+/**
+ * Compute the length of a vector.
+ *
+ * Supports 1,2,3,4 components
+ */
_RS_RUNTIME float __attribute__((overloadable)) length(float v);
_RS_RUNTIME float __attribute__((overloadable)) length(float2 v);
_RS_RUNTIME float __attribute__((overloadable)) length(float3 v);
_RS_RUNTIME float __attribute__((overloadable)) length(float4 v);
+/**
+ * Compute the distance between two points.
+ *
+ * Supports 1,2,3,4 components
+ */
_RS_RUNTIME float __attribute__((overloadable)) distance(float lhs, float rhs);
_RS_RUNTIME float __attribute__((overloadable)) distance(float2 lhs, float2 rhs);
_RS_RUNTIME float __attribute__((overloadable)) distance(float3 lhs, float3 rhs);
_RS_RUNTIME float __attribute__((overloadable)) distance(float4 lhs, float4 rhs);
+/**
+ * Normalize a vector.
+ *
+ * Supports 1,2,3,4 components
+ */
_RS_RUNTIME float __attribute__((overloadable)) normalize(float v);
_RS_RUNTIME float2 __attribute__((overloadable)) normalize(float2 v);
_RS_RUNTIME float3 __attribute__((overloadable)) normalize(float3 v);
diff --git a/libs/rs/scriptc/rs_quaternion.rsh b/libs/rs/scriptc/rs_quaternion.rsh
index 36e6736..23945ae 100644
--- a/libs/rs/scriptc/rs_quaternion.rsh
+++ b/libs/rs/scriptc/rs_quaternion.rsh
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-/** @file rs_matrix.rsh
+/** @file rs_quaternion.rsh
* \brief Quaternion routines
*
*
diff --git a/libs/rs/scriptc/rs_time.rsh b/libs/rs/scriptc/rs_time.rsh
index f8f297d..60e3dee 100644
--- a/libs/rs/scriptc/rs_time.rsh
+++ b/libs/rs/scriptc/rs_time.rsh
@@ -15,43 +15,96 @@
*/
/** @file rs_time.rsh
- * \brief Time routines
+ * \brief Renderscript time routines
*
- *
+ * This file contains Renderscript functions relating to time and date
+ * manipulation.
*/
#ifndef __RS_TIME_RSH__
#define __RS_TIME_RSH__
+/**
+ * Calendar time interpreted as seconds elapsed since the Epoch (00:00:00 on
+ * January 1, 1970, Coordinated Universal Time (UTC)).
+ */
typedef int rs_time_t;
+/**
+ * Data structure for broken-down time components.
+ *
+ * tm_sec - Seconds after the minute. This ranges from 0 to 59, but possibly
+ * up to 60 for leap seconds.
+ * tm_min - Minutes after the hour. This ranges from 0 to 59.
+ * tm_hour - Hours past midnight. This ranges from 0 to 23.
+ * tm_mday - Day of the month. This ranges from 1 to 31.
+ * tm_mon - Months since January. This ranges from 0 to 11.
+ * tm_year - Years since 1900.
+ * tm_wday - Days since Sunday. This ranges from 0 to 6.
+ * tm_yday - Days since January 1. This ranges from 0 to 365.
+ * tm_isdst - Flag to indicate whether daylight saving time is in effect. The
+ * value is positive if it is in effect, zero if it is not, and
+ * negative if the information is not available.
+ */
typedef struct {
- int tm_sec;
- int tm_min;
- int tm_hour;
- int tm_mday;
- int tm_mon;
- int tm_year;
- int tm_wday;
- int tm_yday;
- int tm_isdst;
+ int tm_sec; ///< seconds
+ int tm_min; ///< minutes
+ int tm_hour; ///< hours
+ int tm_mday; ///< day of the month
+ int tm_mon; ///< month
+ int tm_year; ///< year
+ int tm_wday; ///< day of the week
+ int tm_yday; ///< day of the year
+ int tm_isdst; ///< daylight savings time
} rs_tm;
+/**
+ * Returns the number of seconds since the Epoch (00:00:00 UTC, January 1,
+ * 1970). If @p timer is non-NULL, the result is also stored in the memory
+ * pointed to by this variable. If an error occurs, a value of -1 is returned.
+ *
+ * @param timer Location to also store the returned calendar time.
+ *
+ * @return Seconds since the Epoch.
+ */
extern rs_time_t __attribute__((overloadable))
rsTime(rs_time_t *timer);
+/**
+ * Converts the time specified by @p timer into broken-down time and stores it
+ * in @p local. This function also returns a pointer to @p local. If @p local
+ * is NULL, this function does nothing and returns NULL.
+ *
+ * @param local Broken-down time.
+ * @param timer Input time as calendar time.
+ *
+ * @return Pointer to broken-down time (same as input @p local).
+ */
extern rs_tm * __attribute__((overloadable))
rsLocaltime(rs_tm *local, const rs_time_t *timer);
-// Return the current system clock in milliseconds
+/**
+ * Returns the current system clock (uptime) in milliseconds.
+ *
+ * @return Uptime in milliseconds.
+ */
extern int64_t __attribute__((overloadable))
rsUptimeMillis(void);
-// Return the current system clock in nanoseconds
+/**
+ * Returns the current system clock (uptime) in nanoseconds.
+ *
+ * @return Uptime in nanoseconds.
+ */
extern int64_t __attribute__((overloadable))
rsUptimeNanos(void);
-// Return the time in seconds since function was last called in this script.
+/**
+ * Returns the time in seconds since this function was last called in this
+ * script.
+ *
+ * @return Time in seconds.
+ */
extern float __attribute__((overloadable))
rsGetDt(void);
diff --git a/libs/rs/scriptc/rs_types.rsh b/libs/rs/scriptc/rs_types.rsh
index 875beb9..5d5df60 100644
--- a/libs/rs/scriptc/rs_types.rsh
+++ b/libs/rs/scriptc/rs_types.rsh
@@ -89,7 +89,7 @@
*/
typedef uint32_t uint;
/**
- * Typedef for unsigned char (use for 64-bit unsigned integers)
+ * Typedef for unsigned long (use for 64-bit unsigned integers)
*/
typedef uint64_t ulong;
/**
@@ -102,67 +102,67 @@
typedef int32_t ssize_t;
/**
- * \brief Opaque handle to a RenderScript element.
+ * \brief Opaque handle to a Renderscript element.
*
* See: android.renderscript.Element
*/
typedef struct { const int* const p; } __attribute__((packed, aligned(4))) rs_element;
/**
- * \brief Opaque handle to a RenderScript type.
+ * \brief Opaque handle to a Renderscript type.
*
* See: android.renderscript.Type
*/
typedef struct { const int* const p; } __attribute__((packed, aligned(4))) rs_type;
/**
- * \brief Opaque handle to a RenderScript allocation.
+ * \brief Opaque handle to a Renderscript allocation.
*
* See: android.renderscript.Allocation
*/
typedef struct { const int* const p; } __attribute__((packed, aligned(4))) rs_allocation;
/**
- * \brief Opaque handle to a RenderScript sampler object.
+ * \brief Opaque handle to a Renderscript sampler object.
*
* See: android.renderscript.Sampler
*/
typedef struct { const int* const p; } __attribute__((packed, aligned(4))) rs_sampler;
/**
- * \brief Opaque handle to a RenderScript script object.
+ * \brief Opaque handle to a Renderscript script object.
*
* See: android.renderscript.ScriptC
*/
typedef struct { const int* const p; } __attribute__((packed, aligned(4))) rs_script;
/**
- * \brief Opaque handle to a RenderScript mesh object.
+ * \brief Opaque handle to a Renderscript mesh object.
*
* See: android.renderscript.Mesh
*/
typedef struct { const int* const p; } __attribute__((packed, aligned(4))) rs_mesh;
/**
- * \brief Opaque handle to a RenderScript ProgramFragment object.
+ * \brief Opaque handle to a Renderscript ProgramFragment object.
*
* See: android.renderscript.ProgramFragment
*/
typedef struct { const int* const p; } __attribute__((packed, aligned(4))) rs_program_fragment;
/**
- * \brief Opaque handle to a RenderScript ProgramVertex object.
+ * \brief Opaque handle to a Renderscript ProgramVertex object.
*
* See: android.renderscript.ProgramVertex
*/
typedef struct { const int* const p; } __attribute__((packed, aligned(4))) rs_program_vertex;
/**
- * \brief Opaque handle to a RenderScript sampler object.
+ * \brief Opaque handle to a Renderscript ProgramRaster object.
*
- * See: android.renderscript.Sampler
+ * See: android.renderscript.ProgramRaster
*/
typedef struct { const int* const p; } __attribute__((packed, aligned(4))) rs_program_raster;
/**
- * \brief Opaque handle to a RenderScript ProgramStore object.
+ * \brief Opaque handle to a Renderscript ProgramStore object.
*
* See: android.renderscript.ProgramStore
*/
typedef struct { const int* const p; } __attribute__((packed, aligned(4))) rs_program_store;
/**
- * \brief Opaque handle to a RenderScript font object.
+ * \brief Opaque handle to a Renderscript font object.
*
* See: android.renderscript.Font
*/
@@ -170,163 +170,163 @@
/**
* Vector version of the basic float type.
- * Provides two float fields packed into a single 64bit field with 64 bit
+ * Provides two float fields packed into a single 64 bit field with 64 bit
* alignment.
*/
typedef float float2 __attribute__((ext_vector_type(2)));
/**
* Vector version of the basic float type. Provides three float fields packed
- * into a single 128bit field with 128 bit alignment.
+ * into a single 128 bit field with 128 bit alignment.
*/
typedef float float3 __attribute__((ext_vector_type(3)));
/**
* Vector version of the basic float type.
- * Provides four float fields packed into a single 128bit field with 128bit
+ * Provides four float fields packed into a single 128 bit field with 128 bit
* alignment.
*/
typedef float float4 __attribute__((ext_vector_type(4)));
/**
* Vector version of the basic double type. Provides two double fields packed
- * into a single 128bit field with 128bit alignment.
+ * into a single 128 bit field with 128 bit alignment.
*/
typedef double double2 __attribute__((ext_vector_type(2)));
/**
* Vector version of the basic double type. Provides three double fields packed
- * into a single 256bit field with 256bit alignment.
+ * into a single 256 bit field with 256 bit alignment.
*/
typedef double double3 __attribute__((ext_vector_type(3)));
/**
* Vector version of the basic double type. Provides four double fields packed
- * into a single 256bit field with 256bit alignment.
+ * into a single 256 bit field with 256 bit alignment.
*/
typedef double double4 __attribute__((ext_vector_type(4)));
/**
* Vector version of the basic uchar type. Provides two uchar fields packed
- * into a single 16bit field with 16bit alignment.
+ * into a single 16 bit field with 16 bit alignment.
*/
typedef uchar uchar2 __attribute__((ext_vector_type(2)));
/**
* Vector version of the basic uchar type. Provides three uchar fields packed
- * into a single 32bit field with 32bit alignment.
+ * into a single 32 bit field with 32 bit alignment.
*/
typedef uchar uchar3 __attribute__((ext_vector_type(3)));
/**
* Vector version of the basic uchar type. Provides four uchar fields packed
- * into a single 32bit field with 32bit alignment.
+ * into a single 32 bit field with 32 bit alignment.
*/
typedef uchar uchar4 __attribute__((ext_vector_type(4)));
/**
* Vector version of the basic ushort type. Provides two ushort fields packed
- * into a single 32bit field with 32bit alignment.
+ * into a single 32 bit field with 32 bit alignment.
*/
typedef ushort ushort2 __attribute__((ext_vector_type(2)));
/**
* Vector version of the basic ushort type. Provides three ushort fields packed
- * into a single 64bit field with 64bit alignment.
+ * into a single 64 bit field with 64 bit alignment.
*/
typedef ushort ushort3 __attribute__((ext_vector_type(3)));
/**
* Vector version of the basic ushort type. Provides four ushort fields packed
- * into a single 64bit field with 64bit alignment.
+ * into a single 64 bit field with 64 bit alignment.
*/
typedef ushort ushort4 __attribute__((ext_vector_type(4)));
/**
* Vector version of the basic uint type. Provides two uint fields packed into a
- * single 64bit field with 64bit alignment.
+ * single 64 bit field with 64 bit alignment.
*/
typedef uint uint2 __attribute__((ext_vector_type(2)));
/**
* Vector version of the basic uint type. Provides three uint fields packed into
- * a single 128bit field with 128bit alignment.
+ * a single 128 bit field with 128 bit alignment.
*/
typedef uint uint3 __attribute__((ext_vector_type(3)));
/**
* Vector version of the basic uint type. Provides four uint fields packed into
- * a single 128bit field with 128bit alignment.
+ * a single 128 bit field with 128 bit alignment.
*/
typedef uint uint4 __attribute__((ext_vector_type(4)));
/**
* Vector version of the basic ulong type. Provides two ulong fields packed into
- * a single 128bit field with 128bit alignment.
+ * a single 128 bit field with 128 bit alignment.
*/
typedef ulong ulong2 __attribute__((ext_vector_type(2)));
/**
* Vector version of the basic ulong type. Provides three ulong fields packed
- * into a single 256bit field with 256bit alignment.
+ * into a single 256 bit field with 256 bit alignment.
*/
typedef ulong ulong3 __attribute__((ext_vector_type(3)));
/**
* Vector version of the basic ulong type. Provides four ulong fields packed
- * into a single 256bit field with 256bit alignment.
+ * into a single 256 bit field with 256 bit alignment.
*/
typedef ulong ulong4 __attribute__((ext_vector_type(4)));
/**
* Vector version of the basic char type. Provides two char fields packed into a
- * single 16bit field with 16bit alignment.
+ * single 16 bit field with 16 bit alignment.
*/
typedef char char2 __attribute__((ext_vector_type(2)));
/**
* Vector version of the basic char type. Provides three char fields packed into
- * a single 32bit field with 32bit alignment.
+ * a single 32 bit field with 32 bit alignment.
*/
typedef char char3 __attribute__((ext_vector_type(3)));
/**
* Vector version of the basic char type. Provides four char fields packed into
- * a single 32bit field with 32bit alignment.
+ * a single 32 bit field with 32 bit alignment.
*/
typedef char char4 __attribute__((ext_vector_type(4)));
/**
* Vector version of the basic short type. Provides two short fields packed into
- * a single 32bit field with 32bit alignment.
+ * a single 32 bit field with 32 bit alignment.
*/
typedef short short2 __attribute__((ext_vector_type(2)));
/**
* Vector version of the basic short type. Provides three short fields packed
- * into a single 64bit field with 64bit alignment.
+ * into a single 64 bit field with 64 bit alignment.
*/
typedef short short3 __attribute__((ext_vector_type(3)));
/**
* Vector version of the basic short type. Provides four short fields packed
- * into a single 64bit field with 64bit alignment.
+ * into a single 64 bit field with 64 bit alignment.
*/
typedef short short4 __attribute__((ext_vector_type(4)));
/**
* Vector version of the basic int type. Provides two int fields packed into a
- * single 64bit field with 64bit alignment.
+ * single 64 bit field with 64 bit alignment.
*/
typedef int int2 __attribute__((ext_vector_type(2)));
/**
* Vector version of the basic int type. Provides three int fields packed into a
- * single 128bit field with 128bit alignment.
+ * single 128 bit field with 128 bit alignment.
*/
typedef int int3 __attribute__((ext_vector_type(3)));
/**
* Vector version of the basic int type. Provides two four fields packed into a
- * single 128bit field with 128bit alignment.
+ * single 128 bit field with 128 bit alignment.
*/
typedef int int4 __attribute__((ext_vector_type(4)));
/**
* Vector version of the basic long type. Provides two long fields packed into a
- * single 128bit field with 128bit alignment.
+ * single 128 bit field with 128 bit alignment.
*/
typedef long long2 __attribute__((ext_vector_type(2)));
/**
* Vector version of the basic long type. Provides three long fields packed into
- * a single 256bit field with 256bit alignment.
+ * a single 256 bit field with 256 bit alignment.
*/
typedef long long3 __attribute__((ext_vector_type(3)));
/**
* Vector version of the basic long type. Provides four long fields packed into
- * a single 256bit field with 256bit alignment.
+ * a single 256 bit field with 256 bit alignment.
*/
typedef long long4 __attribute__((ext_vector_type(4)));
@@ -369,8 +369,6 @@
/**
* \brief Enum for selecting cube map faces
- *
- * Used todo-alexst
*/
typedef enum {
RS_ALLOCATION_CUBEMAP_FACE_POSITIVE_X = 0,
diff --git a/libs/utils/Threads.cpp b/libs/utils/Threads.cpp
index d18c0a2..02c380b 100644
--- a/libs/utils/Threads.cpp
+++ b/libs/utils/Threads.cpp
@@ -368,6 +368,41 @@
return rc;
}
+int androidGetThreadSchedulingGroup(pid_t tid)
+{
+ int ret = ANDROID_TGROUP_DEFAULT;
+
+#if defined(HAVE_PTHREADS)
+ // convention is to not call get/set_sched_policy methods if disabled by property
+ pthread_once(&gDoSchedulingGroupOnce, checkDoSchedulingGroup);
+ if (gDoSchedulingGroup) {
+ SchedPolicy policy;
+ // get_sched_policy does not support tid == 0
+ if (tid == 0) {
+ tid = androidGetTid();
+ }
+ if (get_sched_policy(tid, &policy) < 0) {
+ ret = INVALID_OPERATION;
+ } else {
+ switch (policy) {
+ case SP_BACKGROUND:
+ ret = ANDROID_TGROUP_BG_NONINTERACT;
+ break;
+ case SP_FOREGROUND:
+ ret = ANDROID_TGROUP_FG_BOOST;
+ break;
+ default:
+ // should not happen, as enum SchedPolicy does not have any other values
+ ret = INVALID_OPERATION;
+ break;
+ }
+ }
+ }
+#endif
+
+ return ret;
+}
+
namespace android {
/*
diff --git a/media/java/android/media/AudioService.java b/media/java/android/media/AudioService.java
index dbe4115..cd15718 100644
--- a/media/java/android/media/AudioService.java
+++ b/media/java/android/media/AudioService.java
@@ -1558,21 +1558,29 @@
private boolean checkForRingerModeChange(int oldIndex, int direction) {
boolean adjustVolumeIndex = true;
int newRingerMode = mRingerMode;
+ int uiIndex = (oldIndex + 5) / 10;
if (mRingerMode == AudioManager.RINGER_MODE_NORMAL) {
- // audible mode, at the bottom of the scale
- if ((direction == AudioManager.ADJUST_LOWER &&
- mPrevVolDirection != AudioManager.ADJUST_LOWER) &&
- ((oldIndex + 5) / 10 == 0)) {
- // "silent mode", but which one?
- newRingerMode = System.getInt(mContentResolver, System.VIBRATE_IN_SILENT, 1) == 1
- ? AudioManager.RINGER_MODE_VIBRATE
- : AudioManager.RINGER_MODE_SILENT;
+ if ((direction == AudioManager.ADJUST_LOWER) && (uiIndex <= 1)) {
+ // enter silent mode if current index is the last audible one and not repeating a
+ // volume key down
+ if (mPrevVolDirection != AudioManager.ADJUST_LOWER) {
+ // "silent mode", but which one?
+ newRingerMode = System.getInt(mContentResolver, System.VIBRATE_IN_SILENT, 1) == 1
+ ? AudioManager.RINGER_MODE_VIBRATE
+ : AudioManager.RINGER_MODE_SILENT;
+ }
+ if (uiIndex == 0) {
+ adjustVolumeIndex = false;
+ }
}
} else {
if (direction == AudioManager.ADJUST_RAISE) {
// exiting silent mode
newRingerMode = AudioManager.RINGER_MODE_NORMAL;
+ if (uiIndex != 0) {
+ adjustVolumeIndex = false;
+ }
} else {
// prevent last audible index to reach 0
adjustVolumeIndex = false;
@@ -1581,13 +1589,6 @@
if (newRingerMode != mRingerMode) {
setRingerMode(newRingerMode);
-
- /*
- * If we are changing ringer modes, do not increment/decrement the
- * volume index. Instead, the handler for the message above will
- * take care of changing the index.
- */
- adjustVolumeIndex = false;
}
mPrevVolDirection = direction;
@@ -2637,7 +2638,7 @@
notifyTopOfAudioFocusStack();
// there's a new top of the stack, let the remote control know
synchronized(mRCStack) {
- checkUpdateRemoteControlDisplay(RC_INFO_ALL);
+ checkUpdateRemoteControlDisplay_syncAfRcs(RC_INFO_ALL);
}
}
} else {
@@ -2680,7 +2681,7 @@
notifyTopOfAudioFocusStack();
// there's a new top of the stack, let the remote control know
synchronized(mRCStack) {
- checkUpdateRemoteControlDisplay(RC_INFO_ALL);
+ checkUpdateRemoteControlDisplay_syncAfRcs(RC_INFO_ALL);
}
}
}
@@ -2784,7 +2785,7 @@
// there's a new top of the stack, let the remote control know
synchronized(mRCStack) {
- checkUpdateRemoteControlDisplay(RC_INFO_ALL);
+ checkUpdateRemoteControlDisplay_syncAfRcs(RC_INFO_ALL);
}
}//synchronized(mAudioFocusLock)
@@ -3182,7 +3183,7 @@
* Helper function:
* Called synchronized on mRCStack
*/
- private void clearRemoteControlDisplay() {
+ private void clearRemoteControlDisplay_syncAfRcs() {
synchronized(mCurrentRcLock) {
mCurrentRcClient = null;
}
@@ -3191,18 +3192,21 @@
}
/**
- * Helper function:
- * Called synchronized on mRCStack
- * mRCStack.empty() is false
+ * Helper function for code readability: only to be called from
+ * checkUpdateRemoteControlDisplay_syncAfRcs() which checks the preconditions for
+ * this method.
+ * Preconditions:
+ * - called synchronized mAudioFocusLock then on mRCStack
+ * - mRCStack.isEmpty() is false
*/
- private void updateRemoteControlDisplay(int infoChangedFlags) {
+ private void updateRemoteControlDisplay_syncAfRcs(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_syncAfRcs();
return;
}
synchronized(mCurrentRcLock) {
@@ -3219,17 +3223,17 @@
/**
* Helper function:
- * Called synchronized on mFocusLock, then mRCStack
+ * Called synchronized on mAudioFocusLock, then mRCStack
* Check whether the remote control display should be updated, triggers the update if required
* @param infoChangedFlags the flags corresponding to the remote control client information
* 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_syncAfRcs(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_syncAfRcs();
return;
}
// if the top of the two stacks belong to different packages, there is a mismatch, clear
@@ -3237,17 +3241,18 @@
&& (mFocusStack.peek().mPackageName != null)
&& !(mRCStack.peek().mCallingPackageName.compareTo(
mFocusStack.peek().mPackageName) == 0)) {
- clearRemoteControlDisplay();
+ clearRemoteControlDisplay_syncAfRcs();
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_syncAfRcs();
return;
}
// refresh conditions were verified: update the remote controls
- updateRemoteControlDisplay(infoChangedFlags);
+ // ok to call: synchronized mAudioFocusLock then on mRCStack, mRCStack is not empty
+ updateRemoteControlDisplay_syncAfRcs(infoChangedFlags);
}
/** see AudioManager.registerMediaButtonEventReceiver(ComponentName eventReceiver) */
@@ -3258,7 +3263,7 @@
synchronized(mRCStack) {
pushMediaButtonReceiver(eventReceiver);
// new RC client, assume every type of information shall be queried
- checkUpdateRemoteControlDisplay(RC_INFO_ALL);
+ checkUpdateRemoteControlDisplay_syncAfRcs(RC_INFO_ALL);
}
}
}
@@ -3273,7 +3278,7 @@
removeMediaButtonReceiver(eventReceiver);
if (topOfStackWillChange) {
// current RC client will change, assume every type of info needs to be queried
- checkUpdateRemoteControlDisplay(RC_INFO_ALL);
+ checkUpdateRemoteControlDisplay_syncAfRcs(RC_INFO_ALL);
}
}
}
@@ -3282,6 +3287,7 @@
/** see AudioManager.registerRemoteControlClient(ComponentName eventReceiver, ...) */
public void registerRemoteControlClient(ComponentName eventReceiver,
IRemoteControlClient rcClient, String clientName, String callingPackageName) {
+ if (DEBUG_RC) Log.i(TAG, "Register remote control client rcClient="+rcClient);
synchronized(mAudioFocusLock) {
synchronized(mRCStack) {
// store the new display information
@@ -3329,7 +3335,7 @@
// 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_syncAfRcs(RC_INFO_ALL);
}
}
}
@@ -3426,51 +3432,43 @@
}
/**
- * 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.
*/
public void registerRemoteControlDisplay(IRemoteControlDisplay rcd) {
if (DEBUG_RC) Log.d(TAG, ">>> registerRemoteControlDisplay("+rcd+")");
- synchronized(mRCStack) {
- if ((mRcDisplay == rcd) || (rcd == null)) {
- return;
- }
- // if we had a display before, stop monitoring its death
- rcDisplay_stopDeathMonitor_syncRcStack();
- mRcDisplay = rcd;
- // new display, start monitoring its death
- rcDisplay_startDeathMonitor_syncRcStack();
+ synchronized(mAudioFocusLock) {
+ synchronized(mRCStack) {
+ if ((mRcDisplay == rcd) || (rcd == null)) {
+ return;
+ }
+ // if we had a display before, stop monitoring its death
+ rcDisplay_stopDeathMonitor_syncRcStack();
+ mRcDisplay = rcd;
+ // new display, start monitoring its death
+ rcDisplay_startDeathMonitor_syncRcStack();
- // let all the remote control clients there is a new display
- // no need to unplug the previous because we only support one display
- // and the clients don't track the death of the display
- Iterator<RemoteControlStackEntry> stackIterator = mRCStack.iterator();
- while(stackIterator.hasNext()) {
- RemoteControlStackEntry rcse = stackIterator.next();
- if(rcse.mRcClient != null) {
- try {
- rcse.mRcClient.plugRemoteControlDisplay(mRcDisplay);
- } catch (RemoteException e) {
- Log.e(TAG, "Error connecting remote control display to client: " + e);
- e.printStackTrace();
+ // let all the remote control clients there is a new display
+ // no need to unplug the previous because we only support one display
+ // and the clients don't track the death of the display
+ Iterator<RemoteControlStackEntry> stackIterator = mRCStack.iterator();
+ while(stackIterator.hasNext()) {
+ RemoteControlStackEntry rcse = stackIterator.next();
+ if(rcse.mRcClient != null) {
+ try {
+ rcse.mRcClient.plugRemoteControlDisplay(mRcDisplay);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Error connecting remote control display to client: " + e);
+ e.printStackTrace();
+ }
}
}
- }
- // 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
+ checkUpdateRemoteControlDisplay_syncAfRcs(RC_INFO_ALL);
}
}
}
diff --git a/media/java/android/media/MediaPlayer.java b/media/java/android/media/MediaPlayer.java
index 66bd56a..1ee9a1f 100644
--- a/media/java/android/media/MediaPlayer.java
+++ b/media/java/android/media/MediaPlayer.java
@@ -381,7 +381,7 @@
* <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 @@
* 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 @@
/**
* 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/RemoteControlClient.java b/media/java/android/media/RemoteControlClient.java
index d59bc2b..d7b85e4 100644
--- a/media/java/android/media/RemoteControlClient.java
+++ b/media/java/android/media/RemoteControlClient.java
@@ -22,6 +22,7 @@
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.RectF;
+import android.media.MediaMetadataRetriever;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
@@ -29,6 +30,7 @@
import android.os.RemoteException;
import android.util.Log;
+import java.lang.IllegalArgumentException;
import java.util.HashMap;
/**
@@ -236,6 +238,23 @@
mEventHandler = new EventHandler(this, looper);
}
+ private static final int[] METADATA_KEYS_TYPE_STRING = {
+ MediaMetadataRetriever.METADATA_KEY_ALBUM,
+ MediaMetadataRetriever.METADATA_KEY_ALBUMARTIST,
+ MediaMetadataRetriever.METADATA_KEY_TITLE,
+ MediaMetadataRetriever.METADATA_KEY_ARTIST,
+ MediaMetadataRetriever.METADATA_KEY_AUTHOR,
+ MediaMetadataRetriever.METADATA_KEY_COMPILATION,
+ MediaMetadataRetriever.METADATA_KEY_COMPOSER,
+ MediaMetadataRetriever.METADATA_KEY_DATE,
+ MediaMetadataRetriever.METADATA_KEY_GENRE,
+ MediaMetadataRetriever.METADATA_KEY_TITLE,
+ MediaMetadataRetriever.METADATA_KEY_WRITER };
+ private static final int[] METADATA_KEYS_TYPE_LONG = {
+ MediaMetadataRetriever.METADATA_KEY_CD_TRACK_NUMBER,
+ MediaMetadataRetriever.METADATA_KEY_DISC_NUMBER,
+ MediaMetadataRetriever.METADATA_KEY_DURATION };
+
/**
* Class used to modify metadata in a {@link RemoteControlClient} object.
*/
@@ -256,6 +275,11 @@
}
/**
+ * The metadata key for the content artwork / album art.
+ */
+ public final static int METADATA_KEY_ARTWORK = 100;
+
+ /**
* Adds textual information to be displayed.
* Note that none of the information added after {@link #apply()} has been called,
* will be displayed.
@@ -265,49 +289,73 @@
* {@link android.media.MediaMetadataRetriever#METADATA_KEY_TITLE},
* {@link android.media.MediaMetadataRetriever#METADATA_KEY_ARTIST},
* {@link android.media.MediaMetadataRetriever#METADATA_KEY_AUTHOR},
- * {@link android.media.MediaMetadataRetriever#METADATA_KEY_CD_TRACK_NUMBER},
* {@link android.media.MediaMetadataRetriever#METADATA_KEY_COMPILATION},
* {@link android.media.MediaMetadataRetriever#METADATA_KEY_COMPOSER},
* {@link android.media.MediaMetadataRetriever#METADATA_KEY_DATE},
- * {@link android.media.MediaMetadataRetriever#METADATA_KEY_DISC_NUMBER},
- * {@link android.media.MediaMetadataRetriever#METADATA_KEY_DURATION},
* {@link android.media.MediaMetadataRetriever#METADATA_KEY_GENRE},
* {@link android.media.MediaMetadataRetriever#METADATA_KEY_TITLE},
* {@link android.media.MediaMetadataRetriever#METADATA_KEY_WRITER},
- * {@link android.media.MediaMetadataRetriever#METADATA_KEY_YEAR}.
- * @param value the text for the given key, or null to signify there is no valid
+ * .
+ * @param value the text for the given key, or {@code null} to signify there is no valid
* information for the field.
* @return FIXME description
*/
- public synchronized MetadataEditor putString(int key, String value) {
+ public synchronized MetadataEditor putString(int key, String value)
+ throws IllegalArgumentException {
if (mApplied) {
Log.e(TAG, "Can't edit a previously applied MetadataEditor");
return this;
}
+ if (!validTypeForKey(key, METADATA_KEYS_TYPE_STRING)) {
+ throw(new IllegalArgumentException("Invalid type 'String' for key "+ key));
+ }
mEditorMetadata.putString(String.valueOf(key), value);
mMetadataChanged = true;
return this;
}
/**
- * The metadata key for the content artwork / album art.
+ * FIXME javadoc
+ * @param key the identifier of a the metadata field to set. Valid values are
+ * {@link android.media.MediaMetadataRetriever#METADATA_KEY_CD_TRACK_NUMBER},
+ * {@link android.media.MediaMetadataRetriever#METADATA_KEY_DISC_NUMBER},
+ * {@link android.media.MediaMetadataRetriever#METADATA_KEY_DURATION} (with a value
+ * expressed in milliseconds),
+ * {@link android.media.MediaMetadataRetriever#METADATA_KEY_YEAR}.
+ * @param value FIXME javadoc
+ * @return FIXME javadoc
+ * @throws IllegalArgumentException
*/
- public final int METADATA_KEY_ARTWORK = 100;
+ public synchronized MetadataEditor putLong(int key, long value)
+ throws IllegalArgumentException {
+ if (mApplied) {
+ Log.e(TAG, "Can't edit a previously applied MetadataEditor");
+ return this;
+ }
+ if (!validTypeForKey(key, METADATA_KEYS_TYPE_LONG)) {
+ throw(new IllegalArgumentException("Invalid type 'long' for key "+ key));
+ }
+ mEditorMetadata.putLong(String.valueOf(key), value);
+ mMetadataChanged = true;
+ return this;
+ }
/**
* Sets the album / artwork picture to be displayed on the remote control.
* @param key FIXME description
* @param bitmap the bitmap for the artwork, or null if there isn't any.
* @return FIXME description
+ * @throws IllegalArgumentException
* @see android.graphics.Bitmap
*/
- public synchronized MetadataEditor putBitmap(int key, Bitmap bitmap) {
+ public synchronized MetadataEditor putBitmap(int key, Bitmap bitmap)
+ throws IllegalArgumentException {
if (mApplied) {
Log.e(TAG, "Can't edit a previously applied MetadataEditor");
return this;
}
if (key != METADATA_KEY_ARTWORK) {
- return this;
+ throw(new IllegalArgumentException("Invalid type 'Bitmap' for key "+ key));
}
if ((mArtworkExpectedWidth > 0) && (mArtworkExpectedHeight > 0)) {
mEditorArtwork = scaleBitmapIfTooBig(bitmap,
@@ -740,6 +788,24 @@
}
}
return bitmap;
+ }
+ /**
+ * Fast routine to go through an array of allowed keys and return whether the key is part
+ * of that array
+ * @param key the key value
+ * @param validKeys the array of valid keys for a given type
+ * @return true if the key is part of the array, false otherwise
+ */
+ private static boolean validTypeForKey(int key, int[] validKeys) {
+ try {
+ for (int i = 0 ; ; i++) {
+ if (key == validKeys[i]) {
+ return true;
+ }
+ }
+ } catch (ArrayIndexOutOfBoundsException e) {
+ return false;
+ }
}
}
diff --git a/media/java/android/media/videoeditor/MediaArtistNativeHelper.java b/media/java/android/media/videoeditor/MediaArtistNativeHelper.java
index b7d129d..2b4e85f 100644
--- a/media/java/android/media/videoeditor/MediaArtistNativeHelper.java
+++ b/media/java/android/media/videoeditor/MediaArtistNativeHelper.java
@@ -29,6 +29,7 @@
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Rect;
+import android.graphics.Matrix;
import android.media.videoeditor.VideoEditor.ExportProgressListener;
import android.media.videoeditor.VideoEditor.PreviewProgressListener;
import android.media.videoeditor.VideoEditor.MediaProcessingProgressListener;
@@ -1050,6 +1051,10 @@
*/
public int rgbWidth;
public int rgbHeight;
+ /**
+ * Video rotation degree.
+ */
+ public int rotationDegree;
}
/**
@@ -1700,6 +1705,11 @@
*/
public int audioVolumeValue;
+ /**
+ * Video rotation degree.
+ */
+ public int videoRotation;
+
public String Id;
}
@@ -2254,6 +2264,7 @@
lclipSettings.panZoomTopLeftXEnd = 0;
lclipSettings.panZoomTopLeftYEnd = 0;
lclipSettings.mediaRendering = 0;
+ lclipSettings.rotationDegree = 0;
}
@@ -3784,7 +3795,8 @@
**/
void getPixelsList(String filename, final int width, final int height,
long startMs, long endMs, int thumbnailCount, int[] indices,
- final MediaItem.GetThumbnailListCallback callback) {
+ final MediaItem.GetThumbnailListCallback callback,
+ final int videoRotation) {
/* Make width and height as even */
final int newWidth = (width + 1) & 0xFFFFFFFE;
final int newHeight = (height + 1) & 0xFFFFFFFE;
@@ -3799,7 +3811,7 @@
final int[] rgb888 = new int[thumbnailSize];
final IntBuffer tmpBuffer = IntBuffer.allocate(thumbnailSize);
nativeGetPixelsList(filename, rgb888, newWidth, newHeight,
- thumbnailCount, startMs, endMs, indices,
+ thumbnailCount, videoRotation, startMs, endMs, indices,
new NativeGetPixelsListCallback() {
public void onThumbnail(int index) {
Bitmap bitmap = Bitmap.createBitmap(
@@ -3821,7 +3833,21 @@
canvas.setBitmap(null);
}
- callback.onThumbnail(bitmap, index);
+
+ if (videoRotation == 0) {
+ callback.onThumbnail(bitmap, index);
+ } else {
+ Matrix mtx = new Matrix();
+ mtx.postRotate(videoRotation);
+ Bitmap rotatedBmp =
+ Bitmap.createBitmap(bitmap, 0, 0, width, height, mtx, false);
+ callback.onThumbnail(rotatedBmp, index);
+
+ if (bitmap != null) {
+ bitmap.recycle();
+ }
+ }
+
}
});
@@ -3943,8 +3969,8 @@
long timeMS);
private native int nativeGetPixelsList(String fileName, int[] pixelArray,
- int width, int height, int nosofTN, long startTimeMs, long endTimeMs,
- int[] indices, NativeGetPixelsListCallback callback);
+ int width, int height, int nosofTN, int videoRotation, long startTimeMs,
+ long endTimeMs, int[] indices, NativeGetPixelsListCallback callback);
/**
* Releases the JNI and cleans up the core native module.. Should be called
diff --git a/media/java/android/media/videoeditor/MediaImageItem.java b/media/java/android/media/videoeditor/MediaImageItem.java
index b2a279a..65a9e19 100755
--- a/media/java/android/media/videoeditor/MediaImageItem.java
+++ b/media/java/android/media/videoeditor/MediaImageItem.java
@@ -638,7 +638,7 @@
}
mMANativeHelper.getPixelsList(getGeneratedImageClip(), width,
- height, startMs, endMs, thumbnailCount, indices, callback);
+ height, startMs, endMs, thumbnailCount, indices, callback, 0);
}
}
diff --git a/media/java/android/media/videoeditor/MediaVideoItem.java b/media/java/android/media/videoeditor/MediaVideoItem.java
index fea751b..2ce857c 100755
--- a/media/java/android/media/videoeditor/MediaVideoItem.java
+++ b/media/java/android/media/videoeditor/MediaVideoItem.java
@@ -57,6 +57,7 @@
private String mAudioWaveformFilename;
private MediaArtistNativeHelper mMANativeHelper;
private VideoEditorImpl mVideoEditor;
+ private final int mVideoRotationDegree;
/**
* The audio waveform data
*/
@@ -190,6 +191,7 @@
} else {
mWaveformData = null;
}
+ mVideoRotationDegree = properties.videoRotation;
}
/**
@@ -317,7 +319,8 @@
}
mMANativeHelper.getPixelsList(super.getFilename(), width,
- height, startMs, endMs, thumbnailCount, indices, callback);
+ height, startMs, endMs, thumbnailCount, indices, callback,
+ mVideoRotationDegree);
}
/*
@@ -425,7 +428,12 @@
*/
@Override
public int getWidth() {
- return mWidth;
+ if (mVideoRotationDegree == 90 ||
+ mVideoRotationDegree == 270) {
+ return mHeight;
+ } else {
+ return mWidth;
+ }
}
/*
@@ -433,7 +441,12 @@
*/
@Override
public int getHeight() {
- return mHeight;
+ if (mVideoRotationDegree == 90 ||
+ mVideoRotationDegree == 270) {
+ return mWidth;
+ } else {
+ return mHeight;
+ }
}
/*
@@ -725,6 +738,7 @@
clipSettings.beginCutTime = (int)getBoundaryBeginTime();
clipSettings.endCutTime = (int)getBoundaryEndTime();
clipSettings.mediaRendering = mMANativeHelper.getMediaItemRenderingMode(getRenderingMode());
+ clipSettings.rotationDegree = mVideoRotationDegree;
return clipSettings;
}
diff --git a/media/java/android/media/videoeditor/VideoEditorProfile.java b/media/java/android/media/videoeditor/VideoEditorProfile.java
index ecdcdfb..202a2df 100755
--- a/media/java/android/media/videoeditor/VideoEditorProfile.java
+++ b/media/java/android/media/videoeditor/VideoEditorProfile.java
@@ -91,7 +91,7 @@
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/jni/mediaeditor/VideoEditorClasses.cpp b/media/jni/mediaeditor/VideoEditorClasses.cpp
index 69735ca..4e0e0f2 100755
--- a/media/jni/mediaeditor/VideoEditorClasses.cpp
+++ b/media/jni/mediaeditor/VideoEditorClasses.cpp
@@ -490,7 +490,8 @@
VIDEOEDIT_JAVA_FIELD_INIT("audioDuration", "I"),
VIDEOEDIT_JAVA_FIELD_INIT("audioBitrate", "I"),
VIDEOEDIT_JAVA_FIELD_INIT("audioChannels", "I"),
- VIDEOEDIT_JAVA_FIELD_INIT("audioSamplingFrequency", "I")
+ VIDEOEDIT_JAVA_FIELD_INIT("audioSamplingFrequency", "I"),
+ VIDEOEDIT_JAVA_FIELD_INIT("videoRotation", "I")
};
VIDEOEDIT_JAVA_DEFINE_FIELD_CLASS(Properties, PROPERTIES_CLASS_NAME)
@@ -540,7 +541,8 @@
VIDEOEDIT_JAVA_FIELD_INIT("panZoomTopLeftYEnd", "I" ),
VIDEOEDIT_JAVA_FIELD_INIT("mediaRendering", "I" ),
VIDEOEDIT_JAVA_FIELD_INIT("rgbWidth", "I" ),
- VIDEOEDIT_JAVA_FIELD_INIT("rgbHeight", "I" )
+ VIDEOEDIT_JAVA_FIELD_INIT("rgbHeight", "I" ),
+ VIDEOEDIT_JAVA_FIELD_INIT("rotationDegree", "I" )
};
VIDEOEDIT_JAVA_DEFINE_FIELD_CLASS(ClipSettings, CLIP_SETTINGS_CLASS_NAME)
@@ -1402,6 +1404,10 @@
VIDEOEDIT_LOG_FUNCTION(ANDROID_LOG_INFO, "VIDEO_EDITOR", \
"getClipSettings-- rgbFileHeight %d ",
pSettings->ClipProperties.uiStillPicHeight);
+
+ // Set the video rotation degree
+ pSettings->ClipProperties.videoRotationDegrees =
+ (M4OSA_UInt32)pEnv->GetIntField(object, fieldIds.rotationDegree);
}
// Check if settings could be set.
@@ -1513,6 +1519,10 @@
pSettings->ClipProperties.uiStillPicWidth ,
pSettings->ClipProperties.uiStillPicHeight);
+ // Set the video rotation
+ pEnv->SetIntField(object, fieldIds.rotationDegree,
+ pSettings->ClipProperties.videoRotationDegrees);
+
// Return the object.
(*pObject) = object;
}
@@ -1609,6 +1619,9 @@
pEnv->SetIntField(object, fieldIds.audioSamplingFrequency,
pProperties->uiSamplingFrequency);
+ // Set the video rotation field.
+ pEnv->SetIntField(object, fieldIds.videoRotation, pProperties->uiRotation);
+
// Return the object.
(*pObject) = object;
}
diff --git a/media/jni/mediaeditor/VideoEditorClasses.h b/media/jni/mediaeditor/VideoEditorClasses.h
index 3c10b1d..a4c82a8 100755
--- a/media/jni/mediaeditor/VideoEditorClasses.h
+++ b/media/jni/mediaeditor/VideoEditorClasses.h
@@ -145,6 +145,7 @@
M4OSA_UInt32 uiAudioBitrate;
M4OSA_UInt32 uiNbChannels;
M4OSA_UInt32 uiSamplingFrequency;
+ M4OSA_UInt32 uiRotation;
} VideoEditPropClass_Properties;
typedef struct
@@ -166,6 +167,7 @@
jfieldID audioBitrate;
jfieldID audioChannels;
jfieldID audioSamplingFrequency;
+ jfieldID videoRotation;
} VideoEditJava_PropertiesFieldIds;
@@ -187,6 +189,7 @@
jfieldID mediaRendering;
jfieldID rgbFileWidth;
jfieldID rgbFileHeight;
+ jfieldID rotationDegree;
} VideoEditJava_ClipSettingsFieldIds;
typedef struct
diff --git a/media/jni/mediaeditor/VideoEditorMain.cpp b/media/jni/mediaeditor/VideoEditorMain.cpp
index b737e5d..4e73581 100755
--- a/media/jni/mediaeditor/VideoEditorMain.cpp
+++ b/media/jni/mediaeditor/VideoEditorMain.cpp
@@ -185,6 +185,7 @@
M4OSA_UInt32 width,
M4OSA_UInt32 height,
M4OSA_UInt32 noOfThumbnails,
+ M4OSA_UInt32 videoRotation,
jlong startTime,
jlong endTime,
jintArray indexArray,
@@ -291,7 +292,7 @@
(void *)videoEditor_release },
{"nativeGetPixels", "(Ljava/lang/String;[IIIJ)I",
(void*)videoEditor_getPixels },
- {"nativeGetPixelsList", "(Ljava/lang/String;[IIIIJJ[ILandroid/media/videoeditor/MediaArtistNativeHelper$NativeGetPixelsListCallback;)I",
+ {"nativeGetPixelsList", "(Ljava/lang/String;[IIIIIJJ[ILandroid/media/videoeditor/MediaArtistNativeHelper$NativeGetPixelsListCallback;)I",
(void*)videoEditor_getPixelsList },
{"getMediaProperties",
"(Ljava/lang/String;)Landroid/media/videoeditor/MediaArtistNativeHelper$Properties;",
@@ -375,6 +376,12 @@
pEnv->GetIntField(object,fid);
M4OSA_TRACE1_1("audioVolumeValue = %d",
pSettings->ClipProperties.uiClipAudioVolumePercentage);
+
+ fid = pEnv->GetFieldID(clazz,"videoRotation","I");
+ pSettings->ClipProperties.videoRotationDegrees =
+ pEnv->GetIntField(object,fid);
+ M4OSA_TRACE1_1("videoRotation = %d",
+ pSettings->ClipProperties.videoRotationDegrees);
}
static void jniPreviewProgressCallback (void* cookie, M4OSA_UInt32 msgType,
@@ -789,6 +796,8 @@
pContext->pEditSettings->pClipList[iCurrentClipIndex]->ClipProperties.uiVideoWidth,
(M4OSA_Void **)&frameStr.pBuffer);
tnTimeMs = (M4OSA_UInt32)timeMs;
+
+ frameStr.videoRotationDegree = 0;
} else {
/* Handle 3gp/mp4 Clips here */
/* get thumbnail*/
@@ -913,6 +922,9 @@
/* Fill up the render structure*/
frameStr.pBuffer = (M4OSA_Void*)yuvPlane[0].pac_data;
+
+ frameStr.videoRotationDegree = pContext->pEditSettings->\
+ pClipList[iCurrentClipIndex]->ClipProperties.videoRotationDegrees;
}
frameStr.timeMs = timeMs; /* timestamp on storyboard*/
@@ -976,13 +988,12 @@
videoEditJava_checkAndThrowRuntimeException(&needToBeLoaded, pEnv,
(M4NO_ERROR != result), result);
- if (pContext->pEditSettings->pClipList[iCurrentClipIndex]->FileType ==\
- /*M4VIDEOEDITING_kFileType_JPG */ M4VIDEOEDITING_kFileType_ARGB8888) {
- free(frameStr.pBuffer);
- } else {
- free(yuvPlane[0].pac_data);
+ free(frameStr.pBuffer);
+ if (pContext->pEditSettings->pClipList[iCurrentClipIndex]->FileType !=
+ M4VIDEOEDITING_kFileType_ARGB8888) {
free(yuvPlane);
}
+
return tnTimeMs;
}
@@ -2275,6 +2286,7 @@
M4OSA_UInt32 width,
M4OSA_UInt32 height,
M4OSA_UInt32 noOfThumbnails,
+ M4OSA_UInt32 videoRotation,
jlong startTime,
jlong endTime,
jintArray indexArray,
diff --git a/media/jni/mediaeditor/VideoEditorMain.h b/media/jni/mediaeditor/VideoEditorMain.h
index ca4a945..4c3b517 100755
--- a/media/jni/mediaeditor/VideoEditorMain.h
+++ b/media/jni/mediaeditor/VideoEditorMain.h
@@ -71,6 +71,7 @@
M4OSA_Bool bApplyEffect; /* Apply video effects before render*/
M4OSA_UInt32 clipBeginCutTime; /* Clip begin cut time relative to storyboard */
M4OSA_UInt32 clipEndCutTime; /* Clip end cut time relative to storyboard */
+ M4OSA_UInt32 videoRotationDegree; /* Video rotation degree */
} VideoEditor_renderPreviewFrameStr;
#endif /*__VIDEO_EDITOR_API_H__*/
diff --git a/media/jni/mediaeditor/VideoEditorPropertiesMain.cpp b/media/jni/mediaeditor/VideoEditorPropertiesMain.cpp
index 2ca3a08..c8fb263 100755
--- a/media/jni/mediaeditor/VideoEditorPropertiesMain.cpp
+++ b/media/jni/mediaeditor/VideoEditorPropertiesMain.cpp
@@ -258,6 +258,8 @@
pProperties->uiAudioBitrate = pClipProperties->uiAudioBitrate;
pProperties->uiNbChannels = pClipProperties->uiNbChannels;
pProperties->uiSamplingFrequency = pClipProperties->uiSamplingFrequency;
+ pProperties->uiRotation = pClipProperties->videoRotationDegrees;
+
}
// Free the clip properties.
diff --git a/media/libmedia/AudioSystem.cpp b/media/libmedia/AudioSystem.cpp
index bb91fa9..853a5f6 100644
--- a/media/libmedia/AudioSystem.cpp
+++ b/media/libmedia/AudioSystem.cpp
@@ -727,6 +727,14 @@
}
+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 cecedb5..3b6c64d 100644
--- a/media/libmedia/AudioTrack.cpp
+++ b/media/libmedia/AudioTrack.cpp
@@ -1164,6 +1164,10 @@
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/libmediaplayerservice/nuplayer/HTTPLiveSource.cpp b/media/libmediaplayerservice/nuplayer/HTTPLiveSource.cpp
index 0251baf..605d056 100644
--- a/media/libmediaplayerservice/nuplayer/HTTPLiveSource.cpp
+++ b/media/libmediaplayerservice/nuplayer/HTTPLiveSource.cpp
@@ -124,7 +124,14 @@
: ATSParser::DISCONTINUITY_FORMATCHANGE,
extra);
} else {
- mTSParser->feedTSPacket(buffer, sizeof(buffer));
+ status_t err = mTSParser->feedTSPacket(buffer, sizeof(buffer));
+
+ if (err != OK) {
+ LOGE("TS Parser returned error %d", err);
+ mTSParser->signalEOS(err);
+ mEOS = true;
+ break;
+ }
}
mOffset += n;
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp
index 1f08a91..ee77f47 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp
+++ b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp
@@ -663,6 +663,19 @@
sp<AMessage> reply;
CHECK(msg->findMessage("reply", &reply));
+ if (IsFlushingState(audio ? mFlushingAudio : mFlushingVideo)) {
+ // We're currently attempting to flush the decoder, in order
+ // to complete this, the decoder wants all its buffers back,
+ // so we don't want any output buffers it sent us (from before
+ // we initiated the flush) to be stuck in the renderer's queue.
+
+ LOGV("we're still flushing the %s decoder, sending its output buffer"
+ " right back.", audio ? "audio" : "video");
+
+ reply->post();
+ return;
+ }
+
sp<RefBase> obj;
CHECK(msg->findObject("buffer", &obj));
diff --git a/media/libmediaplayerservice/nuplayer/StreamingSource.cpp b/media/libmediaplayerservice/nuplayer/StreamingSource.cpp
index a6a3a18..a741987 100644
--- a/media/libmediaplayerservice/nuplayer/StreamingSource.cpp
+++ b/media/libmediaplayerservice/nuplayer/StreamingSource.cpp
@@ -42,7 +42,7 @@
void NuPlayer::StreamingSource::start() {
mStreamListener = new NuPlayerStreamListener(mSource, 0);
- mTSParser = new ATSParser;
+ mTSParser = new ATSParser(ATSParser::TS_TIMESTAMPS_ARE_ABSOLUTE);
mStreamListener->start();
}
@@ -86,7 +86,15 @@
: ATSParser::DISCONTINUITY_FORMATCHANGE,
extra);
} else {
- mTSParser->feedTSPacket(buffer, sizeof(buffer));
+ status_t err = mTSParser->feedTSPacket(buffer, sizeof(buffer));
+
+ if (err != OK) {
+ LOGE("TS Parser returned error %d", err);
+
+ mTSParser->signalEOS(err);
+ mEOS = true;
+ break;
+ }
}
}
}
diff --git a/media/libstagefright/AACExtractor.cpp b/media/libstagefright/AACExtractor.cpp
index a5a6b64..52b1200 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 @@
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 @@
}
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 @@
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 @@
}
}
- 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 @@
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/libstagefright/AwesomePlayer.cpp b/media/libstagefright/AwesomePlayer.cpp
index 142dda0..47224cc 100644
--- a/media/libstagefright/AwesomePlayer.cpp
+++ b/media/libstagefright/AwesomePlayer.cpp
@@ -513,7 +513,8 @@
// If we did this later, audio would continue playing while we
// shutdown the video-related resources and the player appear to
// not be as responsive to a reset request.
- if (mAudioPlayer == NULL && mAudioSource != NULL) {
+ if ((mAudioPlayer == NULL || !(mFlags & AUDIOPLAYER_STARTED))
+ && mAudioSource != NULL) {
// If we had an audio player, it would have effectively
// taken possession of the audio source and stopped it when
// _it_ is stopped. Otherwise this is still our responsibility.
@@ -977,7 +978,7 @@
CHECK(!mAudioPlayer->isSeeking());
// We will have finished the seek while starting the audio player.
- postAudioSeekComplete_l();
+ postAudioSeekComplete();
}
} else {
mAudioPlayer->resume();
@@ -1876,7 +1877,8 @@
mQueue.postEventWithDelay(mVideoLagEvent, 1000000ll);
}
-void AwesomePlayer::postCheckAudioStatusEvent_l(int64_t delayUs) {
+void AwesomePlayer::postCheckAudioStatusEvent(int64_t delayUs) {
+ Mutex::Autolock autoLock(mAudioLock);
if (mAudioStatusEventPending) {
return;
}
@@ -1885,14 +1887,18 @@
}
void AwesomePlayer::onCheckAudioStatus() {
- Mutex::Autolock autoLock(mLock);
- if (!mAudioStatusEventPending) {
- // Event was dispatched and while we were blocking on the mutex,
- // has already been cancelled.
- return;
+ {
+ Mutex::Autolock autoLock(mAudioLock);
+ if (!mAudioStatusEventPending) {
+ // Event was dispatched and while we were blocking on the mutex,
+ // has already been cancelled.
+ return;
+ }
+
+ mAudioStatusEventPending = false;
}
- mAudioStatusEventPending = false;
+ Mutex::Autolock autoLock(mLock);
if (mWatchForAudioSeekComplete && !mAudioPlayer->isSeeking()) {
mWatchForAudioSeekComplete = false;
@@ -2238,17 +2244,11 @@
}
void AwesomePlayer::postAudioEOS(int64_t delayUs) {
- Mutex::Autolock autoLock(mLock);
- postCheckAudioStatusEvent_l(delayUs);
+ postCheckAudioStatusEvent(delayUs);
}
void AwesomePlayer::postAudioSeekComplete() {
- Mutex::Autolock autoLock(mLock);
- postAudioSeekComplete_l();
-}
-
-void AwesomePlayer::postAudioSeekComplete_l() {
- postCheckAudioStatusEvent_l(0 /* delayUs */);
+ postCheckAudioStatusEvent(0);
}
status_t AwesomePlayer::setParameter(int key, const Parcel &request) {
diff --git a/media/libstagefright/OMXCodec.cpp b/media/libstagefright/OMXCodec.cpp
index 7f09319..d5b013d 100755
--- a/media/libstagefright/OMXCodec.cpp
+++ b/media/libstagefright/OMXCodec.cpp
@@ -1990,7 +1990,7 @@
CHECK(mIsEncoder);
if (mDecodingTimeList.empty()) {
- CHECK(mNoMoreOutputData);
+ CHECK(mSignalledEOS || mNoMoreOutputData);
// No corresponding input frame available.
// This could happen when EOS is reached.
return 0;
diff --git a/media/libstagefright/SurfaceMediaSource.cpp b/media/libstagefright/SurfaceMediaSource.cpp
index 91b81c2..50dd804 100644
--- a/media/libstagefright/SurfaceMediaSource.cpp
+++ b/media/libstagefright/SurfaceMediaSource.cpp
@@ -46,9 +46,10 @@
mSynchronousMode(true),
mConnectedApi(NO_CONNECTED_API),
mFrameRate(30),
+ mStopped(false),
mNumFramesReceived(0),
mNumFramesEncoded(0),
- mStopped(false) {
+ mFirstFrameTimestamp(0) {
LOGV("SurfaceMediaSource::SurfaceMediaSource");
sp<ISurfaceComposer> composer(ComposerService::getComposerService());
mGraphicBufferAlloc = composer->createGraphicBufferAlloc();
@@ -471,10 +472,25 @@
return -EINVAL;
}
+ if (mNumFramesReceived == 0) {
+ mFirstFrameTimestamp = timestamp;
+ // Initial delay
+ if (mStartTimeNs > 0) {
+ if (timestamp < mStartTimeNs) {
+ // This frame predates start of record, discard
+ mSlots[bufIndex].mBufferState = BufferSlot::FREE;
+ mDequeueCondition.signal();
+ return OK;
+ }
+ mStartTimeNs = timestamp - mStartTimeNs;
+ }
+ }
+ timestamp = mStartTimeNs + (timestamp - mFirstFrameTimestamp);
+
+ mNumFramesReceived++;
if (mSynchronousMode) {
// in synchronous mode we queue all buffers in a FIFO
mQueue.push_back(bufIndex);
- mNumFramesReceived++;
LOGV("Client queued buf# %d @slot: %d, Q size = %d, handle = %p, timestamp = %lld",
mNumFramesReceived, bufIndex, mQueue.size(),
mSlots[bufIndex].mGraphicBuffer->handle, timestamp);
@@ -684,6 +700,13 @@
status_t SurfaceMediaSource::start(MetaData *params)
{
LOGV("started!");
+
+ mStartTimeNs = 0;
+ int64_t startTimeUs;
+ if (params && params->findInt64(kKeyTime, &startTimeUs)) {
+ mStartTimeNs = startTimeUs * 1000;
+ }
+
return OK;
}
@@ -753,6 +776,7 @@
mCurrentBuf = mSlots[mCurrentSlot].mGraphicBuffer;
int64_t prevTimeStamp = mCurrentTimestamp;
mCurrentTimestamp = mSlots[mCurrentSlot].mTimestamp;
+
mNumFramesEncoded++;
// Pass the data to the MediaBuffer. Pass in only the metadata
passMetadataBufferLocked(buffer);
diff --git a/media/libstagefright/include/AwesomePlayer.h b/media/libstagefright/include/AwesomePlayer.h
index 24cf77c..8e73121 100644
--- a/media/libstagefright/include/AwesomePlayer.h
+++ b/media/libstagefright/include/AwesomePlayer.h
@@ -148,6 +148,7 @@
mutable Mutex mLock;
Mutex mMiscStateLock;
mutable Mutex mStatsLock;
+ Mutex mAudioLock;
OMXClient mClient;
TimedEventQueue mQueue;
@@ -223,7 +224,7 @@
void postVideoEvent_l(int64_t delayUs = -1);
void postBufferingEvent_l();
void postStreamDoneEvent_l(status_t status);
- void postCheckAudioStatusEvent_l(int64_t delayUs);
+ void postCheckAudioStatusEvent(int64_t delayUs);
void postVideoLagEvent_l();
status_t play_l();
@@ -295,7 +296,6 @@
void ensureCacheIsFetching_l();
status_t startAudioPlayer_l(bool sendErrorNotification = true);
- void postAudioSeekComplete_l();
void shutdownVideoDecoder_l();
status_t setNativeWindow_l(const sp<ANativeWindow> &native);
diff --git a/media/libstagefright/mpeg2ts/ATSParser.cpp b/media/libstagefright/mpeg2ts/ATSParser.cpp
index 5bbc2b4..e13464e 100644
--- a/media/libstagefright/mpeg2ts/ATSParser.cpp
+++ b/media/libstagefright/mpeg2ts/ATSParser.cpp
@@ -48,7 +48,7 @@
bool parsePID(
unsigned pid, unsigned payload_unit_start_indicator,
- ABitReader *br);
+ ABitReader *br, status_t *err);
void signalDiscontinuity(
DiscontinuityType type, const sp<AMessage> &extra);
@@ -77,7 +77,7 @@
bool mFirstPTSValid;
uint64_t mFirstPTS;
- void parseProgramMap(ABitReader *br);
+ status_t parseProgramMap(ABitReader *br);
DISALLOW_EVIL_CONSTRUCTORS(Program);
};
@@ -89,7 +89,7 @@
unsigned pid() const { return mElementaryPID; }
void setPID(unsigned pid) { mElementaryPID = pid; }
- void parse(
+ status_t parse(
unsigned payload_unit_start_indicator,
ABitReader *br);
@@ -111,13 +111,11 @@
sp<ABuffer> mBuffer;
sp<AnotherPacketSource> mSource;
bool mPayloadStarted;
- DiscontinuityType mPendingDiscontinuity;
- sp<AMessage> mPendingDiscontinuityExtra;
ElementaryStreamQueue *mQueue;
- void flush();
- void parsePES(ABitReader *br);
+ status_t flush();
+ status_t parsePES(ABitReader *br);
void onPayloadData(
unsigned PTS_DTS_flags, uint64_t PTS, uint64_t DTS,
@@ -125,9 +123,6 @@
void extractAACFrames(const sp<ABuffer> &buffer);
- void deferDiscontinuity(
- DiscontinuityType type, const sp<AMessage> &extra);
-
DISALLOW_EVIL_CONSTRUCTORS(Stream);
};
@@ -145,14 +140,17 @@
bool ATSParser::Program::parsePID(
unsigned pid, unsigned payload_unit_start_indicator,
- ABitReader *br) {
+ ABitReader *br, status_t *err) {
+ *err = OK;
+
if (pid == mProgramMapPID) {
if (payload_unit_start_indicator) {
unsigned skip = br->getBits(8);
br->skipBits(skip * 8);
}
- parseProgramMap(br);
+ *err = parseProgramMap(br);
+
return true;
}
@@ -161,7 +159,7 @@
return false;
}
- mStreams.editValueAt(index)->parse(
+ *err = mStreams.editValueAt(index)->parse(
payload_unit_start_indicator, br);
return true;
@@ -185,7 +183,7 @@
unsigned mPID;
};
-void ATSParser::Program::parseProgramMap(ABitReader *br) {
+status_t ATSParser::Program::parseProgramMap(ABitReader *br) {
unsigned table_id = br->getBits(8);
LOGV(" table_id = %u", table_id);
CHECK_EQ(table_id, 0x02u);
@@ -288,7 +286,60 @@
}
if (PIDsChanged) {
- mStreams.clear();
+#if 0
+ LOGI("before:");
+ for (size_t i = 0; i < mStreams.size(); ++i) {
+ sp<Stream> stream = mStreams.editValueAt(i);
+
+ LOGI("PID 0x%08x => type 0x%02x", stream->pid(), stream->type());
+ }
+
+ LOGI("after:");
+ for (size_t i = 0; i < infos.size(); ++i) {
+ StreamInfo &info = infos.editItemAt(i);
+
+ LOGI("PID 0x%08x => type 0x%02x", info.mPID, info.mType);
+ }
+#endif
+
+ // The only case we can recover from is if we have two streams
+ // and they switched PIDs.
+
+ bool success = false;
+
+ if (mStreams.size() == 2 && infos.size() == 2) {
+ const StreamInfo &info1 = infos.itemAt(0);
+ const StreamInfo &info2 = infos.itemAt(1);
+
+ sp<Stream> s1 = mStreams.editValueAt(0);
+ sp<Stream> s2 = mStreams.editValueAt(1);
+
+ bool caseA =
+ info1.mPID == s1->pid() && info1.mType == s2->type()
+ && info2.mPID == s2->pid() && info2.mType == s1->type();
+
+ bool caseB =
+ info1.mPID == s2->pid() && info1.mType == s1->type()
+ && info2.mPID == s1->pid() && info2.mType == s2->type();
+
+ if (caseA || caseB) {
+ unsigned pid1 = s1->pid();
+ unsigned pid2 = s2->pid();
+ s1->setPID(pid2);
+ s2->setPID(pid1);
+
+ mStreams.clear();
+ mStreams.add(s1->pid(), s1);
+ mStreams.add(s2->pid(), s2);
+
+ success = true;
+ }
+ }
+
+ if (!success) {
+ LOGI("Stream PIDs changed and we cannot recover.");
+ return ERROR_MALFORMED;
+ }
}
for (size_t i = 0; i < infos.size(); ++i) {
@@ -299,13 +350,10 @@
if (index < 0) {
sp<Stream> stream = new Stream(this, info.mPID, info.mType);
mStreams.add(info.mPID, stream);
-
- if (PIDsChanged) {
- sp<AMessage> extra;
- stream->signalDiscontinuity(DISCONTINUITY_FORMATCHANGE, extra);
- }
}
}
+
+ return OK;
}
sp<MediaSource> ATSParser::Program::getSource(SourceType type) {
@@ -325,14 +373,16 @@
}
int64_t ATSParser::Program::convertPTSToTimestamp(uint64_t PTS) {
- if (!mFirstPTSValid) {
- mFirstPTSValid = true;
- mFirstPTS = PTS;
- PTS = 0;
- } else if (PTS < mFirstPTS) {
- PTS = 0;
- } else {
- PTS -= mFirstPTS;
+ if (!(mParser->mFlags & TS_TIMESTAMPS_ARE_ABSOLUTE)) {
+ if (!mFirstPTSValid) {
+ mFirstPTSValid = true;
+ mFirstPTS = PTS;
+ PTS = 0;
+ } else if (PTS < mFirstPTS) {
+ PTS = 0;
+ } else {
+ PTS -= mFirstPTS;
+ }
}
return (PTS * 100) / 9;
@@ -345,12 +395,8 @@
: mProgram(program),
mElementaryPID(elementaryPID),
mStreamType(streamType),
- mBuffer(new ABuffer(192 * 1024)),
mPayloadStarted(false),
- mPendingDiscontinuity(DISCONTINUITY_NONE),
mQueue(NULL) {
- mBuffer->setRange(0, 0);
-
switch (mStreamType) {
case STREAMTYPE_H264:
mQueue = new ElementaryStreamQueue(ElementaryStreamQueue::H264);
@@ -380,6 +426,11 @@
}
LOGV("new stream PID 0x%02x, type 0x%02x", elementaryPID, streamType);
+
+ if (mQueue != NULL) {
+ mBuffer = new ABuffer(192 * 1024);
+ mBuffer->setRange(0, 0);
+ }
}
ATSParser::Stream::~Stream() {
@@ -387,22 +438,30 @@
mQueue = NULL;
}
-void ATSParser::Stream::parse(
+status_t ATSParser::Stream::parse(
unsigned payload_unit_start_indicator, ABitReader *br) {
+ if (mQueue == NULL) {
+ return OK;
+ }
+
if (payload_unit_start_indicator) {
if (mPayloadStarted) {
// Otherwise we run the danger of receiving the trailing bytes
// of a PES packet that we never saw the start of and assuming
// we have a a complete PES packet.
- flush();
+ status_t err = flush();
+
+ if (err != OK) {
+ return err;
+ }
}
mPayloadStarted = true;
}
if (!mPayloadStarted) {
- return;
+ return OK;
}
size_t payloadSizeBits = br->numBitsLeft();
@@ -423,10 +482,16 @@
memcpy(mBuffer->data() + mBuffer->size(), br->data(), payloadSizeBits / 8);
mBuffer->setRange(0, mBuffer->size() + payloadSizeBits / 8);
+
+ return OK;
}
void ATSParser::Stream::signalDiscontinuity(
DiscontinuityType type, const sp<AMessage> &extra) {
+ if (mQueue == NULL) {
+ return;
+ }
+
mPayloadStarted = false;
mBuffer->setRange(0, 0);
@@ -451,8 +516,6 @@
if (mSource != NULL) {
mSource->queueDiscontinuity(type, extra);
- } else {
- deferDiscontinuity(type, extra);
}
break;
}
@@ -463,22 +526,13 @@
}
}
-void ATSParser::Stream::deferDiscontinuity(
- DiscontinuityType type, const sp<AMessage> &extra) {
- if (type > mPendingDiscontinuity) {
- // Only upgrade discontinuities.
- mPendingDiscontinuity = type;
- mPendingDiscontinuityExtra = extra;
- }
-}
-
void ATSParser::Stream::signalEOS(status_t finalResult) {
if (mSource != NULL) {
mSource->signalEOS(finalResult);
}
}
-void ATSParser::Stream::parsePES(ABitReader *br) {
+status_t ATSParser::Stream::parsePES(ABitReader *br) {
unsigned packet_startcode_prefix = br->getBits(24);
LOGV("packet_startcode_prefix = 0x%08x", packet_startcode_prefix);
@@ -486,7 +540,8 @@
if (packet_startcode_prefix != 1) {
LOGV("Supposedly payload_unit_start=1 unit does not start "
"with startcode.");
- return;
+
+ return ERROR_MALFORMED;
}
CHECK_EQ(packet_startcode_prefix, 0x000001u);
@@ -613,6 +668,14 @@
unsigned dataLength =
PES_packet_length - 3 - PES_header_data_length;
+ if (br->numBitsLeft() < dataLength * 8) {
+ LOGE("PES packet does not carry enough data to contain "
+ "payload. (numBitsLeft = %d, required = %d)",
+ br->numBitsLeft(), dataLength * 8);
+
+ return ERROR_MALFORMED;
+ }
+
CHECK_GE(br->numBitsLeft(), dataLength * 8);
onPayloadData(
@@ -636,19 +699,24 @@
CHECK_NE(PES_packet_length, 0u);
br->skipBits(PES_packet_length * 8);
}
+
+ return OK;
}
-void ATSParser::Stream::flush() {
+status_t ATSParser::Stream::flush() {
if (mBuffer->size() == 0) {
- return;
+ return OK;
}
LOGV("flushing stream 0x%04x size = %d", mElementaryPID, mBuffer->size());
ABitReader br(mBuffer->data(), mBuffer->size());
- parsePES(&br);
+
+ status_t err = parsePES(&br);
mBuffer->setRange(0, 0);
+
+ return err;
}
void ATSParser::Stream::onPayloadData(
@@ -656,10 +724,6 @@
const uint8_t *data, size_t size) {
LOGV("onPayloadData mStreamType=0x%02x", mStreamType);
- if (mQueue == NULL) {
- return;
- }
-
CHECK(PTS_DTS_flags == 2 || PTS_DTS_flags == 3);
int64_t timeUs = mProgram->convertPTSToTimestamp(PTS);
@@ -679,14 +743,6 @@
mElementaryPID, mStreamType);
mSource = new AnotherPacketSource(meta);
-
- if (mPendingDiscontinuity != DISCONTINUITY_NONE) {
- mSource->queueDiscontinuity(
- mPendingDiscontinuity, mPendingDiscontinuityExtra);
- mPendingDiscontinuity = DISCONTINUITY_NONE;
- mPendingDiscontinuityExtra.clear();
- }
-
mSource->queueAccessUnit(accessUnit);
}
} else if (mQueue->getFormat() != NULL) {
@@ -734,17 +790,18 @@
////////////////////////////////////////////////////////////////////////////////
-ATSParser::ATSParser() {
+ATSParser::ATSParser(uint32_t flags)
+ : mFlags(flags) {
}
ATSParser::~ATSParser() {
}
-void ATSParser::feedTSPacket(const void *data, size_t size) {
+status_t ATSParser::feedTSPacket(const void *data, size_t size) {
CHECK_EQ(size, kTSPacketSize);
ABitReader br((const uint8_t *)data, kTSPacketSize);
- parseTS(&br);
+ return parseTS(&br);
}
void ATSParser::signalDiscontinuity(
@@ -822,7 +879,7 @@
MY_LOGV(" CRC = 0x%08x", br->getBits(32));
}
-void ATSParser::parsePID(
+status_t ATSParser::parsePID(
ABitReader *br, unsigned PID,
unsigned payload_unit_start_indicator) {
if (PID == 0) {
@@ -831,13 +888,18 @@
br->skipBits(skip * 8);
}
parseProgramAssociationTable(br);
- return;
+ return OK;
}
bool handled = false;
for (size_t i = 0; i < mPrograms.size(); ++i) {
+ status_t err;
if (mPrograms.editItemAt(i)->parsePID(
- PID, payload_unit_start_indicator, br)) {
+ PID, payload_unit_start_indicator, br, &err)) {
+ if (err != OK) {
+ return err;
+ }
+
handled = true;
break;
}
@@ -846,6 +908,8 @@
if (!handled) {
LOGV("PID 0x%04x not handled.", PID);
}
+
+ return OK;
}
void ATSParser::parseAdaptationField(ABitReader *br) {
@@ -855,7 +919,7 @@
}
}
-void ATSParser::parseTS(ABitReader *br) {
+status_t ATSParser::parseTS(ABitReader *br) {
LOGV("---");
unsigned sync_byte = br->getBits(8);
@@ -886,8 +950,10 @@
}
if (adaptation_field_control == 1 || adaptation_field_control == 3) {
- parsePID(br, PID, payload_unit_start_indicator);
+ return parsePID(br, PID, payload_unit_start_indicator);
}
+
+ return OK;
}
sp<MediaSource> ATSParser::getSource(SourceType type) {
diff --git a/media/libstagefright/mpeg2ts/ATSParser.h b/media/libstagefright/mpeg2ts/ATSParser.h
index 1e6451d..388cb54 100644
--- a/media/libstagefright/mpeg2ts/ATSParser.h
+++ b/media/libstagefright/mpeg2ts/ATSParser.h
@@ -38,9 +38,18 @@
DISCONTINUITY_FORMATCHANGE
};
- ATSParser();
+ enum Flags {
+ // The 90kHz clock (PTS/DTS) is absolute, i.e. PTS=0 corresponds to
+ // a media time of 0.
+ // If this flag is _not_ specified, the first PTS encountered in a
+ // program of this stream will be assumed to correspond to media time 0
+ // instead.
+ TS_TIMESTAMPS_ARE_ABSOLUTE = 1
+ };
- void feedTSPacket(const void *data, size_t size);
+ ATSParser(uint32_t flags = 0);
+
+ status_t feedTSPacket(const void *data, size_t size);
void signalDiscontinuity(
DiscontinuityType type, const sp<AMessage> &extra);
@@ -73,18 +82,19 @@
struct Program;
struct Stream;
+ uint32_t mFlags;
Vector<sp<Program> > mPrograms;
void parseProgramAssociationTable(ABitReader *br);
void parseProgramMap(ABitReader *br);
void parsePES(ABitReader *br);
- void parsePID(
+ status_t parsePID(
ABitReader *br, unsigned PID,
unsigned payload_unit_start_indicator);
void parseAdaptationField(ABitReader *br);
- void parseTS(ABitReader *br);
+ status_t parseTS(ABitReader *br);
DISALLOW_EVIL_CONSTRUCTORS(ATSParser);
};
diff --git a/media/libstagefright/mpeg2ts/MPEG2TSExtractor.cpp b/media/libstagefright/mpeg2ts/MPEG2TSExtractor.cpp
index 8250ad1..17cf45a 100644
--- a/media/libstagefright/mpeg2ts/MPEG2TSExtractor.cpp
+++ b/media/libstagefright/mpeg2ts/MPEG2TSExtractor.cpp
@@ -210,13 +210,10 @@
if (n < (ssize_t)kTSPacketSize) {
return (n < 0) ? (status_t)n : ERROR_END_OF_STREAM;
- } else {
- mParser->feedTSPacket(packet, kTSPacketSize);
}
mOffset += n;
-
- return OK;
+ return mParser->feedTSPacket(packet, kTSPacketSize);
}
void MPEG2TSExtractor::setLiveSession(const sp<LiveSession> &liveSession) {
diff --git a/media/libstagefright/tests/SurfaceMediaSource_test.cpp b/media/libstagefright/tests/SurfaceMediaSource_test.cpp
index d643a0b..d663602 100644
--- a/media/libstagefright/tests/SurfaceMediaSource_test.cpp
+++ b/media/libstagefright/tests/SurfaceMediaSource_test.cpp
@@ -106,13 +106,14 @@
mEglSurface = eglCreateWindowSurface(mEglDisplay, mGlConfig,
window.get(), NULL);
} else {
- EGLint pbufferAttribs[] = {
- EGL_WIDTH, getSurfaceWidth(),
- EGL_HEIGHT, getSurfaceHeight(),
- EGL_NONE };
+ LOGV("No actual display. Choosing EGLSurface based on SurfaceMediaSource");
+ sp<SurfaceMediaSource> sms = new SurfaceMediaSource(
+ getSurfaceWidth(), getSurfaceHeight());
+ sp<SurfaceTextureClient> stc = new SurfaceTextureClient(sms);
+ sp<ANativeWindow> window = stc;
- mEglSurface = eglCreatePbufferSurface(mEglDisplay, mGlConfig,
- pbufferAttribs);
+ mEglSurface = eglCreateWindowSurface(mEglDisplay, mGlConfig,
+ window.get(), NULL);
}
ASSERT_EQ(EGL_SUCCESS, eglGetError());
ASSERT_NE(EGL_NO_SURFACE, mEglSurface);
@@ -408,7 +409,6 @@
mSTC.clear();
mANW.clear();
GLTest::TearDown();
- eglDestroySurface(mEglDisplay, mSmsEglSurface);
}
void setUpEGLSurfaceFromMediaRecorder(sp<MediaRecorder>& mr);
@@ -419,8 +419,6 @@
sp<SurfaceMediaSource> mSMS;
sp<SurfaceTextureClient> mSTC;
sp<ANativeWindow> mANW;
- EGLConfig mSMSGlConfig;
- EGLSurface mSmsEglSurface;
};
/////////////////////////////////////////////////////////////////////
@@ -462,7 +460,7 @@
glClear(GL_COLOR_BUFFER_BIT);
// The following call dequeues and queues the buffer
- eglSwapBuffers(mEglDisplay, mSmsEglSurface);
+ eglSwapBuffers(mEglDisplay, mEglSurface);
glDisable(GL_SCISSOR_TEST);
}
@@ -488,19 +486,12 @@
mSTC = new SurfaceTextureClient(iST);
mANW = mSTC;
- EGLint numConfigs = 0;
- EXPECT_TRUE(eglChooseConfig(mEglDisplay, getConfigAttribs(), &mSMSGlConfig,
- 1, &numConfigs));
- ASSERT_EQ(EGL_SUCCESS, eglGetError());
-
- LOGV("Native Window = %p, mSTC = %p", mANW.get(), mSTC.get());
-
- mSmsEglSurface = eglCreateWindowSurface(mEglDisplay, mSMSGlConfig,
+ mEglSurface = eglCreateWindowSurface(mEglDisplay, mGlConfig,
mANW.get(), NULL);
ASSERT_EQ(EGL_SUCCESS, eglGetError());
- ASSERT_NE(EGL_NO_SURFACE, mSmsEglSurface) ;
+ ASSERT_NE(EGL_NO_SURFACE, mEglSurface) ;
- EXPECT_TRUE(eglMakeCurrent(mEglDisplay, mSmsEglSurface, mSmsEglSurface,
+ EXPECT_TRUE(eglMakeCurrent(mEglDisplay, mEglSurface, mEglSurface,
mEglContext));
ASSERT_EQ(EGL_SUCCESS, eglGetError());
}
@@ -778,9 +769,9 @@
// Test to examine whether we can choose the Recordable Android GLConfig
// DummyRecorder used- no real encoding here
-TEST_F(SurfaceMediaSourceGLTest, ChooseAndroidRecordableEGLConfigDummyWrite) {
+TEST_F(SurfaceMediaSourceGLTest, ChooseAndroidRecordableEGLConfigDummyWriter) {
LOGV("Test # %d", testId++);
- LOGV("Test to verify creating a surface w/ right config *********");
+ LOGV("Verify creating a surface w/ right config + dummy writer*********");
mSMS = new SurfaceMediaSource(mYuvTexWidth, mYuvTexHeight);
mSTC = new SurfaceTextureClient(mSMS);
@@ -789,17 +780,12 @@
DummyRecorder writer(mSMS);
writer.start();
- EGLint numConfigs = 0;
- EXPECT_TRUE(eglChooseConfig(mEglDisplay, getConfigAttribs(), &mSMSGlConfig,
- 1, &numConfigs));
- ASSERT_EQ(EGL_SUCCESS, eglGetError());
-
- mSmsEglSurface = eglCreateWindowSurface(mEglDisplay, mSMSGlConfig,
+ mEglSurface = eglCreateWindowSurface(mEglDisplay, mGlConfig,
mANW.get(), NULL);
ASSERT_EQ(EGL_SUCCESS, eglGetError());
- ASSERT_NE(EGL_NO_SURFACE, mSmsEglSurface) ;
+ ASSERT_NE(EGL_NO_SURFACE, mEglSurface) ;
- EXPECT_TRUE(eglMakeCurrent(mEglDisplay, mSmsEglSurface, mSmsEglSurface,
+ EXPECT_TRUE(eglMakeCurrent(mEglDisplay, mEglSurface, mEglSurface,
mEglContext));
ASSERT_EQ(EGL_SUCCESS, eglGetError());
diff --git a/media/tests/MediaDump/src/com/android/mediadump/VideoDumpView.java b/media/tests/MediaDump/src/com/android/mediadump/VideoDumpView.java
index 809ee82..f76cf37 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.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 @@
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 b396223..0810643 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 @@
}
// 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 @@
} 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 @@
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 @@
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 @@
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/opengl/libs/EGL/egl.cpp b/opengl/libs/EGL/egl.cpp
index ddad2d3..ca62908 100644
--- a/opengl/libs/EGL/egl.cpp
+++ b/opengl/libs/EGL/egl.cpp
@@ -95,12 +95,12 @@
if (fgets(cmdline, sizeof(cmdline) - 1, file))
{
if (!strcmp(value, cmdline))
- sEGLTraceLevel = 1;
+ gEGLDebugLevel = 1;
}
fclose(file);
}
- if (sEGLTraceLevel > 0)
+ if (gEGLDebugLevel > 0)
{
property_get("debug.egl.debug_port", value, "5039");
const unsigned short port = (unsigned short)atoi(value);
@@ -117,7 +117,7 @@
if (sEGLTraceLevel > 0) {
setGlTraceThreadSpecific(value);
setGlThreadSpecific(&gHooksTrace);
- } else if (sEGLTraceLevel > 0 && value != &gHooksNoContext) {
+ } else if (gEGLDebugLevel > 0 && value != &gHooksNoContext) {
setGlTraceThreadSpecific(value);
setGlThreadSpecific(&gHooksDebug);
} else {
diff --git a/packages/SystemUI/res/drawable-hdpi/recents_bg_protect_tile.png b/packages/SystemUI/res/drawable-hdpi/recents_bg_protect_tile.png
deleted file mode 100644
index 87c7be6..0000000
--- a/packages/SystemUI/res/drawable-hdpi/recents_bg_protect_tile.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/recents_blue_glow.9.png b/packages/SystemUI/res/drawable-hdpi/recents_blue_glow.9.png
index 4f4ae78..4362836 100644
--- a/packages/SystemUI/res/drawable-hdpi/recents_blue_glow.9.png
+++ b/packages/SystemUI/res/drawable-hdpi/recents_blue_glow.9.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/recents_callout_line.9.png b/packages/SystemUI/res/drawable-hdpi/recents_callout_line.9.png
new file mode 100644
index 0000000..335d5a8
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/recents_callout_line.9.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/recents_callout_line.png b/packages/SystemUI/res/drawable-hdpi/recents_callout_line.png
deleted file mode 100644
index 5f4c035..0000000
--- a/packages/SystemUI/res/drawable-hdpi/recents_callout_line.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/recents_thumbnail_bg.9.png b/packages/SystemUI/res/drawable-hdpi/recents_thumbnail_bg.9.png
new file mode 100644
index 0000000..1ad16f7
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/recents_thumbnail_bg.9.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/recents_thumbnail_bg.png b/packages/SystemUI/res/drawable-hdpi/recents_thumbnail_bg.png
deleted file mode 100644
index 23aabce..0000000
--- a/packages/SystemUI/res/drawable-hdpi/recents_thumbnail_bg.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/recents_thumbnail_bg_press.9.png b/packages/SystemUI/res/drawable-hdpi/recents_thumbnail_bg_press.9.png
new file mode 100644
index 0000000..6e806ee
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/recents_thumbnail_bg_press.9.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/recents_thumbnail_bg_press.png b/packages/SystemUI/res/drawable-hdpi/recents_thumbnail_bg_press.png
deleted file mode 100644
index 0b0765b..0000000
--- a/packages/SystemUI/res/drawable-hdpi/recents_thumbnail_bg_press.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-large-hdpi/app_icon.png b/packages/SystemUI/res/drawable-large-hdpi/app_icon.png
deleted file mode 100644
index 52354bd..0000000
--- a/packages/SystemUI/res/drawable-large-hdpi/app_icon.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-large-hdpi/recents_bg_protect_tile.png b/packages/SystemUI/res/drawable-large-hdpi/recents_bg_protect_tile.png
deleted file mode 100644
index ce01276..0000000
--- a/packages/SystemUI/res/drawable-large-hdpi/recents_bg_protect_tile.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-large-hdpi/recents_blue_glow.9.png b/packages/SystemUI/res/drawable-large-hdpi/recents_blue_glow.9.png
deleted file mode 100644
index 1848fcd..0000000
--- a/packages/SystemUI/res/drawable-large-hdpi/recents_blue_glow.9.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-large-hdpi/recents_callout_line.png b/packages/SystemUI/res/drawable-large-hdpi/recents_callout_line.png
deleted file mode 100644
index 61a3f87..0000000
--- a/packages/SystemUI/res/drawable-large-hdpi/recents_callout_line.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-large-hdpi/recents_thumbnail_bg.png b/packages/SystemUI/res/drawable-large-hdpi/recents_thumbnail_bg.png
deleted file mode 100644
index b6aca49..0000000
--- a/packages/SystemUI/res/drawable-large-hdpi/recents_thumbnail_bg.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-large-hdpi/recents_thumbnail_bg_press.png b/packages/SystemUI/res/drawable-large-hdpi/recents_thumbnail_bg_press.png
deleted file mode 100644
index 226aaac..0000000
--- a/packages/SystemUI/res/drawable-large-hdpi/recents_thumbnail_bg_press.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-large-mdpi/app_icon.png b/packages/SystemUI/res/drawable-large-mdpi/app_icon.png
deleted file mode 100644
index 001811f..0000000
--- a/packages/SystemUI/res/drawable-large-mdpi/app_icon.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-large-mdpi/recents_bg_protect_tile.png b/packages/SystemUI/res/drawable-large-mdpi/recents_bg_protect_tile.png
deleted file mode 100644
index 3d0fbf2..0000000
--- a/packages/SystemUI/res/drawable-large-mdpi/recents_bg_protect_tile.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-large-mdpi/recents_blue_glow.9.png b/packages/SystemUI/res/drawable-large-mdpi/recents_blue_glow.9.png
deleted file mode 100644
index 4362836..0000000
--- a/packages/SystemUI/res/drawable-large-mdpi/recents_blue_glow.9.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-large-mdpi/recents_callout_line.png b/packages/SystemUI/res/drawable-large-mdpi/recents_callout_line.png
deleted file mode 100644
index f4ccd7e..0000000
--- a/packages/SystemUI/res/drawable-large-mdpi/recents_callout_line.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-large-mdpi/recents_thumbnail_bg.png b/packages/SystemUI/res/drawable-large-mdpi/recents_thumbnail_bg.png
deleted file mode 100644
index 6392fa1..0000000
--- a/packages/SystemUI/res/drawable-large-mdpi/recents_thumbnail_bg.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-large-mdpi/recents_thumbnail_bg_press.png b/packages/SystemUI/res/drawable-large-mdpi/recents_thumbnail_bg_press.png
deleted file mode 100644
index f6ee596..0000000
--- a/packages/SystemUI/res/drawable-large-mdpi/recents_thumbnail_bg_press.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/recents_bg_protect_tile.png b/packages/SystemUI/res/drawable-mdpi/recents_bg_protect_tile.png
deleted file mode 100644
index 87c7be6..0000000
--- a/packages/SystemUI/res/drawable-mdpi/recents_bg_protect_tile.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/recents_blue_glow.9.png b/packages/SystemUI/res/drawable-mdpi/recents_blue_glow.9.png
index 4f4ae78..4362836 100644
--- a/packages/SystemUI/res/drawable-mdpi/recents_blue_glow.9.png
+++ b/packages/SystemUI/res/drawable-mdpi/recents_blue_glow.9.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/recents_callout_line.9.png b/packages/SystemUI/res/drawable-mdpi/recents_callout_line.9.png
new file mode 100644
index 0000000..724a5cd
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/recents_callout_line.9.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/recents_callout_line.png b/packages/SystemUI/res/drawable-mdpi/recents_callout_line.png
deleted file mode 100644
index 5f4c035..0000000
--- a/packages/SystemUI/res/drawable-mdpi/recents_callout_line.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/recents_thumbnail_bg.9.png b/packages/SystemUI/res/drawable-mdpi/recents_thumbnail_bg.9.png
new file mode 100644
index 0000000..82ba091
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/recents_thumbnail_bg.9.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/recents_thumbnail_bg.png b/packages/SystemUI/res/drawable-mdpi/recents_thumbnail_bg.png
deleted file mode 100644
index 23aabce..0000000
--- a/packages/SystemUI/res/drawable-mdpi/recents_thumbnail_bg.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/recents_thumbnail_bg_press.9.png b/packages/SystemUI/res/drawable-mdpi/recents_thumbnail_bg_press.9.png
new file mode 100644
index 0000000..7376085
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/recents_thumbnail_bg_press.9.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/recents_thumbnail_bg_press.png b/packages/SystemUI/res/drawable-mdpi/recents_thumbnail_bg_press.png
deleted file mode 100644
index 0b0765b..0000000
--- a/packages/SystemUI/res/drawable-mdpi/recents_thumbnail_bg_press.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw600dp-hdpi/recents_blue_glow.9.png b/packages/SystemUI/res/drawable-sw600dp-hdpi/recents_blue_glow.9.png
new file mode 100644
index 0000000..4ac131a
--- /dev/null
+++ b/packages/SystemUI/res/drawable-sw600dp-hdpi/recents_blue_glow.9.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw600dp-mdpi/recents_blue_glow.9.png b/packages/SystemUI/res/drawable-sw600dp-mdpi/recents_blue_glow.9.png
index 4f4ae78..4362836 100644
--- a/packages/SystemUI/res/drawable-sw600dp-mdpi/recents_blue_glow.9.png
+++ b/packages/SystemUI/res/drawable-sw600dp-mdpi/recents_blue_glow.9.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw600dp-mdpi/recents_callout_line.png b/packages/SystemUI/res/drawable-sw600dp-mdpi/recents_callout_line.png
deleted file mode 100644
index 5f4c035..0000000
--- a/packages/SystemUI/res/drawable-sw600dp-mdpi/recents_callout_line.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw600dp-mdpi/recents_thumbnail_bg.png b/packages/SystemUI/res/drawable-sw600dp-mdpi/recents_thumbnail_bg.png
deleted file mode 100644
index 87a67c9..0000000
--- a/packages/SystemUI/res/drawable-sw600dp-mdpi/recents_thumbnail_bg.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw600dp-mdpi/recents_thumbnail_bg_press.png b/packages/SystemUI/res/drawable-sw600dp-mdpi/recents_thumbnail_bg_press.png
deleted file mode 100644
index a1c39e6..0000000
--- a/packages/SystemUI/res/drawable-sw600dp-mdpi/recents_thumbnail_bg_press.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw600dp-xhdpi/recents_bg_protect_tile.png b/packages/SystemUI/res/drawable-sw600dp-xhdpi/recents_bg_protect_tile.png
new file mode 100644
index 0000000..59908ad
--- /dev/null
+++ b/packages/SystemUI/res/drawable-sw600dp-xhdpi/recents_bg_protect_tile.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw600dp-xhdpi/recents_blue_glow.9.png b/packages/SystemUI/res/drawable-sw600dp-xhdpi/recents_blue_glow.9.png
new file mode 100644
index 0000000..3938502
--- /dev/null
+++ b/packages/SystemUI/res/drawable-sw600dp-xhdpi/recents_blue_glow.9.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/recents_blue_glow.9.png b/packages/SystemUI/res/drawable-xhdpi/recents_blue_glow.9.png
new file mode 100644
index 0000000..e1e08c6
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/recents_blue_glow.9.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/recents_callout_line.9.png b/packages/SystemUI/res/drawable-xhdpi/recents_callout_line.9.png
new file mode 100644
index 0000000..1bd018a
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/recents_callout_line.9.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/recents_thumbnail_bg.9.png b/packages/SystemUI/res/drawable-xhdpi/recents_thumbnail_bg.9.png
new file mode 100644
index 0000000..0352aca
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/recents_thumbnail_bg.9.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/recents_thumbnail_bg_press.9.png b/packages/SystemUI/res/drawable-xhdpi/recents_thumbnail_bg_press.9.png
new file mode 100644
index 0000000..507ee22
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/recents_thumbnail_bg_press.9.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xlarge-hdpi/app_icon.png b/packages/SystemUI/res/drawable-xlarge-hdpi/app_icon.png
deleted file mode 100644
index 52354bd..0000000
--- a/packages/SystemUI/res/drawable-xlarge-hdpi/app_icon.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xlarge-hdpi/recents_bg_protect_tile.png b/packages/SystemUI/res/drawable-xlarge-hdpi/recents_bg_protect_tile.png
deleted file mode 100644
index ce01276..0000000
--- a/packages/SystemUI/res/drawable-xlarge-hdpi/recents_bg_protect_tile.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xlarge-hdpi/recents_blue_glow.9.png b/packages/SystemUI/res/drawable-xlarge-hdpi/recents_blue_glow.9.png
deleted file mode 100644
index 1848fcd..0000000
--- a/packages/SystemUI/res/drawable-xlarge-hdpi/recents_blue_glow.9.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xlarge-hdpi/recents_callout_line.png b/packages/SystemUI/res/drawable-xlarge-hdpi/recents_callout_line.png
deleted file mode 100644
index 846bc49..0000000
--- a/packages/SystemUI/res/drawable-xlarge-hdpi/recents_callout_line.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xlarge-hdpi/recents_thumbnail_bg.png b/packages/SystemUI/res/drawable-xlarge-hdpi/recents_thumbnail_bg.png
deleted file mode 100644
index a983e12..0000000
--- a/packages/SystemUI/res/drawable-xlarge-hdpi/recents_thumbnail_bg.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xlarge-hdpi/recents_thumbnail_bg_press.png b/packages/SystemUI/res/drawable-xlarge-hdpi/recents_thumbnail_bg_press.png
deleted file mode 100644
index 7c6e44e..0000000
--- a/packages/SystemUI/res/drawable-xlarge-hdpi/recents_thumbnail_bg_press.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xlarge-mdpi/app_icon.png b/packages/SystemUI/res/drawable-xlarge-mdpi/app_icon.png
deleted file mode 100644
index 001811f..0000000
--- a/packages/SystemUI/res/drawable-xlarge-mdpi/app_icon.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xlarge-mdpi/recents_bg_protect_tile.png b/packages/SystemUI/res/drawable-xlarge-mdpi/recents_bg_protect_tile.png
deleted file mode 100644
index 3d0fbf2..0000000
--- a/packages/SystemUI/res/drawable-xlarge-mdpi/recents_bg_protect_tile.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xlarge-mdpi/recents_blue_glow.9.png b/packages/SystemUI/res/drawable-xlarge-mdpi/recents_blue_glow.9.png
deleted file mode 100644
index 4362836..0000000
--- a/packages/SystemUI/res/drawable-xlarge-mdpi/recents_blue_glow.9.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xlarge-mdpi/recents_callout_line.png b/packages/SystemUI/res/drawable-xlarge-mdpi/recents_callout_line.png
deleted file mode 100644
index f4ccd7e..0000000
--- a/packages/SystemUI/res/drawable-xlarge-mdpi/recents_callout_line.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xlarge-mdpi/recents_thumbnail_bg.png b/packages/SystemUI/res/drawable-xlarge-mdpi/recents_thumbnail_bg.png
deleted file mode 100644
index 6392fa1..0000000
--- a/packages/SystemUI/res/drawable-xlarge-mdpi/recents_thumbnail_bg.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xlarge-mdpi/recents_thumbnail_bg_press.png b/packages/SystemUI/res/drawable-xlarge-mdpi/recents_thumbnail_bg_press.png
deleted file mode 100644
index f6ee596..0000000
--- a/packages/SystemUI/res/drawable-xlarge-mdpi/recents_thumbnail_bg_press.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable/recents_thumbnail_overlay.xml b/packages/SystemUI/res/drawable/recents_thumbnail_overlay.xml
index 200bac4..6d05095 100644
--- a/packages/SystemUI/res/drawable/recents_thumbnail_overlay.xml
+++ b/packages/SystemUI/res/drawable/recents_thumbnail_overlay.xml
@@ -15,5 +15,6 @@
-->
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="@drawable/recents_thumbnail_bg_press" android:state_pressed="true" />
+ <item android:drawable="@drawable/recents_thumbnail_bg" android:state_activated="true" />
<item android:drawable="@*android:color/transparent"/>
</selector>
diff --git a/packages/SystemUI/res/layout-land/status_bar_recent_item.xml b/packages/SystemUI/res/layout-land/status_bar_recent_item.xml
index 16008a3..e99888c 100644
--- a/packages/SystemUI/res/layout-land/status_bar_recent_item.xml
+++ b/packages/SystemUI/res/layout-land/status_bar_recent_item.xml
@@ -19,70 +19,74 @@
-->
<!-- android:background="@drawable/status_bar_closed_default_background" -->
-<RelativeLayout
+<FrameLayout
xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_height="wrap_content"
- android:layout_width="@dimen/status_bar_recents_thumbnail_view_width">
+ android:layout_height="match_parent"
+ android:layout_width="wrap_content">
- <FrameLayout android:id="@+id/app_thumbnail"
- android:layout_width="wrap_content"
+ <RelativeLayout android:id="@+id/recent_item"
+ android:layout_gravity="bottom"
android:layout_height="wrap_content"
- android:layout_alignParentLeft="true"
- android:layout_alignParentTop="true"
- android:layout_marginLeft="@dimen/status_bar_recents_thumbnail_left_margin"
- android:scaleType="center"
- android:clickable="true"
- android:background="@drawable/recents_thumbnail_bg"
- android:foreground="@drawable/recents_thumbnail_overlay">
- <ImageView android:id="@+id/app_thumbnail_image"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
+ android:layout_width="wrap_content"
+ android:paddingBottom="@*android:dimen/status_bar_height">
+
+ <FrameLayout android:id="@+id/app_thumbnail"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_alignParentLeft="true"
+ android:layout_alignParentTop="true"
+ android:layout_marginLeft="@dimen/status_bar_recents_thumbnail_left_margin"
+ android:scaleType="center"
+ android:clickable="true"
+ android:background="@drawable/recents_thumbnail_overlay">
+ <ImageView android:id="@+id/app_thumbnail_image"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:visibility="invisible"
+ />
+ </FrameLayout>
+
+ <ImageView android:id="@+id/app_icon"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_alignLeft="@id/app_thumbnail"
+ android:layout_alignTop="@id/app_thumbnail"
+ android:layout_marginTop="@dimen/status_bar_recents_app_icon_top_margin"
+ android:layout_marginLeft="@dimen/status_bar_recents_app_icon_left_margin"
+ android:maxWidth="@dimen/status_bar_recents_app_icon_max_width"
+ android:maxHeight="@dimen/status_bar_recents_app_icon_max_height"
+ android:adjustViewBounds="true"
android:visibility="invisible"
/>
- </FrameLayout>
- <ImageView android:id="@+id/app_icon"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_alignLeft="@id/app_thumbnail"
- android:layout_alignTop="@id/app_thumbnail"
- android:layout_marginTop="@dimen/status_bar_recents_app_icon_top_margin"
- android:layout_marginLeft="@dimen/status_bar_recents_app_icon_left_margin"
- android:maxWidth="@dimen/status_bar_recents_thumbnail_max_width"
- android:maxHeight="@dimen/status_bar_recents_thumbnail_max_height"
- android:adjustViewBounds="true"
- android:visibility="invisible"
- />
+ <TextView android:id="@+id/app_label"
+ android:layout_width="@dimen/status_bar_recents_app_label_width"
+ android:layout_height="wrap_content"
+ android:textSize="@dimen/status_bar_recents_app_label_text_size"
+ android:fadingEdge="horizontal"
+ android:fadingEdgeLength="@dimen/status_bar_recents_fading_edge_length"
+ android:scrollHorizontally="true"
+ android:layout_alignLeft="@id/app_thumbnail"
+ android:layout_below="@id/app_thumbnail"
+ android:layout_marginTop="@dimen/status_bar_recents_text_description_padding"
+ android:singleLine="true"
+ android:ellipsize="marquee"
+ android:visibility="invisible"
+ />
- <TextView android:id="@+id/app_label"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:textSize="@dimen/status_bar_recents_app_label_text_size"
- android:fadingEdge="horizontal"
- android:fadingEdgeLength="@dimen/status_bar_recents_fading_edge_length"
- android:scrollHorizontally="true"
- android:layout_alignLeft="@id/app_thumbnail"
- android:layout_below="@id/app_thumbnail"
- android:layout_marginTop="@dimen/status_bar_recents_text_description_padding"
- android:layout_marginLeft="@dimen/recents_thumbnail_bg_padding_left"
- android:singleLine="true"
- android:ellipsize="marquee"
- android:visibility="invisible"
- />
+ <TextView android:id="@+id/app_description"
+ android:layout_width="@dimen/status_bar_recents_app_label_width"
+ android:layout_height="wrap_content"
+ android:textSize="@dimen/status_bar_recents_app_description_text_size"
+ android:fadingEdge="horizontal"
+ android:fadingEdgeLength="@dimen/status_bar_recents_fading_edge_length"
+ android:scrollHorizontally="true"
+ android:layout_alignLeft="@id/app_thumbnail"
+ android:layout_below="@id/app_label"
+ android:layout_marginTop="@dimen/status_bar_recents_text_description_padding"
+ android:singleLine="true"
+ android:ellipsize="marquee"
+ />
- <TextView android:id="@+id/app_description"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:textSize="@dimen/status_bar_recents_app_description_text_size"
- android:fadingEdge="horizontal"
- android:fadingEdgeLength="@dimen/status_bar_recents_fading_edge_length"
- android:scrollHorizontally="true"
- android:layout_alignLeft="@id/app_thumbnail"
- android:layout_below="@id/app_label"
- android:layout_marginTop="@dimen/status_bar_recents_text_description_padding"
- android:layout_marginLeft="@dimen/recents_thumbnail_bg_padding_left"
- android:singleLine="true"
- android:ellipsize="marquee"
- />
-
-</RelativeLayout>
+ </RelativeLayout>
+</FrameLayout>
diff --git a/packages/SystemUI/res/layout-land/status_bar_recent_panel.xml b/packages/SystemUI/res/layout-land/status_bar_recent_panel.xml
index 20ef7cf..f84cc19 100644
--- a/packages/SystemUI/res/layout-land/status_bar_recent_panel.xml
+++ b/packages/SystemUI/res/layout-land/status_bar_recent_panel.xml
@@ -30,13 +30,12 @@
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_alignParentBottom="true"
- android:paddingBottom="@*android:dimen/status_bar_height"
android:clipToPadding="false"
android:clipChildren="false">
<LinearLayout android:id="@+id/recents_glow"
android:layout_width="wrap_content"
- android:layout_height="wrap_content"
+ android:layout_height="match_parent"
android:layout_gravity="bottom|right"
android:orientation="horizontal"
android:clipToPadding="false"
@@ -44,7 +43,7 @@
>
<com.android.systemui.recent.RecentsHorizontalScrollView android:id="@+id/recents_container"
android:layout_width="wrap_content"
- android:layout_height="wrap_content"
+ android:layout_height="match_parent"
android:layout_marginRight="@dimen/status_bar_recents_right_glow_margin"
android:divider="@null"
android:stackFromBottom="true"
@@ -58,7 +57,7 @@
<LinearLayout android:id="@+id/recents_linear_layout"
android:layout_width="wrap_content"
- android:layout_height="wrap_content"
+ android:layout_height="match_parent"
android:orientation="horizontal"
android:clipToPadding="false"
android:clipChildren="false">
diff --git a/packages/SystemUI/res/layout-port/status_bar_recent_item.xml b/packages/SystemUI/res/layout-port/status_bar_recent_item.xml
index c0fce71..73ca335 100644
--- a/packages/SystemUI/res/layout-port/status_bar_recent_item.xml
+++ b/packages/SystemUI/res/layout-port/status_bar_recent_item.xml
@@ -19,79 +19,83 @@
-->
<!-- android:background="@drawable/status_bar_closed_default_background" -->
-<RelativeLayout
+<FrameLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_height="wrap_content"
- android:layout_width="@dimen/status_bar_recents_thumbnail_view_width">
+ android:layout_width="match_parent">
- <FrameLayout android:id="@+id/app_thumbnail"
- android:layout_width="wrap_content"
+ <RelativeLayout android:id="@+id/recent_item"
android:layout_height="wrap_content"
- android:layout_alignParentLeft="true"
- android:layout_alignParentTop="true"
- android:clickable="true"
- android:layout_marginLeft="@dimen/status_bar_recents_thumbnail_left_margin"
- android:scaleType="center"
- android:background="@drawable/recents_thumbnail_bg"
- android:foreground="@drawable/recents_thumbnail_overlay">
- <ImageView android:id="@+id/app_thumbnail_image"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:visibility="invisible"
+ android:layout_width="match_parent">
+
+ <FrameLayout android:id="@+id/app_thumbnail"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_alignParentLeft="true"
+ android:layout_alignParentTop="true"
+ android:clickable="true"
+ android:layout_marginLeft="@dimen/status_bar_recents_thumbnail_left_margin"
+ android:scaleType="center"
+ android:background="@drawable/recents_thumbnail_overlay">
+ <ImageView android:id="@+id/app_thumbnail_image"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:visibility="invisible"
+ />
+ </FrameLayout>
+
+ <ImageView android:id="@+id/app_icon"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_alignLeft="@id/app_thumbnail"
+ android:layout_alignTop="@id/app_thumbnail"
+ android:layout_marginLeft="@dimen/status_bar_recents_app_icon_left_margin"
+ android:layout_marginTop="@dimen/status_bar_recents_app_icon_top_margin"
+ android:maxWidth="@dimen/status_bar_recents_app_icon_max_width"
+ android:maxHeight="@dimen/status_bar_recents_app_icon_max_height"
+ android:adjustViewBounds="true"
/>
- </FrameLayout>
- <ImageView android:id="@+id/app_icon"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_alignLeft="@id/app_thumbnail"
- android:layout_alignTop="@id/app_thumbnail"
- android:layout_marginLeft="@dimen/status_bar_recents_app_icon_left_margin"
- android:layout_marginTop="@dimen/status_bar_recents_app_icon_top_margin"
- android:maxWidth="@dimen/status_bar_recents_thumbnail_max_width"
- android:maxHeight="@dimen/status_bar_recents_thumbnail_max_height"
- android:adjustViewBounds="true"
- />
+ <TextView android:id="@+id/app_label"
+ android:layout_width="@dimen/status_bar_recents_app_label_width"
+ android:layout_height="wrap_content"
+ android:textSize="@dimen/status_bar_recents_app_label_text_size"
+ android:fadingEdge="horizontal"
+ android:fadingEdgeLength="@dimen/status_bar_recents_fading_edge_length"
+ android:scrollHorizontally="true"
+ android:layout_alignParentLeft="true"
+ android:layout_alignTop="@id/app_icon"
+ android:layout_marginLeft="@dimen/status_bar_recents_app_label_left_margin"
+ android:singleLine="true"
+ android:ellipsize="marquee"
+ />
- <TextView android:id="@+id/app_label"
- android:layout_width="@dimen/status_bar_recents_app_label_width"
- android:layout_height="wrap_content"
- android:textSize="@dimen/status_bar_recents_app_label_text_size"
- android:fadingEdge="horizontal"
- android:fadingEdgeLength="@dimen/status_bar_recents_fading_edge_length"
- android:scrollHorizontally="true"
- android:layout_alignParentLeft="true"
- android:layout_alignTop="@id/app_icon"
- android:layout_marginLeft="@dimen/status_bar_recents_app_label_left_margin"
- android:singleLine="true"
- android:ellipsize="marquee"
- />
+ <View android:id="@+id/recents_callout_line"
+ android:layout_width="@dimen/status_bar_recents_app_label_width"
+ android:layout_height="1dip"
+ android:layout_alignParentLeft="true"
+ android:layout_marginLeft="@dimen/status_bar_recents_app_label_left_margin"
+ android:layout_toLeftOf="@id/app_thumbnail"
+ android:layout_below="@id/app_label"
+ android:layout_marginRight="3dip"
+ android:layout_marginTop="3dip"
+ android:background="@drawable/recents_callout_line"
+ />
- <View android:id="@+id/recents_callout_line"
- android:layout_width="@dimen/status_bar_recents_app_label_width"
- android:layout_height="1dip"
- android:layout_alignParentLeft="true"
- android:layout_marginLeft="@dimen/status_bar_recents_app_label_left_margin"
- android:layout_toLeftOf="@id/app_thumbnail"
- android:layout_below="@id/app_label"
- android:layout_marginRight="3dip"
- android:layout_marginTop="3dip"
- android:background="@drawable/recents_callout_line"
- />
+ <TextView android:id="@+id/app_description"
+ android:layout_width="@dimen/status_bar_recents_app_label_width"
+ android:layout_height="wrap_content"
+ android:textSize="@dimen/status_bar_recents_app_description_text_size"
+ android:fadingEdge="horizontal"
+ android:fadingEdgeLength="@dimen/status_bar_recents_fading_edge_length"
+ android:scrollHorizontally="true"
+ android:layout_alignParentLeft="true"
+ android:layout_marginLeft="@dimen/status_bar_recents_app_label_left_margin"
+ android:layout_below="@id/recents_callout_line"
+ android:layout_marginTop="3dip"
+ android:singleLine="true"
+ android:ellipsize="marquee"
+ />
- <TextView android:id="@+id/app_description"
- android:layout_width="@dimen/status_bar_recents_app_label_width"
- android:layout_height="wrap_content"
- android:textSize="@dimen/status_bar_recents_app_description_text_size"
- android:fadingEdge="horizontal"
- android:fadingEdgeLength="@dimen/status_bar_recents_fading_edge_length"
- android:scrollHorizontally="true"
- android:layout_alignParentLeft="true"
- android:layout_marginLeft="@dimen/status_bar_recents_app_label_left_margin"
- android:layout_below="@id/recents_callout_line"
- android:layout_marginTop="3dip"
- android:singleLine="true"
- android:ellipsize="marquee"
- />
-
-</RelativeLayout>
+ </RelativeLayout>
+</FrameLayout>
diff --git a/packages/SystemUI/res/layout-port/status_bar_recent_panel.xml b/packages/SystemUI/res/layout-port/status_bar_recent_panel.xml
index c680b8e..dd25cf9 100644
--- a/packages/SystemUI/res/layout-port/status_bar_recent_panel.xml
+++ b/packages/SystemUI/res/layout-port/status_bar_recent_panel.xml
@@ -40,7 +40,7 @@
android:layout_marginTop="@*android:dimen/status_bar_height">
<com.android.systemui.recent.RecentsVerticalScrollView
android:id="@+id/recents_container"
- android:layout_width="@dimen/status_bar_recents_width"
+ android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginRight="0dp"
android:divider="@null"
@@ -53,7 +53,7 @@
android:clipChildren="false">
<LinearLayout android:id="@+id/recents_linear_layout"
- android:layout_width="wrap_content"
+ android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:clipToPadding="false"
diff --git a/packages/SystemUI/res/layout-sw600dp/status_bar_recent_item.xml b/packages/SystemUI/res/layout-sw600dp/status_bar_recent_item.xml
index 5306508..cab90fd 100644
--- a/packages/SystemUI/res/layout-sw600dp/status_bar_recent_item.xml
+++ b/packages/SystemUI/res/layout-sw600dp/status_bar_recent_item.xml
@@ -19,21 +19,20 @@
-->
<!-- android:background="@drawable/status_bar_closed_default_background" -->
-<RelativeLayout
+<RelativeLayout android:id="@+id/recent_item"
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_height="wrap_content"
- android:layout_width="@dimen/status_bar_recents_thumbnail_view_width">
+ android:layout_width="wrap_content">
<FrameLayout android:id="@+id/app_thumbnail"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_alignParentTop="true"
+ android:clickable="true"
android:layout_marginLeft="@dimen/status_bar_recents_thumbnail_left_margin"
android:scaleType="center"
- android:clickable="true"
- android:background="@drawable/recents_thumbnail_bg"
- android:foreground="@drawable/recents_thumbnail_overlay">
+ android:background="@drawable/recents_thumbnail_overlay">
<ImageView android:id="@+id/app_thumbnail_image"
android:layout_width="match_parent"
android:layout_height="match_parent"
@@ -48,8 +47,8 @@
android:layout_alignTop="@id/app_thumbnail"
android:layout_marginLeft="@dimen/status_bar_recents_app_icon_left_margin"
android:layout_marginTop="@dimen/status_bar_recents_app_icon_top_margin"
- android:maxWidth="@dimen/status_bar_recents_thumbnail_max_width"
- android:maxHeight="@dimen/status_bar_recents_thumbnail_max_height"
+ android:maxWidth="@dimen/status_bar_recents_app_icon_max_width"
+ android:maxHeight="@dimen/status_bar_recents_app_icon_max_height"
android:adjustViewBounds="true"
/>
diff --git a/packages/SystemUI/res/layout-sw600dp/status_bar_recent_panel.xml b/packages/SystemUI/res/layout-sw600dp/status_bar_recent_panel.xml
index 2c9a152..4ef602e 100644
--- a/packages/SystemUI/res/layout-sw600dp/status_bar_recent_panel.xml
+++ b/packages/SystemUI/res/layout-sw600dp/status_bar_recent_panel.xml
@@ -47,7 +47,7 @@
android:clipChildren="false"
>
<com.android.systemui.recent.RecentsVerticalScrollView android:id="@+id/recents_container"
- android:layout_width="@dimen/status_bar_recents_width"
+ android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginRight="@dimen/status_bar_recents_right_glow_margin"
android:divider="@null"
diff --git a/packages/SystemUI/res/layout/status_bar.xml b/packages/SystemUI/res/layout/status_bar.xml
index ed13ace..f3d0bee 100644
--- a/packages/SystemUI/res/layout/status_bar.xml
+++ b/packages/SystemUI/res/layout/status_bar.xml
@@ -71,6 +71,7 @@
</LinearLayout>
<com.android.systemui.statusbar.policy.Clock
+ android:id="@+id/clock"
android:textAppearance="@*android:style/TextAppearance.StatusBar.Icon"
android:layout_width="wrap_content"
android:layout_height="match_parent"
diff --git a/packages/SystemUI/res/values-hdpi/dimens.xml b/packages/SystemUI/res/values-hdpi/dimens.xml
index 287e0d1..6b6fd4d 100644
--- a/packages/SystemUI/res/values-hdpi/dimens.xml
+++ b/packages/SystemUI/res/values-hdpi/dimens.xml
@@ -16,12 +16,6 @@
*/
-->
<resources>
- <!-- Offsets for rendering thumbnails over drawable recents_thumbnail_bg -->
- <dimen name="recents_thumbnail_bg_padding_left">6px</dimen>
- <dimen name="recents_thumbnail_bg_padding_top">7px</dimen>
- <dimen name="recents_thumbnail_bg_padding_right">6px</dimen>
- <dimen name="recents_thumbnail_bg_padding_bottom">6px</dimen>
-
<!-- thickness (height) of each notification row, including any separators or padding -->
<!-- Note: this is 64dip + 1px divider = 97px. -->
<dimen name="notification_height">97px</dimen>
diff --git a/packages/SystemUI/res/values-land/dimens.xml b/packages/SystemUI/res/values-land/dimens.xml
index 3919685..ca74b8b 100644
--- a/packages/SystemUI/res/values-land/dimens.xml
+++ b/packages/SystemUI/res/values-land/dimens.xml
@@ -20,18 +20,14 @@
<dimen name="navigation_bar_size">@*android:dimen/navigation_bar_width</dimen>
<!-- Recent Applications parameters -->
- <!-- Width of a recent app view, including all content -->
- <dimen name="status_bar_recents_thumbnail_view_width">156dp</dimen>
<!-- How far the thumbnail for a recent app appears from left edge -->
<dimen name="status_bar_recents_thumbnail_left_margin">8dp</dimen>
<!-- How far the thumbnail for a recent app appears from top edge -->
<dimen name="status_bar_recents_thumbnail_top_margin">12dp</dimen>
- <!-- Width of scrollable area in recents -->
- <dimen name="status_bar_recents_width">128dp</dimen>
<!-- Padding for text descriptions -->
<dimen name="status_bar_recents_text_description_padding">8dp</dimen>
<!-- Width of application label text -->
- <dimen name="status_bar_recents_app_label_width">97dip</dimen>
+ <dimen name="status_bar_recents_app_label_width">156dip</dimen>
<!-- Left margin of application label text -->
<dimen name="status_bar_recents_app_label_left_margin">16dip</dimen>
<!-- Margin between recents container and glow on the right -->
diff --git a/packages/SystemUI/res/values-mdpi/dimens.xml b/packages/SystemUI/res/values-mdpi/dimens.xml
deleted file mode 100644
index 741b75a..0000000
--- a/packages/SystemUI/res/values-mdpi/dimens.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-<?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>
- <!-- Offsets for rendering thumbnails over drawable recents_thumbnail_bg -->
- <dimen name="recents_thumbnail_bg_padding_left">6px</dimen>
- <dimen name="recents_thumbnail_bg_padding_top">7px</dimen>
- <dimen name="recents_thumbnail_bg_padding_right">6px</dimen>
- <dimen name="recents_thumbnail_bg_padding_bottom">6px</dimen>
-</resources>
diff --git a/packages/SystemUI/res/values-port/dimens.xml b/packages/SystemUI/res/values-port/dimens.xml
index 54c25fa..b89a610 100644
--- a/packages/SystemUI/res/values-port/dimens.xml
+++ b/packages/SystemUI/res/values-port/dimens.xml
@@ -17,18 +17,14 @@
-->
<resources>
<!-- Recent Applications parameters -->
- <!-- Width of a recent app view, including all content -->
- <dimen name="status_bar_recents_thumbnail_view_width">156dp</dimen>
<!-- How far the thumbnail for a recent app appears from left edge -->
<dimen name="status_bar_recents_thumbnail_left_margin">110dp</dimen>
- <!-- Width of scrollable area in recents -->
- <dimen name="status_bar_recents_width">356dp</dimen>
<!-- Padding for text descriptions -->
<dimen name="status_bar_recents_text_description_padding">8dp</dimen>
<!-- Width of application label text -->
<dimen name="status_bar_recents_app_label_width">97dip</dimen>
<!-- Left margin of application label text -->
- <dimen name="status_bar_recents_app_label_left_margin">16dip</dimen>
+ <dimen name="status_bar_recents_app_label_left_margin">8dip</dimen>
<!-- Margin between recents container and glow on the right -->
<dimen name="status_bar_recents_right_glow_margin">100dip</dimen>
</resources>
diff --git a/packages/SystemUI/res/values-sw600dp/config.xml b/packages/SystemUI/res/values-sw600dp/config.xml
new file mode 100644
index 0000000..3e2ec59
--- /dev/null
+++ b/packages/SystemUI/res/values-sw600dp/config.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+** Copyright 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>
+
+ <!-- Whether we're using the tablet-optimized recents interface (we use this
+ value at runtime for some things) -->
+ <bool name="config_recents_interface_for_tablets">true</bool>
+</resources>
diff --git a/packages/SystemUI/res/values-sw600dp/dimens.xml b/packages/SystemUI/res/values-sw600dp/dimens.xml
index a5bea5c..fe9245d 100644
--- a/packages/SystemUI/res/values-sw600dp/dimens.xml
+++ b/packages/SystemUI/res/values-sw600dp/dimens.xml
@@ -30,16 +30,19 @@
<dimen name="panel_float">56dp</dimen>
<!-- Recent Applications parameters -->
- <!-- Width of a recent app view, including all content -->
- <dimen name="status_bar_recents_thumbnail_view_width">156dp</dimen>
<!-- How far the thumbnail for a recent app appears from left edge -->
- <dimen name="status_bar_recents_thumbnail_left_margin">110dp</dimen>
+ <dimen name="status_bar_recents_thumbnail_left_margin">121dp</dimen>
<!-- Upper width limit for application icon -->
- <dimen name="status_bar_recents_thumbnail_max_width">64dp</dimen>
+ <dimen name="status_bar_recents_app_icon_max_width">64dp</dimen>
<!-- Upper height limit for application icon -->
- <dimen name="status_bar_recents_thumbnail_max_height">64dp</dimen>
- <!-- Width of scrollable area in recents -->
- <dimen name="status_bar_recents_width">356dp</dimen>
+ <dimen name="status_bar_recents_app_icon_max_height">64dp</dimen>
+
+ <!-- Size of application icon -->
+ <dimen name="status_bar_recents_thumbnail_width">245dp</dimen>
+ <dimen name="status_bar_recents_thumbnail_height">144dp</dimen>
+
+ <!-- Width of recents panel -->
+ <dimen name="status_bar_recents_width">600dp</dimen>
<!-- Padding for text descriptions -->
<dimen name="status_bar_recents_text_description_padding">8dp</dimen>
<!-- Size of application label text -->
@@ -55,12 +58,6 @@
<!-- Margin between recents container and glow on the right -->
<dimen name="status_bar_recents_right_glow_margin">100dip</dimen>
- <!-- Offsets for rendering thumbnails over drawable recents_thumbnail_bg -->
- <dimen name="recents_thumbnail_bg_padding_left">15px</dimen>
- <dimen name="recents_thumbnail_bg_padding_top">8px</dimen>
- <dimen name="recents_thumbnail_bg_padding_right">12px</dimen>
- <dimen name="recents_thumbnail_bg_padding_bottom">8px</dimen>
-
<!-- Where to place the app icon over the thumbnail -->
<dimen name="status_bar_recents_app_icon_left_margin">13dp</dimen>
<dimen name="status_bar_recents_app_icon_top_margin">13dp</dimen>
diff --git a/packages/SystemUI/res/values/colors.xml b/packages/SystemUI/res/values/colors.xml
index 5d14fa8..4c222f9 100644
--- a/packages/SystemUI/res/values/colors.xml
+++ b/packages/SystemUI/res/values/colors.xml
@@ -22,5 +22,6 @@
<drawable name="ticker_background_color">#ff1d1d1d</drawable>
<drawable name="status_bar_background">#ff000000</drawable>
<drawable name="status_bar_recents_background">#b3000000</drawable>
+ <drawable name="status_bar_recents_app_thumbnail_background">#88000000</drawable>
<drawable name="status_bar_notification_row_background_color">#ff000000</drawable>
</resources>
diff --git a/packages/SystemUI/res/values/config.xml b/packages/SystemUI/res/values/config.xml
index d7d7817..4ac89b2 100644
--- a/packages/SystemUI/res/values/config.xml
+++ b/packages/SystemUI/res/values/config.xml
@@ -21,6 +21,10 @@
for different hardware and product builds. -->
<resources>
+ <!-- Whether we're using the tablet-optimized recents interface (we use this
+ value at runtime for some things) -->
+ <bool name="config_recents_interface_for_tablets">false</bool>
+
<!-- Control whether status bar should distinguish HSPA data icon form UMTS
data icon on devices -->
<bool name="config_hspa_data_distinguishable">false</bool>
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index f633825c..d0ece6c 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -21,17 +21,21 @@
<!-- Recent Applications parameters -->
<!-- Upper width limit for application icon -->
- <dimen name="status_bar_recents_thumbnail_max_width">64dp</dimen>
+ <dimen name="status_bar_recents_app_icon_max_width">64dp</dimen>
<!-- Upper height limit for application icon -->
- <dimen name="status_bar_recents_thumbnail_max_height">64dp</dimen>
+ <dimen name="status_bar_recents_app_icon_max_height">64dp</dimen>
<!-- Where to place the app icon over the thumbnail -->
<dimen name="status_bar_recents_app_icon_left_margin">13dp</dimen>
<dimen name="status_bar_recents_app_icon_top_margin">13dp</dimen>
+ <!-- Size of application thumbnail -->
+ <dimen name="status_bar_recents_thumbnail_width">164dp</dimen>
+ <dimen name="status_bar_recents_thumbnail_height">164dp</dimen>
+
<!-- Size of application label text -->
- <dimen name="status_bar_recents_app_label_text_size">18dip</dimen>
+ <dimen name="status_bar_recents_app_label_text_size">16dip</dimen>
<!-- Size of application description text -->
- <dimen name="status_bar_recents_app_description_text_size">18dip</dimen>
+ <dimen name="status_bar_recents_app_description_text_size">16dip</dimen>
<!-- Size of fading edge for scroll effect -->
<dimen name="status_bar_recents_fading_edge_length">20dip</dimen>
<!-- Margin between recents container and glow on the right -->
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index 7779703..bad7e1f 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -36,10 +36,10 @@
<string name="status_bar_please_disturb_button">Show notifications</string>
<!-- Title shown in recents popup for removing an application from the list -->
- <string name="status_bar_recent_remove_item_title">Remove</string>
+ <string name="status_bar_recent_remove_item_title">Remove from list</string>
<!-- Title shown in recents popup for inspecting an application's properties -->
- <string name="status_bar_recent_inspect_item_title">Inspect</string>
+ <string name="status_bar_recent_inspect_item_title">App info</string>
<!-- The label in the bar at the top of the status bar when there are no notifications
showing. [CHAR LIMIT=40]-->
diff --git a/packages/SystemUI/src/com/android/systemui/SwipeHelper.java b/packages/SystemUI/src/com/android/systemui/SwipeHelper.java
index e7ed052..14743f4 100644
--- a/packages/SystemUI/src/com/android/systemui/SwipeHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/SwipeHelper.java
@@ -33,20 +33,19 @@
private static final boolean DEBUG = false;
private static final boolean DEBUG_INVALIDATE = false;
private static final boolean SLOW_ANIMATIONS = false; // DEBUG;
+ private static final boolean CONSTRAIN_SWIPE = true;
+ private static final boolean FADE_OUT_DURING_SWIPE = true;
+ private static final boolean DISMISS_IF_SWIPED_FAR_ENOUGH = true;
public static final int X = 0;
public static final int Y = 1;
- private boolean CONSTRAIN_SWIPE = true;
- private boolean FADE_OUT_DURING_SWIPE = true;
- private boolean DISMISS_IF_SWIPED_FAR_ENOUGH = true;
-
private float SWIPE_ESCAPE_VELOCITY = 100f; // dp/sec
private int MAX_ESCAPE_ANIMATION_DURATION = 500; // ms
private int MAX_DISMISS_VELOCITY = 1000; // dp/sec
private static final int SNAP_ANIM_LEN = SLOW_ANIMATIONS ? 1000 : 250; // ms
- public static float ALPHA_FADE_START = 0.8f; // fraction of thumbnail width
+ public static float ALPHA_FADE_START = 0f; // fraction of thumbnail width
// where fade starts
static final float ALPHA_FADE_END = 0.5f; // fraction of thumbnail width
// beyond which alpha->0
@@ -59,6 +58,8 @@
private float mInitialTouchPos;
private boolean mDragging;
private View mCurrView;
+ private View mCurrAnimView;
+ private boolean mCanCurrViewBeDimissed;
private float mDensityScale;
public SwipeHelper(int swipeDirection, Callback callback, float densityScale,
@@ -82,8 +83,8 @@
return mSwipeDirection == X ? ev.getX() : ev.getY();
}
- private float getPos(View v) {
- return mSwipeDirection == X ? v.getX() : v.getY();
+ private float getTranslation(View v) {
+ return mSwipeDirection == X ? v.getTranslationX() : v.getTranslationY();
}
private float getVelocity(VelocityTracker vt) {
@@ -115,19 +116,15 @@
v.getMeasuredHeight();
}
- private float getContentSize(View v) {
- View content = mCallback.getChildContentView(v);
- return getSize(content);
- }
-
- private float getAlphaForOffset(View view, float thumbSize) {
- final float fadeSize = ALPHA_FADE_END * thumbSize;
+ private float getAlphaForOffset(View view) {
+ float viewSize = getSize(view);
+ final float fadeSize = ALPHA_FADE_END * viewSize;
float result = 1.0f;
- float pos = getPos(view);
- if (pos >= thumbSize * ALPHA_FADE_START) {
- result = 1.0f - (pos - thumbSize * ALPHA_FADE_START) / fadeSize;
- } else if (pos < thumbSize * (1.0f - ALPHA_FADE_START)) {
- result = 1.0f + (thumbSize * ALPHA_FADE_START + pos) / fadeSize;
+ float pos = getTranslation(view);
+ if (pos >= viewSize * ALPHA_FADE_START) {
+ result = 1.0f - (pos - viewSize * ALPHA_FADE_START) / fadeSize;
+ } else if (pos < viewSize * (1.0f - ALPHA_FADE_START)) {
+ result = 1.0f + (viewSize * ALPHA_FADE_START + pos) / fadeSize;
}
return result;
}
@@ -168,6 +165,8 @@
case MotionEvent.ACTION_DOWN:
mDragging = false;
mCurrView = mCallback.getChildAtPosition(ev);
+ mCurrAnimView = mCallback.getChildContentView(mCurrView);
+ mCanCurrViewBeDimissed = mCallback.canChildBeDismissed(mCurrView);
mVelocityTracker.clear();
mVelocityTracker.addMovement(ev);
mInitialTouchPos = getPos(ev);
@@ -180,21 +179,24 @@
if (Math.abs(delta) > mPagingTouchSlop) {
mCallback.onBeginDrag(mCurrView);
mDragging = true;
- mInitialTouchPos = getPos(ev) - getPos(mCurrView);
+ mInitialTouchPos = getPos(ev) - getTranslation(mCurrAnimView);
}
}
break;
case MotionEvent.ACTION_UP:
mDragging = false;
mCurrView = null;
+ mCurrAnimView = null;
break;
}
return mDragging;
}
- public void dismissChild(final View animView, float velocity) {
+ public void dismissChild(final View view, float velocity) {
+ final View animView = mCallback.getChildContentView(view);
+ final boolean canAnimViewBeDismissed = mCallback.canChildBeDismissed(view);
float newPos;
- if (velocity < 0 || (velocity == 0 && getPos(animView) < 0)) {
+ if (velocity < 0 || (velocity == 0 && getTranslation(animView) < 0)) {
newPos = -getSize(animView);
} else {
newPos = getSize(animView);
@@ -202,7 +204,7 @@
int duration = MAX_ESCAPE_ANIMATION_DURATION;
if (velocity != 0) {
duration = Math.min(duration,
- (int) (Math.abs(newPos - getPos(animView)) * 1000f / Math
+ (int) (Math.abs(newPos - getTranslation(animView)) * 1000f / Math
.abs(velocity)));
}
ObjectAnimator anim = createTranslationAnimation(animView, newPos);
@@ -216,17 +218,17 @@
}
public void onAnimationEnd(Animator animation) {
- mCallback.onChildDismissed(animView);
+ mCallback.onChildDismissed(view);
}
public void onAnimationCancel(Animator animation) {
- mCallback.onChildDismissed(animView);
+ mCallback.onChildDismissed(view);
}
});
anim.addUpdateListener(new AnimatorUpdateListener() {
public void onAnimationUpdate(ValueAnimator animation) {
- if (FADE_OUT_DURING_SWIPE) {
- animView.setAlpha(getAlphaForOffset(animView, getContentSize(animView)));
+ if (FADE_OUT_DURING_SWIPE && canAnimViewBeDismissed) {
+ animView.setAlpha(getAlphaForOffset(animView));
}
invalidateGlobalRegion(animView);
}
@@ -234,14 +236,16 @@
anim.start();
}
- public void snapChild(final View animView, float velocity) {
+ public void snapChild(final View view, float velocity) {
+ final View animView = mCallback.getChildContentView(view);
+ final boolean canAnimViewBeDismissed = mCallback.canChildBeDismissed(animView);
ObjectAnimator anim = createTranslationAnimation(animView, 0);
int duration = SNAP_ANIM_LEN;
anim.setDuration(duration);
anim.addUpdateListener(new AnimatorUpdateListener() {
public void onAnimationUpdate(ValueAnimator animation) {
- if (FADE_OUT_DURING_SWIPE) {
- animView.setAlpha(getAlphaForOffset(animView, getContentSize(animView)));
+ if (FADE_OUT_DURING_SWIPE && canAnimViewBeDismissed) {
+ animView.setAlpha(getAlphaForOffset(animView));
}
invalidateGlobalRegion(animView);
}
@@ -264,7 +268,7 @@
// don't let items that can't be dismissed be dragged more than
// maxScrollDistance
if (CONSTRAIN_SWIPE && !mCallback.canChildBeDismissed(mCurrView)) {
- float size = getSize(mCurrView);
+ float size = getSize(mCurrAnimView);
float maxScrollDistance = 0.15f * size;
if (Math.abs(delta) >= size) {
delta = delta > 0 ? maxScrollDistance : -maxScrollDistance;
@@ -272,9 +276,9 @@
delta = maxScrollDistance * (float) Math.sin((delta/size)*(Math.PI/2));
}
}
- setTranslation(mCurrView, delta);
- if (FADE_OUT_DURING_SWIPE) {
- mCurrView.setAlpha(getAlphaForOffset(mCurrView, getContentSize(mCurrView)));
+ setTranslation(mCurrAnimView, delta);
+ if (FADE_OUT_DURING_SWIPE && mCanCurrViewBeDimissed) {
+ mCurrAnimView.setAlpha(getAlphaForOffset(mCurrAnimView));
}
invalidateGlobalRegion(mCurrView);
}
@@ -290,10 +294,10 @@
// Decide whether to dismiss the current view
boolean childSwipedFarEnough = DISMISS_IF_SWIPED_FAR_ENOUGH &&
- Math.abs(getPos(mCurrView)) > 0.4 * getSize(mCurrView);
+ Math.abs(getTranslation(mCurrAnimView)) > 0.4 * getSize(mCurrAnimView);
boolean childSwipedFastEnough = (Math.abs(velocity) > escapeVelocity) &&
(Math.abs(velocity) > Math.abs(perpendicularVelocity)) &&
- (velocity > 0) == (getPos(mCurrView) > 0);
+ (velocity > 0) == (getTranslation(mCurrAnimView) > 0);
boolean dismissChild = mCallback.canChildBeDismissed(mCurrView) &&
(childSwipedFastEnough || childSwipedFarEnough);
@@ -303,6 +307,7 @@
dismissChild(mCurrView, childSwipedFastEnough ? velocity : 0f);
} else {
// snappity
+ mCallback.onDragCancelled(mCurrView);
snapChild(mCurrView, velocity);
}
}
@@ -321,5 +326,7 @@
void onBeginDrag(View v);
void onChildDismissed(View v);
+
+ void onDragCancelled(View v);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/recent/RecentsCallback.java b/packages/SystemUI/src/com/android/systemui/recent/RecentsCallback.java
index 5609ead..2de4185 100644
--- a/packages/SystemUI/src/com/android/systemui/recent/RecentsCallback.java
+++ b/packages/SystemUI/src/com/android/systemui/recent/RecentsCallback.java
@@ -27,4 +27,8 @@
void handleOnClick(View selectedView);
void handleSwipe(View selectedView);
void handleLongPress(View selectedView, View anchorView);
+ void handleShowBackground(boolean show);
+
+ // TODO: find another way to get this info from RecentsPanelView
+ boolean isRecentsVisible();
}
diff --git a/packages/SystemUI/src/com/android/systemui/recent/RecentsHorizontalScrollView.java b/packages/SystemUI/src/com/android/systemui/recent/RecentsHorizontalScrollView.java
index 8da2db6..85cde7c 100644
--- a/packages/SystemUI/src/com/android/systemui/recent/RecentsHorizontalScrollView.java
+++ b/packages/SystemUI/src/com/android/systemui/recent/RecentsHorizontalScrollView.java
@@ -20,6 +20,7 @@
import android.content.Context;
import android.content.res.Configuration;
import android.database.DataSetObserver;
+import android.graphics.Canvas;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
@@ -41,6 +42,8 @@
private RecentsCallback mCallback;
protected int mLastScrollPosition;
private SwipeHelper mSwipeHelper;
+ private RecentsScrollViewPerformanceHelper mPerformanceHelper;
+
private OnLongClickListener mOnLongClick = new OnLongClickListener() {
public boolean onLongClick(View v) {
final View anchorView = v.findViewById(R.id.app_description);
@@ -49,15 +52,12 @@
}
};
- public RecentsHorizontalScrollView(Context context) {
- this(context, null);
- }
-
public RecentsHorizontalScrollView(Context context, AttributeSet attrs) {
super(context, attrs, 0);
float densityScale = getResources().getDisplayMetrics().density;
float pagingTouchSlop = ViewConfiguration.get(mContext).getScaledPagingTouchSlop();
mSwipeHelper = new SwipeHelper(SwipeHelper.Y, this, densityScale, pagingTouchSlop);
+ mPerformanceHelper = RecentsScrollViewPerformanceHelper.create(context, attrs, this, false);
}
private int scrollPositionOfMostRecent() {
@@ -71,7 +71,11 @@
view.setLongClickable(true);
view.setOnLongClickListener(mOnLongClick);
- final View thumbnail = getChildContentView(view);
+ if (mPerformanceHelper != null) {
+ mPerformanceHelper.addViewCallback(view);
+ }
+
+ final View thumbnail = view.findViewById(R.id.app_thumbnail);
// thumbnail is set to clickable in the layout file
thumbnail.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
@@ -123,6 +127,11 @@
// We do this so the underlying ScrollView knows that it won't get
// the chance to intercept events anymore
requestDisallowInterceptTouchEvent(true);
+ v.setActivated(true);
+ }
+
+ public void onDragCancelled(View v) {
+ v.setActivated(false);
}
public View getChildAtPosition(MotionEvent ev) {
@@ -139,7 +148,60 @@
}
public View getChildContentView(View v) {
- return v.findViewById(R.id.app_thumbnail);
+ return v.findViewById(R.id.recent_item);
+ }
+
+ @Override
+ protected void onLayout (boolean changed, int left, int top, int right, int bottom) {
+ super.onLayout(changed, left, top, right, bottom);
+ if (mPerformanceHelper != null) {
+ mPerformanceHelper.onLayoutCallback();
+ }
+ }
+
+ @Override
+ public void draw(Canvas canvas) {
+ super.draw(canvas);
+
+ if (mPerformanceHelper != null) {
+ int paddingLeft = mPaddingLeft;
+ final boolean offsetRequired = isPaddingOffsetRequired();
+ if (offsetRequired) {
+ paddingLeft += getLeftPaddingOffset();
+ }
+
+ int left = mScrollX + paddingLeft;
+ int right = left + mRight - mLeft - mPaddingRight - paddingLeft;
+ int top = mScrollY + getFadeTop(offsetRequired);
+ int bottom = top + getFadeHeight(offsetRequired);
+
+ if (offsetRequired) {
+ right += getRightPaddingOffset();
+ bottom += getBottomPaddingOffset();
+ }
+ mPerformanceHelper.drawCallback(canvas,
+ left, right, top, bottom, mScrollX, mScrollY,
+ 0, 0,
+ getLeftFadingEdgeStrength(), getRightFadingEdgeStrength());
+ }
+ }
+
+ @Override
+ public int getVerticalFadingEdgeLength() {
+ if (mPerformanceHelper != null) {
+ return mPerformanceHelper.getVerticalFadingEdgeLengthCallback();
+ } else {
+ return super.getVerticalFadingEdgeLength();
+ }
+ }
+
+ @Override
+ public int getHorizontalFadingEdgeLength() {
+ if (mPerformanceHelper != null) {
+ return mPerformanceHelper.getHorizontalFadingEdgeLengthCallback();
+ } else {
+ return super.getHorizontalFadingEdgeLength();
+ }
}
@Override
@@ -153,6 +215,14 @@
}
@Override
+ public void onAttachedToWindow() {
+ if (mPerformanceHelper != null) {
+ mPerformanceHelper.onAttachedToWindowCallback(
+ mCallback, mLinearLayout, isHardwareAccelerated());
+ }
+ }
+
+ @Override
protected void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
float densityScale = getResources().getDisplayMetrics().density;
@@ -192,6 +262,12 @@
});
}
+ public void onRecentsVisibilityChanged() {
+ if (mPerformanceHelper != null) {
+ mPerformanceHelper.updateShowBackground();
+ }
+ }
+
@Override
protected void onVisibilityChanged(View changedView, int visibility) {
super.onVisibilityChanged(changedView, visibility);
@@ -220,6 +296,9 @@
@Override
public void setLayoutTransition(LayoutTransition transition) {
+ if (mPerformanceHelper != null) {
+ mPerformanceHelper.setLayoutTransitionCallback(transition);
+ }
// The layout transition applies to our embedded LinearLayout
mLinearLayout.setLayoutTransition(transition);
}
diff --git a/packages/SystemUI/src/com/android/systemui/recent/RecentsListView.java b/packages/SystemUI/src/com/android/systemui/recent/RecentsListView.java
deleted file mode 100644
index d8b086b..0000000
--- a/packages/SystemUI/src/com/android/systemui/recent/RecentsListView.java
+++ /dev/null
@@ -1,92 +0,0 @@
-/*
- * 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.systemui.recent;
-
-import android.content.Context;
-import android.util.AttributeSet;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.widget.ListView;
-
-import com.android.systemui.R;
-
-public class RecentsListView extends ListView {
- private int mLastVisiblePosition;
- private RecentsCallback mCallback;
-
- public RecentsListView(Context context) {
- this(context, null);
- }
-
- public RecentsListView(Context context, AttributeSet attrs) {
- super(context, attrs, 0);
- }
-
- @Override
- protected void onFinishInflate() {
- super.onFinishInflate();
- LayoutInflater inflater = (LayoutInflater)
- mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
-
- View footer = inflater.inflate(R.layout.status_bar_recent_panel_footer, this, false);
- setScrollbarFadingEnabled(true);
- addFooterView(footer, null, false);
- final int leftPadding = mContext.getResources()
- .getDimensionPixelOffset(R.dimen.status_bar_recents_thumbnail_left_margin);
- setOverScrollEffectPadding(leftPadding, 0);
- }
-
- @Override
- protected void onSizeChanged(int w, int h, int oldw, int oldh) {
- super.onSizeChanged(w, h, oldw, oldh);
- // Keep track of the last visible item in the list so we can restore it
- // to the bottom when the orientation changes.
- final int childCount = getChildCount();
- if (childCount > 0) {
- mLastVisiblePosition = getFirstVisiblePosition() + childCount - 1;
- View view = getChildAt(childCount - 1);
- final int distanceFromBottom = getHeight() - view.getTop();
-
- // This has to happen post-layout, so run it "in the future"
- post(new Runnable() {
- public void run() {
- setSelectionFromTop(mLastVisiblePosition, getHeight() - distanceFromBottom);
- }
- });
- }
- }
-
- @Override
- protected void onVisibilityChanged(View changedView, int visibility) {
- super.onVisibilityChanged(changedView, visibility);
- // scroll to bottom after reloading
- int count = getAdapter().getCount();
- mLastVisiblePosition = count - 1;
- if (visibility == View.VISIBLE && changedView == this) {
- post(new Runnable() {
- public void run() {
- setSelection(mLastVisiblePosition);
- }
- });
- }
- }
-
- public void setCallback(RecentsCallback callback) {
- mCallback = callback;
- }
-
-}
diff --git a/packages/SystemUI/src/com/android/systemui/recent/RecentsPanelView.java b/packages/SystemUI/src/com/android/systemui/recent/RecentsPanelView.java
index 9cc2c29..e59c109 100644
--- a/packages/SystemUI/src/com/android/systemui/recent/RecentsPanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/recent/RecentsPanelView.java
@@ -56,7 +56,6 @@
import android.view.ViewGroup;
import android.view.animation.AnimationUtils;
import android.widget.AdapterView;
-import android.widget.AdapterView.OnItemClickListener;
import android.widget.BaseAdapter;
import android.widget.HorizontalScrollView;
import android.widget.ImageView;
@@ -64,6 +63,7 @@
import android.widget.RelativeLayout;
import android.widget.ScrollView;
import android.widget.TextView;
+import android.widget.AdapterView.OnItemClickListener;
import com.android.systemui.R;
import com.android.systemui.statusbar.StatusBar;
@@ -73,7 +73,7 @@
public class RecentsPanelView extends RelativeLayout
implements OnItemClickListener, RecentsCallback, StatusBarPanel, Animator.AnimatorListener {
- static final String TAG = "RecentsListView";
+ static final String TAG = "RecentsPanelView";
static final boolean DEBUG = TabletStatusBar.DEBUG || PhoneStatusBar.DEBUG || false;
private static final int DISPLAY_TASKS = 20;
private static final int MAX_TASKS = DISPLAY_TASKS + 1; // allow extra for non-apps
@@ -84,12 +84,8 @@
private View mRecentsScrim;
private View mRecentsGlowView;
private ViewGroup mRecentsContainer;
- private Bitmap mGlowBitmap;
- // TODO: add these widgets attributes to the layout file
- private int mGlowBitmapPaddingLeftPx;
- private int mGlowBitmapPaddingTopPx;
- private int mGlowBitmapPaddingRightPx;
- private int mGlowBitmapPaddingBottomPx;
+ private Bitmap mAppThumbnailBackground;
+
private boolean mShowing;
private Choreographer mChoreo;
private View mRecentsDismissButton;
@@ -129,7 +125,7 @@
}
public void setThumbnail(Bitmap thumbnail) {
- mThumbnail = compositeBitmap(mGlowBitmap, thumbnail);
+ mThumbnail = compositeBitmap(mAppThumbnailBackground, thumbnail);
}
public Bitmap getThumbnail() {
@@ -178,7 +174,7 @@
public View getView(int position, View convertView, ViewGroup parent) {
ViewHolder holder;
if (convertView == null) {
- convertView = mInflater.inflate(R.layout.status_bar_recent_item, null);
+ convertView = mInflater.inflate(R.layout.status_bar_recent_item, parent, false);
holder = new ViewHolder();
holder.thumbnailView = convertView.findViewById(R.id.app_thumbnail);
holder.thumbnailViewImage = (ImageView) convertView.findViewById(
@@ -247,6 +243,28 @@
}
}
+ public void hide(boolean animate) {
+ mShowing = false;
+ if (!animate) {
+ setVisibility(View.GONE);
+ }
+ if (mBar != null) {
+ mBar.animateCollapse();
+ }
+ }
+
+ public void handleShowBackground(boolean show) {
+ if (show) {
+ mRecentsScrim.setBackgroundResource(R.drawable.status_bar_recents_background);
+ } else {
+ mRecentsScrim.setBackgroundDrawable(null);
+ }
+ }
+
+ public boolean isRecentsVisible() {
+ return getVisibility() == VISIBLE;
+ }
+
public void onAnimationCancel(Animator animation) {
}
@@ -315,15 +333,12 @@
mIconDpi = xlarge ? DisplayMetrics.DENSITY_HIGH : res.getDisplayMetrics().densityDpi;
- mGlowBitmap = BitmapFactory.decodeResource(res, R.drawable.recents_thumbnail_bg);
- mGlowBitmapPaddingLeftPx =
- res.getDimensionPixelSize(R.dimen.recents_thumbnail_bg_padding_left);
- mGlowBitmapPaddingTopPx =
- res.getDimensionPixelSize(R.dimen.recents_thumbnail_bg_padding_top);
- mGlowBitmapPaddingRightPx =
- res.getDimensionPixelSize(R.dimen.recents_thumbnail_bg_padding_right);
- mGlowBitmapPaddingBottomPx =
- res.getDimensionPixelSize(R.dimen.recents_thumbnail_bg_padding_bottom);
+ int width = (int) res.getDimension(R.dimen.status_bar_recents_thumbnail_width);
+ int height = (int) res.getDimension(R.dimen.status_bar_recents_thumbnail_height);
+ int color = res.getColor(R.drawable.status_bar_recents_app_thumbnail_background);
+ mAppThumbnailBackground = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
+ Canvas c = new Canvas(mAppThumbnailBackground);
+ c.drawColor(color);
}
@Override
@@ -332,12 +347,7 @@
mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
mRecentsContainer = (ViewGroup) findViewById(R.id.recents_container);
mListAdapter = new ActivityDescriptionAdapter(mContext);
- if (mRecentsContainer instanceof RecentsListView) {
- RecentsListView listView = (RecentsListView) mRecentsContainer;
- listView.setAdapter(mListAdapter);
- listView.setOnItemClickListener(this);
- listView.setCallback(this);
- } else if (mRecentsContainer instanceof RecentsHorizontalScrollView){
+ if (mRecentsContainer instanceof RecentsHorizontalScrollView){
RecentsHorizontalScrollView scrollView
= (RecentsHorizontalScrollView) mRecentsContainer;
scrollView.setAdapter(mListAdapter);
@@ -349,7 +359,7 @@
scrollView.setCallback(this);
}
else {
- throw new IllegalArgumentException("missing RecentsListView/RecentsScrollView");
+ throw new IllegalArgumentException("missing Recents[Horizontal]ScrollView");
}
@@ -382,6 +392,14 @@
if (visibility == View.VISIBLE && changedView == this) {
refreshApplicationList();
}
+
+ if (mRecentsContainer instanceof RecentsHorizontalScrollView) {
+ ((RecentsHorizontalScrollView) mRecentsContainer).onRecentsVisibilityChanged();
+ } else if (mRecentsContainer instanceof RecentsVerticalScrollView) {
+ ((RecentsVerticalScrollView) mRecentsContainer).onRecentsVisibilityChanged();
+ } else {
+ throw new IllegalArgumentException("missing Recents[Horizontal]ScrollView");
+ }
}
Drawable getFullResDefaultActivityIcon() {
@@ -555,6 +573,9 @@
mThumbnailLoader = null;
}
mActivityDescriptions = getRecentTasks();
+ for (ActivityDescription ad : mActivityDescriptions) {
+ ad.setThumbnail(mAppThumbnailBackground);
+ }
mListAdapter.notifyDataSetInvalidated();
if (mActivityDescriptions.size() > 0) {
if (DEBUG) Log.v(TAG, "Showing " + mActivityDescriptions.size() + " apps");
@@ -629,14 +650,8 @@
paint.setAntiAlias(true);
paint.setFilterBitmap(true);
paint.setAlpha(255);
- final int srcWidth = thumbnail.getWidth();
- final int srcHeight = thumbnail.getHeight();
- if (DEBUG) Log.v(TAG, "Source thumb: " + srcWidth + "x" + srcHeight);
- canvas.drawBitmap(thumbnail,
- new Rect(0, 0, srcWidth-1, srcHeight-1),
- new RectF(mGlowBitmapPaddingLeftPx, mGlowBitmapPaddingTopPx,
- outBitmap.getWidth() - mGlowBitmapPaddingRightPx,
- outBitmap.getHeight() - mGlowBitmapPaddingBottomPx), paint);
+ canvas.drawBitmap(thumbnail, null,
+ new RectF(0, 0, outBitmap.getWidth(), outBitmap.getHeight()), paint);
canvas.setBitmap(null);
}
return outBitmap;
@@ -649,15 +664,6 @@
mRecentsGlowView.setVisibility(items > 0 ? View.VISIBLE : View.GONE);
}
- public void hide(boolean animate) {
- if (!animate) {
- setVisibility(View.GONE);
- }
- if (mBar != null) {
- mBar.animateCollapse();
- }
- }
-
public void handleOnClick(View view) {
ActivityDescription ad = ((ViewHolder) view.getTag()).activityDescription;
final Context context = view.getContext();
diff --git a/packages/SystemUI/src/com/android/systemui/recent/RecentsScrollViewPerformanceHelper.java b/packages/SystemUI/src/com/android/systemui/recent/RecentsScrollViewPerformanceHelper.java
new file mode 100644
index 0000000..b7e656e
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/recent/RecentsScrollViewPerformanceHelper.java
@@ -0,0 +1,304 @@
+/*
+ * 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.systemui.recent;
+
+import android.animation.LayoutTransition;
+import android.content.Context;
+import android.content.res.TypedArray;
+import android.graphics.Canvas;
+import android.graphics.LinearGradient;
+import android.graphics.Matrix;
+import android.graphics.Paint;
+import android.graphics.Shader;
+import android.graphics.drawable.Drawable;
+import android.util.AttributeSet;
+import android.view.View;
+import android.view.ViewConfiguration;
+import android.view.ViewGroup;
+import android.widget.LinearLayout;
+
+import com.android.systemui.R;
+
+public class RecentsScrollViewPerformanceHelper {
+ public static final boolean OPTIMIZE_SW_RENDERED_RECENTS = true;
+ public static final boolean USE_DARK_FADE_IN_HW_ACCELERATED_MODE = true;
+ private View mScrollView;
+ private LinearLayout mLinearLayout;
+ private RecentsCallback mCallback;
+
+ private boolean mShowBackground = false;
+ private int mFadingEdgeLength;
+ private Drawable.ConstantState mBackgroundDrawable;
+ private Context mContext;
+ private boolean mIsVertical;
+ private boolean mFirstTime = true;
+ private boolean mSoftwareRendered = false;
+ private boolean mAttachedToWindow = false;
+
+ public static RecentsScrollViewPerformanceHelper create(Context context,
+ AttributeSet attrs, View scrollView, boolean isVertical) {
+ boolean isTablet = context.getResources().
+ getBoolean(R.bool.config_recents_interface_for_tablets);
+ if (!isTablet && (OPTIMIZE_SW_RENDERED_RECENTS || USE_DARK_FADE_IN_HW_ACCELERATED_MODE)) {
+ return new RecentsScrollViewPerformanceHelper(context, attrs, scrollView, isVertical);
+ } else {
+ return null;
+ }
+ }
+
+ public RecentsScrollViewPerformanceHelper(Context context,
+ AttributeSet attrs, View scrollView, boolean isVertical) {
+ mScrollView = scrollView;
+ mContext = context;
+ TypedArray a = context.obtainStyledAttributes(attrs, com.android.internal.R.styleable.View);
+ mFadingEdgeLength = a.getDimensionPixelSize(android.R.styleable.View_fadingEdgeLength,
+ ViewConfiguration.get(context).getScaledFadingEdgeLength());
+ mIsVertical = isVertical;
+ }
+
+ public void onAttachedToWindowCallback(
+ RecentsCallback callback, LinearLayout layout, boolean hardwareAccelerated) {
+ mSoftwareRendered = !hardwareAccelerated;
+ if ((mSoftwareRendered && OPTIMIZE_SW_RENDERED_RECENTS)
+ || USE_DARK_FADE_IN_HW_ACCELERATED_MODE) {
+ mScrollView.setVerticalFadingEdgeEnabled(false);
+ mScrollView.setHorizontalFadingEdgeEnabled(false);
+ }
+ if (mSoftwareRendered && OPTIMIZE_SW_RENDERED_RECENTS) {
+ mCallback = callback;
+ mLinearLayout = layout;
+ mAttachedToWindow = true;
+ mBackgroundDrawable = mContext.getResources()
+ .getDrawable(R.drawable.status_bar_recents_background).getConstantState();
+ updateShowBackground();
+ }
+
+ }
+
+ public void addViewCallback(View newLinearLayoutChild) {
+ if (mSoftwareRendered && OPTIMIZE_SW_RENDERED_RECENTS) {
+ final View view = newLinearLayoutChild;
+ if (mShowBackground) {
+ view.setBackgroundDrawable(mBackgroundDrawable.newDrawable());
+ view.setDrawingCacheEnabled(true);
+ view.buildDrawingCache();
+ } else {
+ view.setBackgroundDrawable(null);
+ view.setDrawingCacheEnabled(false);
+ view.destroyDrawingCache();
+ }
+ }
+ }
+
+ public void onLayoutCallback() {
+ if (mSoftwareRendered && OPTIMIZE_SW_RENDERED_RECENTS) {
+ mScrollView.post(new Runnable() {
+ public void run() {
+ updateShowBackground();
+ }
+ });
+ }
+ }
+
+ public void drawCallback(Canvas canvas,
+ int left, int right, int top, int bottom, int scrollX, int scrollY,
+ float topFadingEdgeStrength, float bottomFadingEdgeStrength,
+ float leftFadingEdgeStrength, float rightFadingEdgeStrength) {
+ if (mSoftwareRendered && OPTIMIZE_SW_RENDERED_RECENTS) {
+ if (mIsVertical) {
+ if (scrollY < 0) {
+ Drawable d = mBackgroundDrawable.newDrawable().getCurrent();
+ d.setBounds(0, scrollY, mScrollView.getWidth(), 0);
+ d.draw(canvas);
+ } else {
+ final int childHeight = mLinearLayout.getHeight();
+ if (scrollY + mScrollView.getHeight() > childHeight) {
+ Drawable d = mBackgroundDrawable.newDrawable().getCurrent();
+ d.setBounds(0, childHeight, mScrollView.getWidth(),
+ scrollY + mScrollView.getHeight());
+ d.draw(canvas);
+ }
+ }
+ } else {
+ if (scrollX < 0) {
+ Drawable d = mBackgroundDrawable.newDrawable().getCurrent();
+ d.setBounds(scrollX, 0, 0, mScrollView.getHeight());
+ d.draw(canvas);
+ } else {
+ final int childWidth = mLinearLayout.getWidth();
+ if (scrollX + mScrollView.getWidth() > childWidth) {
+ Drawable d = mBackgroundDrawable.newDrawable().getCurrent();
+ d.setBounds(childWidth, 0,
+ scrollX + mScrollView.getWidth(), mScrollView.getHeight());
+ d.draw(canvas);
+ }
+ }
+ }
+ }
+
+ if ((mSoftwareRendered && OPTIMIZE_SW_RENDERED_RECENTS)
+ || USE_DARK_FADE_IN_HW_ACCELERATED_MODE) {
+ Paint p = new Paint();
+ Matrix matrix = new Matrix();
+ // use use a height of 1, and then wack the matrix each time we
+ // actually use it.
+ Shader fade = new LinearGradient(0, 0, 0, 1, 0xCC000000, 0, Shader.TileMode.CLAMP);
+ // PULL OUT THIS CONSTANT
+
+ p.setShader(fade);
+
+ // draw the fade effect
+ boolean drawTop = false;
+ boolean drawBottom = false;
+ boolean drawLeft = false;
+ boolean drawRight = false;
+
+ float topFadeStrength = 0.0f;
+ float bottomFadeStrength = 0.0f;
+ float leftFadeStrength = 0.0f;
+ float rightFadeStrength = 0.0f;
+
+ final float fadeHeight = mFadingEdgeLength;
+ int length = (int) fadeHeight;
+
+ // clip the fade length if top and bottom fades overlap
+ // overlapping fades produce odd-looking artifacts
+ if (mIsVertical && (top + length > bottom - length)) {
+ length = (bottom - top) / 2;
+ }
+
+ // also clip horizontal fades if necessary
+ if (!mIsVertical && (left + length > right - length)) {
+ length = (right - left) / 2;
+ }
+
+ if (mIsVertical) {
+ topFadeStrength = Math.max(0.0f, Math.min(1.0f, topFadingEdgeStrength));
+ drawTop = topFadeStrength * fadeHeight > 1.0f;
+ bottomFadeStrength = Math.max(0.0f, Math.min(1.0f, bottomFadingEdgeStrength));
+ drawBottom = bottomFadeStrength * fadeHeight > 1.0f;
+ }
+
+ if (!mIsVertical) {
+ leftFadeStrength = Math.max(0.0f, Math.min(1.0f, leftFadingEdgeStrength));
+ drawLeft = leftFadeStrength * fadeHeight > 1.0f;
+ rightFadeStrength = Math.max(0.0f, Math.min(1.0f, rightFadingEdgeStrength));
+ drawRight = rightFadeStrength * fadeHeight > 1.0f;
+ }
+
+ if (drawTop) {
+ matrix.setScale(1, fadeHeight * topFadeStrength);
+ matrix.postTranslate(left, top);
+ fade.setLocalMatrix(matrix);
+ canvas.drawRect(left, top, right, top + length, p);
+ }
+
+ if (drawBottom) {
+ matrix.setScale(1, fadeHeight * bottomFadeStrength);
+ matrix.postRotate(180);
+ matrix.postTranslate(left, bottom);
+ fade.setLocalMatrix(matrix);
+ canvas.drawRect(left, bottom - length, right, bottom, p);
+ }
+
+ if (drawLeft) {
+ matrix.setScale(1, fadeHeight * leftFadeStrength);
+ matrix.postRotate(-90);
+ matrix.postTranslate(left, top);
+ fade.setLocalMatrix(matrix);
+ canvas.drawRect(left, top, left + length, bottom, p);
+ }
+
+ if (drawRight) {
+ matrix.setScale(1, fadeHeight * rightFadeStrength);
+ matrix.postRotate(90);
+ matrix.postTranslate(right, top);
+ fade.setLocalMatrix(matrix);
+ canvas.drawRect(right - length, top, right, bottom, p);
+ }
+ }
+ }
+
+ public int getVerticalFadingEdgeLengthCallback() {
+ return mFadingEdgeLength;
+ }
+
+ public int getHorizontalFadingEdgeLengthCallback() {
+ return mFadingEdgeLength;
+ }
+
+ public void setLayoutTransitionCallback(LayoutTransition transition) {
+ if (mSoftwareRendered && OPTIMIZE_SW_RENDERED_RECENTS) {
+ if (transition != null) {
+ transition.addTransitionListener(new LayoutTransition.TransitionListener() {
+ @Override
+ public void startTransition(LayoutTransition transition,
+ ViewGroup container, View view, int transitionType) {
+ updateShowBackground();
+ }
+
+ @Override
+ public void endTransition(LayoutTransition transition,
+ ViewGroup container, View view, int transitionType) {
+ updateShowBackground();
+ }
+ });
+ }
+ }
+ }
+
+ // Turn on/off drawing the background in our ancestor, and turn on/off drawing
+ // in the items in LinearLayout contained by this scrollview.
+ // Moving the background drawing to our children, and turning on a drawing cache
+ // for each of them, gives us a ~20fps gain when Recents is rendered in software
+ public void updateShowBackground() {
+ if (!mAttachedToWindow) {
+ // We haven't been initialized yet-- we'll get called again when we are
+ return;
+ }
+ if (mSoftwareRendered && OPTIMIZE_SW_RENDERED_RECENTS) {
+ LayoutTransition transition = mLinearLayout.getLayoutTransition();
+ int linearLayoutSize =
+ mIsVertical ? mLinearLayout.getHeight() : mLinearLayout.getWidth();
+ int scrollViewSize =
+ mIsVertical ? mScrollView.getHeight() : mScrollView.getWidth();
+ boolean show = !mScrollView.isHardwareAccelerated() &&
+ (linearLayoutSize > scrollViewSize) &&
+ !(transition != null && transition.isRunning()) &&
+ mCallback.isRecentsVisible();
+
+ if (!mFirstTime && show == mShowBackground) return;
+ mShowBackground = show;
+ mFirstTime = false;
+
+ mCallback.handleShowBackground(!show);
+ for (int i = 0; i < mLinearLayout.getChildCount(); i++) {
+ View v = mLinearLayout.getChildAt(i);
+ if (show) {
+ v.setBackgroundDrawable(mBackgroundDrawable.newDrawable());
+ v.setDrawingCacheEnabled(true);
+ v.buildDrawingCache();
+ } else {
+ v.setDrawingCacheEnabled(false);
+ v.destroyDrawingCache();
+ v.setBackgroundDrawable(null);
+ }
+ }
+ }
+ }
+
+}
diff --git a/packages/SystemUI/src/com/android/systemui/recent/RecentsVerticalScrollView.java b/packages/SystemUI/src/com/android/systemui/recent/RecentsVerticalScrollView.java
index b1a30d9..3acef08 100644
--- a/packages/SystemUI/src/com/android/systemui/recent/RecentsVerticalScrollView.java
+++ b/packages/SystemUI/src/com/android/systemui/recent/RecentsVerticalScrollView.java
@@ -20,6 +20,7 @@
import android.content.Context;
import android.content.res.Configuration;
import android.database.DataSetObserver;
+import android.graphics.Canvas;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
@@ -40,6 +41,7 @@
private RecentsCallback mCallback;
protected int mLastScrollPosition;
private SwipeHelper mSwipeHelper;
+ private RecentsScrollViewPerformanceHelper mPerformanceHelper;
private OnLongClickListener mOnLongClick = new OnLongClickListener() {
public boolean onLongClick(View v) {
@@ -49,15 +51,13 @@
}
};
- public RecentsVerticalScrollView(Context context) {
- this(context, null);
- }
-
public RecentsVerticalScrollView(Context context, AttributeSet attrs) {
super(context, attrs, 0);
float densityScale = getResources().getDisplayMetrics().density;
float pagingTouchSlop = ViewConfiguration.get(mContext).getScaledPagingTouchSlop();
mSwipeHelper = new SwipeHelper(SwipeHelper.X, this, densityScale, pagingTouchSlop);
+
+ mPerformanceHelper = RecentsScrollViewPerformanceHelper.create(context, attrs, this, true);
}
private int scrollPositionOfMostRecent() {
@@ -77,11 +77,15 @@
}
final View view = mAdapter.getView(i, old, mLinearLayout);
+ if (mPerformanceHelper != null) {
+ mPerformanceHelper.addViewCallback(view);
+ }
+
if (old == null) {
view.setClickable(true);
view.setOnLongClickListener(mOnLongClick);
- final View thumbnail = getChildContentView(view);
+ final View thumbnail = view.findViewById(R.id.app_thumbnail);
// thumbnail is set to clickable in the layout file
thumbnail.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
@@ -138,6 +142,11 @@
// We do this so the underlying ScrollView knows that it won't get
// the chance to intercept events anymore
requestDisallowInterceptTouchEvent(true);
+ v.setActivated(true);
+ }
+
+ public void onDragCancelled(View v) {
+ v.setActivated(false);
}
public View getChildAtPosition(MotionEvent ev) {
@@ -155,7 +164,60 @@
}
public View getChildContentView(View v) {
- return v.findViewById(R.id.app_thumbnail);
+ return v.findViewById(R.id.recent_item);
+ }
+
+ @Override
+ protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
+ super.onLayout(changed, left, top, right, bottom);
+ if (mPerformanceHelper != null) {
+ mPerformanceHelper.onLayoutCallback();
+ }
+ }
+
+ @Override
+ public void draw(Canvas canvas) {
+ super.draw(canvas);
+
+ if (mPerformanceHelper != null) {
+ int paddingLeft = mPaddingLeft;
+ final boolean offsetRequired = isPaddingOffsetRequired();
+ if (offsetRequired) {
+ paddingLeft += getLeftPaddingOffset();
+ }
+
+ int left = mScrollX + paddingLeft;
+ int right = left + mRight - mLeft - mPaddingRight - paddingLeft;
+ int top = mScrollY + getFadeTop(offsetRequired);
+ int bottom = top + getFadeHeight(offsetRequired);
+
+ if (offsetRequired) {
+ right += getRightPaddingOffset();
+ bottom += getBottomPaddingOffset();
+ }
+ mPerformanceHelper.drawCallback(canvas,
+ left, right, top, bottom, mScrollX, mScrollY,
+ getTopFadingEdgeStrength(), getBottomFadingEdgeStrength(),
+ 0, 0);
+ }
+ }
+
+ @Override
+ public int getVerticalFadingEdgeLength() {
+ if (mPerformanceHelper != null) {
+ return mPerformanceHelper.getVerticalFadingEdgeLengthCallback();
+ } else {
+ return super.getVerticalFadingEdgeLength();
+ }
+ }
+
+ @Override
+ public int getHorizontalFadingEdgeLength() {
+ if (mPerformanceHelper != null) {
+ return mPerformanceHelper.getHorizontalFadingEdgeLengthCallback();
+ } else {
+ return super.getHorizontalFadingEdgeLength();
+ }
}
@Override
@@ -169,6 +231,14 @@
}
@Override
+ public void onAttachedToWindow() {
+ if (mPerformanceHelper != null) {
+ mPerformanceHelper.onAttachedToWindowCallback(
+ mCallback, mLinearLayout, isHardwareAccelerated());
+ }
+ }
+
+ @Override
protected void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
float densityScale = getResources().getDisplayMetrics().density;
@@ -208,6 +278,12 @@
});
}
+ public void onRecentsVisibilityChanged() {
+ if (mPerformanceHelper != null) {
+ mPerformanceHelper.updateShowBackground();
+ }
+ }
+
@Override
protected void onVisibilityChanged(View changedView, int visibility) {
super.onVisibilityChanged(changedView, visibility);
@@ -236,6 +312,9 @@
@Override
public void setLayoutTransition(LayoutTransition transition) {
+ if (mPerformanceHelper != null) {
+ mPerformanceHelper.setLayoutTransitionCallback(transition);
+ }
// The layout transition applies to our embedded LinearLayout
mLinearLayout.setLayoutTransition(transition);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
index e6c0b96..98dca92 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
@@ -70,6 +70,14 @@
return mCurrentView.findViewById(R.id.menu);
}
+ public View getBackButton() {
+ return mCurrentView.findViewById(R.id.back);
+ }
+
+ public View getHomeButton() {
+ return mCurrentView.findViewById(R.id.home);
+ }
+
public NavigationBarView(Context context, AttributeSet attrs) {
super(context, attrs);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
index 6e6567b..3d23abe 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
@@ -380,7 +380,7 @@
}
protected WindowManager.LayoutParams getRecentsLayoutParams(LayoutParams layoutParams) {
- boolean translucent = false;
+ boolean opaque = false;
WindowManager.LayoutParams lp = new WindowManager.LayoutParams(
layoutParams.width,
layoutParams.height,
@@ -388,7 +388,7 @@
WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN
| WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM
| WindowManager.LayoutParams.FLAG_SPLIT_TOUCH,
- (translucent ? PixelFormat.OPAQUE : PixelFormat.TRANSLUCENT));
+ (opaque ? PixelFormat.OPAQUE : PixelFormat.TRANSLUCENT));
if (ActivityManager.isHighEndGfx(mDisplay)) {
lp.flags |= WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED;
}
@@ -404,7 +404,7 @@
// Recents Panel
boolean visible = false;
if (mRecentsPanel != null) {
- visible = mRecentsPanel.getVisibility() == View.VISIBLE;
+ visible = mRecentsPanel.isShowing();
WindowManagerImpl.getDefault().removeView(mRecentsPanel);
}
@@ -1060,6 +1060,12 @@
*/
}
+ public void showClock(boolean show) {
+ View clock = mStatusBarView.findViewById(R.id.clock);
+ if (clock != null) {
+ clock.setVisibility(show ? View.VISIBLE : View.GONE);
+ }
+ }
/**
* State is one or more of the DISABLE constants from StatusBarManager.
@@ -1074,6 +1080,10 @@
old, state, diff));
}
+ if ((diff & StatusBarManager.DISABLE_CLOCK) != 0) {
+ boolean show = (state & StatusBarManager.DISABLE_CLOCK) == 0;
+ showClock(show);
+ }
if ((diff & StatusBarManager.DISABLE_EXPAND) != 0) {
if ((state & StatusBarManager.DISABLE_EXPAND) != 0) {
Slog.d(TAG, "DISABLE_EXPAND: yes");
@@ -1081,18 +1091,9 @@
}
}
- if ((diff & StatusBarManager.DISABLE_NAVIGATION) != 0) {
- if ((state & StatusBarManager.DISABLE_NAVIGATION) != 0) {
- Slog.d(TAG, "DISABLE_NAVIGATION: yes");
-
- // close recents if it's visible
- mHandler.removeMessages(MSG_CLOSE_RECENTS_PANEL);
- mHandler.sendEmptyMessage(MSG_CLOSE_RECENTS_PANEL);
- }
-
- if (mNavigationBarView != null) {
- mNavigationBarView.setEnabled((state & StatusBarManager.DISABLE_NAVIGATION) == 0);
- }
+ if ((diff & (StatusBarManager.DISABLE_NAVIGATION | StatusBarManager.DISABLE_BACK)) != 0) {
+ setNavigationVisibility(state &
+ (StatusBarManager.DISABLE_NAVIGATION | StatusBarManager.DISABLE_BACK));
}
if ((diff & StatusBarManager.DISABLE_NOTIFICATION_ICONS) != 0) {
@@ -1117,6 +1118,32 @@
}
}
+ private void setNavigationVisibility(int visibility) {
+ boolean disableNavigation = ((visibility & StatusBarManager.DISABLE_NAVIGATION) != 0);
+ boolean disableBack = ((visibility & StatusBarManager.DISABLE_BACK) != 0);
+
+ Slog.i(TAG, "DISABLE_BACK: " + (disableBack ? "yes" : "no"));
+ Slog.i(TAG, "DISABLE_NAVIGATION: " + (disableNavigation ? "yes" : "no"));
+
+ if (mNavigationBarView != null) {
+ if (disableNavigation && disableBack) {
+ mNavigationBarView.setEnabled(false);
+ } else {
+ mNavigationBarView.getBackButton().setEnabled(!disableBack);
+ mNavigationBarView.getHomeButton().setEnabled(!disableNavigation);
+ mNavigationBarView.getRecentsButton().setEnabled(!disableNavigation);
+
+ mNavigationBarView.setEnabled(true);
+ }
+ }
+
+ if (disableNavigation) {
+ // close recents if it's visible
+ mHandler.removeMessages(MSG_CLOSE_RECENTS_PANEL);
+ mHandler.sendEmptyMessage(MSG_CLOSE_RECENTS_PANEL);
+ }
+ }
+
/**
* All changes to the status bar and notifications funnel through here and are batched.
*/
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkController.java
index 60dfdac..3c85814 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkController.java
@@ -130,6 +130,8 @@
int mLastDataTypeIconId = -1;
String mLastLabel = "";
+ private boolean mHasMobileDataFeature;
+
boolean mDataAndWifiStacked = false;
// yuck -- stop doing this here and put it in the framework
@@ -147,6 +149,10 @@
public NetworkController(Context context) {
mContext = context;
+ ConnectivityManager cm = (ConnectivityManager)mContext.getSystemService(
+ Context.CONNECTIVITY_SERVICE);
+ mHasMobileDataFeature = cm.isNetworkSupported(ConnectivityManager.TYPE_MOBILE);
+
// set up the default wifi icon, used when no radios have ever appeared
updateWifiIcons();
@@ -229,7 +235,7 @@
mWifiIconId,
mWifiActivityIconId);
cluster.setMobileDataIndicators(
- hasMobileDataFeature(),
+ mHasMobileDataFeature,
mPhoneSignalIconId,
mMobileActivityIconId,
mDataTypeIconId);
@@ -376,12 +382,6 @@
}
}
- private boolean hasMobileDataFeature() {
- // XXX: HAX: replace when a more reliable method is available
- return (! "wifi-only".equals(SystemProperties.get("ro.carrier")));
- }
-
-
private void updateAirplaneMode() {
mAirplaneMode = (Settings.System.getInt(mContext.getContentResolver(),
Settings.System.AIRPLANE_MODE_ON, 0) == 1);
@@ -828,8 +828,8 @@
label = context.getString(R.string.status_bar_settings_signal_meter_disconnected);
// On devices without mobile radios, we want to show the wifi icon
combinedSignalIconId =
- hasMobileDataFeature() ? mDataSignalIconId : mWifiIconId;
- mContentDescriptionCombinedSignal = hasMobileDataFeature()
+ mHasMobileDataFeature ? mDataSignalIconId : mWifiIconId;
+ mContentDescriptionCombinedSignal = mHasMobileDataFeature
? mContentDescriptionDataType : mContentDescriptionWifi;
mDataTypeIconId = 0;
}
@@ -866,7 +866,7 @@
mWifiIconId,
mWifiActivityIconId);
cluster.setMobileDataIndicators(
- hasMobileDataFeature(),
+ mHasMobileDataFeature,
mPhoneSignalIconId,
mMobileActivityIconId,
mDataTypeIconId);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NotificationRowLayout.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NotificationRowLayout.java
index 469b462..e287b7a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NotificationRowLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NotificationRowLayout.java
@@ -124,6 +124,9 @@
requestDisallowInterceptTouchEvent(true);
}
+ public void onDragCancelled(View v) {
+ }
+
public View getChildAtPosition(MotionEvent ev) {
// find the view under the pointer, accounting for GONE views
final int count = getChildCount();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/InputMethodsPanel.java b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/InputMethodsPanel.java
index 1e417ac..5911378 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/InputMethodsPanel.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/InputMethodsPanel.java
@@ -428,7 +428,7 @@
private CharSequence getIMIName(InputMethodInfo imi) {
if (imi == null) return null;
- return mPackageManager.getApplicationLabel(imi.getServiceInfo().applicationInfo);
+ return imi.loadLabel(mPackageManager);
}
private CharSequence getSubtypeName(InputMethodInfo imi, InputMethodSubtype subtype) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletStatusBar.java
index 2ab667d..cc73d7b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletStatusBar.java
@@ -306,7 +306,7 @@
mStatusBarView.setIgnoreChildren(2, mRecentButton, mRecentsPanel);
lp = new WindowManager.LayoutParams(
- ViewGroup.LayoutParams.MATCH_PARENT,
+ (int) res.getDimension(R.dimen.status_bar_recents_width),
ViewGroup.LayoutParams.MATCH_PARENT,
WindowManager.LayoutParams.TYPE_STATUS_BAR_PANEL,
WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN
@@ -949,29 +949,34 @@
mTicker.halt();
}
}
- if ((diff & StatusBarManager.DISABLE_NAVIGATION) != 0) {
- if ((state & StatusBarManager.DISABLE_NAVIGATION) != 0) {
- Slog.i(TAG, "DISABLE_NAVIGATION: yes");
- mNavigationArea.setVisibility(View.INVISIBLE);
- mInputMethodSwitchButton.setScreenLocked(true);
- } else {
- Slog.i(TAG, "DISABLE_NAVIGATION: no");
- mNavigationArea.setVisibility(View.VISIBLE);
- mInputMethodSwitchButton.setScreenLocked(false);
- }
+ if ((diff & (StatusBarManager.DISABLE_NAVIGATION | StatusBarManager.DISABLE_BACK)) != 0) {
+ setNavigationVisibility(state &
+ (StatusBarManager.DISABLE_NAVIGATION | StatusBarManager.DISABLE_BACK));
}
- if ((diff & StatusBarManager.DISABLE_BACK) != 0) {
- if ((state & StatusBarManager.DISABLE_BACK) != 0) {
- Slog.i(TAG, "DISABLE_BACK: yes");
- mBackButton.setEnabled(false);
- mInputMethodSwitchButton.setScreenLocked(true);
- } else {
- Slog.i(TAG, "DISABLE_BACK: no");
- mBackButton.setEnabled(true);
- mInputMethodSwitchButton.setScreenLocked(false);
- }
+ }
+
+ private void setNavigationVisibility(int visibility) {
+ boolean disableNavigation = ((visibility & StatusBarManager.DISABLE_NAVIGATION) != 0);
+ boolean disableBack = ((visibility & StatusBarManager.DISABLE_BACK) != 0);
+
+ Slog.i(TAG, "DISABLE_BACK: " + (disableBack ? "yes" : "no"));
+ Slog.i(TAG, "DISABLE_NAVIGATION: " + (disableNavigation ? "yes" : "no"));
+
+ if (disableNavigation && disableBack) {
+ mNavigationArea.setVisibility(View.INVISIBLE);
+ } else {
+ int backVisiblity = (disableBack ? View.INVISIBLE : View.VISIBLE);
+ int navVisibility = (disableNavigation ? View.INVISIBLE : View.VISIBLE);
+
+ mBackButton.setVisibility(backVisiblity);
+ mHomeButton.setVisibility(navVisibility);
+ mRecentButton.setVisibility(navVisibility);
+ // don't change menu button visibility here
+
+ mNavigationArea.setVisibility(View.VISIBLE);
}
+ mInputMethodSwitchButton.setScreenLocked(disableNavigation);
}
private boolean hasTicker(Notification n) {
diff --git a/policy/src/com/android/internal/policy/impl/KeyguardStatusViewManager.java b/policy/src/com/android/internal/policy/impl/KeyguardStatusViewManager.java
index 9629702..40cc7d8 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.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 @@
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 @@
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 @@
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 @@
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 @@
* @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 @@
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 77f1932..2955de3 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_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 @@
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 @@
case MSG_PHONE_STATE_CHANGED:
handlePhoneStateChanged((String)msg.obj);
break;
- case MSG_TRANSPORT_CONTROL_STATE_CHANGED:
- handleTransportControlStateChanged(msg.arg1);
- break;
}
}
};
@@ -263,23 +259,10 @@
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 @@
*/
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 void reportFailedAttempt() {
mFailedAttempts++;
}
+
}
diff --git a/policy/src/com/android/internal/policy/impl/KeyguardViewMediator.java b/policy/src/com/android/internal/policy/impl/KeyguardViewMediator.java
index 5661116..a544167 100644
--- a/policy/src/com/android/internal/policy/impl/KeyguardViewMediator.java
+++ b/policy/src/com/android/internal/policy/impl/KeyguardViewMediator.java
@@ -145,10 +145,10 @@
private static final int KEYGUARD_DONE_DRAWING_TIMEOUT_MS = 2000;
/**
- * Allow the user to operate the status bar when the keyguard is engaged (without a pattern or
- * password).
+ * Allow the user to expand the status bar when the keyguard is engaged
+ * (without a pattern or password).
*/
- private static final boolean ENABLE_STATUS_BAR_IN_KEYGUARD = true;
+ private static final boolean ENABLE_INSECURE_STATUS_BAR_EXPAND = true;
private Context mContext;
private AlarmManager mAlarmManager;
@@ -1184,19 +1184,29 @@
}
}
- // if the keyguard is shown, allow the status bar to open only if the keyguard is
- // insecure and (is covered by another window OR this feature is enabled in general)
- boolean enable = !mShowing
- || ((ENABLE_STATUS_BAR_IN_KEYGUARD || mHidden) && !isSecure());
- if (DEBUG) {
- Log.d(TAG, "adjustStatusBarLocked: mShowing=" + mShowing + " mHidden=" + mHidden
- + " isSecure=" + isSecure() + " --> enable=" + enable);
+ int flags = StatusBarManager.DISABLE_NONE;
+ if (mShowing) {
+ // disable navigation status bar components if lock screen is up
+ flags |= StatusBarManager.DISABLE_NAVIGATION;
+ if (!mHidden) {
+ // showing lockscreen exclusively (no activities in front of it)
+ // disable clock and back button too
+ flags |= StatusBarManager.DISABLE_BACK;
+ flags |= StatusBarManager.DISABLE_CLOCK;
+ }
+ if (isSecure() || !ENABLE_INSECURE_STATUS_BAR_EXPAND) {
+ // showing secure lockscreen; disable expanding.
+ flags |= StatusBarManager.DISABLE_EXPAND;
+ }
}
- mStatusBarManager.disable(enable ?
- StatusBarManager.DISABLE_NONE :
- ( StatusBarManager.DISABLE_EXPAND
- | StatusBarManager.DISABLE_NAVIGATION
- | StatusBarManager.DISABLE_CLOCK));
+
+ if (DEBUG) {
+ Log.d(TAG,
+ "adjustStatusBarLocked: mShowing=" + mShowing + " mHidden=" + mHidden
+ + " isSecure=" + isSecure() + " --> flags=" + flags);
+ }
+
+ mStatusBarManager.disable(flags);
}
}
diff --git a/policy/src/com/android/internal/policy/impl/LockPatternKeyguardView.java b/policy/src/com/android/internal/policy/impl/LockPatternKeyguardView.java
index 70772eb..9c14734 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.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 @@
*/
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 @@
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 @@
* 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 @@
*/
private final LockPatternUtils mLockPatternUtils;
- private UnlockMode mCurrentUnlockMode = UnlockMode.Unknown;
-
/**
* The current configuration.
*/
@@ -173,7 +179,23 @@
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 @@
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 @@
mIsVerifyUnlockOnly = false;
getCallback().keyguardDone(false);
} else {
- updateScreen(Mode.LockScreen);
+ updateScreen(Mode.LockScreen, false);
}
}
@@ -240,14 +257,14 @@
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 void recreateMe(Configuration config) {
- mConfiguration = config;
removeCallbacks(mRecreateRunnable);
post(mRecreateRunnable);
}
@@ -330,7 +346,7 @@
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 @@
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 void reset() {
mIsVerifyUnlockOnly = false;
mForgotPattern = false;
- updateScreen(getInitialMode());
+ updateScreen(getInitialMode(), false);
}
@Override
@@ -457,7 +460,7 @@
mScreenOn = false;
mForgotPattern = false;
if (mMode == Mode.LockScreen) {
- ((KeyguardScreen) mLockScreen).onPause();
+ ((KeyguardScreen) mLockScreen).onPause();
} else {
((KeyguardScreen) mUnlockScreen).onPause();
}
@@ -467,50 +470,54 @@
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 @@
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 @@
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 @@
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 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();
+ // 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) {
+ 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 @@
}
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 @@
}
}
- goneScreen.setVisibility(View.GONE);
+ if (goneScreen != null) {
+ goneScreen.setVisibility(View.GONE);
+ }
visibleScreen.setVisibility(View.VISIBLE);
requestLayout();
@@ -632,12 +659,14 @@
}
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 @@
// 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 @@
} 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 @@
!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 ce3bc74..2f2d3b7 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 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/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
index dfd1b00..2f5deba 100755
--- a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
+++ b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
@@ -38,6 +38,7 @@
import android.database.ContentObserver;
import android.graphics.PixelFormat;
import android.graphics.Rect;
+import android.graphics.RectF;
import android.os.Binder;
import android.os.Handler;
import android.os.IBinder;
@@ -266,6 +267,7 @@
int mLidOpen = LID_ABSENT;
boolean mSystemReady;
+ boolean mSystemBooted;
boolean mHdmiPlugged;
int mUiMode = Configuration.UI_MODE_TYPE_NORMAL;
int mDockMode = Intent.EXTRA_DOCK_STATE_UNDOCKED;
@@ -900,6 +902,7 @@
lp.setTitle("PointerLocation");
WindowManager wm = (WindowManager)
mContext.getSystemService(Context.WINDOW_SERVICE);
+ lp.inputFeatures |= WindowManager.LayoutParams.INPUT_FEATURE_NO_INPUT_CHANNEL;
wm.addView(addView, lp);
if (mPointerLocationInputChannel == null) {
@@ -2262,7 +2265,7 @@
// incorrectly think it does cover it when it doesn't. We'll revisit
// this later when we re-do the phone status bar.
if (mStatusBar != null && mStatusBar.isVisibleLw()) {
- Rect rect = new Rect(mStatusBar.getShownFrameLw());
+ RectF rect = new RectF(mStatusBar.getShownFrameLw());
for (int i=mStatusBarPanels.size()-1; i>=0; i--) {
WindowState w = mStatusBarPanels.get(i);
if (w.isVisibleLw()) {
@@ -2495,6 +2498,11 @@
mKeyguardMediator.isShowingAndNotHidden() :
mKeyguardMediator.isShowing());
+ if (!mSystemBooted) {
+ // If we have not yet booted, don't let key events do anything.
+ return 0;
+ }
+
if (false) {
Log.d(TAG, "interceptKeyTq keycode=" + keyCode
+ " screenIsOn=" + isScreenOn + " keyguardActive=" + keyguardActive);
@@ -3098,6 +3106,13 @@
}
}
+ /** {@inheritDoc} */
+ public void systemBooted() {
+ synchronized (mLock) {
+ mSystemBooted = true;
+ }
+ }
+
ProgressDialog mBootMsgDialog = null;
/** {@inheritDoc} */
@@ -3490,7 +3505,8 @@
public void dump(String prefix, FileDescriptor fd, PrintWriter pw, String[] args) {
pw.print(prefix); pw.print("mSafeMode="); pw.print(mSafeMode);
- pw.print(" mSystemRead="); pw.println(mSystemReady);
+ pw.print(" mSystemReady="); pw.print(mSystemReady);
+ pw.print(" mSystemBooted="); pw.println(mSystemBooted);
pw.print(prefix); pw.print("mLidOpen="); pw.print(mLidOpen);
pw.print(" mLidOpenRotation="); pw.print(mLidOpenRotation);
pw.print(" mHdmiPlugged="); pw.println(mHdmiPlugged);
diff --git a/services/audioflinger/AudioFlinger.cpp b/services/audioflinger/AudioFlinger.cpp
index 744fa50..94efa74 100644
--- a/services/audioflinger/AudioFlinger.cpp
+++ b/services/audioflinger/AudioFlinger.cpp
@@ -151,7 +151,7 @@
AudioFlinger::AudioFlinger()
: BnAudioFlinger(),
mPrimaryHardwareDev(0), mMasterVolume(1.0f), mMasterMute(false), mNextUniqueId(1),
- mBtNrec(false)
+ mBtNrecIsOff(false)
{
}
@@ -751,15 +751,15 @@
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 @@
track->sessionId());
}
}
- mBtNrec = btNrec;
+ mBtNrecIsOff = btNrecIsOff;
}
}
return final_result;
@@ -1362,6 +1362,7 @@
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 @@
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::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 @@
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 @@
// 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 @@
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 1141f6c..2e05593 100644
--- a/services/audioflinger/AudioFlinger.h
+++ b/services/audioflinger/AudioFlinger.h
@@ -210,7 +210,7 @@
uint32_t getMode() { return mMode; }
- bool btNrec() { return mBtNrec; }
+ bool btNrecIsOff() { return mBtNrecIsOff; }
private:
AudioFlinger();
@@ -751,14 +751,18 @@
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 @@
DefaultKeyedVector< pid_t, sp<NotificationClient> > mNotificationClients;
volatile int32_t mNextUniqueId;
uint32_t mMode;
- bool mBtNrec;
+ bool mBtNrecIsOff;
Vector<AudioSessionRef*> mAudioSessionRefs;
};
diff --git a/services/camera/libcameraservice/CameraService.cpp b/services/camera/libcameraservice/CameraService.cpp
index e193be0..b178fd9 100644
--- a/services/camera/libcameraservice/CameraService.cpp
+++ b/services/camera/libcameraservice/CameraService.cpp
@@ -769,11 +769,6 @@
status_t result = checkPidAndHardware();
if (result != NO_ERROR) return result;
- if (mHardware->recordingEnabled()) {
- LOGE("Cannot take picture during recording.");
- return INVALID_OPERATION;
- }
-
if ((msgType & CAMERA_MSG_RAW_IMAGE) &&
(msgType & CAMERA_MSG_RAW_IMAGE_NOTIFY)) {
LOGE("CAMERA_MSG_RAW_IMAGE and CAMERA_MSG_RAW_IMAGE_NOTIFY"
diff --git a/services/input/Android.mk b/services/input/Android.mk
index afbe546..86c6c8a 100644
--- a/services/input/Android.mk
+++ b/services/input/Android.mk
@@ -18,6 +18,7 @@
LOCAL_SRC_FILES:= \
EventHub.cpp \
+ InputApplication.cpp \
InputDispatcher.cpp \
InputListener.cpp \
InputManager.cpp \
diff --git a/services/input/EventHub.cpp b/services/input/EventHub.cpp
index 1d7cc19..80ee28e 100644
--- a/services/input/EventHub.cpp
+++ b/services/input/EventHub.cpp
@@ -78,6 +78,40 @@
return value ? "true" : "false";
}
+// --- Global Functions ---
+
+uint32_t getAbsAxisUsage(int32_t axis, uint32_t deviceClasses) {
+ // Touch devices get dibs on touch-related axes.
+ if (deviceClasses & INPUT_DEVICE_CLASS_TOUCH) {
+ switch (axis) {
+ case ABS_X:
+ case ABS_Y:
+ case ABS_PRESSURE:
+ case ABS_TOOL_WIDTH:
+ case ABS_DISTANCE:
+ case ABS_TILT_X:
+ case ABS_TILT_Y:
+ case ABS_MT_SLOT:
+ case ABS_MT_TOUCH_MAJOR:
+ case ABS_MT_TOUCH_MINOR:
+ case ABS_MT_WIDTH_MAJOR:
+ case ABS_MT_WIDTH_MINOR:
+ case ABS_MT_ORIENTATION:
+ case ABS_MT_POSITION_X:
+ case ABS_MT_POSITION_Y:
+ case ABS_MT_TOOL_TYPE:
+ case ABS_MT_BLOB_ID:
+ case ABS_MT_TRACKING_ID:
+ case ABS_MT_PRESSURE:
+ case ABS_MT_DISTANCE:
+ return INPUT_DEVICE_CLASS_TOUCH;
+ }
+ }
+
+ // Joystick devices get the rest.
+ return deviceClasses & INPUT_DEVICE_CLASS_JOYSTICK;
+}
+
// --- EventHub::Device ---
EventHub::Device::Device(int fd, int32_t id, const String8& path,
@@ -936,13 +970,17 @@
}
// See if this device is a joystick.
- // Ignore touchscreens because they use the same absolute axes for other purposes.
// Assumes that joysticks always have gamepad buttons in order to distinguish them
// from other devices such as accelerometers that also have absolute axes.
- if (haveGamepadButtons
- && !(device->classes & INPUT_DEVICE_CLASS_TOUCH)
- && containsNonZeroByte(device->absBitmask, 0, sizeof_bit_array(ABS_MAX + 1))) {
- device->classes |= INPUT_DEVICE_CLASS_JOYSTICK;
+ if (haveGamepadButtons) {
+ uint32_t assumedClasses = device->classes | INPUT_DEVICE_CLASS_JOYSTICK;
+ for (int i = 0; i <= ABS_MAX; i++) {
+ if (test_bit(i, device->absBitmask)
+ && (getAbsAxisUsage(i, assumedClasses) & INPUT_DEVICE_CLASS_JOYSTICK)) {
+ device->classes = assumedClasses;
+ break;
+ }
+ }
}
// Check whether this device has switches.
@@ -1094,9 +1132,8 @@
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/input/EventHub.h b/services/input/EventHub.h
index fae5d4f..d37549a 100644
--- a/services/input/EventHub.h
+++ b/services/input/EventHub.h
@@ -112,6 +112,12 @@
};
/*
+ * Gets the class that owns an axis, in cases where multiple classes might claim
+ * the same axis for different purposes.
+ */
+extern uint32_t getAbsAxisUsage(int32_t axis, uint32_t deviceClasses);
+
+/*
* Grand Central Station for events.
*
* The event hub aggregates input events received across all known input
diff --git a/services/input/InputApplication.cpp b/services/input/InputApplication.cpp
new file mode 100644
index 0000000..a99e637
--- /dev/null
+++ b/services/input/InputApplication.cpp
@@ -0,0 +1,42 @@
+/*
+ * 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.
+ */
+
+#define LOG_TAG "InputApplication"
+
+#include "InputApplication.h"
+
+#include <cutils/log.h>
+
+namespace android {
+
+// --- InputApplicationHandle ---
+
+InputApplicationHandle::InputApplicationHandle() :
+ mInfo(NULL) {
+}
+
+InputApplicationHandle::~InputApplicationHandle() {
+ delete mInfo;
+}
+
+void InputApplicationHandle::releaseInfo() {
+ if (mInfo) {
+ delete mInfo;
+ mInfo = NULL;
+ }
+}
+
+} // namespace android
diff --git a/services/input/InputApplication.h b/services/input/InputApplication.h
index 8902f7a..67ae94b 100644
--- a/services/input/InputApplication.h
+++ b/services/input/InputApplication.h
@@ -27,14 +27,32 @@
/*
* Describes the properties of an application that can receive input.
+ */
+struct InputApplicationInfo {
+ String8 name;
+ nsecs_t dispatchingTimeout;
+};
+
+
+/*
+ * Handle for an application that can receive input.
*
* Used by the native input dispatcher as a handle for the window manager objects
* that describe an application.
*/
class InputApplicationHandle : public RefBase {
public:
- String8 name;
- nsecs_t dispatchingTimeout;
+ inline const InputApplicationInfo* getInfo() const {
+ return mInfo;
+ }
+
+ inline String8 getName() const {
+ return mInfo ? mInfo->name : String8("<invalid>");
+ }
+
+ inline nsecs_t getDispatchingTimeout(nsecs_t defaultValue) const {
+ return mInfo ? mInfo->dispatchingTimeout : defaultValue;
+ }
/**
* Requests that the state of this object be updated to reflect
@@ -45,11 +63,19 @@
*
* Returns true on success, or false if the handle is no longer valid.
*/
- virtual bool update() = 0;
+ virtual bool updateInfo() = 0;
+
+ /**
+ * Releases the storage used by the associated information when it is
+ * no longer needed.
+ */
+ void releaseInfo();
protected:
- InputApplicationHandle() { }
- virtual ~InputApplicationHandle() { }
+ InputApplicationHandle();
+ virtual ~InputApplicationHandle();
+
+ InputApplicationInfo* mInfo;
};
} // namespace android
diff --git a/services/input/InputDispatcher.cpp b/services/input/InputDispatcher.cpp
index cf167ae..1eb5f0e 100644
--- a/services/input/InputDispatcher.cpp
+++ b/services/input/InputDispatcher.cpp
@@ -306,7 +306,12 @@
}
}
}
+
+ // Nothing to do if there is no pending event.
if (! mPendingEvent) {
+ if (mActiveConnections.isEmpty()) {
+ dispatchIdleLocked();
+ }
return;
}
} else {
@@ -462,6 +467,16 @@
}
}
+void InputDispatcher::dispatchIdleLocked() {
+#if DEBUG_FOCUS
+ LOGD("Dispatcher idle. There are no pending events or active connections.");
+#endif
+
+ // Reset targets when idle, to release input channels and other resources
+ // they are holding onto.
+ resetTargetsLocked();
+}
+
bool InputDispatcher::enqueueInboundEventLocked(EventEntry* entry) {
bool needWake = mInboundQueue.isEmpty();
mInboundQueue.enqueueAtTail(entry);
@@ -525,20 +540,21 @@
size_t numWindows = mWindowHandles.size();
for (size_t i = 0; i < numWindows; i++) {
sp<InputWindowHandle> windowHandle = mWindowHandles.itemAt(i);
- int32_t flags = windowHandle->layoutParamsFlags;
+ const InputWindowInfo* windowInfo = windowHandle->getInfo();
+ int32_t flags = windowInfo->layoutParamsFlags;
- if (windowHandle->visible) {
- if (!(flags & InputWindowHandle::FLAG_NOT_TOUCHABLE)) {
- bool isTouchModal = (flags & (InputWindowHandle::FLAG_NOT_FOCUSABLE
- | InputWindowHandle::FLAG_NOT_TOUCH_MODAL)) == 0;
- if (isTouchModal || windowHandle->touchableRegionContainsPoint(x, y)) {
+ if (windowInfo->visible) {
+ if (!(flags & InputWindowInfo::FLAG_NOT_TOUCHABLE)) {
+ bool isTouchModal = (flags & (InputWindowInfo::FLAG_NOT_FOCUSABLE
+ | InputWindowInfo::FLAG_NOT_TOUCH_MODAL)) == 0;
+ if (isTouchModal || windowInfo->touchableRegionContainsPoint(x, y)) {
// Found window.
return windowHandle;
}
}
}
- if (flags & InputWindowHandle::FLAG_SYSTEM_ERROR) {
+ if (flags & InputWindowInfo::FLAG_SYSTEM_ERROR) {
// Error window is on top but not visible, so touch is dropped.
return NULL;
}
@@ -1051,9 +1067,15 @@
LOGD("Waiting for application to become ready for input: %s",
getApplicationWindowLabelLocked(applicationHandle, windowHandle).string());
#endif
- nsecs_t timeout = windowHandle != NULL ? windowHandle->dispatchingTimeout :
- applicationHandle != NULL ?
- applicationHandle->dispatchingTimeout : DEFAULT_INPUT_DISPATCHING_TIMEOUT;
+ nsecs_t timeout;
+ if (windowHandle != NULL) {
+ timeout = windowHandle->getDispatchingTimeout(DEFAULT_INPUT_DISPATCHING_TIMEOUT);
+ } else if (applicationHandle != NULL) {
+ timeout = applicationHandle->getDispatchingTimeout(
+ DEFAULT_INPUT_DISPATCHING_TIMEOUT);
+ } else {
+ timeout = DEFAULT_INPUT_DISPATCHING_TIMEOUT;
+ }
mInputTargetWaitCause = INPUT_TARGET_WAIT_CAUSE_APPLICATION_NOT_READY;
mInputTargetWaitStartTime = currentTime;
@@ -1168,7 +1190,7 @@
}
// If the currently focused window is paused then keep waiting.
- if (mFocusedWindowHandle->paused) {
+ if (mFocusedWindowHandle->getInfo()->paused) {
#if DEBUG_FOCUS
LOGD("Waiting because focused window is paused.");
#endif
@@ -1302,21 +1324,22 @@
size_t numWindows = mWindowHandles.size();
for (size_t i = 0; i < numWindows; i++) {
sp<InputWindowHandle> windowHandle = mWindowHandles.itemAt(i);
- int32_t flags = windowHandle->layoutParamsFlags;
+ const InputWindowInfo* windowInfo = windowHandle->getInfo();
+ int32_t flags = windowInfo->layoutParamsFlags;
- if (flags & InputWindowHandle::FLAG_SYSTEM_ERROR) {
+ if (flags & InputWindowInfo::FLAG_SYSTEM_ERROR) {
if (topErrorWindowHandle == NULL) {
topErrorWindowHandle = windowHandle;
}
}
- if (windowHandle->visible) {
- if (! (flags & InputWindowHandle::FLAG_NOT_TOUCHABLE)) {
- isTouchModal = (flags & (InputWindowHandle::FLAG_NOT_FOCUSABLE
- | InputWindowHandle::FLAG_NOT_TOUCH_MODAL)) == 0;
- if (isTouchModal || windowHandle->touchableRegionContainsPoint(x, y)) {
+ if (windowInfo->visible) {
+ if (! (flags & InputWindowInfo::FLAG_NOT_TOUCHABLE)) {
+ isTouchModal = (flags & (InputWindowInfo::FLAG_NOT_FOCUSABLE
+ | InputWindowInfo::FLAG_NOT_TOUCH_MODAL)) == 0;
+ if (isTouchModal || windowInfo->touchableRegionContainsPoint(x, y)) {
if (! screenWasOff
- || (flags & InputWindowHandle::FLAG_TOUCHABLE_WHEN_WAKING)) {
+ || (flags & InputWindowInfo::FLAG_TOUCHABLE_WHEN_WAKING)) {
newTouchedWindowHandle = windowHandle;
}
break; // found touched window, exit window loop
@@ -1324,7 +1347,7 @@
}
if (maskedAction == AMOTION_EVENT_ACTION_DOWN
- && (flags & InputWindowHandle::FLAG_WATCH_OUTSIDE_TOUCH)) {
+ && (flags & InputWindowInfo::FLAG_WATCH_OUTSIDE_TOUCH)) {
int32_t outsideTargetFlags = InputTarget::FLAG_DISPATCH_AS_OUTSIDE;
if (isWindowObscuredAtPointLocked(windowHandle, x, y)) {
outsideTargetFlags |= InputTarget::FLAG_WINDOW_IS_OBSCURED;
@@ -1350,7 +1373,8 @@
}
// Figure out whether splitting will be allowed for this window.
- if (newTouchedWindowHandle != NULL && newTouchedWindowHandle->supportsSplitTouch()) {
+ if (newTouchedWindowHandle != NULL
+ && newTouchedWindowHandle->getInfo()->supportsSplitTouch()) {
// New window supports splitting.
isSplit = true;
} else if (isSplit) {
@@ -1396,7 +1420,7 @@
// within the touched window.
if (!isTouchModal) {
while (sample->next) {
- if (!newHoverWindowHandle->touchableRegionContainsPoint(
+ if (!newHoverWindowHandle->getInfo()->touchableRegionContainsPoint(
sample->next->pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_X),
sample->next->pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_Y))) {
*outSplitBatchAfterSample = sample;
@@ -1444,15 +1468,15 @@
&& newTouchedWindowHandle != NULL) {
#if DEBUG_FOCUS
LOGD("Touch is slipping out of window %s into window %s.",
- oldTouchedWindowHandle->name.string(),
- newTouchedWindowHandle->name.string());
+ oldTouchedWindowHandle->getName().string(),
+ newTouchedWindowHandle->getName().string());
#endif
// Make a slippery exit from the old window.
mTempTouchState.addOrUpdateWindow(oldTouchedWindowHandle,
InputTarget::FLAG_DISPATCH_AS_SLIPPERY_EXIT, BitSet32(0));
// Make a slippery entrance into the new window.
- if (newTouchedWindowHandle->supportsSplitTouch()) {
+ if (newTouchedWindowHandle->getInfo()->supportsSplitTouch()) {
isSplit = true;
}
@@ -1484,7 +1508,8 @@
// Let the previous window know that the hover sequence is over.
if (mLastHoverWindowHandle != NULL) {
#if DEBUG_HOVER
- LOGD("Sending hover exit event to window %s.", mLastHoverWindowHandle->name.string());
+ LOGD("Sending hover exit event to window %s.",
+ mLastHoverWindowHandle->getName().string());
#endif
mTempTouchState.addOrUpdateWindow(mLastHoverWindowHandle,
InputTarget::FLAG_DISPATCH_AS_HOVER_EXIT, BitSet32(0));
@@ -1493,7 +1518,8 @@
// Let the new window know that the hover sequence is starting.
if (newHoverWindowHandle != NULL) {
#if DEBUG_HOVER
- LOGD("Sending hover enter event to window %s.", newHoverWindowHandle->name.string());
+ LOGD("Sending hover enter event to window %s.",
+ newHoverWindowHandle->getName().string());
#endif
mTempTouchState.addOrUpdateWindow(newHoverWindowHandle,
InputTarget::FLAG_DISPATCH_AS_HOVER_ENTER, BitSet32(0));
@@ -1533,12 +1559,12 @@
if (maskedAction == AMOTION_EVENT_ACTION_DOWN) {
sp<InputWindowHandle> foregroundWindowHandle =
mTempTouchState.getFirstForegroundWindowHandle();
- const int32_t foregroundWindowUid = foregroundWindowHandle->ownerUid;
+ const int32_t foregroundWindowUid = foregroundWindowHandle->getInfo()->ownerUid;
for (size_t i = 0; i < mTempTouchState.windows.size(); i++) {
const TouchedWindow& touchedWindow = mTempTouchState.windows[i];
if (touchedWindow.targetFlags & InputTarget::FLAG_DISPATCH_AS_OUTSIDE) {
sp<InputWindowHandle> inputWindowHandle = touchedWindow.windowHandle;
- if (inputWindowHandle->ownerUid != foregroundWindowUid) {
+ if (inputWindowHandle->getInfo()->ownerUid != foregroundWindowUid) {
mTempTouchState.addOrUpdateWindow(inputWindowHandle,
InputTarget::FLAG_ZERO_COORDS, BitSet32(0));
}
@@ -1551,7 +1577,7 @@
const TouchedWindow& touchedWindow = mTempTouchState.windows[i];
if (touchedWindow.targetFlags & InputTarget::FLAG_FOREGROUND) {
// If the touched window is paused then keep waiting.
- if (touchedWindow.windowHandle->paused) {
+ if (touchedWindow.windowHandle->getInfo()->paused) {
#if DEBUG_FOCUS
LOGD("Waiting because touched window is paused.");
#endif
@@ -1581,10 +1607,11 @@
if (maskedAction == AMOTION_EVENT_ACTION_DOWN) {
sp<InputWindowHandle> foregroundWindowHandle =
mTempTouchState.getFirstForegroundWindowHandle();
- if (foregroundWindowHandle->hasWallpaper) {
+ if (foregroundWindowHandle->getInfo()->hasWallpaper) {
for (size_t i = 0; i < mWindowHandles.size(); i++) {
sp<InputWindowHandle> windowHandle = mWindowHandles.itemAt(i);
- if (windowHandle->layoutParamsType == InputWindowHandle::TYPE_WALLPAPER) {
+ if (windowHandle->getInfo()->layoutParamsType
+ == InputWindowInfo::TYPE_WALLPAPER) {
mTempTouchState.addOrUpdateWindow(windowHandle,
InputTarget::FLAG_WINDOW_IS_OBSCURED
| InputTarget::FLAG_DISPATCH_AS_IS,
@@ -1708,12 +1735,13 @@
int32_t targetFlags, BitSet32 pointerIds) {
mCurrentInputTargets.push();
+ const InputWindowInfo* windowInfo = windowHandle->getInfo();
InputTarget& target = mCurrentInputTargets.editTop();
- target.inputChannel = windowHandle->inputChannel;
+ target.inputChannel = windowInfo->inputChannel;
target.flags = targetFlags;
- target.xOffset = - windowHandle->frameLeft;
- target.yOffset = - windowHandle->frameTop;
- target.scaleFactor = windowHandle->scaleFactor;
+ target.xOffset = - windowInfo->frameLeft;
+ target.yOffset = - windowInfo->frameTop;
+ target.scaleFactor = windowInfo->scaleFactor;
target.pointerIds = pointerIds;
}
@@ -1734,14 +1762,15 @@
bool InputDispatcher::checkInjectionPermission(const sp<InputWindowHandle>& windowHandle,
const InjectionState* injectionState) {
if (injectionState
- && (windowHandle == NULL || windowHandle->ownerUid != injectionState->injectorUid)
+ && (windowHandle == NULL
+ || windowHandle->getInfo()->ownerUid != injectionState->injectorUid)
&& !hasInjectionPermission(injectionState->injectorPid, injectionState->injectorUid)) {
if (windowHandle != NULL) {
LOGW("Permission denied: injecting event from pid %d uid %d to window %s "
"owned by uid %d",
injectionState->injectorPid, injectionState->injectorUid,
- windowHandle->name.string(),
- windowHandle->ownerUid);
+ windowHandle->getName().string(),
+ windowHandle->getInfo()->ownerUid);
} else {
LOGW("Permission denied: injecting event from pid %d uid %d",
injectionState->injectorPid, injectionState->injectorUid);
@@ -1759,8 +1788,10 @@
if (otherHandle == windowHandle) {
break;
}
- if (otherHandle->visible && ! otherHandle->isTrustedOverlay()
- && otherHandle->frameContainsPoint(x, y)) {
+
+ const InputWindowInfo* otherInfo = otherHandle->getInfo();
+ if (otherInfo->visible && ! otherInfo->isTrustedOverlay()
+ && otherInfo->frameContainsPoint(x, y)) {
return true;
}
}
@@ -1769,7 +1800,7 @@
bool InputDispatcher::isWindowFinishedWithPreviousInputLocked(
const sp<InputWindowHandle>& windowHandle) {
- ssize_t connectionIndex = getConnectionIndexLocked(windowHandle->inputChannel);
+ ssize_t connectionIndex = getConnectionIndexLocked(windowHandle->getInputChannel());
if (connectionIndex >= 0) {
sp<Connection> connection = mConnectionsByReceiveFd.valueAt(connectionIndex);
return connection->outboundQueue.isEmpty();
@@ -1783,15 +1814,15 @@
const sp<InputWindowHandle>& windowHandle) {
if (applicationHandle != NULL) {
if (windowHandle != NULL) {
- String8 label(applicationHandle->name);
+ String8 label(applicationHandle->getName());
label.append(" - ");
- label.append(windowHandle->name);
+ label.append(windowHandle->getName());
return label;
} else {
- return applicationHandle->name;
+ return applicationHandle->getName();
}
} else if (windowHandle != NULL) {
- return windowHandle->name;
+ return windowHandle->getName();
} else {
return String8("<unknown application or window>");
}
@@ -2127,7 +2158,7 @@
if (status) {
LOGE("channel '%s' ~ Could not publish key event, "
"status=%d", connection->getInputChannelName(), status);
- abortBrokenDispatchCycleLocked(currentTime, connection);
+ abortBrokenDispatchCycleLocked(currentTime, connection, true /*notify*/);
return;
}
break;
@@ -2190,7 +2221,7 @@
if (status) {
LOGE("channel '%s' ~ Could not publish motion event, "
"status=%d", connection->getInputChannelName(), status);
- abortBrokenDispatchCycleLocked(currentTime, connection);
+ abortBrokenDispatchCycleLocked(currentTime, connection, true /*notify*/);
return;
}
@@ -2223,7 +2254,7 @@
LOGE("channel '%s' ~ Could not append motion sample "
"for a reason other than out of memory, status=%d",
connection->getInputChannelName(), status);
- abortBrokenDispatchCycleLocked(currentTime, connection);
+ abortBrokenDispatchCycleLocked(currentTime, connection, true /*notify*/);
return;
}
}
@@ -2245,7 +2276,7 @@
if (status) {
LOGE("channel '%s' ~ Could not send dispatch signal, status=%d",
connection->getInputChannelName(), status);
- abortBrokenDispatchCycleLocked(currentTime, connection);
+ abortBrokenDispatchCycleLocked(currentTime, connection, true /*notify*/);
return;
}
@@ -2280,7 +2311,7 @@
if (status) {
LOGE("channel '%s' ~ Could not reset publisher, status=%d",
connection->getInputChannelName(), status);
- abortBrokenDispatchCycleLocked(currentTime, connection);
+ abortBrokenDispatchCycleLocked(currentTime, connection, true /*notify*/);
return;
}
@@ -2324,10 +2355,10 @@
}
void InputDispatcher::abortBrokenDispatchCycleLocked(nsecs_t currentTime,
- const sp<Connection>& connection) {
+ const sp<Connection>& connection, bool notify) {
#if DEBUG_DISPATCH_CYCLE
- LOGD("channel '%s' ~ abortBrokenDispatchCycle",
- connection->getInputChannelName());
+ LOGD("channel '%s' ~ abortBrokenDispatchCycle - notify=%s",
+ connection->getInputChannelName(), toString(notify));
#endif
// Clear the outbound queue.
@@ -2338,8 +2369,10 @@
if (connection->status == Connection::STATUS_NORMAL) {
connection->status = Connection::STATUS_BROKEN;
- // Notify other system components.
- onDispatchCycleBrokenLocked(currentTime, connection);
+ if (notify) {
+ // Notify other system components.
+ onDispatchCycleBrokenLocked(currentTime, connection);
+ }
}
}
@@ -2368,36 +2401,41 @@
return 0; // remove the callback
}
- nsecs_t currentTime = now();
-
+ bool notify;
sp<Connection> connection = d->mConnectionsByReceiveFd.valueAt(connectionIndex);
- if (events & (ALOOPER_EVENT_ERROR | ALOOPER_EVENT_HANGUP)) {
- LOGE("channel '%s' ~ Consumer closed input channel or an error occurred. "
- "events=0x%x", connection->getInputChannelName(), events);
- d->abortBrokenDispatchCycleLocked(currentTime, connection);
- d->runCommandsLockedInterruptible();
- return 0; // remove the callback
- }
+ if (!(events & (ALOOPER_EVENT_ERROR | ALOOPER_EVENT_HANGUP))) {
+ if (!(events & ALOOPER_EVENT_INPUT)) {
+ LOGW("channel '%s' ~ Received spurious callback for unhandled poll event. "
+ "events=0x%x", connection->getInputChannelName(), events);
+ return 1;
+ }
- if (! (events & ALOOPER_EVENT_INPUT)) {
- LOGW("channel '%s' ~ Received spurious callback for unhandled poll event. "
- "events=0x%x", connection->getInputChannelName(), events);
- return 1;
- }
+ bool handled = false;
+ status_t status = connection->inputPublisher.receiveFinishedSignal(&handled);
+ if (!status) {
+ nsecs_t currentTime = now();
+ d->finishDispatchCycleLocked(currentTime, connection, handled);
+ d->runCommandsLockedInterruptible();
+ return 1;
+ }
- bool handled = false;
- status_t status = connection->inputPublisher.receiveFinishedSignal(&handled);
- if (status) {
LOGE("channel '%s' ~ Failed to receive finished signal. status=%d",
connection->getInputChannelName(), status);
- d->abortBrokenDispatchCycleLocked(currentTime, connection);
- d->runCommandsLockedInterruptible();
- return 0; // remove the callback
+ notify = true;
+ } else {
+ // Monitor channels are never explicitly unregistered.
+ // We do it automatically when the remote endpoint is closed so don't warn
+ // about them.
+ notify = !connection->monitor;
+ if (notify) {
+ LOGW("channel '%s' ~ Consumer closed input channel or an error occurred. "
+ "events=0x%x", connection->getInputChannelName(), events);
+ }
}
- d->finishDispatchCycleLocked(currentTime, connection, handled);
- d->runCommandsLockedInterruptible();
- return 1;
+ // Unregister the channel.
+ d->unregisterInputChannelLocked(connection->inputChannel, notify);
+ return 0; // remove the callback
} // release lock
}
@@ -2450,9 +2488,10 @@
InputTarget target;
sp<InputWindowHandle> windowHandle = getWindowHandleLocked(connection->inputChannel);
if (windowHandle != NULL) {
- target.xOffset = -windowHandle->frameLeft;
- target.yOffset = -windowHandle->frameTop;
- target.scaleFactor = windowHandle->scaleFactor;
+ const InputWindowInfo* windowInfo = windowHandle->getInfo();
+ target.xOffset = -windowInfo->frameLeft;
+ target.yOffset = -windowInfo->frameTop;
+ target.scaleFactor = windowInfo->scaleFactor;
} else {
target.xOffset = 0;
target.yOffset = 0;
@@ -2854,9 +2893,9 @@
#if DEBUG_BATCHING
LOGD("Not streaming hover move because the last hovered window "
"is '%s' but the currently hovered window is '%s'.",
- mLastHoverWindowHandle->name.string(),
+ mLastHoverWindowHandle->getName().string(),
hoverWindowHandle != NULL
- ? hoverWindowHandle->name.string() : "<null>");
+ ? hoverWindowHandle->getName().string() : "<null>");
#endif
goto NoBatchingOrStreaming;
}
@@ -3183,7 +3222,7 @@
size_t numWindows = mWindowHandles.size();
for (size_t i = 0; i < numWindows; i++) {
const sp<InputWindowHandle>& windowHandle = mWindowHandles.itemAt(i);
- if (windowHandle->inputChannel == inputChannel) {
+ if (windowHandle->getInputChannel() == inputChannel) {
return windowHandle;
}
}
@@ -3208,17 +3247,18 @@
{ // acquire lock
AutoMutex _l(mLock);
+ Vector<sp<InputWindowHandle> > oldWindowHandles = mWindowHandles;
mWindowHandles = inputWindowHandles;
sp<InputWindowHandle> newFocusedWindowHandle;
bool foundHoveredWindow = false;
for (size_t i = 0; i < mWindowHandles.size(); i++) {
const sp<InputWindowHandle>& windowHandle = mWindowHandles.itemAt(i);
- if (!windowHandle->update() || windowHandle->inputChannel == NULL) {
+ if (!windowHandle->updateInfo() || windowHandle->getInputChannel() == NULL) {
mWindowHandles.removeAt(i--);
continue;
}
- if (windowHandle->hasFocus) {
+ if (windowHandle->getInfo()->hasFocus) {
newFocusedWindowHandle = windowHandle;
}
if (windowHandle == mLastHoverWindowHandle) {
@@ -3234,19 +3274,20 @@
if (mFocusedWindowHandle != NULL) {
#if DEBUG_FOCUS
LOGD("Focus left window: %s",
- mFocusedWindowHandle->name.string());
+ mFocusedWindowHandle->getName().string());
#endif
- if (mFocusedWindowHandle->inputChannel != NULL) {
+ sp<InputChannel> focusedInputChannel = mFocusedWindowHandle->getInputChannel();
+ if (focusedInputChannel != NULL) {
CancelationOptions options(CancelationOptions::CANCEL_NON_POINTER_EVENTS,
"focus left window");
synthesizeCancelationEventsForInputChannelLocked(
- mFocusedWindowHandle->inputChannel, options);
+ focusedInputChannel, options);
}
}
if (newFocusedWindowHandle != NULL) {
#if DEBUG_FOCUS
LOGD("Focus entered window: %s",
- newFocusedWindowHandle->name.string());
+ newFocusedWindowHandle->getName().string());
#endif
}
mFocusedWindowHandle = newFocusedWindowHandle;
@@ -3256,17 +3297,34 @@
TouchedWindow& touchedWindow = mTouchState.windows.editItemAt(i);
if (!hasWindowHandleLocked(touchedWindow.windowHandle)) {
#if DEBUG_FOCUS
- LOGD("Touched window was removed: %s", touchedWindow.windowHandle->name.string());
+ LOGD("Touched window was removed: %s",
+ touchedWindow.windowHandle->getName().string());
#endif
- if (touchedWindow.windowHandle->inputChannel != NULL) {
+ sp<InputChannel> touchedInputChannel =
+ touchedWindow.windowHandle->getInputChannel();
+ if (touchedInputChannel != NULL) {
CancelationOptions options(CancelationOptions::CANCEL_POINTER_EVENTS,
"touched window was removed");
synthesizeCancelationEventsForInputChannelLocked(
- touchedWindow.windowHandle->inputChannel, options);
+ touchedInputChannel, options);
}
mTouchState.windows.removeAt(i--);
}
}
+
+ // Release information for windows that are no longer present.
+ // This ensures that unused input channels are released promptly.
+ // Otherwise, they might stick around until the window handle is destroyed
+ // which might not happen until the next GC.
+ for (size_t i = 0; i < oldWindowHandles.size(); i++) {
+ const sp<InputWindowHandle>& oldWindowHandle = oldWindowHandles.itemAt(i);
+ if (!hasWindowHandleLocked(oldWindowHandle)) {
+#if DEBUG_FOCUS
+ LOGD("Window went away: %s", oldWindowHandle->getName().string());
+#endif
+ oldWindowHandle->releaseInfo();
+ }
+ }
} // release lock
// Wake up poll loop since it may need to make new input dispatching choices.
@@ -3281,15 +3339,17 @@
{ // acquire lock
AutoMutex _l(mLock);
- if (inputApplicationHandle != NULL && inputApplicationHandle->update()) {
+ if (inputApplicationHandle != NULL && inputApplicationHandle->updateInfo()) {
if (mFocusedApplicationHandle != inputApplicationHandle) {
if (mFocusedApplicationHandle != NULL) {
resetTargetsLocked();
+ mFocusedApplicationHandle->releaseInfo();
}
mFocusedApplicationHandle = inputApplicationHandle;
}
} else if (mFocusedApplicationHandle != NULL) {
resetTargetsLocked();
+ mFocusedApplicationHandle->releaseInfo();
mFocusedApplicationHandle.clear();
}
@@ -3469,13 +3529,14 @@
if (mFocusedApplicationHandle != NULL) {
dump.appendFormat(INDENT "FocusedApplication: name='%s', dispatchingTimeout=%0.3fms\n",
- mFocusedApplicationHandle->name.string(),
- mFocusedApplicationHandle->dispatchingTimeout / 1000000.0);
+ mFocusedApplicationHandle->getName().string(),
+ mFocusedApplicationHandle->getDispatchingTimeout(
+ DEFAULT_INPUT_DISPATCHING_TIMEOUT) / 1000000.0);
} else {
dump.append(INDENT "FocusedApplication: <null>\n");
}
dump.appendFormat(INDENT "FocusedWindow: name='%s'\n",
- mFocusedWindowHandle != NULL ? mFocusedWindowHandle->name.string() : "<null>");
+ mFocusedWindowHandle != NULL ? mFocusedWindowHandle->getName().string() : "<null>");
dump.appendFormat(INDENT "TouchDown: %s\n", toString(mTouchState.down));
dump.appendFormat(INDENT "TouchSplit: %s\n", toString(mTouchState.split));
@@ -3486,7 +3547,8 @@
for (size_t i = 0; i < mTouchState.windows.size(); i++) {
const TouchedWindow& touchedWindow = mTouchState.windows[i];
dump.appendFormat(INDENT2 "%d: name='%s', pointerIds=0x%0x, targetFlags=0x%x\n",
- i, touchedWindow.windowHandle->name.string(), touchedWindow.pointerIds.value,
+ i, touchedWindow.windowHandle->getName().string(),
+ touchedWindow.pointerIds.value,
touchedWindow.targetFlags);
}
} else {
@@ -3497,26 +3559,28 @@
dump.append(INDENT "Windows:\n");
for (size_t i = 0; i < mWindowHandles.size(); i++) {
const sp<InputWindowHandle>& windowHandle = mWindowHandles.itemAt(i);
+ const InputWindowInfo* windowInfo = windowHandle->getInfo();
+
dump.appendFormat(INDENT2 "%d: name='%s', paused=%s, hasFocus=%s, hasWallpaper=%s, "
"visible=%s, canReceiveKeys=%s, flags=0x%08x, type=0x%08x, layer=%d, "
"frame=[%d,%d][%d,%d], scale=%f, "
"touchableRegion=",
- i, windowHandle->name.string(),
- toString(windowHandle->paused),
- toString(windowHandle->hasFocus),
- toString(windowHandle->hasWallpaper),
- toString(windowHandle->visible),
- toString(windowHandle->canReceiveKeys),
- windowHandle->layoutParamsFlags, windowHandle->layoutParamsType,
- windowHandle->layer,
- windowHandle->frameLeft, windowHandle->frameTop,
- windowHandle->frameRight, windowHandle->frameBottom,
- windowHandle->scaleFactor);
- dumpRegion(dump, windowHandle->touchableRegion);
- dump.appendFormat(", inputFeatures=0x%08x", windowHandle->inputFeatures);
+ i, windowInfo->name.string(),
+ toString(windowInfo->paused),
+ toString(windowInfo->hasFocus),
+ toString(windowInfo->hasWallpaper),
+ toString(windowInfo->visible),
+ toString(windowInfo->canReceiveKeys),
+ windowInfo->layoutParamsFlags, windowInfo->layoutParamsType,
+ windowInfo->layer,
+ windowInfo->frameLeft, windowInfo->frameTop,
+ windowInfo->frameRight, windowInfo->frameBottom,
+ windowInfo->scaleFactor);
+ dumpRegion(dump, windowInfo->touchableRegion);
+ dump.appendFormat(", inputFeatures=0x%08x", windowInfo->inputFeatures);
dump.appendFormat(", ownerPid=%d, ownerUid=%d, dispatchingTimeout=%0.3fms\n",
- windowHandle->ownerPid, windowHandle->ownerUid,
- windowHandle->dispatchingTimeout / 1000000.0);
+ windowInfo->ownerPid, windowInfo->ownerUid,
+ windowInfo->dispatchingTimeout / 1000000.0);
}
} else {
dump.append(INDENT "Windows: <none>\n");
@@ -3572,7 +3636,7 @@
return BAD_VALUE;
}
- sp<Connection> connection = new Connection(inputChannel, inputWindowHandle);
+ sp<Connection> connection = new Connection(inputChannel, inputWindowHandle, monitor);
status_t status = connection->initialize();
if (status) {
LOGE("Failed to initialize input publisher for input channel '%s', status=%d",
@@ -3602,31 +3666,10 @@
{ // acquire lock
AutoMutex _l(mLock);
- ssize_t connectionIndex = getConnectionIndexLocked(inputChannel);
- if (connectionIndex < 0) {
- LOGW("Attempted to unregister already unregistered input channel '%s'",
- inputChannel->getName().string());
- return BAD_VALUE;
+ status_t status = unregisterInputChannelLocked(inputChannel, false /*notify*/);
+ if (status) {
+ return status;
}
-
- sp<Connection> connection = mConnectionsByReceiveFd.valueAt(connectionIndex);
- mConnectionsByReceiveFd.removeItemsAt(connectionIndex);
-
- connection->status = Connection::STATUS_ZOMBIE;
-
- for (size_t i = 0; i < mMonitoringChannels.size(); i++) {
- if (mMonitoringChannels[i] == inputChannel) {
- mMonitoringChannels.removeAt(i);
- break;
- }
- }
-
- mLooper->removeFd(inputChannel->getReceivePipeFd());
-
- nsecs_t currentTime = now();
- abortBrokenDispatchCycleLocked(currentTime, connection);
-
- runCommandsLockedInterruptible();
} // release lock
// Wake the poll loop because removing the connection may have changed the current
@@ -3635,6 +3678,42 @@
return OK;
}
+status_t InputDispatcher::unregisterInputChannelLocked(const sp<InputChannel>& inputChannel,
+ bool notify) {
+ ssize_t connectionIndex = getConnectionIndexLocked(inputChannel);
+ if (connectionIndex < 0) {
+ LOGW("Attempted to unregister already unregistered input channel '%s'",
+ inputChannel->getName().string());
+ return BAD_VALUE;
+ }
+
+ sp<Connection> connection = mConnectionsByReceiveFd.valueAt(connectionIndex);
+ mConnectionsByReceiveFd.removeItemsAt(connectionIndex);
+
+ if (connection->monitor) {
+ removeMonitorChannelLocked(inputChannel);
+ }
+
+ mLooper->removeFd(inputChannel->getReceivePipeFd());
+
+ nsecs_t currentTime = now();
+ abortBrokenDispatchCycleLocked(currentTime, connection, notify);
+
+ runCommandsLockedInterruptible();
+
+ connection->status = Connection::STATUS_ZOMBIE;
+ return OK;
+}
+
+void InputDispatcher::removeMonitorChannelLocked(const sp<InputChannel>& inputChannel) {
+ for (size_t i = 0; i < mMonitoringChannels.size(); i++) {
+ if (mMonitoringChannels[i] == inputChannel) {
+ mMonitoringChannels.removeAt(i);
+ break;
+ }
+ }
+}
+
ssize_t InputDispatcher::getConnectionIndexLocked(const sp<InputChannel>& inputChannel) {
ssize_t connectionIndex = mConnectionsByReceiveFd.indexOfKey(inputChannel->getReceivePipeFd());
if (connectionIndex >= 0) {
@@ -3736,7 +3815,7 @@
resumeAfterTargetsNotReadyTimeoutLocked(newTimeout,
commandEntry->inputWindowHandle != NULL
- ? commandEntry->inputWindowHandle->inputChannel : NULL);
+ ? commandEntry->inputWindowHandle->getInputChannel() : NULL);
}
void InputDispatcher::doInterceptKeyBeforeDispatchingLockedInterruptible(
@@ -4495,8 +4574,9 @@
// --- InputDispatcher::Connection ---
InputDispatcher::Connection::Connection(const sp<InputChannel>& inputChannel,
- const sp<InputWindowHandle>& inputWindowHandle) :
+ const sp<InputWindowHandle>& inputWindowHandle, bool monitor) :
status(STATUS_NORMAL), inputChannel(inputChannel), inputWindowHandle(inputWindowHandle),
+ monitor(monitor),
inputPublisher(inputChannel),
lastEventTime(LONG_LONG_MAX), lastDispatchTime(LONG_LONG_MAX) {
}
@@ -4627,8 +4707,9 @@
for (size_t i = 0; i < windows.size(); i++) {
const TouchedWindow& window = windows.itemAt(i);
if (window.targetFlags & InputTarget::FLAG_FOREGROUND) {
- if (haveSlipperyForegroundWindow || !(window.windowHandle->layoutParamsFlags
- & InputWindowHandle::FLAG_SLIPPERY)) {
+ if (haveSlipperyForegroundWindow
+ || !(window.windowHandle->getInfo()->layoutParamsFlags
+ & InputWindowInfo::FLAG_SLIPPERY)) {
return false;
}
haveSlipperyForegroundWindow = true;
diff --git a/services/input/InputDispatcher.h b/services/input/InputDispatcher.h
index 3c83691..e78f7bd 100644
--- a/services/input/InputDispatcher.h
+++ b/services/input/InputDispatcher.h
@@ -814,6 +814,7 @@
Status status;
sp<InputChannel> inputChannel; // never null
sp<InputWindowHandle> inputWindowHandle; // may be null
+ bool monitor;
InputPublisher inputPublisher;
InputState inputState;
Queue<DispatchEntry> outboundQueue;
@@ -822,7 +823,7 @@
nsecs_t lastDispatchTime; // the time when the last event was dispatched
explicit Connection(const sp<InputChannel>& inputChannel,
- const sp<InputWindowHandle>& inputWindowHandle);
+ const sp<InputWindowHandle>& inputWindowHandle, bool monitor);
inline const char* getInputChannelName() const { return inputChannel->getName().string(); }
@@ -868,6 +869,7 @@
Vector<EventEntry*> mTempCancelationEvents;
void dispatchOnceInnerLocked(nsecs_t* nextWakeupTime);
+ void dispatchIdleLocked();
// Batches a new sample onto a motion entry.
// Assumes that the we have already checked that we can append samples.
@@ -1073,7 +1075,8 @@
void finishDispatchCycleLocked(nsecs_t currentTime, const sp<Connection>& connection,
bool handled);
void startNextDispatchCycleLocked(nsecs_t currentTime, const sp<Connection>& connection);
- void abortBrokenDispatchCycleLocked(nsecs_t currentTime, const sp<Connection>& connection);
+ void abortBrokenDispatchCycleLocked(nsecs_t currentTime, const sp<Connection>& connection,
+ bool notify);
void drainOutboundQueueLocked(Connection* connection);
static int handleReceiveCallback(int receiveFd, int events, void* data);
@@ -1094,6 +1097,10 @@
void dumpDispatchStateLocked(String8& dump);
void logDispatchStateLocked();
+ // Registration.
+ void removeMonitorChannelLocked(const sp<InputChannel>& inputChannel);
+ status_t unregisterInputChannelLocked(const sp<InputChannel>& inputChannel, bool notify);
+
// Add or remove a connection to the mActiveConnections vector.
void activateConnectionLocked(Connection* connection);
void deactivateConnectionLocked(Connection* connection);
diff --git a/services/input/InputReader.cpp b/services/input/InputReader.cpp
index bfcf8e0..88c19a4 100644
--- a/services/input/InputReader.cpp
+++ b/services/input/InputReader.cpp
@@ -390,7 +390,7 @@
InputDevice* InputReader::createDeviceLocked(int32_t deviceId,
const String8& name, uint32_t classes) {
- InputDevice* device = new InputDevice(&mContext, deviceId, name);
+ InputDevice* device = new InputDevice(&mContext, deviceId, name, classes);
// External devices.
if (classes & INPUT_DEVICE_CLASS_EXTERNAL) {
@@ -842,9 +842,10 @@
// --- InputDevice ---
-InputDevice::InputDevice(InputReaderContext* context, int32_t id, const String8& name) :
- mContext(context), mId(id), mName(name), mSources(0),
- mIsExternal(false), mDropUntilNextSync(false) {
+InputDevice::InputDevice(InputReaderContext* context, int32_t id, const String8& name,
+ uint32_t classes) :
+ mContext(context), mId(id), mName(name), mClasses(classes),
+ mSources(0), mIsExternal(false), mDropUntilNextSync(false) {
}
InputDevice::~InputDevice() {
@@ -2491,7 +2492,8 @@
bool resetNeeded = false;
if (!changes || (changes & (InputReaderConfiguration::CHANGE_DISPLAY_INFO
- | InputReaderConfiguration::CHANGE_POINTER_GESTURE_ENABLEMENT))) {
+ | InputReaderConfiguration::CHANGE_POINTER_GESTURE_ENABLEMENT
+ | InputReaderConfiguration::CHANGE_SHOW_TOUCHES))) {
// Configure device sources, surface dimensions, orientation and
// scaling factors.
configureSurface(when, &resetNeeded);
@@ -2523,17 +2525,17 @@
}
}
- if (getEventHub()->hasRelativeAxis(getDeviceId(), REL_X)
+ if (getEventHub()->hasInputProperty(getDeviceId(), INPUT_PROP_DIRECT)) {
+ // The device is a touch screen.
+ mParameters.deviceType = Parameters::DEVICE_TYPE_TOUCH_SCREEN;
+ } else if (getEventHub()->hasInputProperty(getDeviceId(), INPUT_PROP_POINTER)) {
+ // The device is a pointing device like a track pad.
+ mParameters.deviceType = Parameters::DEVICE_TYPE_POINTER;
+ } else if (getEventHub()->hasRelativeAxis(getDeviceId(), REL_X)
|| getEventHub()->hasRelativeAxis(getDeviceId(), REL_Y)) {
// The device is a cursor device with a touch pad attached.
// By default don't use the touch pad to move the pointer.
mParameters.deviceType = Parameters::DEVICE_TYPE_TOUCH_PAD;
- } else if (getEventHub()->hasInputProperty(getDeviceId(), INPUT_PROP_POINTER)) {
- // The device is a pointing device like a track pad.
- mParameters.deviceType = Parameters::DEVICE_TYPE_POINTER;
- } else if (getEventHub()->hasInputProperty(getDeviceId(), INPUT_PROP_DIRECT)) {
- // The device is a touch screen.
- mParameters.deviceType = Parameters::DEVICE_TYPE_TOUCH_SCREEN;
} else {
// The device is a touch pad of unknown purpose.
mParameters.deviceType = Parameters::DEVICE_TYPE_POINTER;
@@ -2681,18 +2683,19 @@
bool deviceModeChanged;
if (mDeviceMode != oldDeviceMode) {
deviceModeChanged = true;
-
- if (mDeviceMode == DEVICE_MODE_POINTER) {
- if (mPointerController == NULL) {
- mPointerController = getPolicy()->obtainPointerController(getDeviceId());
- }
- } else {
- mPointerController.clear();
- }
-
mOrientedRanges.clear();
}
+ // Create pointer controller if needed.
+ if (mDeviceMode == DEVICE_MODE_POINTER ||
+ (mDeviceMode == DEVICE_MODE_DIRECT && mConfig.showTouches)) {
+ if (mPointerController == NULL) {
+ mPointerController = getPolicy()->obtainPointerController(getDeviceId());
+ }
+ } else {
+ mPointerController.clear();
+ }
+
bool orientationChanged = mSurfaceOrientation != orientation;
if (orientationChanged) {
mSurfaceOrientation = orientation;
@@ -3380,7 +3383,7 @@
cookPointerData();
// Dispatch the touches either directly or by translation through a pointer on screen.
- if (mPointerController != NULL) {
+ if (mDeviceMode == DEVICE_MODE_POINTER) {
for (BitSet32 idBits(mCurrentRawPointerData.touchingIdBits); !idBits.isEmpty(); ) {
uint32_t id = idBits.clearFirstMarkedBit();
const RawPointerData::Pointer& pointer = mCurrentRawPointerData.pointerForId(id);
@@ -3418,6 +3421,17 @@
dispatchPointerUsage(when, policyFlags, pointerUsage);
} else {
+ if (mDeviceMode == DEVICE_MODE_DIRECT
+ && mConfig.showTouches && mPointerController != NULL) {
+ mPointerController->setPresentation(PointerControllerInterface::PRESENTATION_SPOT);
+ mPointerController->fade(PointerControllerInterface::TRANSITION_GRADUAL);
+
+ mPointerController->setButtonState(mCurrentButtonState);
+ mPointerController->setSpots(mCurrentCookedPointerData.pointerCoords,
+ mCurrentCookedPointerData.idToIndex,
+ mCurrentCookedPointerData.touchingIdBits);
+ }
+
dispatchHoverExit(when, policyFlags);
dispatchTouches(when, policyFlags);
dispatchHoverEnterAndMove(when, policyFlags);
@@ -3442,7 +3456,7 @@
}
void TouchInputMapper::timeoutExpired(nsecs_t when) {
- if (mPointerController != NULL) {
+ if (mDeviceMode == DEVICE_MODE_POINTER) {
if (mPointerUsage == POINTER_USAGE_GESTURES) {
dispatchPointerGestures(when, 0 /*policyFlags*/, true /*isTimeout*/);
}
@@ -5746,6 +5760,11 @@
if (!changes) { // first time only
// Collect all axes.
for (int32_t abs = 0; abs <= ABS_MAX; abs++) {
+ if (!(getAbsAxisUsage(abs, getDevice()->getClasses())
+ & INPUT_DEVICE_CLASS_JOYSTICK)) {
+ continue; // axis must be claimed by a different device
+ }
+
RawAbsoluteAxisInfo rawAxisInfo;
getAbsoluteAxisInfo(abs, &rawAxisInfo);
if (rawAxisInfo.valid) {
diff --git a/services/input/InputReader.h b/services/input/InputReader.h
index bad96df..a122c97 100644
--- a/services/input/InputReader.h
+++ b/services/input/InputReader.h
@@ -56,6 +56,9 @@
// The display size or orientation changed.
CHANGE_DISPLAY_INFO = 1 << 2,
+ // The visible touches option changed.
+ CHANGE_SHOW_TOUCHES = 1 << 3,
+
// All devices must be reopened.
CHANGE_MUST_REOPEN = 1 << 31,
};
@@ -140,6 +143,9 @@
// will cover this portion of the display diagonal.
float pointerGestureZoomSpeedRatio;
+ // True to show the location of touches on the touch screen as spots.
+ bool showTouches;
+
InputReaderConfiguration() :
virtualKeyQuietTime(0),
pointerVelocityControlParameters(1.0f, 500.0f, 3000.0f, 3.0f),
@@ -155,7 +161,8 @@
pointerGestureSwipeTransitionAngleCosine(0.2588f), // cosine of 75 degrees
pointerGestureSwipeMaxWidthRatio(0.25f),
pointerGestureMovementSpeedRatio(0.8f),
- pointerGestureZoomSpeedRatio(0.3f) { }
+ pointerGestureZoomSpeedRatio(0.3f),
+ showTouches(false) { }
bool getDisplayInfo(int32_t displayId, bool external,
int32_t* width, int32_t* height, int32_t* orientation) const;
@@ -423,12 +430,13 @@
/* Represents the state of a single input device. */
class InputDevice {
public:
- InputDevice(InputReaderContext* context, int32_t id, const String8& name);
+ InputDevice(InputReaderContext* context, int32_t id, const String8& name, uint32_t classes);
~InputDevice();
inline InputReaderContext* getContext() { return mContext; }
inline int32_t getId() { return mId; }
inline const String8& getName() { return mName; }
+ inline uint32_t getClasses() { return mClasses; }
inline uint32_t getSources() { return mSources; }
inline bool isExternal() { return mIsExternal; }
@@ -476,10 +484,11 @@
private:
InputReaderContext* mContext;
int32_t mId;
+ String8 mName;
+ uint32_t mClasses;
Vector<InputMapper*> mMappers;
- String8 mName;
uint32_t mSources;
bool mIsExternal;
bool mDropUntilNextSync;
diff --git a/services/input/InputWindow.cpp b/services/input/InputWindow.cpp
index 0ce8867..fe61918 100644
--- a/services/input/InputWindow.cpp
+++ b/services/input/InputWindow.cpp
@@ -22,25 +22,43 @@
namespace android {
-// --- InputWindowHandle ---
+// --- InputWindowInfo ---
-bool InputWindowHandle::touchableRegionContainsPoint(int32_t x, int32_t y) const {
+bool InputWindowInfo::touchableRegionContainsPoint(int32_t x, int32_t y) const {
return touchableRegion.contains(x, y);
}
-bool InputWindowHandle::frameContainsPoint(int32_t x, int32_t y) const {
+bool InputWindowInfo::frameContainsPoint(int32_t x, int32_t y) const {
return x >= frameLeft && x <= frameRight
&& y >= frameTop && y <= frameBottom;
}
-bool InputWindowHandle::isTrustedOverlay() const {
+bool InputWindowInfo::isTrustedOverlay() const {
return layoutParamsType == TYPE_INPUT_METHOD
|| layoutParamsType == TYPE_INPUT_METHOD_DIALOG
|| layoutParamsType == TYPE_SECURE_SYSTEM_OVERLAY;
}
-bool InputWindowHandle::supportsSplitTouch() const {
+bool InputWindowInfo::supportsSplitTouch() const {
return layoutParamsFlags & FLAG_SPLIT_TOUCH;
}
+
+// --- InputWindowHandle ---
+
+InputWindowHandle::InputWindowHandle(const sp<InputApplicationHandle>& inputApplicationHandle) :
+ inputApplicationHandle(inputApplicationHandle), mInfo(NULL) {
+}
+
+InputWindowHandle::~InputWindowHandle() {
+ delete mInfo;
+}
+
+void InputWindowHandle::releaseInfo() {
+ if (mInfo) {
+ delete mInfo;
+ mInfo = NULL;
+ }
+}
+
} // namespace android
diff --git a/services/input/InputWindow.h b/services/input/InputWindow.h
index 272081c..8861bee 100644
--- a/services/input/InputWindow.h
+++ b/services/input/InputWindow.h
@@ -30,15 +30,9 @@
namespace android {
/*
- * A handle to a window that can receive input.
- *
- * Used by the native input dispatcher to indirectly refer to the window manager objects
- * that describe a window.
+ * Describes the properties of a window that can receive input.
*/
-class InputWindowHandle : public RefBase {
-public:
- const sp<InputApplicationHandle> inputApplicationHandle;
-
+struct InputWindowInfo {
// Window flags from WindowManager.LayoutParams
enum {
FLAG_ALLOW_LOCK_WHILE_SCREEN_ON = 0x00000001,
@@ -116,7 +110,6 @@
INPUT_FEATURE_DISABLE_TOUCH_PAD_GESTURES = 0x00000001,
};
- sp<InputWindowHandle> inputWindowHandle;
sp<InputChannel> inputChannel;
String8 name;
int32_t layoutParamsFlags;
@@ -149,6 +142,34 @@
bool isTrustedOverlay() const;
bool supportsSplitTouch() const;
+};
+
+
+/*
+ * Handle for a window that can receive input.
+ *
+ * Used by the native input dispatcher to indirectly refer to the window manager objects
+ * that describe a window.
+ */
+class InputWindowHandle : public RefBase {
+public:
+ const sp<InputApplicationHandle> inputApplicationHandle;
+
+ inline const InputWindowInfo* getInfo() const {
+ return mInfo;
+ }
+
+ inline sp<InputChannel> getInputChannel() const {
+ return mInfo ? mInfo->inputChannel : NULL;
+ }
+
+ inline String8 getName() const {
+ return mInfo ? mInfo->name : String8("<invalid>");
+ }
+
+ inline nsecs_t getDispatchingTimeout(nsecs_t defaultValue) const {
+ return mInfo ? mInfo->dispatchingTimeout : defaultValue;
+ }
/**
* Requests that the state of this object be updated to reflect
@@ -159,12 +180,19 @@
*
* Returns true on success, or false if the handle is no longer valid.
*/
- virtual bool update() = 0;
+ virtual bool updateInfo() = 0;
+
+ /**
+ * Releases the storage used by the associated information when it is
+ * no longer needed.
+ */
+ void releaseInfo();
protected:
- InputWindowHandle(const sp<InputApplicationHandle>& inputApplicationHandle) :
- inputApplicationHandle(inputApplicationHandle) { }
- virtual ~InputWindowHandle() { }
+ InputWindowHandle(const sp<InputApplicationHandle>& inputApplicationHandle);
+ virtual ~InputWindowHandle();
+
+ InputWindowInfo* mInfo;
};
} // namespace android
diff --git a/services/input/tests/InputReader_test.cpp b/services/input/tests/InputReader_test.cpp
index 32f948b..a086208 100644
--- a/services/input/tests/InputReader_test.cpp
+++ b/services/input/tests/InputReader_test.cpp
@@ -852,8 +852,8 @@
mNextDevice = device;
}
- InputDevice* newDevice(int32_t deviceId, const String8& name) {
- return new InputDevice(&mContext, deviceId, name);
+ InputDevice* newDevice(int32_t deviceId, const String8& name, uint32_t classes) {
+ return new InputDevice(&mContext, deviceId, name, classes);
}
protected:
@@ -912,7 +912,7 @@
FakeInputMapper* addDeviceWithFakeInputMapper(int32_t deviceId,
const String8& name, uint32_t classes, uint32_t sources,
const PropertyMap* configuration) {
- InputDevice* device = mReader->newDevice(deviceId, name);
+ InputDevice* device = mReader->newDevice(deviceId, name, classes);
FakeInputMapper* mapper = new FakeInputMapper(device, sources);
device->addMapper(mapper);
mReader->setNextDevice(device);
@@ -1211,6 +1211,7 @@
protected:
static const char* DEVICE_NAME;
static const int32_t DEVICE_ID;
+ static const uint32_t DEVICE_CLASSES;
sp<FakeEventHub> mFakeEventHub;
sp<FakeInputReaderPolicy> mFakePolicy;
@@ -1226,7 +1227,7 @@
mFakeContext = new FakeInputReaderContext(mFakeEventHub, mFakePolicy, mFakeListener);
mFakeEventHub->addDevice(DEVICE_ID, String8(DEVICE_NAME), 0);
- mDevice = new InputDevice(mFakeContext, DEVICE_ID, String8(DEVICE_NAME));
+ mDevice = new InputDevice(mFakeContext, DEVICE_ID, String8(DEVICE_NAME), DEVICE_CLASSES);
}
virtual void TearDown() {
@@ -1241,10 +1242,13 @@
const char* InputDeviceTest::DEVICE_NAME = "device";
const int32_t InputDeviceTest::DEVICE_ID = 1;
+const uint32_t InputDeviceTest::DEVICE_CLASSES = INPUT_DEVICE_CLASS_KEYBOARD
+ | INPUT_DEVICE_CLASS_TOUCH | INPUT_DEVICE_CLASS_JOYSTICK;
TEST_F(InputDeviceTest, ImmutableProperties) {
ASSERT_EQ(DEVICE_ID, mDevice->getId());
ASSERT_STREQ(DEVICE_NAME, mDevice->getName());
+ ASSERT_EQ(DEVICE_CLASSES, mDevice->getClasses());
}
TEST_F(InputDeviceTest, WhenNoMappersAreRegistered_DeviceIsIgnored) {
@@ -1390,6 +1394,7 @@
protected:
static const char* DEVICE_NAME;
static const int32_t DEVICE_ID;
+ static const uint32_t DEVICE_CLASSES;
sp<FakeEventHub> mFakeEventHub;
sp<FakeInputReaderPolicy> mFakePolicy;
@@ -1402,7 +1407,7 @@
mFakePolicy = new FakeInputReaderPolicy();
mFakeListener = new FakeInputListener();
mFakeContext = new FakeInputReaderContext(mFakeEventHub, mFakePolicy, mFakeListener);
- mDevice = new InputDevice(mFakeContext, DEVICE_ID, String8(DEVICE_NAME));
+ mDevice = new InputDevice(mFakeContext, DEVICE_ID, String8(DEVICE_NAME), DEVICE_CLASSES);
mFakeEventHub->addDevice(DEVICE_ID, String8(DEVICE_NAME), 0);
}
@@ -1483,6 +1488,7 @@
const char* InputMapperTest::DEVICE_NAME = "device";
const int32_t InputMapperTest::DEVICE_ID = 1;
+const uint32_t InputMapperTest::DEVICE_CLASSES = 0; // not needed for current tests
// --- SwitchInputMapperTest ---
diff --git a/services/java/com/android/server/BackupManagerService.java b/services/java/com/android/server/BackupManagerService.java
index b3309e5..997318a 100644
--- a/services/java/com/android/server/BackupManagerService.java
+++ b/services/java/com/android/server/BackupManagerService.java
@@ -197,14 +197,14 @@
= 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 @@
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 @@
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 @@
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 @@
added = false;
pkgList = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST);
}
+
if (pkgList == null || pkgList.length == 0) {
return;
}
@@ -1665,9 +1674,7 @@
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 @@
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 @@
// 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 @@
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 @@
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 @@
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 @@
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 @@
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 bfca851..2348d76 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;
@@ -701,6 +703,12 @@
return result.toArray(new NetworkInfo[result.size()]);
}
+ @Override
+ public boolean isNetworkSupported(int networkType) {
+ enforceAccessPermission();
+ return (isNetworkTypeValid(networkType) && (mNetTrackers[networkType] != null));
+ }
+
/**
* Return LinkProperties for the active (i.e., connected) default
* network interface. It is assumed that at most one default network
@@ -1418,6 +1426,9 @@
// 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 +1487,13 @@
}
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 +1572,10 @@
}
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 +1593,7 @@
}
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 +1604,10 @@
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 +2300,6 @@
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/InputMethodManagerService.java b/services/java/com/android/server/InputMethodManagerService.java
index 38bcebc..bb831f5 100644
--- a/services/java/com/android/server/InputMethodManagerService.java
+++ b/services/java/com/android/server/InputMethodManagerService.java
@@ -1682,7 +1682,12 @@
for (int i = 0; i < packageNum; ++i) {
if (packageInfos[i].equals(imi.getPackageName())) {
mFileManager.addInputMethodSubtypes(imi, subtypes);
- buildInputMethodListLocked(mMethodList, mMethodMap);
+ final long ident = Binder.clearCallingIdentity();
+ try {
+ buildInputMethodListLocked(mMethodList, mMethodMap);
+ } finally {
+ Binder.restoreCallingIdentity(ident);
+ }
return true;
}
}
@@ -1707,7 +1712,7 @@
return;
}
- long ident = Binder.clearCallingIdentity();
+ final long ident = Binder.clearCallingIdentity();
try {
setInputMethodLocked(id, subtypeId);
} finally {
@@ -3065,17 +3070,11 @@
public void addInputMethodSubtypes(
InputMethodInfo imi, InputMethodSubtype[] additionalSubtypes) {
synchronized (mMethodMap) {
- final HashSet<InputMethodSubtype> existingSubtypes =
- new HashSet<InputMethodSubtype>();
- for (int i = 0; i < imi.getSubtypeCount(); ++i) {
- existingSubtypes.add(imi.getSubtypeAt(i));
- }
-
final ArrayList<InputMethodSubtype> subtypes = new ArrayList<InputMethodSubtype>();
final int N = additionalSubtypes.length;
for (int i = 0; i < N; ++i) {
final InputMethodSubtype subtype = additionalSubtypes[i];
- if (!subtypes.contains(subtype) && !existingSubtypes.contains(subtype)) {
+ if (!subtypes.contains(subtype)) {
subtypes.add(subtype);
}
}
diff --git a/services/java/com/android/server/NotificationManagerService.java b/services/java/com/android/server/NotificationManagerService.java
index 7a3a344..6ee20bb 100755
--- a/services/java/com/android/server/NotificationManagerService.java
+++ b/services/java/com/android/server/NotificationManagerService.java
@@ -101,6 +101,7 @@
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 @@
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 @@
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 @@
}
}
- // 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/SystemServer.java b/services/java/com/android/server/SystemServer.java
index d0e8b5e..2714fc5 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -350,7 +350,6 @@
Slog.i(TAG, "Wi-Fi Service");
wifi = new WifiService(context);
ServiceManager.addService(Context.WIFI_SERVICE, wifi);
- wifi.checkAndStartWifi();
} catch (Throwable e) {
reportWtf("starting Wi-Fi Service", e);
}
@@ -361,6 +360,7 @@
ServiceManager.addService(Context.CONNECTIVITY_SERVICE, connectivity);
networkStats.bindConnectivityManager(connectivity);
networkPolicy.bindConnectivityManager(connectivity);
+ wifi.checkAndStartWifi();
wifiP2p.connectivityServiceReady();
} catch (Throwable e) {
reportWtf("starting Connectivity Service", e);
diff --git a/services/java/com/android/server/TextServicesManagerService.java b/services/java/com/android/server/TextServicesManagerService.java
index f6c369e..c792b33 100644
--- a/services/java/com/android/server/TextServicesManagerService.java
+++ b/services/java/com/android/server/TextServicesManagerService.java
@@ -201,7 +201,7 @@
Settings.Secure.getString(mContext.getContentResolver(),
Settings.Secure.SELECTED_SPELL_CHECKER_SUBTYPE);
if (DBG) {
- Slog.w(TAG, "getCurrentSpellChecker: " + subtypeHashCodeStr);
+ Slog.w(TAG, "getCurrentSpellCheckerSubtype: " + subtypeHashCodeStr);
}
final SpellCheckerInfo sci = getCurrentSpellChecker(null);
if (sci == null || sci.getSubtypeCount() == 0) {
@@ -509,7 +509,8 @@
listener.mScLocale, listener.mScListener, listener.mBundle);
listener.mTsListener.onServiceConnected(session);
} catch (RemoteException e) {
- Slog.e(TAG, "Exception in getting the spell checker session: " + e);
+ Slog.e(TAG, "Exception in getting the spell checker session."
+ + "Reconnect to the spellchecker. ", e);
removeAll();
return;
}
@@ -579,8 +580,12 @@
Slog.d(TAG, "cleanLocked");
}
if (mListeners.isEmpty()) {
- if (mSpellCheckerBindGroups.containsKey(this)) {
- mSpellCheckerBindGroups.remove(this);
+ final String sciId = mInternalConnection.mSciId;
+ if (mSpellCheckerBindGroups.containsKey(sciId)) {
+ if (DBG) {
+ Slog.d(TAG, "Remove bind group.");
+ }
+ mSpellCheckerBindGroups.remove(sciId);
}
// Unbind service when there is no active clients.
mContext.unbindService(mInternalConnection);
diff --git a/services/java/com/android/server/net/NetworkPolicyManagerService.java b/services/java/com/android/server/net/NetworkPolicyManagerService.java
index 77f53c2..8af90ff 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.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.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.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 @@
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 bb0a0d1..e0dc96f 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.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 @@
}
// 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/pm/PackageManagerService.java b/services/java/com/android/server/pm/PackageManagerService.java
index b8797d18..bfb244b 100644
--- a/services/java/com/android/server/pm/PackageManagerService.java
+++ b/services/java/com/android/server/pm/PackageManagerService.java
@@ -78,8 +78,6 @@
import android.os.Environment;
import android.os.FileObserver;
import android.os.FileUtils;
-import android.os.FileUtils.FileStatus;
-import android.os.Debug;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.IBinder;
@@ -706,6 +704,7 @@
Runtime.getRuntime().gc();
}
if (msg.obj != null) {
+ @SuppressWarnings("unchecked")
Set<SdInstallArgs> args = (Set<SdInstallArgs>) msg.obj;
if (DEBUG_SD_INSTALL) Log.i(TAG, "Unloading all containers");
// Unload containers
@@ -3039,10 +3038,6 @@
return null;
}
mScanningPath = scanFile;
- if (pkg == null) {
- mLastScanError = PackageManager.INSTALL_PARSE_FAILED_BAD_PACKAGE_NAME;
- return null;
- }
if ((parseFlags&PackageParser.PARSE_IS_SYSTEM) != 0) {
pkg.applicationInfo.flags |= ApplicationInfo.FLAG_SYSTEM;
diff --git a/services/java/com/android/server/wm/BlackFrame.java b/services/java/com/android/server/wm/BlackFrame.java
index 36f5dcb..10e294b 100644
--- a/services/java/com/android/server/wm/BlackFrame.java
+++ b/services/java/com/android/server/wm/BlackFrame.java
@@ -51,8 +51,8 @@
mTmpMatrix.setTranslate(left, top);
mTmpMatrix.postConcat(matrix);
mTmpMatrix.getValues(mTmpFloats);
- surface.setPosition((int)mTmpFloats[Matrix.MTRANS_X],
- (int)mTmpFloats[Matrix.MTRANS_Y]);
+ surface.setPosition(mTmpFloats[Matrix.MTRANS_X],
+ mTmpFloats[Matrix.MTRANS_Y]);
surface.setMatrix(
mTmpFloats[Matrix.MSCALE_X], mTmpFloats[Matrix.MSKEW_Y],
mTmpFloats[Matrix.MSKEW_X], mTmpFloats[Matrix.MSCALE_Y]);
diff --git a/services/java/com/android/server/wm/DragState.java b/services/java/com/android/server/wm/DragState.java
index b37d1c2..dd440bf 100644
--- a/services/java/com/android/server/wm/DragState.java
+++ b/services/java/com/android/server/wm/DragState.java
@@ -139,6 +139,9 @@
mServerChannel.dispose();
mClientChannel = null;
mServerChannel = null;
+
+ mDragWindowHandle = null;
+ mDragApplicationHandle = null;
}
}
@@ -270,7 +273,7 @@
if (WindowManagerService.SHOW_TRANSACTIONS) Slog.i(WindowManagerService.TAG, ">>> OPEN TRANSACTION notifyMoveLw");
Surface.openTransaction();
try {
- mSurface.setPosition((int)(x - mThumbOffsetX), (int)(y - mThumbOffsetY));
+ mSurface.setPosition(x - mThumbOffsetX, y - mThumbOffsetY);
if (WindowManagerService.SHOW_TRANSACTIONS) Slog.i(WindowManagerService.TAG, " DRAG "
+ mSurface + ": pos=(" +
(int)(x - mThumbOffsetX) + "," + (int)(y - mThumbOffsetY) + ")");
diff --git a/services/java/com/android/server/wm/InputApplicationHandle.java b/services/java/com/android/server/wm/InputApplicationHandle.java
index d78b1d9..1812f11 100644
--- a/services/java/com/android/server/wm/InputApplicationHandle.java
+++ b/services/java/com/android/server/wm/InputApplicationHandle.java
@@ -46,7 +46,10 @@
@Override
protected void finalize() throws Throwable {
- nativeDispose();
- super.finalize();
+ try {
+ nativeDispose();
+ } finally {
+ super.finalize();
+ }
}
}
diff --git a/services/java/com/android/server/wm/InputManager.java b/services/java/com/android/server/wm/InputManager.java
index c8b18c8..60333a3 100644
--- a/services/java/com/android/server/wm/InputManager.java
+++ b/services/java/com/android/server/wm/InputManager.java
@@ -94,6 +94,7 @@
private static native boolean nativeTransferTouchFocus(InputChannel fromChannel,
InputChannel toChannel);
private static native void nativeSetPointerSpeed(int speed);
+ private static native void nativeSetShowTouches(boolean enabled);
private static native String nativeDump();
private static native void nativeMonitor();
@@ -147,7 +148,10 @@
nativeStart();
registerPointerSpeedSettingObserver();
+ registerShowTouchesSettingObserver();
+
updatePointerSpeedFromSettings();
+ updateShowTouchesFromSettings();
}
public void setDisplaySize(int displayId, int width, int height,
@@ -454,6 +458,32 @@
return speed;
}
+ public void updateShowTouchesFromSettings() {
+ int setting = getShowTouchesSetting(0);
+ nativeSetShowTouches(setting != 0);
+ }
+
+ private void registerShowTouchesSettingObserver() {
+ mContext.getContentResolver().registerContentObserver(
+ Settings.System.getUriFor(Settings.System.SHOW_TOUCHES), true,
+ new ContentObserver(mWindowManagerService.mH) {
+ @Override
+ public void onChange(boolean selfChange) {
+ updateShowTouchesFromSettings();
+ }
+ });
+ }
+
+ private int getShowTouchesSetting(int defaultValue) {
+ int result = defaultValue;
+ try {
+ result = Settings.System.getInt(mContext.getContentResolver(),
+ Settings.System.SHOW_TOUCHES);
+ } catch (SettingNotFoundException snfe) {
+ }
+ return result;
+ }
+
public void dump(PrintWriter pw) {
String dumpStr = nativeDump();
if (dumpStr != null) {
diff --git a/services/java/com/android/server/wm/InputMonitor.java b/services/java/com/android/server/wm/InputMonitor.java
index 12ef238..573a7d42 100644
--- a/services/java/com/android/server/wm/InputMonitor.java
+++ b/services/java/com/android/server/wm/InputMonitor.java
@@ -17,10 +17,10 @@
package com.android.server.wm;
import android.graphics.Rect;
-import android.os.Process;
import android.os.RemoteException;
import android.util.Log;
import android.util.Slog;
+import android.view.InputChannel;
import android.view.KeyEvent;
import android.view.WindowManager;
@@ -160,13 +160,21 @@
if (WindowManagerService.DEBUG_DRAG) {
Log.d(WindowManagerService.TAG, "Inserting drag window");
}
- addInputWindowHandleLw(mService.mDragState.mDragWindowHandle);
+ final InputWindowHandle dragWindowHandle = mService.mDragState.mDragWindowHandle;
+ if (dragWindowHandle != null) {
+ addInputWindowHandleLw(dragWindowHandle);
+ } else {
+ Slog.w(WindowManagerService.TAG, "Drag is in progress but there is no "
+ + "drag window handle.");
+ }
}
final int N = windows.size();
for (int i = N - 1; i >= 0; i--) {
final WindowState child = windows.get(i);
- if (child.mInputChannel == null || child.mRemoved) {
+ final InputChannel inputChannel = child.mInputChannel;
+ final InputWindowHandle inputWindowHandle = child.mInputWindowHandle;
+ if (inputChannel == null || inputWindowHandle == null || child.mRemoved) {
// Skip this window because it cannot possibly receive input.
continue;
}
@@ -186,8 +194,6 @@
}
// Add a window to our list of input windows.
- final InputWindowHandle inputWindowHandle = child.mInputWindowHandle;
- inputWindowHandle.inputChannel = child.mInputChannel;
inputWindowHandle.name = child.toString();
inputWindowHandle.layoutParamsFlags = flags;
inputWindowHandle.layoutParamsType = type;
diff --git a/services/java/com/android/server/wm/InputWindowHandle.java b/services/java/com/android/server/wm/InputWindowHandle.java
index abf68d9..264877c 100644
--- a/services/java/com/android/server/wm/InputWindowHandle.java
+++ b/services/java/com/android/server/wm/InputWindowHandle.java
@@ -98,7 +98,10 @@
@Override
protected void finalize() throws Throwable {
- nativeDispose();
- super.finalize();
+ try {
+ nativeDispose();
+ } finally {
+ super.finalize();
+ }
}
}
diff --git a/services/java/com/android/server/wm/ScreenRotationAnimation.java b/services/java/com/android/server/wm/ScreenRotationAnimation.java
index 16af151..3c475a0 100644
--- a/services/java/com/android/server/wm/ScreenRotationAnimation.java
+++ b/services/java/com/android/server/wm/ScreenRotationAnimation.java
@@ -148,8 +148,8 @@
void setSnapshotTransform(Matrix matrix, float alpha) {
if (mSurface != null) {
matrix.getValues(mTmpFloats);
- mSurface.setPosition((int)mTmpFloats[Matrix.MTRANS_X],
- (int)mTmpFloats[Matrix.MTRANS_Y]);
+ mSurface.setPosition(mTmpFloats[Matrix.MTRANS_X],
+ mTmpFloats[Matrix.MTRANS_Y]);
mSurface.setMatrix(
mTmpFloats[Matrix.MSCALE_X], mTmpFloats[Matrix.MSKEW_Y],
mTmpFloats[Matrix.MSKEW_X], mTmpFloats[Matrix.MSCALE_Y]);
diff --git a/services/java/com/android/server/wm/Session.java b/services/java/com/android/server/wm/Session.java
index 50b251f..2e0c9ab 100644
--- a/services/java/com/android/server/wm/Session.java
+++ b/services/java/com/android/server/wm/Session.java
@@ -281,8 +281,8 @@
if (WindowManagerService.SHOW_TRANSACTIONS) Slog.i(WindowManagerService.TAG, ">>> OPEN TRANSACTION performDrag");
Surface.openTransaction();
try {
- surface.setPosition((int)(touchX - thumbCenterX),
- (int)(touchY - thumbCenterY));
+ surface.setPosition(touchX - thumbCenterX,
+ touchY - thumbCenterY);
surface.setAlpha(.7071f);
surface.setLayer(mService.mDragState.getDragLayerLw());
surface.show();
diff --git a/services/java/com/android/server/wm/ViewServer.java b/services/java/com/android/server/wm/ViewServer.java
index 70cb26a..a763e2c 100644
--- a/services/java/com/android/server/wm/ViewServer.java
+++ b/services/java/com/android/server/wm/ViewServer.java
@@ -319,7 +319,7 @@
}
}
} catch (Exception e) {
- Slog.w(LOG_TAG, "Connection error: ", e);
+ // Ignore
} finally {
if (out != null) {
try {
diff --git a/services/java/com/android/server/wm/WindowManagerService.java b/services/java/com/android/server/wm/WindowManagerService.java
index 192d32b..755a268 100644
--- a/services/java/com/android/server/wm/WindowManagerService.java
+++ b/services/java/com/android/server/wm/WindowManagerService.java
@@ -2051,10 +2051,11 @@
return res;
}
- if (outInputChannel != null) {
+ if (outInputChannel != null && (attrs.inputFeatures
+ & WindowManager.LayoutParams.INPUT_FEATURE_NO_INPUT_CHANNEL) == 0) {
String name = win.makeInputChannelName();
InputChannel[] inputChannels = InputChannel.openInputChannelPair(name);
- win.mInputChannel = inputChannels[0];
+ win.setInputChannel(inputChannels[0]);
inputChannels[1].transferTo(outInputChannel);
mInputManager.registerInputChannel(win.mInputChannel, win.mInputWindowHandle);
@@ -2497,6 +2498,10 @@
int attrChanges = 0;
int flagChanges = 0;
if (attrs != null) {
+ if (win.mAttrs.type != attrs.type) {
+ throw new IllegalArgumentException(
+ "Window type can not be changed after the window is added.");
+ }
flagChanges = win.mAttrs.flags ^= attrs.flags;
attrChanges = win.mAttrs.copyFrom(attrs);
}
@@ -2533,6 +2538,7 @@
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;
@@ -4701,6 +4707,8 @@
mH.sendMessageDelayed(msg, 30*1000);
}
+ mPolicy.systemBooted();
+
performEnableScreen();
}
@@ -7919,17 +7927,32 @@
if (mWindowDetachedWallpaper != windowDetachedWallpaper) {
if (DEBUG_WALLPAPER) Slog.v(TAG,
"Detached wallpaper changed from " + mWindowDetachedWallpaper
- + windowDetachedWallpaper);
+ + " to " + windowDetachedWallpaper);
mWindowDetachedWallpaper = windowDetachedWallpaper;
wallpaperMayChange = true;
}
if (windowAnimationBackgroundColor != 0) {
+ // If the 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();
@@ -8438,8 +8461,8 @@
+ Integer.toHexString(diff));
}
win.mConfiguration = mCurConfiguration;
- win.mClient.resized(win.mSurfaceW, win.mSurfaceH, win.mLastContentInsets,
- win.mLastVisibleInsets, win.mDrawPending,
+ win.mClient.resized((int)win.mSurfaceW, (int)win.mSurfaceH,
+ win.mLastContentInsets, win.mLastVisibleInsets, win.mDrawPending,
configChanged ? win.mConfiguration : null);
win.mContentInsetsChanged = false;
win.mVisibleInsetsChanged = false;
diff --git a/services/java/com/android/server/wm/WindowState.java b/services/java/com/android/server/wm/WindowState.java
index cdd0047..bb36d3a7 100644
--- a/services/java/com/android/server/wm/WindowState.java
+++ b/services/java/com/android/server/wm/WindowState.java
@@ -30,6 +30,7 @@
import android.graphics.Matrix;
import android.graphics.PixelFormat;
import android.graphics.Rect;
+import android.graphics.RectF;
import android.graphics.Region;
import android.os.IBinder;
import android.os.RemoteException;
@@ -110,7 +111,7 @@
* are in the screen's coordinate space (WITH the compatibility scale
* applied).
*/
- final Rect mShownFrame = new Rect();
+ final RectF mShownFrame = new RectF();
/**
* Set when we have changed the size of the surface, to know that
@@ -267,7 +268,7 @@
// For debugging, this is the last information given to the surface flinger.
boolean mSurfaceShown;
- int mSurfaceX, mSurfaceY, mSurfaceW, mSurfaceH;
+ float mSurfaceX, mSurfaceY, mSurfaceW, mSurfaceH;
int mSurfaceLayer;
float mSurfaceAlpha;
@@ -518,7 +519,7 @@
return mFrame;
}
- public Rect getShownFrameLw() {
+ public RectF getShownFrameLw() {
return mShownFrame;
}
@@ -1128,8 +1129,8 @@
mDtDx = tmpFloats[Matrix.MSKEW_Y];
mDsDy = tmpFloats[Matrix.MSKEW_X];
mDtDy = tmpFloats[Matrix.MSCALE_Y];
- int x = (int)tmpFloats[Matrix.MTRANS_X];
- int y = (int)tmpFloats[Matrix.MTRANS_Y];
+ float x = tmpFloats[Matrix.MTRANS_X];
+ float y = tmpFloats[Matrix.MTRANS_Y];
int w = frame.width();
int h = frame.height();
mShownFrame.set(x, y, x+w, y+h);
@@ -1236,7 +1237,8 @@
* Input Manager uses when discarding windows from input consideration.
*/
boolean isPotentialDragTarget() {
- return isVisibleNow() && (mInputChannel != null) && !mRemoved;
+ return isVisibleNow() && !mRemoved
+ && mInputChannel != null && mInputWindowHandle != null;
}
/**
@@ -1372,7 +1374,16 @@
// we are doing this as part of processing a death note.)
}
}
-
+
+ void setInputChannel(InputChannel inputChannel) {
+ if (mInputChannel != null) {
+ throw new IllegalStateException("Window already has an input channel.");
+ }
+
+ mInputChannel = inputChannel;
+ mInputWindowHandle.inputChannel = inputChannel;
+ }
+
void disposeInputChannel() {
if (mInputChannel != null) {
mService.mInputManager.unregisterInputChannel(mInputChannel);
@@ -1380,6 +1391,8 @@
mInputChannel.dispose();
mInputChannel = null;
}
+
+ mInputWindowHandle.inputChannel = null;
}
private class DeathRecipient implements IBinder.DeathRecipient {
diff --git a/services/jni/com_android_server_InputApplicationHandle.cpp b/services/jni/com_android_server_InputApplicationHandle.cpp
index 7de67d9..c76ab53 100644
--- a/services/jni/com_android_server_InputApplicationHandle.cpp
+++ b/services/jni/com_android_server_InputApplicationHandle.cpp
@@ -49,25 +49,30 @@
return env->NewLocalRef(mObjWeak);
}
-bool NativeInputApplicationHandle::update() {
+bool NativeInputApplicationHandle::updateInfo() {
JNIEnv* env = AndroidRuntime::getJNIEnv();
jobject obj = env->NewLocalRef(mObjWeak);
if (!obj) {
+ releaseInfo();
return false;
}
+ if (!mInfo) {
+ mInfo = new InputApplicationInfo();
+ }
+
jstring nameObj = jstring(env->GetObjectField(obj,
gInputApplicationHandleClassInfo.name));
if (nameObj) {
const char* nameStr = env->GetStringUTFChars(nameObj, NULL);
- name.setTo(nameStr);
+ mInfo->name.setTo(nameStr);
env->ReleaseStringUTFChars(nameObj, nameStr);
env->DeleteLocalRef(nameObj);
} else {
- name.setTo("<null>");
+ mInfo->name.setTo("<null>");
}
- dispatchingTimeout = env->GetLongField(obj,
+ mInfo->dispatchingTimeout = env->GetLongField(obj,
gInputApplicationHandleClassInfo.dispatchingTimeoutNanos);
env->DeleteLocalRef(obj);
diff --git a/services/jni/com_android_server_InputApplicationHandle.h b/services/jni/com_android_server_InputApplicationHandle.h
index 04cd9d6..89d48c6 100644
--- a/services/jni/com_android_server_InputApplicationHandle.h
+++ b/services/jni/com_android_server_InputApplicationHandle.h
@@ -31,7 +31,7 @@
jobject getInputApplicationHandleObjLocalRef(JNIEnv* env);
- virtual bool update();
+ virtual bool updateInfo();
private:
jweak mObjWeak;
diff --git a/services/jni/com_android_server_InputManager.cpp b/services/jni/com_android_server_InputManager.cpp
index f2a0a71..f976301 100644
--- a/services/jni/com_android_server_InputManager.cpp
+++ b/services/jni/com_android_server_InputManager.cpp
@@ -179,6 +179,7 @@
void setInputDispatchMode(bool enabled, bool frozen);
void setSystemUiVisibility(int32_t visibility);
void setPointerSpeed(int32_t speed);
+ void setShowTouches(bool enabled);
/* --- InputReaderPolicyInterface implementation --- */
@@ -233,6 +234,9 @@
// True if pointer gestures are enabled.
bool pointerGesturesEnabled;
+ // Show touches feature enable/disable.
+ bool showTouches;
+
// Sprite controller singleton, created on first use.
sp<SpriteController> spriteController;
@@ -276,6 +280,7 @@
mLocked.systemUiVisibility = ASYSTEM_UI_VISIBILITY_STATUS_BAR_VISIBLE;
mLocked.pointerSpeed = 0;
mLocked.pointerGesturesEnabled = true;
+ mLocked.showTouches = false;
}
sp<EventHub> eventHub = new EventHub();
@@ -431,6 +436,8 @@
* POINTER_SPEED_EXPONENT);
outConfig->pointerGesturesEnabled = mLocked.pointerGesturesEnabled;
+ outConfig->showTouches = mLocked.showTouches;
+
outConfig->setDisplayInfo(0, false /*external*/,
mLocked.displayWidth, mLocked.displayHeight, mLocked.displayOrientation);
outConfig->setDisplayInfo(0, true /*external*/,
@@ -611,8 +618,9 @@
size_t numWindows = windowHandles.size();
for (size_t i = 0; i < numWindows; i++) {
const sp<InputWindowHandle>& windowHandle = windowHandles.itemAt(i);
- if (windowHandle->hasFocus && (windowHandle->inputFeatures
- & InputWindowHandle::INPUT_FEATURE_DISABLE_TOUCH_PAD_GESTURES)) {
+ const InputWindowInfo* windowInfo = windowHandle->getInfo();
+ if (windowInfo && windowInfo->hasFocus && (windowInfo->inputFeatures
+ & InputWindowInfo::INPUT_FEATURE_DISABLE_TOUCH_PAD_GESTURES)) {
newPointerGesturesEnabled = false;
}
}
@@ -678,6 +686,22 @@
InputReaderConfiguration::CHANGE_POINTER_SPEED);
}
+void NativeInputManager::setShowTouches(bool enabled) {
+ { // acquire lock
+ AutoMutex _l(mLock);
+
+ if (mLocked.showTouches == enabled) {
+ return;
+ }
+
+ LOGI("Setting show touches feature to %s.", enabled ? "enabled" : "disabled");
+ mLocked.showTouches = enabled;
+ } // release lock
+
+ mInputManager->getReader()->requestRefreshConfiguration(
+ InputReaderConfiguration::CHANGE_SHOW_TOUCHES);
+}
+
bool NativeInputManager::isScreenOn() {
return android_server_PowerManagerService_isScreenOn();
}
@@ -1063,8 +1087,9 @@
status_t status = gNativeInputManager->registerInputChannel(
env, inputChannel, inputWindowHandle, monitor);
if (status) {
- jniThrowRuntimeException(env, "Failed to register input channel. "
- "Check logs for details.");
+ String8 message;
+ message.appendFormat("Failed to register input channel. status=%d", status);
+ jniThrowRuntimeException(env, message.string());
return;
}
@@ -1090,9 +1115,10 @@
android_view_InputChannel_setDisposeCallback(env, inputChannelObj, NULL, NULL);
status_t status = gNativeInputManager->unregisterInputChannel(env, inputChannel);
- if (status) {
- jniThrowRuntimeException(env, "Failed to unregister input channel. "
- "Check logs for details.");
+ if (status && status != BAD_VALUE) { // ignore already unregistered channel
+ String8 message;
+ message.appendFormat("Failed to unregister input channel. status=%d", status);
+ jniThrowRuntimeException(env, message.string());
}
}
@@ -1276,6 +1302,15 @@
gNativeInputManager->setPointerSpeed(speed);
}
+static void android_server_InputManager_nativeSetShowTouches(JNIEnv* env,
+ jclass clazz, jboolean enabled) {
+ if (checkInputManagerUnitialized(env)) {
+ return;
+ }
+
+ gNativeInputManager->setShowTouches(enabled);
+}
+
static jstring android_server_InputManager_nativeDump(JNIEnv* env, jclass clazz) {
if (checkInputManagerUnitialized(env)) {
return NULL;
@@ -1343,6 +1378,8 @@
(void*) android_server_InputManager_nativeTransferTouchFocus },
{ "nativeSetPointerSpeed", "(I)V",
(void*) android_server_InputManager_nativeSetPointerSpeed },
+ { "nativeSetShowTouches", "(Z)V",
+ (void*) android_server_InputManager_nativeSetShowTouches },
{ "nativeDump", "()Ljava/lang/String;",
(void*) android_server_InputManager_nativeDump },
{ "nativeMonitor", "()V",
diff --git a/services/jni/com_android_server_InputWindowHandle.cpp b/services/jni/com_android_server_InputWindowHandle.cpp
index 09be881..0607eee 100644
--- a/services/jni/com_android_server_InputWindowHandle.cpp
+++ b/services/jni/com_android_server_InputWindowHandle.cpp
@@ -74,77 +74,82 @@
return env->NewLocalRef(mObjWeak);
}
-bool NativeInputWindowHandle::update() {
+bool NativeInputWindowHandle::updateInfo() {
JNIEnv* env = AndroidRuntime::getJNIEnv();
jobject obj = env->NewLocalRef(mObjWeak);
if (!obj) {
+ releaseInfo();
return false;
}
+ if (!mInfo) {
+ mInfo = new InputWindowInfo();
+ }
+
jobject inputChannelObj = env->GetObjectField(obj,
gInputWindowHandleClassInfo.inputChannel);
if (inputChannelObj) {
- inputChannel = android_view_InputChannel_getInputChannel(env, inputChannelObj);
+ mInfo->inputChannel = android_view_InputChannel_getInputChannel(env, inputChannelObj);
env->DeleteLocalRef(inputChannelObj);
} else {
- inputChannel = NULL;
+ mInfo->inputChannel.clear();
}
jstring nameObj = jstring(env->GetObjectField(obj,
gInputWindowHandleClassInfo.name));
if (nameObj) {
const char* nameStr = env->GetStringUTFChars(nameObj, NULL);
- name.setTo(nameStr);
+ mInfo->name.setTo(nameStr);
env->ReleaseStringUTFChars(nameObj, nameStr);
env->DeleteLocalRef(nameObj);
} else {
- name.setTo("<null>");
+ mInfo->name.setTo("<null>");
}
- layoutParamsFlags = env->GetIntField(obj,
+ mInfo->layoutParamsFlags = env->GetIntField(obj,
gInputWindowHandleClassInfo.layoutParamsFlags);
- layoutParamsType = env->GetIntField(obj,
+ mInfo->layoutParamsType = env->GetIntField(obj,
gInputWindowHandleClassInfo.layoutParamsType);
- dispatchingTimeout = env->GetLongField(obj,
+ mInfo->dispatchingTimeout = env->GetLongField(obj,
gInputWindowHandleClassInfo.dispatchingTimeoutNanos);
- frameLeft = env->GetIntField(obj,
+ mInfo->frameLeft = env->GetIntField(obj,
gInputWindowHandleClassInfo.frameLeft);
- frameTop = env->GetIntField(obj,
+ mInfo->frameTop = env->GetIntField(obj,
gInputWindowHandleClassInfo.frameTop);
- frameRight = env->GetIntField(obj,
+ mInfo->frameRight = env->GetIntField(obj,
gInputWindowHandleClassInfo.frameRight);
- frameBottom = env->GetIntField(obj,
+ mInfo->frameBottom = env->GetIntField(obj,
gInputWindowHandleClassInfo.frameBottom);
- scaleFactor = env->GetFloatField(obj,
+ mInfo->scaleFactor = env->GetFloatField(obj,
gInputWindowHandleClassInfo.scaleFactor);
jobject regionObj = env->GetObjectField(obj,
gInputWindowHandleClassInfo.touchableRegion);
if (regionObj) {
SkRegion* region = android_graphics_Region_getSkRegion(env, regionObj);
- touchableRegion.set(*region);
+ mInfo->touchableRegion.set(*region);
env->DeleteLocalRef(regionObj);
} else {
- touchableRegion.setEmpty();
+ mInfo->touchableRegion.setEmpty();
}
- visible = env->GetBooleanField(obj,
+ mInfo->visible = env->GetBooleanField(obj,
gInputWindowHandleClassInfo.visible);
- canReceiveKeys = env->GetBooleanField(obj,
+ mInfo->canReceiveKeys = env->GetBooleanField(obj,
gInputWindowHandleClassInfo.canReceiveKeys);
- hasFocus = env->GetBooleanField(obj,
+ mInfo->hasFocus = env->GetBooleanField(obj,
gInputWindowHandleClassInfo.hasFocus);
- hasWallpaper = env->GetBooleanField(obj,
+ mInfo->hasWallpaper = env->GetBooleanField(obj,
gInputWindowHandleClassInfo.hasWallpaper);
- paused = env->GetBooleanField(obj,
+ mInfo->paused = env->GetBooleanField(obj,
gInputWindowHandleClassInfo.paused);
- layer = env->GetIntField(obj,
+ mInfo->layer = env->GetIntField(obj,
gInputWindowHandleClassInfo.layer);
- ownerPid = env->GetIntField(obj,
+ mInfo->ownerPid = env->GetIntField(obj,
gInputWindowHandleClassInfo.ownerPid);
- ownerUid = env->GetIntField(obj,
+ mInfo->ownerUid = env->GetIntField(obj,
gInputWindowHandleClassInfo.ownerUid);
- inputFeatures = env->GetIntField(obj,
+ mInfo->inputFeatures = env->GetIntField(obj,
gInputWindowHandleClassInfo.inputFeatures);
env->DeleteLocalRef(obj);
diff --git a/services/jni/com_android_server_InputWindowHandle.h b/services/jni/com_android_server_InputWindowHandle.h
index 913c3b1..2cfa17d3 100644
--- a/services/jni/com_android_server_InputWindowHandle.h
+++ b/services/jni/com_android_server_InputWindowHandle.h
@@ -32,7 +32,7 @@
jobject getInputWindowHandleObjLocalRef(JNIEnv* env);
- virtual bool update();
+ virtual bool updateInfo();
private:
jweak mObjWeak;
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
index f8925b8..edbc7b0 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -212,6 +212,24 @@
} else {
hwcl->transform = finalTransform;
}
+
+ if (isCropped()) {
+ hwcl->sourceCrop.left = mCurrentCrop.left;
+ hwcl->sourceCrop.top = mCurrentCrop.top;
+ 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) {
+ hwcl->sourceCrop.right = buffer->width;
+ hwcl->sourceCrop.bottom = buffer->height;
+ } else {
+ hwcl->sourceCrop.right = mTransformedBounds.width();
+ hwcl->sourceCrop.bottom = mTransformedBounds.height();
+ }
+ }
}
void Layer::setPerFrameData(hwc_layer_t* hwcl) {
@@ -225,23 +243,6 @@
} else {
hwcl->handle = buffer->handle;
}
-
- if (isCropped()) {
- hwcl->sourceCrop.left = mCurrentCrop.left;
- hwcl->sourceCrop.top = mCurrentCrop.top;
- hwcl->sourceCrop.right = mCurrentCrop.right;
- hwcl->sourceCrop.bottom = mCurrentCrop.bottom;
- } else {
- hwcl->sourceCrop.left = 0;
- hwcl->sourceCrop.top = 0;
- if (buffer != NULL) {
- hwcl->sourceCrop.right = buffer->width;
- hwcl->sourceCrop.bottom = buffer->height;
- } else {
- hwcl->sourceCrop.right = mTransformedBounds.width();
- hwcl->sourceCrop.bottom = mTransformedBounds.height();
- }
- }
}
void Layer::onDraw(const Region& clip) const
@@ -416,8 +417,7 @@
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 @@
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 @@
// 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 4cc245a..603fb60 100644
--- a/services/surfaceflinger/LayerBase.cpp
+++ b/services/surfaceflinger/LayerBase.cpp
@@ -45,7 +45,6 @@
mFlinger(flinger), mFiltering(false),
mNeedsFiltering(false),
mOrientation(0),
- mLeft(0), mTop(0),
mTransactionFlags(0),
mPremultipliedAlpha(true), mName("unnamed"), mDebug(false),
mInvalidate(0)
@@ -119,7 +118,7 @@
return android_atomic_or(flags, &mTransactionFlags);
}
-bool LayerBase::setPosition(int32_t x, int32_t y) {
+bool LayerBase::setPosition(float x, float y) {
if (mCurrentState.transform.tx() == x && mCurrentState.transform.ty() == y)
return false;
mCurrentState.sequence++;
@@ -259,8 +258,6 @@
mOrientation = tr.getOrientation();
mTransform = tr;
mTransformedBounds = tr.makeBounds(w, h);
- mLeft = tr.tx();
- mTop = tr.ty();
}
void LayerBase::lockPageFlip(bool& recomputeVisibleRegions)
@@ -335,15 +332,16 @@
reinterpret_cast<hwc_rect_t const *>(
visibleRegionScreen.getArray(
&hwcl->visibleRegionScreen.numRects));
+
+ 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;
- hwcl->sourceCrop.left = 0;
- hwcl->sourceCrop.top = 0;
- hwcl->sourceCrop.right = mTransformedBounds.width();
- hwcl->sourceCrop.bottom = mTransformedBounds.height();
}
void LayerBase::setFiltering(bool filtering)
@@ -476,10 +474,10 @@
snprintf(buffer, SIZE,
"+ %s %p\n"
" "
- "z=%9d, pos=(%4d,%4d), size=(%4d,%4d), "
+ "z=%9d, pos=(%g,%g), size=(%4d,%4d), "
"isOpaque=%1d, needsDithering=%1d, invalidate=%1d, "
"alpha=0x%02x, flags=0x%08x, tr=[%.2f, %.2f][%.2f, %.2f]\n",
- getTypeId(), this, s.z, tx(), ty(), s.w, s.h,
+ getTypeId(), this, s.z, s.transform.tx(), s.transform.ty(), s.w, s.h,
isOpaque(), needsDithering(), contentDirty,
s.alpha, s.flags,
s.transform[0][0], s.transform[0][1],
diff --git a/services/surfaceflinger/LayerBase.h b/services/surfaceflinger/LayerBase.h
index 2cd3a94..d20f06a 100644
--- a/services/surfaceflinger/LayerBase.h
+++ b/services/surfaceflinger/LayerBase.h
@@ -84,7 +84,7 @@
String8 getName() const;
// modify current state
- bool setPosition(int32_t x, int32_t y);
+ bool setPosition(float x, float y);
bool setLayer(uint32_t z);
bool setSize(uint32_t w, uint32_t h);
bool setAlpha(uint8_t alpha);
@@ -217,8 +217,6 @@
inline State& currentState() { return mCurrentState; }
int32_t getOrientation() const { return mOrientation; }
- int tx() const { return mLeft; }
- int ty() const { return mTop; }
protected:
const GraphicPlane& graphicPlane(int dpy) const;
@@ -250,8 +248,6 @@
Transform mTransform;
GLfloat mVertices[4][2];
Rect mTransformedBounds;
- int mLeft;
- int mTop;
// these are protected by an external lock
State mCurrentState;
diff --git a/services/surfaceflinger/Transform.cpp b/services/surfaceflinger/Transform.cpp
index 05b7527..ba345ce 100644
--- a/services/surfaceflinger/Transform.cpp
+++ b/services/surfaceflinger/Transform.cpp
@@ -91,12 +91,12 @@
return type() > TRANSLATE;
}
-int Transform::tx() const {
- return floorf(mMatrix[2][0] + 0.5f);
+float Transform::tx() const {
+ return mMatrix[2][0];
}
-int Transform::ty() const {
- return floorf(mMatrix[2][1] + 0.5f);
+float Transform::ty() const {
+ return mMatrix[2][1];
}
void Transform::reset() {
@@ -239,7 +239,9 @@
out.set(transform(reg.bounds()));
}
} else {
- out = reg.translate(tx(), ty());
+ int xpos = floorf(tx() + 0.5f);
+ int ypos = floorf(ty() + 0.5f);
+ out = reg.translate(xpos, ypos);
}
return out;
}
diff --git a/services/surfaceflinger/Transform.h b/services/surfaceflinger/Transform.h
index 8fa5b86..ec74243 100644
--- a/services/surfaceflinger/Transform.h
+++ b/services/surfaceflinger/Transform.h
@@ -64,8 +64,8 @@
uint32_t getOrientation() const;
float const* operator [] (int i) const; // returns column i
- int tx() const;
- int ty() const;
+ float tx() const;
+ float ty() const;
// modify the transform
void reset();
diff --git a/services/tests/servicestests/src/com/android/server/NetworkPolicyManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/NetworkPolicyManagerServiceTest.java
index f67d251..e892b5e 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 @@
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 @@
future = expectMeteredIfacesChanged();
replay();
- mServiceContext.sendBroadcast(new Intent(CONNECTIVITY_ACTION));
+ mServiceContext.sendBroadcast(new Intent(CONNECTIVITY_ACTION_IMMEDIATE));
future.get();
verifyAndReset();
@@ -615,7 +615,7 @@
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 6dd8cd6..54f3bb0 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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
expectNetworkStatsSummary(buildEmptyStats());
replay();
- mServiceContext.sendBroadcast(new Intent(CONNECTIVITY_ACTION));
+ mServiceContext.sendBroadcast(new Intent(CONNECTIVITY_ACTION_IMMEDIATE));
verifyAndReset();
// create some traffic
@@ -509,7 +509,7 @@
expectNetworkStatsSummary(buildEmptyStats());
replay();
- mServiceContext.sendBroadcast(new Intent(CONNECTIVITY_ACTION));
+ mServiceContext.sendBroadcast(new Intent(CONNECTIVITY_ACTION_IMMEDIATE));
verifyAndReset();
// create some traffic
@@ -541,7 +541,7 @@
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 @@
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 @@
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/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index 1954172..c59dd3c 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -60,12 +60,13 @@
/** @hide */
public TelephonyManager(Context context) {
+ context = context.getApplicationContext();
if (sContext == null) {
- sContext = context.getApplicationContext();
+ sContext = context;
sRegistry = ITelephonyRegistry.Stub.asInterface(ServiceManager.getService(
"telephony.registry"));
- } else {
+ } else if (sContext != context) {
Log.e(TAG, "Hidden constructor called more than once per process!");
Log.e(TAG, "Original: " + sContext.getPackageName() + ", new: " +
context.getPackageName());
diff --git a/telephony/java/com/android/internal/telephony/IccCard.java b/telephony/java/com/android/internal/telephony/IccCard.java
index bce9991..955849d 100644
--- a/telephony/java/com/android/internal/telephony/IccCard.java
+++ b/telephony/java/com/android/internal/telephony/IccCard.java
@@ -470,19 +470,6 @@
} 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 @@
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/RIL.java b/telephony/java/com/android/internal/telephony/RIL.java
index 3e13a86..bd35058 100644
--- a/telephony/java/com/android/internal/telephony/RIL.java
+++ b/telephony/java/com/android/internal/telephony/RIL.java
@@ -29,6 +29,7 @@
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
+import android.net.ConnectivityManager;
import android.net.LocalSocket;
import android.net.LocalSocketAddress;
import android.os.AsyncResult;
@@ -230,8 +231,6 @@
Object mLastNITZTimeInfo;
- private static final String WIFI_ONLY_CARRIER = "wifi-only";
-
//***** Events
static final int EVENT_SEND = 1;
@@ -626,10 +625,9 @@
Looper looper = mSenderThread.getLooper();
mSender = new RILSender(looper);
- // TODO: Provide a common API for determining if a
- // device is wifi-only. bug: 3480713
- String carrier = SystemProperties.get("ro.carrier");
- if (WIFI_ONLY_CARRIER.equals(carrier)) {
+ ConnectivityManager cm = (ConnectivityManager)context.getSystemService(
+ Context.CONNECTIVITY_SERVICE);
+ if (cm.isNetworkSupported(ConnectivityManager.TYPE_MOBILE) == false) {
riljLog("Not starting RILReceiver: wifi-only");
} else {
riljLog("Starting RILReceiver");
diff --git a/telephony/java/com/android/internal/telephony/cdma/CdmaLteServiceStateTracker.java b/telephony/java/com/android/internal/telephony/cdma/CdmaLteServiceStateTracker.java
index 134227a..e92a276 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 @@
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 @@
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 e17d98d..6743da0 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 android.content.res.Resources;
+import java.util.TimeZone;
/**
@@ -231,7 +232,7 @@
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 28034cc..d84715e 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 @@
// 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 @@
@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 643f709..1fa278a 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 @@
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 @@
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 0000000..7bc5f857
--- /dev/null
+++ b/tests/BandwidthTests/Android.mk
@@ -0,0 +1,24 @@
+#
+# 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_MODULE_TAGS := tests
+
+LOCAL_PACKAGE_NAME := BandwidthEnforcementTest
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
+
+include $(BUILD_PACKAGE)
diff --git a/tests/BandwidthTests/AndroidManifest.xml b/tests/BandwidthTests/AndroidManifest.xml
new file mode 100644
index 0000000..19f38ca
--- /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 0000000..3392b21
--- /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 0000000..a4a78c2
--- /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 0000000..f0e43ac
--- /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 0000000..a2427f5
--- /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/tools/aidl/aidl.cpp b/tools/aidl/aidl.cpp
index 92f5b64..fb4067a 100644
--- a/tools/aidl/aidl.cpp
+++ b/tools/aidl/aidl.cpp
@@ -575,12 +575,19 @@
// ==========================================================
void
-generate_dep_file(const Options& options)
+generate_dep_file(const Options& options, const document_item_type* items)
{
- /* we open the file in binary mode to ensure that the same output is
- * generated on all platforms !!
- */
- FILE* to = fopen(options.depFileName.c_str(), "wb");
+ /* we open the file in binary mode to ensure that the same output is
+ * generated on all platforms !!
+ */
+ FILE* to = NULL;
+ if (options.autoDepFile) {
+ string fileName = options.outputFileName + ".d";
+ to = fopen(fileName.c_str(), "wb");
+ } else {
+ to = fopen(options.depFileName.c_str(), "wb");
+ }
+
if (to == NULL) {
return;
}
@@ -591,7 +598,12 @@
slash = "";
}
- fprintf(to, "%s: \\\n", options.outputFileName.c_str());
+ if (items->item_type == INTERFACE_TYPE) {
+ fprintf(to, "%s: \\\n", options.outputFileName.c_str());
+ } else {
+ // parcelable: there's no output file.
+ fprintf(to, " : \\\n");
+ }
fprintf(to, " %s %s\n", options.inputFileName.c_str(), slash);
while (import) {
@@ -611,44 +623,60 @@
// ==========================================================
static string
-generate_outputFileName(const Options& options, const document_item_type* items)
+generate_outputFileName2(const Options& options, const buffer_type& name, const char* package)
{
string result;
- // items has already been checked to have only one interface.
- if (items->item_type == INTERFACE_TYPE) {
- interface_type* type = (interface_type*)items;
+ // create the path to the destination folder based on the
+ // interface package name
+ result = options.outputBaseFolder;
+ result += OS_PATH_SEPARATOR;
- // create the path to the destination folder based on the
- // interface package name
- result = options.outputBaseFolder;
- result += OS_PATH_SEPARATOR;
-
- string package = type->package;
- size_t len = package.length();
- for (size_t i=0; i<len; i++) {
- if (package[i] == '.') {
- package[i] = OS_PATH_SEPARATOR;
- }
+ string packageStr = package;
+ size_t len = packageStr.length();
+ for (size_t i=0; i<len; i++) {
+ if (packageStr[i] == '.') {
+ packageStr[i] = OS_PATH_SEPARATOR;
}
-
- result += package;
-
- // add the filename by replacing the .aidl extension to .java
- const char* p = strchr(type->name.data, '.');
- len = p ? p-type->name.data : strlen(type->name.data);
-
- result += OS_PATH_SEPARATOR;
- result.append(type->name.data, len);
- result += ".java";
}
+ result += packageStr;
+
+ // add the filename by replacing the .aidl extension to .java
+ const char* p = strchr(name.data, '.');
+ len = p ? p-name.data : strlen(name.data);
+
+ result += OS_PATH_SEPARATOR;
+ result.append(name.data, len);
+ result += ".java";
+
return result;
}
// ==========================================================
+static string
+generate_outputFileName(const Options& options, const document_item_type* items)
+{
+ // items has already been checked to have only one interface.
+ if (items->item_type == INTERFACE_TYPE) {
+ interface_type* type = (interface_type*)items;
+
+ return generate_outputFileName2(options, type->name, type->package);
+ } else if (items->item_type == PARCELABLE_TYPE) {
+ parcelable_type* type = (parcelable_type*)items;
+ return generate_outputFileName2(options, type->name, type->package);
+ }
+
+ // I don't think we can come here, but safer than returning NULL.
+ string result;
+ return result;
+}
+
+
+
+// ==========================================================
static void
-check_outputFileName(const string& path) {
+check_outputFilePath(const string& path) {
size_t len = path.length();
for (size_t i=0; i<len ; i++) {
if (path[i] == OS_PATH_SEPARATOR) {
@@ -756,7 +784,7 @@
// ==========================================================
static int
-compile_aidl(const Options& options)
+compile_aidl(Options& options)
{
int err = 0, N;
@@ -850,27 +878,30 @@
return 1;
}
+ // if needed, generate the outputFileName from the outputBaseFolder
+ if (options.outputFileName.length() == 0 &&
+ options.outputBaseFolder.length() > 0) {
+ options.outputFileName = generate_outputFileName(options, mainDoc);
+ }
+
+ // if we were asked to, generate a make dependency file
+ // unless it's a parcelable *and* it's supposed to fail on parcelable
+ if ((options.autoDepFile || options.depFileName != "") &&
+ !(onlyParcelable && options.failOnParcelable)) {
+ // make sure the folders of the output file all exists
+ check_outputFilePath(options.outputFileName);
+ generate_dep_file(options, mainDoc);
+ }
+
// they didn't ask to fail on parcelables, so just exit quietly.
if (onlyParcelable && !options.failOnParcelable) {
return 0;
}
- // if we were asked to, generate a make dependency file
- if (options.depFileName != "") {
- generate_dep_file(options);
- }
-
- // if needed, generate the outputFileName from the outputBaseFolder
- string outputFileName = options.outputFileName;
- if (outputFileName.length() == 0 &&
- options.outputBaseFolder.length() > 0) {
- outputFileName = generate_outputFileName(options, mainDoc);
- }
-
// make sure the folders of the output file all exists
- check_outputFileName(outputFileName);
+ check_outputFilePath(options.outputFileName);
- err = generate_java(outputFileName, options.inputFileName.c_str(),
+ err = generate_java(options.outputFileName, options.inputFileName.c_str(),
(interface_type*)mainDoc);
return err;
diff --git a/tools/aidl/options.cpp b/tools/aidl/options.cpp
index 0aa7db2..7b2daeb 100644
--- a/tools/aidl/options.cpp
+++ b/tools/aidl/options.cpp
@@ -15,6 +15,7 @@
"OPTIONS:\n"
" -I<DIR> search path for import statements.\n"
" -d<FILE> generate dependency file.\n"
+ " -a generate dependency file next to the output file with the name based on the input file.\n"
" -p<FILE> file created by --preprocess to import.\n"
" -o<FOLDER> base output folder for generated files.\n"
" -b fail when trying to compile a parcelable.\n"
@@ -49,6 +50,7 @@
options->task = COMPILE_AIDL;
options->failOnParcelable = false;
+ options->autoDepFile = false;
// OPTIONS
while (i < argc) {
@@ -73,6 +75,9 @@
return usage();
}
}
+ else if (s[1] == 'a') {
+ options->autoDepFile = true;
+ }
else if (s[1] == 'p') {
if (len > 2) {
options->preprocessedFiles.push_back(s+2);
diff --git a/tools/aidl/options.h b/tools/aidl/options.h
index d88d988..387e37d 100644
--- a/tools/aidl/options.h
+++ b/tools/aidl/options.h
@@ -23,6 +23,7 @@
string outputFileName;
string outputBaseFolder;
string depFileName;
+ bool autoDepFile;
vector<string> filesToPreprocess;
};
diff --git a/voip/java/com/android/server/sip/SipSessionGroup.java b/voip/java/com/android/server/sip/SipSessionGroup.java
index 3b3cbf3..49effa8 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.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 @@
}
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());
+ int time = -1;
+ ContactHeader contact = (ContactHeader) response.getHeader(ContactHeader.NAME);
+ if (contact != null) {
+ time = contact.getExpires();
}
- return expires;
+ 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 c1f6785..450f816 100644
--- a/wifi/java/android/net/wifi/WifiNative.java
+++ b/wifi/java/android/net/wifi/WifiNative.java
@@ -60,7 +60,9 @@
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 @@
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");
}
@@ -269,8 +284,11 @@
break;
}
+ //TODO: Add persist behavior once the supplicant interaction is fixed for both
+ // group and client scenarios
/* Persist unless there is an explicit request to not do so*/
- if (config.persist != WifiP2pConfig.Persist.NO) args.add("persistent");
+ //if (config.persist != WifiP2pConfig.Persist.NO) args.add("persistent");
+
if (joinExistingGroup) args.add("join");
int groupOwnerIntent = config.groupOwnerIntent;
diff --git a/wifi/java/android/net/wifi/WifiStateMachine.java b/wifi/java/android/net/wifi/WifiStateMachine.java
index c6f7da2..d116e5b 100644
--- a/wifi/java/android/net/wifi/WifiStateMachine.java
+++ b/wifi/java/android/net/wifi/WifiStateMachine.java
@@ -1911,6 +1911,12 @@
transitionTo(mDriverUnloadingState);
break;
case CMD_START_SUPPLICANT:
+ try {
+ mNwService.wifiFirmwareReload(mInterfaceName, "STA");
+ } catch (Exception e) {
+ Log.e(TAG, "Failed to reload STA firmware " + e);
+ // continue
+ }
//A runtime crash can leave the interface up and
//this affects connectivity when supplicant starts up.
//Ensure interface is down before a supplicant start.
@@ -2524,23 +2530,11 @@
public boolean processMessage(Message message) {
if (DBG) Log.d(TAG, getName() + message.toString() + "\n");
switch (message.what) {
- case CMD_START_DRIVER:
- mWakeLock.acquire();
- WifiNative.startDriverCommand();
- mWakeLock.release();
- break;
- case WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT:
- SupplicantState state = handleSupplicantStateChange(message);
- /* A driver start causes supplicant to first report an INTERFACE_DISABLED
- * state before transitioning out of it for connection. Stay in
- * DriverStoppedState until we get an INTERFACE_DISABLED state and transition
- * to DriverStarting upon getting that
- * TODO: Fix this when the supplicant can be made to just transition out of
- * INTERFACE_DISABLED state when driver gets started
- */
- if (state == SupplicantState.INTERFACE_DISABLED) {
- transitionTo(mDriverStartingState);
- }
+ case CMD_START_DRIVER:
+ mWakeLock.acquire();
+ WifiNative.startDriverCommand();
+ mWakeLock.release();
+ transitionTo(mDriverStartingState);
break;
default:
return NOT_HANDLED;
diff --git a/wifi/java/android/net/wifi/WifiWatchdogStateMachine.java b/wifi/java/android/net/wifi/WifiWatchdogStateMachine.java
index 274edae..c52142d 100644
--- a/wifi/java/android/net/wifi/WifiWatchdogStateMachine.java
+++ b/wifi/java/android/net/wifi/WifiWatchdogStateMachine.java
@@ -36,6 +36,7 @@
import android.provider.Settings;
import android.provider.Settings.Secure;
import android.util.Slog;
+import android.util.Log;
import com.android.internal.util.Protocol;
import com.android.internal.util.State;
@@ -174,7 +175,7 @@
* It triggers a disableNetwork call if a DNS check fails.
*/
public boolean mDisableAPNextFailure = false;
- private ConnectivityManager mConnectivityManager;
+ private static boolean sWifiOnly = false;
private boolean mNotificationShown;
public boolean mHasConnectedWifiManager = false;
@@ -219,9 +220,14 @@
public static WifiWatchdogStateMachine makeWifiWatchdogStateMachine(Context context) {
ContentResolver contentResolver = context.getContentResolver();
+
+ ConnectivityManager cm = (ConnectivityManager) context.getSystemService(
+ Context.CONNECTIVITY_SERVICE);
+ sWifiOnly = (cm.isNetworkSupported(ConnectivityManager.TYPE_MOBILE) == false);
+
// Disable for wifi only devices.
if (Settings.Secure.getString(contentResolver, Settings.Secure.WIFI_WATCHDOG_ON) == null &&
- "wifi-only".equals(SystemProperties.get("ro.carrier"))) {
+ sWifiOnly) {
putSettingsBoolean(contentResolver, Settings.Secure.WIFI_WATCHDOG_ON, false);
}
WifiWatchdogStateMachine wwsm = new WifiWatchdogStateMachine(context);
@@ -508,22 +514,6 @@
}
}
- /**
- * @return true if there is definitely no mobile data (we'll be less aggressive)
- */
- private boolean hasNoMobileData() {
- if (mConnectivityManager == null) {
- mConnectivityManager = (ConnectivityManager) mContext.getSystemService(
- Context.CONNECTIVITY_SERVICE);
- }
- NetworkInfo mobileNetInfo = mConnectivityManager.getNetworkInfo(
- ConnectivityManager.TYPE_MOBILE);
- if (mobileNetInfo == null || !mobileNetInfo.isAvailable()) {
- return true;
- }
- return false;
- }
-
class DefaultState extends State {
@Override
public boolean processMessage(Message msg) {
@@ -941,7 +931,7 @@
if (mDisableAPNextFailure || mNumCheckFailures >= mBssids.size()
|| mNumCheckFailures >= mMaxSsidBlacklists) {
- if (hasNoMobileData()) {
+ if (sWifiOnly) {
Slog.w(WWSM_TAG, "Would disable bad network, but device has no mobile data!" +
" Going idle...");
// This state should be called idle -- will be changing flow.
diff --git a/wifi/java/android/net/wifi/p2p/WifiP2pService.java b/wifi/java/android/net/wifi/p2p/WifiP2pService.java
index adf13be..f67680d 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.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 @@
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 @@
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 @@
"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 @@
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 @@
mNetworkInfo.setIsAvailable(true);
//Start listening for new connections
WifiNative.p2pListen();
+ initializeP2pSettings();
}
@Override
@@ -637,6 +652,22 @@
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 @@
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 @@
//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 @@
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 @@
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) {