diff options
author | Dianne Hackborn <hackbod@google.com> | 2010-06-04 13:30:32 -0700 |
---|---|---|
committer | Android (Google) Code Review <android-gerrit@google.com> | 2010-06-04 13:30:32 -0700 |
commit | faed5fbf1583ccb6633cde31f1ec3a3acf508260 (patch) | |
tree | 385e1b8de68667650e2022ac29817342b3c4c5cb /core | |
parent | 7c035d8a65626b8fed6e7da46477137ab9d5573e (diff) | |
parent | 860755faa6bdd3c2aeae49c05b87b5bc080ae60c (diff) | |
download | frameworks_base-faed5fbf1583ccb6633cde31f1ec3a3acf508260.zip frameworks_base-faed5fbf1583ccb6633cde31f1ec3a3acf508260.tar.gz frameworks_base-faed5fbf1583ccb6633cde31f1ec3a3acf508260.tar.bz2 |
Merge "Add support for heavy-weight applications." into kraken
Diffstat (limited to 'core')
-rw-r--r-- | core/java/android/app/ActivityManager.java | 6 | ||||
-rw-r--r-- | core/java/android/app/ActivityManagerNative.java | 17 | ||||
-rw-r--r-- | core/java/android/app/IActivityManager.java | 3 | ||||
-rw-r--r-- | core/java/android/content/IntentSender.java | 20 | ||||
-rw-r--r-- | core/java/android/content/pm/ApplicationInfo.java | 11 | ||||
-rw-r--r-- | core/java/android/content/pm/PackageParser.java | 38 | ||||
-rw-r--r-- | core/java/com/android/internal/app/HeavyWeightSwitcherActivity.java | 156 | ||||
-rw-r--r-- | core/res/AndroidManifest.xml | 6 | ||||
-rw-r--r-- | core/res/res/layout/heavy_weight_switcher.xml | 145 | ||||
-rw-r--r-- | core/res/res/values/attrs_manifest.xml | 9 | ||||
-rw-r--r-- | core/res/res/values/public.xml | 3 | ||||
-rw-r--r-- | core/res/res/values/strings.xml | 23 |
12 files changed, 435 insertions, 2 deletions
diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java index c9096cf..793b9d2 100644 --- a/core/java/android/app/ActivityManager.java +++ b/core/java/android/app/ActivityManager.java @@ -726,6 +726,12 @@ public class ActivityManager { public static final int IMPORTANCE_FOREGROUND = 100; /** + * Constant for {@link #importance}: this process is running a + * heavy-weight application and thus should not be killed. + */ + public static final int IMPORTANCE_HEAVY_WEIGHT = 150; + + /** * Constant for {@link #importance}: this process is running something * that is considered to be actively visible to the user. */ diff --git a/core/java/android/app/ActivityManagerNative.java b/core/java/android/app/ActivityManagerNative.java index f694285..b78d22f 100644 --- a/core/java/android/app/ActivityManagerNative.java +++ b/core/java/android/app/ActivityManagerNative.java @@ -1251,6 +1251,13 @@ public abstract class ActivityManagerNative extends Binder implements IActivityM reply.writeNoException(); return true; } + + case FINISH_HEAVY_WEIGHT_APP_TRANSACTION: { + data.enforceInterface(IActivityManager.descriptor); + finishHeavyWeightApp(); + reply.writeNoException(); + return true; + } } return super.onTransact(code, data, reply, flags); @@ -2758,5 +2765,15 @@ class ActivityManagerProxy implements IActivityManager return res; } + public void finishHeavyWeightApp() throws RemoteException { + Parcel data = Parcel.obtain(); + Parcel reply = Parcel.obtain(); + data.writeInterfaceToken(IActivityManager.descriptor); + mRemote.transact(FINISH_HEAVY_WEIGHT_APP_TRANSACTION, data, reply, 0); + reply.readException(); + data.recycle(); + reply.recycle(); + } + private IBinder mRemote; } diff --git a/core/java/android/app/IActivityManager.java b/core/java/android/app/IActivityManager.java index 31f0a63..cd24fa6 100644 --- a/core/java/android/app/IActivityManager.java +++ b/core/java/android/app/IActivityManager.java @@ -303,6 +303,8 @@ public interface IActivityManager extends IInterface { public boolean isUserAMonkey() throws RemoteException; + public void finishHeavyWeightApp() throws RemoteException; + /* * Private non-Binder interfaces */ @@ -513,4 +515,5 @@ public interface IActivityManager extends IInterface { int WILL_ACTIVITY_BE_VISIBLE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+105; int START_ACTIVITY_WITH_CONFIG_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+106; int GET_RUNNING_EXTERNAL_APPLICATIONS_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+107; + int FINISH_HEAVY_WEIGHT_APP_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+108; } diff --git a/core/java/android/content/IntentSender.java b/core/java/android/content/IntentSender.java index e182021..007a715 100644 --- a/core/java/android/content/IntentSender.java +++ b/core/java/android/content/IntentSender.java @@ -16,6 +16,7 @@ package android.content; +import android.app.ActivityManagerNative; import android.content.Context; import android.content.Intent; import android.content.IIntentSender; @@ -170,6 +171,25 @@ public class IntentSender implements Parcelable { } /** + * Return the package name of the application that created this + * IntentSender, that is the identity under which you will actually be + * sending the Intent. The returned string is supplied by the system, so + * that an application can not spoof its package. + * + * @return The package name of the PendingIntent, or null if there is + * none associated with it. + */ + public String getTargetPackage() { + try { + return ActivityManagerNative.getDefault() + .getPackageForIntentSender(mTarget); + } catch (RemoteException e) { + // Should never happen. + return null; + } + } + + /** * Comparison operator on two IntentSender objects, such that true * is returned then they both represent the same operation from the * same package. diff --git a/core/java/android/content/pm/ApplicationInfo.java b/core/java/android/content/pm/ApplicationInfo.java index 7047113..7901b155 100644 --- a/core/java/android/content/pm/ApplicationInfo.java +++ b/core/java/android/content/pm/ApplicationInfo.java @@ -273,6 +273,17 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable { public static final int FLAG_SUPPORTS_XLARGE_SCREENS = 1<<19; /** + * Value for {@link #flags}: set to <code>true</code> if the application + * has reported that it is heavy-weight, and thus can not participate in + * the normal application lifecycle. + * + * <p>Comes from the + * {@link android.R.styleable#AndroidManifestApplication_heavyWeight android:heavyWeight} + * attribute of the <application> tag. + */ + public static final int FLAG_HEAVY_WEIGHT = 1<<20; + + /** * Value for {@link #flags}: this is true if the application has set * its android:neverEncrypt to true, false otherwise. It is used to specify * that this package specifically "opts-out" of a secured file system solution, diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java index 4ddc124..a5f5acc 100644 --- a/core/java/android/content/pm/PackageParser.java +++ b/core/java/android/content/pm/PackageParser.java @@ -1600,6 +1600,18 @@ public class PackageParser { ai.enabled = sa.getBoolean( com.android.internal.R.styleable.AndroidManifestApplication_enabled, true); + + if (sa.getBoolean( + com.android.internal.R.styleable.AndroidManifestApplication_heavyWeight, + false)) { + ai.flags |= ApplicationInfo.FLAG_HEAVY_WEIGHT; + + // A heavy-weight application can not be in a custom process. + // We can do direct compare because we intern all strings. + if (ai.processName != null && ai.processName != ai.packageName) { + outError[0] = "Heavy-weight applications can not use custom processes"; + } + } } sa.recycle(); @@ -1889,6 +1901,14 @@ public class PackageParser { sa.recycle(); + if (receiver && (owner.applicationInfo.flags&ApplicationInfo.FLAG_HEAVY_WEIGHT) != 0) { + // A heavy-weight application can not have receives in its main process + // We can do direct compare because we intern all strings. + if (a.info.processName == owner.packageName) { + outError[0] = "Heavy-weight applications can not have receivers in main process"; + } + } + if (outError[0] != null) { return null; } @@ -2171,6 +2191,15 @@ public class PackageParser { sa.recycle(); + if ((owner.applicationInfo.flags&ApplicationInfo.FLAG_HEAVY_WEIGHT) != 0) { + // A heavy-weight application can not have providers in its main process + // We can do direct compare because we intern all strings. + if (p.info.processName == owner.packageName) { + outError[0] = "Heavy-weight applications can not have providers in main process"; + return null; + } + } + if (cpname == null) { outError[0] = "<provider> does not incude authorities attribute"; return null; @@ -2403,6 +2432,15 @@ public class PackageParser { sa.recycle(); + if ((owner.applicationInfo.flags&ApplicationInfo.FLAG_HEAVY_WEIGHT) != 0) { + // A heavy-weight application can not have services in its main process + // We can do direct compare because we intern all strings. + if (s.info.processName == owner.packageName) { + outError[0] = "Heavy-weight applications can not have services in main process"; + return null; + } + } + int outerDepth = parser.getDepth(); int type; while ((type=parser.next()) != XmlPullParser.END_DOCUMENT diff --git a/core/java/com/android/internal/app/HeavyWeightSwitcherActivity.java b/core/java/com/android/internal/app/HeavyWeightSwitcherActivity.java new file mode 100644 index 0000000..ada7f36 --- /dev/null +++ b/core/java/com/android/internal/app/HeavyWeightSwitcherActivity.java @@ -0,0 +1,156 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.internal.app; + +import com.android.internal.R; + +import android.app.Activity; +import android.app.ActivityManagerNative; +import android.content.Intent; +import android.content.IntentSender; +import android.content.pm.ApplicationInfo; +import android.content.pm.PackageManager; +import android.graphics.drawable.Drawable; +import android.os.Bundle; +import android.os.RemoteException; +import android.util.Log; +import android.view.View; +import android.view.Window; +import android.view.View.OnClickListener; +import android.widget.Button; +import android.widget.ImageView; +import android.widget.TextView; + +/** + * This activity is displayed when the system attempts to start an Intent for + * which there is more than one matching activity, allowing the user to decide + * which to go to. It is not normally used directly by application developers. + */ +public class HeavyWeightSwitcherActivity extends Activity { + /** The PendingIntent of the new activity being launched. */ + public static final String KEY_INTENT = "intent"; + /** Set if the caller is requesting a result. */ + public static final String KEY_HAS_RESULT = "has_result"; + /** Package of current heavy-weight app. */ + public static final String KEY_CUR_APP = "cur_app"; + /** Task that current heavy-weight activity is running in. */ + public static final String KEY_CUR_TASK = "cur_task"; + /** Package of newly requested heavy-weight app. */ + public static final String KEY_NEW_APP = "new_app"; + + IntentSender mStartIntent; + boolean mHasResult; + String mCurApp; + int mCurTask; + String mNewApp; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + requestWindowFeature(Window.FEATURE_LEFT_ICON); + + mStartIntent = (IntentSender)getIntent().getParcelableExtra(KEY_INTENT); + mHasResult = getIntent().getBooleanExtra(KEY_HAS_RESULT, false); + mCurApp = getIntent().getStringExtra(KEY_CUR_APP); + mCurTask = getIntent().getIntExtra(KEY_CUR_TASK, 0); + mNewApp = getIntent().getStringExtra(KEY_NEW_APP); + + setContentView(com.android.internal.R.layout.heavy_weight_switcher); + + setIconAndText(R.id.old_app_icon, R.id.old_app_action, R.id.old_app_description, + mCurApp, R.string.old_app_action, R.string.old_app_description); + setIconAndText(R.id.new_app_icon, R.id.new_app_action, R.id.new_app_description, + mNewApp, R.string.new_app_action, R.string.new_app_description); + + View button = findViewById((R.id.switch_old)); + button.setOnClickListener(mSwitchOldListener); + button = findViewById((R.id.switch_new)); + button.setOnClickListener(mSwitchNewListener); + button = findViewById((R.id.cancel)); + button.setOnClickListener(mCancelListener); + + getWindow().setFeatureDrawableResource(Window.FEATURE_LEFT_ICON, + android.R.drawable.ic_dialog_alert); + } + + void setText(int id, CharSequence text) { + ((TextView)findViewById(id)).setText(text); + } + + void setDrawable(int id, Drawable dr) { + if (dr != null) { + ((ImageView)findViewById(id)).setImageDrawable(dr); + } + } + + void setIconAndText(int iconId, int actionId, int descriptionId, + String packageName, int actionStr, int descriptionStr) { + CharSequence appName = ""; + Drawable appIcon = null; + if (mCurApp != null) { + try { + ApplicationInfo info = getPackageManager().getApplicationInfo( + packageName, 0); + appName = info.loadLabel(getPackageManager()); + appIcon = info.loadIcon(getPackageManager()); + } catch (PackageManager.NameNotFoundException e) { + } + } + + setDrawable(iconId, appIcon); + setText(actionId, getString(actionStr, appName)); + setText(descriptionId, getText(descriptionStr)); + } + + private OnClickListener mSwitchOldListener = new OnClickListener() { + public void onClick(View v) { + try { + ActivityManagerNative.getDefault().moveTaskToFront(mCurTask); + } catch (RemoteException e) { + } + finish(); + } + }; + + private OnClickListener mSwitchNewListener = new OnClickListener() { + public void onClick(View v) { + try { + ActivityManagerNative.getDefault().finishHeavyWeightApp(); + } catch (RemoteException e) { + } + try { + if (mHasResult) { + startIntentSenderForResult(mStartIntent, -1, null, + Intent.FLAG_ACTIVITY_FORWARD_RESULT, + Intent.FLAG_ACTIVITY_FORWARD_RESULT, 0); + } else { + startIntentSenderForResult(mStartIntent, -1, null, 0, 0, 0); + } + } catch (IntentSender.SendIntentException ex) { + Log.w("HeavyWeightSwitcherActivity", "Failure starting", ex); + } + finish(); + } + }; + + private OnClickListener mCancelListener = new OnClickListener() { + public void onClick(View v) { + finish(); + } + }; +} diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml index 2a2208f..1fcf186 100644 --- a/core/res/AndroidManifest.xml +++ b/core/res/AndroidManifest.xml @@ -1250,6 +1250,12 @@ <category android:name="android.intent.category.DEFAULT" /> </intent-filter> </activity> + <activity android:name="com.android.internal.app.HeavyWeightSwitcherActivity" + android:theme="@style/Theme.Dialog" + android:label="@string/heavy_weight_switcher_title" + android:finishOnCloseSystemDialogs="true" + android:excludeFromRecents="true"> + </activity> <activity android:name="com.android.internal.app.DisableCarModeActivity" android:theme="@style/Theme.NoDisplay" android:excludeFromRecents="true"> diff --git a/core/res/res/layout/heavy_weight_switcher.xml b/core/res/res/layout/heavy_weight_switcher.xml new file mode 100644 index 0000000..9acf009 --- /dev/null +++ b/core/res/res/layout/heavy_weight_switcher.xml @@ -0,0 +1,145 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Copyright (C) 2010 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> + +<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" + android:orientation="vertical" android:padding="4dp" + android:gravity="center_horizontal" + android:layout_width="wrap_content" android:layout_height="wrap_content"> + + <TextView + android:layout_width="match_parent" android:layout_height="wrap_content" + android:layout_weight="0" + android:paddingBottom="8dp" + android:text="@string/heavy_weight_switcher_text"/> + + <ImageView android:layout_width="match_parent" + android:layout_height="wrap_content" + android:scaleType="fitXY" + android:src="?android:listDivider" /> + + <LinearLayout android:id="@+id/switch_old" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:minHeight="?android:attr/listPreferredItemHeight" + android:orientation="horizontal" + android:background="@android:drawable/list_selector_background" + android:paddingRight="3dip" + android:paddingLeft="3dip" + android:paddingTop="5dip" + android:paddingBottom="14dip" + android:gravity="center_vertical" + android:focusable="true" > + + <ImageView android:id="@+id/old_app_icon" + android:layout_width="@android:dimen/app_icon_size" + android:layout_height="@android:dimen/app_icon_size" + android:layout_marginRight="11dip" + android:layout_gravity="center_vertical" + android:scaleType="fitCenter"/> + + <LinearLayout + android:orientation="vertical" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:duplicateParentState="true" > + <TextView android:id="@+id/old_app_action" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:textAppearance="?android:attr/textAppearanceMedium" + android:textStyle="bold" + android:singleLine="true" + android:layout_marginBottom="2dip" + android:duplicateParentState="true" /> + <TextView android:id="@+id/old_app_description" + android:layout_marginTop="-4dip" + android:layout_gravity="center_vertical" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:textAppearance="?android:attr/textAppearanceSmall" + android:duplicateParentState="true" /> + </LinearLayout> + </LinearLayout> + + <ImageView android:layout_width="match_parent" + android:layout_height="wrap_content" + android:scaleType="fitXY" + android:src="?android:listDivider" /> + + <LinearLayout android:id="@+id/switch_new" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:minHeight="?android:attr/listPreferredItemHeight" + android:orientation="horizontal" + android:background="@android:drawable/list_selector_background" + android:paddingRight="3dip" + android:paddingLeft="3dip" + android:paddingTop="5dip" + android:paddingBottom="8dip" + android:gravity="center_vertical" + android:focusable="true" > + + <ImageView android:id="@+id/new_app_icon" + android:layout_width="@android:dimen/app_icon_size" + android:layout_height="@android:dimen/app_icon_size" + android:layout_marginRight="11dip" + android:layout_gravity="center_vertical" + android:scaleType="fitCenter"/> + + <LinearLayout + android:orientation="vertical" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:duplicateParentState="true" > + <TextView android:id="@+id/new_app_action" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:textAppearance="?android:attr/textAppearanceMedium" + android:textStyle="bold" + android:singleLine="true" + android:layout_marginBottom="2dip" + android:duplicateParentState="true" /> + <TextView android:id="@+id/new_app_description" + android:layout_marginTop="-4dip" + android:layout_gravity="center_vertical" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:textAppearance="?android:attr/textAppearanceSmall" + android:duplicateParentState="true" /> + </LinearLayout> + </LinearLayout> + + <ImageView android:layout_width="match_parent" + android:layout_height="wrap_content" + android:scaleType="fitXY" + android:src="?android:listDivider" /> + + <TextView android:id="@+id/cancel" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:minHeight="?android:attr/listPreferredItemHeight" + android:textAppearance="?android:attr/textAppearanceMedium" + android:background="@android:drawable/list_selector_background" + android:paddingRight="6dip" + android:paddingLeft="6dip" + android:paddingTop="5dip" + android:paddingBottom="8dip" + android:textStyle="bold" + android:singleLine="true" + android:gravity="center" + android:focusable="true" + android:text="@string/cancel" /> + +</LinearLayout> diff --git a/core/res/res/values/attrs_manifest.xml b/core/res/res/values/attrs_manifest.xml index b4c4811..5ca7b28 100644 --- a/core/res/res/values/attrs_manifest.xml +++ b/core/res/res/values/attrs_manifest.xml @@ -740,6 +740,15 @@ <attr name="restoreNeedsApplication" /> <attr name="restoreAnyVersion" /> <attr name="neverEncrypt" /> + <!-- Declare that this is a heavy-weight application. This kind of + application is not able to save and restore its state on demand, + so can not participate in the normal activity lifecycle. It will + not be killed while in the background; the user must explicitly + quit it. Only one such app can be running at a time; if the user + tries to launch a second heavy-weight app, they will be prompted + to quit the first before doing so. While a heavy-weight + application is running, the user will be informed of this. --> + <attr name="heavyWeight" format="boolean" /> </declare-styleable> <!-- The <code>permission</code> tag declares a security permission that can be diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml index 5d18e9e..1932771 100644 --- a/core/res/res/values/public.xml +++ b/core/res/res/values/public.xml @@ -1245,8 +1245,9 @@ <public type="attr" name="logo" id="0x010102be" /> <public type="attr" name="xlargeScreens" id="0x010102bf" /> - + <public type="attr" name="heavyWeight" id="0x010102c0" /> <public-padding type="attr" name="kraken_resource_pad" end="0x01010300" /> + <public-padding type="id" name="kraken_resource_pad" end="0x01020040" /> <public-padding type="anim" name="kraken_resource_pad" end="0x010a0020" /> <public-padding type="drawable" name="kraken_resource_pad" end="0x01080100" /> diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml index 613a9a2..e7f892a 100644 --- a/core/res/res/values/strings.xml +++ b/core/res/res/values/strings.xml @@ -1935,8 +1935,29 @@ <!-- Button allowing the user to choose to wait for an application that is not responding to become responsive again. --> <string name="wait">Wait</string> + <!-- Notification text to tell the user that a heavy-weight application is running. --> + <string name="heavy_weight_notification"><xliff:g id="app">%1$s</xliff:g> running</string> + + <!-- Notification details to tell the user that a heavy-weight application is running. --> + <string name="heavy_weight_notification_detail">Select to switch to application</string> + + <!-- Title of dialog prompting whether user wants to switch between heavy-weight apps. --> + <string name="heavy_weight_switcher_title">Switch applications?</string> + + <!-- Descriptive text for switching to a new heavy-weight application. --> + <string name="heavy_weight_switcher_text">Another application is already running + that must be stopped before you can start a new one.</string> + + <string name="old_app_action">Return to <xliff:g id="old_app">%1$s</xliff:g></string> + <string name="old_app_description">Don\'t start the new application.</string> + + <string name="new_app_action">Start <xliff:g id="old_app">%1$s</xliff:g></string> + <string name="new_app_description">Stop the old application without saving.</string> + <!-- Displayed in the title of the chooser for things to do with text that - is to be sent to another application. For example, I can send text through SMS or IM. A dialog with those choices would be shown, and this would be the title. --> + is to be sent to another application. For example, I can send + text through SMS or IM. A dialog with those choices would be shown, + and this would be the title. --> <string name="sendText">Select an action for text</string> <!-- Title of the dialog where the user is adjusting the phone ringer volume --> |