diff options
-rw-r--r-- | cmds/am/src/com/android/commands/am/Am.java | 5 | ||||
-rw-r--r-- | cmds/pm/src/com/android/commands/pm/Pm.java | 19 | ||||
-rw-r--r-- | core/java/android/app/ActivityManager.java | 76 | ||||
-rw-r--r-- | core/java/android/app/ActivityManagerNative.java | 72 | ||||
-rw-r--r-- | core/java/android/app/IActivityManager.java | 10 | ||||
-rw-r--r-- | core/java/android/content/res/CompatibilityInfo.java | 30 | ||||
-rw-r--r-- | packages/SystemUI/res/drawable-mdpi/hd_off.png | bin | 0 -> 3634 bytes | |||
-rw-r--r-- | packages/SystemUI/res/drawable-mdpi/hd_on.png | bin | 0 -> 3507 bytes | |||
-rw-r--r-- | packages/SystemUI/res/drawable/hd.xml | 21 | ||||
-rw-r--r-- | packages/SystemUI/res/layout-large/status_bar_recent_panel.xml | 12 | ||||
-rw-r--r-- | packages/SystemUI/src/com/android/systemui/statusbar/tablet/RecentAppsPanel.java | 31 | ||||
-rw-r--r-- | services/java/com/android/server/PackageManagerService.java | 7 | ||||
-rw-r--r-- | services/java/com/android/server/am/ActivityManagerService.java | 112 | ||||
-rw-r--r-- | services/java/com/android/server/am/CompatModePackages.java | 295 |
14 files changed, 602 insertions, 88 deletions
diff --git a/cmds/am/src/com/android/commands/am/Am.java b/cmds/am/src/com/android/commands/am/Am.java index 5c8abe4..8a9144c 100644 --- a/cmds/am/src/com/android/commands/am/Am.java +++ b/cmds/am/src/com/android/commands/am/Am.java @@ -18,6 +18,7 @@ package com.android.commands.am; +import android.app.ActivityManager; import android.app.ActivityManagerNative; import android.app.IActivityController; import android.app.IActivityManager; @@ -794,7 +795,9 @@ public class Am { String packageName = nextArgRequired(); do { try { - mAm.setPackageScreenCompatMode(packageName, enabled); + mAm.setPackageScreenCompatMode(packageName, enabled + ? ActivityManager.COMPAT_MODE_ENABLED + : ActivityManager.COMPAT_MODE_DISABLED); } catch (RemoteException e) { } packageName = nextArg(); diff --git a/cmds/pm/src/com/android/commands/pm/Pm.java b/cmds/pm/src/com/android/commands/pm/Pm.java index d058e38..b759de0 100644 --- a/cmds/pm/src/com/android/commands/pm/Pm.java +++ b/cmds/pm/src/com/android/commands/pm/Pm.java @@ -193,6 +193,7 @@ public final class Pm { private void runListPackages(boolean showApplicationPackage) { int getFlags = 0; boolean listDisabled = false, listEnabled = false; + boolean listSystem = false, listThirdParty = false; try { String opt; while ((opt=nextOption()) != null) { @@ -206,6 +207,10 @@ public final class Pm { listDisabled = true; } else if (opt.equals("-e")) { listEnabled = true; + } else if (opt.equals("-s")) { + listSystem = true; + } else if (opt.equals("-3")) { + listThirdParty = true; } else if (opt.equals("-u")) { getFlags |= PackageManager.GET_UNINSTALLED_PACKAGES; } else { @@ -231,8 +236,12 @@ public final class Pm { if (filter != null && !info.packageName.contains(filter)) { continue; } + final boolean isSystem = + (info.applicationInfo.flags&ApplicationInfo.FLAG_SYSTEM) != 0; if ((!listDisabled || !info.applicationInfo.enabled) && - (!listEnabled || info.applicationInfo.enabled)) { + (!listEnabled || info.applicationInfo.enabled) && + (!listSystem || isSystem) && + (!listThirdParty || !isSystem)) { System.out.print("package:"); if (showApplicationPackage) { System.out.print(info.applicationInfo.sourceDir); @@ -993,7 +1002,7 @@ public final class Pm { private static void showUsage() { System.err.println("usage: pm [list|path|install|uninstall]"); - System.err.println(" pm list packages [-f] [-d] [-e] [-u] [FILTER]"); + System.err.println(" pm list packages [-f] [-d] [-e] [-s] [-e] [-u] [FILTER]"); System.err.println(" pm list permission-groups"); System.err.println(" pm list permissions [-g] [-f] [-d] [-u] [GROUP]"); System.err.println(" pm list instrumentation [-f] [TARGET-PACKAGE]"); @@ -1010,8 +1019,10 @@ public final class Pm { System.err.println("The list packages command prints all packages, optionally only"); System.err.println("those whose package name contains the text in FILTER. Options:"); System.err.println(" -f: see their associated file."); - System.err.println(" -d: filter to include disbled packages."); - System.err.println(" -e: filter to include enabled packages."); + System.err.println(" -d: filter to only show disbled packages."); + System.err.println(" -e: filter to only show enabled packages."); + System.err.println(" -s: filter to only show system packages."); + System.err.println(" -3: filter to only show third party packages."); System.err.println(" -u: also include uninstalled packages."); System.err.println(""); System.err.println("The list permission-groups command prints all known"); diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java index b6581e9..e4499797 100644 --- a/core/java/android/app/ActivityManager.java +++ b/core/java/android/app/ActivityManager.java @@ -59,6 +59,82 @@ public class ActivityManager { } /** + * Screen compatibility mode: the application most always run in + * compatibility mode. + * @hide + */ + public static final int COMPAT_MODE_ALWAYS = -1; + + /** + * Screen compatibility mode: the application can never run in + * compatibility mode. + * @hide + */ + public static final int COMPAT_MODE_NEVER = -2; + + /** + * Screen compatibility mode: unknown. + * @hide + */ + public static final int COMPAT_MODE_UNKNOWN = -3; + + /** + * Screen compatibility mode: the application currently has compatibility + * mode disabled. + * @hide + */ + public static final int COMPAT_MODE_DISABLED = 0; + + /** + * Screen compatibility mode: the application currently has compatibility + * mode enabled. + * @hide + */ + public static final int COMPAT_MODE_ENABLED = 1; + + /** + * Screen compatibility mode: request to toggle the application's + * compatibility mode. + * @hide + */ + public static final int COMPAT_MODE_TOGGLE = 2; + + /** @hide */ + public int getFrontActivityScreenCompatMode() { + try { + return ActivityManagerNative.getDefault().getFrontActivityScreenCompatMode(); + } catch (RemoteException e) { + // System dead, we will be dead too soon! + return 0; + } + } + + public void setFrontActivityScreenCompatMode(int mode) { + try { + ActivityManagerNative.getDefault().setFrontActivityScreenCompatMode(mode); + } catch (RemoteException e) { + // System dead, we will be dead too soon! + } + } + + public int getPackageScreenCompatMode(String packageName) { + try { + return ActivityManagerNative.getDefault().getPackageScreenCompatMode(packageName); + } catch (RemoteException e) { + // System dead, we will be dead too soon! + return 0; + } + } + + public void setPackageScreenCompatMode(String packageName, int mode) { + try { + ActivityManagerNative.getDefault().setPackageScreenCompatMode(packageName, mode); + } catch (RemoteException e) { + // System dead, we will be dead too soon! + } + } + + /** * Return the approximate per-application memory class of the current * device. This gives you an idea of how hard a memory limit you should * impose on your application to let the overall system work best. The diff --git a/core/java/android/app/ActivityManagerNative.java b/core/java/android/app/ActivityManagerNative.java index 11e9975..4beb5cc 100644 --- a/core/java/android/app/ActivityManagerNative.java +++ b/core/java/android/app/ActivityManagerNative.java @@ -1398,12 +1398,41 @@ public abstract class ActivityManagerNative extends Binder implements IActivityM return true; } + case GET_FRONT_ACTIVITY_SCREEN_COMPAT_MODE_TRANSACTION: + { + data.enforceInterface(IActivityManager.descriptor); + int mode = getFrontActivityScreenCompatMode(); + reply.writeNoException(); + reply.writeInt(mode); + return true; + } + + case SET_FRONT_ACTIVITY_SCREEN_COMPAT_MODE_TRANSACTION: + { + data.enforceInterface(IActivityManager.descriptor); + int mode = data.readInt(); + setFrontActivityScreenCompatMode(mode); + reply.writeNoException(); + reply.writeInt(mode); + return true; + } + + case GET_PACKAGE_SCREEN_COMPAT_MODE_TRANSACTION: + { + data.enforceInterface(IActivityManager.descriptor); + String pkg = data.readString(); + int mode = getPackageScreenCompatMode(pkg); + reply.writeNoException(); + reply.writeInt(mode); + return true; + } + case SET_PACKAGE_SCREEN_COMPAT_MODE_TRANSACTION: { data.enforceInterface(IActivityManager.descriptor); String pkg = data.readString(); - boolean enabled = data.readInt() != 0; - setPackageScreenCompatMode(pkg, enabled); + int mode = data.readInt(); + setPackageScreenCompatMode(pkg, mode); reply.writeNoException(); return true; } @@ -3152,13 +3181,48 @@ class ActivityManagerProxy implements IActivityManager return result; } - public void setPackageScreenCompatMode(String packageName, boolean compatEnabled) + public int getFrontActivityScreenCompatMode() throws RemoteException { + Parcel data = Parcel.obtain(); + Parcel reply = Parcel.obtain(); + data.writeInterfaceToken(IActivityManager.descriptor); + mRemote.transact(GET_FRONT_ACTIVITY_SCREEN_COMPAT_MODE_TRANSACTION, data, reply, 0); + reply.readException(); + int mode = reply.readInt(); + reply.recycle(); + data.recycle(); + return mode; + } + + public void setFrontActivityScreenCompatMode(int mode) throws RemoteException { + Parcel data = Parcel.obtain(); + Parcel reply = Parcel.obtain(); + data.writeInterfaceToken(IActivityManager.descriptor); + data.writeInt(mode); + mRemote.transact(SET_FRONT_ACTIVITY_SCREEN_COMPAT_MODE_TRANSACTION, data, reply, 0); + reply.readException(); + reply.recycle(); + data.recycle(); + } + + public int getPackageScreenCompatMode(String packageName) throws RemoteException { + Parcel data = Parcel.obtain(); + Parcel reply = Parcel.obtain(); + data.writeInterfaceToken(IActivityManager.descriptor); + mRemote.transact(SET_PACKAGE_SCREEN_COMPAT_MODE_TRANSACTION, data, reply, 0); + reply.readException(); + int mode = reply.readInt(); + reply.recycle(); + data.recycle(); + return mode; + } + + public void setPackageScreenCompatMode(String packageName, int mode) throws RemoteException { Parcel data = Parcel.obtain(); Parcel reply = Parcel.obtain(); data.writeInterfaceToken(IActivityManager.descriptor); data.writeString(packageName); - data.writeInt(compatEnabled ? 1 : 0); + data.writeInt(mode); mRemote.transact(SET_PACKAGE_SCREEN_COMPAT_MODE_TRANSACTION, data, reply, 0); reply.readException(); reply.recycle(); diff --git a/core/java/android/app/IActivityManager.java b/core/java/android/app/IActivityManager.java index 4c2ccf4..24706f9 100644 --- a/core/java/android/app/IActivityManager.java +++ b/core/java/android/app/IActivityManager.java @@ -342,7 +342,10 @@ public interface IActivityManager extends IInterface { public int startActivitiesInPackage(int uid, Intent[] intents, String[] resolvedTypes, IBinder resultTo) throws RemoteException; - public void setPackageScreenCompatMode(String packageName, boolean compatEnabled) + public int getFrontActivityScreenCompatMode() throws RemoteException; + public void setFrontActivityScreenCompatMode(int mode) throws RemoteException; + public int getPackageScreenCompatMode(String packageName) throws RemoteException; + public void setPackageScreenCompatMode(String packageName, int mode) throws RemoteException; /* @@ -560,5 +563,8 @@ public interface IActivityManager extends IInterface { int START_ACTIVITIES_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+120; int START_ACTIVITIES_IN_PACKAGE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+121; int ACTIVITY_SLEPT_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+122; - int SET_PACKAGE_SCREEN_COMPAT_MODE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+123; + int GET_FRONT_ACTIVITY_SCREEN_COMPAT_MODE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+123; + int SET_FRONT_ACTIVITY_SCREEN_COMPAT_MODE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+124; + int GET_PACKAGE_SCREEN_COMPAT_MODE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+125; + int SET_PACKAGE_SCREEN_COMPAT_MODE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+126; } diff --git a/core/java/android/content/res/CompatibilityInfo.java b/core/java/android/content/res/CompatibilityInfo.java index ab9bfce..8bcb005 100644 --- a/core/java/android/content/res/CompatibilityInfo.java +++ b/core/java/android/content/res/CompatibilityInfo.java @@ -81,9 +81,19 @@ public class CompatibilityInfo implements Parcelable { private static final int XLARGE_SCREENS = 32; /** + * Application must always run in compatibility mode? + */ + private static final int ALWAYS_COMPAT = 64; + + /** + * Application never should run in compatibility mode? + */ + private static final int NEVER_COMPAT = 128; + + /** * Set if the application needs to run in screen size compatibility mode. */ - private static final int NEEDS_SCREEN_COMPAT = 128; + private static final int NEEDS_SCREEN_COMPAT = 256; /** * The effective screen density we have selected for this application. @@ -131,11 +141,17 @@ public class CompatibilityInfo implements Parcelable { if ((compatFlags&XLARGE_SCREENS) != 0) { supportsScreen = true; } + if ((appInfo.flags & ApplicationInfo.FLAG_SUPPORTS_XLARGE_SCREENS) != 0) { + compatFlags |= NEVER_COMPAT; + } break; case Configuration.SCREENLAYOUT_SIZE_LARGE: if ((compatFlags&LARGE_SCREENS) != 0) { supportsScreen = true; } + if ((appInfo.flags & ApplicationInfo.FLAG_SUPPORTS_LARGE_SCREENS) != 0) { + compatFlags |= NEVER_COMPAT; + } break; } @@ -143,6 +159,10 @@ public class CompatibilityInfo implements Parcelable { if ((compatFlags&EXPANDABLE) != 0) { supportsScreen = true; } + if ((compatFlags&EXPANDABLE) == 0 && + (appInfo.flags & ApplicationInfo.FLAG_RESIZEABLE_FOR_SCREENS) == 0) { + compatFlags |= ALWAYS_COMPAT; + } } if (supportsScreen) { @@ -192,6 +212,14 @@ public class CompatibilityInfo implements Parcelable { return (mCompatibilityFlags&NEEDS_SCREEN_COMPAT) == 0; } + public boolean neverSupportsScreen() { + return (mCompatibilityFlags&NEVER_COMPAT) != 0; + } + + public boolean alwaysSupportsScreen() { + return (mCompatibilityFlags&ALWAYS_COMPAT) != 0; + } + @Override public String toString() { return "CompatibilityInfo{scale=" + applicationScale + "}"; diff --git a/packages/SystemUI/res/drawable-mdpi/hd_off.png b/packages/SystemUI/res/drawable-mdpi/hd_off.png Binary files differnew file mode 100644 index 0000000..ad09eef --- /dev/null +++ b/packages/SystemUI/res/drawable-mdpi/hd_off.png diff --git a/packages/SystemUI/res/drawable-mdpi/hd_on.png b/packages/SystemUI/res/drawable-mdpi/hd_on.png Binary files differnew file mode 100644 index 0000000..1471c13 --- /dev/null +++ b/packages/SystemUI/res/drawable-mdpi/hd_on.png diff --git a/packages/SystemUI/res/drawable/hd.xml b/packages/SystemUI/res/drawable/hd.xml new file mode 100644 index 0000000..73867a2 --- /dev/null +++ b/packages/SystemUI/res/drawable/hd.xml @@ -0,0 +1,21 @@ +<?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. +--> + +<selector xmlns:android="http://schemas.android.com/apk/res/android"> + <item android:state_checked="false" + android:drawable="@drawable/hd_off" /> + <item android:drawable="@drawable/hd_on" /> +</selector> diff --git a/packages/SystemUI/res/layout-large/status_bar_recent_panel.xml b/packages/SystemUI/res/layout-large/status_bar_recent_panel.xml index 42940be..f019e2d 100644 --- a/packages/SystemUI/res/layout-large/status_bar_recent_panel.xml +++ b/packages/SystemUI/res/layout-large/status_bar_recent_panel.xml @@ -24,11 +24,23 @@ android:layout_height="match_parent" android:layout_width="wrap_content"> + <CheckBox android:id="@+id/recents_compat_mode" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_alignParentBottom="true" + android:layout_alignParentRight="true" + android:layout_marginLeft="16dp" + android:layout_marginBottom="@*android:dimen/status_bar_height" + android:background="@drawable/hd" + android:button="@null" + /> + <FrameLayout android:id="@+id/recents_bg_protect" android:background="@drawable/recents_bg_protect_tile" android:layout_width="wrap_content" android:layout_height="match_parent" + android:layout_toLeftOf="@id/recents_compat_mode" android:layout_alignParentBottom="true" android:paddingBottom="@*android:dimen/status_bar_height" android:clipToPadding="false"> diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/RecentAppsPanel.java b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/RecentAppsPanel.java index c5a7df2..7db1ce8 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/RecentAppsPanel.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/RecentAppsPanel.java @@ -50,6 +50,7 @@ import android.view.ViewGroup; import android.widget.AdapterView; import android.widget.AdapterView.OnItemClickListener; import android.widget.BaseAdapter; +import android.widget.CheckBox; import android.widget.ImageView; import android.widget.ListView; import android.widget.RelativeLayout; @@ -69,6 +70,7 @@ public class RecentAppsPanel extends RelativeLayout implements StatusBarPanel, O private View mRecentsScrim; private View mRecentsGlowView; private ListView mRecentsContainer; + private CheckBox mCompatMode; private Bitmap mGlowBitmap; private boolean mShowing; private Choreographer mChoreo; @@ -356,6 +358,15 @@ public class RecentAppsPanel extends RelativeLayout implements StatusBarPanel, O mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE); mRecentsContainer = (ListView) findViewById(R.id.recents_container); + mCompatMode = (CheckBox) findViewById(R.id.recents_compat_mode); + mCompatMode.setOnClickListener(new OnClickListener() { + public void onClick(View v) { + final ActivityManager am = (ActivityManager) + mContext.getSystemService(Context.ACTIVITY_SERVICE); + am.setFrontActivityScreenCompatMode(ActivityManager.COMPAT_MODE_TOGGLE); + hide(true); + } + }); View footer = inflater.inflate(R.layout.status_bar_recent_panel_footer, mRecentsContainer, false); mRecentsContainer.setScrollbarFadingEnabled(true); @@ -492,12 +503,32 @@ public class RecentAppsPanel extends RelativeLayout implements StatusBarPanel, O return desc; } + private void updateShownCompatMode() { + final ActivityManager am = (ActivityManager) + mContext.getSystemService(Context.ACTIVITY_SERVICE); + int mode = am.getFrontActivityScreenCompatMode(); + switch (mode) { + case ActivityManager.COMPAT_MODE_DISABLED: + mCompatMode.setVisibility(View.VISIBLE); + mCompatMode.setChecked(true); + break; + case ActivityManager.COMPAT_MODE_ENABLED: + mCompatMode.setVisibility(View.VISIBLE); + mCompatMode.setChecked(false); + break; + default: + mCompatMode.setVisibility(View.GONE); + break; + } + } + private void refreshApplicationList() { mActivityDescriptions = getRecentTasks(); mListAdapter.notifyDataSetInvalidated(); if (mActivityDescriptions.size() > 0) { mLastVisibleItem = mActivityDescriptions.size() - 1; // scroll to bottom after reloading updateUiElements(getResources().getConfiguration()); + updateShownCompatMode(); } else { // Immediately hide this panel hide(false); diff --git a/services/java/com/android/server/PackageManagerService.java b/services/java/com/android/server/PackageManagerService.java index 5cd942c..4a66a40 100644 --- a/services/java/com/android/server/PackageManagerService.java +++ b/services/java/com/android/server/PackageManagerService.java @@ -8088,18 +8088,11 @@ class PackageManagerService extends IPackageManager.Stub { Settings() { File dataDir = Environment.getDataDirectory(); File systemDir = new File(dataDir, "system"); - // TODO(oam): This secure dir creation needs to be moved somewhere else (later) - File systemSecureDir = new File(dataDir, "secure/system"); systemDir.mkdirs(); - systemSecureDir.mkdirs(); FileUtils.setPermissions(systemDir.toString(), FileUtils.S_IRWXU|FileUtils.S_IRWXG |FileUtils.S_IROTH|FileUtils.S_IXOTH, -1, -1); - FileUtils.setPermissions(systemSecureDir.toString(), - FileUtils.S_IRWXU|FileUtils.S_IRWXG - |FileUtils.S_IROTH|FileUtils.S_IXOTH, - -1, -1); mSettingsFilename = new File(systemDir, "packages.xml"); mBackupSettingsFilename = new File(systemDir, "packages-backup.xml"); mPackageListFilename = new File(systemDir, "packages.list"); diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java index 811221e..6a5ca1f 100644 --- a/services/java/com/android/server/am/ActivityManagerService.java +++ b/services/java/com/android/server/am/ActivityManagerService.java @@ -550,7 +550,7 @@ public final class ActivityManagerService extends ActivityManagerNative * Packages that the user has asked to have run in screen size * compatibility mode instead of filling the screen. */ - final HashSet<String> mScreenCompatPackages = new HashSet<String>(); + final CompatModePackages mCompatModePackages; /** * Set of PendingResultRecord objects that are currently active. @@ -1485,6 +1485,8 @@ public final class ActivityManagerService extends ActivityManagerNative mConfiguration.locale = Locale.getDefault(); mProcessStats.init(); + mCompatModePackages = new CompatModePackages(this, systemDir); + // Add ourself to the Watchdog monitors. Watchdog.getInstance().addMonitor(this); @@ -2099,70 +2101,30 @@ public final class ActivityManagerService extends ActivityManagerNative } CompatibilityInfo compatibilityInfoForPackageLocked(ApplicationInfo ai) { - return new CompatibilityInfo(ai, mConfiguration.screenLayout, - mScreenCompatPackages.contains(ai.packageName)); + return mCompatModePackages.compatibilityInfoForPackageLocked(ai); } - public void setPackageScreenCompatMode(String packageName, boolean compatEnabled) { + public int getFrontActivityScreenCompatMode() { synchronized (this) { - ApplicationInfo ai = null; - try { - ai = AppGlobals.getPackageManager(). - getApplicationInfo(packageName, STOCK_PM_FLAGS); - } catch (RemoteException e) { - } - if (ai == null) { - Slog.w(TAG, "setPackageScreenCompatMode failed: unknown package " + packageName); - return; - } - boolean changed = false; - if (compatEnabled) { - if (!mScreenCompatPackages.contains(packageName)) { - changed = true; - mScreenCompatPackages.add(packageName); - } - } else { - if (mScreenCompatPackages.contains(packageName)) { - changed = true; - mScreenCompatPackages.remove(packageName); - } - } - if (changed) { - CompatibilityInfo ci = compatibilityInfoForPackageLocked(ai); + return mCompatModePackages.getFrontActivityScreenCompatModeLocked(); + } + } - // Tell all processes that loaded this package about the change. - for (int i=mLruProcesses.size()-1; i>=0; i--) { - ProcessRecord app = mLruProcesses.get(i); - if (!app.pkgList.contains(packageName)) { - continue; - } - try { - if (app.thread != null) { - if (DEBUG_CONFIGURATION) Slog.v(TAG, "Sending to proc " - + app.processName + " new compat " + ci); - app.thread.updatePackageCompatibilityInfo(packageName, ci); - } - } catch (Exception e) { - } - } + public void setFrontActivityScreenCompatMode(int mode) { + synchronized (this) { + mCompatModePackages.setFrontActivityScreenCompatModeLocked(mode); + } + } - // All activities that came from the packge must be - // restarted as if there was a config change. - for (int i=mMainStack.mHistory.size()-1; i>=0; i--) { - ActivityRecord a = (ActivityRecord)mMainStack.mHistory.get(i); - if (a.info.packageName.equals(packageName)) { - a.forceNewConfig = true; - } - } + public int getPackageScreenCompatMode(String packageName) { + synchronized (this) { + return mCompatModePackages.getPackageScreenCompatModeLocked(packageName); + } + } - ActivityRecord starting = mMainStack.topRunningActivityLocked(null); - if (starting != null) { - mMainStack.ensureActivityConfigurationLocked(starting, 0); - // And we need to make sure at this point that all other activities - // are made visible with the correct configuration. - mMainStack.ensureActivitiesVisibleLocked(starting, 0); - } - } + public void setPackageScreenCompatMode(String packageName, int mode) { + synchronized (this) { + mCompatModePackages.setPackageScreenCompatModeLocked(packageName, mode); } } @@ -7855,9 +7817,9 @@ public final class ActivityManagerService extends ActivityManagerNative } pw.println(" mConfiguration: " + mConfiguration); pw.println(" mConfigWillChange: " + mMainStack.mConfigWillChange); - if (mScreenCompatPackages.size() > 0) { + if (mCompatModePackages.getPackages().size() > 0) { pw.print(" mScreenCompatPackages="); - pw.println(mScreenCompatPackages); + pw.println(mCompatModePackages.getPackages()); } pw.println(" mSleeping=" + mSleeping + " mShuttingDown=" + mShuttingDown); if (mDebugApp != null || mOrigDebugApp != null || mDebugTransient @@ -10706,10 +10668,10 @@ public final class ActivityManagerService extends ActivityManagerNative // Handle special intents: if this broadcast is from the package // manager about a package being removed, we need to remove all of // its activities from the history stack. - final boolean uidRemoved = intent.ACTION_UID_REMOVED.equals( + final boolean uidRemoved = Intent.ACTION_UID_REMOVED.equals( intent.getAction()); - if (intent.ACTION_PACKAGE_REMOVED.equals(intent.getAction()) - || intent.ACTION_PACKAGE_CHANGED.equals(intent.getAction()) + if (Intent.ACTION_PACKAGE_REMOVED.equals(intent.getAction()) + || Intent.ACTION_PACKAGE_CHANGED.equals(intent.getAction()) || Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE.equals(intent.getAction()) || uidRemoved) { if (checkComponentPermission( @@ -10746,7 +10708,7 @@ public final class ActivityManagerService extends ActivityManagerNative forceStopPackageLocked(ssp, intent.getIntExtra(Intent.EXTRA_UID, -1), false, true, true); } - if (intent.ACTION_PACKAGE_REMOVED.equals(intent.getAction())) { + if (Intent.ACTION_PACKAGE_REMOVED.equals(intent.getAction())) { sendPackageBroadcastLocked(IApplicationThread.PACKAGE_REMOVED, new String[] {ssp}); } @@ -10762,6 +10724,18 @@ public final class ActivityManagerService extends ActivityManagerNative Slog.w(TAG, msg); throw new SecurityException(msg); } + + // Special case for adding a package: by default turn on compatibility + // mode. + } else if (Intent.ACTION_PACKAGE_ADDED.equals(intent.getAction())) { + if (!intent.getBooleanExtra(Intent.EXTRA_REPLACING, false)) { + Uri data = intent.getData(); + String ssp; + if (data != null && (ssp=data.getSchemeSpecificPart()) != null) { + mCompatModePackages.setPackageScreenCompatModeLocked(ssp, + ActivityManager.COMPAT_MODE_ENABLED); + } + } } /* @@ -10920,9 +10894,9 @@ public final class ActivityManagerService extends ActivityManagerNative // broadcast or such for apps, but we'd like to deliberately make // this decision. String skipPackages[] = null; - if (intent.ACTION_PACKAGE_ADDED.equals(intent.getAction()) - || intent.ACTION_PACKAGE_RESTARTED.equals(intent.getAction()) - || intent.ACTION_PACKAGE_DATA_CLEARED.equals(intent.getAction())) { + if (Intent.ACTION_PACKAGE_ADDED.equals(intent.getAction()) + || Intent.ACTION_PACKAGE_RESTARTED.equals(intent.getAction()) + || Intent.ACTION_PACKAGE_DATA_CLEARED.equals(intent.getAction())) { Uri data = intent.getData(); if (data != null) { String pkgName = data.getSchemeSpecificPart(); @@ -10930,7 +10904,7 @@ public final class ActivityManagerService extends ActivityManagerNative skipPackages = new String[] { pkgName }; } } - } else if (intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE.equals(intent.getAction())) { + } else if (Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE.equals(intent.getAction())) { skipPackages = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST); } if (skipPackages != null && (skipPackages.length > 0)) { diff --git a/services/java/com/android/server/am/CompatModePackages.java b/services/java/com/android/server/am/CompatModePackages.java new file mode 100644 index 0000000..1faf8da --- /dev/null +++ b/services/java/com/android/server/am/CompatModePackages.java @@ -0,0 +1,295 @@ +package com.android.server.am; + +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.util.HashSet; +import java.util.Iterator; + +import org.xmlpull.v1.XmlPullParser; +import org.xmlpull.v1.XmlPullParserException; +import org.xmlpull.v1.XmlSerializer; + +import com.android.internal.os.AtomicFile; +import com.android.internal.util.FastXmlSerializer; + +import android.app.ActivityManager; +import android.app.AppGlobals; +import android.content.pm.ApplicationInfo; +import android.content.pm.IPackageManager; +import android.content.res.CompatibilityInfo; +import android.os.Handler; +import android.os.Message; +import android.os.RemoteException; +import android.util.Slog; +import android.util.Xml; + +public class CompatModePackages { + private final String TAG = ActivityManagerService.TAG; + private final boolean DEBUG_CONFIGURATION = ActivityManagerService.DEBUG_CONFIGURATION; + + private final ActivityManagerService mService; + private final AtomicFile mFile; + + private final HashSet<String> mPackages = new HashSet<String>(); + + private static final int MSG_WRITE = 1; + + private final Handler mHandler = new Handler() { + @Override public void handleMessage(Message msg) { + switch (msg.what) { + case MSG_WRITE: + saveCompatModes(); + break; + default: + super.handleMessage(msg); + break; + } + } + }; + + public CompatModePackages(ActivityManagerService service, File systemDir) { + mService = service; + mFile = new AtomicFile(new File(systemDir, "packages-compat.xml")); + + FileInputStream fis = null; + try { + fis = mFile.openRead(); + XmlPullParser parser = Xml.newPullParser(); + parser.setInput(fis, null); + int eventType = parser.getEventType(); + while (eventType != XmlPullParser.START_TAG) { + eventType = parser.next(); + } + String tagName = parser.getName(); + if ("compat-packages".equals(tagName)) { + eventType = parser.next(); + do { + if (eventType == XmlPullParser.START_TAG) { + tagName = parser.getName(); + if (parser.getDepth() == 2) { + if ("pkg".equals(tagName)) { + String pkg = parser.getAttributeValue(null, "name"); + if (pkg != null) { + mPackages.add(pkg); + } + } + } + } + eventType = parser.next(); + } while (eventType != XmlPullParser.END_DOCUMENT); + } + } catch (XmlPullParserException e) { + Slog.w(TAG, "Error reading compat-packages", e); + } catch (java.io.IOException e) { + if (fis != null) Slog.w(TAG, "Error reading compat-packages", e); + } finally { + if (fis != null) { + try { + fis.close(); + } catch (java.io.IOException e1) { + } + } + } + } + + public HashSet<String> getPackages() { + return mPackages; + } + + public CompatibilityInfo compatibilityInfoForPackageLocked(ApplicationInfo ai) { + return new CompatibilityInfo(ai, mService.mConfiguration.screenLayout, + mPackages.contains(ai.packageName)); + } + + private int computeCompatModeLocked(ApplicationInfo ai) { + boolean enabled = mPackages.contains(ai.packageName); + CompatibilityInfo info = new CompatibilityInfo(ai, + mService.mConfiguration.screenLayout, enabled); + if (info.alwaysSupportsScreen()) { + return ActivityManager.COMPAT_MODE_NEVER; + } + if (info.neverSupportsScreen()) { + return ActivityManager.COMPAT_MODE_ALWAYS; + } + return enabled ? ActivityManager.COMPAT_MODE_ENABLED + : ActivityManager.COMPAT_MODE_DISABLED; + } + + public int getFrontActivityScreenCompatModeLocked() { + ActivityRecord r = mService.mMainStack.topRunningActivityLocked(null); + if (r == null) { + return ActivityManager.COMPAT_MODE_UNKNOWN; + } + return computeCompatModeLocked(r.info.applicationInfo); + } + + public void setFrontActivityScreenCompatModeLocked(int mode) { + ActivityRecord r = mService.mMainStack.topRunningActivityLocked(null); + if (r == null) { + Slog.w(TAG, "setFrontActivityScreenCompatMode failed: no top activity"); + return; + } + setPackageScreenCompatModeLocked(r.info.applicationInfo, mode); + } + + public int getPackageScreenCompatModeLocked(String packageName) { + ApplicationInfo ai = null; + try { + ai = AppGlobals.getPackageManager().getApplicationInfo(packageName, 0); + } catch (RemoteException e) { + } + if (ai == null) { + return ActivityManager.COMPAT_MODE_UNKNOWN; + } + return computeCompatModeLocked(ai); + } + + public void setPackageScreenCompatModeLocked(String packageName, int mode) { + ApplicationInfo ai = null; + try { + ai = AppGlobals.getPackageManager().getApplicationInfo(packageName, 0); + } catch (RemoteException e) { + } + if (ai == null) { + Slog.w(TAG, "setPackageScreenCompatMode failed: unknown package " + packageName); + return; + } + setPackageScreenCompatModeLocked(ai, mode); + } + + private void setPackageScreenCompatModeLocked(ApplicationInfo ai, int mode) { + final String packageName = ai.packageName; + + boolean changed = false; + boolean enable; + switch (mode) { + case ActivityManager.COMPAT_MODE_DISABLED: + enable = false; + break; + case ActivityManager.COMPAT_MODE_ENABLED: + enable = true; + break; + case ActivityManager.COMPAT_MODE_TOGGLE: + enable = !mPackages.contains(packageName); + break; + default: + Slog.w(TAG, "Unknown screen compat mode req #" + mode + "; ignoring"); + return; + } + if (enable) { + if (!mPackages.contains(packageName)) { + changed = true; + mPackages.add(packageName); + } + } else { + if (mPackages.contains(packageName)) { + changed = true; + mPackages.remove(packageName); + } + } + if (changed) { + CompatibilityInfo ci = compatibilityInfoForPackageLocked(ai); + if (ci.alwaysSupportsScreen()) { + Slog.w(TAG, "Ignoring compat mode change of " + packageName + + "; compatibility never needed"); + return; + } + if (ci.neverSupportsScreen()) { + Slog.w(TAG, "Ignoring compat mode change of " + packageName + + "; compatibility always needed"); + return; + } + + mHandler.removeMessages(MSG_WRITE); + Message msg = mHandler.obtainMessage(MSG_WRITE); + mHandler.sendMessageDelayed(msg, 10000); + + // Tell all processes that loaded this package about the change. + for (int i=mService.mLruProcesses.size()-1; i>=0; i--) { + ProcessRecord app = mService.mLruProcesses.get(i); + if (!app.pkgList.contains(packageName)) { + continue; + } + try { + if (app.thread != null) { + if (DEBUG_CONFIGURATION) Slog.v(TAG, "Sending to proc " + + app.processName + " new compat " + ci); + app.thread.updatePackageCompatibilityInfo(packageName, ci); + } + } catch (Exception e) { + } + } + + // All activities that came from the packge must be + // restarted as if there was a config change. + for (int i=mService.mMainStack.mHistory.size()-1; i>=0; i--) { + ActivityRecord a = (ActivityRecord)mService.mMainStack.mHistory.get(i); + if (a.info.packageName.equals(packageName)) { + a.forceNewConfig = true; + } + } + + ActivityRecord starting = mService.mMainStack.topRunningActivityLocked(null); + if (starting != null) { + mService.mMainStack.ensureActivityConfigurationLocked(starting, 0); + // And we need to make sure at this point that all other activities + // are made visible with the correct configuration. + mService.mMainStack.ensureActivitiesVisibleLocked(starting, 0); + } + } + } + + void saveCompatModes() { + HashSet<String> pkgs; + synchronized (mService) { + pkgs = new HashSet<String>(mPackages); + } + + FileOutputStream fos = null; + + try { + fos = mFile.startWrite(); + XmlSerializer out = new FastXmlSerializer(); + out.setOutput(fos, "utf-8"); + out.startDocument(null, true); + out.setFeature("http://xmlpull.org/v1/doc/features.html#indent-output", true); + out.startTag(null, "compat-packages"); + + final IPackageManager pm = AppGlobals.getPackageManager(); + final int screenLayout = mService.mConfiguration.screenLayout; + final Iterator<String> it = pkgs.iterator(); + while (it.hasNext()) { + String pkg = it.next(); + ApplicationInfo ai = null; + try { + ai = pm.getApplicationInfo(pkg, 0); + } catch (RemoteException e) { + } + if (ai == null) { + continue; + } + CompatibilityInfo info = new CompatibilityInfo(ai, screenLayout, false); + if (info.alwaysSupportsScreen()) { + continue; + } + if (info.neverSupportsScreen()) { + continue; + } + out.startTag(null, "pkg"); + out.attribute(null, "name", pkg); + out.endTag(null, "pkg"); + } + + out.endTag(null, "compat-packages"); + out.endDocument(); + + mFile.finishWrite(fos); + } catch (java.io.IOException e1) { + Slog.w(TAG, "Error writing compat packages", e1); + if (fos != null) { + mFile.failWrite(fos); + } + } + } +} |