Merge "Removes some storage tests from the DumpRenderTree skipped lists, now that Android-specific results are provided"
diff --git a/api/current.xml b/api/current.xml
index 1f7be9e..212e661 100644
--- a/api/current.xml
+++ b/api/current.xml
@@ -24220,6 +24220,17 @@
visibility="public"
>
</field>
+<field name="CURSOR_EXTRA_KEY_IN_PROGRESS"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value=""in_progress""
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
<field name="EXTRA_DATA_KEY"
type="java.lang.String"
transient="false"
@@ -83832,6 +83843,19 @@
visibility="public"
>
</method>
+<method name="setAudioChannels"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="numChannels" type="int">
+</parameter>
+</method>
<method name="setAudioEncoder"
return="void"
abstract="false"
@@ -83847,6 +83871,32 @@
<exception name="IllegalStateException" type="java.lang.IllegalStateException">
</exception>
</method>
+<method name="setAudioEncodingBitRate"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="bitRate" type="int">
+</parameter>
+</method>
+<method name="setAudioSamplingRate"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="samplingRate" type="int">
+</parameter>
+</method>
<method name="setAudioSource"
return="void"
abstract="false"
@@ -84004,6 +84054,19 @@
<exception name="IllegalStateException" type="java.lang.IllegalStateException">
</exception>
</method>
+<method name="setVideoEncodingBitRate"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="bitRate" type="int">
+</parameter>
+</method>
<method name="setVideoFrameRate"
return="void"
abstract="false"
diff --git a/cmds/installd/commands.c b/cmds/installd/commands.c
index a447f53..c8d1397 100644
--- a/cmds/installd/commands.c
+++ b/cmds/installd/commands.c
@@ -674,14 +674,19 @@
return 0;
}
-void mkinnerdirs(char* path, int basepos, mode_t mode, int uid, int gid)
+void mkinnerdirs(char* path, int basepos, mode_t mode, int uid, int gid,
+ struct stat* statbuf)
{
while (path[basepos] != 0) {
if (path[basepos] == '/') {
path[basepos] = 0;
- LOGI("Making directory: %s\n", path);
- if (mkdir(path, mode) == 0) {
- chown(path, uid, gid);
+ if (lstat(path, statbuf) < 0) {
+ LOGI("Making directory: %s\n", path);
+ if (mkdir(path, mode) == 0) {
+ chown(path, uid, gid);
+ } else {
+ LOGW("Unable to make directory %s: %s\n", path, strerror(errno));
+ }
}
path[basepos] = '/';
basepos++;
@@ -690,8 +695,8 @@
}
}
-int movefileordir(char* srcpath, char* dstpath, int dstuid, int dstgid,
- struct stat* statbuf)
+int movefileordir(char* srcpath, char* dstpath, int dstbasepos,
+ int dstuid, int dstgid, struct stat* statbuf)
{
DIR *d;
struct dirent *de;
@@ -706,8 +711,9 @@
}
if ((statbuf->st_mode&S_IFDIR) == 0) {
+ mkinnerdirs(dstpath, dstbasepos, S_IRWXU|S_IRWXG|S_IXOTH,
+ dstuid, dstgid, statbuf);
LOGI("Renaming %s to %s (uid %d)\n", srcpath, dstpath, dstuid);
- mkinnerdirs(dstpath, dstend-1, S_IRWXU|S_IRWXG|S_IXOTH, dstuid, dstgid);
if (rename(srcpath, dstpath) >= 0) {
if (chown(dstpath, dstuid, dstgid) < 0) {
LOGE("cannot chown %s: %s\n", dstpath, strerror(errno));
@@ -752,7 +758,7 @@
strcpy(srcpath+srcend+1, name);
strcpy(dstpath+dstend+1, name);
- if (movefileordir(srcpath, dstpath, dstuid, dstgid, statbuf) != 0) {
+ if (movefileordir(srcpath, dstpath, dstbasepos, dstuid, dstgid, statbuf) != 0) {
res = 1;
}
@@ -834,7 +840,9 @@
LOGV("Move file: %s (from %s to %s)\n", buf+bufp, srcpkg, dstpkg);
if (!create_move_path(srcpath, PKG_DIR_PREFIX, srcpkg, buf+bufp) &&
!create_move_path(dstpath, PKG_DIR_PREFIX, dstpkg, buf+bufp)) {
- movefileordir(srcpath, dstpath, dstuid, dstgid, &s);
+ movefileordir(srcpath, dstpath,
+ strlen(dstpath)-strlen(buf+bufp),
+ dstuid, dstgid, &s);
}
}
} else {
diff --git a/core/java/android/app/SearchDialog.java b/core/java/android/app/SearchDialog.java
index af68689..c2afd07 100644
--- a/core/java/android/app/SearchDialog.java
+++ b/core/java/android/app/SearchDialog.java
@@ -464,15 +464,14 @@
}
}
- /**
- * Update the text in the search button. Note: This is deprecated functionality, for
- * 1.0 compatibility only.
- */
- private void updateSearchButton() {
+ private void updateSearchButton() {
String textLabel = null;
Drawable iconLabel = null;
int textId = mSearchable.getSearchButtonText();
- if (textId != 0) {
+ if (isBrowserSearch()){
+ iconLabel = getContext().getResources()
+ .getDrawable(com.android.internal.R.drawable.ic_btn_search_play);
+ } else if (textId != 0) {
textLabel = mActivityContext.getResources().getString(textId);
} else {
iconLabel = getContext().getResources().
@@ -483,10 +482,6 @@
}
private void updateSearchAppIcon() {
- // In Donut, we special-case the case of the browser to hide the app icon as if it were
- // global search, for extra space for url entry.
- //
- // TODO: Remove this special case once the issue has been reconciled in Eclair.
if (isBrowserSearch()) {
mAppIcon.setImageResource(0);
mAppIcon.setVisibility(View.GONE);
@@ -583,8 +578,7 @@
}
/**
- * Hack to determine whether this is the browser, so we can remove the browser icon
- * to the left of the search field.
+ * Hack to determine whether this is the browser, so we can adjust the UI.
*/
private boolean isBrowserSearch() {
return mLaunchComponent.flattenToShortString().startsWith("com.android.browser/");
diff --git a/core/java/android/app/SearchManager.java b/core/java/android/app/SearchManager.java
index 67f9629..0ed572a 100644
--- a/core/java/android/app/SearchManager.java
+++ b/core/java/android/app/SearchManager.java
@@ -1300,6 +1300,14 @@
public final static String EXTRA_SELECT_QUERY = "select_query";
/**
+ * Boolean extra data key for a suggestion provider to return in {@link Cursor#getExtras} to
+ * indicate that the search is not complete yet. This can be used by the search UI
+ * to indicate that a search is in progress. The suggestion provider can return partial results
+ * this way and send a change notification on the cursor when more results are available.
+ */
+ public final static String CURSOR_EXTRA_KEY_IN_PROGRESS = "in_progress";
+
+ /**
* Intent extra data key: Use this key with Intent.ACTION_SEARCH and
* {@link android.content.Intent#getStringExtra content.Intent.getStringExtra()}
* to obtain the action message that was defined for a particular search action key and/or
diff --git a/core/java/android/app/SuggestionsAdapter.java b/core/java/android/app/SuggestionsAdapter.java
index 07e9793..3e11a3f 100644
--- a/core/java/android/app/SuggestionsAdapter.java
+++ b/core/java/android/app/SuggestionsAdapter.java
@@ -159,19 +159,23 @@
* for in app search we show the progress spinner until the cursor is returned with
* the results.
*/
+ Cursor cursor = null;
mSearchDialog.getWindow().getDecorView().post(mStartSpinnerRunnable);
try {
- final Cursor cursor = mSearchManager.getSuggestions(mSearchable, query, QUERY_LIMIT);
+ cursor = mSearchManager.getSuggestions(mSearchable, query, QUERY_LIMIT);
// trigger fill window so the spinner stays up until the results are copied over and
// closer to being ready
- if (cursor != null) cursor.getCount();
- return cursor;
+ if (cursor != null) {
+ cursor.getCount();
+ return cursor;
+ }
} catch (RuntimeException e) {
Log.w(LOG_TAG, "Search suggestions query threw an exception.", e);
- return null;
- } finally {
- mSearchDialog.getWindow().getDecorView().post(mStopSpinnerRunnable);
}
+ // If cursor is null or an exception was thrown, stop the spinner and return null.
+ // changeCursor doesn't get called if cursor is null
+ mSearchDialog.getWindow().getDecorView().post(mStopSpinnerRunnable);
+ return null;
}
public void close() {
@@ -180,6 +184,39 @@
mClosed = true;
}
+ @Override
+ public void notifyDataSetChanged() {
+ if (DBG) Log.d(LOG_TAG, "notifyDataSetChanged");
+ super.notifyDataSetChanged();
+
+ updateSpinnerState(getCursor());
+ }
+
+ @Override
+ public void notifyDataSetInvalidated() {
+ if (DBG) Log.d(LOG_TAG, "notifyDataSetInvalidated");
+ super.notifyDataSetInvalidated();
+
+ updateSpinnerState(getCursor());
+ }
+
+ private void updateSpinnerState(Cursor cursor) {
+ if (DBG) {
+ Log.d(LOG_TAG, "updateSpinnerState - extra = "
+ + (cursor != null
+ ? cursor.getExtras().getBoolean(SearchManager.CURSOR_EXTRA_KEY_IN_PROGRESS)
+ : null));
+ }
+ // Check if the Cursor indicates that the query is not complete and show the spinner
+ if (cursor != null
+ && cursor.getExtras().getBoolean(SearchManager.CURSOR_EXTRA_KEY_IN_PROGRESS)) {
+ mSearchDialog.getWindow().getDecorView().post(mStartSpinnerRunnable);
+ return;
+ }
+ // If cursor is null or is done, stop the spinner
+ mSearchDialog.getWindow().getDecorView().post(mStopSpinnerRunnable);
+ }
+
/**
* Cache columns.
*/
@@ -202,7 +239,8 @@
mText2UrlCol = c.getColumnIndex(SearchManager.SUGGEST_COLUMN_TEXT_2_URL);
mIconName1Col = c.getColumnIndex(SearchManager.SUGGEST_COLUMN_ICON_1);
mIconName2Col = c.getColumnIndex(SearchManager.SUGGEST_COLUMN_ICON_2);
- mBackgroundColorCol = c.getColumnIndex(SearchManager.SUGGEST_COLUMN_BACKGROUND_COLOR);
+ mBackgroundColorCol =
+ c.getColumnIndex(SearchManager.SUGGEST_COLUMN_BACKGROUND_COLOR);
}
} catch (Exception e) {
Log.e(LOG_TAG, "error changing cursor and caching columns", e);
diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java
index 90e8c14..179b807 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -1632,12 +1632,20 @@
/**
* Broadcast Action: External media is unmounted because it is being shared via USB mass storage.
- * The path to the mount point for the removed media is contained in the Intent.mData field.
+ * The path to the mount point for the shared media is contained in the Intent.mData field.
*/
@SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
public static final String ACTION_MEDIA_SHARED = "android.intent.action.MEDIA_SHARED";
/**
+ * Broadcast Action: External media is no longer being shared via USB mass storage.
+ * The path to the mount point for the previously shared media is contained in the Intent.mData field.
+ *
+ * @hide
+ */
+ public static final String ACTION_MEDIA_UNSHARED = "android.intent.action.MEDIA_UNSHARED";
+
+ /**
* Broadcast Action: External media was removed from SD card slot, but mount point was not unmounted.
* The path to the mount point for the removed media is contained in the Intent.mData field.
*/
diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java
index b07bafcf..7a0337cd 100644
--- a/core/java/android/content/pm/PackageParser.java
+++ b/core/java/android/content/pm/PackageParser.java
@@ -967,8 +967,11 @@
String orig =sa.getNonResourceString(
com.android.internal.R.styleable.AndroidManifestOriginalPackage_name);
if (!pkg.packageName.equals(orig)) {
- pkg.mOriginalPackage = orig;
- pkg.mRealPackage = pkg.packageName;
+ if (pkg.mOriginalPackages == null) {
+ pkg.mOriginalPackages = new ArrayList<String>();
+ pkg.mRealPackage = pkg.packageName;
+ }
+ pkg.mOriginalPackages.add(orig);
}
sa.recycle();
@@ -2579,7 +2582,7 @@
public ArrayList<String> usesOptionalLibraries = null;
public String[] usesLibraryFiles = null;
- public String mOriginalPackage = null;
+ public ArrayList<String> mOriginalPackages = null;
public String mRealPackage = null;
public ArrayList<String> mAdoptPermissions = null;
diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java
index c76aca1..a6668e7 100644
--- a/core/java/android/net/ConnectivityManager.java
+++ b/core/java/android/net/ConnectivityManager.java
@@ -364,7 +364,7 @@
/**
* Sets the persisted value for enabling/disabling Mobile data.
*
- * @param allowMobileData Whether the mobile data connection should be
+ * @param enabled Whether the mobile data connection should be
* used or not.
* @hide
*/
@@ -418,22 +418,35 @@
/**
* {@hide}
*/
- public boolean tether(String iface) {
+ public String[] getTetheringErroredIfaces() {
try {
- return mService.tether(iface);
+ return mService.getTetheringErroredIfaces();
} catch (RemoteException e) {
- return false;
+ return new String[0];
}
}
/**
+ * @return error A TETHER_ERROR value indicating success or failure type
* {@hide}
*/
- public boolean untether(String iface) {
+ public int tether(String iface) {
+ try {
+ return mService.tether(iface);
+ } catch (RemoteException e) {
+ return TETHER_ERROR_SERVICE_UNAVAIL;
+ }
+ }
+
+ /**
+ * @return error A TETHER_ERROR value indicating success or failure type
+ * {@hide}
+ */
+ public int untether(String iface) {
try {
return mService.untether(iface);
} catch (RemoteException e) {
- return false;
+ return TETHER_ERROR_SERVICE_UNAVAIL;
}
}
@@ -469,4 +482,41 @@
return new String[0];
}
}
+
+ /** {@hide} */
+ public static final int TETHER_ERROR_NO_ERROR = 0;
+ /** {@hide} */
+ public static final int TETHER_ERROR_UNKNOWN_IFACE = 1;
+ /** {@hide} */
+ public static final int TETHER_ERROR_SERVICE_UNAVAIL = 2;
+ /** {@hide} */
+ public static final int TETHER_ERROR_UNSUPPORTED = 3;
+ /** {@hide} */
+ public static final int TETHER_ERROR_UNAVAIL_IFACE = 4;
+ /** {@hide} */
+ public static final int TETHER_ERROR_MASTER_ERROR = 5;
+ /** {@hide} */
+ public static final int TETHER_ERROR_TETHER_IFACE_ERROR = 6;
+ /** {@hide} */
+ public static final int TETHER_ERROR_UNTETHER_IFACE_ERROR = 7;
+ /** {@hide} */
+ public static final int TETHER_ERROR_ENABLE_NAT_ERROR = 8;
+ /** {@hide} */
+ public static final int TETHER_ERROR_DISABLE_NAT_ERROR = 9;
+ /** {@hide} */
+ public static final int TETHER_ERROR_IFACE_CFG_ERROR = 10;
+
+ /**
+ * @param iface The name of the interface we're interested in
+ * @return error The error code of the last error tethering or untethering the named
+ * interface
+ * {@hide}
+ */
+ public int getLastTetherError(String iface) {
+ try {
+ return mService.getLastTetherError(iface);
+ } catch (RemoteException e) {
+ return TETHER_ERROR_SERVICE_UNAVAIL;
+ }
+ }
}
diff --git a/core/java/android/net/IConnectivityManager.aidl b/core/java/android/net/IConnectivityManager.aidl
index 2514693..b05c2ed 100644
--- a/core/java/android/net/IConnectivityManager.aidl
+++ b/core/java/android/net/IConnectivityManager.aidl
@@ -55,9 +55,11 @@
void setMobileDataEnabled(boolean enabled);
- boolean tether(String iface);
+ int tether(String iface);
- boolean untether(String iface);
+ int untether(String iface);
+
+ int getLastTetherError(String iface);
boolean isTetheringSupported();
@@ -65,6 +67,8 @@
String[] getTetheredIfaces();
+ String[] getTetheringErroredIfaces();
+
String[] getTetherableUsbRegexs();
String[] getTetherableWifiRegexs();
diff --git a/core/java/android/pim/vcard/VCardConfig.java b/core/java/android/pim/vcard/VCardConfig.java
index ecd089a..3442ae7 100644
--- a/core/java/android/pim/vcard/VCardConfig.java
+++ b/core/java/android/pim/vcard/VCardConfig.java
@@ -330,7 +330,7 @@
(VCARD_TYPE_V21_JAPANESE_MOBILE | FLAG_DOCOMO);
/* package */ static final String VCARD_TYPE_DOCOMO_STR = "docomo";
-
+
public static int VCARD_TYPE_DEFAULT = VCARD_TYPE_V21_GENERIC_UTF8;
private static final Map<String, Integer> sVCardTypeMap;
@@ -363,6 +363,8 @@
final String loweredKey = vcardTypeString.toLowerCase();
if (sVCardTypeMap.containsKey(loweredKey)) {
return sVCardTypeMap.get(loweredKey);
+ } else if ("default".equalsIgnoreCase(vcardTypeString)) {
+ return VCARD_TYPE_DEFAULT;
} else {
Log.e(LOG_TAG, "Unknown vCard type String: \"" + vcardTypeString + "\"");
return VCARD_TYPE_DEFAULT;
diff --git a/core/java/android/pim/vcard/VCardEntry.java b/core/java/android/pim/vcard/VCardEntry.java
index 1cf3144..f6135fc 100644
--- a/core/java/android/pim/vcard/VCardEntry.java
+++ b/core/java/android/pim/vcard/VCardEntry.java
@@ -61,7 +61,7 @@
private final static int DEFAULT_ORGANIZATION_TYPE = Organization.TYPE_WORK;
private static final String ACCOUNT_TYPE_GOOGLE = "com.google";
- private static final String GOOGLE_MY_CONTACTS_GROUP = "System Group: My Contacts";
+ private static final String GOOGLE_MY_CONTACTS_GROUP = "My Contacts";
private static final Map<String, Integer> sImMap = new HashMap<String, Integer>();
diff --git a/core/java/android/view/ScaleGestureDetector.java b/core/java/android/view/ScaleGestureDetector.java
index 8140d61..d8b6d1f 100644
--- a/core/java/android/view/ScaleGestureDetector.java
+++ b/core/java/android/view/ScaleGestureDetector.java
@@ -154,9 +154,8 @@
boolean handled = true;
if (!mGestureInProgress) {
- if ((action == MotionEvent.ACTION_POINTER_1_DOWN ||
- action == MotionEvent.ACTION_POINTER_2_DOWN) &&
- event.getPointerCount() >= 2) {
+ switch (action & MotionEvent.ACTION_MASK) {
+ case MotionEvent.ACTION_POINTER_DOWN: {
// We have a new multi-finger gesture
// as orientation can change, query the metrics in touch down
@@ -189,7 +188,7 @@
boolean p1sloppy = x1 < edgeSlop || y1 < edgeSlop
|| x1 > rightSlop || y1 > bottomSlop;
- if(p0sloppy && p1sloppy) {
+ if (p0sloppy && p1sloppy) {
mFocusX = -1;
mFocusY = -1;
mSloppyGesture = true;
@@ -204,54 +203,61 @@
} else {
mGestureInProgress = mListener.onScaleBegin(this);
}
- } else if (action == MotionEvent.ACTION_MOVE && mSloppyGesture) {
- // Initiate sloppy gestures if we've moved outside of the slop area.
- final float edgeSlop = mEdgeSlop;
- final float rightSlop = mRightSlopEdge;
- final float bottomSlop = mBottomSlopEdge;
- final float x0 = event.getRawX();
- final float y0 = event.getRawY();
- final float x1 = getRawX(event, 1);
- final float y1 = getRawY(event, 1);
+ }
+ break;
+
+ case MotionEvent.ACTION_MOVE:
+ if (mSloppyGesture) {
+ // Initiate sloppy gestures if we've moved outside of the slop area.
+ final float edgeSlop = mEdgeSlop;
+ final float rightSlop = mRightSlopEdge;
+ final float bottomSlop = mBottomSlopEdge;
+ final float x0 = event.getRawX();
+ final float y0 = event.getRawY();
+ final float x1 = getRawX(event, 1);
+ final float y1 = getRawY(event, 1);
- boolean p0sloppy = x0 < edgeSlop || y0 < edgeSlop
- || x0 > rightSlop || y0 > bottomSlop;
- boolean p1sloppy = x1 < edgeSlop || y1 < edgeSlop
- || x1 > rightSlop || y1 > bottomSlop;
+ boolean p0sloppy = x0 < edgeSlop || y0 < edgeSlop
+ || x0 > rightSlop || y0 > bottomSlop;
+ boolean p1sloppy = x1 < edgeSlop || y1 < edgeSlop
+ || x1 > rightSlop || y1 > bottomSlop;
- if(p0sloppy && p1sloppy) {
- mFocusX = -1;
- mFocusY = -1;
- } else if (p0sloppy) {
- mFocusX = event.getX(1);
- mFocusY = event.getY(1);
- } else if (p1sloppy) {
- mFocusX = event.getX(0);
- mFocusY = event.getY(0);
- } else {
- mSloppyGesture = false;
- mGestureInProgress = mListener.onScaleBegin(this);
+ if(p0sloppy && p1sloppy) {
+ mFocusX = -1;
+ mFocusY = -1;
+ } else if (p0sloppy) {
+ mFocusX = event.getX(1);
+ mFocusY = event.getY(1);
+ } else if (p1sloppy) {
+ mFocusX = event.getX(0);
+ mFocusY = event.getY(0);
+ } else {
+ mSloppyGesture = false;
+ mGestureInProgress = mListener.onScaleBegin(this);
+ }
}
- } else if ((action == MotionEvent.ACTION_POINTER_1_UP
- || action == MotionEvent.ACTION_POINTER_2_UP)
- && mSloppyGesture) {
- // Set focus point to the remaining finger
- int id = (((action & MotionEvent.ACTION_POINTER_ID_MASK)
- >> MotionEvent.ACTION_POINTER_ID_SHIFT) == 0) ? 1 : 0;
- mFocusX = event.getX(id);
- mFocusY = event.getY(id);
+ break;
+
+ case MotionEvent.ACTION_POINTER_UP:
+ if (mSloppyGesture) {
+ // Set focus point to the remaining finger
+ int id = (((action & MotionEvent.ACTION_POINTER_INDEX_MASK)
+ >> MotionEvent.ACTION_POINTER_INDEX_SHIFT) == 0) ? 1 : 0;
+ mFocusX = event.getX(id);
+ mFocusY = event.getY(id);
+ }
+ break;
}
} else {
// Transform gesture in progress - attempt to handle it
- switch (action) {
- case MotionEvent.ACTION_POINTER_1_UP:
- case MotionEvent.ACTION_POINTER_2_UP:
+ switch (action & MotionEvent.ACTION_MASK) {
+ case MotionEvent.ACTION_POINTER_UP:
// Gesture ended
setContext(event);
// Set focus point to the remaining finger
- int id = (((action & MotionEvent.ACTION_POINTER_ID_MASK)
- >> MotionEvent.ACTION_POINTER_ID_SHIFT) == 0) ? 1 : 0;
+ int id = (((action & MotionEvent.ACTION_POINTER_INDEX_MASK)
+ >> MotionEvent.ACTION_POINTER_INDEX_SHIFT) == 0) ? 1 : 0;
mFocusX = event.getX(id);
mFocusY = event.getY(id);
diff --git a/core/java/android/widget/ExpandableListConnector.java b/core/java/android/widget/ExpandableListConnector.java
index 9c43e9b..01d3a4a 100644
--- a/core/java/android/widget/ExpandableListConnector.java
+++ b/core/java/android/widget/ExpandableListConnector.java
@@ -67,7 +67,7 @@
private int mMaxExpGroupCount = Integer.MAX_VALUE;
/** Change observer used to have ExpandableListAdapter changes pushed to us */
- private DataSetObserver mDataSetObserver = new MyDataSetObserver();
+ private final DataSetObserver mDataSetObserver = new MyDataSetObserver();
/**
* Constructs the connector
@@ -849,7 +849,7 @@
* position to either a) group position for groups, or b) child position for
* children
*/
- static class GroupMetadata implements Parcelable, Comparable {
+ static class GroupMetadata implements Parcelable, Comparable<GroupMetadata> {
final static int REFRESH = -1;
/** This group's flat list position */
@@ -885,12 +885,12 @@
return gm;
}
- public int compareTo(Object another) {
- if (another == null || !(another instanceof GroupMetadata)) {
- throw new ClassCastException();
+ public int compareTo(GroupMetadata another) {
+ if (another == null) {
+ throw new IllegalArgumentException();
}
- return gPos - ((GroupMetadata) another).gPos;
+ return gPos - another.gPos;
}
public int describeContents() {
diff --git a/core/java/android/widget/ExpandableListView.java b/core/java/android/widget/ExpandableListView.java
index 9cc8bd5..8bd797b 100644
--- a/core/java/android/widget/ExpandableListView.java
+++ b/core/java/android/widget/ExpandableListView.java
@@ -389,7 +389,8 @@
// Only proceed as possible child if the divider isn't above all items (if it is above
// all items, then the item below it has to be a group)
if (flatListPosition >= 0) {
- PositionMetadata pos = mConnector.getUnflattenedPos(flatListPosition);
+ final int adjustedPosition = getFlatPositionForConnector(flatListPosition);
+ PositionMetadata pos = mConnector.getUnflattenedPos(adjustedPosition);
// If this item is a child, or it is a non-empty group that is expanded
if ((pos.position.type == ExpandableListPosition.CHILD) || (pos.isExpanded() &&
pos.groupMetadata.lastChildFlPos != pos.groupMetadata.flPos)) {
@@ -482,11 +483,37 @@
return mAdapter;
}
+ /**
+ * @param position An absolute (including header and footer) flat list position.
+ * @return true if the position corresponds to a header or a footer item.
+ */
private boolean isHeaderOrFooterPosition(int position) {
final int footerViewsStart = mItemCount - getFooterViewsCount();
return (position < getHeaderViewsCount() || position >= footerViewsStart);
}
+ /**
+ * Converts an absolute item flat position into a group/child flat position, shifting according
+ * to the number of header items.
+ *
+ * @param flatListPosition The absolute flat position
+ * @return A group/child flat position as expected by the connector.
+ */
+ private int getFlatPositionForConnector(int flatListPosition) {
+ return flatListPosition - getHeaderViewsCount();
+ }
+
+ /**
+ * Converts a group/child flat position into an absolute flat position, that takes into account
+ * the possible headers.
+ *
+ * @param flatListPosition The child/group flat position
+ * @return An absolute flat position.
+ */
+ private int getAbsoluteFlatPosition(int flatListPosition) {
+ return flatListPosition + getHeaderViewsCount();
+ }
+
@Override
public boolean performItemClick(View v, int position, long id) {
// Ignore clicks in header/footers
@@ -496,8 +523,8 @@
}
// Internally handle the item click
- final int headerViewsCount = getHeaderViewsCount();
- return handleItemClick(v, position - headerViewsCount, id);
+ final int adjustedPosition = getFlatPositionForConnector(position);
+ return handleItemClick(v, adjustedPosition, id);
}
/**
@@ -711,8 +738,8 @@
return PACKED_POSITION_VALUE_NULL;
}
- final int shiftedPosition = flatListPosition - getHeaderViewsCount();
- PositionMetadata pm = mConnector.getUnflattenedPos(shiftedPosition);
+ final int adjustedPosition = getFlatPositionForConnector(flatListPosition);
+ PositionMetadata pm = mConnector.getUnflattenedPos(adjustedPosition);
long packedPos = pm.position.getPackedPosition();
pm.recycle();
return packedPos;
@@ -732,9 +759,9 @@
public int getFlatListPosition(long packedPosition) {
PositionMetadata pm = mConnector.getFlattenedPos(ExpandableListPosition
.obtainPosition(packedPosition));
- int retValue = pm.position.flatListPos;
+ final int flatListPosition = pm.position.flatListPos;
pm.recycle();
- return retValue + getHeaderViewsCount();
+ return getAbsoluteFlatPosition(flatListPosition);
}
/**
@@ -783,7 +810,8 @@
.obtainGroupPosition(groupPosition);
PositionMetadata pm = mConnector.getFlattenedPos(elGroupPos);
elGroupPos.recycle();
- super.setSelection(pm.position.flatListPos);
+ final int absoluteFlatPosition = getAbsoluteFlatPosition(pm.position.flatListPos);
+ super.setSelection(absoluteFlatPosition);
pm.recycle();
}
@@ -819,7 +847,8 @@
}
}
- super.setSelection(flatChildPos.position.flatListPos);
+ int absoluteFlatPosition = getAbsoluteFlatPosition(flatChildPos.position.flatListPos);
+ super.setSelection(absoluteFlatPosition);
elChildPos.recycle();
flatChildPos.recycle();
@@ -937,7 +966,7 @@
return new AdapterContextMenuInfo(view, flatListPosition, id);
}
- final int adjustedPosition = flatListPosition - getHeaderViewsCount();
+ final int adjustedPosition = getFlatPositionForConnector(flatListPosition);
PositionMetadata pm = mConnector.getUnflattenedPos(adjustedPosition);
ExpandableListPosition pos = pm.position;
pm.recycle();
diff --git a/core/java/com/android/internal/app/TetherActivity.java b/core/java/com/android/internal/app/TetherActivity.java
index 5d71231..7f83b2b 100644
--- a/core/java/com/android/internal/app/TetherActivity.java
+++ b/core/java/com/android/internal/app/TetherActivity.java
@@ -62,6 +62,7 @@
// determine if we advertise tethering or untethering
ConnectivityManager cm =
(ConnectivityManager)getSystemService(Context.CONNECTIVITY_SERVICE);
+
mTethered = cm.getTetheredIfaces().length;
int tetherable = cm.getTetherableIfaces().length;
if ((mTethered == 0) && (tetherable == 0)) {
@@ -116,7 +117,7 @@
* {@inheritDoc}
*/
public void onClick(DialogInterface dialog, int which) {
- boolean error = false;
+ int error = ConnectivityManager.TETHER_ERROR_NO_ERROR;
if (which == POSITIVE_BUTTON) {
ConnectivityManager cm =
@@ -130,24 +131,17 @@
for (String t : tetherable) {
for (String r : usbRegexs) {
if (t.matches(r)) {
- if (!cm.tether(t))
- error = true;
+ error = cm.tether(t);
break;
}
}
}
- if (error) {
- showTetheringError();
- }
+ showTetheringError(error);
} else {
for (String t : tethered) {
- if (!cm.untether(t)) {
- error = true;
- }
+ error = cm.untether(t);
}
- if (error) {
- showUnTetheringError();
- }
+ showUnTetheringError(error);
}
}
// No matter what, finish the activity
@@ -163,14 +157,23 @@
}
}
- private void showTetheringError() {
- Toast.makeText(this, com.android.internal.R.string.tether_error_message,
- Toast.LENGTH_LONG).show();
+ private void showTetheringError(int error) {
+ switch(error) {
+ case ConnectivityManager.TETHER_ERROR_NO_ERROR:
+ return;
+ default:
+ Toast.makeText(this, com.android.internal.R.string.tether_error_message,
+ Toast.LENGTH_LONG).show();
+ }
}
- private void showUnTetheringError() {
- Toast.makeText(this, com.android.internal.R.string.tether_stop_error_message,
- Toast.LENGTH_LONG).show();
+ private void showUnTetheringError(int error) {
+ switch(error) {
+ case ConnectivityManager.TETHER_ERROR_NO_ERROR:
+ return;
+ default:
+ Toast.makeText(this, com.android.internal.R.string.tether_stop_error_message,
+ Toast.LENGTH_LONG).show();
+ }
}
-
}
diff --git a/core/java/com/android/internal/content/PackageHelper.java b/core/java/com/android/internal/content/PackageHelper.java
index c5db83f..04a10b9 100644
--- a/core/java/com/android/internal/content/PackageHelper.java
+++ b/core/java/com/android/internal/content/PackageHelper.java
@@ -54,11 +54,13 @@
// Create mount point via MountService
IMountService mountService = getMountService();
long len = tmpPackageFile.length();
- int mbLen = (int) (len/(1024*1024));
+ int mbLen = (int) (len >> 20);
if ((len - (mbLen * 1024 * 1024)) > 0) {
mbLen++;
}
- if (localLOGV) Log.i(TAG, "Size of resource " + mbLen);
+ // Add buffer size
+ mbLen++;
+ if (localLOGV) Log.i(TAG, "Size of container " + mbLen + " MB " + len + " bytes");
try {
int rc = mountService.createSecureContainer(
diff --git a/core/res/res/drawable-hdpi/ic_btn_search_play.png b/core/res/res/drawable-hdpi/ic_btn_search_play.png
new file mode 100644
index 0000000..fb1b974
--- /dev/null
+++ b/core/res/res/drawable-hdpi/ic_btn_search_play.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_btn_search_play.png b/core/res/res/drawable-mdpi/ic_btn_search_play.png
new file mode 100644
index 0000000..dc25dae
--- /dev/null
+++ b/core/res/res/drawable-mdpi/ic_btn_search_play.png
Binary files differ
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 02961f0..84cd4c3 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -267,6 +267,11 @@
it will be removed when the lower-level touch driver generates better
data. -->
<bool name="config_filterTouchEvents">false</bool>
+
+ <!-- Enables special filtering code in the framework for raw touch events
+ from the touch driver. This code exists for one particular device,
+ and should not be enabled for any others. -->
+ <bool name="config_filterJumpyTouchEvents">false</bool>
<!-- Component name of the default wallpaper. This will be ImageWallpaper if not
specified -->
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index 35ea0cc..d34599f 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -2249,8 +2249,10 @@
<string name="tether_button">Tether</string>
<!-- See TETHER. This is the button text to ignore the plugging in of the phone.. -->
<string name="tether_button_cancel">Cancel</string>
- <!-- See TETHER. If there was an error mounting, this is the text. -->
- <string name="tether_error_message">There is a problem tethering.</string>
+
+ <!-- See TETHER. If there was a recoverable error, this is the text. -->
+ <string name="tether_error_message">We\'ve encountered a problem turning on Tethering. Please try again.</string>
+
<!-- TETHER: When the user connects the phone to a computer, we show a notification asking if he wants to share his cellular network connection. This is the title -->
<string name="tether_available_notification_title">USB tethering available</string>
<!-- See USB_STORAGE. This is the message. -->
@@ -2270,7 +2272,8 @@
<string name="tether_stop_button">Disconnect</string>
<!-- See TETHER_STOP. This is the button text to cancel disconnecting the tether. -->
<string name="tether_stop_button_cancel">Cancel</string>
- <!-- See TETHER_STOP_DIALOG. If there was an error disconnect, this is the text. -->
+
+ <!-- See TETHER_STOP. If there was an error disconnect, this is the text. -->
<string name="tether_stop_error_message">We\'ve encountered a problem turning off Tethering. Please try again.</string>
<!-- Strings for car mode notification -->
diff --git a/libs/rs/RenderScript.h b/libs/rs/RenderScript.h
index cd8361c..d280f50 100644
--- a/libs/rs/RenderScript.h
+++ b/libs/rs/RenderScript.h
@@ -202,6 +202,12 @@
RS_PRIMITIVE_TRIANGLE_FAN
};
+enum RsError {
+ RS_ERROR_NONE,
+ RS_ERROR_BAD_SHADER,
+ RS_ERROR_BAD_SCRIPT
+};
+
#ifndef NO_RS_FUNCS
#include "rsgApiFuncDecl.h"
#endif
diff --git a/libs/rs/rs.spec b/libs/rs/rs.spec
index 4d97c0f..cb9937c 100644
--- a/libs/rs/rs.spec
+++ b/libs/rs/rs.spec
@@ -36,6 +36,11 @@
param int32_t bits
}
+ContextGetError {
+ param RsError *err
+ ret const char *
+ }
+
ContextSetPriority {
param int32_t priority
}
diff --git a/libs/rs/rsContext.cpp b/libs/rs/rsContext.cpp
index cc3a74fb..d8a9a99 100644
--- a/libs/rs/rsContext.cpp
+++ b/libs/rs/rsContext.cpp
@@ -178,6 +178,11 @@
uint32_t ret = runScript(mRootScript.get(), 0);
checkError("runRootScript");
+ if (mError != RS_ERROR_NONE) {
+ // If we have an error condition we stop rendering until
+ // somthing changes that might fix it.
+ ret = 0;
+ }
return ret;
}
@@ -240,10 +245,13 @@
}
}
-void Context::setupCheck()
+bool Context::setupCheck()
{
if (checkVersion2_0()) {
- mShaderCache.lookup(this, mVertex.get(), mFragment.get());
+ if (!mShaderCache.lookup(this, mVertex.get(), mFragment.get())) {
+ LOGE("Context::setupCheck() 1 fail");
+ return false;
+ }
mFragmentStore->setupGL2(this, &mStateFragmentStore);
mFragment->setupGL2(this, &mStateFragment, &mShaderCache);
@@ -256,6 +264,7 @@
mRaster->setupGL(this, &mStateRaster);
mVertex->setupGL(this, &mStateVertex);
}
+ return true;
}
static bool getProp(const char *str)
@@ -389,6 +398,9 @@
mUseDepth = useDepth;
mPaused = false;
mObjHead = NULL;
+ mError = RS_ERROR_NONE;
+ mErrorMsg = NULL;
+
memset(&mEGL, 0, sizeof(mEGL));
memset(&mGL, 0, sizeof(mGL));
mIsGraphicsContext = isGraphics;
@@ -764,6 +776,23 @@
mIO.mToClient.shutdown();
}
+const char * Context::getError(RsError *err)
+{
+ *err = mError;
+ mError = RS_ERROR_NONE;
+ if (*err != RS_ERROR_NONE) {
+ return mErrorMsg;
+ }
+ return NULL;
+}
+
+void Context::setError(RsError e, const char *msg)
+{
+ mError = e;
+ mErrorMsg = msg;
+}
+
+
void Context::dumpDebug() const
{
LOGE("RS Context debug %p", this);
@@ -874,6 +903,15 @@
ObjectBase::dumpAll(rsc);
}
+const char * rsi_ContextGetError(Context *rsc, RsError *e)
+{
+ const char *msg = rsc->getError(e);
+ if (*e != RS_ERROR_NONE) {
+ LOGE("RS Error %i %s", *e, msg);
+ }
+ return msg;
+}
+
}
}
diff --git a/libs/rs/rsContext.h b/libs/rs/rsContext.h
index 04bd748..82c3687 100644
--- a/libs/rs/rsContext.h
+++ b/libs/rs/rsContext.h
@@ -93,7 +93,7 @@
const ProgramRaster * getRaster() {return mRaster.get();}
const ProgramVertex * getVertex() {return mVertex.get();}
- void setupCheck();
+ bool setupCheck();
bool checkDriver() const {return mEGL.mSurface != 0;}
void pause();
@@ -160,6 +160,8 @@
void dumpDebug() const;
void checkError(const char *) const;
+ const char * getError(RsError *);
+ void setError(RsError e, const char *msg);
mutable const ObjectBase * mObjHead;
@@ -211,6 +213,8 @@
bool mExit;
bool mUseDepth;
bool mPaused;
+ RsError mError;
+ const char *mErrorMsg;
pthread_t mThreadId;
pid_t mNativeThreadId;
diff --git a/libs/rs/rsProgram.cpp b/libs/rs/rsProgram.cpp
index 656a3c3..478a6dc 100644
--- a/libs/rs/rsProgram.cpp
+++ b/libs/rs/rsProgram.cpp
@@ -39,6 +39,7 @@
mInputCount = 0;
mOutputCount = 0;
mConstantCount = 0;
+ mIsValid = false;
}
Program::Program(Context *rsc, const char * shaderText, uint32_t shaderLength,
@@ -216,6 +217,7 @@
}
glDeleteShader(mShaderID);
mShaderID = 0;
+ rsc->setError(RS_ERROR_BAD_SHADER, "Error returned from GL driver loading shader text,");
return false;
}
}
@@ -224,6 +226,7 @@
if (rsc->props.mLogShaders) {
LOGV("--Shader load result %x ", glGetError());
}
+ mIsValid = true;
return true;
}
diff --git a/libs/rs/rsProgram.h b/libs/rs/rsProgram.h
index a34e89f..86f85fb 100644
--- a/libs/rs/rsProgram.h
+++ b/libs/rs/rsProgram.h
@@ -59,6 +59,8 @@
String8 getGLSLOutputString() const;
String8 getGLSLConstantString() const;
+ bool isValid() const {return mIsValid;}
+
protected:
// Components not listed in "in" will be passed though
// unless overwritten by components in out.
@@ -68,6 +70,7 @@
uint32_t mInputCount;
uint32_t mOutputCount;
uint32_t mConstantCount;
+ bool mIsValid;
ObjectBaseRef<Allocation> mConstants[MAX_UNIFORMS];
diff --git a/libs/rs/rsScript.cpp b/libs/rs/rsScript.cpp
index cb1436b..a33933b 100644
--- a/libs/rs/rsScript.cpp
+++ b/libs/rs/rsScript.cpp
@@ -96,6 +96,10 @@
void rsi_ScriptInvoke(Context *rsc, RsScript vs, uint32_t slot)
{
Script *s = static_cast<Script *>(vs);
+ if (s->mEnviroment.mInvokables[slot] == NULL) {
+ rsc->setError(RS_ERROR_BAD_SCRIPT, "Calling invoke on bad script");
+ return;
+ }
s->setupScript();
s->mEnviroment.mInvokables[slot]();
}
diff --git a/libs/rs/rsScriptC.cpp b/libs/rs/rsScriptC.cpp
index b7e0b86..1f23773 100644
--- a/libs/rs/rsScriptC.cpp
+++ b/libs/rs/rsScriptC.cpp
@@ -62,6 +62,11 @@
uint32_t ScriptC::run(Context *rsc, uint32_t launchIndex)
{
+ if (mProgram.mScript == NULL) {
+ rsc->setError(RS_ERROR_BAD_SCRIPT, "Attempted to run bad script");
+ return 0;
+ }
+
Context::ScriptTLSStruct * tls =
(Context::ScriptTLSStruct *)pthread_getspecific(Context::gThreadTLSKey);
rsAssert(tls);
@@ -154,7 +159,9 @@
ACCchar buf[4096];
ACCsizei len;
accGetScriptInfoLog(s->mAccScript, sizeof(buf), &len, buf);
- LOGV(buf);
+ LOGE(buf);
+ rsc->setError(RS_ERROR_BAD_SCRIPT, "Error compiling user script.");
+ return;
}
if (s->mProgram.mInit) {
diff --git a/libs/rs/rsScriptC_Lib.cpp b/libs/rs/rsScriptC_Lib.cpp
index 235c153..202ca3d 100644
--- a/libs/rs/rsScriptC_Lib.cpp
+++ b/libs/rs/rsScriptC_Lib.cpp
@@ -683,7 +683,9 @@
float x2, float y2, float z2)
{
GET_TLS();
- rsc->setupCheck();
+ if (!rsc->setupCheck()) {
+ return;
+ }
float vtx[] = { x1, y1, z1, x2, y2, z2 };
VertexArray va;
@@ -700,7 +702,9 @@
static void SC_drawPoint(float x, float y, float z)
{
GET_TLS();
- rsc->setupCheck();
+ if (!rsc->setupCheck()) {
+ return;
+ }
float vtx[] = { x, y, z };
@@ -725,7 +729,9 @@
float u4, float v4)
{
GET_TLS();
- rsc->setupCheck();
+ if (!rsc->setupCheck()) {
+ return;
+ }
//LOGE("Quad");
//LOGE("%4.2f, %4.2f, %4.2f", x1, y1, z1);
@@ -782,7 +788,9 @@
float cx0, float cy0, float cx1, float cy1)
{
GET_TLS();
- rsc->setupCheck();
+ if (!rsc->setupCheck()) {
+ return;
+ }
GLint crop[4] = {cx0, cy0, cx1, cy1};
glTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_CROP_RECT_OES, crop);
@@ -831,7 +839,9 @@
{
GET_TLS();
SimpleMesh *sm = static_cast<SimpleMesh *>(vsm);
- rsc->setupCheck();
+ if (!rsc->setupCheck()) {
+ return;
+ }
sm->render(rsc);
}
@@ -839,7 +849,9 @@
{
GET_TLS();
SimpleMesh *sm = static_cast<SimpleMesh *>(vsm);
- rsc->setupCheck();
+ if (!rsc->setupCheck()) {
+ return;
+ }
sm->renderRange(rsc, start, len);
}
diff --git a/libs/rs/rsShaderCache.cpp b/libs/rs/rsShaderCache.cpp
index 3a1f370..4711d1b 100644
--- a/libs/rs/rsShaderCache.cpp
+++ b/libs/rs/rsShaderCache.cpp
@@ -123,6 +123,8 @@
}
}
glDeleteProgram(pgm);
+ rsc->setError(RS_ERROR_BAD_SHADER, "Error linking GL Programs");
+ return false;
}
if (vtx->isUserProgram()) {
for (uint32_t ct=0; ct < vtx->getAttribCount(); ct++) {
@@ -146,6 +148,7 @@
}
}
+ e->mIsValid = true;
//LOGV("SC made program %i", e->program);
glUseProgram(e->program);
mEntryCount++;
diff --git a/libs/rs/rsShaderCache.h b/libs/rs/rsShaderCache.h
index 7aa8183..df99ccc 100644
--- a/libs/rs/rsShaderCache.h
+++ b/libs/rs/rsShaderCache.h
@@ -56,6 +56,7 @@
int32_t mFragAttribSlots[Program::MAX_ATTRIBS];
int32_t mFragUniformSlots[Program::MAX_UNIFORMS];
bool mUserVertexProgram;
+ bool mIsValid;
} entry_t;
entry_t *mEntries;
entry_t *mCurrent;
diff --git a/libs/rs/spec.l b/libs/rs/spec.l
index d81d47e..6a9010fe 100644
--- a/libs/rs/spec.l
+++ b/libs/rs/spec.l
@@ -148,6 +148,9 @@
BEGIN(api_entry2);
}
+<api_entry2>"*" {
+ currType->ptrLevel ++;
+ }
<api_entry2>"}" {
apiCount++;
diff --git a/location/java/android/location/LocationManager.java b/location/java/android/location/LocationManager.java
index da760a1..9e4a16b 100644
--- a/location/java/android/location/LocationManager.java
+++ b/location/java/android/location/LocationManager.java
@@ -317,7 +317,7 @@
List<String> providers = getProviders(enabledOnly);
for (String providerName : providers) {
LocationProvider provider = getProvider(providerName);
- if (provider.meetsCriteria(criteria)) {
+ if (provider != null && provider.meetsCriteria(criteria)) {
if (goodProviders.isEmpty()) {
goodProviders = new ArrayList<String>();
}
diff --git a/media/java/android/media/AudioService.java b/media/java/android/media/AudioService.java
index a36ee85..e586869 100644
--- a/media/java/android/media/AudioService.java
+++ b/media/java/android/media/AudioService.java
@@ -450,10 +450,20 @@
VolumeStreamState streamState = mStreamStates[streamType];
if (streamState.setIndex(index, lastAudible) || force) {
// Post message to set system volume (it in turn will post a message
- // to persist). Do not change volume if stream is muted.
- if (streamState.muteCount() == 0) {
+ // to persist).
+ // If stream is muted or we are in silent mode and stream is affected by ringer mode
+ // and the new volume is not 0, just persist the new volume but do not change
+ // current value
+ if (streamState.muteCount() == 0 &&
+ (mRingerMode == AudioManager.RINGER_MODE_NORMAL ||
+ !isStreamAffectedByRingerMode(streamType) ||
+ index == 0)) {
sendMsg(mAudioHandler, MSG_SET_SYSTEM_VOLUME, streamType, SENDMSG_NOOP, 0, 0,
streamState, 0);
+ } else {
+ // Post a persist volume msg
+ sendMsg(mAudioHandler, MSG_PERSIST_VOLUME, streamType,
+ SENDMSG_REPLACE, 0, 1, streamState, PERSIST_DELAY);
}
}
}
@@ -512,7 +522,7 @@
if (!isStreamAffectedByRingerMode(streamType)) continue;
// Bring back last audible volume
setStreamVolumeInt(streamType, mStreamStates[streamType].mLastAudibleIndex,
- false, false);
+ true, false);
}
} else {
for (int streamType = numStreamTypes - 1; streamType >= 0; streamType--) {
@@ -524,7 +534,7 @@
// to non affected by ringer mode. Does not arm to do it for streams that
// are not affected as well.
setStreamVolumeInt(streamType, mStreamStates[streamType].mLastAudibleIndex,
- false, false);
+ true, false);
}
}
}
@@ -1269,14 +1279,18 @@
// Post a persist volume msg
sendMsg(mAudioHandler, MSG_PERSIST_VOLUME, streamState.mStreamType,
- SENDMSG_REPLACE, 0, 0, streamState, PERSIST_DELAY);
+ SENDMSG_REPLACE, 1, 1, streamState, PERSIST_DELAY);
}
- private void persistVolume(VolumeStreamState streamState) {
- System.putInt(mContentResolver, streamState.mVolumeIndexSettingName,
- (streamState.mIndex + 5)/ 10);
- System.putInt(mContentResolver, streamState.mLastAudibleVolumeIndexSettingName,
+ private void persistVolume(VolumeStreamState streamState, boolean current, boolean lastAudible) {
+ if (current) {
+ System.putInt(mContentResolver, streamState.mVolumeIndexSettingName,
+ (streamState.mIndex + 5)/ 10);
+ }
+ if (lastAudible) {
+ System.putInt(mContentResolver, streamState.mLastAudibleVolumeIndexSettingName,
(streamState.mLastAudibleIndex + 5) / 10);
+ }
}
private void persistRingerMode() {
@@ -1361,7 +1375,7 @@
break;
case MSG_PERSIST_VOLUME:
- persistVolume((VolumeStreamState) msg.obj);
+ persistVolume((VolumeStreamState) msg.obj, (msg.arg1 != 0), (msg.arg2 != 0));
break;
case MSG_PERSIST_RINGER_MODE:
@@ -1469,7 +1483,7 @@
// and persist with no delay as there might be registered observers of the persisted
// notification volume.
sendMsg(mAudioHandler, MSG_PERSIST_VOLUME, AudioSystem.STREAM_NOTIFICATION,
- SENDMSG_REPLACE, 0, 0, mStreamStates[AudioSystem.STREAM_NOTIFICATION], 0);
+ SENDMSG_REPLACE, 1, 1, mStreamStates[AudioSystem.STREAM_NOTIFICATION], 0);
}
}
}
diff --git a/media/java/android/media/MediaRecorder.java b/media/java/android/media/MediaRecorder.java
index 15e35010..2c5cbf6 100644
--- a/media/java/android/media/MediaRecorder.java
+++ b/media/java/android/media/MediaRecorder.java
@@ -225,46 +225,6 @@
public static final int MPEG_4_SP = 3;
}
-
- /**
- * @hide Defines the audio sampling rate. This must be set before
- * setAudioEncoder() or it will be ignored.
- * This parameter is used with
- * {@link MediaRecorder#setParameters(String)}.
- */
- public final class AudioParamSamplingRate {
- /* Do not change these values without updating their counterparts
- * in include/media/mediarecorder.h!
- */
- private AudioParamSamplingRate() {}
- public static final String AUDIO_PARAM_SAMPLING_RATE_KEY = "audio-param-sampling-rate=";
- }
-
- /**
- * @hide Defines the audio number of channels. This must be set before
- * setAudioEncoder() or it will be ignored.
- * This parameter is used with
- * {@link MediaRecorder#setParameters(String)}.
- */
- public final class AudioParamChannels {
- /* Do not change these values without updating their counterparts
- * in include/media/mediarecorder.h!
- */
- private AudioParamChannels() {}
- public static final String AUDIO_PARAM_NUMBER_OF_CHANNELS = "audio-param-number-of-channels=";
- }
-
- /**
- * @hide Defines the audio encoding bitrate. This must be set before
- * setAudioEncoder() or it will be ignored.
- * This parameter is used with
- * {@link MediaRecorder#setParameters(String)}.
- */
- public final class AudioParamEncodingBitrate{
- private AudioParamEncodingBitrate() {}
- public static final String AUDIO_PARAM_ENCODING_BITRATE = "audio-param-encoding-bitrate=";
- }
-
/**
* Sets the audio source to be used for recording. If this method is not
* called, the output file will not contain an audio track. The source needs
@@ -399,14 +359,69 @@
throws IllegalStateException;
/**
- * @hide Sets a parameter in the author engine.
+ * Sets the audio sampling rate for recording. Call this method before prepare().
+ * Prepare() may perform additional checks on the parameter to make sure whether
+ * the specified audio sampling rate is applicable. The sampling rate really depends
+ * on the format for the audio recording, as well as the capabilities of the platform.
+ * For instance, the sampling rate supported by AAC audio coding standard ranges
+ * from 8 to 96 kHz. Please consult with the related audio coding standard for the
+ * supported audio sampling rate.
*
- * @param params the parameter to set.
- * @see android.media.MediaRecorder.AudioParamSamplingRate
- * @see android.media.MediaRecorder.AudioParamChannels
- * @see android.media.MediaRecorder.AudioParamEncodingBitrate
+ * @param samplingRate the sampling rate for audio in samples per second.
*/
- public native void setParameters(String params);
+ public void setAudioSamplingRate(int samplingRate) {
+ if (samplingRate <= 0) {
+ throw new IllegalArgumentException("Audio sampling rate is not positive");
+ }
+ setParameter(String.format("audio-param-sampling-rate=%d", samplingRate));
+ }
+
+ /**
+ * Sets the number of audio channels for recording. Call this method before prepare().
+ * Prepare() may perform additional checks on the parameter to make sure whether the
+ * specified number of audio channels are applicable.
+ *
+ * @param numChannels the number of audio channels. Usually it is either 1 (mono) or 2
+ * (stereo).
+ */
+ public void setAudioChannels(int numChannels) {
+ if (numChannels <= 0) {
+ throw new IllegalArgumentException("Number of channels is not positive");
+ }
+ setParameter(String.format("audio-param-number-of-channels=%d", numChannels));
+ }
+
+ /**
+ * Sets the audio encoding bit rate for recording. Call this method before prepare().
+ * Prepare() may perform additional checks on the parameter to make sure whether the
+ * specified bit rate is applicable, and sometimes the passed bitRate will be clipped
+ * internally to ensure the audio recording can proceed smoothly based on the
+ * capabilities of the platform.
+ *
+ * @param bitRate the audio encoding bit rate in bits per second.
+ */
+ public void setAudioEncodingBitRate(int bitRate) {
+ if (bitRate <= 0) {
+ throw new IllegalArgumentException("Audio encoding bit rate is not positive");
+ }
+ setParameter(String.format("audio-param-encoding-bitrate=%d", bitRate));
+ }
+
+ /**
+ * Sets the video encoding bit rate for recording. Call this method before prepare().
+ * Prepare() may perform additional checks on the parameter to make sure whether the
+ * specified bit rate is applicable, and sometimes the passed bitRate will be
+ * clipped internally to ensure the video recording can proceed smoothly based on
+ * the capabilities of the platform.
+ *
+ * @param bitRate the video encoding bit rate in bits per second.
+ */
+ public void setVideoEncodingBitRate(int bitRate) {
+ if (bitRate <= 0) {
+ throw new IllegalArgumentException("Video encoding bit rate is not positive");
+ }
+ setParameter(String.format("video-param-encoding-bitrate=%d", bitRate));
+ }
/**
* Pass in the file descriptor of the file to be written. Call this after
@@ -670,6 +685,8 @@
private native final void native_finalize();
+ private native void setParameter(String nameValuePair);
+
@Override
protected void finalize() { native_finalize(); }
}
diff --git a/media/jni/android_media_MediaRecorder.cpp b/media/jni/android_media_MediaRecorder.cpp
index 3063f15..00af3a2 100644
--- a/media/jni/android_media_MediaRecorder.cpp
+++ b/media/jni/android_media_MediaRecorder.cpp
@@ -223,9 +223,9 @@
}
static void
-android_media_MediaRecorder_setParameters(JNIEnv *env, jobject thiz, jstring params)
+android_media_MediaRecorder_setParameter(JNIEnv *env, jobject thiz, jstring params)
{
- LOGV("setParameters()");
+ LOGV("setParameter()");
if (params == NULL)
{
LOGE("Invalid or empty params string. This parameter will be ignored.");
@@ -455,7 +455,7 @@
{"setOutputFormat", "(I)V", (void *)android_media_MediaRecorder_setOutputFormat},
{"setVideoEncoder", "(I)V", (void *)android_media_MediaRecorder_setVideoEncoder},
{"setAudioEncoder", "(I)V", (void *)android_media_MediaRecorder_setAudioEncoder},
- {"setParameters", "(Ljava/lang/String;)V", (void *)android_media_MediaRecorder_setParameters},
+ {"setParameter", "(Ljava/lang/String;)V", (void *)android_media_MediaRecorder_setParameter},
{"_setOutputFile", "(Ljava/io/FileDescriptor;JJ)V", (void *)android_media_MediaRecorder_setOutputFileFD},
{"setVideoSize", "(II)V", (void *)android_media_MediaRecorder_setVideoSize},
{"setVideoFrameRate", "(I)V", (void *)android_media_MediaRecorder_setVideoFrameRate},
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/MediaRecorderTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/MediaRecorderTest.java
index 39caccd..a52fd76 100644
--- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/MediaRecorderTest.java
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/MediaRecorderTest.java
@@ -141,14 +141,10 @@
mMediaRecorder.setOutputFile(filename);
mMediaRecorder.setVideoFrameRate(videoFps);
mMediaRecorder.setVideoSize(videoWidth, videoHeight);
- mMediaRecorder.setParameters(String.format("video-param-encoding-bitrate=%d",
- videoBitrate));
- mMediaRecorder.setParameters(String.format("audio-param-encoding-bitrate=%d",
- audioBitrate));
- mMediaRecorder.setParameters(String.format("audio-param-number-of-channels=%d",
- audioChannels));
- mMediaRecorder.setParameters(String.format("audio-param-sampling-rate=%d",
- audioSamplingRate));
+ mMediaRecorder.setVideoEncodingBitRate(videoBitrate);
+ mMediaRecorder.setAudioEncodingBitRate(audioBitrate);
+ mMediaRecorder.setAudioChannels(audioChannels);
+ mMediaRecorder.setAudioSamplingRate(audioSamplingRate);
mMediaRecorder.setVideoEncoder(videoEncoder);
mMediaRecorder.setAudioEncoder(audioEncoder);
mMediaRecorder.setPreviewDisplay(mSurfaceHolder.getSurface());
diff --git a/media/tests/omxjpegdecoder/jpeg_decoder_bench.cpp b/media/tests/omxjpegdecoder/jpeg_decoder_bench.cpp
index 2d05a49..7537e35 100644
--- a/media/tests/omxjpegdecoder/jpeg_decoder_bench.cpp
+++ b/media/tests/omxjpegdecoder/jpeg_decoder_bench.cpp
@@ -32,8 +32,7 @@
}
protected:
- virtual bool onDecode(SkStream* stream, SkBitmap* bm,
- SkBitmap::Config pref, Mode);
+ virtual bool onDecode(SkStream* stream, SkBitmap* bm, Mode);
};
int nullObjectReturn(const char msg[]) {
diff --git a/media/tests/omxjpegdecoder/omx_jpeg_decoder.cpp b/media/tests/omxjpegdecoder/omx_jpeg_decoder.cpp
index f229f9d..209e71c 100644
--- a/media/tests/omxjpegdecoder/omx_jpeg_decoder.cpp
+++ b/media/tests/omxjpegdecoder/omx_jpeg_decoder.cpp
@@ -97,14 +97,14 @@
}
bool OmxJpegImageDecoder::onDecode(SkStream* stream,
- SkBitmap* bm, SkBitmap::Config pref, Mode mode) {
+ SkBitmap* bm, Mode mode) {
sp<MediaSource> source = prepareMediaSource(stream);
sp<MetaData> meta = source->getFormat();
int width;
int height;
meta->findInt32(kKeyWidth, &width);
meta->findInt32(kKeyHeight, &height);
- configBitmapSize(bm, pref, width, height);
+ configBitmapSize(bm, getPrefConfig(k32Bit_SrcDepth, false), width, height);
// mode == DecodeBounds
if (mode == SkImageDecoder::kDecodeBounds_Mode) {
diff --git a/media/tests/omxjpegdecoder/omx_jpeg_decoder.h b/media/tests/omxjpegdecoder/omx_jpeg_decoder.h
index 7d8bac09c..a313877 100644
--- a/media/tests/omxjpegdecoder/omx_jpeg_decoder.h
+++ b/media/tests/omxjpegdecoder/omx_jpeg_decoder.h
@@ -42,8 +42,7 @@
}
protected:
- virtual bool onDecode(SkStream* stream, SkBitmap* bm,
- SkBitmap::Config pref, Mode mode);
+ virtual bool onDecode(SkStream* stream, SkBitmap* bm, Mode mode);
private:
JPEGSource* prepareMediaSource(SkStream* stream);
diff --git a/packages/DefaultContainerService/src/com/android/defcontainer/DefaultContainerService.java b/packages/DefaultContainerService/src/com/android/defcontainer/DefaultContainerService.java
index a79f0cd..c826973 100644
--- a/packages/DefaultContainerService/src/com/android/defcontainer/DefaultContainerService.java
+++ b/packages/DefaultContainerService/src/com/android/defcontainer/DefaultContainerService.java
@@ -166,62 +166,41 @@
String codePath = packageURI.getPath();
File codeFile = new File(codePath);
String newCachePath = null;
- final int CREATE_FAILED = 1;
- final int COPY_FAILED = 2;
- final int FINALIZE_FAILED = 3;
- final int PASS = 4;
- int errCode = CREATE_FAILED;
// Create new container
if ((newCachePath = PackageHelper.createSdDir(codeFile,
- newCid, key, Process.myUid())) != null) {
- if (localLOGV) Log.i(TAG, "Created container for " + newCid
- + " at path : " + newCachePath);
- File resFile = new File(newCachePath, resFileName);
- errCode = COPY_FAILED;
- // Copy file from codePath
- if (FileUtils.copyFile(new File(codePath), resFile)) {
- if (localLOGV) Log.i(TAG, "Copied " + codePath + " to " + resFile);
- errCode = FINALIZE_FAILED;
- if (PackageHelper.finalizeSdDir(newCid)) {
- if (localLOGV) Log.i(TAG, "Finalized container " + newCid);
- errCode = PASS;
- }
- }
- }
- // Print error based on errCode
- String errMsg = "";
- switch (errCode) {
- case CREATE_FAILED:
- errMsg = "CREATE_FAILED";
- break;
- case COPY_FAILED:
- errMsg = "COPY_FAILED";
- if (localLOGV) Log.i(TAG, "Destroying " + newCid +
- " at path " + newCachePath + " after " + errMsg);
- PackageHelper.destroySdDir(newCid);
- break;
- case FINALIZE_FAILED:
- errMsg = "FINALIZE_FAILED";
- if (localLOGV) Log.i(TAG, "Destroying " + newCid +
- " at path " + newCachePath + " after " + errMsg);
- PackageHelper.destroySdDir(newCid);
- break;
- default:
- errMsg = "PASS";
- if (PackageHelper.isContainerMounted(newCid)) {
- if (localLOGV) Log.i(TAG, "Unmounting " + newCid +
- " at path " + newCachePath + " after " + errMsg);
- // Force a gc to avoid being killed.
- Runtime.getRuntime().gc();
- PackageHelper.unMountSdDir(newCid);
- } else {
- if (localLOGV) Log.i(TAG, "Container " + newCid + " not mounted");
- }
- break;
- }
- if (errCode != PASS) {
+ newCid, key, Process.myUid())) == null) {
+ Log.e(TAG, "Failed creating container " + newCid);
return null;
}
+ if (localLOGV) Log.i(TAG, "Created container for " + newCid
+ + " at path : " + newCachePath);
+ File resFile = new File(newCachePath, resFileName);
+ // Copy file from codePath
+ if (!FileUtils.copyFile(new File(codePath), resFile)) {
+ Log.e(TAG, "Failed to copy " + codePath + " to " + resFile);
+ // Clean up created container
+ PackageHelper.destroySdDir(newCid);
+ return null;
+ }
+ if (localLOGV) Log.i(TAG, "Copied " + codePath + " to " + resFile);
+ // Finalize container now
+ if (!PackageHelper.finalizeSdDir(newCid)) {
+ Log.e(TAG, "Failed to finalize " + newCid + " at cache path " + newCachePath);
+ // Clean up created container
+ PackageHelper.destroySdDir(newCid);
+ return null;
+ }
+ if (localLOGV) Log.i(TAG, "Finalized container " + newCid);
+ // Force a gc to avoid being killed.
+ Runtime.getRuntime().gc();
+ // Unmount container
+ if (PackageHelper.isContainerMounted(newCid)) {
+ if (localLOGV) Log.i(TAG, "Unmounting " + newCid +
+ " at path " + newCachePath);
+ PackageHelper.unMountSdDir(newCid);
+ } else {
+ if (localLOGV) Log.i(TAG, "Container " + newCid + " not mounted");
+ }
return newCachePath;
}
diff --git a/services/java/com/android/server/ConnectivityService.java b/services/java/com/android/server/ConnectivityService.java
index 67b6200..a1c45dc 100644
--- a/services/java/com/android/server/ConnectivityService.java
+++ b/services/java/com/android/server/ConnectivityService.java
@@ -1457,15 +1457,36 @@
}
// javadoc from interface
- public boolean tether(String iface) {
+ public int tether(String iface) {
enforceTetherChangePermission();
- return isTetheringSupported() && mTethering.tether(iface);
+
+ if (isTetheringSupported()) {
+ return mTethering.tether(iface);
+ } else {
+ return ConnectivityManager.TETHER_ERROR_UNSUPPORTED;
+ }
}
// javadoc from interface
- public boolean untether(String iface) {
+ public int untether(String iface) {
enforceTetherChangePermission();
- return isTetheringSupported() && mTethering.untether(iface);
+
+ if (isTetheringSupported()) {
+ return mTethering.untether(iface);
+ } else {
+ return ConnectivityManager.TETHER_ERROR_UNSUPPORTED;
+ }
+ }
+
+ // javadoc from interface
+ public int getLastTetherError(String iface) {
+ enforceTetherAccessPermission();
+
+ if (isTetheringSupported()) {
+ return mTethering.getLastTetherError(iface);
+ } else {
+ return ConnectivityManager.TETHER_ERROR_UNSUPPORTED;
+ }
}
// TODO - proper iface API for selection by property, inspection, etc
@@ -1499,6 +1520,11 @@
return mTethering.getTetheredIfaces();
}
+ public String[] getTetheringErroredIfaces() {
+ enforceTetherAccessPermission();
+ return mTethering.getErroredIfaces();
+ }
+
// if ro.tether.denied = true we default to no tethering
// gservices could set the secure setting to 1 though to enable it on a build where it
// had previously been turned off.
diff --git a/services/java/com/android/server/InputDevice.java b/services/java/com/android/server/InputDevice.java
index d5e94ec..ed7eed0 100644
--- a/services/java/com/android/server/InputDevice.java
+++ b/services/java/com/android/server/InputDevice.java
@@ -34,6 +34,16 @@
/** Maximum number of pointers we will track and report. */
static final int MAX_POINTERS = 10;
+ /**
+ * Slop distance for jumpy pointer detection.
+ * This is in touchscreen coordinates, not pixels or dips.
+ */
+ private static final int JUMPY_EPSILON = 30;
+
+ /** Number of jumpy points to drop for touchscreens that need it. */
+ private static final int JUMPY_TRANSITION_DROPS = 3;
+ private static final int JUMPY_DROP_LIMIT = 3;
+
final int id;
final int classes;
final String name;
@@ -84,6 +94,9 @@
// Used to determine whether we dropped bad data, to avoid doing
// it repeatedly.
final boolean[] mDroppedBadPoint = new boolean[MAX_POINTERS];
+
+ // Used to count the number of jumpy points dropped.
+ private int mJumpyPointsDropped = 0;
// Used to perform averaging of reported coordinates, to smooth
// the data and filter out transients during a release.
@@ -232,6 +245,158 @@
}
}
+ void dropJumpyPoint(InputDevice dev) {
+ final int nextNumPointers = mNextNumPointers;
+ final int lastNumPointers = mLastNumPointers;
+ final int[] nextData = mNextData;
+ final int[] lastData = mLastData;
+
+ if (nextNumPointers != mLastNumPointers) {
+ if (DEBUG_HACKS) {
+ Slog.d("InputDevice", "Different pointer count " + lastNumPointers +
+ " -> " + nextNumPointers);
+ for (int i = 0; i < nextNumPointers; i++) {
+ int ioff = i * MotionEvent.NUM_SAMPLE_DATA;
+ Slog.d("InputDevice", "Pointer " + i + " (" +
+ mNextData[ioff + MotionEvent.SAMPLE_X] + ", " +
+ mNextData[ioff + MotionEvent.SAMPLE_Y] + ")");
+ }
+ }
+
+ // Just drop the first few events going from 1 to 2 pointers.
+ // They're bad often enough that they're not worth considering.
+ if (lastNumPointers == 1 && nextNumPointers == 2
+ && mJumpyPointsDropped < JUMPY_TRANSITION_DROPS) {
+ mNextNumPointers = 1;
+ mJumpyPointsDropped++;
+ } else if (lastNumPointers == 2 && nextNumPointers == 1
+ && mJumpyPointsDropped < JUMPY_TRANSITION_DROPS) {
+ // The event when we go from 2 -> 1 tends to be messed up too
+ System.arraycopy(lastData, 0, nextData, 0,
+ lastNumPointers * MotionEvent.NUM_SAMPLE_DATA);
+ mNextNumPointers = lastNumPointers;
+ mJumpyPointsDropped++;
+
+ if (DEBUG_HACKS) {
+ for (int i = 0; i < mNextNumPointers; i++) {
+ int ioff = i * MotionEvent.NUM_SAMPLE_DATA;
+ Slog.d("InputDevice", "Pointer " + i + " replaced (" +
+ mNextData[ioff + MotionEvent.SAMPLE_X] + ", " +
+ mNextData[ioff + MotionEvent.SAMPLE_Y] + ")");
+ }
+ }
+ } else {
+ mJumpyPointsDropped = 0;
+
+ if (DEBUG_HACKS) {
+ Slog.d("InputDevice", "Transition - drop limit reset");
+ }
+ }
+ return;
+ }
+
+ // A 'jumpy' point is one where the coordinate value for one axis
+ // has jumped to the other pointer's location. No need to do anything
+ // else if we only have one pointer.
+ if (nextNumPointers < 2) {
+ return;
+ }
+
+ int badPointerIndex = -1;
+ int badPointerReplaceXWith = 0;
+ int badPointerReplaceYWith = 0;
+ int badPointerDistance = Integer.MIN_VALUE;
+ for (int i = nextNumPointers - 1; i >= 0; i--) {
+ boolean dropx = false;
+ boolean dropy = false;
+
+ // Limit how many times a jumpy point can get dropped.
+ if (mJumpyPointsDropped < JUMPY_DROP_LIMIT) {
+ final int ioff = i * MotionEvent.NUM_SAMPLE_DATA;
+ final int x = nextData[ioff + MotionEvent.SAMPLE_X];
+ final int y = nextData[ioff + MotionEvent.SAMPLE_Y];
+
+ if (DEBUG_HACKS) {
+ Slog.d("InputDevice", "Point " + i + " (" + x + ", " + y + ")");
+ }
+
+ // Check if a touch point is too close to another's coordinates
+ for (int j = 0; j < nextNumPointers && !dropx && !dropy; j++) {
+ if (j == i) {
+ continue;
+ }
+
+ final int joff = j * MotionEvent.NUM_SAMPLE_DATA;
+ final int xOther = nextData[joff + MotionEvent.SAMPLE_X];
+ final int yOther = nextData[joff + MotionEvent.SAMPLE_Y];
+
+ dropx = Math.abs(x - xOther) <= JUMPY_EPSILON;
+ dropy = Math.abs(y - yOther) <= JUMPY_EPSILON;
+ }
+
+ if (dropx) {
+ int xreplace = lastData[MotionEvent.SAMPLE_X];
+ int yreplace = lastData[MotionEvent.SAMPLE_Y];
+ int distance = Math.abs(yreplace - y);
+ for (int j = 1; j < lastNumPointers; j++) {
+ final int joff = j * MotionEvent.NUM_SAMPLE_DATA;
+ int lasty = lastData[joff + MotionEvent.SAMPLE_Y];
+ int currDist = Math.abs(lasty - y);
+ if (currDist < distance) {
+ xreplace = lastData[joff + MotionEvent.SAMPLE_X];
+ yreplace = lasty;
+ distance = currDist;
+ }
+ }
+
+ int badXDelta = Math.abs(xreplace - x);
+ if (badXDelta > badPointerDistance) {
+ badPointerDistance = badXDelta;
+ badPointerIndex = i;
+ badPointerReplaceXWith = xreplace;
+ badPointerReplaceYWith = yreplace;
+ }
+ } else if (dropy) {
+ int xreplace = lastData[MotionEvent.SAMPLE_X];
+ int yreplace = lastData[MotionEvent.SAMPLE_Y];
+ int distance = Math.abs(xreplace - x);
+ for (int j = 1; j < lastNumPointers; j++) {
+ final int joff = j * MotionEvent.NUM_SAMPLE_DATA;
+ int lastx = lastData[joff + MotionEvent.SAMPLE_X];
+ int currDist = Math.abs(lastx - x);
+ if (currDist < distance) {
+ xreplace = lastx;
+ yreplace = lastData[joff + MotionEvent.SAMPLE_Y];
+ distance = currDist;
+ }
+ }
+
+ int badYDelta = Math.abs(yreplace - y);
+ if (badYDelta > badPointerDistance) {
+ badPointerDistance = badYDelta;
+ badPointerIndex = i;
+ badPointerReplaceXWith = xreplace;
+ badPointerReplaceYWith = yreplace;
+ }
+ }
+ }
+ }
+ if (badPointerIndex >= 0) {
+ if (DEBUG_HACKS) {
+ Slog.d("InputDevice", "Replacing bad pointer " + badPointerIndex +
+ " with (" + badPointerReplaceXWith + ", " + badPointerReplaceYWith +
+ ")");
+ }
+
+ final int offset = badPointerIndex * MotionEvent.NUM_SAMPLE_DATA;
+ nextData[offset + MotionEvent.SAMPLE_X] = badPointerReplaceXWith;
+ nextData[offset + MotionEvent.SAMPLE_Y] = badPointerReplaceYWith;
+ mJumpyPointsDropped++;
+ } else {
+ mJumpyPointsDropped = 0;
+ }
+ }
+
/**
* Special hack for devices that have bad screen data: aggregate and
* compute averages of the coordinate data, to reduce the amount of
diff --git a/services/java/com/android/server/KeyInputQueue.java b/services/java/com/android/server/KeyInputQueue.java
index a08258a..8cd9578 100644
--- a/services/java/com/android/server/KeyInputQueue.java
+++ b/services/java/com/android/server/KeyInputQueue.java
@@ -18,6 +18,7 @@
import android.content.Context;
import android.content.res.Configuration;
+import android.content.res.Resources;
import android.os.Environment;
import android.os.LatencyTimer;
import android.os.PowerManager;
@@ -60,6 +61,12 @@
*/
static boolean BAD_TOUCH_HACK = false;
+ /**
+ * Turn on some hacks to improve touch interaction with another device
+ * where touch coordinate data can get corrupted.
+ */
+ static boolean JUMPY_TOUCH_HACK = false;
+
private static final String EXCLUDED_DEVICES_PATH = "etc/excluded-input-devices.xml";
final SparseArray<InputDevice> mDevices = new SparseArray<InputDevice>();
@@ -284,8 +291,10 @@
lt = new LatencyTimer(100, 1000);
}
- BAD_TOUCH_HACK = context.getResources().getBoolean(
- com.android.internal.R.bool.config_filterTouchEvents);
+ Resources r = context.getResources();
+ BAD_TOUCH_HACK = r.getBoolean(com.android.internal.R.bool.config_filterTouchEvents);
+
+ JUMPY_TOUCH_HACK = r.getBoolean(com.android.internal.R.bool.config_filterJumpyTouchEvents);
mHapticFeedbackCallback = hapticFeedbackCallback;
@@ -758,6 +767,9 @@
if (BAD_TOUCH_HACK) {
ms.dropBadPoint(di);
}
+ if (JUMPY_TOUCH_HACK) {
+ ms.dropJumpyPoint(di);
+ }
boolean doMotion = !monitorVirtualKey(di,
ev, curTime, curTimeNano);
diff --git a/services/java/com/android/server/MountService.java b/services/java/com/android/server/MountService.java
index 41f3850..0974f7f 100644
--- a/services/java/com/android/server/MountService.java
+++ b/services/java/com/android/server/MountService.java
@@ -523,6 +523,11 @@
Intent in = null;
+ if (oldState == VolumeState.Shared && newState != oldState) {
+ mContext.sendBroadcast(new Intent(Intent.ACTION_MEDIA_UNSHARED,
+ Uri.parse("file://" + path)));
+ }
+
if (newState == VolumeState.Init) {
} else if (newState == VolumeState.NoMedia) {
// NoMedia is handled via Disk Remove events
@@ -1171,13 +1176,6 @@
} catch (NativeDaemonConnectorException e) {
rc = StorageResultCode.OperationFailedInternalError;
}
- if (rc == StorageResultCode.OperationSucceeded) {
- synchronized (mAsecMountSet) {
- if (!mAsecMountSet.contains(newId)) {
- mAsecMountSet.add(newId);
- }
- }
- }
return rc;
}
diff --git a/services/java/com/android/server/NetworkManagementService.java b/services/java/com/android/server/NetworkManagementService.java
index 6d121c3..53076de 100644
--- a/services/java/com/android/server/NetworkManagementService.java
+++ b/services/java/com/android/server/NetworkManagementService.java
@@ -447,7 +447,7 @@
String []tok = line.split(" ");
int code = Integer.parseInt(tok[0]);
if (code == NetdResponseCode.UsbRNDISStatusResult) {
- if (tok[2].equals("started"))
+ if (tok[3].equals("started"))
return true;
return false;
} else {
diff --git a/services/java/com/android/server/PackageManagerService.java b/services/java/com/android/server/PackageManagerService.java
index bf2b1c7..664f028 100644
--- a/services/java/com/android/server/PackageManagerService.java
+++ b/services/java/com/android/server/PackageManagerService.java
@@ -318,6 +318,11 @@
// Set of pending broadcasts for aggregating enable/disable of components.
final HashMap<String, ArrayList<String>> mPendingBroadcasts
= new HashMap<String, ArrayList<String>>();
+ // Service Connection to remote media container service to copy
+ // package uri's from external media onto secure containers
+ // or internal storage.
+ private IMediaContainerService mContainerService = null;
+
static final int SEND_PENDING_BROADCAST = 1;
static final int MCS_BOUND = 3;
static final int END_COPY = 4;
@@ -326,17 +331,23 @@
static final int START_CLEANING_PACKAGE = 7;
static final int FIND_INSTALL_LOC = 8;
static final int POST_INSTALL = 9;
+ static final int MCS_RECONNECT = 10;
+ static final int MCS_GIVE_UP = 11;
+
// Delay time in millisecs
static final int BROADCAST_DELAY = 10 * 1000;
- private ServiceConnection mDefContainerConn = new ServiceConnection() {
+ final private DefaultContainerConnection mDefContainerConn =
+ new DefaultContainerConnection();
+ class DefaultContainerConnection implements ServiceConnection {
public void onServiceConnected(ComponentName name, IBinder service) {
+ if (DEBUG_SD_INSTALL) Log.i(TAG, "onServiceConnected");
IMediaContainerService imcs =
IMediaContainerService.Stub.asInterface(service);
- Message msg = mHandler.obtainMessage(MCS_BOUND, imcs);
- mHandler.sendMessage(msg);
+ mHandler.sendMessage(mHandler.obtainMessage(MCS_BOUND, imcs));
}
public void onServiceDisconnected(ComponentName name) {
+ if (DEBUG_SD_INSTALL) Log.i(TAG, "onServiceDisconnected");
}
};
@@ -355,12 +366,27 @@
int mNextInstallToken = 1; // nonzero; will be wrapped back to 1 when ++ overflows
class PackageHandler extends Handler {
+ private boolean mBound = false;
final ArrayList<HandlerParams> mPendingInstalls =
new ArrayList<HandlerParams>();
- // Service Connection to remote media container service to copy
- // package uri's from external media onto secure containers
- // or internal storage.
- private IMediaContainerService mContainerService = null;
+
+ private boolean connectToService() {
+ if (DEBUG_SD_INSTALL) Log.i(TAG, "Trying to bind to" +
+ " DefaultContainerService");
+ Intent service = new Intent().setComponent(DEFAULT_CONTAINER_COMPONENT);
+ if (mContext.bindService(service, mDefContainerConn,
+ Context.BIND_AUTO_CREATE)) {
+ mBound = true;
+ return true;
+ }
+ return false;
+ }
+
+ private void disconnectService() {
+ mContainerService = null;
+ mBound = false;
+ mContext.unbindService(mDefContainerConn);
+ }
PackageHandler(Looper looper) {
super(looper);
@@ -368,41 +394,99 @@
public void handleMessage(Message msg) {
switch (msg.what) {
case INIT_COPY: {
+ if (DEBUG_SD_INSTALL) Log.i(TAG, "init_copy");
HandlerParams params = (HandlerParams) msg.obj;
- Intent service = new Intent().setComponent(DEFAULT_CONTAINER_COMPONENT);
- if (mContainerService != null) {
- // No need to add to pending list. Use remote stub directly
- params.handleStartCopy(mContainerService);
- } else {
- if (mContext.bindService(service, mDefContainerConn,
- Context.BIND_AUTO_CREATE)) {
- mPendingInstalls.add(params);
- } else {
+ int idx = mPendingInstalls.size();
+ if (DEBUG_SD_INSTALL) Log.i(TAG, "idx=" + idx);
+ // If a bind was already initiated we dont really
+ // need to do anything. The pending install
+ // will be processed later on.
+ if (!mBound) {
+ // If this is the only one pending we might
+ // have to bind to the service again.
+ if (!connectToService()) {
Log.e(TAG, "Failed to bind to media container service");
- // Indicate service bind error
- params.handleServiceError();
+ params.serviceError();
+ return;
+ } else {
+ // Once we bind to the service, the first
+ // pending request will be processed.
+ mPendingInstalls.add(idx, params);
+ }
+ } else {
+ mPendingInstalls.add(idx, params);
+ // Already bound to the service. Just make
+ // sure we trigger off processing the first request.
+ if (idx == 0) {
+ mHandler.sendEmptyMessage(MCS_BOUND);
}
}
break;
}
case MCS_BOUND: {
- // Initialize mContainerService if needed.
+ if (DEBUG_SD_INSTALL) Log.i(TAG, "mcs_bound");
if (msg.obj != null) {
mContainerService = (IMediaContainerService) msg.obj;
}
- if (mPendingInstalls.size() > 0) {
- HandlerParams params = mPendingInstalls.remove(0);
+ if (mContainerService == null) {
+ // Something seriously wrong. Bail out
+ Log.e(TAG, "Cannot bind to media container service");
+ for (HandlerParams params : mPendingInstalls) {
+ mPendingInstalls.remove(0);
+ // Indicate service bind error
+ params.serviceError();
+ }
+ mPendingInstalls.clear();
+ } else if (mPendingInstalls.size() > 0) {
+ HandlerParams params = mPendingInstalls.get(0);
if (params != null) {
- params.handleStartCopy(mContainerService);
+ params.startCopy();
+ }
+ } else {
+ // Should never happen ideally.
+ Log.w(TAG, "Empty queue");
+ }
+ break;
+ }
+ case MCS_RECONNECT : {
+ if (DEBUG_SD_INSTALL) Log.i(TAG, "mcs_reconnect");
+ if (mPendingInstalls.size() > 0) {
+ if (mBound) {
+ disconnectService();
+ }
+ if (!connectToService()) {
+ Log.e(TAG, "Failed to bind to media container service");
+ for (HandlerParams params : mPendingInstalls) {
+ mPendingInstalls.remove(0);
+ // Indicate service bind error
+ params.serviceError();
+ }
+ mPendingInstalls.clear();
}
}
break;
}
case MCS_UNBIND : {
- if (mPendingInstalls.size() == 0) {
- mContext.unbindService(mDefContainerConn);
- mContainerService = null;
+ if (DEBUG_SD_INSTALL) Log.i(TAG, "mcs_unbind");
+ // Delete pending install
+ if (mPendingInstalls.size() > 0) {
+ mPendingInstalls.remove(0);
}
+ if (mPendingInstalls.size() == 0) {
+ if (mBound) {
+ disconnectService();
+ }
+ } else {
+ // There are more pending requests in queue.
+ // Just post MCS_BOUND message to trigger processing
+ // of next pending install.
+ mHandler.sendEmptyMessage(MCS_BOUND);
+ }
+ break;
+ }
+ case MCS_GIVE_UP: {
+ if (DEBUG_SD_INSTALL) Log.i(TAG, "mcs_giveup too many retries");
+ HandlerParams params = mPendingInstalls.remove(0);
break;
}
case SEND_PENDING_BROADCAST : {
@@ -2288,10 +2372,10 @@
synchronized (mPackages) {
// Look to see if we already know about this package.
String oldName = mSettings.mRenamedPackages.get(pkg.packageName);
- if (oldName != null && oldName.equals(pkg.mOriginalPackage)) {
+ if (pkg.mOriginalPackages != null && pkg.mOriginalPackages.contains(oldName)) {
// This package has been renamed to its original name. Let's
// use that.
- ps = mSettings.peekPackageLP(pkg.mOriginalPackage);
+ ps = mSettings.peekPackageLP(oldName);
}
// If there was no original package, see one for the real package name.
if (ps == null) {
@@ -2561,7 +2645,7 @@
if ((pkg.applicationInfo.flags&ApplicationInfo.FLAG_SYSTEM) == 0) {
// Only system apps can use these features.
- pkg.mOriginalPackage = null;
+ pkg.mOriginalPackages = null;
pkg.mRealPackage = null;
pkg.mAdoptPermissions = null;
}
@@ -2643,22 +2727,22 @@
}
if (false) {
- if (pkg.mOriginalPackage != null) {
+ if (pkg.mOriginalPackages != null) {
Log.w(TAG, "WAITING FOR DEBUGGER");
Debug.waitForDebugger();
- Log.i(TAG, "Package " + pkg.packageName + " from original package"
- + pkg.mOriginalPackage);
+ Log.i(TAG, "Package " + pkg.packageName + " from original packages"
+ + pkg.mOriginalPackages);
}
}
// Check if we are renaming from an original package name.
PackageSetting origPackage = null;
String realName = null;
- if (pkg.mOriginalPackage != null) {
+ if (pkg.mOriginalPackages != null) {
// This package may need to be renamed to a previously
// installed name. Let's check on that...
String renamed = mSettings.mRenamedPackages.get(pkg.mRealPackage);
- if (pkg.mOriginalPackage.equals(renamed)) {
+ if (pkg.mOriginalPackages.contains(renamed)) {
// This package had originally been installed as the
// original name, and we have already taken care of
// transitioning to the new one. Just update the new
@@ -2671,25 +2755,32 @@
pkg.setPackageName(renamed);
}
- } else if ((origPackage
- = mSettings.peekPackageLP(pkg.mOriginalPackage)) != null) {
- // We do have the package already installed under its
- // original name... should we use it?
- if (!verifyPackageUpdate(origPackage, pkg)) {
- // New package is not compatible with original.
- origPackage = null;
- } else if (origPackage.sharedUser != null) {
- // Make sure uid is compatible between packages.
- if (!origPackage.sharedUser.name.equals(pkg.mSharedUserId)) {
- Log.w(TAG, "Unable to migrate data from " + origPackage.name
- + " to " + pkg.packageName + ": old uid "
- + origPackage.sharedUser.name
- + " differs from " + pkg.mSharedUserId);
- origPackage = null;
+ } else {
+ for (int i=pkg.mOriginalPackages.size()-1; i>=0; i--) {
+ if ((origPackage=mSettings.peekPackageLP(
+ pkg.mOriginalPackages.get(i))) != null) {
+ // We do have the package already installed under its
+ // original name... should we use it?
+ if (!verifyPackageUpdate(origPackage, pkg)) {
+ // New package is not compatible with original.
+ origPackage = null;
+ continue;
+ } else if (origPackage.sharedUser != null) {
+ // Make sure uid is compatible between packages.
+ if (!origPackage.sharedUser.name.equals(pkg.mSharedUserId)) {
+ Log.w(TAG, "Unable to migrate data from " + origPackage.name
+ + " to " + pkg.packageName + ": old uid "
+ + origPackage.sharedUser.name
+ + " differs from " + pkg.mSharedUserId);
+ origPackage = null;
+ continue;
+ }
+ } else {
+ if (DEBUG_UPGRADE) Log.v(TAG, "Renaming new package "
+ + pkg.packageName + " to old name " + origPackage.name);
+ }
+ break;
}
- } else {
- if (DEBUG_UPGRADE) Log.v(TAG, "Renaming new package "
- + pkg.packageName + " to old name " + origPackage.name);
}
}
}
@@ -4407,12 +4498,41 @@
});
}
- interface HandlerParams {
- void handleStartCopy(IMediaContainerService imcs);
- void handleServiceError();
+ abstract class HandlerParams {
+ final static int MAX_RETRIES = 4;
+ int retry = 0;
+ final void startCopy() {
+ try {
+ if (DEBUG_SD_INSTALL) Log.i(TAG, "startCopy");
+ retry++;
+ if (retry > MAX_RETRIES) {
+ Log.w(TAG, "Failed to invoke remote methods on default container service. Giving up");
+ mHandler.sendEmptyMessage(MCS_GIVE_UP);
+ handleServiceError();
+ return;
+ } else {
+ handleStartCopy();
+ if (DEBUG_SD_INSTALL) Log.i(TAG, "Posting install MCS_UNBIND");
+ mHandler.sendEmptyMessage(MCS_UNBIND);
+ }
+ } catch (RemoteException e) {
+ if (DEBUG_SD_INSTALL) Log.i(TAG, "Posting install MCS_RECONNECT");
+ mHandler.sendEmptyMessage(MCS_RECONNECT);
+ }
+ handleReturnCode();
+ }
+
+ final void serviceError() {
+ if (DEBUG_SD_INSTALL) Log.i(TAG, "serviceError");
+ handleServiceError();
+ handleReturnCode();
+ }
+ abstract void handleStartCopy() throws RemoteException;
+ abstract void handleServiceError();
+ abstract void handleReturnCode();
}
- class InstallParams implements HandlerParams {
+ class InstallParams extends HandlerParams {
final IPackageInstallObserver observer;
int flags;
final Uri packageURI;
@@ -4428,22 +4548,14 @@
this.installerPackageName = installerPackageName;
}
- private int getInstallLocation(IMediaContainerService imcs) {
- try {
- return imcs.getRecommendedInstallLocation(packageURI);
- } catch (RemoteException e) {
- }
- return -1;
- }
-
- public void handleStartCopy(IMediaContainerService imcs) {
+ public void handleStartCopy() throws RemoteException {
int ret = PackageManager.INSTALL_SUCCEEDED;
// Dont need to invoke getInstallLocation for forward locked apps.
if ((flags & PackageManager.INSTALL_FORWARD_LOCK) != 0) {
flags &= ~PackageManager.INSTALL_EXTERNAL;
- } else if (imcs != null) {
+ } else {
// Remote call to find out default install location
- int loc = getInstallLocation(imcs);
+ int loc = mContainerService.getRecommendedInstallLocation(packageURI);
// Use install location to create InstallArgs and temporary
// install location
if (loc == PackageHelper.RECOMMEND_FAILED_INSUFFICIENT_STORAGE){
@@ -4468,23 +4580,22 @@
if (ret == PackageManager.INSTALL_SUCCEEDED) {
// Create copy only if we are not in an erroneous state.
// Remote call to initiate copy using temporary file
- ret = mArgs.copyApk(imcs, true);
+ ret = mArgs.copyApk(mContainerService, true);
}
mRet = ret;
- mHandler.sendEmptyMessage(MCS_UNBIND);
- handleReturnCode();
}
+ @Override
void handleReturnCode() {
processPendingInstall(mArgs, mRet);
}
- public void handleServiceError() {
+ @Override
+ void handleServiceError() {
mArgs = createInstallArgs(this);
mRet = PackageManager.INSTALL_FAILED_INTERNAL_ERROR;
- handleReturnCode();
}
- };
+ }
/*
* Utility class used in movePackage api.
@@ -4493,7 +4604,7 @@
* We probably want to return ErrorPrams for both failed installs
* and moves.
*/
- class MoveParams implements HandlerParams {
+ class MoveParams extends HandlerParams {
final IPackageMoveObserver observer;
final int flags;
final String packageName;
@@ -4515,25 +4626,36 @@
}
}
- public void handleStartCopy(IMediaContainerService imcs) {
+ public void handleStartCopy() throws RemoteException {
// Create the file args now.
- mRet = targetArgs.copyApk(imcs, false);
+ mRet = targetArgs.copyApk(mContainerService, false);
targetArgs.doPreInstall(mRet);
- mHandler.sendEmptyMessage(MCS_UNBIND);
- handleReturnCode();
+ if (DEBUG_SD_INSTALL) {
+ StringBuilder builder = new StringBuilder();
+ if (srcArgs != null) {
+ builder.append("src: ");
+ builder.append(srcArgs.getCodePath());
+ }
+ if (targetArgs != null) {
+ builder.append(" target : ");
+ builder.append(targetArgs.getCodePath());
+ }
+ Log.i(TAG, "Posting move MCS_UNBIND for " + builder.toString());
+ }
}
+ @Override
void handleReturnCode() {
targetArgs.doPostInstall(mRet);
// TODO invoke pending move
processPendingMove(this, mRet);
}
- public void handleServiceError() {
+ @Override
+ void handleServiceError() {
mRet = PackageManager.INSTALL_FAILED_INTERNAL_ERROR;
- handleReturnCode();
}
- };
+ }
private InstallArgs createInstallArgs(InstallParams params) {
if (installOnSd(params.flags)) {
@@ -4577,7 +4699,7 @@
}
abstract void createCopyFile();
- abstract int copyApk(IMediaContainerService imcs, boolean temp);
+ abstract int copyApk(IMediaContainerService imcs, boolean temp) throws RemoteException;
abstract int doPreInstall(int status);
abstract boolean doRename(int status, String pkgName, String oldCodePath);
abstract int doPostInstall(int status);
@@ -4628,7 +4750,7 @@
created = true;
}
- int copyApk(IMediaContainerService imcs, boolean temp) {
+ int copyApk(IMediaContainerService imcs, boolean temp) throws RemoteException {
if (temp) {
// Generate temp file name
createCopyFile();
@@ -4662,7 +4784,6 @@
if (imcs.copyResource(packageURI, out)) {
ret = PackageManager.INSTALL_SUCCEEDED;
}
- } catch (RemoteException e) {
} finally {
try { if (out != null) out.close(); } catch (IOException e) {}
}
@@ -4818,16 +4939,13 @@
cid = getTempContainerId();
}
- int copyApk(IMediaContainerService imcs, boolean temp) {
+ int copyApk(IMediaContainerService imcs, boolean temp) throws RemoteException {
if (temp) {
createCopyFile();
}
- try {
- cachePath = imcs.copyResourceToContainer(
- packageURI, cid,
- getEncryptKey(), RES_FILE_NAME);
- } catch (RemoteException e) {
- }
+ cachePath = imcs.copyResourceToContainer(
+ packageURI, cid,
+ getEncryptKey(), RES_FILE_NAME);
return (cachePath == null) ? PackageManager.INSTALL_FAILED_CONTAINER_ERROR :
PackageManager.INSTALL_SUCCEEDED;
}
@@ -4862,67 +4980,34 @@
String oldCodePath) {
String newCacheId = getNextCodePath(oldCodePath, pkgName, "/" + RES_FILE_NAME);
String newCachePath = null;
- boolean enableRename = false;
- if (enableRename) {
- if (PackageHelper.isContainerMounted(cid)) {
- // Unmount the container
- if (!PackageHelper.unMountSdDir(cid)) {
- Log.i(TAG, "Failed to unmount " + cid + " before renaming");
- return false;
- }
- }
- if (!PackageHelper.renameSdDir(cid, newCacheId)) {
- Log.e(TAG, "Failed to rename " + cid + " to " + newCacheId);
+ if (PackageHelper.isContainerMounted(cid)) {
+ // Unmount the container
+ if (!PackageHelper.unMountSdDir(cid)) {
+ Log.i(TAG, "Failed to unmount " + cid + " before renaming");
return false;
}
- if (!PackageHelper.isContainerMounted(newCacheId)) {
- Log.w(TAG, "Mounting container " + newCacheId);
- newCachePath = PackageHelper.mountSdDir(newCacheId,
- getEncryptKey(), Process.SYSTEM_UID);
- } else {
- newCachePath = PackageHelper.getSdDir(newCacheId);
- }
- if (newCachePath == null) {
- Log.w(TAG, "Failed to get cache path for " + newCacheId);
- return false;
- }
- // Mount old container?
- Log.i(TAG, "Succesfully renamed " + cid +
- " at path: " + cachePath + " to " + newCacheId +
- " at new path: " + newCachePath);
- cid = newCacheId;
- cachePath = newCachePath;
- return true;
- } else {
- // STOPSHIP work around for rename
- Log.i(TAG, "Copying instead of renaming");
- File srcFile = new File(getCodePath());
- // Create new container
- newCachePath = PackageHelper.createSdDir(srcFile, newCacheId,
- getEncryptKey(), Process.SYSTEM_UID);
- Log.i(TAG, "Created rename container " + newCacheId);
- File destFile = new File(newCachePath + "/" + RES_FILE_NAME);
- if (!FileUtils.copyFile(srcFile, destFile)) {
- Log.e(TAG, "Failed to copy " + srcFile + " to " + destFile);
- return false;
- }
- Log.i(TAG, "Successfully copied resource to " + newCachePath);
- if (!PackageHelper.finalizeSdDir(newCacheId)) {
- Log.e(TAG, "Failed to finalize " + newCacheId);
- PackageHelper.destroySdDir(newCacheId);
- return false;
- }
- Log.i(TAG, "Finalized " + newCacheId);
- Runtime.getRuntime().gc();
- // Unmount first
- PackageHelper.unMountSdDir(cid);
- // Delete old container
- PackageHelper.destroySdDir(cid);
- // Dont have to mount. Already mounted.
- cid = newCacheId;
- cachePath = newCachePath;
- return true;
}
+ if (!PackageHelper.renameSdDir(cid, newCacheId)) {
+ Log.e(TAG, "Failed to rename " + cid + " to " + newCacheId);
+ return false;
+ }
+ if (!PackageHelper.isContainerMounted(newCacheId)) {
+ Log.w(TAG, "Mounting container " + newCacheId);
+ newCachePath = PackageHelper.mountSdDir(newCacheId,
+ getEncryptKey(), Process.SYSTEM_UID);
+ } else {
+ newCachePath = PackageHelper.getSdDir(newCacheId);
+ }
+ if (newCachePath == null) {
+ Log.w(TAG, "Failed to get cache path for " + newCacheId);
+ return false;
+ }
+ Log.i(TAG, "Succesfully renamed " + cid +
+ " at path: " + cachePath + " to " + newCacheId +
+ " at new path: " + newCachePath);
+ cid = newCacheId;
+ cachePath = newCachePath;
+ return true;
}
int doPostInstall(int status) {
@@ -5401,13 +5486,14 @@
// Check if installing already existing package
if ((pFlags&PackageManager.INSTALL_REPLACE_EXISTING) != 0) {
String oldName = mSettings.mRenamedPackages.get(pkgName);
- if (oldName != null && oldName.equals(pkg.mOriginalPackage)
+ if (pkg.mOriginalPackages != null
+ && pkg.mOriginalPackages.contains(oldName)
&& mPackages.containsKey(oldName)) {
// This package is derived from an original package,
// and this device has been updating from that original
// name. We must continue using the original name, so
// rename the new package here.
- pkg.setPackageName(pkg.mOriginalPackage);
+ pkg.setPackageName(oldName);
pkgName = pkg.packageName;
replace = true;
} else if (mPackages.containsKey(pkgName)) {
@@ -8885,6 +8971,7 @@
* Return true if PackageManager does have packages to be updated.
*/
public boolean updateExternalMediaStatus(final boolean mediaStatus) {
+ final boolean ret;
synchronized (mPackages) {
if (DEBUG_SD_INSTALL) Log.i(TAG, "updateExternalMediaStatus:: mediaStatus=" +
mediaStatus+", mMediaMounted=" + mMediaMounted);
@@ -8892,72 +8979,77 @@
return false;
}
mMediaMounted = mediaStatus;
- boolean ret = false;
- synchronized (mPackages) {
- Set<String> appList = mSettings.findPackagesWithFlag(ApplicationInfo.FLAG_ON_SDCARD);
- ret = appList != null && appList.size() > 0;
- }
- if (!ret) {
- // No packages will be effected by the sdcard update. Just return.
- return false;
- }
- // Queue up an async operation since the package installation may take a little while.
- mHandler.post(new Runnable() {
- public void run() {
- mHandler.removeCallbacks(this);
- // If we are up here that means there are packages to be
- // enabled or disabled.
- final HashMap<SdInstallArgs, String> processCids =
- new HashMap<SdInstallArgs, String>();
- final int[] uidArr = getExternalMediaPackages(mediaStatus, processCids);
- if (mediaStatus) {
- if (DEBUG_SD_INSTALL) Log.i(TAG, "Loading packages");
- loadMediaPackages(processCids, uidArr);
- startCleaningPackages();
- } else {
- if (DEBUG_SD_INSTALL) Log.i(TAG, "Unloading packages");
- unloadMediaPackages(processCids, uidArr);
- }
- }
- });
- return true;
+ Set<String> appList = mSettings.findPackagesWithFlag(ApplicationInfo.FLAG_ON_SDCARD);
+ ret = appList != null && appList.size() > 0;
}
+ // Queue up an async operation since the package installation may take a little while.
+ mHandler.post(new Runnable() {
+ public void run() {
+ mHandler.removeCallbacks(this);
+ updateExternalMediaStatusInner(mediaStatus, ret);
+ }
+ });
+ return ret;
}
- private int[] getExternalMediaPackages(boolean mediaStatus,
- Map<SdInstallArgs, String> processCids) {
+ private void updateExternalMediaStatusInner(boolean mediaStatus,
+ boolean sendUpdateBroadcast) {
+ // If we are up here that means there are packages to be
+ // enabled or disabled.
final String list[] = PackageHelper.getSecureContainerList();
if (list == null || list.length == 0) {
- return null;
+ return;
}
int uidList[] = new int[list.length];
int num = 0;
+ HashSet<String> removeCids = new HashSet<String>();
+ HashMap<SdInstallArgs, String> processCids = new HashMap<SdInstallArgs, String>();
+ /*HashMap<String, String> cidPathMap = new HashMap<String, String>();
+ // Don't hold any locks when getting cache paths
+ for (String cid : list) {
+ String cpath = PackageHelper.getSdDir(cid);
+ if (cpath == null) {
+ removeCids.add(cid);
+ } else {
+ cidPathMap.put(cid, cpath);
+ }
+ }*/
synchronized (mPackages) {
- Set<String> appList = mSettings.findPackagesWithFlag(ApplicationInfo.FLAG_ON_SDCARD);
for (String cid : list) {
SdInstallArgs args = new SdInstallArgs(cid);
- String removeEntry = null;
- for (String app : appList) {
- if (args.matchContainer(app)) {
- removeEntry = app;
- break;
+ if (DEBUG_SD_INSTALL) Log.i(TAG, "Processing container " + cid);
+ boolean failed = true;
+ try {
+ String pkgName = args.getPackageName();
+ if (pkgName == null) {
+ continue;
}
- }
- if (removeEntry == null) {
- // No matching app on device. Skip entry or may be cleanup?
- // Ignore default package
- continue;
- }
- appList.remove(removeEntry);
- PackageSetting ps = mSettings.mPackages.get(removeEntry);
- processCids.put(args, ps.codePathString);
- int uid = ps.userId;
- if (uid != -1) {
- uidList[num++] = uid;
+ if (DEBUG_SD_INSTALL) Log.i(TAG, "Looking for pkg : " + pkgName);
+ PackageSetting ps = mSettings.mPackages.get(pkgName);
+ if (ps != null && ps.codePathString != null &&
+ (ps.pkgFlags & ApplicationInfo.FLAG_ON_SDCARD) != 0) {
+ if (DEBUG_SD_INSTALL) Log.i(TAG, "Container : " + cid +
+ " corresponds to pkg : " + pkgName +
+ " at code path: " + ps.codePathString);
+ // We do have a valid package installed on sdcard
+ processCids.put(args, ps.codePathString);
+ failed = false;
+ int uid = ps.userId;
+ if (uid != -1) {
+ uidList[num++] = uid;
+ }
+ }
+ } finally {
+ if (failed) {
+ // Stale container on sdcard. Just delete
+ if (DEBUG_SD_INSTALL) Log.i(TAG, "Container : " + cid + " stale");
+ removeCids.add(cid);
+ }
}
}
}
+ // Organize uids
int uidArr[] = null;
if (num > 0) {
// Sort uid list
@@ -8972,7 +9064,15 @@
}
}
}
- return uidArr;
+ // Process packages with valid entries.
+ if (mediaStatus) {
+ if (DEBUG_SD_INSTALL) Log.i(TAG, "Loading packages");
+ loadMediaPackages(processCids, uidArr, sendUpdateBroadcast, removeCids);
+ startCleaningPackages();
+ } else {
+ if (DEBUG_SD_INSTALL) Log.i(TAG, "Unloading packages");
+ unloadMediaPackages(processCids, uidArr, sendUpdateBroadcast);
+ }
}
private void sendResourcesChangedBroadcast(boolean mediaStatus,
@@ -8992,57 +9092,100 @@
}
}
- private void loadMediaPackages(HashMap<SdInstallArgs, String> processCids, int uidArr[]) {
+ /*
+ * Look at potentially valid container ids from processCids
+ * If package information doesn't match the one on record
+ * or package scanning fails, the cid is added to list of
+ * removeCids and cleaned up. Since cleaning up containers
+ * involves destroying them, we do not want any parse
+ * references to such stale containers. So force gc's
+ * to avoid unnecessary crashes.
+ */
+ private void loadMediaPackages(HashMap<SdInstallArgs, String> processCids,
+ int uidArr[], boolean sendUpdateBroadcast,
+ HashSet<String> removeCids) {
ArrayList<String> pkgList = new ArrayList<String>();
Set<SdInstallArgs> keys = processCids.keySet();
+ boolean doGc = false;
for (SdInstallArgs args : keys) {
String codePath = processCids.get(args);
- if (DEBUG_SD_INSTALL) Log.i(TAG, "Trying to install pkg : "
- + args.cid + " from " + args.cachePath);
- if (args.doPreInstall(PackageManager.INSTALL_SUCCEEDED) != PackageManager.INSTALL_SUCCEEDED) {
- Log.e(TAG, "Failed to install package: " + codePath + " from sdcard");
- continue;
- }
- // Parse package
- int parseFlags = PackageParser.PARSE_CHATTY |
- PackageParser.PARSE_ON_SDCARD | mDefParseFlags;
- PackageParser pp = new PackageParser(codePath);
- pp.setSeparateProcesses(mSeparateProcesses);
- final PackageParser.Package pkg = pp.parsePackage(new File(codePath),
- codePath, mMetrics, parseFlags);
- if (pkg == null) {
- Log.e(TAG, "Trying to install pkg : "
- + args.cid + " from " + args.cachePath);
- continue;
- }
- setApplicationInfoPaths(pkg, codePath, codePath);
+ if (DEBUG_SD_INSTALL) Log.i(TAG, "Loading container : "
+ + args.cid);
int retCode = PackageManager.INSTALL_FAILED_CONTAINER_ERROR;
- synchronized (mInstallLock) {
- // Scan the package
- if (scanPackageLI(pkg, parseFlags, SCAN_MONITOR) != null) {
- synchronized (mPackages) {
- // Grant permissions
- grantPermissionsLP(pkg, false);
- // Persist settings
- mSettings.writeLP();
- retCode = PackageManager.INSTALL_SUCCEEDED;
- pkgList.add(pkg.packageName);
+ try {
+ // Make sure there are no container errors first.
+ if (args.doPreInstall(PackageManager.INSTALL_SUCCEEDED)
+ != PackageManager.INSTALL_SUCCEEDED) {
+ Log.e(TAG, "Failed to mount cid : " + args.cid +
+ " when installing from sdcard");
+ continue;
+ }
+ // Check code path here.
+ if (codePath == null || !codePath.equals(args.getCodePath())) {
+ Log.e(TAG, "Container " + args.cid + " cachepath " + args.getCodePath()+
+ " does not match one in settings " + codePath);
+ continue;
+ }
+ // Parse package
+ int parseFlags = PackageParser.PARSE_CHATTY |
+ PackageParser.PARSE_ON_SDCARD | mDefParseFlags;
+ PackageParser pp = new PackageParser(codePath);
+ pp.setSeparateProcesses(mSeparateProcesses);
+ final PackageParser.Package pkg = pp.parsePackage(new File(codePath),
+ codePath, mMetrics, parseFlags);
+ pp = null;
+ doGc = true;
+ // Check for parse errors
+ if (pkg == null) {
+ Log.e(TAG, "Parse error when installing install pkg : "
+ + args.cid + " from " + args.cachePath);
+ continue;
+ }
+ setApplicationInfoPaths(pkg, codePath, codePath);
+ synchronized (mInstallLock) {
+ // Scan the package
+ if (scanPackageLI(pkg, parseFlags, SCAN_MONITOR) != null) {
+ synchronized (mPackages) {
+ // Grant permissions
+ grantPermissionsLP(pkg, false);
+ // Persist settings
+ mSettings.writeLP();
+ retCode = PackageManager.INSTALL_SUCCEEDED;
+ pkgList.add(pkg.packageName);
+ // Post process args
+ args.doPostInstall(PackageManager.INSTALL_SUCCEEDED);
+ }
+ } else {
+ Log.i(TAG, "Failed to install pkg: " +
+ pkg.packageName + " from sdcard");
}
- } else {
- Log.i(TAG, "Failed to install package: " + pkg.packageName + " from sdcard");
+ }
+
+ } finally {
+ if (retCode != PackageManager.INSTALL_SUCCEEDED) {
+ // Don't destroy container here. Wait till gc clears things up.
+ removeCids.add(args.cid);
}
}
- args.doPostInstall(retCode);
}
// Send a broadcast to let everyone know we are done processing
- sendResourcesChangedBroadcast(true, pkgList, uidArr);
- if (pkgList.size() > 0) {
+ if (sendUpdateBroadcast) {
+ sendResourcesChangedBroadcast(true, pkgList, uidArr);
+ }
+ if (doGc) {
Runtime.getRuntime().gc();
- // If something failed do we clean up here or next install?
+ }
+ // Delete any stale containers if needed.
+ if (removeCids != null) {
+ for (String cid : removeCids) {
+ Log.i(TAG, "Destroying stale container : " + cid);
+ PackageHelper.destroySdDir(cid);
+ }
}
}
- private void unloadMediaPackages(HashMap<SdInstallArgs, String> processCids, int uidArr[]) {
+ private void unloadMediaPackages(HashMap<SdInstallArgs, String> processCids,
+ int uidArr[], boolean sendUpdateBroadcast) {
if (DEBUG_SD_INSTALL) Log.i(TAG, "unloading media packages");
ArrayList<String> pkgList = new ArrayList<String>();
ArrayList<SdInstallArgs> failedList = new ArrayList<SdInstallArgs>();
@@ -9064,13 +9207,14 @@
}
}
}
- sendResourcesChangedBroadcast(false, pkgList, uidArr);
// Send broadcasts
- if (pkgList.size() > 0) {
- Runtime.getRuntime().gc();
+ if (sendUpdateBroadcast) {
+ sendResourcesChangedBroadcast(false, pkgList, uidArr);
}
- // Do clean up. Just unmount
- for (SdInstallArgs args : failedList) {
+ // Force gc
+ Runtime.getRuntime().gc();
+ // Just unmount all valid containers.
+ for (SdInstallArgs args : keys) {
synchronized (mInstallLock) {
args.doPostDeleteLI(false);
}
@@ -9189,21 +9333,21 @@
}
}
}
- if (moveSucceeded) {
- // Delete older code
- synchronized (mInstallLock) {
- mp.srcArgs.cleanUpResourcesLI();
- }
- // Send resources available broadcast
- sendResourcesChangedBroadcast(true, pkgList, uidArr);
- Runtime.getRuntime().gc();
- }
+ // Send resources available broadcast
+ sendResourcesChangedBroadcast(true, pkgList, uidArr);
}
if (!moveSucceeded){
// Clean up failed installation
if (mp.targetArgs != null) {
mp.targetArgs.doPostInstall(
- PackageManager.INSTALL_FAILED_INTERNAL_ERROR);
+ returnCode);
+ }
+ } else {
+ // Force a gc to clear things up.
+ Runtime.getRuntime().gc();
+ // Delete older code
+ synchronized (mInstallLock) {
+ mp.srcArgs.doPostDeleteLI(true);
}
}
IPackageMoveObserver observer = mp.observer;
diff --git a/services/java/com/android/server/connectivity/Tethering.java b/services/java/com/android/server/connectivity/Tethering.java
index 5f37a42..ee54f73 100644
--- a/services/java/com/android/server/connectivity/Tethering.java
+++ b/services/java/com/android/server/connectivity/Tethering.java
@@ -40,6 +40,7 @@
import android.os.ServiceManager;
import android.provider.Settings;
import android.util.Log;
+import android.widget.Toast;
import com.android.internal.telephony.Phone;
import com.android.internal.util.HierarchicalState;
@@ -236,7 +237,7 @@
}
}
- public boolean tether(String iface) {
+ public int tether(String iface) {
Log.d(TAG, "Tethering " + iface);
TetherInterfaceSM sm = null;
synchronized (mIfaces) {
@@ -244,21 +245,17 @@
}
if (sm == null) {
Log.e(TAG, "Tried to Tether an unknown iface :" + iface + ", ignoring");
- return false;
+ return ConnectivityManager.TETHER_ERROR_UNKNOWN_IFACE;
}
- if (sm.isErrored()) {
- Log.e(TAG, "Tried to Tether to an errored iface :" + iface + ", ignoring");
- return false;
- }
- if (!sm.isAvailable()) {
+ if (!sm.isAvailable() && !sm.isErrored()) {
Log.e(TAG, "Tried to Tether an unavailable iface :" + iface + ", ignoring");
- return false;
+ return ConnectivityManager.TETHER_ERROR_UNAVAIL_IFACE;
}
sm.sendMessage(sm.obtainMessage(TetherInterfaceSM.CMD_TETHER_REQUESTED));
- return true;
+ return ConnectivityManager.TETHER_ERROR_NO_ERROR;
}
- public boolean untether(String iface) {
+ public int untether(String iface) {
Log.d(TAG, "Untethering " + iface);
TetherInterfaceSM sm = null;
synchronized (mIfaces) {
@@ -266,14 +263,26 @@
}
if (sm == null) {
Log.e(TAG, "Tried to Untether an unknown iface :" + iface + ", ignoring");
- return false;
+ return ConnectivityManager.TETHER_ERROR_UNKNOWN_IFACE;
}
if (sm.isErrored()) {
Log.e(TAG, "Tried to Untethered an errored iface :" + iface + ", ignoring");
- return false;
+ return ConnectivityManager.TETHER_ERROR_UNAVAIL_IFACE;
}
sm.sendMessage(sm.obtainMessage(TetherInterfaceSM.CMD_TETHER_UNREQUESTED));
- return true;
+ return ConnectivityManager.TETHER_ERROR_NO_ERROR;
+ }
+
+ public int getLastTetherError(String iface) {
+ TetherInterfaceSM sm = null;
+ synchronized (mIfaces) {
+ sm = mIfaces.get(iface);
+ }
+ if (sm == null) {
+ Log.e(TAG, "Tried to getLastTetherError on an unknown iface :" + iface + ", ignoring");
+ return ConnectivityManager.TETHER_ERROR_UNKNOWN_IFACE;
+ }
+ return sm.getLastError();
}
private void sendTetherStateChangedBroadcast() {
@@ -430,6 +439,28 @@
}
}
+ private void showErrorToast(int error) {
+ int num;
+ switch(error) {
+ case ConnectivityManager.TETHER_ERROR_TETHER_IFACE_ERROR:
+ case ConnectivityManager.TETHER_ERROR_ENABLE_NAT_ERROR:
+ case ConnectivityManager.TETHER_ERROR_IFACE_CFG_ERROR:
+ case ConnectivityManager.TETHER_ERROR_MASTER_ERROR:
+ num = com.android.internal.R.string.tether_error_message;
+ break;
+ case ConnectivityManager.TETHER_ERROR_UNTETHER_IFACE_ERROR:
+ case ConnectivityManager.TETHER_ERROR_DISABLE_NAT_ERROR:
+ num = com.android.internal.R.string.tether_stop_error_message;
+ break;
+ default:
+ // do nothing
+ return;
+ }
+ String text = mContext.getResources().getString(num) + " - EC" + error;
+ Log.e(TAG, text);
+ Toast.makeText(mContext, text, Toast.LENGTH_LONG).show();
+ }
+
private class StateReceiver extends BroadcastReceiver {
public void onReceive(Context content, Intent intent) {
String action = intent.getAction();
@@ -542,10 +573,9 @@
ifcg.interfaceFlags = ifcg.interfaceFlags.replace("down", "up");
} else {
ifcg.interfaceFlags = ifcg.interfaceFlags.replace("up", "down");
- // TODO - clean this up - maybe a better regex?
- ifcg.interfaceFlags = ifcg.interfaceFlags.replace("running", "");
- ifcg.interfaceFlags = ifcg.interfaceFlags.replace(" "," ");
}
+ ifcg.interfaceFlags = ifcg.interfaceFlags.replace("running", "");
+ ifcg.interfaceFlags = ifcg.interfaceFlags.replace(" "," ");
service.setInterfaceConfig(iface, ifcg);
}
} catch (Exception e) {
@@ -611,6 +641,24 @@
return retVal;
}
+ public String[] getErroredIfaces() {
+ ArrayList<String> list = new ArrayList<String>();
+ synchronized (mIfaces) {
+ Set keys = mIfaces.keySet();
+ for (Object key : keys) {
+ TetherInterfaceSM sm = mIfaces.get(key);
+ if (sm.isErrored()) {
+ list.add((String)key);
+ }
+ }
+ }
+ String[] retVal = new String[list.size()];
+ for (int i= 0; i< list.size(); i++) {
+ retVal[i] = list.get(i);
+ }
+ return retVal;
+ }
+
class TetherInterfaceSM extends HierarchicalStateMachine {
// notification from the master SM that it's in tether mode
@@ -637,8 +685,8 @@
static final int CMD_STOP_TETHERING_ERROR = 14;
// notification from the master SM that it had trouble setting the DNS forwarders
static final int CMD_SET_DNS_FORWARDERS_ERROR = 15;
- // a mechanism to transition self to error state from an enter function
- static final int CMD_TRANSITION_TO_ERROR = 16;
+ // a mechanism to transition self to another state from an enter function
+ static final int CMD_TRANSITION_TO_STATE = 16;
private HierarchicalState mDefaultState;
@@ -646,18 +694,11 @@
private HierarchicalState mStartingState;
private HierarchicalState mTetheredState;
- private HierarchicalState mMasterTetherErrorState;
- private HierarchicalState mTetherInterfaceErrorState;
- private HierarchicalState mUntetherInterfaceErrorState;
- private HierarchicalState mEnableNatErrorState;
- private HierarchicalState mDisableNatErrorState;
- private HierarchicalState mUsbConfigurationErrorState;
-
private HierarchicalState mUnavailableState;
private boolean mAvailable;
- private boolean mErrored;
private boolean mTethered;
+ int mLastError;
String mIfaceName;
boolean mUsb;
@@ -666,6 +707,7 @@
super(name);
mIfaceName = name;
mUsb = usb;
+ setLastError(ConnectivityManager.TETHER_ERROR_NO_ERROR);
mInitialState = new InitialState();
addState(mInitialState);
@@ -673,18 +715,6 @@
addState(mStartingState);
mTetheredState = new TetheredState();
addState(mTetheredState);
- mMasterTetherErrorState = new MasterTetherErrorState();
- addState(mMasterTetherErrorState);
- mTetherInterfaceErrorState = new TetherInterfaceErrorState();
- addState(mTetherInterfaceErrorState);
- mUntetherInterfaceErrorState = new UntetherInterfaceErrorState();
- addState(mUntetherInterfaceErrorState);
- mEnableNatErrorState = new EnableNatErrorState();
- addState(mEnableNatErrorState);
- mDisableNatErrorState = new DisableNatErrorState();
- addState(mDisableNatErrorState);
- mUsbConfigurationErrorState = new UsbConfigurationErrorState();
- addState(mUsbConfigurationErrorState);
mUnavailableState = new UnavailableState();
addState(mUnavailableState);
@@ -698,19 +728,30 @@
if (current == mInitialState) res += "InitialState";
if (current == mStartingState) res += "StartingState";
if (current == mTetheredState) res += "TetheredState";
- if (current == mMasterTetherErrorState) res += "MasterTetherErrorState";
- if (current == mTetherInterfaceErrorState) res += "TetherInterfaceErrorState";
- if (current == mUntetherInterfaceErrorState) res += "UntetherInterfaceErrorState";
- if (current == mEnableNatErrorState) res += "EnableNatErrorState";
- if (current == mDisableNatErrorState) res += "DisableNatErrorState";
- if (current == mUsbConfigurationErrorState) res += "UsbConfigurationErrorState";
if (current == mUnavailableState) res += "UnavailableState";
if (mAvailable) res += " - Available";
if (mTethered) res += " - Tethered";
- if (mErrored) res += " - ERRORED";
+ res += " - lastError =" + mLastError;
return res;
}
+ public synchronized int getLastError() {
+ return mLastError;
+ }
+
+ private synchronized void setLastError(int error) {
+ mLastError = error;
+
+ if (isErrored()) {
+ if (mUsb) {
+ // note everything's been unwound by this point so nothing to do on
+ // further error..
+ Tethering.this.configureUsbIface(false);
+ }
+ Tethering.this.showErrorToast(error);
+ }
+ }
+
// synchronized between this getter and the following setter
public synchronized boolean isAvailable() {
return mAvailable;
@@ -731,18 +772,7 @@
// synchronized between this getter and the following setter
public synchronized boolean isErrored() {
- return mErrored;
- }
-
- private void setErrored(boolean errored) {
- synchronized (this) {
- mErrored = errored;
- }
- if (errored && mUsb) {
- // note everything's been unwound by this point so nothing to do on
- // further error..
- Tethering.this.configureUsbIface(false);
- }
+ return (mLastError != ConnectivityManager.TETHER_ERROR_NO_ERROR);
}
class InitialState extends HierarchicalState {
@@ -750,7 +780,6 @@
public void enter() {
setAvailable(true);
setTethered(false);
- setErrored(false);
sendTetherStateChangedBroadcast();
}
@@ -760,6 +789,7 @@
boolean retValue = true;
switch (message.what) {
case CMD_TETHER_REQUESTED:
+ setLastError(ConnectivityManager.TETHER_ERROR_NO_ERROR);
Message m = mTetherMasterSM.obtainMessage(
TetherMasterSM.CMD_TETHER_MODE_REQUESTED);
m.obj = TetherInterfaceSM.this;
@@ -788,8 +818,10 @@
m.obj = TetherInterfaceSM.this;
mTetherMasterSM.sendMessage(m);
- m = obtainMessage(CMD_TRANSITION_TO_ERROR);
- m.obj = mUsbConfigurationErrorState;
+ setLastError(ConnectivityManager.TETHER_ERROR_IFACE_CFG_ERROR);
+
+ m = obtainMessage(CMD_TRANSITION_TO_STATE);
+ m.obj = mInitialState;
sendMessageAtFrontOfQueue(m);
return;
}
@@ -809,7 +841,8 @@
mTetherMasterSM.sendMessage(m);
if (mUsb) {
if (!Tethering.this.configureUsbIface(false)) {
- transitionTo(mUsbConfigurationErrorState);
+ setLastErrorAndTransitionToInitialState(
+ ConnectivityManager.TETHER_ERROR_IFACE_CFG_ERROR);
break;
}
}
@@ -824,7 +857,8 @@
case CMD_START_TETHERING_ERROR:
case CMD_STOP_TETHERING_ERROR:
case CMD_SET_DNS_FORWARDERS_ERROR:
- transitionTo(mMasterTetherErrorState);
+ setLastErrorAndTransitionToInitialState(
+ ConnectivityManager.TETHER_ERROR_MASTER_ERROR);
break;
case CMD_INTERFACE_DOWN:
m = mTetherMasterSM.obtainMessage(
@@ -833,7 +867,7 @@
mTetherMasterSM.sendMessage(m);
transitionTo(mUnavailableState);
break;
- case CMD_TRANSITION_TO_ERROR:
+ case CMD_TRANSITION_TO_STATE:
HierarchicalState s = (HierarchicalState)(message.obj);
transitionTo(s);
break;
@@ -853,16 +887,24 @@
try {
service.tetherInterface(mIfaceName);
} catch (Exception e) {
- Message m = obtainMessage(CMD_TRANSITION_TO_ERROR);
- m.obj = mTetherInterfaceErrorState;
+ setLastError(ConnectivityManager.TETHER_ERROR_TETHER_IFACE_ERROR);
+
+ Message m = obtainMessage(CMD_TRANSITION_TO_STATE);
+ m.obj = mInitialState;
sendMessageAtFrontOfQueue(m);
return;
}
try {
service.enableNat(mIfaceName, mUpstreamIfaceName);
} catch (Exception e) {
- Message m = obtainMessage(CMD_TRANSITION_TO_ERROR);
- m.obj = mEnableNatErrorState;
+ try {
+ service.untetherInterface(mIfaceName);
+ } catch (Exception ee) {}
+
+ setLastError(ConnectivityManager.TETHER_ERROR_ENABLE_NAT_ERROR);
+
+ Message m = obtainMessage(CMD_TRANSITION_TO_STATE);
+ m.obj = mInitialState;
sendMessageAtFrontOfQueue(m);
return;
}
@@ -890,13 +932,19 @@
try {
service.disableNat(mIfaceName, mUpstreamIfaceName);
} catch (Exception e) {
- transitionTo(mDisableNatErrorState);
+ try {
+ service.untetherInterface(mIfaceName);
+ } catch (Exception ee) {}
+
+ setLastErrorAndTransitionToInitialState(
+ ConnectivityManager.TETHER_ERROR_DISABLE_NAT_ERROR);
break;
}
try {
service.untetherInterface(mIfaceName);
} catch (Exception e) {
- transitionTo(mUntetherInterfaceErrorState);
+ setLastErrorAndTransitionToInitialState(
+ ConnectivityManager.TETHER_ERROR_UNTETHER_IFACE_ERROR);
break;
}
Message m = mTetherMasterSM.obtainMessage(
@@ -906,13 +954,11 @@
if (message.what == CMD_TETHER_UNREQUESTED) {
if (mUsb) {
if (!Tethering.this.configureUsbIface(false)) {
- transitionTo(mUsbConfigurationErrorState);
- } else {
- transitionTo(mInitialState);
+ setLastError(
+ ConnectivityManager.TETHER_ERROR_IFACE_CFG_ERROR);
}
- } else {
- transitionTo(mInitialState);
}
+ transitionTo(mInitialState);
} else if (message.what == CMD_INTERFACE_DOWN) {
transitionTo(mUnavailableState);
}
@@ -932,30 +978,36 @@
try {
service.disableNat(mIfaceName, mUpstreamIfaceName);
} catch (Exception e) {
- transitionTo(mDisableNatErrorState);
+ try {
+ service.untetherInterface(mIfaceName);
+ } catch (Exception ee) {}
+
+ setLastErrorAndTransitionToInitialState(
+ ConnectivityManager.TETHER_ERROR_DISABLE_NAT_ERROR);
break;
}
try {
service.untetherInterface(mIfaceName);
} catch (Exception e) {
- transitionTo(mUntetherInterfaceErrorState);
+ setLastErrorAndTransitionToInitialState(
+ ConnectivityManager.TETHER_ERROR_UNTETHER_IFACE_ERROR);
break;
}
if (error) {
- transitionTo(mMasterTetherErrorState);
+ setLastErrorAndTransitionToInitialState(
+ ConnectivityManager.TETHER_ERROR_MASTER_ERROR);
break;
}
Log.d(TAG, "Tether lost upstream connection " + mIfaceName);
sendTetherStateChangedBroadcast();
if (mUsb) {
if (!Tethering.this.configureUsbIface(false)) {
- transitionTo(mUsbConfigurationErrorState);
- break;
+ setLastError(ConnectivityManager.TETHER_ERROR_IFACE_CFG_ERROR);
}
}
transitionTo(mInitialState);
break;
- case CMD_TRANSITION_TO_ERROR:
+ case CMD_TRANSITION_TO_STATE:
HierarchicalState s = (HierarchicalState)(message.obj);
transitionTo(s);
break;
@@ -971,7 +1023,7 @@
@Override
public void enter() {
setAvailable(false);
- setErrored(false);
+ setLastError(ConnectivityManager.TETHER_ERROR_NO_ERROR);
setTethered(false);
sendTetherStateChangedBroadcast();
}
@@ -990,95 +1042,11 @@
}
}
-
- class ErrorState extends HierarchicalState {
- int mErrorNotification;
- @Override
- public boolean processMessage(Message message) {
- boolean retValue = true;
- switch (message.what) {
- case CMD_TETHER_REQUESTED:
- sendTetherStateChangedBroadcast();
- break;
- default:
- retValue = false;
- break;
- }
- return retValue;
- }
+ void setLastErrorAndTransitionToInitialState(int error) {
+ setLastError(error);
+ transitionTo(mInitialState);
}
- class MasterTetherErrorState extends ErrorState {
- @Override
- public void enter() {
- Log.e(TAG, "Error in Master Tether state " + mIfaceName);
- setAvailable(false);
- setErrored(true);
- sendTetherStateChangedBroadcast();
- }
- }
-
- class TetherInterfaceErrorState extends ErrorState {
- @Override
- public void enter() {
- Log.e(TAG, "Error trying to tether " + mIfaceName);
- setAvailable(false);
- setErrored(true);
- sendTetherStateChangedBroadcast();
- }
- }
-
- class UntetherInterfaceErrorState extends ErrorState {
- @Override
- public void enter() {
- Log.e(TAG, "Error trying to untether " + mIfaceName);
- setAvailable(false);
- setErrored(true);
- sendTetherStateChangedBroadcast();
- }
- }
-
- class EnableNatErrorState extends ErrorState {
- @Override
- public void enter() {
- Log.e(TAG, "Error trying to enable NAT " + mIfaceName);
- setAvailable(false);
- setErrored(true);
-
- IBinder b = ServiceManager.getService(Context.NETWORKMANAGEMENT_SERVICE);
- INetworkManagementService service = INetworkManagementService.Stub.asInterface(b);
- try {
- service.untetherInterface(mIfaceName);
- } catch (Exception e) {}
- sendTetherStateChangedBroadcast();
- }
- }
-
-
- class DisableNatErrorState extends ErrorState {
- @Override
- public void enter() {
- Log.e(TAG, "Error trying to disable NAT " + mIfaceName);
- setAvailable(false);
- setErrored(true);
-
- IBinder b = ServiceManager.getService(Context.NETWORKMANAGEMENT_SERVICE);
- INetworkManagementService service = INetworkManagementService.Stub.asInterface(b);
- try {
- service.untetherInterface(mIfaceName);
- } catch (Exception e) {}
- sendTetherStateChangedBroadcast();
- }
- }
-
- class UsbConfigurationErrorState extends ErrorState {
- @Override
- public void enter() {
- Log.e(TAG, "Error trying to configure USB " + mIfaceName);
- setAvailable(false);
- setErrored(true);
- }
- }
}
class TetherMasterSM extends HierarchicalStateMachine {
diff --git a/telephony/java/com/android/internal/telephony/DataConnection.java b/telephony/java/com/android/internal/telephony/DataConnection.java
index 562a9f8..521072e 100644
--- a/telephony/java/com/android/internal/telephony/DataConnection.java
+++ b/telephony/java/com/android/internal/telephony/DataConnection.java
@@ -51,7 +51,7 @@
*
* DataConnection {
* + mDefaultState {
- * EVENT_RESET { clearSettings, >mInactiveState }.
+ * EVENT_RESET { clearSettings, notifiyDisconnectCompleted, >mInactiveState }.
* EVENT_CONNECT { notifyConnectCompleted(FailCause.UNKNOWN) }.
* EVENT_DISCONNECT { notifyDisconnectCompleted }.
*
@@ -60,8 +60,10 @@
* EVENT_GET_LAST_FAIL_DONE,
* EVENT_DEACTIVATE_DONE.
* }
- * ++ # mInactiveState {
- * EVENT_RESET.
+ * ++ # mInactiveState
+ * e(doNotifications)
+ * x(clearNotifications) {
+ * EVENT_RESET { notifiyDisconnectCompleted }.
* EVENT_CONNECT {startConnecting, >mActivatingState }.
* }
* ++ mActivatingState {
@@ -338,6 +340,8 @@
if (DBG) log("NotifyDisconnectCompleted");
Message msg = dp.onCompletedMsg;
+ log(String.format("msg.what=%d msg.obj=%s",
+ msg.what, ((msg.obj instanceof String) ? (String) msg.obj : "<no-reason>")));
AsyncResult.forMessage(msg);
msg.sendToTarget();
@@ -437,6 +441,9 @@
case EVENT_RESET:
if (DBG) log("DcDefaultState: msg.what=EVENT_RESET");
clearSettings();
+ if (msg.obj != null) {
+ notifyDisconnectCompleted((DisconnectParams) msg.obj);
+ }
transitionTo(mInactiveState);
break;
@@ -467,9 +474,48 @@
* The state machine is inactive and expects a EVENT_CONNECT.
*/
private class DcInactiveState extends HierarchicalState {
+ private ConnectionParams mConnectionParams = null;
+ private FailCause mFailCause = null;
+ private DisconnectParams mDisconnectParams = null;
+
+ public void setEnterNotificationParams(ConnectionParams cp, FailCause cause) {
+ log("DcInactiveState: setEnterNoticationParams cp,cause");
+ mConnectionParams = cp;
+ mFailCause = cause;
+ }
+
+ public void setEnterNotificationParams(DisconnectParams dp) {
+ log("DcInactiveState: setEnterNoticationParams dp");
+ mDisconnectParams = dp;
+ }
+
@Override protected void enter() {
mTag += 1;
+
+ /**
+ * Now that we've transitioned to Inactive state we
+ * can send notifications. Previously we sent the
+ * notifications in the processMessage handler but
+ * that caused a race condition because the synchronous
+ * call to isInactive.
+ */
+ if ((mConnectionParams != null) && (mFailCause != null)) {
+ log("DcInactiveState: enter notifyConnectCompleted");
+ notifyConnectCompleted(mConnectionParams, mFailCause);
+ }
+ if (mDisconnectParams != null) {
+ log("DcInactiveState: enter notifyDisconnectCompleted");
+ notifyDisconnectCompleted(mDisconnectParams);
+ }
}
+
+ @Override protected void exit() {
+ // clear notifications
+ mConnectionParams = null;
+ mFailCause = null;
+ mDisconnectParams = null;
+ }
+
@Override protected boolean processMessage(Message msg) {
boolean retVal;
@@ -478,6 +524,9 @@
if (DBG) {
log("DcInactiveState: msg.what=EVENT_RESET, ignore we're already reset");
}
+ if (msg.obj != null) {
+ notifyDisconnectCompleted((DisconnectParams) msg.obj);
+ }
retVal = true;
break;
@@ -526,12 +575,14 @@
switch (result) {
case SUCCESS:
// All is well
- notifyConnectCompleted(cp, FailCause.NONE);
+ mActiveState.setEnterNotificationParams(cp, FailCause.NONE);
transitionTo(mActiveState);
break;
case ERR_BadCommand:
// Vendor ril rejected the command and didn't connect.
- notifyConnectCompleted(cp, result.mFailCause);
+ // Transition to inactive but send notifications after
+ // we've entered the mInactive state.
+ mInactiveState.setEnterNotificationParams(cp, result.mFailCause);
transitionTo(mInactiveState);
break;
case ERR_BadDns:
@@ -565,7 +616,9 @@
int rilFailCause = ((int[]) (ar.result))[0];
cause = getFailCauseFromRequest(rilFailCause);
}
- notifyConnectCompleted(cp, cause);
+ // Transition to inactive but send notifications after
+ // we've entered the mInactive state.
+ mInactiveState.setEnterNotificationParams(cp, cause);
transitionTo(mInactiveState);
} else {
if (DBG) {
@@ -591,6 +644,35 @@
* The state machine is connected, expecting an EVENT_DISCONNECT.
*/
private class DcActiveState extends HierarchicalState {
+ private ConnectionParams mConnectionParams = null;
+ private FailCause mFailCause = null;
+
+ public void setEnterNotificationParams(ConnectionParams cp, FailCause cause) {
+ log("DcInactiveState: setEnterNoticationParams cp,cause");
+ mConnectionParams = cp;
+ mFailCause = cause;
+ }
+
+ @Override public void enter() {
+ /**
+ * Now that we've transitioned to Active state we
+ * can send notifications. Previously we sent the
+ * notifications in the processMessage handler but
+ * that caused a race condition because the synchronous
+ * call to isActive.
+ */
+ if ((mConnectionParams != null) && (mFailCause != null)) {
+ log("DcActiveState: enter notifyConnectCompleted");
+ notifyConnectCompleted(mConnectionParams, mFailCause);
+ }
+ }
+
+ @Override protected void exit() {
+ // clear notifications
+ mConnectionParams = null;
+ mFailCause = null;
+ }
+
@Override protected boolean processMessage(Message msg) {
boolean retVal;
@@ -627,7 +709,9 @@
AsyncResult ar = (AsyncResult) msg.obj;
DisconnectParams dp = (DisconnectParams) ar.userObj;
if (dp.tag == mTag) {
- notifyDisconnectCompleted((DisconnectParams) ar.userObj);
+ // Transition to inactive but send notifications after
+ // we've entered the mInactive state.
+ mInactiveState.setEnterNotificationParams((DisconnectParams) ar.userObj);
transitionTo(mInactiveState);
} else {
if (DBG) log("DcDisconnectState EVENT_DEACTIVATE_DONE stale dp.tag="
@@ -660,7 +744,9 @@
ConnectionParams cp = (ConnectionParams) ar.userObj;
if (cp.tag == mTag) {
if (DBG) log("DcDisconnectingBadDnsState msg.what=EVENT_DEACTIVATE_DONE");
- notifyConnectCompleted(cp, FailCause.UNKNOWN);
+ // Transition to inactive but send notifications after
+ // we've entered the mInactive state.
+ mInactiveState.setEnterNotificationParams(cp, FailCause.UNKNOWN);
transitionTo(mInactiveState);
} else {
if (DBG) log("DcDisconnectingBadDnsState EVENT_DEACTIVE_DONE stale dp.tag="
@@ -683,9 +769,12 @@
/**
* Disconnect from the network.
+ *
+ * @param onCompletedMsg is sent with its msg.obj as an AsyncResult object.
+ * With AsyncResult.userObj set to the original msg.obj.
*/
- public void reset() {
- sendMessage(obtainMessage(EVENT_RESET));
+ public void reset(Message onCompletedMsg) {
+ sendMessage(obtainMessage(EVENT_RESET, new DisconnectParams(onCompletedMsg)));
}
/**
@@ -726,6 +815,9 @@
// ****** The following are used for debugging.
/**
+ * TODO: This should be an asynchronous call and we wouldn't
+ * have to use handle the notification in the DcInactiveState.enter.
+ *
* @return true if the state machine is in the inactive state.
*/
public boolean isInactive() {
@@ -734,7 +826,10 @@
}
/**
- * @return true if the state machine is in the inactive state.
+ * TODO: This should be an asynchronous call and we wouldn't
+ * have to use handle the notification in the DcActiveState.enter.
+ *
+ * @return true if the state machine is in the active state.
*/
public boolean isActive() {
boolean retVal = getCurrentState() == mActiveState;
diff --git a/telephony/java/com/android/internal/telephony/DataConnectionTracker.java b/telephony/java/com/android/internal/telephony/DataConnectionTracker.java
index cab7b81..e8e18a1 100644
--- a/telephony/java/com/android/internal/telephony/DataConnectionTracker.java
+++ b/telephony/java/com/android/internal/telephony/DataConnectionTracker.java
@@ -101,6 +101,7 @@
protected static final int EVENT_CDMA_OTA_PROVISION = 35;
protected static final int EVENT_RESTART_RADIO = 36;
protected static final int EVENT_SET_MASTER_DATA_ENABLE = 37;
+ protected static final int EVENT_RESET_DONE = 38;
/***** Constants *****/
@@ -265,6 +266,7 @@
protected abstract void onRadioOffOrNotAvailable();
protected abstract void onDataSetupComplete(AsyncResult ar);
protected abstract void onDisconnectDone(AsyncResult ar);
+ protected abstract void onResetDone(AsyncResult ar);
protected abstract void onVoiceCallStarted();
protected abstract void onVoiceCallEnded();
protected abstract void onCleanUpConnection(boolean tearDown, String reason);
@@ -331,6 +333,10 @@
onSetDataEnabled(enabled);
break;
+ case EVENT_RESET_DONE:
+ onResetDone((AsyncResult) msg.obj);
+ break;
+
default:
Log.e("DATA", "Unidentified event = " + msg.what);
break;
diff --git a/telephony/java/com/android/internal/telephony/cdma/CdmaDataConnectionTracker.java b/telephony/java/com/android/internal/telephony/cdma/CdmaDataConnectionTracker.java
index b5461bf..9218715 100644
--- a/telephony/java/com/android/internal/telephony/cdma/CdmaDataConnectionTracker.java
+++ b/telephony/java/com/android/internal/telephony/cdma/CdmaDataConnectionTracker.java
@@ -368,7 +368,7 @@
* @param reason reason for the clean up.
*/
private void cleanUpConnection(boolean tearDown, String reason) {
- if (DBG) log("Clean up connection due to " + reason);
+ if (DBG) log("cleanUpConnection: reason: " + reason);
// Clear the reconnect alarm, if set.
if (mReconnectIntent != null) {
@@ -380,25 +380,25 @@
setState(State.DISCONNECTING);
- for (DataConnection connBase : dataConnectionList) {
- CdmaDataConnection conn = (CdmaDataConnection) connBase;
-
+ boolean notificationDeferred = false;
+ for (DataConnection conn : dataConnectionList) {
if(conn != null) {
if (tearDown) {
- Message msg = obtainMessage(EVENT_DISCONNECT_DONE, reason);
- conn.disconnect(msg);
+ if (DBG) log("cleanUpConnection: teardown, call conn.disconnect");
+ conn.disconnect(obtainMessage(EVENT_DISCONNECT_DONE, reason));
} else {
- conn.reset();
+ if (DBG) log("cleanUpConnection: !tearDown, call conn.reset");
+ conn.reset(obtainMessage(EVENT_RESET_DONE, reason));
}
+ notificationDeferred = true;
}
}
stopNetStatPoll();
- if (!tearDown) {
- setState(State.IDLE);
- phone.notifyDataConnection(reason);
- mIsApnActive = false;
+ if (!notificationDeferred) {
+ if (DBG) log("cleanupConnection: !tearDown && !resettingConn");
+ gotoIdleAndNotifyDataConnection(reason);
}
}
@@ -622,6 +622,13 @@
setState(State.FAILED);
}
+ private void gotoIdleAndNotifyDataConnection(String reason) {
+ if (DBG) log("gotoIdleAndNotifyDataConnection: reason=" + reason);
+ setState(State.IDLE);
+ phone.notifyDataConnection(reason);
+ mIsApnActive = false;
+ }
+
protected void onRecordsLoaded() {
if (state == State.FAILED) {
cleanUpConnection(false, null);
@@ -731,7 +738,7 @@
}
/**
- * @override com.android.internal.telephony.DataConnectionTracker
+ * Called when EVENT_DISCONNECT_DONE is received.
*/
protected void onDisconnectDone(AsyncResult ar) {
if(DBG) log("EVENT_DISCONNECT_DONE");
@@ -762,6 +769,20 @@
}
/**
+ * Called when EVENT_RESET_DONE is received so goto
+ * IDLE state and send notifications to those interested.
+ */
+ @Override
+ protected void onResetDone(AsyncResult ar) {
+ if (DBG) log("EVENT_RESET_DONE");
+ String reason = null;
+ if (ar.userObj instanceof String) {
+ reason = (String) ar.userObj;
+ }
+ gotoIdleAndNotifyDataConnection(reason);
+ }
+
+ /**
* @override com.android.internal.telephony.DataConnectionTracker
*/
protected void onVoiceCallStarted() {
diff --git a/telephony/java/com/android/internal/telephony/gsm/GsmDataConnectionTracker.java b/telephony/java/com/android/internal/telephony/gsm/GsmDataConnectionTracker.java
index 30beaaa..f26e54e 100644
--- a/telephony/java/com/android/internal/telephony/gsm/GsmDataConnectionTracker.java
+++ b/telephony/java/com/android/internal/telephony/gsm/GsmDataConnectionTracker.java
@@ -502,20 +502,22 @@
setState(State.DISCONNECTING);
+ boolean notificationDeferred = false;
for (DataConnection conn : pdpList) {
if (tearDown) {
- Message msg = obtainMessage(EVENT_DISCONNECT_DONE, reason);
- conn.disconnect(msg);
+ if (DBG) log("cleanUpConnection: teardown, call conn.disconnect");
+ conn.disconnect(obtainMessage(EVENT_DISCONNECT_DONE, reason));
} else {
- conn.reset();
+ if (DBG) log("cleanUpConnection: !tearDown, call conn.reset");
+ conn.reset(obtainMessage(EVENT_RESET_DONE, reason));
}
+ notificationDeferred = true;
}
stopNetStatPoll();
- if (!tearDown) {
- setState(State.IDLE);
- phone.notifyDataConnection(reason);
- mActiveApn = null;
+ if (!notificationDeferred) {
+ if (DBG) log("cleanupConnection: !tearDown && !resettingConn");
+ gotoIdleAndNotifyDataConnection(reason);
}
}
@@ -749,6 +751,13 @@
mReregisterOnReconnectFailure = false;
}
+ private void gotoIdleAndNotifyDataConnection(String reason) {
+ if (DBG) log("gotoIdleAndNotifyDataConnection: reason=" + reason);
+ setState(State.IDLE);
+ phone.notifyDataConnection(reason);
+ mActiveApn = null;
+ }
+
/**
* This is a kludge to deal with the fact that
* the PDP state change notification doesn't always work
@@ -1172,6 +1181,9 @@
}
}
+ /**
+ * Called when EVENT_DISCONNECT_DONE is received.
+ */
protected void onDisconnectDone(AsyncResult ar) {
String reason = null;
if(DBG) log("EVENT_DISCONNECT_DONE");
@@ -1186,6 +1198,19 @@
}
}
+ /**
+ * Called when EVENT_RESET_DONE is received.
+ */
+ @Override
+ protected void onResetDone(AsyncResult ar) {
+ if (DBG) log("EVENT_RESET_DONE");
+ String reason = null;
+ if (ar.userObj instanceof String) {
+ reason = (String) ar.userObj;
+ }
+ gotoIdleAndNotifyDataConnection(reason);
+ }
+
protected void onPollPdp() {
if (state == State.CONNECTED) {
// only poll when connected
@@ -1487,5 +1512,4 @@
protected void log(String s) {
Log.d(LOG_TAG, "[GsmDataConnectionTracker] " + s);
}
-
}
diff --git a/tests/AndroidTests/src/com/android/unit_tests/PackageManagerTests.java b/tests/AndroidTests/src/com/android/unit_tests/PackageManagerTests.java
index 5e3895a..50eca02 100755
--- a/tests/AndroidTests/src/com/android/unit_tests/PackageManagerTests.java
+++ b/tests/AndroidTests/src/com/android/unit_tests/PackageManagerTests.java
@@ -263,6 +263,9 @@
if (expInstallLocation == PackageInfo.INSTALL_LOCATION_PREFER_EXTERNAL) {
return true;
}
+ if (expInstallLocation == PackageInfo.INSTALL_LOCATION_INTERNAL_ONLY) {
+ return false;
+ }
// TODO Out of memory checks here.
boolean checkSd = false;
int setLoc = 0;
@@ -403,7 +406,7 @@
return ip;
} finally {
if (cleanUp) {
- //cleanUpInstall(ip);
+ cleanUpInstall(ip);
}
}
}
@@ -931,9 +934,9 @@
public void testManifestInstallLocationFwdLockedSdcard() {
installFromRawResource("install.apk", R.raw.install_loc_sdcard,
- PackageManager.INSTALL_FORWARD_LOCK, true, true,
- PackageManager.INSTALL_FAILED_INVALID_INSTALL_LOCATION,
- PackageInfo.INSTALL_LOCATION_AUTO);
+ PackageManager.INSTALL_FORWARD_LOCK, true, false,
+ -1,
+ PackageInfo.INSTALL_LOCATION_INTERNAL_ONLY);
}
public void xxxtestClearAllSecureContainers() {
@@ -1050,6 +1053,21 @@
}
}
+ private int getInstallLoc() {
+ boolean userSetting = false;
+ int origDefaultLoc = PackageInfo.INSTALL_LOCATION_AUTO;
+ try {
+ userSetting = Settings.System.getInt(mContext.getContentResolver(), Settings.System.SET_INSTALL_LOCATION) != 0;
+ origDefaultLoc = Settings.System.getInt(mContext.getContentResolver(), Settings.System.DEFAULT_INSTALL_LOCATION);
+ } catch (SettingNotFoundException e1) {
+ }
+ return origDefaultLoc;
+ }
+
+ private void setInstallLoc(int loc) {
+ Settings.System.putInt(mContext.getContentResolver(),
+ Settings.System.DEFAULT_INSTALL_LOCATION, loc);
+ }
/*
* Utility function that reads a apk bundled as a raw resource
* copies it into own data directory and invokes
@@ -1058,6 +1076,8 @@
*/
public void moveFromRawResource(int installFlags, int moveFlags,
int expRetCode) {
+ int origDefaultLoc = getInstallLoc();
+ setInstallLoc(PackageInfo.INSTALL_LOCATION_AUTO);
// Install first
InstallParams ip = sampleInstallFromRawResource(installFlags, false);
ApplicationInfo oldAppInfo = null;
@@ -1091,6 +1111,8 @@
failStr("Failed with exception : " + e);
} finally {
cleanUpInstall(ip);
+ // Restore default install location
+ setInstallLoc(origDefaultLoc);
}
}
diff --git a/tools/aapt/Resource.cpp b/tools/aapt/Resource.cpp
index 9fcb21c..ea021d8 100644
--- a/tools/aapt/Resource.cpp
+++ b/tools/aapt/Resource.cpp
@@ -637,6 +637,7 @@
sp<XMLNode> application = root->getChildElement(String16(), String16("application"));
if (application != NULL) {
fullyQualifyClassName(origPackage, application, String16("name"));
+ fullyQualifyClassName(origPackage, application, String16("backupAgent"));
Vector<sp<XMLNode> >& children = const_cast<Vector<sp<XMLNode> >&>(application->getChildren());
for (size_t i = 0; i < children.size(); i++) {
@@ -1778,6 +1779,40 @@
rules.editValueAt(index).add(where);
}
+void
+addProguardKeepRule(ProguardKeepSet* keep, const String8& inClassName,
+ const char* pkg, const String8& srcName, int line)
+{
+ String8 className(inClassName);
+ if (pkg != NULL) {
+ // asdf --> package.asdf
+ // .asdf .a.b --> package.asdf package.a.b
+ // asdf.adsf --> asdf.asdf
+ const char* p = className.string();
+ const char* q = strchr(p, '.');
+ if (p == q) {
+ className = pkg;
+ className.append(inClassName);
+ } else if (q == NULL) {
+ className = pkg;
+ className.append(".");
+ className.append(inClassName);
+ }
+ }
+
+ String8 rule("-keep class ");
+ rule += className;
+ rule += " { <init>(...); }";
+
+ String8 location("view ");
+ location += srcName;
+ char lineno[20];
+ sprintf(lineno, ":%d", line);
+ location += lineno;
+
+ keep->add(rule, location);
+}
+
status_t
writeProguardForAndroidManifest(ProguardKeepSet* keep, const sp<AaptAssets>& assets)
{
@@ -1839,6 +1874,13 @@
if (tag == "application") {
inApplication = true;
keepTag = true;
+
+ String8 agent = getAttribute(tree, "http://schemas.android.com/apk/res/android",
+ "backupAgent", &error);
+ if (agent.length() > 0) {
+ addProguardKeepRule(keep, agent, pkg.string(),
+ assFile->getPrintableSource(), tree.getLineNumber());
+ }
} else if (tag == "instrumentation") {
keepTag = true;
}
@@ -1856,31 +1898,8 @@
return -1;
}
if (name.length() > 0) {
- // asdf --> package.asdf
- // .asdf .a.b --> package.asdf package.a.b
- // asdf.adsf --> asdf.asdf
- String8 rule("-keep class ");
- const char* p = name.string();
- const char* q = strchr(p, '.');
- if (p == q) {
- rule += pkg;
- rule += name;
- } else if (q == NULL) {
- rule += pkg;
- rule += ".";
- rule += name;
- } else {
- rule += name;
- }
-
- String8 location = tag;
- location += " ";
- location += assFile->getSourceFile();
- char lineno[20];
- sprintf(lineno, ":%d", tree.getLineNumber());
- location += lineno;
-
- keep->add(rule, location);
+ addProguardKeepRule(keep, name, pkg.string(),
+ assFile->getPrintableSource(), tree.getLineNumber());
}
}
}
@@ -1888,23 +1907,6 @@
return NO_ERROR;
}
-void
-addProguardKeepRule(ProguardKeepSet* keep, const String8& className,
- const String8& srcName, int line)
-{
- String8 rule("-keep class ");
- rule += className;
- rule += " { <init>(...); }";
-
- String8 location("view ");
- location += srcName;
- char lineno[20];
- sprintf(lineno, ":%d", line);
- location += lineno;
-
- keep->add(rule, location);
-}
-
status_t
writeProguardForXml(ProguardKeepSet* keep, const sp<AaptFile>& layoutFile,
const char* startTag, const char* altTag)
@@ -1946,7 +1948,7 @@
// If there is no '.', we'll assume that it's one of the built in names.
if (strchr(tag.string(), '.')) {
- addProguardKeepRule(keep, tag,
+ addProguardKeepRule(keep, tag, NULL,
layoutFile->getPrintableSource(), tree.getLineNumber());
} else if (altTag != NULL && tag == altTag) {
ssize_t classIndex = tree.indexOfAttribute(NULL, "class");
@@ -1956,7 +1958,7 @@
} else {
size_t len;
addProguardKeepRule(keep,
- String8(tree.getAttributeStringValue(classIndex, &len)),
+ String8(tree.getAttributeStringValue(classIndex, &len)), NULL,
layoutFile->getPrintableSource(), tree.getLineNumber());
}
}