diff options
| -rw-r--r-- | api/8.xml | 22 | ||||
| -rw-r--r-- | api/current.xml | 33 | ||||
| -rw-r--r-- | cmds/am/src/com/android/commands/am/Am.java | 64 | ||||
| -rw-r--r-- | core/java/android/app/ActivityManagerNative.java | 47 | ||||
| -rw-r--r-- | core/java/android/app/IActivityManager.java | 48 | ||||
| -rw-r--r-- | core/java/android/content/pm/PackageManager.java | 13 | ||||
| -rw-r--r-- | core/java/android/net/MobileDataStateTracker.java | 9 | ||||
| -rw-r--r-- | core/java/android/pim/EventRecurrence.java | 63 | ||||
| -rw-r--r-- | core/java/android/speech/RecognizerIntent.java | 9 | ||||
| -rw-r--r-- | core/res/res/values/strings.xml | 11 | ||||
| -rw-r--r-- | services/java/com/android/server/PackageManagerService.java | 32 | ||||
| -rw-r--r-- | services/java/com/android/server/am/ActivityManagerService.java | 106 | ||||
| -rw-r--r-- | services/java/com/android/server/am/HistoryRecord.java | 2 | ||||
| -rw-r--r-- | services/java/com/android/server/connectivity/Tethering.java | 35 |
14 files changed, 302 insertions, 192 deletions
diff --git a/api/8.xml b/api/8.xml index a07537cef744..c5e899dfcffc 100644 --- a/api/8.xml +++ b/api/8.xml @@ -42346,28 +42346,6 @@ visibility="public" > </field> -<field name="PKG_INSTALL_COMPLETE" - type="int" - transient="false" - volatile="false" - value="1" - static="true" - final="true" - deprecated="not deprecated" - visibility="public" -> -</field> -<field name="PKG_INSTALL_INCOMPLETE" - type="int" - transient="false" - volatile="false" - value="0" - static="true" - final="true" - deprecated="not deprecated" - visibility="public" -> -</field> <field name="SIGNATURE_FIRST_NOT_SIGNED" type="int" transient="false" diff --git a/api/current.xml b/api/current.xml index 815b9ff2a224..ad1df1abca1b 100644 --- a/api/current.xml +++ b/api/current.xml @@ -45440,28 +45440,6 @@ visibility="public" > </field> -<field name="PKG_INSTALL_COMPLETE" - type="int" - transient="false" - volatile="false" - value="1" - static="true" - final="true" - deprecated="not deprecated" - visibility="public" -> -</field> -<field name="PKG_INSTALL_INCOMPLETE" - type="int" - transient="false" - volatile="false" - value="0" - static="true" - final="true" - deprecated="not deprecated" - visibility="public" -> -</field> <field name="SIGNATURE_FIRST_NOT_SIGNED" type="int" transient="false" @@ -138443,6 +138421,17 @@ visibility="public" > </field> +<field name="EXTRA_ONLY_RETURN_LANGUAGE_PREFERENCE" + type="java.lang.String" + transient="false" + volatile="false" + value=""android.speech.extra.ONLY_RETURN_LANGUAGE_PREFERENCE"" + static="true" + final="true" + deprecated="not deprecated" + visibility="public" +> +</field> <field name="EXTRA_PARTIAL_RESULTS" type="java.lang.String" transient="false" diff --git a/cmds/am/src/com/android/commands/am/Am.java b/cmds/am/src/com/android/commands/am/Am.java index b6c9de41101f..5d6970ac3fc2 100644 --- a/cmds/am/src/com/android/commands/am/Am.java +++ b/cmds/am/src/com/android/commands/am/Am.java @@ -35,6 +35,7 @@ import android.view.IWindowManager; import java.io.File; import java.io.FileNotFoundException; +import java.io.PrintStream; import java.net.URISyntaxException; import java.util.Iterator; import java.util.Set; @@ -47,6 +48,7 @@ public class Am { private String mCurArgData; private boolean mDebugOption = false; + private boolean mWaitOption = false; // These are magic strings understood by the Eclipse plugin. private static final String FATAL_ERROR_CODE = "Error type 1"; @@ -106,6 +108,7 @@ public class Am { boolean hasIntentInfo = false; mDebugOption = false; + mWaitOption = false; Uri data = null; String type = null; @@ -153,6 +156,8 @@ public class Am { intent.setFlags(Integer.decode(str).intValue()); } else if (opt.equals("-D")) { mDebugOption = true; + } else if (opt.equals("-W")) { + mWaitOption = true; } else { System.err.println("Error: Unknown option: " + opt); showUsage(); @@ -199,58 +204,90 @@ public class Am { System.out.println("Starting: " + intent); intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); // XXX should do something to determine the MIME type. - int res = mAm.startActivity(null, intent, intent.getType(), - null, 0, null, null, 0, false, mDebugOption); + IActivityManager.WaitResult result = null; + int res; + if (mWaitOption) { + result = mAm.startActivityAndWait(null, intent, intent.getType(), + null, 0, null, null, 0, false, mDebugOption); + res = result.result; + } else { + res = mAm.startActivity(null, intent, intent.getType(), + null, 0, null, null, 0, false, mDebugOption); + } + PrintStream out = mWaitOption ? System.out : System.err; + boolean launched = false; switch (res) { case IActivityManager.START_SUCCESS: + launched = true; break; case IActivityManager.START_SWITCHES_CANCELED: - System.err.println( + launched = true; + out.println( "Warning: Activity not started because the " + " current activity is being kept for the user."); break; case IActivityManager.START_DELIVERED_TO_TOP: - System.err.println( + launched = true; + out.println( "Warning: Activity not started, intent has " + "been delivered to currently running " + "top-most instance."); break; case IActivityManager.START_RETURN_INTENT_TO_CALLER: - System.err.println( + launched = true; + out.println( "Warning: Activity not started because intent " + "should be handled by the caller"); break; case IActivityManager.START_TASK_TO_FRONT: - System.err.println( + launched = true; + out.println( "Warning: Activity not started, its current " + "task has been brought to the front"); break; case IActivityManager.START_INTENT_NOT_RESOLVED: - System.err.println( + out.println( "Error: Activity not started, unable to " + "resolve " + intent.toString()); break; case IActivityManager.START_CLASS_NOT_FOUND: - System.err.println(NO_CLASS_ERROR_CODE); - System.err.println("Error: Activity class " + + out.println(NO_CLASS_ERROR_CODE); + out.println("Error: Activity class " + intent.getComponent().toShortString() + " does not exist."); break; case IActivityManager.START_FORWARD_AND_REQUEST_CONFLICT: - System.err.println( + out.println( "Error: Activity not started, you requested to " + "both forward and receive its result"); break; case IActivityManager.START_PERMISSION_DENIED: - System.err.println( + out.println( "Error: Activity not started, you do not " + "have permission to access it."); break; default: - System.err.println( + out.println( "Error: Activity not started, unknown error code " + res); break; } + if (mWaitOption && launched) { + if (result == null) { + result = new IActivityManager.WaitResult(); + result.who = intent.getComponent(); + } + System.out.println("Status: " + (result.timeout ? "timeout" : "ok")); + if (result.who != null) { + System.out.println("Activity: " + result.who.flattenToShortString()); + } + if (result.thisTime >= 0) { + System.out.println("ThisTime: " + result.thisTime); + } + if (result.totalTime >= 0) { + System.out.println("TotalTime: " + result.totalTime); + } + System.out.println("Complete"); + } } private void sendBroadcast() throws Exception { @@ -504,8 +541,9 @@ public class Am { System.err.println( "usage: am [subcommand] [options]\n" + "\n" + - " start an Activity: am start [-D] <INTENT>\n" + + " start an Activity: am start [-D] [-W] <INTENT>\n" + " -D: enable debugging\n" + + " -W: wait for launch to complete\n" + "\n" + " start a Service: am startservice <INTENT>\n" + "\n" + diff --git a/core/java/android/app/ActivityManagerNative.java b/core/java/android/app/ActivityManagerNative.java index 2e39c10db744..6849fd766035 100644 --- a/core/java/android/app/ActivityManagerNative.java +++ b/core/java/android/app/ActivityManagerNative.java @@ -146,6 +146,28 @@ public abstract class ActivityManagerNative extends Binder implements IActivityM return true; } + case START_ACTIVITY_AND_WAIT_TRANSACTION: + { + data.enforceInterface(IActivityManager.descriptor); + IBinder b = data.readStrongBinder(); + IApplicationThread app = ApplicationThreadNative.asInterface(b); + Intent intent = Intent.CREATOR.createFromParcel(data); + String resolvedType = data.readString(); + Uri[] grantedUriPermissions = data.createTypedArray(Uri.CREATOR); + int grantedMode = data.readInt(); + IBinder resultTo = data.readStrongBinder(); + String resultWho = data.readString(); + int requestCode = data.readInt(); + boolean onlyIfNeeded = data.readInt() != 0; + boolean debug = data.readInt() != 0; + WaitResult result = startActivityAndWait(app, intent, resolvedType, + grantedUriPermissions, grantedMode, resultTo, resultWho, + requestCode, onlyIfNeeded, debug); + reply.writeNoException(); + result.writeToParcel(reply, 0); + return true; + } + case START_ACTIVITY_INTENT_SENDER_TRANSACTION: { data.enforceInterface(IActivityManager.descriptor); @@ -1238,6 +1260,31 @@ class ActivityManagerProxy implements IActivityManager data.recycle(); return result; } + public WaitResult startActivityAndWait(IApplicationThread caller, Intent intent, + String resolvedType, Uri[] grantedUriPermissions, int grantedMode, + IBinder resultTo, String resultWho, + int requestCode, boolean onlyIfNeeded, + boolean debug) throws RemoteException { + Parcel data = Parcel.obtain(); + Parcel reply = Parcel.obtain(); + data.writeInterfaceToken(IActivityManager.descriptor); + data.writeStrongBinder(caller != null ? caller.asBinder() : null); + intent.writeToParcel(data, 0); + data.writeString(resolvedType); + data.writeTypedArray(grantedUriPermissions, 0); + data.writeInt(grantedMode); + data.writeStrongBinder(resultTo); + data.writeString(resultWho); + data.writeInt(requestCode); + data.writeInt(onlyIfNeeded ? 1 : 0); + data.writeInt(debug ? 1 : 0); + mRemote.transact(START_ACTIVITY_AND_WAIT_TRANSACTION, data, reply, 0); + reply.readException(); + WaitResult result = WaitResult.CREATOR.createFromParcel(reply); + reply.recycle(); + data.recycle(); + return result; + } public int startActivityIntentSender(IApplicationThread caller, IntentSender intent, Intent fillInIntent, String resolvedType, IBinder resultTo, String resultWho, int requestCode, diff --git a/core/java/android/app/IActivityManager.java b/core/java/android/app/IActivityManager.java index 86f28bfa6cb3..3913ed5da0a2 100644 --- a/core/java/android/app/IActivityManager.java +++ b/core/java/android/app/IActivityManager.java @@ -84,6 +84,10 @@ public interface IActivityManager extends IInterface { Intent intent, String resolvedType, Uri[] grantedUriPermissions, int grantedMode, IBinder resultTo, String resultWho, int requestCode, boolean onlyIfNeeded, boolean debug) throws RemoteException; + public WaitResult startActivityAndWait(IApplicationThread caller, + Intent intent, String resolvedType, Uri[] grantedUriPermissions, + int grantedMode, IBinder resultTo, String resultWho, int requestCode, + boolean onlyIfNeeded, boolean debug) throws RemoteException; public int startActivityIntentSender(IApplicationThread caller, IntentSender intent, Intent fillInIntent, String resolvedType, IBinder resultTo, String resultWho, int requestCode, @@ -348,6 +352,49 @@ public interface IActivityManager extends IInterface { } }; + /** Information returned after waiting for an activity start. */ + public static class WaitResult implements Parcelable { + public int result; + public boolean timeout; + public ComponentName who; + public long thisTime; + public long totalTime; + + public WaitResult() { + } + + public int describeContents() { + return 0; + } + + public void writeToParcel(Parcel dest, int flags) { + dest.writeInt(result); + dest.writeInt(timeout ? 1 : 0); + ComponentName.writeToParcel(who, dest); + dest.writeLong(thisTime); + dest.writeLong(totalTime); + } + + public static final Parcelable.Creator<WaitResult> CREATOR + = new Parcelable.Creator<WaitResult>() { + public WaitResult createFromParcel(Parcel source) { + return new WaitResult(source); + } + + public WaitResult[] newArray(int size) { + return new WaitResult[size]; + } + }; + + private WaitResult(Parcel source) { + result = source.readInt(); + timeout = source.readInt() != 0; + who = ComponentName.readFromParcel(source); + thisTime = source.readLong(); + totalTime = source.readLong(); + } + }; + String descriptor = "android.app.IActivityManager"; // Please keep these transaction codes the same -- they are also @@ -453,4 +500,5 @@ public interface IActivityManager extends IInterface { int HANDLE_APPLICATION_WTF_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+101; int KILL_BACKGROUND_PROCESSES_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+102; int IS_USER_A_MONKEY_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+103; + int START_ACTIVITY_AND_WAIT_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+104; } diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java index 2edb430fa2f7..dc8f3864b736 100644 --- a/core/java/android/content/pm/PackageManager.java +++ b/core/java/android/content/pm/PackageManager.java @@ -530,19 +530,6 @@ public abstract class PackageManager { public static final int INSTALL_FAILED_INTERNAL_ERROR = -110; /** - * Indicates the state of installation. Used by PackageManager to - * figure out incomplete installations. Say a package is being installed - * (the state is set to PKG_INSTALL_INCOMPLETE) and remains so till - * the package installation is successful or unsuccesful lin which case - * the PackageManager will no longer maintain state information associated - * with the package. If some exception(like device freeze or battery being - * pulled out) occurs during installation of a package, the PackageManager - * needs this information to clean up the previously failed installation. - */ - public static final int PKG_INSTALL_INCOMPLETE = 0; - public static final int PKG_INSTALL_COMPLETE = 1; - - /** * Flag parameter for {@link #deletePackage} to indicate that you don't want to delete the * package's data directory. * diff --git a/core/java/android/net/MobileDataStateTracker.java b/core/java/android/net/MobileDataStateTracker.java index b2549615b70d..b59e2791e757 100644 --- a/core/java/android/net/MobileDataStateTracker.java +++ b/core/java/android/net/MobileDataStateTracker.java @@ -48,6 +48,7 @@ public class MobileDataStateTracker extends NetworkStateTracker { private ITelephony mPhoneService; private String mApnType; + private String mApnTypeToWatchFor; private String mApnName; private boolean mEnabled; private BroadcastReceiver mStateReceiver; @@ -65,6 +66,12 @@ public class MobileDataStateTracker extends NetworkStateTracker { TelephonyManager.getDefault().getNetworkType(), tag, TelephonyManager.getDefault().getNetworkTypeName()); mApnType = networkTypeToApnType(netType); + if (TextUtils.equals(mApnType, Phone.APN_TYPE_HIPRI)) { + mApnTypeToWatchFor = Phone.APN_TYPE_DEFAULT; + } else { + mApnTypeToWatchFor = mApnType; + } + mPhoneService = null; if(netType == ConnectivityManager.TYPE_MOBILE) { mEnabled = true; @@ -122,7 +129,7 @@ public class MobileDataStateTracker extends NetworkStateTracker { String[] list = typeList.split(","); for(int i=0; i< list.length; i++) { - if (TextUtils.equals(list[i], mApnType) || + if (TextUtils.equals(list[i], mApnTypeToWatchFor) || TextUtils.equals(list[i], Phone.APN_TYPE_ALL)) { return true; } diff --git a/core/java/android/pim/EventRecurrence.java b/core/java/android/pim/EventRecurrence.java index 3ea9b4a89bbc..56c4f7ad8a28 100644 --- a/core/java/android/pim/EventRecurrence.java +++ b/core/java/android/pim/EventRecurrence.java @@ -16,7 +16,6 @@ package android.pim; -import android.content.res.Resources; import android.text.TextUtils; import android.text.format.Time; @@ -325,55 +324,6 @@ public class EventRecurrence return s.toString(); } - public String getRepeatString() { - Resources r = Resources.getSystem(); - - // TODO Implement "Until" portion of string, as well as custom settings - switch (this.freq) { - case DAILY: - return r.getString(com.android.internal.R.string.daily); - case WEEKLY: { - if (repeatsOnEveryWeekDay()) { - return r.getString(com.android.internal.R.string.every_weekday); - } else { - String format = r.getString(com.android.internal.R.string.weekly); - StringBuilder days = new StringBuilder(); - - // Do one less iteration in the loop so the last element is added out of the - // loop. This is done so the comma is not placed after the last item. - int count = this.bydayCount - 1; - if (count >= 0) { - for (int i = 0 ; i < count ; i++) { - days.append(dayToString(r, this.byday[i])); - days.append(","); - } - days.append(dayToString(r, this.byday[count])); - - return String.format(format, days.toString()); - } - - // There is no "BYDAY" specifier, so use the day of the - // first event. For this to work, the setStartDate() - // method must have been used by the caller to set the - // date of the first event in the recurrence. - if (startDate == null) { - return null; - } - - int day = timeDay2Day(startDate.weekDay); - return String.format(format, dayToString(r, day)); - } - } - case MONTHLY: { - return r.getString(com.android.internal.R.string.monthly); - } - case YEARLY: - return r.getString(com.android.internal.R.string.yearly); - } - - return null; - } - public boolean repeatsOnEveryWeekDay() { if (this.freq != WEEKLY) { return false; @@ -405,17 +355,4 @@ public class EventRecurrence return true; } - - private String dayToString(Resources r, int day) { - switch (day) { - case SU: return r.getString(com.android.internal.R.string.day_of_week_long_sunday); - case MO: return r.getString(com.android.internal.R.string.day_of_week_long_monday); - case TU: return r.getString(com.android.internal.R.string.day_of_week_long_tuesday); - case WE: return r.getString(com.android.internal.R.string.day_of_week_long_wednesday); - case TH: return r.getString(com.android.internal.R.string.day_of_week_long_thursday); - case FR: return r.getString(com.android.internal.R.string.day_of_week_long_friday); - case SA: return r.getString(com.android.internal.R.string.day_of_week_long_saturday); - default: throw new IllegalArgumentException("bad day argument: " + day); - } - } } diff --git a/core/java/android/speech/RecognizerIntent.java b/core/java/android/speech/RecognizerIntent.java index bf411e1bce01..d55a9431d1d2 100644 --- a/core/java/android/speech/RecognizerIntent.java +++ b/core/java/android/speech/RecognizerIntent.java @@ -298,6 +298,15 @@ public class RecognizerIntent { "android.speech.action.GET_LANGUAGE_DETAILS"; /** + * Specify this boolean extra in a broadcast of {@link #ACTION_GET_LANGUAGE_DETAILS} to + * indicate that only the current language preference is needed in the response. This + * avoids any additional computation if all you need is {@link #EXTRA_LANGUAGE_PREFERENCE} + * in the response. + */ + public static final String EXTRA_ONLY_RETURN_LANGUAGE_PREFERENCE = + "android.speech.extra.ONLY_RETURN_LANGUAGE_PREFERENCE"; + + /** * The key to the extra in the {@link Bundle} returned by {@link #ACTION_GET_LANGUAGE_DETAILS} * which is a {@link String} that represents the current language preference this user has * specified - a locale string like "en-US". diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml index 1c15f12bdb3c..394ce0a31985 100644 --- a/core/res/res/values/strings.xml +++ b/core/res/res/values/strings.xml @@ -1822,17 +1822,6 @@ <!-- Appened to express the value is this unit of time. --> <string name="years">years</string> - <!-- Calendar spinner item, to select that an event recurs every weekday. --> - <string name="every_weekday">"Every weekday (Mon\u2013Fri)"</string> - <!-- Calendar spinner item, to select that an event recurs every day. --> - <string name="daily">Daily</string> - <!-- Calendar spinner item, to select that an event recurs every week on a particular day of the week. --> - <string name="weekly">"Weekly on <xliff:g id="day">%s</xliff:g>"</string> - <!-- Calendar spinner item, to select that an event recurs every month. --> - <string name="monthly">Monthly</string> - <!-- Calendar spinner item, to select that an event recurs every year. --> - <string name="yearly">Yearly</string> - <!-- Title for error alert when a video cannot be played. it can be used by any app. --> <string name="VideoView_error_title">Cannot play video</string> diff --git a/services/java/com/android/server/PackageManagerService.java b/services/java/com/android/server/PackageManagerService.java index 63fdaef3d4a7..7ce9a4ce69a1 100644 --- a/services/java/com/android/server/PackageManagerService.java +++ b/services/java/com/android/server/PackageManagerService.java @@ -56,8 +56,6 @@ import android.content.pm.PackageStats; import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_DEFAULT; import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_DISABLED; import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_ENABLED; -import static android.content.pm.PackageManager.PKG_INSTALL_COMPLETE; -import static android.content.pm.PackageManager.PKG_INSTALL_INCOMPLETE; import android.content.pm.PackageParser; import android.content.pm.PermissionInfo; import android.content.pm.PermissionGroupInfo; @@ -151,6 +149,19 @@ class PackageManagerService extends IPackageManager.Stub { // package apks to install directory. private static final String INSTALL_PACKAGE_SUFFIX = "-"; + /** + * Indicates the state of installation. Used by PackageManager to + * figure out incomplete installations. Say a package is being installed + * (the state is set to PKG_INSTALL_INCOMPLETE) and remains so till + * the package installation is successful or unsuccesful lin which case + * the PackageManager will no longer maintain state information associated + * with the package. If some exception(like device freeze or battery being + * pulled out) occurs during installation of a package, the PackageManager + * needs this information to clean up the previously failed installation. + */ + private static final int PKG_INSTALL_INCOMPLETE = 0; + private static final int PKG_INSTALL_COMPLETE = 1; + static final int SCAN_MONITOR = 1<<0; static final int SCAN_NO_DEX = 1<<1; static final int SCAN_FORCE_DEX = 1<<2; @@ -4426,8 +4437,11 @@ class PackageManagerService extends IPackageManager.Stub { } public void handleStartCopy(IMediaContainerService imcs) { - int ret = PackageManager.INSTALL_FAILED_INTERNAL_ERROR; - if (imcs != null) { + 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) { // Remote call to find out default install location int loc = getInstallLocation(imcs); // Use install location to create InstallArgs and temporary @@ -4447,16 +4461,6 @@ class PackageManagerService extends IPackageManager.Stub { flags &= ~PackageManager.INSTALL_EXTERNAL; } } - // Disable forward locked apps on sdcard. - if ((flags & PackageManager.INSTALL_FORWARD_LOCK) != 0 && - (flags & PackageManager.INSTALL_EXTERNAL) != 0) { - // Make sure forward locked apps can only be installed - // on internal storage - Log.w(TAG, "Cannot install protected apps on sdcard"); - ret = PackageManager.INSTALL_FAILED_INVALID_INSTALL_LOCATION; - } else { - ret = PackageManager.INSTALL_SUCCEEDED; - } } } // Create the file args now. diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java index 7b6470432044..a404ec5c7f54 100644 --- a/services/java/com/android/server/am/ActivityManagerService.java +++ b/services/java/com/android/server/am/ActivityManagerService.java @@ -35,6 +35,7 @@ import android.app.AlertDialog; import android.app.ApplicationErrorReport; import android.app.Dialog; import android.app.IActivityController; +import android.app.IActivityManager; import android.app.IActivityWatcher; import android.app.IApplicationThread; import android.app.IInstrumentationWatcher; @@ -388,6 +389,18 @@ public final class ActivityManagerService extends ActivityManagerNative implemen = new ArrayList<PendingActivityLaunch>(); /** + * List of people waiting to find out about the next launched activity. + */ + final ArrayList<IActivityManager.WaitResult> mWaitingActivityLaunched + = new ArrayList<IActivityManager.WaitResult>(); + + /** + * List of people waiting to find out about the next visible activity. + */ + final ArrayList<IActivityManager.WaitResult> mWaitingActivityVisible + = new ArrayList<IActivityManager.WaitResult>(); + + /** * List of all active broadcasts that are to be executed immediately * (without waiting for another broadcast to finish). Currently this only * contains broadcasts to registered receivers, to avoid spinning up @@ -3559,11 +3572,38 @@ public final class ActivityManagerService extends ActivityManagerNative implemen return START_SUCCESS; } - public final int startActivity(IApplicationThread caller, + void reportActivityLaunchedLocked(boolean timeout, HistoryRecord r, + long thisTime, long totalTime) { + for (int i=mWaitingActivityLaunched.size()-1; i>=0; i--) { + WaitResult w = mWaitingActivityLaunched.get(i); + w.timeout = timeout; + if (r != null) { + w.who = new ComponentName(r.info.packageName, r.info.name); + } + w.thisTime = thisTime; + w.totalTime = totalTime; + } + notify(); + } + + void reportActivityVisibleLocked(HistoryRecord r) { + for (int i=mWaitingActivityVisible.size()-1; i>=0; i--) { + WaitResult w = mWaitingActivityVisible.get(i); + w.timeout = false; + if (r != null) { + w.who = new ComponentName(r.info.packageName, r.info.name); + } + w.totalTime = SystemClock.uptimeMillis() - w.thisTime; + w.thisTime = w.totalTime; + } + notify(); + } + + private final int startActivityMayWait(IApplicationThread caller, Intent intent, String resolvedType, Uri[] grantedUriPermissions, int grantedMode, IBinder resultTo, String resultWho, int requestCode, boolean onlyIfNeeded, - boolean debug) { + boolean debug, WaitResult outResult) { // Refuse possible leaked file descriptors if (intent != null && intent.hasFileDescriptors()) { throw new IllegalArgumentException("File descriptors passed in Intent"); @@ -3603,7 +3643,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen } } - synchronized(this) { + synchronized (this) { int callingPid; int callingUid; if (caller == null) { @@ -3618,11 +3658,62 @@ public final class ActivityManagerService extends ActivityManagerNative implemen resultTo, resultWho, requestCode, callingPid, callingUid, onlyIfNeeded, componentSpecified); Binder.restoreCallingIdentity(origId); + + if (outResult != null) { + outResult.result = res; + if (res == IActivityManager.START_SUCCESS) { + mWaitingActivityLaunched.add(outResult); + do { + try { + wait(); + } catch (InterruptedException e) { + } + } while (!outResult.timeout && outResult.who == null); + } else if (res == IActivityManager.START_TASK_TO_FRONT) { + HistoryRecord r = this.topRunningActivityLocked(null); + if (r.nowVisible) { + outResult.timeout = false; + outResult.who = new ComponentName(r.info.packageName, r.info.name); + outResult.totalTime = 0; + outResult.thisTime = 0; + } else { + outResult.thisTime = SystemClock.uptimeMillis(); + mWaitingActivityVisible.add(outResult); + do { + try { + wait(); + } catch (InterruptedException e) { + } + } while (!outResult.timeout && outResult.who == null); + } + } + } + return res; } } - public int startActivityIntentSender(IApplicationThread caller, + public final int startActivity(IApplicationThread caller, + Intent intent, String resolvedType, Uri[] grantedUriPermissions, + int grantedMode, IBinder resultTo, + String resultWho, int requestCode, boolean onlyIfNeeded, + boolean debug) { + return startActivityMayWait(caller, intent, resolvedType, grantedUriPermissions, + grantedMode, resultTo, resultWho, requestCode, onlyIfNeeded, debug, null); + } + + public final WaitResult startActivityAndWait(IApplicationThread caller, + Intent intent, String resolvedType, Uri[] grantedUriPermissions, + int grantedMode, IBinder resultTo, + String resultWho, int requestCode, boolean onlyIfNeeded, + boolean debug) { + WaitResult res = new WaitResult(); + startActivityMayWait(caller, intent, resolvedType, grantedUriPermissions, + grantedMode, resultTo, resultWho, requestCode, onlyIfNeeded, debug, res); + return res; + } + + public int startActivityIntentSender(IApplicationThread caller, IntentSender intent, Intent fillInIntent, String resolvedType, IBinder resultTo, String resultWho, int requestCode, int flagsMask, int flagsValues) { @@ -5505,6 +5596,10 @@ public final class ActivityManagerService extends ActivityManagerNative implemen if (index >= 0) { HistoryRecord r = (HistoryRecord)mHistory.get(index); + if (fromTimeout) { + reportActivityLaunchedLocked(fromTimeout, r, -1, -1); + } + // This is a hack to semi-deal with a race condition // in the client where it can be constructed with a // newer configuration from when we asked it to launch. @@ -5539,6 +5634,9 @@ public final class ActivityManagerService extends ActivityManagerNative implemen mBooted = true; enableScreen = true; } + + } else if (fromTimeout) { + reportActivityLaunchedLocked(fromTimeout, null, -1, -1); } // Atomically retrieve all of the other things to do. diff --git a/services/java/com/android/server/am/HistoryRecord.java b/services/java/com/android/server/am/HistoryRecord.java index 0b34f7c99f66..7d7247c64268 100644 --- a/services/java/com/android/server/am/HistoryRecord.java +++ b/services/java/com/android/server/am/HistoryRecord.java @@ -387,12 +387,14 @@ class HistoryRecord extends IApplicationToken.Stub { sb.append(" ms)"); Log.i(ActivityManagerService.TAG, sb.toString()); } + service.reportActivityLaunchedLocked(false, this, thisTime, totalTime); if (totalTime > 0) { service.mUsageStatsService.noteLaunchTime(realActivity, (int)totalTime); } startTime = 0; service.mInitialStartTime = 0; } + service.reportActivityVisibleLocked(this); if (ActivityManagerService.DEBUG_SWITCH) Log.v( ActivityManagerService.TAG, "windowsVisible(): " + this); if (!nowVisible) { diff --git a/services/java/com/android/server/connectivity/Tethering.java b/services/java/com/android/server/connectivity/Tethering.java index 16638bc02bfe..1c47bb4bed1b 100644 --- a/services/java/com/android/server/connectivity/Tethering.java +++ b/services/java/com/android/server/connectivity/Tethering.java @@ -31,6 +31,7 @@ import android.net.InterfaceConfiguration; import android.net.IConnectivityManager; import android.net.INetworkManagementEventObserver; import android.net.NetworkInfo; +import android.os.BatteryManager; import android.os.Binder; import android.os.IBinder; import android.os.INetworkManagementService; @@ -88,11 +89,6 @@ public class Tethering extends INetworkManagementEventObserver.Stub { private String mUpstreamIfaceName; - // turning on/off RNDIS resets the interface generating and extra discon/conn cycle - // count how many to ignore.. Self correcting if you plug/unplug a bunch of times. - // TODO - brittle - maybe don't need? - private int mUsbResetExpected = 0; - HierarchicalStateMachine mTetherMasterSM; public Tethering(Context context) { @@ -116,8 +112,7 @@ public class Tethering extends INetworkManagementEventObserver.Stub { // TODO - remove this hack after real USB connections are detected. IntentFilter filter = new IntentFilter(); - filter.addAction(Intent.ACTION_UMS_DISCONNECTED); - filter.addAction(Intent.ACTION_UMS_CONNECTED); + filter.addAction(Intent.ACTION_BATTERY_CHANGED); filter.addAction(ConnectivityManager.CONNECTIVITY_ACTION); mStateReceiver = new StateReceiver(); mContext.registerReceiver(mStateReceiver, filter); @@ -428,26 +423,10 @@ public class Tethering extends INetworkManagementEventObserver.Stub { private class StateReceiver extends BroadcastReceiver { public void onReceive(Context content, Intent intent) { String action = intent.getAction(); - if (action.equals(Intent.ACTION_UMS_CONNECTED)) { - Log.w(TAG, "got UMS connected"); - synchronized (Tethering.this) { - if(mUsbResetExpected != 0) { - Log.w(TAG, "mUsbResetExpected == " + mUsbResetExpected + ", ignored"); - mUsbResetExpected--; - return; - } - } - Tethering.this.enableUsbIfaces(true); // add them - } else if (action.equals(Intent.ACTION_UMS_DISCONNECTED)) { - Log.w(TAG, "got UMS disconneded broadcast"); - synchronized (Tethering.this) { - if(mUsbResetExpected != 0) { - Log.w(TAG, "mUsbResetExpected == " + mUsbResetExpected + ", ignored"); - mUsbResetExpected--; - return; - } - } - Tethering.this.enableUsbIfaces(false); // remove them + if (action.equals(Intent.ACTION_BATTERY_CHANGED)) { + boolean usbConnected = (intent.getIntExtra(BatteryManager.EXTRA_PLUGGED, -1) + == BatteryManager.BATTERY_PLUGGED_USB); + Tethering.this.enableUsbIfaces(usbConnected); // add or remove them } else if (action.equals(ConnectivityManager.CONNECTIVITY_ACTION)) { IBinder b = ServiceManager.getService(Context.CONNECTIVITY_SERVICE); IConnectivityManager service = IConnectivityManager.Stub.asInterface(b); @@ -497,10 +476,8 @@ public class Tethering extends INetworkManagementEventObserver.Stub { try { if (enabled) { - // turning this on will reset USB and generate two bogus events - ignore them synchronized (this) { if (!service.isUsbRNDISStarted()) { - mUsbResetExpected += 2; service.startUsbRNDIS(); } } |