Merge "InputDevice filtering for jumpy screens. Updated ScaleGestureDetector for framework deprecations."
diff --git a/api/current.xml b/api/current.xml
index 1f7be9e..eae20e7 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"
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/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/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/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/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/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/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/PackageManagerService.java b/services/java/com/android/server/PackageManagerService.java
index b41a7d9..664f028 100644
--- a/services/java/com/android/server/PackageManagerService.java
+++ b/services/java/com/android/server/PackageManagerService.java
@@ -2372,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) {
@@ -2645,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;
}
@@ -2727,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
@@ -2755,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);
}
}
}
@@ -5479,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)) {
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 {