summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--cmds/am/src/com/android/commands/am/Am.java27
-rw-r--r--core/java/android/app/ActivityManagerNative.java23
-rw-r--r--core/java/android/app/ActivityThread.java167
-rw-r--r--core/java/android/app/ApplicationThreadNative.java65
-rw-r--r--core/java/android/app/ContextImpl.java4
-rw-r--r--core/java/android/app/IActivityManager.java4
-rw-r--r--core/java/android/app/IApplicationThread.java23
-rw-r--r--core/java/android/app/LoadedApk.java10
-rw-r--r--core/java/android/content/res/CompatibilityInfo.java358
-rw-r--r--core/java/android/content/res/Configuration.java21
-rwxr-xr-xcore/java/android/content/res/Resources.java31
-rw-r--r--core/java/android/util/DisplayMetrics.java108
-rw-r--r--core/java/android/view/Display.java3
-rw-r--r--core/java/android/view/WindowManagerPolicy.java12
-rw-r--r--include/ui/Input.h2
-rw-r--r--libs/ui/Input.cpp47
-rwxr-xr-xpolicy/src/com/android/internal/policy/impl/PhoneWindowManager.java13
-rw-r--r--services/input/InputDispatcher.cpp71
-rw-r--r--services/input/InputDispatcher.h7
-rw-r--r--services/input/InputWindow.cpp3
-rw-r--r--services/input/InputWindow.h6
-rw-r--r--services/java/com/android/server/am/ActivityManagerService.java103
-rw-r--r--services/java/com/android/server/am/ActivityRecord.java4
-rw-r--r--services/java/com/android/server/am/ActivityStack.java11
-rw-r--r--services/java/com/android/server/am/ProcessRecord.java1
-rw-r--r--services/java/com/android/server/wm/InputMonitor.java11
-rw-r--r--services/java/com/android/server/wm/InputWindow.java4
-rw-r--r--services/java/com/android/server/wm/WindowManagerService.java65
-rw-r--r--services/java/com/android/server/wm/WindowState.java129
-rw-r--r--services/jni/com_android_server_InputWindow.cpp6
-rw-r--r--tests/DpiTest/src/com/google/android/test/dpi/DpiTestActivity.java3
31 files changed, 891 insertions, 451 deletions
diff --git a/cmds/am/src/com/android/commands/am/Am.java b/cmds/am/src/com/android/commands/am/Am.java
index b073004..5c8abe4 100644
--- a/cmds/am/src/com/android/commands/am/Am.java
+++ b/cmds/am/src/com/android/commands/am/Am.java
@@ -106,6 +106,8 @@ public class Am {
runDumpHeap();
} else if (op.equals("monitor")) {
runMonitor();
+ } else if (op.equals("screen-compat")) {
+ runScreenCompat();
} else {
throw new IllegalArgumentException("Unknown command: " + op);
}
@@ -776,6 +778,29 @@ public class Am {
controller.run();
}
+ private void runScreenCompat() throws Exception {
+ String mode = nextArgRequired();
+ boolean enabled;
+ if ("on".equals(mode)) {
+ enabled = true;
+ } else if ("off".equals(mode)) {
+ enabled = false;
+ } else {
+ System.err.println("Error: enabled mode must be 'on' or 'off' at " + mode);
+ showUsage();
+ return;
+ }
+
+ String packageName = nextArgRequired();
+ do {
+ try {
+ mAm.setPackageScreenCompatMode(packageName, enabled);
+ } catch (RemoteException e) {
+ }
+ packageName = nextArg();
+ } while (packageName != null);
+ }
+
private class IntentReceiver extends IIntentReceiver.Stub {
private boolean mFinished = false;
@@ -956,6 +981,8 @@ public class Am {
" start monitoring: am monitor [--gdb <port>]\n" +
" --gdb: start gdbserv on the given port at crash/ANR\n" +
"\n" +
+ " control screen compatibility: am screen-compat [on|off] [package]\n" +
+ "\n" +
" <INTENT> specifications include these flags:\n" +
" [-a <ACTION>] [-d <DATA_URI>] [-t <MIME_TYPE>]\n" +
" [-c <CATEGORY> [-c <CATEGORY>] ...]\n" +
diff --git a/core/java/android/app/ActivityManagerNative.java b/core/java/android/app/ActivityManagerNative.java
index 6426635..11e9975 100644
--- a/core/java/android/app/ActivityManagerNative.java
+++ b/core/java/android/app/ActivityManagerNative.java
@@ -1398,6 +1398,16 @@ public abstract class ActivityManagerNative extends Binder implements IActivityM
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);
+ reply.writeNoException();
+ return true;
+ }
+
}
return super.onTransact(code, data, reply, flags);
@@ -3142,5 +3152,18 @@ class ActivityManagerProxy implements IActivityManager
return result;
}
+ public void setPackageScreenCompatMode(String packageName, boolean compatEnabled)
+ throws RemoteException {
+ Parcel data = Parcel.obtain();
+ Parcel reply = Parcel.obtain();
+ data.writeInterfaceToken(IActivityManager.descriptor);
+ data.writeString(packageName);
+ data.writeInt(compatEnabled ? 1 : 0);
+ mRemote.transact(SET_PACKAGE_SCREEN_COMPAT_MODE_TRANSACTION, data, reply, 0);
+ reply.readException();
+ reply.recycle();
+ data.recycle();
+ }
+
private IBinder mRemote;
}
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index bd83762..67e8839 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -202,7 +202,7 @@ public final class ActivityThread {
Bundle mCoreSettings = null;
- private static final class ActivityClientRecord {
+ static final class ActivityClientRecord {
IBinder token;
int ident;
Intent intent;
@@ -220,6 +220,7 @@ public final class ActivityThread {
ActivityClientRecord nextIdle;
ActivityInfo activityInfo;
+ CompatibilityInfo compatInfo;
LoadedApk packageInfo;
List<ResultInfo> pendingResults;
@@ -260,7 +261,7 @@ public final class ActivityThread {
}
}
- private final class ProviderClientRecord implements IBinder.DeathRecipient {
+ final class ProviderClientRecord implements IBinder.DeathRecipient {
final String mName;
final IContentProvider mProvider;
final ContentProvider mLocalProvider;
@@ -277,7 +278,7 @@ public final class ActivityThread {
}
}
- private static final class NewIntentData {
+ static final class NewIntentData {
List<Intent> intents;
IBinder token;
public String toString() {
@@ -285,7 +286,7 @@ public final class ActivityThread {
}
}
- private static final class ReceiverData extends BroadcastReceiver.PendingResult {
+ static final class ReceiverData extends BroadcastReceiver.PendingResult {
public ReceiverData(Intent intent, int resultCode, String resultData, Bundle resultExtras,
boolean ordered, boolean sticky, IBinder token) {
super(resultCode, resultData, resultExtras, TYPE_COMPONENT, ordered, sticky, token);
@@ -294,6 +295,7 @@ public final class ActivityThread {
Intent intent;
ActivityInfo info;
+ CompatibilityInfo compatInfo;
public String toString() {
return "ReceiverData{intent=" + intent + " packageName=" +
info.packageName + " resultCode=" + getResultCode()
@@ -302,8 +304,9 @@ public final class ActivityThread {
}
}
- private static final class CreateBackupAgentData {
+ static final class CreateBackupAgentData {
ApplicationInfo appInfo;
+ CompatibilityInfo compatInfo;
int backupMode;
public String toString() {
return "CreateBackupAgentData{appInfo=" + appInfo
@@ -312,9 +315,10 @@ public final class ActivityThread {
}
}
- private static final class CreateServiceData {
+ static final class CreateServiceData {
IBinder token;
ServiceInfo info;
+ CompatibilityInfo compatInfo;
Intent intent;
public String toString() {
return "CreateServiceData{token=" + token + " className="
@@ -323,7 +327,7 @@ public final class ActivityThread {
}
}
- private static final class BindServiceData {
+ static final class BindServiceData {
IBinder token;
Intent intent;
boolean rebind;
@@ -332,7 +336,7 @@ public final class ActivityThread {
}
}
- private static final class ServiceArgsData {
+ static final class ServiceArgsData {
IBinder token;
int startId;
int flags;
@@ -343,7 +347,7 @@ public final class ActivityThread {
}
}
- private static final class AppBindData {
+ static final class AppBindData {
LoadedApk info;
String processName;
ApplicationInfo appInfo;
@@ -355,13 +359,14 @@ public final class ActivityThread {
int debugMode;
boolean restrictedBackupMode;
Configuration config;
+ CompatibilityInfo compatInfo;
boolean handlingProfiling;
public String toString() {
return "AppBindData{appInfo=" + appInfo + "}";
}
}
- private static final class DumpComponentInfo {
+ static final class DumpComponentInfo {
FileDescriptor fd;
IBinder token;
String prefix;
@@ -369,7 +374,7 @@ public final class ActivityThread {
boolean dumped;
}
- private static final class ResultData {
+ static final class ResultData {
IBinder token;
List<ResultInfo> results;
public String toString() {
@@ -377,22 +382,27 @@ public final class ActivityThread {
}
}
- private static final class ContextCleanupInfo {
+ static final class ContextCleanupInfo {
ContextImpl context;
String what;
String who;
}
- private static final class ProfilerControlData {
+ static final class ProfilerControlData {
String path;
ParcelFileDescriptor fd;
}
- private static final class DumpHeapData {
+ static final class DumpHeapData {
String path;
ParcelFileDescriptor fd;
}
+ static final class UpdateCompatibilityData {
+ String pkg;
+ CompatibilityInfo info;
+ }
+
private final class ApplicationThread extends ApplicationThreadNative {
private static final String HEAP_COLUMN = "%17s %8s %8s %8s %8s";
private static final String ONE_COUNT_COLUMN = "%17s %8d";
@@ -443,7 +453,8 @@ public final class ActivityThread {
// we use token to identify this activity without having to send the
// activity itself back to the activity manager. (matters more with ipc)
public final void scheduleLaunchActivity(Intent intent, IBinder token, int ident,
- ActivityInfo info, Bundle state, List<ResultInfo> pendingResults,
+ ActivityInfo info, CompatibilityInfo compatInfo, Bundle state,
+ List<ResultInfo> pendingResults,
List<Intent> pendingNewIntents, boolean notResumed, boolean isForward) {
ActivityClientRecord r = new ActivityClientRecord();
@@ -451,6 +462,7 @@ public final class ActivityThread {
r.ident = ident;
r.intent = intent;
r.activityInfo = info;
+ r.compatInfo = compatInfo;
r.state = state;
r.pendingResults = pendingResults;
@@ -484,33 +496,40 @@ public final class ActivityThread {
}
public final void scheduleReceiver(Intent intent, ActivityInfo info,
- int resultCode, String data, Bundle extras, boolean sync) {
+ CompatibilityInfo compatInfo, int resultCode, String data, Bundle extras,
+ boolean sync) {
ReceiverData r = new ReceiverData(intent, resultCode, data, extras,
sync, false, mAppThread.asBinder());
r.info = info;
+ r.compatInfo = compatInfo;
queueOrSendMessage(H.RECEIVER, r);
}
- public final void scheduleCreateBackupAgent(ApplicationInfo app, int backupMode) {
+ public final void scheduleCreateBackupAgent(ApplicationInfo app,
+ CompatibilityInfo compatInfo, int backupMode) {
CreateBackupAgentData d = new CreateBackupAgentData();
d.appInfo = app;
+ d.compatInfo = compatInfo;
d.backupMode = backupMode;
queueOrSendMessage(H.CREATE_BACKUP_AGENT, d);
}
- public final void scheduleDestroyBackupAgent(ApplicationInfo app) {
+ public final void scheduleDestroyBackupAgent(ApplicationInfo app,
+ CompatibilityInfo compatInfo) {
CreateBackupAgentData d = new CreateBackupAgentData();
d.appInfo = app;
+ d.compatInfo = compatInfo;
queueOrSendMessage(H.DESTROY_BACKUP_AGENT, d);
}
public final void scheduleCreateService(IBinder token,
- ServiceInfo info) {
+ ServiceInfo info, CompatibilityInfo compatInfo) {
CreateServiceData s = new CreateServiceData();
s.token = token;
s.info = info;
+ s.compatInfo = compatInfo;
queueOrSendMessage(H.CREATE_SERVICE, s);
}
@@ -553,7 +572,8 @@ public final class ActivityThread {
ComponentName instrumentationName, String profileFile,
Bundle instrumentationArgs, IInstrumentationWatcher instrumentationWatcher,
int debugMode, boolean isRestrictedBackupMode, Configuration config,
- Map<String, IBinder> services, Bundle coreSettings) {
+ CompatibilityInfo compatInfo, Map<String, IBinder> services,
+ Bundle coreSettings) {
if (services != null) {
// Setup the service cache in the ServiceManager
@@ -573,6 +593,7 @@ public final class ActivityThread {
data.debugMode = debugMode;
data.restrictedBackupMode = isRestrictedBackupMode;
data.config = config;
+ data.compatInfo = compatInfo;
queueOrSendMessage(H.BIND_APPLICATION, data);
}
@@ -903,6 +924,13 @@ public final class ActivityThread {
public void setCoreSettings(Bundle coreSettings) {
queueOrSendMessage(H.SET_CORE_SETTINGS, coreSettings);
}
+
+ public void updatePackageCompatibilityInfo(String pkg, CompatibilityInfo info) {
+ UpdateCompatibilityData ucd = new UpdateCompatibilityData();
+ ucd.pkg = pkg;
+ ucd.info = info;
+ queueOrSendMessage(H.UPDATE_PACKAGE_COMPATIBILITY_INFO, ucd);
+ }
}
private final class H extends Handler {
@@ -945,6 +973,7 @@ public final class ActivityThread {
public static final int DUMP_ACTIVITY = 136;
public static final int SLEEPING = 137;
public static final int SET_CORE_SETTINGS = 138;
+ public static final int UPDATE_PACKAGE_COMPATIBILITY_INFO = 139;
String codeToString(int code) {
if (DEBUG_MESSAGES) {
switch (code) {
@@ -987,6 +1016,7 @@ public final class ActivityThread {
case DUMP_ACTIVITY: return "DUMP_ACTIVITY";
case SLEEPING: return "SLEEPING";
case SET_CORE_SETTINGS: return "SET_CORE_SETTINGS";
+ case UPDATE_PACKAGE_COMPATIBILITY_INFO: return "UPDATE_PACKAGE_COMPATIBILITY_INFO";
}
}
return "(unknown)";
@@ -998,7 +1028,7 @@ public final class ActivityThread {
ActivityClientRecord r = (ActivityClientRecord)msg.obj;
r.packageInfo = getPackageInfoNoCheck(
- r.activityInfo.applicationInfo);
+ r.activityInfo.applicationInfo, r.compatInfo);
handleLaunchActivity(r, null);
} break;
case RELAUNCH_ACTIVITY: {
@@ -1072,7 +1102,7 @@ public final class ActivityThread {
handleRequestThumbnail((IBinder)msg.obj);
break;
case CONFIGURATION_CHANGED:
- handleConfigurationChanged((Configuration)msg.obj);
+ handleConfigurationChanged((Configuration)msg.obj, null);
break;
case CLEAN_UP_CONTEXT:
ContextCleanupInfo cci = (ContextCleanupInfo)msg.obj;
@@ -1125,6 +1155,8 @@ public final class ActivityThread {
case SET_CORE_SETTINGS:
handleSetCoreSettings((Bundle) msg.obj);
break;
+ case UPDATE_PACKAGE_COMPATIBILITY_INFO:
+ handleUpdatePackageCompatibilityInfo((UpdateCompatibilityData)msg.obj);
}
if (DEBUG_MESSAGES) Slog.v(TAG, "<<< done: " + msg.what);
}
@@ -1335,7 +1367,8 @@ public final class ActivityThread {
return mH;
}
- public final LoadedApk getPackageInfo(String packageName, int flags) {
+ public final LoadedApk getPackageInfo(String packageName, CompatibilityInfo compatInfo,
+ int flags) {
synchronized (mPackages) {
WeakReference<LoadedApk> ref;
if ((flags&Context.CONTEXT_INCLUDE_CODE) != 0) {
@@ -1369,13 +1402,14 @@ public final class ActivityThread {
}
if (ai != null) {
- return getPackageInfo(ai, flags);
+ return getPackageInfo(ai, compatInfo, flags);
}
return null;
}
- public final LoadedApk getPackageInfo(ApplicationInfo ai, int flags) {
+ public final LoadedApk getPackageInfo(ApplicationInfo ai, CompatibilityInfo compatInfo,
+ int flags) {
boolean includeCode = (flags&Context.CONTEXT_INCLUDE_CODE) != 0;
boolean securityViolation = includeCode && ai.uid != 0
&& ai.uid != Process.SYSTEM_UID && (mBoundApplication != null
@@ -1394,14 +1428,27 @@ public final class ActivityThread {
throw new SecurityException(msg);
}
}
- return getPackageInfo(ai, null, securityViolation, includeCode);
+ return getPackageInfo(ai, compatInfo, null, securityViolation, includeCode);
}
- public final LoadedApk getPackageInfoNoCheck(ApplicationInfo ai) {
- return getPackageInfo(ai, null, false, true);
+ public final LoadedApk getPackageInfoNoCheck(ApplicationInfo ai,
+ CompatibilityInfo compatInfo) {
+ return getPackageInfo(ai, compatInfo, null, false, true);
}
- private final LoadedApk getPackageInfo(ApplicationInfo aInfo,
+ public final LoadedApk peekPackageInfo(String packageName, boolean includeCode) {
+ synchronized (mPackages) {
+ WeakReference<LoadedApk> ref;
+ if (includeCode) {
+ ref = mPackages.get(packageName);
+ } else {
+ ref = mResourcePackages.get(packageName);
+ }
+ return ref != null ? ref.get() : null;
+ }
+ }
+
+ private final LoadedApk getPackageInfo(ApplicationInfo aInfo, CompatibilityInfo compatInfo,
ClassLoader baseLoader, boolean securityViolation, boolean includeCode) {
synchronized (mPackages) {
WeakReference<LoadedApk> ref;
@@ -1419,7 +1466,7 @@ public final class ActivityThread {
? mBoundApplication.processName : null)
+ ")");
packageInfo =
- new LoadedApk(this, aInfo, this, baseLoader,
+ new LoadedApk(this, aInfo, compatInfo, this, baseLoader,
securityViolation, includeCode &&
(aInfo.flags&ApplicationInfo.FLAG_HAS_CODE) != 0);
if (includeCode) {
@@ -1476,7 +1523,8 @@ public final class ActivityThread {
if (mSystemContext == null) {
ContextImpl context =
ContextImpl.createSystemContext(this);
- LoadedApk info = new LoadedApk(this, "android", context, null);
+ LoadedApk info = new LoadedApk(this, "android", context, null,
+ CompatibilityInfo.DEFAULT_COMPATIBILITY_INFO);
context.init(info, null, this);
context.getResources().updateConfiguration(
getConfiguration(), getDisplayMetricsLocked(false));
@@ -1491,7 +1539,8 @@ public final class ActivityThread {
public void installSystemApplicationInfo(ApplicationInfo info) {
synchronized (this) {
ContextImpl context = getSystemContext();
- context.init(new LoadedApk(this, "android", context, info), null, this);
+ context.init(new LoadedApk(this, "android", context, info,
+ new CompatibilityInfo(info, 0, false)), null, this);
}
}
@@ -1641,7 +1690,7 @@ public final class ActivityThread {
ActivityInfo aInfo = r.activityInfo;
if (r.packageInfo == null) {
- r.packageInfo = getPackageInfo(aInfo.applicationInfo,
+ r.packageInfo = getPackageInfo(aInfo.applicationInfo, r.compatInfo,
Context.CONTEXT_INCLUDE_CODE);
}
@@ -1865,7 +1914,7 @@ public final class ActivityThread {
String component = data.intent.getComponent().getClassName();
LoadedApk packageInfo = getPackageInfoNoCheck(
- data.info.applicationInfo);
+ data.info.applicationInfo, data.compatInfo);
IActivityManager mgr = ActivityManagerNative.getDefault();
@@ -1926,7 +1975,7 @@ public final class ActivityThread {
unscheduleGcIdler();
// instantiate the BackupAgent class named in the manifest
- LoadedApk packageInfo = getPackageInfoNoCheck(data.appInfo);
+ LoadedApk packageInfo = getPackageInfoNoCheck(data.appInfo, data.compatInfo);
String packageName = packageInfo.mPackageName;
if (mBackupAgents.get(packageName) != null) {
Slog.d(TAG, "BackupAgent " + " for " + packageName
@@ -1988,7 +2037,7 @@ public final class ActivityThread {
private final void handleDestroyBackupAgent(CreateBackupAgentData data) {
if (DEBUG_BACKUP) Slog.v(TAG, "handleDestroyBackupAgent: " + data);
- LoadedApk packageInfo = getPackageInfoNoCheck(data.appInfo);
+ LoadedApk packageInfo = getPackageInfoNoCheck(data.appInfo, data.compatInfo);
String packageName = packageInfo.mPackageName;
BackupAgent agent = mBackupAgents.get(packageName);
if (agent != null) {
@@ -2010,7 +2059,7 @@ public final class ActivityThread {
unscheduleGcIdler();
LoadedApk packageInfo = getPackageInfoNoCheck(
- data.info.applicationInfo);
+ data.info.applicationInfo, data.compatInfo);
Service service = null;
try {
java.lang.ClassLoader cl = packageInfo.getClassLoader();
@@ -2727,6 +2776,18 @@ public final class ActivityThread {
}
}
+ private void handleUpdatePackageCompatibilityInfo(UpdateCompatibilityData data) {
+ LoadedApk apk = peekPackageInfo(data.pkg, false);
+ if (apk != null) {
+ apk.mCompatibilityInfo = data.info;
+ }
+ apk = peekPackageInfo(data.pkg, true);
+ if (apk != null) {
+ apk.mCompatibilityInfo = data.info;
+ }
+ handleConfigurationChanged(mConfiguration, data.info);
+ }
+
private final void deliverResults(ActivityClientRecord r, List<ResultInfo> results) {
final int N = results.size();
for (int i=0; i<N; i++) {
@@ -3064,7 +3125,7 @@ public final class ActivityThread {
// If there was a pending configuration change, execute it first.
if (changedConfig != null) {
- handleConfigurationChanged(changedConfig);
+ handleConfigurationChanged(changedConfig, null);
}
ActivityClientRecord r = mActivities.get(tmp.token);
@@ -3234,11 +3295,12 @@ public final class ActivityThread {
}
}
- final boolean applyConfigurationToResourcesLocked(Configuration config) {
+ final boolean applyConfigurationToResourcesLocked(Configuration config,
+ CompatibilityInfo compat) {
if (mResConfiguration == null) {
mResConfiguration = new Configuration();
}
- if (!mResConfiguration.isOtherSeqNewer(config)) {
+ if (!mResConfiguration.isOtherSeqNewer(config) && compat == null) {
if (DEBUG_CONFIGURATION) Slog.v(TAG, "Skipping new config: curSeq="
+ mResConfiguration.seq + ", newSeq=" + config.seq);
return false;
@@ -3251,7 +3313,7 @@ public final class ActivityThread {
Locale.setDefault(config.locale);
}
- Resources.updateSystemConfiguration(config, dm);
+ Resources.updateSystemConfiguration(config, dm, compat);
ApplicationPackageManager.configurationChanged();
//Slog.i(TAG, "Configuration changed in " + currentPackageName());
@@ -3266,7 +3328,7 @@ public final class ActivityThread {
if (r != null) {
if (DEBUG_CONFIGURATION) Slog.v(TAG, "Changing resources "
+ r + " config to: " + config);
- r.updateConfiguration(config, dm);
+ r.updateConfiguration(config, dm, compat);
//Slog.i(TAG, "Updated app resources " + v.getKey()
// + " " + r + ": " + r.getConfiguration());
} else {
@@ -3278,7 +3340,7 @@ public final class ActivityThread {
return changes != 0;
}
- final void handleConfigurationChanged(Configuration config) {
+ final void handleConfigurationChanged(Configuration config, CompatibilityInfo compat) {
ArrayList<ComponentCallbacks> callbacks = null;
@@ -3297,15 +3359,21 @@ public final class ActivityThread {
if (DEBUG_CONFIGURATION) Slog.v(TAG, "Handle configuration changed: "
+ config);
- applyConfigurationToResourcesLocked(config);
+ applyConfigurationToResourcesLocked(config, compat);
if (mConfiguration == null) {
mConfiguration = new Configuration();
}
- if (!mConfiguration.isOtherSeqNewer(config)) {
+ if (!mConfiguration.isOtherSeqNewer(config) && compat == null) {
return;
}
mConfiguration.updateFrom(config);
+ if (compat != null) {
+ // Can't do this here, because it causes us to report the
+ // comatible config back to the am as the current config
+ // of the activity, and much unhappiness results.
+ //compat.applyToConfiguration(mConfiguration);
+ }
callbacks = collectComponentCallbacksLocked(false, config);
}
@@ -3445,9 +3513,10 @@ public final class ActivityThread {
* reflect configuration changes. The configuration object passed
* in AppBindData can be safely assumed to be up to date
*/
- Resources.getSystem().updateConfiguration(mConfiguration, null);
+ Resources.getSystem().updateConfiguration(mConfiguration,
+ Resources.getSystem().getDisplayMetrics(), data.compatInfo);
- data.info = getPackageInfoNoCheck(data.appInfo);
+ data.info = getPackageInfoNoCheck(data.appInfo, data.compatInfo);
/**
* For system applications on userdebug/eng builds, log stack
@@ -3539,7 +3608,7 @@ public final class ActivityThread {
instrApp.publicSourceDir = ii.publicSourceDir;
instrApp.dataDir = ii.dataDir;
instrApp.nativeLibraryDir = ii.nativeLibraryDir;
- LoadedApk pi = getPackageInfo(instrApp,
+ LoadedApk pi = getPackageInfo(instrApp, data.compatInfo,
appContext.getClassLoader(), false, true);
ContextImpl instrContext = new ContextImpl();
instrContext.init(pi, null, this);
@@ -3953,7 +4022,7 @@ public final class ActivityThread {
// We need to apply this change to the resources
// immediately, because upon returning the view
// hierarchy will be informed about it.
- if (applyConfigurationToResourcesLocked(newConfig)) {
+ if (applyConfigurationToResourcesLocked(newConfig, null)) {
// This actually changed the resources! Tell
// everyone about it.
if (mPendingConfiguration == null ||
diff --git a/core/java/android/app/ApplicationThreadNative.java b/core/java/android/app/ApplicationThreadNative.java
index aa26b04..e1d76a4 100644
--- a/core/java/android/app/ApplicationThreadNative.java
+++ b/core/java/android/app/ApplicationThreadNative.java
@@ -23,6 +23,7 @@ import android.content.pm.ActivityInfo;
import android.content.pm.ApplicationInfo;
import android.content.pm.ProviderInfo;
import android.content.pm.ServiceInfo;
+import android.content.res.CompatibilityInfo;
import android.content.res.Configuration;
import android.os.Binder;
import android.os.Bundle;
@@ -131,12 +132,13 @@ public abstract class ApplicationThreadNative extends Binder
IBinder b = data.readStrongBinder();
int ident = data.readInt();
ActivityInfo info = ActivityInfo.CREATOR.createFromParcel(data);
+ CompatibilityInfo compatInfo = CompatibilityInfo.CREATOR.createFromParcel(data);
Bundle state = data.readBundle();
List<ResultInfo> ri = data.createTypedArrayList(ResultInfo.CREATOR);
List<Intent> pi = data.createTypedArrayList(Intent.CREATOR);
boolean notResumed = data.readInt() != 0;
boolean isForward = data.readInt() != 0;
- scheduleLaunchActivity(intent, b, ident, info, state, ri, pi,
+ scheduleLaunchActivity(intent, b, ident, info, compatInfo, state, ri, pi,
notResumed, isForward);
return true;
}
@@ -181,11 +183,12 @@ public abstract class ApplicationThreadNative extends Binder
data.enforceInterface(IApplicationThread.descriptor);
Intent intent = Intent.CREATOR.createFromParcel(data);
ActivityInfo info = ActivityInfo.CREATOR.createFromParcel(data);
+ CompatibilityInfo compatInfo = CompatibilityInfo.CREATOR.createFromParcel(data);
int resultCode = data.readInt();
String resultData = data.readString();
Bundle resultExtras = data.readBundle();
boolean sync = data.readInt() != 0;
- scheduleReceiver(intent, info, resultCode, resultData,
+ scheduleReceiver(intent, info, compatInfo, resultCode, resultData,
resultExtras, sync);
return true;
}
@@ -194,7 +197,8 @@ public abstract class ApplicationThreadNative extends Binder
data.enforceInterface(IApplicationThread.descriptor);
IBinder token = data.readStrongBinder();
ServiceInfo info = ServiceInfo.CREATOR.createFromParcel(data);
- scheduleCreateService(token, info);
+ CompatibilityInfo compatInfo = CompatibilityInfo.CREATOR.createFromParcel(data);
+ scheduleCreateService(token, info, compatInfo);
return true;
}
@@ -256,12 +260,13 @@ public abstract class ApplicationThreadNative extends Binder
int testMode = data.readInt();
boolean restrictedBackupMode = (data.readInt() != 0);
Configuration config = Configuration.CREATOR.createFromParcel(data);
+ CompatibilityInfo compatInfo = CompatibilityInfo.CREATOR.createFromParcel(data);
HashMap<String, IBinder> services = data.readHashMap(null);
Bundle coreSettings = data.readBundle();
bindApplication(packageName, info,
providers, testName, profileName,
testArgs, testWatcher, testMode, restrictedBackupMode,
- config, services, coreSettings);
+ config, compatInfo, services, coreSettings);
return true;
}
@@ -389,8 +394,9 @@ public abstract class ApplicationThreadNative extends Binder
{
data.enforceInterface(IApplicationThread.descriptor);
ApplicationInfo appInfo = ApplicationInfo.CREATOR.createFromParcel(data);
+ CompatibilityInfo compatInfo = CompatibilityInfo.CREATOR.createFromParcel(data);
int backupMode = data.readInt();
- scheduleCreateBackupAgent(appInfo, backupMode);
+ scheduleCreateBackupAgent(appInfo, compatInfo, backupMode);
return true;
}
@@ -398,7 +404,8 @@ public abstract class ApplicationThreadNative extends Binder
{
data.enforceInterface(IApplicationThread.descriptor);
ApplicationInfo appInfo = ApplicationInfo.CREATOR.createFromParcel(data);
- scheduleDestroyBackupAgent(appInfo);
+ CompatibilityInfo compatInfo = CompatibilityInfo.CREATOR.createFromParcel(data);
+ scheduleDestroyBackupAgent(appInfo, compatInfo);
return true;
}
@@ -456,12 +463,20 @@ public abstract class ApplicationThreadNative extends Binder
return true;
}
- case SET_CORE_SETTINGS: {
+ case SET_CORE_SETTINGS_TRANSACTION: {
data.enforceInterface(IApplicationThread.descriptor);
Bundle settings = data.readBundle();
setCoreSettings(settings);
return true;
}
+
+ case UPDATE_PACKAGE_COMPATIBILITY_INFO_TRANSACTION: {
+ data.enforceInterface(IApplicationThread.descriptor);
+ String pkg = data.readString();
+ CompatibilityInfo compat = CompatibilityInfo.CREATOR.createFromParcel(data);
+ updatePackageCompatibilityInfo(pkg, compat);
+ return true;
+ }
}
return super.onTransact(code, data, reply, flags);
@@ -554,7 +569,8 @@ class ApplicationThreadProxy implements IApplicationThread {
}
public final void scheduleLaunchActivity(Intent intent, IBinder token, int ident,
- ActivityInfo info, Bundle state, List<ResultInfo> pendingResults,
+ ActivityInfo info, CompatibilityInfo compatInfo, Bundle state,
+ List<ResultInfo> pendingResults,
List<Intent> pendingNewIntents, boolean notResumed, boolean isForward)
throws RemoteException {
Parcel data = Parcel.obtain();
@@ -563,6 +579,7 @@ class ApplicationThreadProxy implements IApplicationThread {
data.writeStrongBinder(token);
data.writeInt(ident);
info.writeToParcel(data, 0);
+ compatInfo.writeToParcel(data, 0);
data.writeBundle(state);
data.writeTypedList(pendingResults);
data.writeTypedList(pendingNewIntents);
@@ -619,12 +636,13 @@ class ApplicationThreadProxy implements IApplicationThread {
}
public final void scheduleReceiver(Intent intent, ActivityInfo info,
- int resultCode, String resultData,
+ CompatibilityInfo compatInfo, int resultCode, String resultData,
Bundle map, boolean sync) throws RemoteException {
Parcel data = Parcel.obtain();
data.writeInterfaceToken(IApplicationThread.descriptor);
intent.writeToParcel(data, 0);
info.writeToParcel(data, 0);
+ compatInfo.writeToParcel(data, 0);
data.writeInt(resultCode);
data.writeString(resultData);
data.writeBundle(map);
@@ -634,32 +652,36 @@ class ApplicationThreadProxy implements IApplicationThread {
data.recycle();
}
- public final void scheduleCreateBackupAgent(ApplicationInfo app, int backupMode)
- throws RemoteException {
+ public final void scheduleCreateBackupAgent(ApplicationInfo app,
+ CompatibilityInfo compatInfo, int backupMode) throws RemoteException {
Parcel data = Parcel.obtain();
data.writeInterfaceToken(IApplicationThread.descriptor);
app.writeToParcel(data, 0);
+ compatInfo.writeToParcel(data, 0);
data.writeInt(backupMode);
mRemote.transact(SCHEDULE_CREATE_BACKUP_AGENT_TRANSACTION, data, null,
IBinder.FLAG_ONEWAY);
data.recycle();
}
- public final void scheduleDestroyBackupAgent(ApplicationInfo app) throws RemoteException {
+ public final void scheduleDestroyBackupAgent(ApplicationInfo app,
+ CompatibilityInfo compatInfo) throws RemoteException {
Parcel data = Parcel.obtain();
data.writeInterfaceToken(IApplicationThread.descriptor);
app.writeToParcel(data, 0);
+ compatInfo.writeToParcel(data, 0);
mRemote.transact(SCHEDULE_DESTROY_BACKUP_AGENT_TRANSACTION, data, null,
IBinder.FLAG_ONEWAY);
data.recycle();
}
- public final void scheduleCreateService(IBinder token, ServiceInfo info)
- throws RemoteException {
+ public final void scheduleCreateService(IBinder token, ServiceInfo info,
+ CompatibilityInfo compatInfo) throws RemoteException {
Parcel data = Parcel.obtain();
data.writeInterfaceToken(IApplicationThread.descriptor);
data.writeStrongBinder(token);
info.writeToParcel(data, 0);
+ compatInfo.writeToParcel(data, 0);
mRemote.transact(SCHEDULE_CREATE_SERVICE_TRANSACTION, data, null,
IBinder.FLAG_ONEWAY);
data.recycle();
@@ -719,7 +741,7 @@ class ApplicationThreadProxy implements IApplicationThread {
public final void bindApplication(String packageName, ApplicationInfo info,
List<ProviderInfo> providers, ComponentName testName,
String profileName, Bundle testArgs, IInstrumentationWatcher testWatcher, int debugMode,
- boolean restrictedBackupMode, Configuration config,
+ boolean restrictedBackupMode, Configuration config, CompatibilityInfo compatInfo,
Map<String, IBinder> services, Bundle coreSettings) throws RemoteException {
Parcel data = Parcel.obtain();
data.writeInterfaceToken(IApplicationThread.descriptor);
@@ -738,6 +760,7 @@ class ApplicationThreadProxy implements IApplicationThread {
data.writeInt(debugMode);
data.writeInt(restrictedBackupMode ? 1 : 0);
config.writeToParcel(data, 0);
+ compatInfo.writeToParcel(data, 0);
data.writeMap(services);
data.writeBundle(coreSettings);
mRemote.transact(BIND_APPLICATION_TRANSACTION, data, null,
@@ -952,6 +975,16 @@ class ApplicationThreadProxy implements IApplicationThread {
Parcel data = Parcel.obtain();
data.writeInterfaceToken(IApplicationThread.descriptor);
data.writeBundle(coreSettings);
- mRemote.transact(SET_CORE_SETTINGS, data, null, IBinder.FLAG_ONEWAY);
+ mRemote.transact(SET_CORE_SETTINGS_TRANSACTION, data, null, IBinder.FLAG_ONEWAY);
+ }
+
+ public void updatePackageCompatibilityInfo(String pkg, CompatibilityInfo info)
+ throws RemoteException {
+ Parcel data = Parcel.obtain();
+ data.writeInterfaceToken(IApplicationThread.descriptor);
+ data.writeString(pkg);
+ info.writeToParcel(data, 0);
+ mRemote.transact(UPDATE_PACKAGE_COMPATIBILITY_INFO_TRANSACTION, data, null,
+ IBinder.FLAG_ONEWAY);
}
}
diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java
index cc1f81c..36b9d72 100644
--- a/core/java/android/app/ContextImpl.java
+++ b/core/java/android/app/ContextImpl.java
@@ -1372,7 +1372,7 @@ class ContextImpl extends Context {
}
LoadedApk pi =
- mMainThread.getPackageInfo(packageName, flags);
+ mMainThread.getPackageInfo(packageName, mResources.getCompatibilityInfo(), flags);
if (pi != null) {
ContextImpl c = new ContextImpl();
c.mRestricted = (flags & CONTEXT_RESTRICTED) == CONTEXT_RESTRICTED;
@@ -1454,7 +1454,7 @@ class ContextImpl extends Context {
" compatiblity info:" + container.getDisplayMetrics());
}
mResources = mainThread.getTopLevelResources(
- mPackageInfo.getResDir(), container.getCompatibilityInfo().copy());
+ mPackageInfo.getResDir(), container.getCompatibilityInfo());
}
mMainThread = mainThread;
mContentResolver = new ApplicationContentResolver(this, mainThread);
diff --git a/core/java/android/app/IActivityManager.java b/core/java/android/app/IActivityManager.java
index 61e6fc8..4c2ccf4 100644
--- a/core/java/android/app/IActivityManager.java
+++ b/core/java/android/app/IActivityManager.java
@@ -342,6 +342,9 @@ 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)
+ throws RemoteException;
+
/*
* Private non-Binder interfaces
*/
@@ -557,4 +560,5 @@ 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;
}
diff --git a/core/java/android/app/IApplicationThread.java b/core/java/android/app/IApplicationThread.java
index 55177a9..93a8ff3 100644
--- a/core/java/android/app/IApplicationThread.java
+++ b/core/java/android/app/IApplicationThread.java
@@ -23,6 +23,7 @@ import android.content.pm.ActivityInfo;
import android.content.pm.ApplicationInfo;
import android.content.pm.ProviderInfo;
import android.content.pm.ServiceInfo;
+import android.content.res.CompatibilityInfo;
import android.content.res.Configuration;
import android.os.Bundle;
import android.os.Debug;
@@ -52,7 +53,8 @@ public interface IApplicationThread extends IInterface {
void scheduleResumeActivity(IBinder token, boolean isForward) throws RemoteException;
void scheduleSendResult(IBinder token, List<ResultInfo> results) throws RemoteException;
void scheduleLaunchActivity(Intent intent, IBinder token, int ident,
- ActivityInfo info, Bundle state, List<ResultInfo> pendingResults,
+ ActivityInfo info, CompatibilityInfo compatInfo, Bundle state,
+ List<ResultInfo> pendingResults,
List<Intent> pendingNewIntents, boolean notResumed, boolean isForward)
throws RemoteException;
void scheduleRelaunchActivity(IBinder token, List<ResultInfo> pendingResults,
@@ -61,14 +63,17 @@ public interface IApplicationThread extends IInterface {
void scheduleNewIntent(List<Intent> intent, IBinder token) throws RemoteException;
void scheduleDestroyActivity(IBinder token, boolean finished,
int configChanges) throws RemoteException;
- void scheduleReceiver(Intent intent, ActivityInfo info, int resultCode,
- String data, Bundle extras, boolean sync) throws RemoteException;
+ void scheduleReceiver(Intent intent, ActivityInfo info, CompatibilityInfo compatInfo,
+ int resultCode, String data, Bundle extras, boolean sync) throws RemoteException;
static final int BACKUP_MODE_INCREMENTAL = 0;
static final int BACKUP_MODE_FULL = 1;
static final int BACKUP_MODE_RESTORE = 2;
- void scheduleCreateBackupAgent(ApplicationInfo app, int backupMode) throws RemoteException;
- void scheduleDestroyBackupAgent(ApplicationInfo app) throws RemoteException;
- void scheduleCreateService(IBinder token, ServiceInfo info) throws RemoteException;
+ void scheduleCreateBackupAgent(ApplicationInfo app, CompatibilityInfo compatInfo,
+ int backupMode) throws RemoteException;
+ void scheduleDestroyBackupAgent(ApplicationInfo app, CompatibilityInfo compatInfo)
+ throws RemoteException;
+ void scheduleCreateService(IBinder token, ServiceInfo info,
+ CompatibilityInfo compatInfo) throws RemoteException;
void scheduleBindService(IBinder token,
Intent intent, boolean rebind) throws RemoteException;
void scheduleUnbindService(IBinder token,
@@ -82,7 +87,7 @@ public interface IApplicationThread extends IInterface {
void bindApplication(String packageName, ApplicationInfo info, List<ProviderInfo> providers,
ComponentName testName, String profileName, Bundle testArguments,
IInstrumentationWatcher testWatcher, int debugMode, boolean restrictedBackupMode,
- Configuration config, Map<String, IBinder> services,
+ Configuration config, CompatibilityInfo compatInfo, Map<String, IBinder> services,
Bundle coreSettings) throws RemoteException;
void scheduleExit() throws RemoteException;
void scheduleSuicide() throws RemoteException;
@@ -112,6 +117,7 @@ public interface IApplicationThread extends IInterface {
void dumpActivity(FileDescriptor fd, IBinder servicetoken, String prefix, String[] args)
throws RemoteException;
void setCoreSettings(Bundle coreSettings) throws RemoteException;
+ void updatePackageCompatibilityInfo(String pkg, CompatibilityInfo info) throws RemoteException;
String descriptor = "android.app.IApplicationThread";
@@ -153,5 +159,6 @@ public interface IApplicationThread extends IInterface {
int DUMP_ACTIVITY_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+36;
int CLEAR_DNS_CACHE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+37;
int SET_HTTP_PROXY_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+38;
- int SET_CORE_SETTINGS = IBinder.FIRST_CALL_TRANSACTION+39;
+ int SET_CORE_SETTINGS_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+39;
+ int UPDATE_PACKAGE_COMPATIBILITY_INFO_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+40;
}
diff --git a/core/java/android/app/LoadedApk.java b/core/java/android/app/LoadedApk.java
index c406524..5307696 100644
--- a/core/java/android/app/LoadedApk.java
+++ b/core/java/android/app/LoadedApk.java
@@ -99,6 +99,7 @@ final class LoadedApk {
}
public LoadedApk(ActivityThread activityThread, ApplicationInfo aInfo,
+ CompatibilityInfo compatInfo,
ActivityThread mainThread, ClassLoader baseLoader,
boolean securityViolation, boolean includeCode) {
mActivityThread = activityThread;
@@ -114,7 +115,7 @@ final class LoadedApk {
mBaseClassLoader = baseLoader;
mSecurityViolation = securityViolation;
mIncludeCode = includeCode;
- mCompatibilityInfo = new CompatibilityInfo(aInfo);
+ mCompatibilityInfo = compatInfo;
if (mAppDir == null) {
if (ActivityThread.mSystemContext == null) {
@@ -122,7 +123,8 @@ final class LoadedApk {
ContextImpl.createSystemContext(mainThread);
ActivityThread.mSystemContext.getResources().updateConfiguration(
mainThread.getConfiguration(),
- mainThread.getDisplayMetricsLocked(false));
+ mainThread.getDisplayMetricsLocked(false),
+ compatInfo);
//Slog.i(TAG, "Created system resources "
// + mSystemContext.getResources() + ": "
// + mSystemContext.getResources().getConfiguration());
@@ -133,7 +135,7 @@ final class LoadedApk {
}
public LoadedApk(ActivityThread activityThread, String name,
- Context systemContext, ApplicationInfo info) {
+ Context systemContext, ApplicationInfo info, CompatibilityInfo compatInfo) {
mActivityThread = activityThread;
mApplicationInfo = info != null ? info : new ApplicationInfo();
mApplicationInfo.packageName = name;
@@ -149,7 +151,7 @@ final class LoadedApk {
mIncludeCode = true;
mClassLoader = systemContext.getClassLoader();
mResources = systemContext.getResources();
- mCompatibilityInfo = new CompatibilityInfo(mApplicationInfo);
+ mCompatibilityInfo = compatInfo;
}
public String getPackageName() {
diff --git a/core/java/android/content/res/CompatibilityInfo.java b/core/java/android/content/res/CompatibilityInfo.java
index e403ac2..ab9bfce 100644
--- a/core/java/android/content/res/CompatibilityInfo.java
+++ b/core/java/android/content/res/CompatibilityInfo.java
@@ -21,9 +21,9 @@ import android.graphics.Canvas;
import android.graphics.PointF;
import android.graphics.Rect;
import android.graphics.Region;
+import android.os.Parcel;
+import android.os.Parcelable;
import android.util.DisplayMetrics;
-import android.util.Log;
-import android.view.Gravity;
import android.view.MotionEvent;
import android.view.WindowManager;
import android.view.WindowManager.LayoutParams;
@@ -34,32 +34,27 @@ import android.view.WindowManager.LayoutParams;
*
* {@hide}
*/
-public class CompatibilityInfo {
- private static final boolean DBG = false;
- private static final String TAG = "CompatibilityInfo";
-
+public class CompatibilityInfo implements Parcelable {
/** default compatibility info object for compatible applications */
public static final CompatibilityInfo DEFAULT_COMPATIBILITY_INFO = new CompatibilityInfo() {
- @Override
- public void setExpandable(boolean expandable) {
- throw new UnsupportedOperationException("trying to change default compatibility info");
- }
};
/**
- * The default width of the screen in portrait mode.
+ * This is the number of pixels we would like to have along the
+ * short axis of an app that needs to run on a normal size screen.
*/
- public static final int DEFAULT_PORTRAIT_WIDTH = 320;
+ public static final int DEFAULT_NORMAL_SHORT_DIMENSION = 320;
/**
- * The default height of the screen in portrait mode.
- */
- public static final int DEFAULT_PORTRAIT_HEIGHT = 480;
+ * This is the maximum aspect ratio we will allow while keeping
+ * applications in a compatible screen size.
+ */
+ public static final float MAXIMUM_ASPECT_RATIO = (854f/480f);
/**
* A compatibility flags
*/
- private int mCompatibilityFlags;
+ private final int mCompatibilityFlags;
/**
* A flag mask to tell if the application needs scaling (when mApplicationScale != 1.0f)
@@ -68,54 +63,27 @@ public class CompatibilityInfo {
private static final int SCALING_REQUIRED = 1;
/**
- * A flag mask to indicates that the application can expand over the original size.
- * The flag is set to true if
- * 1) Application declares its expandable in manifest file using <supports-screens> or
- * 2) Configuration.SCREENLAYOUT_COMPAT_NEEDED is not set
- * {@see compatibilityFlag}
+ * Has the application said that its UI is expandable? Based on the
+ * <supports-screen> android:expandible in the manifest.
*/
private static final int EXPANDABLE = 2;
/**
- * A flag mask to tell if the application is configured to be expandable. This differs
- * from EXPANDABLE in that the application that is not expandable will be
- * marked as expandable if Configuration.SCREENLAYOUT_COMPAT_NEEDED is not set.
- */
- private static final int CONFIGURED_EXPANDABLE = 4;
-
- /**
- * A flag mask to indicates that the application supports large screens.
- * The flag is set to true if
- * 1) Application declares it supports large screens in manifest file using <supports-screens> or
- * 2) The screen size is not large
- * {@see compatibilityFlag}
+ * Has the application said that its UI supports large screens? Based on the
+ * <supports-screen> android:largeScreens in the manifest.
*/
private static final int LARGE_SCREENS = 8;
/**
- * A flag mask to tell if the application supports large screens. This differs
- * from LARGE_SCREENS in that the application that does not support large
- * screens will be marked as supporting them if the current screen is not
- * large.
- */
- private static final int CONFIGURED_LARGE_SCREENS = 16;
-
- /**
- * A flag mask to indicates that the application supports xlarge screens.
- * The flag is set to true if
- * 1) Application declares it supports xlarge screens in manifest file using <supports-screens> or
- * 2) The screen size is not xlarge
- * {@see compatibilityFlag}
+ * Has the application said that its UI supports xlarge screens? Based on the
+ * <supports-screen> android:xlargeScreens in the manifest.
*/
private static final int XLARGE_SCREENS = 32;
/**
- * A flag mask to tell if the application supports xlarge screens. This differs
- * from XLARGE_SCREENS in that the application that does not support xlarge
- * screens will be marked as supporting them if the current screen is not
- * xlarge.
+ * Set if the application needs to run in screen size compatibility mode.
*/
- private static final int CONFIGURED_XLARGE_SCREENS = 64;
+ private static final int NEEDS_SCREEN_COMPAT = 128;
/**
* The effective screen density we have selected for this application.
@@ -132,28 +100,55 @@ public class CompatibilityInfo {
*/
public final float applicationInvertedScale;
- /**
- * The flags from ApplicationInfo.
- */
- public final int appFlags;
-
- public CompatibilityInfo(ApplicationInfo appInfo) {
- appFlags = appInfo.flags;
-
+ public CompatibilityInfo(ApplicationInfo appInfo, int screenLayout, boolean forceCompat) {
+ int compatFlags = 0;
+
if ((appInfo.flags & ApplicationInfo.FLAG_SUPPORTS_LARGE_SCREENS) != 0) {
- // Saying you support large screens also implies you support xlarge
- // screens; there is no compatibility mode for a large app on an
- // xlarge screen.
- mCompatibilityFlags |= LARGE_SCREENS | CONFIGURED_LARGE_SCREENS
- | XLARGE_SCREENS | CONFIGURED_XLARGE_SCREENS
- | EXPANDABLE | CONFIGURED_EXPANDABLE;
+ compatFlags |= LARGE_SCREENS;
+ if (!forceCompat) {
+ // If we aren't forcing the app into compatibility mode, then
+ // assume if it supports large screens that we should allow it
+ // to use the full space of an xlarge screen as well.
+ compatFlags |= XLARGE_SCREENS | EXPANDABLE;
+ }
}
if ((appInfo.flags & ApplicationInfo.FLAG_SUPPORTS_XLARGE_SCREENS) != 0) {
- mCompatibilityFlags |= XLARGE_SCREENS | CONFIGURED_XLARGE_SCREENS
- | EXPANDABLE | CONFIGURED_EXPANDABLE;
+ compatFlags |= XLARGE_SCREENS | EXPANDABLE;
+ }
+ if (!forceCompat) {
+ // If we are forcing compatibility mode, then ignore an app that
+ // just says it is resizable for screens. We'll only have it fill
+ // the screen if it explicitly says it supports the screen size we
+ // are running in.
+ if ((appInfo.flags & ApplicationInfo.FLAG_RESIZEABLE_FOR_SCREENS) != 0) {
+ compatFlags |= EXPANDABLE;
+ }
+ }
+
+ boolean supportsScreen = false;
+ switch (screenLayout&Configuration.SCREENLAYOUT_SIZE_MASK) {
+ case Configuration.SCREENLAYOUT_SIZE_XLARGE:
+ if ((compatFlags&XLARGE_SCREENS) != 0) {
+ supportsScreen = true;
+ }
+ break;
+ case Configuration.SCREENLAYOUT_SIZE_LARGE:
+ if ((compatFlags&LARGE_SCREENS) != 0) {
+ supportsScreen = true;
+ }
+ break;
+ }
+
+ if ((screenLayout&Configuration.SCREENLAYOUT_COMPAT_NEEDED) == 0) {
+ if ((compatFlags&EXPANDABLE) != 0) {
+ supportsScreen = true;
+ }
}
- if ((appInfo.flags & ApplicationInfo.FLAG_RESIZEABLE_FOR_SCREENS) != 0) {
- mCompatibilityFlags |= EXPANDABLE | CONFIGURED_EXPANDABLE;
+
+ if (supportsScreen) {
+ compatFlags &= ~NEEDS_SCREEN_COMPAT;
+ } else {
+ compatFlags |= NEEDS_SCREEN_COMPAT;
}
if ((appInfo.flags & ApplicationInfo.FLAG_SUPPORTS_SCREEN_DENSITIES) != 0) {
@@ -165,13 +160,14 @@ public class CompatibilityInfo {
applicationScale = DisplayMetrics.DENSITY_DEVICE
/ (float) DisplayMetrics.DENSITY_DEFAULT;
applicationInvertedScale = 1.0f / applicationScale;
- mCompatibilityFlags |= SCALING_REQUIRED;
+ compatFlags |= SCALING_REQUIRED;
}
+
+ mCompatibilityFlags = compatFlags;
}
- private CompatibilityInfo(int appFlags, int compFlags,
+ private CompatibilityInfo(int compFlags,
int dens, float scale, float invertedScale) {
- this.appFlags = appFlags;
mCompatibilityFlags = compFlags;
applicationDensity = dens;
applicationScale = scale;
@@ -179,81 +175,13 @@ public class CompatibilityInfo {
}
private CompatibilityInfo() {
- this(ApplicationInfo.FLAG_SUPPORTS_SMALL_SCREENS
- | ApplicationInfo.FLAG_SUPPORTS_NORMAL_SCREENS
- | ApplicationInfo.FLAG_SUPPORTS_LARGE_SCREENS
- | ApplicationInfo.FLAG_SUPPORTS_XLARGE_SCREENS
- | ApplicationInfo.FLAG_RESIZEABLE_FOR_SCREENS,
- EXPANDABLE | CONFIGURED_EXPANDABLE,
+ this(XLARGE_SCREENS | LARGE_SCREENS | EXPANDABLE,
DisplayMetrics.DENSITY_DEVICE,
1.0f,
1.0f);
}
/**
- * Returns the copy of this instance.
- */
- public CompatibilityInfo copy() {
- CompatibilityInfo info = new CompatibilityInfo(appFlags, mCompatibilityFlags,
- applicationDensity, applicationScale, applicationInvertedScale);
- return info;
- }
-
- /**
- * Sets expandable bit in the compatibility flag.
- */
- public void setExpandable(boolean expandable) {
- if (expandable) {
- mCompatibilityFlags |= CompatibilityInfo.EXPANDABLE;
- } else {
- mCompatibilityFlags &= ~CompatibilityInfo.EXPANDABLE;
- }
- }
-
- /**
- * Sets large screen bit in the compatibility flag.
- */
- public void setLargeScreens(boolean expandable) {
- if (expandable) {
- mCompatibilityFlags |= CompatibilityInfo.LARGE_SCREENS;
- } else {
- mCompatibilityFlags &= ~CompatibilityInfo.LARGE_SCREENS;
- }
- }
-
- /**
- * Sets large screen bit in the compatibility flag.
- */
- public void setXLargeScreens(boolean expandable) {
- if (expandable) {
- mCompatibilityFlags |= CompatibilityInfo.XLARGE_SCREENS;
- } else {
- mCompatibilityFlags &= ~CompatibilityInfo.XLARGE_SCREENS;
- }
- }
-
- /**
- * @return true if the application is configured to be expandable.
- */
- public boolean isConfiguredExpandable() {
- return (mCompatibilityFlags & CompatibilityInfo.CONFIGURED_EXPANDABLE) != 0;
- }
-
- /**
- * @return true if the application is configured to be expandable.
- */
- public boolean isConfiguredLargeScreens() {
- return (mCompatibilityFlags & CompatibilityInfo.CONFIGURED_LARGE_SCREENS) != 0;
- }
-
- /**
- * @return true if the application is configured to be expandable.
- */
- public boolean isConfiguredXLargeScreens() {
- return (mCompatibilityFlags & CompatibilityInfo.CONFIGURED_XLARGE_SCREENS) != 0;
- }
-
- /**
* @return true if the scaling is required
*/
public boolean isScalingRequired() {
@@ -261,14 +189,12 @@ public class CompatibilityInfo {
}
public boolean supportsScreen() {
- return (mCompatibilityFlags & (EXPANDABLE|LARGE_SCREENS))
- == (EXPANDABLE|LARGE_SCREENS);
+ return (mCompatibilityFlags&NEEDS_SCREEN_COMPAT) == 0;
}
@Override
public String toString() {
- return "CompatibilityInfo{scale=" + applicationScale +
- ", supports screen=" + supportsScreen() + "}";
+ return "CompatibilityInfo{scale=" + applicationScale + "}";
}
/**
@@ -423,24 +349,144 @@ public class CompatibilityInfo {
}
}
+ public void applyToDisplayMetrics(DisplayMetrics inoutDm) {
+ if (!supportsScreen()) {
+ // This is a larger screen device and the app is not
+ // compatible with large screens, so diddle it.
+ CompatibilityInfo.updateCompatibleScreenFrame(inoutDm, null, inoutDm);
+ }
+
+ if (isScalingRequired()) {
+ float invertedRatio = applicationInvertedScale;
+ inoutDm.density *= invertedRatio;
+ inoutDm.densityDpi = (int)((inoutDm.density*DisplayMetrics.DENSITY_DEFAULT)+.5f);
+ inoutDm.scaledDensity *= invertedRatio;
+ inoutDm.xdpi *= invertedRatio;
+ inoutDm.ydpi *= invertedRatio;
+ inoutDm.widthPixels = (int) (inoutDm.widthPixels * invertedRatio + 0.5f);
+ inoutDm.heightPixels = (int) (inoutDm.heightPixels * invertedRatio + 0.5f);
+ }
+ }
+
+ public void applyToConfiguration(Configuration inoutConfig) {
+ if (!supportsScreen()) {
+ // This is a larger screen device and the app is not
+ // compatible with large screens, so we are forcing it to
+ // run as if the screen is normal size.
+ inoutConfig.screenLayout =
+ (inoutConfig.screenLayout&~Configuration.SCREENLAYOUT_SIZE_MASK)
+ | Configuration.SCREENLAYOUT_SIZE_NORMAL;
+ }
+ }
+
/**
- * Returns the frame Rect for applications runs under compatibility mode.
+ * Compute the frame Rect for applications runs under compatibility mode.
*
* @param dm the display metrics used to compute the frame size.
* @param orientation the orientation of the screen.
* @param outRect the output parameter which will contain the result.
+ * @return Returns the scaling factor for the window.
*/
- public static void updateCompatibleScreenFrame(DisplayMetrics dm, int orientation,
- Rect outRect) {
- int width = dm.widthPixels;
- int portraitHeight = (int) (DEFAULT_PORTRAIT_HEIGHT * dm.density + 0.5f);
- int portraitWidth = (int) (DEFAULT_PORTRAIT_WIDTH * dm.density + 0.5f);
- if (orientation == Configuration.ORIENTATION_LANDSCAPE) {
- int xOffset = (width - portraitHeight) / 2 ;
- outRect.set(xOffset, 0, xOffset + portraitHeight, portraitWidth);
+ public static float updateCompatibleScreenFrame(DisplayMetrics dm,
+ Rect outRect, DisplayMetrics outDm) {
+ final int width = dm.realWidthPixels;
+ final int height = dm.realHeightPixels;
+ int shortSize, longSize;
+ if (width < height) {
+ shortSize = width;
+ longSize = height;
+ } else {
+ shortSize = height;
+ longSize = width;
+ }
+ int newShortSize = (int)(DEFAULT_NORMAL_SHORT_DIMENSION * dm.density + 0.5f);
+ float aspect = ((float)longSize) / shortSize;
+ if (aspect > MAXIMUM_ASPECT_RATIO) {
+ aspect = MAXIMUM_ASPECT_RATIO;
+ }
+ int newLongSize = (int)(newShortSize * aspect + 0.5f);
+ int newWidth, newHeight;
+ if (width < height) {
+ newWidth = newShortSize;
+ newHeight = newLongSize;
} else {
- int xOffset = (width - portraitWidth) / 2 ;
- outRect.set(xOffset, 0, xOffset + portraitWidth, portraitHeight);
+ newWidth = newLongSize;
+ newHeight = newShortSize;
+ }
+
+ float sw = width/(float)newWidth;
+ float sh = height/(float)newHeight;
+ float scale = sw < sh ? sw : sh;
+ if (scale < 1) {
+ scale = 1;
}
+
+ if (outRect != null) {
+ final int left = (int)((width-(newWidth*scale))/2);
+ final int top = (int)((height-(newHeight*scale))/2);
+ outRect.set(left, top, left+newWidth, top+newHeight);
+ }
+
+ if (outDm != null) {
+ outDm.widthPixels = newWidth;
+ outDm.heightPixels = newHeight;
+ }
+
+ return scale;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ try {
+ CompatibilityInfo oc = (CompatibilityInfo)o;
+ if (mCompatibilityFlags != oc.mCompatibilityFlags) return false;
+ if (applicationDensity != oc.applicationDensity) return false;
+ if (applicationScale != oc.applicationScale) return false;
+ if (applicationInvertedScale != oc.applicationInvertedScale) return false;
+ return true;
+ } catch (ClassCastException e) {
+ return false;
+ }
+ }
+
+ @Override
+ public int hashCode() {
+ int result = 17;
+ result = 31 * result + mCompatibilityFlags;
+ result = 31 * result + applicationDensity;
+ result = 31 * result + Float.floatToIntBits(applicationScale);
+ result = 31 * result + Float.floatToIntBits(applicationInvertedScale);
+ return result;
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeInt(mCompatibilityFlags);
+ dest.writeInt(applicationDensity);
+ dest.writeFloat(applicationScale);
+ dest.writeFloat(applicationInvertedScale);
+ }
+
+ public static final Parcelable.Creator<CompatibilityInfo> CREATOR
+ = new Parcelable.Creator<CompatibilityInfo>() {
+ public CompatibilityInfo createFromParcel(Parcel source) {
+ return new CompatibilityInfo(source);
+ }
+
+ public CompatibilityInfo[] newArray(int size) {
+ return new CompatibilityInfo[size];
+ }
+ };
+
+ private CompatibilityInfo(Parcel source) {
+ mCompatibilityFlags = source.readInt();
+ applicationDensity = source.readInt();
+ applicationScale = source.readFloat();
+ applicationInvertedScale = source.readFloat();
}
}
diff --git a/core/java/android/content/res/Configuration.java b/core/java/android/content/res/Configuration.java
index 47c2623..908db11 100644
--- a/core/java/android/content/res/Configuration.java
+++ b/core/java/android/content/res/Configuration.java
@@ -703,11 +703,20 @@ public final class Configuration implements Parcelable, Comparable<Configuration
}
public int hashCode() {
- return ((int)this.fontScale) + this.mcc + this.mnc
- + (this.locale != null ? this.locale.hashCode() : 0)
- + this.touchscreen
- + this.keyboard + this.keyboardHidden + this.hardKeyboardHidden
- + this.navigation + this.navigationHidden
- + this.orientation + this.screenLayout + this.uiMode;
+ int result = 17;
+ result = 31 * result + Float.floatToIntBits(fontScale);
+ result = 31 * result + mcc;
+ result = 31 * result + mnc;
+ result = 31 * result + (locale != null ? locale.hashCode() : 0);
+ result = 31 * result + touchscreen;
+ result = 31 * result + keyboard;
+ result = 31 * result + keyboardHidden;
+ result = 31 * result + hardKeyboardHidden;
+ result = 31 * result + navigation;
+ result = 31 * result + navigationHidden;
+ result = 31 * result + orientation;
+ result = 31 * result + screenLayout;
+ result = 31 * result + uiMode;
+ return result;
}
}
diff --git a/core/java/android/content/res/Resources.java b/core/java/android/content/res/Resources.java
index 81eb09c..00b49e8 100755
--- a/core/java/android/content/res/Resources.java
+++ b/core/java/android/content/res/Resources.java
@@ -91,6 +91,7 @@ public class Resources {
private static boolean mPreloaded;
/*package*/ final TypedValue mTmpValue = new TypedValue();
+ /*package*/ final Configuration mTmpConfig = new Configuration();
// These are protected by the mTmpValue lock.
private final LongSparseArray<WeakReference<Drawable.ConstantState> > mDrawableCache
@@ -1400,18 +1401,30 @@ public class Resources {
*/
public void updateConfiguration(Configuration config,
DisplayMetrics metrics) {
+ updateConfiguration(config, metrics, null);
+ }
+
+ /**
+ * @hide
+ */
+ public void updateConfiguration(Configuration config,
+ DisplayMetrics metrics, CompatibilityInfo compat) {
synchronized (mTmpValue) {
+ if (compat != null) {
+ mCompatibilityInfo = compat;
+ }
int configChanges = 0xfffffff;
if (config != null) {
- configChanges = mConfiguration.updateFrom(config);
+ mTmpConfig.setTo(config);
+ mCompatibilityInfo.applyToConfiguration(mTmpConfig);
+ configChanges = mConfiguration.updateFrom(mTmpConfig);
}
if (mConfiguration.locale == null) {
mConfiguration.locale = Locale.getDefault();
}
if (metrics != null) {
mMetrics.setTo(metrics);
- mMetrics.updateMetrics(mCompatibilityInfo,
- mConfiguration.orientation, mConfiguration.screenLayout);
+ mCompatibilityInfo.applyToDisplayMetrics(mMetrics);
}
mMetrics.scaledDensity = mMetrics.density * mConfiguration.fontScale;
@@ -1500,15 +1513,23 @@ public class Resources {
*
* @hide
*/
- public static void updateSystemConfiguration(Configuration config, DisplayMetrics metrics) {
+ public static void updateSystemConfiguration(Configuration config, DisplayMetrics metrics,
+ CompatibilityInfo compat) {
if (mSystem != null) {
- mSystem.updateConfiguration(config, metrics);
+ mSystem.updateConfiguration(config, metrics, compat);
//Log.i(TAG, "Updated system resources " + mSystem
// + ": " + mSystem.getConfiguration());
}
}
/**
+ * @hide
+ */
+ public static void updateSystemConfiguration(Configuration config, DisplayMetrics metrics) {
+ updateSystemConfiguration(config, metrics, null);
+ }
+
+ /**
* Return the current display metrics that are in effect for this resource
* object. The returned object should be treated as read-only.
*
diff --git a/core/java/android/util/DisplayMetrics.java b/core/java/android/util/DisplayMetrics.java
index 63baf14..8018ff9 100644
--- a/core/java/android/util/DisplayMetrics.java
+++ b/core/java/android/util/DisplayMetrics.java
@@ -16,9 +16,7 @@
package android.util;
-import android.content.res.CompatibilityInfo;
-import android.content.res.Configuration;
-import android.os.*;
+import android.os.SystemProperties;
/**
@@ -107,6 +105,11 @@ public class DisplayMetrics {
*/
public float ydpi;
+ /** @hide */
+ public int realWidthPixels;
+ /** @hide */
+ public int realHeightPixels;
+
public DisplayMetrics() {
}
@@ -118,6 +121,8 @@ public class DisplayMetrics {
scaledDensity = o.scaledDensity;
xdpi = o.xdpi;
ydpi = o.ydpi;
+ realWidthPixels = o.realWidthPixels;
+ realHeightPixels = o.realHeightPixels;
}
public void setToDefaults() {
@@ -128,101 +133,8 @@ public class DisplayMetrics {
scaledDensity = density;
xdpi = DENSITY_DEVICE;
ydpi = DENSITY_DEVICE;
- }
-
- /**
- * Update the display metrics based on the compatibility info and orientation
- * NOTE: DO NOT EXPOSE THIS API! It is introducing a circular dependency
- * with the higher-level android.res package.
- * {@hide}
- */
- public void updateMetrics(CompatibilityInfo compatibilityInfo, int orientation,
- int screenLayout) {
- boolean expandable = compatibilityInfo.isConfiguredExpandable();
- boolean largeScreens = compatibilityInfo.isConfiguredLargeScreens();
- boolean xlargeScreens = compatibilityInfo.isConfiguredXLargeScreens();
-
- // Note: this assume that configuration is updated before calling
- // updateMetrics method.
- if (!expandable) {
- if ((screenLayout&Configuration.SCREENLAYOUT_COMPAT_NEEDED) == 0) {
- expandable = true;
- // the current screen size is compatible with non-resizing apps.
- compatibilityInfo.setExpandable(true);
- } else {
- compatibilityInfo.setExpandable(false);
- }
- }
- if (!largeScreens) {
- if ((screenLayout&Configuration.SCREENLAYOUT_SIZE_MASK)
- != Configuration.SCREENLAYOUT_SIZE_LARGE) {
- largeScreens = true;
- // the current screen size is not large.
- compatibilityInfo.setLargeScreens(true);
- } else {
- compatibilityInfo.setLargeScreens(false);
- }
- }
- if (!xlargeScreens) {
- if ((screenLayout&Configuration.SCREENLAYOUT_SIZE_MASK)
- != Configuration.SCREENLAYOUT_SIZE_XLARGE) {
- xlargeScreens = true;
- // the current screen size is not large.
- compatibilityInfo.setXLargeScreens(true);
- } else {
- compatibilityInfo.setXLargeScreens(false);
- }
- }
-
- if (!expandable || (!largeScreens && !xlargeScreens)) {
- // This is a larger screen device and the app is not
- // compatible with large screens, so diddle it.
-
- // Figure out the compatibility width and height of the screen.
- int defaultWidth;
- int defaultHeight;
- switch (orientation) {
- case Configuration.ORIENTATION_LANDSCAPE: {
- defaultWidth = (int)(CompatibilityInfo.DEFAULT_PORTRAIT_HEIGHT * density +
- 0.5f);
- defaultHeight = (int)(CompatibilityInfo.DEFAULT_PORTRAIT_WIDTH * density +
- 0.5f);
- break;
- }
- case Configuration.ORIENTATION_PORTRAIT:
- case Configuration.ORIENTATION_SQUARE:
- default: {
- defaultWidth = (int)(CompatibilityInfo.DEFAULT_PORTRAIT_WIDTH * density +
- 0.5f);
- defaultHeight = (int)(CompatibilityInfo.DEFAULT_PORTRAIT_HEIGHT * density +
- 0.5f);
- break;
- }
- case Configuration.ORIENTATION_UNDEFINED: {
- // don't change
- return;
- }
- }
-
- if (defaultWidth < widthPixels) {
- // content/window's x offset in original pixels
- widthPixels = defaultWidth;
- }
- if (defaultHeight < heightPixels) {
- heightPixels = defaultHeight;
- }
- }
-
- if (compatibilityInfo.isScalingRequired()) {
- float invertedRatio = compatibilityInfo.applicationInvertedScale;
- density *= invertedRatio;
- densityDpi = (int)((density*DisplayMetrics.DENSITY_DEFAULT)+.5f);
- scaledDensity *= invertedRatio;
- xdpi *= invertedRatio;
- ydpi *= invertedRatio;
- widthPixels = (int) (widthPixels * invertedRatio + 0.5f);
- heightPixels = (int) (heightPixels * invertedRatio + 0.5f);
- }
+ realWidthPixels = 0;
+ realHeightPixels = 0;
}
@Override
diff --git a/core/java/android/view/Display.java b/core/java/android/view/Display.java
index 126f409..89767f2 100644
--- a/core/java/android/view/Display.java
+++ b/core/java/android/view/Display.java
@@ -139,6 +139,9 @@ public class Display
outMetrics.scaledDensity= outMetrics.density;
outMetrics.xdpi = mDpiX;
outMetrics.ydpi = mDpiY;
+
+ outMetrics.realWidthPixels = outMetrics.widthPixels;
+ outMetrics.realHeightPixels = outMetrics.heightPixels;
}
/*
diff --git a/core/java/android/view/WindowManagerPolicy.java b/core/java/android/view/WindowManagerPolicy.java
index 334c68e..2058991 100644
--- a/core/java/android/view/WindowManagerPolicy.java
+++ b/core/java/android/view/WindowManagerPolicy.java
@@ -458,6 +458,18 @@ public interface WindowManagerPolicy {
public int getMaxWallpaperLayer();
/**
+ * Return the display width available after excluding the window
+ * decor.
+ */
+ public int getNonDecorDisplayWidth(int fullWidth);
+
+ /**
+ * Return the display height available after excluding the screen
+ * decor.
+ */
+ public int getNonDecorDisplayHeight(int fullHeight);
+
+ /**
* Return whether the given window should forcibly hide everything
* behind it. Typically returns true for the keyguard.
*/
diff --git a/include/ui/Input.h b/include/ui/Input.h
index d9d77c4..bc5b718 100644
--- a/include/ui/Input.h
+++ b/include/ui/Input.h
@@ -203,6 +203,8 @@ struct PointerCoords {
status_t setAxisValue(int32_t axis, float value);
float* editAxisValue(int32_t axis);
+ void scale(float scale);
+
#ifdef HAVE_ANDROID_OS
status_t readFromParcel(Parcel* parcel);
status_t writeToParcel(Parcel* parcel) const;
diff --git a/libs/ui/Input.cpp b/libs/ui/Input.cpp
index e2e698e..19d590a 100644
--- a/libs/ui/Input.cpp
+++ b/libs/ui/Input.cpp
@@ -298,6 +298,24 @@ float* PointerCoords::editAxisValue(int32_t axis) {
return &values[index];
}
+static inline void scaleAxisValue(PointerCoords& c, int axis, float scaleFactor) {
+ float* value = c.editAxisValue(axis);
+ if (value) {
+ *value *= scaleFactor;
+ }
+}
+
+void PointerCoords::scale(float scaleFactor) {
+ // No need to scale pressure or size since they are normalized.
+ // No need to scale orientation since it is meaningless to do so.
+ scaleAxisValue(*this, AMOTION_EVENT_AXIS_X, scaleFactor);
+ scaleAxisValue(*this, AMOTION_EVENT_AXIS_Y, scaleFactor);
+ scaleAxisValue(*this, AMOTION_EVENT_AXIS_TOUCH_MAJOR, scaleFactor);
+ scaleAxisValue(*this, AMOTION_EVENT_AXIS_TOUCH_MINOR, scaleFactor);
+ scaleAxisValue(*this, AMOTION_EVENT_AXIS_TOOL_MAJOR, scaleFactor);
+ scaleAxisValue(*this, AMOTION_EVENT_AXIS_TOOL_MINOR, scaleFactor);
+}
+
#ifdef HAVE_ANDROID_OS
status_t PointerCoords::readFromParcel(Parcel* parcel) {
bits = parcel->readInt64();
@@ -411,11 +429,9 @@ float MotionEvent::getAxisValue(int32_t axis, size_t pointerIndex) const {
float value = getRawPointerCoords(pointerIndex)->getAxisValue(axis);
switch (axis) {
case AMOTION_EVENT_AXIS_X:
- value += mXOffset;
- break;
+ return value + mXOffset;
case AMOTION_EVENT_AXIS_Y:
- value += mYOffset;
- break;
+ return value + mYOffset;
}
return value;
}
@@ -435,11 +451,9 @@ float MotionEvent::getHistoricalAxisValue(int32_t axis, size_t pointerIndex,
float value = getHistoricalRawPointerCoords(pointerIndex, historicalIndex)->getAxisValue(axis);
switch (axis) {
case AMOTION_EVENT_AXIS_X:
- value += mXOffset;
- break;
+ return value + mXOffset;
case AMOTION_EVENT_AXIS_Y:
- value += mYOffset;
- break;
+ return value + mYOffset;
}
return value;
}
@@ -449,13 +463,6 @@ void MotionEvent::offsetLocation(float xOffset, float yOffset) {
mYOffset += yOffset;
}
-static inline void scaleAxisValue(PointerCoords& c, int axis, float scaleFactor) {
- float* value = c.editAxisValue(axis);
- if (value) {
- *value *= scaleFactor;
- }
-}
-
void MotionEvent::scale(float scaleFactor) {
mXOffset *= scaleFactor;
mYOffset *= scaleFactor;
@@ -464,15 +471,7 @@ void MotionEvent::scale(float scaleFactor) {
size_t numSamples = mSamplePointerCoords.size();
for (size_t i = 0; i < numSamples; i++) {
- PointerCoords& c = mSamplePointerCoords.editItemAt(i);
- // No need to scale pressure or size since they are normalized.
- // No need to scale orientation since it is meaningless to do so.
- scaleAxisValue(c, AMOTION_EVENT_AXIS_X, scaleFactor);
- scaleAxisValue(c, AMOTION_EVENT_AXIS_Y, scaleFactor);
- scaleAxisValue(c, AMOTION_EVENT_AXIS_TOUCH_MAJOR, scaleFactor);
- scaleAxisValue(c, AMOTION_EVENT_AXIS_TOUCH_MINOR, scaleFactor);
- scaleAxisValue(c, AMOTION_EVENT_AXIS_TOOL_MAJOR, scaleFactor);
- scaleAxisValue(c, AMOTION_EVENT_AXIS_TOOL_MINOR, scaleFactor);
+ mSamplePointerCoords.editItemAt(i).scale(scaleFactor);
}
}
diff --git a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
index 8e18f2a..29c5741 100755
--- a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
+++ b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
@@ -35,7 +35,6 @@ import android.database.ContentObserver;
import android.graphics.PixelFormat;
import android.graphics.Rect;
import android.os.Binder;
-import android.os.Build;
import android.os.Handler;
import android.os.IBinder;
import android.os.LocalPowerManager;
@@ -56,7 +55,6 @@ import com.android.internal.telephony.ITelephony;
import com.android.internal.view.BaseInputHandler;
import com.android.internal.widget.PointerLocationView;
-import android.telephony.TelephonyManager;
import android.util.Config;
import android.util.EventLog;
import android.util.Log;
@@ -231,6 +229,7 @@ public class PhoneWindowManager implements WindowManagerPolicy {
boolean mSafeMode;
WindowState mStatusBar = null;
boolean mStatusBarCanHide;
+ int mScreenMarginBottom;
final ArrayList<WindowState> mStatusBarPanels = new ArrayList<WindowState>();
WindowState mKeyguard = null;
KeyguardViewMediator mKeyguardMediator;
@@ -1032,6 +1031,14 @@ public class PhoneWindowManager implements WindowManagerPolicy {
return STATUS_BAR_LAYER;
}
+ public int getNonDecorDisplayWidth(int fullWidth) {
+ return fullWidth;
+ }
+
+ public int getNonDecorDisplayHeight(int fullHeight) {
+ return fullHeight - mScreenMarginBottom;
+ }
+
public boolean doesForceHide(WindowState win, WindowManager.LayoutParams attrs) {
return attrs.type == WindowManager.LayoutParams.TYPE_KEYGUARD;
}
@@ -1181,6 +1188,8 @@ public class PhoneWindowManager implements WindowManagerPolicy {
// The Configuration will be stable by now, so we can load this
mStatusBarCanHide = mContext.getResources().getBoolean(
com.android.internal.R.bool.config_statusBarCanHide);
+ mScreenMarginBottom = mContext.getResources().getDimensionPixelSize(
+ com.android.internal.R.dimen.screen_margin_bottom);
break;
case TYPE_STATUS_BAR_PANEL:
diff --git a/services/input/InputDispatcher.cpp b/services/input/InputDispatcher.cpp
index 19295e6..f8a5cfb 100644
--- a/services/input/InputDispatcher.cpp
+++ b/services/input/InputDispatcher.cpp
@@ -156,6 +156,14 @@ static bool validateMotionEvent(int32_t action, size_t pointerCount,
return true;
}
+static void scalePointerCoords(const PointerCoords* inCoords, size_t count, float scaleFactor,
+ PointerCoords* outCoords) {
+ for (size_t i = 0; i < count; i++) {
+ outCoords[i] = inCoords[i];
+ outCoords[i].scale(scaleFactor);
+ }
+}
+
static void dumpRegion(String8& dump, const SkRegion& region) {
if (region.isEmpty()) {
dump.append("<empty>");
@@ -1494,6 +1502,7 @@ void InputDispatcher::addWindowTargetLocked(const InputWindow* window, int32_t t
target.flags = targetFlags;
target.xOffset = - window->frameLeft;
target.yOffset = - window->frameTop;
+ target.scaleFactor = window->scaleFactor;
target.pointerIds = pointerIds;
}
@@ -1506,6 +1515,7 @@ void InputDispatcher::addMonitoringTargetsLocked() {
target.flags = 0;
target.xOffset = 0;
target.yOffset = 0;
+ target.scaleFactor = 1.0f;
}
}
@@ -1607,12 +1617,12 @@ void InputDispatcher::prepareDispatchCycleLocked(nsecs_t currentTime,
bool resumeWithAppendedMotionSample) {
#if DEBUG_DISPATCH_CYCLE
LOGD("channel '%s' ~ prepareDispatchCycle - flags=%d, "
- "xOffset=%f, yOffset=%f, "
+ "xOffset=%f, yOffset=%f, scaleFactor=%f"
"pointerIds=0x%x, "
"resumeWithAppendedMotionSample=%s",
connection->getInputChannelName(), inputTarget->flags,
inputTarget->xOffset, inputTarget->yOffset,
- inputTarget->pointerIds.value,
+ inputTarget->scaleFactor, inputTarget->pointerIds.value,
toString(resumeWithAppendedMotionSample));
#endif
@@ -1693,8 +1703,19 @@ void InputDispatcher::prepareDispatchCycleLocked(nsecs_t currentTime,
// consumed the motion event (or if the channel is broken).
MotionEntry* motionEntry = static_cast<MotionEntry*>(eventEntry);
MotionSample* appendedMotionSample = motionEntry->lastSample;
- status_t status = connection->inputPublisher.appendMotionSample(
- appendedMotionSample->eventTime, appendedMotionSample->pointerCoords);
+ status_t status;
+ if (motionEventDispatchEntry->scaleFactor == 1.0f) {
+ status = connection->inputPublisher.appendMotionSample(
+ appendedMotionSample->eventTime, appendedMotionSample->pointerCoords);
+ } else {
+ PointerCoords scaledCoords[MAX_POINTERS];
+ for (size_t i = 0; i < motionEntry->pointerCount; i++) {
+ scaledCoords[i] = appendedMotionSample->pointerCoords[i];
+ scaledCoords[i].scale(motionEventDispatchEntry->scaleFactor);
+ }
+ status = connection->inputPublisher.appendMotionSample(
+ appendedMotionSample->eventTime, scaledCoords);
+ }
if (status == OK) {
#if DEBUG_BATCHING
LOGD("channel '%s' ~ Successfully streamed new motion sample.",
@@ -1731,7 +1752,8 @@ void InputDispatcher::prepareDispatchCycleLocked(nsecs_t currentTime,
// This is a new event.
// Enqueue a new dispatch entry onto the outbound queue for this connection.
DispatchEntry* dispatchEntry = mAllocator.obtainDispatchEntry(eventEntry, // increments ref
- inputTarget->flags, inputTarget->xOffset, inputTarget->yOffset);
+ inputTarget->flags, inputTarget->xOffset, inputTarget->yOffset,
+ inputTarget->scaleFactor);
if (dispatchEntry->hasForegroundTarget()) {
incrementPendingForegroundDispatchesLocked(eventEntry);
}
@@ -1827,24 +1849,34 @@ void InputDispatcher::startDispatchCycleLocked(nsecs_t currentTime,
firstMotionSample = & motionEntry->firstSample;
}
+ PointerCoords scaledCoords[MAX_POINTERS];
+ const PointerCoords* usingCoords = firstMotionSample->pointerCoords;
+
// Set the X and Y offset depending on the input source.
- float xOffset, yOffset;
+ float xOffset, yOffset, scaleFactor;
if (motionEntry->source & AINPUT_SOURCE_CLASS_POINTER) {
- xOffset = dispatchEntry->xOffset;
- yOffset = dispatchEntry->yOffset;
+ scaleFactor = dispatchEntry->scaleFactor;
+ xOffset = dispatchEntry->xOffset * scaleFactor;
+ yOffset = dispatchEntry->yOffset * scaleFactor;
+ if (scaleFactor != 1.0f) {
+ for (size_t i = 0; i < motionEntry->pointerCount; i++) {
+ scaledCoords[i] = firstMotionSample->pointerCoords[i];
+ scaledCoords[i].scale(scaleFactor);
+ }
+ usingCoords = scaledCoords;
+ }
} else {
xOffset = 0.0f;
yOffset = 0.0f;
+ scaleFactor = 1.0f;
}
// Publish the motion event and the first motion sample.
status = connection->inputPublisher.publishMotionEvent(motionEntry->deviceId,
motionEntry->source, action, flags, motionEntry->edgeFlags, motionEntry->metaState,
- xOffset, yOffset,
- motionEntry->xPrecision, motionEntry->yPrecision,
+ xOffset, yOffset, motionEntry->xPrecision, motionEntry->yPrecision,
motionEntry->downTime, firstMotionSample->eventTime,
- motionEntry->pointerCount, motionEntry->pointerIds,
- firstMotionSample->pointerCoords);
+ motionEntry->pointerCount, motionEntry->pointerIds, usingCoords);
if (status) {
LOGE("channel '%s' ~ Could not publish motion event, "
@@ -1857,7 +1889,7 @@ void InputDispatcher::startDispatchCycleLocked(nsecs_t currentTime,
MotionSample* nextMotionSample = firstMotionSample->next;
for (; nextMotionSample != NULL; nextMotionSample = nextMotionSample->next) {
status = connection->inputPublisher.appendMotionSample(
- nextMotionSample->eventTime, nextMotionSample->pointerCoords);
+ nextMotionSample->eventTime, usingCoords);
if (status == NO_MEMORY) {
#if DEBUG_DISPATCH_CYCLE
LOGD("channel '%s' ~ Shared memory buffer full. Some motion samples will "
@@ -2095,18 +2127,21 @@ void InputDispatcher::synthesizeCancelationEventsForConnectionLocked(
}
int32_t xOffset, yOffset;
+ float scaleFactor;
const InputWindow* window = getWindowLocked(connection->inputChannel);
if (window) {
xOffset = -window->frameLeft;
yOffset = -window->frameTop;
+ scaleFactor = window->scaleFactor;
} else {
xOffset = 0;
yOffset = 0;
+ scaleFactor = 1.0f;
}
DispatchEntry* cancelationDispatchEntry =
mAllocator.obtainDispatchEntry(cancelationEventEntry, // increments ref
- 0, xOffset, yOffset);
+ 0, xOffset, yOffset, scaleFactor);
connection->outboundQueue.enqueueAtTail(cancelationDispatchEntry);
mAllocator.releaseEventEntry(cancelationEventEntry);
@@ -2957,7 +2992,7 @@ void InputDispatcher::dumpDispatchStateLocked(String8& dump) {
const InputWindow& window = mWindows[i];
dump.appendFormat(INDENT2 "%d: name='%s', paused=%s, hasFocus=%s, hasWallpaper=%s, "
"visible=%s, canReceiveKeys=%s, flags=0x%08x, type=0x%08x, layer=%d, "
- "frame=[%d,%d][%d,%d], "
+ "frame=[%d,%d][%d,%d], scale=%f, "
"touchableRegion=",
i, window.name.string(),
toString(window.paused),
@@ -2968,7 +3003,8 @@ void InputDispatcher::dumpDispatchStateLocked(String8& dump) {
window.layoutParamsFlags, window.layoutParamsType,
window.layer,
window.frameLeft, window.frameTop,
- window.frameRight, window.frameBottom);
+ window.frameRight, window.frameBottom,
+ window.scaleFactor);
dumpRegion(dump, window.touchableRegion);
dump.appendFormat(", ownerPid=%d, ownerUid=%d, dispatchingTimeout=%0.3fms\n",
window.ownerPid, window.ownerUid,
@@ -3460,13 +3496,14 @@ InputDispatcher::MotionEntry* InputDispatcher::Allocator::obtainMotionEntry(nsec
InputDispatcher::DispatchEntry* InputDispatcher::Allocator::obtainDispatchEntry(
EventEntry* eventEntry,
- int32_t targetFlags, float xOffset, float yOffset) {
+ int32_t targetFlags, float xOffset, float yOffset, float scaleFactor) {
DispatchEntry* entry = mDispatchEntryPool.alloc();
entry->eventEntry = eventEntry;
eventEntry->refCount += 1;
entry->targetFlags = targetFlags;
entry->xOffset = xOffset;
entry->yOffset = yOffset;
+ entry->scaleFactor = scaleFactor;
entry->inProgress = false;
entry->headMotionSample = NULL;
entry->tailMotionSample = NULL;
diff --git a/services/input/InputDispatcher.h b/services/input/InputDispatcher.h
index 1e118c4..dd89328 100644
--- a/services/input/InputDispatcher.h
+++ b/services/input/InputDispatcher.h
@@ -112,6 +112,10 @@ struct InputTarget {
// (ignored for KeyEvents)
float xOffset, yOffset;
+ // Scaling factor to apply to MotionEvent as it is delivered.
+ // (ignored for KeyEvents)
+ float scaleFactor;
+
// The subset of pointer ids to include in motion events dispatched to this input target
// if FLAG_SPLIT is set.
BitSet32 pointerIds;
@@ -431,6 +435,7 @@ private:
int32_t targetFlags;
float xOffset;
float yOffset;
+ float scaleFactor;
// True if dispatch has started.
bool inProgress;
@@ -559,7 +564,7 @@ private:
nsecs_t downTime, uint32_t pointerCount,
const int32_t* pointerIds, const PointerCoords* pointerCoords);
DispatchEntry* obtainDispatchEntry(EventEntry* eventEntry,
- int32_t targetFlags, float xOffset, float yOffset);
+ int32_t targetFlags, float xOffset, float yOffset, float scaleFactor);
CommandEntry* obtainCommandEntry(Command command);
void releaseInjectionState(InjectionState* injectionState);
diff --git a/services/input/InputWindow.cpp b/services/input/InputWindow.cpp
index b552f6d..ccea9e4 100644
--- a/services/input/InputWindow.cpp
+++ b/services/input/InputWindow.cpp
@@ -29,8 +29,7 @@ bool InputWindow::touchableRegionContainsPoint(int32_t x, int32_t y) const {
}
bool InputWindow::frameContainsPoint(int32_t x, int32_t y) const {
- return x >= frameLeft && x <= frameRight
- && y >= frameTop && y <= frameBottom;
+ return x <= frameRight || y <= frameBottom;
}
bool InputWindow::isTrustedOverlay() const {
diff --git a/services/input/InputWindow.h b/services/input/InputWindow.h
index 9c43067..72f1773 100644
--- a/services/input/InputWindow.h
+++ b/services/input/InputWindow.h
@@ -131,6 +131,7 @@ struct InputWindow {
int32_t frameTop;
int32_t frameRight;
int32_t frameBottom;
+ float scaleFactor;
SkRegion touchableRegion;
bool visible;
bool canReceiveKeys;
@@ -144,6 +145,11 @@ struct InputWindow {
bool touchableRegionContainsPoint(int32_t x, int32_t y) const;
bool frameContainsPoint(int32_t x, int32_t y) const;
+ /* These use the globalScale to convert a given screen offset to the
+ * corresponding location within the window.
+ */
+ int32_t displayToWindowX(int32_t x) const;
+
/* Returns true if the window is of a trusted type that is allowed to silently
* overlay other windows for the purpose of implementing the secure views feature.
* Trusted overlays, such as IME windows, can partly obscure other windows without causing
diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java
index 01ae522..07d050af 100644
--- a/services/java/com/android/server/am/ActivityManagerService.java
+++ b/services/java/com/android/server/am/ActivityManagerService.java
@@ -74,6 +74,7 @@ import android.content.pm.ProviderInfo;
import android.content.pm.ResolveInfo;
import android.content.pm.ServiceInfo;
import android.content.pm.PackageManager.NameNotFoundException;
+import android.content.res.CompatibilityInfo;
import android.content.res.Configuration;
import android.graphics.Bitmap;
import android.net.Proxy;
@@ -146,7 +147,7 @@ public final class ActivityManagerService extends ActivityManagerNative
implements Watchdog.Monitor, BatteryStatsImpl.BatteryCallback {
static final String TAG = "ActivityManager";
static final boolean DEBUG = false;
- static final boolean localLOGV = DEBUG ? Config.LOGD : Config.LOGV;
+ static final boolean localLOGV = DEBUG;
static final boolean DEBUG_SWITCH = localLOGV || false;
static final boolean DEBUG_TASKS = localLOGV || false;
static final boolean DEBUG_PAUSE = localLOGV || false;
@@ -546,6 +547,12 @@ public final class ActivityManagerService extends ActivityManagerNative
ProcessRecord mHomeProcess;
/**
+ * 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>();
+
+ /**
* Set of PendingResultRecord objects that are currently active.
*/
final HashSet mPendingResultRecords = new HashSet();
@@ -2091,6 +2098,74 @@ public final class ActivityManagerService extends ActivityManagerNative
}
}
+ CompatibilityInfo compatibilityInfoForPackageLocked(ApplicationInfo ai) {
+ return new CompatibilityInfo(ai, mConfiguration.screenLayout,
+ mScreenCompatPackages.contains(ai.packageName));
+ }
+
+ public void setPackageScreenCompatMode(String packageName, boolean compatEnabled) {
+ 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);
+
+ // 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) {
+ }
+ }
+
+ // 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;
+ }
+ }
+
+ 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);
+ }
+ }
+ }
+ }
+
void reportResumedActivityLocked(ActivityRecord r) {
//Slog.i(TAG, "**** REPORT RESUME: " + r);
@@ -3589,12 +3664,14 @@ public final class ActivityManagerService extends ActivityManagerNative
}
if (DEBUG_CONFIGURATION) Slog.v(TAG, "Binding proc "
+ processName + " with config " + mConfiguration);
- thread.bindApplication(processName, app.instrumentationInfo != null
- ? app.instrumentationInfo : app.info, providers,
+ ApplicationInfo appInfo = app.instrumentationInfo != null
+ ? app.instrumentationInfo : app.info;
+ thread.bindApplication(processName, appInfo, providers,
app.instrumentationClass, app.instrumentationProfileFile,
app.instrumentationArguments, app.instrumentationWatcher, testMode,
isRestrictedBackupMode || !normalMode,
- mConfiguration, getCommonServicesLocked(),
+ mConfiguration, compatibilityInfoForPackageLocked(appInfo),
+ getCommonServicesLocked(),
mCoreSettingsObserver.getCoreSettingsLocked());
updateLruProcessLocked(app, false, true);
app.lastRequestedGc = app.lastLowMemory = SystemClock.uptimeMillis();
@@ -3685,7 +3762,9 @@ public final class ActivityManagerService extends ActivityManagerNative
if (DEBUG_BACKUP) Slog.v(TAG, "New app is backup target, launching agent for " + app);
ensurePackageDexOpt(mBackupTarget.appInfo.packageName);
try {
- thread.scheduleCreateBackupAgent(mBackupTarget.appInfo, mBackupTarget.backupMode);
+ thread.scheduleCreateBackupAgent(mBackupTarget.appInfo,
+ compatibilityInfoForPackageLocked(mBackupTarget.appInfo),
+ mBackupTarget.backupMode);
} catch (Exception e) {
Slog.w(TAG, "Exception scheduling backup agent creation: ");
e.printStackTrace();
@@ -7784,6 +7863,10 @@ public final class ActivityManagerService extends ActivityManagerNative
}
pw.println(" mConfiguration: " + mConfiguration);
pw.println(" mConfigWillChange: " + mMainStack.mConfigWillChange);
+ if (mScreenCompatPackages.size() > 0) {
+ pw.print(" mScreenCompatPackages=");
+ pw.println(mScreenCompatPackages);
+ }
pw.println(" mSleeping=" + mSleeping + " mShuttingDown=" + mShuttingDown);
if (mDebugApp != null || mOrigDebugApp != null || mDebugTransient
|| mOrigWaitForDebugger) {
@@ -9246,7 +9329,8 @@ public final class ActivityManagerService extends ActivityManagerNative
r.stats.startLaunchedLocked();
}
ensurePackageDexOpt(r.serviceInfo.packageName);
- app.thread.scheduleCreateService(r, r.serviceInfo);
+ app.thread.scheduleCreateService(r, r.serviceInfo,
+ compatibilityInfoForPackageLocked(r.serviceInfo.applicationInfo));
r.postNotification();
created = true;
} finally {
@@ -10350,7 +10434,8 @@ public final class ActivityManagerService extends ActivityManagerNative
if (proc.thread != null) {
if (DEBUG_BACKUP) Slog.v(TAG, "Agent proc already running: " + proc);
try {
- proc.thread.scheduleCreateBackupAgent(app, backupMode);
+ proc.thread.scheduleCreateBackupAgent(app,
+ compatibilityInfoForPackageLocked(app), backupMode);
} catch (RemoteException e) {
// Will time out on the backup manager side
}
@@ -10422,7 +10507,8 @@ public final class ActivityManagerService extends ActivityManagerNative
// If the app crashed during backup, 'thread' will be null here
if (proc.thread != null) {
try {
- proc.thread.scheduleDestroyBackupAgent(appInfo);
+ proc.thread.scheduleDestroyBackupAgent(appInfo,
+ compatibilityInfoForPackageLocked(appInfo));
} catch (Exception e) {
Slog.e(TAG, "Exception when unbinding backup agent:");
e.printStackTrace();
@@ -11269,6 +11355,7 @@ public final class ActivityManagerService extends ActivityManagerNative
+ ": " + r);
ensurePackageDexOpt(r.intent.getComponent().getPackageName());
app.thread.scheduleReceiver(new Intent(r.intent), r.curReceiver,
+ compatibilityInfoForPackageLocked(r.curReceiver.applicationInfo),
r.resultCode, r.resultData, r.resultExtras, r.ordered);
if (DEBUG_BROADCAST) Slog.v(TAG,
"Process cur broadcast " + r + " DELIVERED for app " + app);
diff --git a/services/java/com/android/server/am/ActivityRecord.java b/services/java/com/android/server/am/ActivityRecord.java
index 0fb30ff..cb0a0f0 100644
--- a/services/java/com/android/server/am/ActivityRecord.java
+++ b/services/java/com/android/server/am/ActivityRecord.java
@@ -111,6 +111,7 @@ class ActivityRecord extends IApplicationToken.Stub {
boolean hasBeenLaunched;// has this activity ever been launched?
boolean frozenBeforeDestroy;// has been frozen but not yet destroyed.
boolean immersive; // immersive mode (don't interrupt if possible)
+ boolean forceNewConfig; // force re-create with new config next time
String stringName; // for caching of toString().
@@ -174,7 +175,8 @@ class ActivityRecord extends IApplicationToken.Stub {
pw.print(" immersive="); pw.print(immersive);
pw.print(" launchMode="); pw.println(launchMode);
pw.print(prefix); pw.print("frozenBeforeDestroy="); pw.print(frozenBeforeDestroy);
- pw.print(" thumbnailNeeded="); pw.println(thumbnailNeeded);
+ pw.print(" thumbnailNeeded="); pw.print(thumbnailNeeded);
+ pw.print(" forceNewConfig="); pw.println(forceNewConfig);
if (launchTime != 0 || startTime != 0) {
pw.print(prefix); pw.print("launchTime=");
TimeUtils.formatDuration(launchTime, pw); pw.print(" startTime=");
diff --git a/services/java/com/android/server/am/ActivityStack.java b/services/java/com/android/server/am/ActivityStack.java
index c087aec..f385042 100644
--- a/services/java/com/android/server/am/ActivityStack.java
+++ b/services/java/com/android/server/am/ActivityStack.java
@@ -537,9 +537,11 @@ public class ActivityStack {
}
mService.ensurePackageDexOpt(r.intent.getComponent().getPackageName());
r.sleeping = false;
+ r.forceNewConfig = false;
app.thread.scheduleLaunchActivity(new Intent(r.intent), r,
System.identityHashCode(r),
- r.info, r.icicle, results, newIntents, !andResume,
+ r.info, mService.compatibilityInfoForPackageLocked(r.info.applicationInfo),
+ r.icicle, results, newIntents, !andResume,
mService.isNextTransitionForward());
if ((app.info.flags&ApplicationInfo.FLAG_CANT_SAVE_STATE) != 0) {
@@ -3750,7 +3752,7 @@ public class ActivityStack {
// Short circuit: if the two configurations are the exact same
// object (the common case), then there is nothing to do.
Configuration newConfig = mService.mConfiguration;
- if (r.configuration == newConfig) {
+ if (r.configuration == newConfig && !r.forceNewConfig) {
if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Slog.v(TAG,
"Configuration unchanged in " + r);
return true;
@@ -3775,6 +3777,7 @@ public class ActivityStack {
if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Slog.v(TAG,
"Configuration doesn't matter not running " + r);
r.stopFreezingScreenLocked(false);
+ r.forceNewConfig = false;
return true;
}
@@ -3786,10 +3789,11 @@ public class ActivityStack {
+ Integer.toHexString(r.info.configChanges)
+ ", newConfig=" + newConfig);
}
- if ((changes&(~r.info.configChanges)) != 0) {
+ if ((changes&(~r.info.configChanges)) != 0 || r.forceNewConfig) {
// Aha, the activity isn't handling the change, so DIE DIE DIE.
r.configChangeFlags |= changes;
r.startFreezingScreenLocked(r.app, globalChanges);
+ r.forceNewConfig = false;
if (r.app == null || r.app.thread == null) {
if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Slog.v(TAG,
"Switch is destroying non-running " + r);
@@ -3860,6 +3864,7 @@ public class ActivityStack {
try {
if (DEBUG_SWITCH) Slog.i(TAG, "Switch is restarting resumed " + r);
+ r.forceNewConfig = false;
r.app.thread.scheduleRelaunchActivity(r, results, newIntents,
changes, !andResume, mService.mConfiguration);
// Note: don't need to call pauseIfSleepingLocked() here, because
diff --git a/services/java/com/android/server/am/ProcessRecord.java b/services/java/com/android/server/am/ProcessRecord.java
index 353ff6d..a63ffae 100644
--- a/services/java/com/android/server/am/ProcessRecord.java
+++ b/services/java/com/android/server/am/ProcessRecord.java
@@ -24,6 +24,7 @@ import android.app.IApplicationThread;
import android.app.IInstrumentationWatcher;
import android.content.ComponentName;
import android.content.pm.ApplicationInfo;
+import android.content.res.CompatibilityInfo;
import android.os.Bundle;
import android.os.IBinder;
import android.os.SystemClock;
diff --git a/services/java/com/android/server/wm/InputMonitor.java b/services/java/com/android/server/wm/InputMonitor.java
index 45a78af..57f0799 100644
--- a/services/java/com/android/server/wm/InputMonitor.java
+++ b/services/java/com/android/server/wm/InputMonitor.java
@@ -205,12 +205,21 @@ final class InputMonitor {
inputWindow.ownerPid = child.mSession.mPid;
inputWindow.ownerUid = child.mSession.mUid;
- final Rect frame = child.mFrame;
+ final Rect frame = child.mScaledFrame;
inputWindow.frameLeft = frame.left;
inputWindow.frameTop = frame.top;
inputWindow.frameRight = frame.right;
inputWindow.frameBottom = frame.bottom;
+ if (child.mGlobalScale != 1) {
+ // If we are scaling the window, input coordinates need
+ // to be inversely scaled to map from what is on screen
+ // to what is actually being touched in the UI.
+ inputWindow.scaleFactor = 1.0f/child.mGlobalScale;
+ } else {
+ inputWindow.scaleFactor = 1;
+ }
+
child.getTouchableRegion(inputWindow.touchableRegion);
}
diff --git a/services/java/com/android/server/wm/InputWindow.java b/services/java/com/android/server/wm/InputWindow.java
index e3eb473..578120e 100644
--- a/services/java/com/android/server/wm/InputWindow.java
+++ b/services/java/com/android/server/wm/InputWindow.java
@@ -46,6 +46,10 @@ public final class InputWindow {
public int frameRight;
public int frameBottom;
+ // Global scaling factor applied to touch events when they are dispatched
+ // to the window
+ public float scaleFactor;
+
// Window touchable region.
public final Region touchableRegion = new Region();
diff --git a/services/java/com/android/server/wm/WindowManagerService.java b/services/java/com/android/server/wm/WindowManagerService.java
index 33e6a36..769e423 100644
--- a/services/java/com/android/server/wm/WindowManagerService.java
+++ b/services/java/com/android/server/wm/WindowManagerService.java
@@ -19,7 +19,6 @@ package com.android.server.wm;
import static android.view.WindowManager.LayoutParams.FIRST_APPLICATION_WINDOW;
import static android.view.WindowManager.LayoutParams.FIRST_SUB_WINDOW;
import static android.view.WindowManager.LayoutParams.FLAG_BLUR_BEHIND;
-import static android.view.WindowManager.LayoutParams.FLAG_COMPATIBLE_WINDOW;
import static android.view.WindowManager.LayoutParams.FLAG_DIM_BEHIND;
import static android.view.WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON;
import static android.view.WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
@@ -586,6 +585,7 @@ public class WindowManagerService extends IWindowManager.Stub
// The frame use to limit the size of the app running in compatibility mode.
Rect mCompatibleScreenFrame = new Rect();
+ float mCompatibleScreenScale;
// The surface used to fill the outer rim of the app running in compatibility mode.
Surface mBackgroundFillerSurface = null;
WindowState mBackgroundFillerTarget = null;
@@ -1757,7 +1757,7 @@ public class WindowManagerService extends IWindowManager.Stub
boolean rawChanged = false;
float wpx = mLastWallpaperX >= 0 ? mLastWallpaperX : 0.5f;
float wpxs = mLastWallpaperXStep >= 0 ? mLastWallpaperXStep : -1.0f;
- int availw = wallpaperWin.mFrame.right-wallpaperWin.mFrame.left-dw;
+ int availw = wallpaperWin.mScaledFrame.right-wallpaperWin.mScaledFrame.left-dw;
int offset = availw > 0 ? -(int)(availw*wpx+.5f) : 0;
changed = wallpaperWin.mXOffset != offset;
if (changed) {
@@ -2887,14 +2887,14 @@ public class WindowManagerService extends IWindowManager.Stub
}
private boolean applyAnimationLocked(AppWindowToken wtoken,
- WindowManager.LayoutParams lp, int transit, boolean enter) {
+ WindowManager.LayoutParams lp, int transit, boolean enter, boolean bgFiller) {
// Only apply an animation if the display isn't frozen. If it is
// frozen, there is no reason to animate and it can cause strange
// artifacts when we unfreeze the display if some different animation
// is running.
if (!mDisplayFrozen && mPolicy.isScreenOn()) {
Animation a;
- if (lp != null && (lp.flags & FLAG_COMPATIBLE_WINDOW) != 0) {
+ if (bgFiller) {
a = new FadeInOutAnimation(enter);
if (DEBUG_ANIM) Slog.v(TAG,
"applying FadeInOutAnimation for a window in compatibility mode");
@@ -3680,7 +3680,7 @@ public class WindowManagerService extends IWindowManager.Stub
}
boolean setTokenVisibilityLocked(AppWindowToken wtoken, WindowManager.LayoutParams lp,
- boolean visible, int transit, boolean performLayout) {
+ boolean visible, int transit, boolean performLayout, boolean bgFiller) {
boolean delayed = false;
if (wtoken.clientHidden == visible) {
@@ -3702,7 +3702,7 @@ public class WindowManagerService extends IWindowManager.Stub
if (wtoken.animation == sDummyAnimation) {
wtoken.animation = null;
}
- applyAnimationLocked(wtoken, lp, transit, visible);
+ applyAnimationLocked(wtoken, lp, transit, visible, bgFiller);
changed = true;
if (wtoken.animation != null) {
delayed = runningAppAnimation = true;
@@ -3855,7 +3855,8 @@ public class WindowManagerService extends IWindowManager.Stub
}
final long origId = Binder.clearCallingIdentity();
- setTokenVisibilityLocked(wtoken, null, visible, WindowManagerPolicy.TRANSIT_UNSET, true);
+ setTokenVisibilityLocked(wtoken, null, visible, WindowManagerPolicy.TRANSIT_UNSET,
+ true, false);
wtoken.updateReportedVisibilityLocked();
Binder.restoreCallingIdentity(origId);
}
@@ -3981,7 +3982,8 @@ public class WindowManagerService extends IWindowManager.Stub
WindowToken basewtoken = mTokenMap.remove(token);
if (basewtoken != null && (wtoken=basewtoken.appWindowToken) != null) {
if (DEBUG_APP_TRANSITIONS) Slog.v(TAG, "Removing app token: " + wtoken);
- delayed = setTokenVisibilityLocked(wtoken, null, false, WindowManagerPolicy.TRANSIT_UNSET, true);
+ delayed = setTokenVisibilityLocked(wtoken, null, false,
+ WindowManagerPolicy.TRANSIT_UNSET, true, false);
wtoken.inPendingTransaction = false;
mOpeningApps.remove(wtoken);
wtoken.waitingToShow = false;
@@ -4753,8 +4755,8 @@ public class WindowManagerService extends IWindowManager.Stub
synchronized(mWindowMap) {
long ident = Binder.clearCallingIdentity();
- dw = mDisplay.getWidth();
- dh = mDisplay.getHeight();
+ dw = mPolicy.getNonDecorDisplayWidth(mDisplay.getWidth());
+ dh = mPolicy.getNonDecorDisplayHeight(mDisplay.getHeight());
int aboveAppLayer = mPolicy.windowTypeToLayerLw(
WindowManager.LayoutParams.TYPE_APPLICATION) * TYPE_LAYER_MULTIPLIER
@@ -4802,7 +4804,7 @@ public class WindowManagerService extends IWindowManager.Stub
// Don't include wallpaper in bounds calculation
if (!ws.mIsWallpaper) {
- final Rect wf = ws.mFrame;
+ final Rect wf = ws.mScaledFrame;
final Rect cr = ws.mContentInsets;
int left = wf.left + cr.left;
int top = wf.top + cr.top;
@@ -5447,7 +5449,10 @@ public class WindowManagerService extends IWindowManager.Stub
DisplayMetrics dm = new DisplayMetrics();
mDisplay.getMetrics(dm);
- CompatibilityInfo.updateCompatibleScreenFrame(dm, orientation, mCompatibleScreenFrame);
+ dm.realWidthPixels = mPolicy.getNonDecorDisplayWidth(dm.realWidthPixels);
+ dm.realHeightPixels = mPolicy.getNonDecorDisplayHeight(dm.realHeightPixels);
+ mCompatibleScreenScale = CompatibilityInfo.updateCompatibleScreenFrame(
+ dm, mCompatibleScreenFrame, null);
if (mScreenLayout == Configuration.SCREENLAYOUT_SIZE_UNDEFINED) {
// Note we only do this once because at this point we don't
@@ -6582,6 +6587,9 @@ public class WindowManagerService extends IWindowManager.Stub
final int dw = mDisplay.getWidth();
final int dh = mDisplay.getHeight();
+ final int innerDw = mPolicy.getNonDecorDisplayWidth(dw);
+ final int innerDh = mPolicy.getNonDecorDisplayHeight(dh);
+
final int N = mWindows.size();
int i;
@@ -6634,7 +6642,9 @@ public class WindowManagerService extends IWindowManager.Stub
//Slog.i(TAG, "Window " + this + " clearing mContentChanged - initial");
win.mContentChanged = false;
}
+ win.prelayout();
mPolicy.layoutWindowLw(win, win.mAttrs, null);
+ win.evalNeedsBackgroundFiller(innerDw, innerDh);
win.mLayoutSeq = seq;
if (DEBUG_LAYOUT) Slog.v(TAG, "-> mFrame="
+ win.mFrame + " mContainingFrame="
@@ -6669,7 +6679,9 @@ public class WindowManagerService extends IWindowManager.Stub
//Slog.i(TAG, "Window " + this + " clearing mContentChanged - initial");
win.mContentChanged = false;
}
+ win.prelayout();
mPolicy.layoutWindowLw(win, win.mAttrs, win.mAttachedWindow);
+ win.evalNeedsBackgroundFiller(innerDw, innerDh);
win.mLayoutSeq = seq;
if (DEBUG_LAYOUT) Slog.v(TAG, "-> mFrame="
+ win.mFrame + " mContainingFrame="
@@ -6700,6 +6712,9 @@ public class WindowManagerService extends IWindowManager.Stub
final int dw = mDisplay.getWidth();
final int dh = mDisplay.getHeight();
+ final int innerDw = mPolicy.getNonDecorDisplayWidth(dw);
+ final int innerDh = mPolicy.getNonDecorDisplayHeight(dh);
+
int i;
if (mFocusMayChange) {
@@ -6799,13 +6814,15 @@ public class WindowManagerService extends IWindowManager.Stub
boolean tokensAnimating = false;
final int NAT = mAppTokens.size();
for (i=0; i<NAT; i++) {
- if (mAppTokens.get(i).stepAnimationLocked(currentTime, dw, dh)) {
+ if (mAppTokens.get(i).stepAnimationLocked(currentTime,
+ innerDw, innerDh)) {
tokensAnimating = true;
}
}
final int NEAT = mExitingAppTokens.size();
for (i=0; i<NEAT; i++) {
- if (mExitingAppTokens.get(i).stepAnimationLocked(currentTime, dw, dh)) {
+ if (mExitingAppTokens.get(i).stepAnimationLocked(currentTime,
+ innerDw, innerDh)) {
tokensAnimating = true;
}
}
@@ -6858,8 +6875,8 @@ public class WindowManagerService extends IWindowManager.Stub
final boolean wasAnimating = w.mAnimating;
- int animDw = dw;
- int animDh = dh;
+ int animDw = innerDw;
+ int animDh = innerDh;
// If the window has moved due to its containing
// content frame changing, then we'd like to animate
@@ -7116,6 +7133,7 @@ public class WindowManagerService extends IWindowManager.Stub
LayoutParams animLp = null;
int bestAnimLayer = -1;
boolean fullscreenAnim = false;
+ boolean needBgFiller = false;
if (DEBUG_APP_TRANSITIONS) Slog.v(TAG,
"New wallpaper target=" + mWallpaperTarget
@@ -7155,9 +7173,10 @@ public class WindowManagerService extends IWindowManager.Stub
if (ws != null) {
// If this is a compatibility mode
// window, we will always use its anim.
- if ((ws.mAttrs.flags&FLAG_COMPATIBLE_WINDOW) != 0) {
+ if (ws.mNeedsBackgroundFiller) {
animLp = ws.mAttrs;
bestAnimLayer = Integer.MAX_VALUE;
+ needBgFiller = true;
} else if (!fullscreenAnim || ws.mLayer > bestAnimLayer) {
animLp = ws.mAttrs;
bestAnimLayer = ws.mLayer;
@@ -7222,7 +7241,8 @@ public class WindowManagerService extends IWindowManager.Stub
wtoken.reportedVisible = false;
wtoken.inPendingTransaction = false;
wtoken.animation = null;
- setTokenVisibilityLocked(wtoken, animLp, true, transit, false);
+ setTokenVisibilityLocked(wtoken, animLp, true,
+ transit, false, needBgFiller);
wtoken.updateReportedVisibilityLocked();
wtoken.waitingToShow = false;
wtoken.showAllWindowsLocked();
@@ -7234,7 +7254,8 @@ public class WindowManagerService extends IWindowManager.Stub
"Now closing app" + wtoken);
wtoken.inPendingTransaction = false;
wtoken.animation = null;
- setTokenVisibilityLocked(wtoken, animLp, false, transit, false);
+ setTokenVisibilityLocked(wtoken, animLp, false,
+ transit, false, needBgFiller);
wtoken.updateReportedVisibilityLocked();
wtoken.waitingToHide = false;
// Force the allDrawn flag, because we want to start
@@ -7737,12 +7758,14 @@ public class WindowManagerService extends IWindowManager.Stub
}
boolean opaqueDrawn = canBeSeen && w.isOpaqueDrawn();
- if (opaqueDrawn && w.isFullscreen(dw, dh)) {
+ if (opaqueDrawn && w.isFullscreen(innerDw, innerDh)) {
// This window completely covers everything behind it,
// so we want to leave all of them as unblurred (for
// performance reasons).
obscured = true;
- } else if (w.needsBackgroundFiller(dw, dh) && (canBeSeen || w.isAnimating())) {
+ } else if (w.mNeedsBackgroundFiller && w.mHasDrawn
+ && w.mViewVisibility == View.VISIBLE
+ && (canBeSeen || w.isAnimating())) {
// This window is in compatibility mode, and needs background filler.
obscured = true;
mBackgroundFillerTarget = w;
diff --git a/services/java/com/android/server/wm/WindowState.java b/services/java/com/android/server/wm/WindowState.java
index f8ff5f8..72049ec 100644
--- a/services/java/com/android/server/wm/WindowState.java
+++ b/services/java/com/android/server/wm/WindowState.java
@@ -72,6 +72,7 @@ final class WindowState implements WindowManagerPolicy.WindowState {
final boolean mIsImWindow;
final boolean mIsWallpaper;
final boolean mIsFloatingLayer;
+ final boolean mEnforceSizeCompat;
int mViewVisibility;
boolean mPolicyVisibility = true;
boolean mPolicyVisibilityAfterAnim = true;
@@ -91,6 +92,7 @@ final class WindowState implements WindowManagerPolicy.WindowState {
int mLastLayer;
boolean mHaveFrame;
boolean mObscured;
+ boolean mNeedsBackgroundFiller;
boolean mTurnOnScreen;
int mLayoutSeq = -1;
@@ -154,6 +156,7 @@ final class WindowState implements WindowManagerPolicy.WindowState {
// Current transformation being applied.
boolean mHaveMatrix;
+ float mGlobalScale=1;
float mDsDx=1, mDtDx=0, mDsDy=0, mDtDy=1;
float mLastDsDx=1, mLastDtDx=0, mLastDsDy=0, mLastDtDy=1;
float mHScale=1, mVScale=1;
@@ -163,6 +166,7 @@ final class WindowState implements WindowManagerPolicy.WindowState {
// "Real" frame that the application sees.
final Rect mFrame = new Rect();
final Rect mLastFrame = new Rect();
+ final Rect mScaledFrame = new Rect();
final Rect mContainingFrame = new Rect();
final Rect mDisplayFrame = new Rect();
@@ -273,6 +277,7 @@ final class WindowState implements WindowManagerPolicy.WindowState {
mViewVisibility = viewVisibility;
DeathRecipient deathRecipient = new DeathRecipient();
mAlpha = a.alpha;
+ mEnforceSizeCompat = (mAttrs.flags & FLAG_COMPATIBLE_WINDOW) != 0;
if (WindowManagerService.localLOGV) Slog.v(
WindowManagerService.TAG, "Window " + this + " client=" + c.asBinder()
+ " token=" + token + " (" + mAttrs.token + ")");
@@ -368,7 +373,7 @@ final class WindowState implements WindowManagerPolicy.WindowState {
final Rect display = mDisplayFrame;
display.set(df);
- if ((mAttrs.flags & FLAG_COMPATIBLE_WINDOW) != 0) {
+ if (mEnforceSizeCompat) {
container.intersect(mService.mCompatibleScreenFrame);
if ((mAttrs.flags & FLAG_LAYOUT_NO_LIMITS) == 0) {
display.intersect(mService.mCompatibleScreenFrame);
@@ -416,6 +421,28 @@ final class WindowState implements WindowManagerPolicy.WindowState {
// Now make sure the window fits in the overall display.
Gravity.applyDisplay(mAttrs.gravity, df, frame);
+ int adjRight=0, adjBottom=0;
+
+ if (mEnforceSizeCompat) {
+ // Adjust window offsets by the scaling factor.
+ int xoff = (int)((frame.left-mService.mCompatibleScreenFrame.left)*mGlobalScale)
+ - (frame.left-mService.mCompatibleScreenFrame.left);
+ int yoff = (int)((frame.top-mService.mCompatibleScreenFrame.top)*mGlobalScale)
+ - (frame.top-mService.mCompatibleScreenFrame.top);
+ frame.offset(xoff, yoff);
+
+ // We are temporarily going to apply the compatibility scale
+ // to the window so that we can correctly associate it with the
+ // content and visible frame.
+ adjRight = frame.right - frame.left;
+ adjRight = (int)((adjRight)*mGlobalScale + .5f) - adjRight;
+ adjBottom = frame.bottom - frame.top;
+ adjBottom = (int)((adjBottom)*mGlobalScale + .5f) - adjBottom;
+ frame.right += adjRight;
+ frame.bottom += adjBottom;
+ }
+ mScaledFrame.set(frame);
+
// Make sure the content and visible frames are inside of the
// final window frame.
if (content.left < frame.left) content.left = frame.left;
@@ -439,6 +466,22 @@ final class WindowState implements WindowManagerPolicy.WindowState {
visibleInsets.right = frame.right-visible.right;
visibleInsets.bottom = frame.bottom-visible.bottom;
+ if (mEnforceSizeCompat) {
+ // Scale the computed insets back to the window's compatibility
+ // coordinate space, and put frame back to correct size.
+ final float invScale = 1.0f/mGlobalScale;
+ contentInsets.left = (int)(contentInsets.left*invScale);
+ contentInsets.top = (int)(contentInsets.top*invScale);
+ contentInsets.right = (int)(contentInsets.right*invScale);
+ contentInsets.bottom = (int)(contentInsets.bottom*invScale);
+ visibleInsets.left = (int)(visibleInsets.left*invScale);
+ visibleInsets.top = (int)(visibleInsets.top*invScale);
+ visibleInsets.right = (int)(visibleInsets.right*invScale);
+ visibleInsets.bottom = (int)(visibleInsets.bottom*invScale);
+ frame.right -= adjRight;
+ frame.bottom -= adjBottom;
+ }
+
if (mIsWallpaper && (fw != frame.width() || fh != frame.height())) {
mService.updateWallpaperOffsetLocked(this, mService.mDisplay.getWidth(),
mService.mDisplay.getHeight(), false);
@@ -819,9 +862,10 @@ final class WindowState implements WindowManagerPolicy.WindowState {
if (!mLocalAnimating) {
if (WindowManagerService.DEBUG_ANIM) Slog.v(
WindowManagerService.TAG, "Starting animation in " + this +
- " @ " + currentTime + ": ww=" + mFrame.width() + " wh=" + mFrame.height() +
+ " @ " + currentTime + ": ww=" + mScaledFrame.width() +
+ " wh=" + mScaledFrame.height() +
" dw=" + dw + " dh=" + dh + " scale=" + mService.mWindowAnimationScale);
- mAnimation.initialize(mFrame.width(), mFrame.height(), dw, dh);
+ mAnimation.initialize(mScaledFrame.width(), mScaledFrame.height(), dw, dh);
mAnimation.setStartTime(currentTime);
mLocalAnimating = true;
mAnimating = true;
@@ -988,6 +1032,14 @@ final class WindowState implements WindowManagerPolicy.WindowState {
return true;
}
+ void prelayout() {
+ if (mEnforceSizeCompat) {
+ mGlobalScale = mService.mCompatibleScreenScale;
+ } else {
+ mGlobalScale = 1;
+ }
+ }
+
void computeShownFrameLocked() {
final boolean selfTransformation = mHasLocalTransformation;
Transformation attachedTransformation =
@@ -1031,6 +1083,7 @@ final class WindowState implements WindowManagerPolicy.WindowState {
// Compute the desired transformation.
tmpMatrix.setTranslate(0, 0);
+ tmpMatrix.postScale(mGlobalScale, mGlobalScale);
if (selfTransformation) {
tmpMatrix.postConcat(mTransformation.getMatrix());
}
@@ -1105,10 +1158,10 @@ final class WindowState implements WindowManagerPolicy.WindowState {
}
mShownAlpha = mAlpha;
mHaveMatrix = false;
- mDsDx = 1;
+ mDsDx = mGlobalScale;
mDtDx = 0;
mDsDy = 0;
- mDtDy = 1;
+ mDtDy = mGlobalScale;
}
/**
@@ -1281,12 +1334,14 @@ final class WindowState implements WindowManagerPolicy.WindowState {
&& mService.mPolicy.isScreenOn();
}
- boolean needsBackgroundFiller(int screenWidth, int screenHeight) {
- return
+ void evalNeedsBackgroundFiller(int screenWidth, int screenHeight) {
+ mNeedsBackgroundFiller =
// only if the application is requesting compatible window
- (mAttrs.flags & FLAG_COMPATIBLE_WINDOW) != 0 &&
+ mEnforceSizeCompat &&
// only if it's visible
mHasDrawn && mViewVisibility == View.VISIBLE &&
+ // not needed if the compat window is actually full screen
+ !isFullscreenIgnoringCompat(screenWidth, screenHeight) &&
// and only if the application fills the compatible screen
mFrame.left <= mService.mCompatibleScreenFrame.left &&
mFrame.top <= mService.mCompatibleScreenFrame.top &&
@@ -1295,8 +1350,19 @@ final class WindowState implements WindowManagerPolicy.WindowState {
}
boolean isFullscreen(int screenWidth, int screenHeight) {
- return mFrame.left <= 0 && mFrame.top <= 0 &&
- mFrame.right >= screenWidth && mFrame.bottom >= screenHeight;
+ if (mEnforceSizeCompat) {
+ return mFrame.left <= mService.mCompatibleScreenFrame.left &&
+ mFrame.top <= mService.mCompatibleScreenFrame.top &&
+ mFrame.right >= mService.mCompatibleScreenFrame.right &&
+ mFrame.bottom >= mService.mCompatibleScreenFrame.bottom;
+ } else {
+ return isFullscreenIgnoringCompat(screenWidth, screenHeight);
+ }
+ }
+
+ boolean isFullscreenIgnoringCompat(int screenWidth, int screenHeight) {
+ return mScaledFrame.left <= 0 && mScaledFrame.top <= 0 &&
+ mScaledFrame.right >= screenWidth && mScaledFrame.bottom >= screenHeight;
}
void removeLocked() {
@@ -1426,30 +1492,38 @@ final class WindowState implements WindowManagerPolicy.WindowState {
return true;
}
+ private static void applyScaledInsets(Region outRegion, Rect frame, Rect inset, float scale) {
+ if (scale != 1) {
+ outRegion.set(frame.left + (int)(inset.left*scale),
+ frame.top + (int)(inset.top*scale),
+ frame.right - (int)(inset.right*scale),
+ frame.bottom - (int)(inset.bottom*scale));
+ } else {
+ outRegion.set(
+ frame.left + inset.left, frame.top + inset.top,
+ frame.right - inset.right, frame.bottom - inset.bottom);
+ }
+ }
+
public void getTouchableRegion(Region outRegion) {
- final Rect frame = mFrame;
+ final Rect frame = mScaledFrame;
switch (mTouchableInsets) {
default:
case ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_FRAME:
outRegion.set(frame);
break;
- case ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_CONTENT: {
- final Rect inset = mGivenContentInsets;
- outRegion.set(
- frame.left + inset.left, frame.top + inset.top,
- frame.right - inset.right, frame.bottom - inset.bottom);
+ case ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_CONTENT:
+ applyScaledInsets(outRegion, frame, mGivenContentInsets, mGlobalScale);
break;
- }
- case ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_VISIBLE: {
- final Rect inset = mGivenVisibleInsets;
- outRegion.set(
- frame.left + inset.left, frame.top + inset.top,
- frame.right - inset.right, frame.bottom - inset.bottom);
+ case ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_VISIBLE:
+ applyScaledInsets(outRegion, frame, mGivenVisibleInsets, mGlobalScale);
break;
- }
case ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_REGION: {
final Region givenTouchableRegion = mGivenTouchableRegion;
outRegion.set(givenTouchableRegion);
+ if (mGlobalScale != 1) {
+ outRegion.scale(mGlobalScale);
+ }
outRegion.translate(frame.left, frame.top);
break;
}
@@ -1512,7 +1586,8 @@ final class WindowState implements WindowManagerPolicy.WindowState {
}
pw.print(prefix); pw.print("Requested w="); pw.print(mRequestedWidth);
pw.print(" h="); pw.print(mRequestedHeight);
- pw.print(" mLayoutSeq="); pw.println(mLayoutSeq);
+ pw.print(" mLayoutSeq="); pw.print(mLayoutSeq);
+ pw.print(" mNeedsBackgroundFiller="); pw.println(mNeedsBackgroundFiller);
if (mXOffset != 0 || mYOffset != 0) {
pw.print(prefix); pw.print("Offsets x="); pw.print(mXOffset);
pw.print(" y="); pw.println(mYOffset);
@@ -1533,6 +1608,7 @@ final class WindowState implements WindowManagerPolicy.WindowState {
pw.println();
pw.print(prefix); pw.print("mFrame="); mFrame.printShortString(pw);
pw.print(" last="); mLastFrame.printShortString(pw);
+ pw.print(" scaled="); mScaledFrame.printShortString(pw);
pw.println();
pw.print(prefix); pw.print("mContainingFrame=");
mContainingFrame.printShortString(pw);
@@ -1568,8 +1644,9 @@ final class WindowState implements WindowManagerPolicy.WindowState {
pw.print(" mAlpha="); pw.print(mAlpha);
pw.print(" mLastAlpha="); pw.println(mLastAlpha);
}
- if (mHaveMatrix) {
- pw.print(prefix); pw.print("mDsDx="); pw.print(mDsDx);
+ if (mHaveMatrix || mGlobalScale != 1) {
+ pw.print(prefix); pw.print("mGlobalScale="); pw.print(mGlobalScale);
+ pw.print(" mDsDx="); pw.print(mDsDx);
pw.print(" mDtDx="); pw.print(mDtDx);
pw.print(" mDsDy="); pw.print(mDsDy);
pw.print(" mDtDy="); pw.println(mDtDy);
diff --git a/services/jni/com_android_server_InputWindow.cpp b/services/jni/com_android_server_InputWindow.cpp
index 8548b47..d36c010 100644
--- a/services/jni/com_android_server_InputWindow.cpp
+++ b/services/jni/com_android_server_InputWindow.cpp
@@ -40,6 +40,7 @@ static struct {
jfieldID frameTop;
jfieldID frameRight;
jfieldID frameBottom;
+ jfieldID scaleFactor;
jfieldID touchableRegion;
jfieldID visible;
jfieldID canReceiveKeys;
@@ -102,6 +103,8 @@ void android_server_InputWindow_toNative(
gInputWindowClassInfo.frameRight);
outInputWindow->frameBottom = env->GetIntField(inputWindowObj,
gInputWindowClassInfo.frameBottom);
+ outInputWindow->scaleFactor = env->GetFloatField(inputWindowObj,
+ gInputWindowClassInfo.scaleFactor);
jobject regionObj = env->GetObjectField(inputWindowObj,
gInputWindowClassInfo.touchableRegion);
@@ -176,6 +179,9 @@ int register_android_server_InputWindow(JNIEnv* env) {
GET_FIELD_ID(gInputWindowClassInfo.frameBottom, gInputWindowClassInfo.clazz,
"frameBottom", "I");
+ GET_FIELD_ID(gInputWindowClassInfo.scaleFactor, gInputWindowClassInfo.clazz,
+ "scaleFactor", "F");
+
GET_FIELD_ID(gInputWindowClassInfo.touchableRegion, gInputWindowClassInfo.clazz,
"touchableRegion", "Landroid/graphics/Region;");
diff --git a/tests/DpiTest/src/com/google/android/test/dpi/DpiTestActivity.java b/tests/DpiTest/src/com/google/android/test/dpi/DpiTestActivity.java
index 6192a3c..2a40c57 100644
--- a/tests/DpiTest/src/com/google/android/test/dpi/DpiTestActivity.java
+++ b/tests/DpiTest/src/com/google/android/test/dpi/DpiTestActivity.java
@@ -62,7 +62,8 @@ public class DpiTestActivity extends Activity {
| ApplicationInfo.FLAG_SUPPORTS_SMALL_SCREENS
| ApplicationInfo.FLAG_RESIZEABLE_FOR_SCREENS
| ApplicationInfo.FLAG_SUPPORTS_SCREEN_DENSITIES;
- app.getResources().setCompatibilityInfo(new CompatibilityInfo(ai));
+ app.getResources().setCompatibilityInfo(new CompatibilityInfo(ai,
+ getResources().getConfiguration().screenLayout, false));
}
} catch (PackageManager.NameNotFoundException e) {
throw new RuntimeException("ouch", e);