summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--api/current.txt4
-rw-r--r--cmds/am/src/com/android/commands/am/Am.java53
-rw-r--r--cmds/installd/commands.c43
-rw-r--r--cmds/installd/installd.c6
-rw-r--r--cmds/pm/src/com/android/commands/pm/Pm.java30
-rw-r--r--cmds/svc/src/com/android/commands/svc/PowerCommand.java18
-rw-r--r--core/java/android/app/ActivityManager.java17
-rw-r--r--core/java/android/app/ActivityManagerNative.java53
-rw-r--r--core/java/android/app/ActivityThread.java10
-rw-r--r--core/java/android/app/ApplicationPackageManager.java17
-rw-r--r--core/java/android/app/ContextImpl.java2
-rw-r--r--core/java/android/app/Fragment.java67
-rw-r--r--core/java/android/app/FragmentManager.java16
-rw-r--r--core/java/android/app/IActivityManager.java13
-rw-r--r--core/java/android/content/ContentResolver.java4
-rw-r--r--core/java/android/content/pm/ApplicationInfo.java7
-rw-r--r--core/java/android/content/pm/IPackageManager.aidl2
-rw-r--r--core/java/android/content/pm/InstrumentationInfo.java4
-rw-r--r--core/java/android/content/pm/PackageManager.java62
-rw-r--r--core/java/android/hardware/display/DisplayManager.java63
-rw-r--r--core/java/android/hardware/display/DisplayManagerGlobal.java37
-rw-r--r--core/java/android/hardware/display/IDisplayManager.aidl14
-rw-r--r--core/java/android/hardware/display/WifiDisplay.aidl19
-rw-r--r--core/java/android/hardware/display/WifiDisplay.java107
-rw-r--r--core/java/android/hardware/display/WifiDisplayStatus.aidl19
-rw-r--r--core/java/android/hardware/display/WifiDisplayStatus.java170
-rw-r--r--core/java/android/os/Binder.java14
-rw-r--r--core/java/android/os/PowerManager.java9
-rw-r--r--core/java/android/provider/Settings.java33
-rw-r--r--core/java/android/text/format/Time.java3
-rw-r--r--core/java/android/view/GLES20Canvas.java11
-rw-r--r--core/java/android/view/GLES20Layer.java10
-rw-r--r--core/java/android/view/HardwareLayer.java9
-rw-r--r--core/java/android/view/Surface.java6
-rw-r--r--core/java/android/view/TextureView.java1
-rw-r--r--core/java/android/view/View.java49
-rw-r--r--core/java/com/android/internal/util/DumpUtils.java57
-rw-r--r--core/java/com/android/internal/util/IndentingPrintWriter.java38
-rw-r--r--core/jni/Android.mk1
-rw-r--r--core/jni/AndroidRuntime.cpp2
-rw-r--r--core/jni/android_media_RemoteDisplay.cpp182
-rw-r--r--core/jni/android_text_format_Time.cpp192
-rw-r--r--core/jni/android_view_GLES20Canvas.cpp16
-rw-r--r--core/jni/android_view_Surface.cpp82
-rw-r--r--core/res/AndroidManifest.xml18
-rw-r--r--core/res/res/layout-land/keyguard_host_view.xml7
-rw-r--r--core/res/res/layout-port/keyguard_host_view.xml7
-rw-r--r--core/res/res/layout-sw600dp-land/keyguard_host_view.xml7
-rw-r--r--core/res/res/layout-sw600dp-port/keyguard_host_view.xml7
-rw-r--r--core/res/res/values/public.xml7
-rwxr-xr-xcore/res/res/values/strings.xml10
-rw-r--r--core/tests/coretests/apks/FrameworkCoreTests_apk.mk3
-rw-r--r--core/tests/coretests/apks/install_jni_lib/Android.mk28
-rw-r--r--core/tests/coretests/apks/install_jni_lib/com_android_frameworks_coretests_JNITest.cpp54
-rwxr-xr-xcore/tests/coretests/src/android/content/pm/PackageManagerTests.java1157
-rw-r--r--docs/downloads/training/BitmapFun.zipbin315657 -> 397971 bytes
-rw-r--r--docs/html/training/displaying-bitmaps/cache-bitmap.jd86
-rw-r--r--docs/html/training/displaying-bitmaps/display-bitmap.jd24
-rw-r--r--docs/html/training/displaying-bitmaps/index.jd6
-rw-r--r--docs/html/training/displaying-bitmaps/process-bitmap.jd14
-rw-r--r--graphics/java/android/graphics/drawable/ShapeDrawable.java12
-rw-r--r--graphics/java/android/renderscript/Matrix4f.java28
-rw-r--r--graphics/java/android/renderscript/ScriptIntrinsicColorMatrix.java94
-rw-r--r--graphics/java/android/renderscript/ScriptIntrinsicYuvToRGB.java2
-rw-r--r--include/android_runtime/android_view_Surface.h5
-rw-r--r--libs/hwui/Android.mk1
-rw-r--r--libs/hwui/DisplayListRenderer.cpp109
-rw-r--r--libs/hwui/DisplayListRenderer.h15
-rw-r--r--libs/hwui/Layer.cpp51
-rw-r--r--libs/hwui/Layer.h12
-rw-r--r--libs/hwui/LayerRenderer.cpp2
-rw-r--r--libs/hwui/OpenGLRenderer.cpp22
-rw-r--r--libs/hwui/OpenGLRenderer.h52
-rw-r--r--libs/hwui/ResourceCache.cpp130
-rw-r--r--libs/hwui/ResourceCache.h41
-rw-r--r--media/java/android/media/AudioSystem.java55
-rw-r--r--media/java/android/media/RemoteDisplay.java153
-rw-r--r--packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java56
-rw-r--r--packages/SettingsProvider/src/com/android/providers/settings/SettingsBackupAgent.java2
-rw-r--r--packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java13
-rw-r--r--packages/SystemUI/AndroidManifest.xml3
-rw-r--r--packages/SystemUI/res/drawable-hdpi/ic_qs_airplane_enabled.pngbin0 -> 3736 bytes
-rw-r--r--packages/SystemUI/res/drawable-hdpi/ic_qs_airplane_normal.pngbin0 -> 3645 bytes
-rw-r--r--packages/SystemUI/res/drawable-hdpi/ic_qs_bluetooth_enabled.pngbin0 -> 4346 bytes
-rw-r--r--packages/SystemUI/res/drawable-hdpi/ic_qs_bluetooth_normal.pngbin0 -> 4288 bytes
-rw-r--r--packages/SystemUI/res/drawable-hdpi/ic_qs_rssi_enabled.pngbin0 -> 3251 bytes
-rw-r--r--packages/SystemUI/res/drawable-hdpi/ic_qs_rssi_normal.pngbin0 -> 3232 bytes
-rw-r--r--packages/SystemUI/res/drawable-hdpi/ic_qs_wifi_enabled.pngbin0 -> 3802 bytes
-rw-r--r--packages/SystemUI/res/drawable-hdpi/ic_qs_wifi_normal.pngbin0 -> 3756 bytes
-rw-r--r--packages/SystemUI/res/drawable-mdpi/ic_qs_airplane_enabled.pngbin0 -> 3438 bytes
-rw-r--r--packages/SystemUI/res/drawable-mdpi/ic_qs_airplane_normal.pngbin0 -> 3358 bytes
-rw-r--r--packages/SystemUI/res/drawable-mdpi/ic_qs_bluetooth_enabled.pngbin0 -> 3574 bytes
-rw-r--r--packages/SystemUI/res/drawable-mdpi/ic_qs_bluetooth_normal.pngbin0 -> 3569 bytes
-rw-r--r--packages/SystemUI/res/drawable-mdpi/ic_qs_rssi_enabled.pngbin0 -> 3083 bytes
-rw-r--r--packages/SystemUI/res/drawable-mdpi/ic_qs_rssi_normal.pngbin0 -> 3074 bytes
-rw-r--r--packages/SystemUI/res/drawable-mdpi/ic_qs_wifi_enabled.pngbin0 -> 3337 bytes
-rw-r--r--packages/SystemUI/res/drawable-mdpi/ic_qs_wifi_normal.pngbin0 -> 3321 bytes
-rw-r--r--packages/SystemUI/res/drawable-xhdpi/ic_qs_airplane_enabled.pngbin0 -> 3827 bytes
-rw-r--r--packages/SystemUI/res/drawable-xhdpi/ic_qs_airplane_normal.pngbin0 -> 3747 bytes
-rw-r--r--packages/SystemUI/res/drawable-xhdpi/ic_qs_bluetooth_enabled.pngbin0 -> 4847 bytes
-rw-r--r--packages/SystemUI/res/drawable-xhdpi/ic_qs_bluetooth_normal.pngbin0 -> 5212 bytes
-rw-r--r--packages/SystemUI/res/drawable-xhdpi/ic_qs_rssi_enabled.pngbin0 -> 3499 bytes
-rw-r--r--packages/SystemUI/res/drawable-xhdpi/ic_qs_rssi_normal.pngbin0 -> 3452 bytes
-rw-r--r--packages/SystemUI/res/drawable-xhdpi/ic_qs_wifi_enabled.pngbin0 -> 4465 bytes
-rw-r--r--packages/SystemUI/res/drawable-xhdpi/ic_qs_wifi_normal.pngbin0 -> 4301 bytes
-rw-r--r--packages/SystemUI/res/drawable/ic_qs_battery.xml20
-rw-r--r--packages/SystemUI/res/layout/quick_settings.xml14
-rw-r--r--packages/SystemUI/res/layout/quick_settings_tile.xml20
-rw-r--r--packages/SystemUI/res/layout/quick_settings_tile_airplane.xml25
-rw-r--r--packages/SystemUI/res/layout/quick_settings_tile_battery.xml26
-rw-r--r--packages/SystemUI/res/layout/quick_settings_tile_bluetooth.xml25
-rw-r--r--packages/SystemUI/res/layout/quick_settings_tile_brightness.xml25
-rw-r--r--packages/SystemUI/res/layout/quick_settings_tile_ime.xml23
-rw-r--r--packages/SystemUI/res/layout/quick_settings_tile_location.xml26
-rw-r--r--packages/SystemUI/res/layout/quick_settings_tile_media.xml23
-rw-r--r--packages/SystemUI/res/layout/quick_settings_tile_rssi.xml25
-rw-r--r--packages/SystemUI/res/layout/quick_settings_tile_settings.xml25
-rw-r--r--packages/SystemUI/res/layout/quick_settings_tile_time.xml35
-rw-r--r--packages/SystemUI/res/layout/quick_settings_tile_user.xml26
-rw-r--r--packages/SystemUI/res/layout/quick_settings_tile_wifi.xml25
-rw-r--r--packages/SystemUI/res/layout/quick_settings_tile_wifi_display.xml26
-rw-r--r--packages/SystemUI/res/layout/wifi_display_dialog.xml38
-rw-r--r--packages/SystemUI/res/values-land/config.xml6
-rw-r--r--packages/SystemUI/res/values-land/dimens.xml3
-rw-r--r--packages/SystemUI/res/values/config.xml6
-rw-r--r--packages/SystemUI/res/values/dimens.xml10
-rw-r--r--packages/SystemUI/res/values/strings.xml50
-rw-r--r--packages/SystemUI/res/values/styles.xml22
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java9
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java26
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickSettings.java787
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickSettingsContainerView.java138
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickSettingsTileView.java51
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/SettingsPanelView.java55
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/policy/BatteryController.java16
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/policy/BluetoothController.java15
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/policy/DateView.java4
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/policy/LocationController.java20
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkController.java37
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/policy/QuickSettingsDateView.java45
-rwxr-xr-xpolicy/src/com/android/internal/policy/impl/PhoneWindowManager.java10
-rw-r--r--policy/src/com/android/internal/policy/impl/keyguard/KeyguardHostView.java184
-rw-r--r--policy/src/com/android/internal/policy/impl/keyguard/KeyguardPasswordView.java12
-rw-r--r--services/input/InputReader.cpp106
-rw-r--r--services/input/InputReader.h73
-rw-r--r--services/input/PointerController.cpp19
-rw-r--r--services/input/PointerController.h3
-rw-r--r--services/input/tests/InputReader_test.cpp17
-rw-r--r--services/java/com/android/server/BackupManagerService.java12
-rw-r--r--services/java/com/android/server/DevicePolicyManagerService.java4
-rw-r--r--services/java/com/android/server/SystemServer.java1
-rw-r--r--services/java/com/android/server/UiModeManagerService.java2
-rw-r--r--services/java/com/android/server/accessibility/ScreenMagnifier.java18
-rw-r--r--services/java/com/android/server/am/ActiveServices.java33
-rw-r--r--services/java/com/android/server/am/ActivityManagerService.java261
-rwxr-xr-xservices/java/com/android/server/am/ActivityStack.java12
-rw-r--r--services/java/com/android/server/am/ContentProviderRecord.java2
-rw-r--r--services/java/com/android/server/am/PendingIntentRecord.java1
-rw-r--r--services/java/com/android/server/am/ProviderMap.java43
-rw-r--r--services/java/com/android/server/display/DisplayDevice.java79
-rw-r--r--services/java/com/android/server/display/DisplayDeviceInfo.java72
-rw-r--r--services/java/com/android/server/display/DisplayManagerService.java218
-rw-r--r--services/java/com/android/server/display/DisplayViewport.java65
-rw-r--r--services/java/com/android/server/display/HeadlessDisplayAdapter.java1
-rw-r--r--services/java/com/android/server/display/LocalDisplayAdapter.java9
-rw-r--r--services/java/com/android/server/display/LogicalDisplay.java41
-rw-r--r--services/java/com/android/server/display/OverlayDisplayAdapter.java97
-rw-r--r--services/java/com/android/server/display/OverlayDisplayWindow.java40
-rw-r--r--services/java/com/android/server/display/WifiDisplayAdapter.java428
-rw-r--r--services/java/com/android/server/display/WifiDisplayController.java712
-rw-r--r--services/java/com/android/server/input/InputManagerService.java50
-rw-r--r--services/java/com/android/server/pm/Installer.java14
-rw-r--r--services/java/com/android/server/pm/PackageManagerService.java397
-rw-r--r--services/java/com/android/server/pm/Settings.java18
-rw-r--r--services/java/com/android/server/power/DisplayPowerController.java3
-rw-r--r--services/java/com/android/server/power/PowerManagerService.java12
-rw-r--r--services/java/com/android/server/wm/DisplayContent.java7
-rwxr-xr-xservices/java/com/android/server/wm/WindowManagerService.java115
-rw-r--r--services/jni/com_android_server_input_InputManagerService.cpp126
-rw-r--r--test-runner/src/android/test/mock/MockPackageManager.java13
-rw-r--r--tests/HwAccelerationTest/AndroidManifest.xml9
-rw-r--r--tests/HwAccelerationTest/src/com/android/test/hwui/LinesActivity.java8
-rw-r--r--tests/HwAccelerationTest/src/com/android/test/hwui/TJunctionActivity.java81
-rw-r--r--tests/RenderScriptTests/ImageProcessing/res/drawable-nodpi/city.pngbin611708 -> 0 bytes
-rw-r--r--tests/RenderScriptTests/ImageProcessing/res/drawable-nodpi/img1600x1067.jpgbin0 -> 1062402 bytes
-rw-r--r--tests/RenderScriptTests/ImageProcessing/res/drawable-nodpi/img640x427.jpgbin0 -> 199029 bytes
-rw-r--r--tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/ColorMatrix.java10
-rw-r--r--tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/ImageProcessingActivity.java16
-rw-r--r--tools/aapt/Android.mk1
-rw-r--r--tools/aapt/StringPool.h2
-rw-r--r--wifi/java/android/net/wifi/p2p/WifiP2pDeviceList.java4
-rw-r--r--wifi/java/android/net/wifi/p2p/WifiP2pGroupList.java16
-rw-r--r--wifi/java/android/net/wifi/p2p/WifiP2pService.java17
193 files changed, 7296 insertions, 1790 deletions
diff --git a/api/current.txt b/api/current.txt
index 7ad9cad..f975bf8 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -3353,6 +3353,7 @@ package android.app {
method public final android.app.FragmentManager getFragmentManager();
method public final int getId();
method public android.app.LoaderManager getLoaderManager();
+ method public final android.app.Fragment getParentFragment();
method public final android.content.res.Resources getResources();
method public final boolean getRetainInstance();
method public final java.lang.String getString(int);
@@ -6327,6 +6328,7 @@ package android.content.pm {
field public static final int FLAG_FACTORY_TEST = 16; // 0x10
field public static final int FLAG_HAS_CODE = 4; // 0x4
field public static final int FLAG_INSTALLED = 8388608; // 0x800000
+ field public static final int FLAG_IS_DATA_ONLY = 16777216; // 0x1000000
field public static final int FLAG_KILL_AFTER_RESTORE = 65536; // 0x10000
field public static final int FLAG_LARGE_HEAP = 1048576; // 0x100000
field public static final int FLAG_PERSISTENT = 8; // 0x8
@@ -15616,6 +15618,7 @@ package android.os {
method public static final void flushPendingCommands();
method public static final int getCallingPid();
method public static final int getCallingUid();
+ method public static final android.os.UserHandle getCallingUserHandle();
method public java.lang.String getInterfaceDescriptor();
method public boolean isBinderAlive();
method public static final void joinThreadPool();
@@ -25027,6 +25030,7 @@ package android.view {
method public void setId(int);
method public void setImportantForAccessibility(int);
method public void setKeepScreenOn(boolean);
+ method public void setLayerPaint(android.graphics.Paint);
method public void setLayerType(int, android.graphics.Paint);
method public void setLayoutDirection(int);
method public void setLayoutParams(android.view.ViewGroup.LayoutParams);
diff --git a/cmds/am/src/com/android/commands/am/Am.java b/cmds/am/src/com/android/commands/am/Am.java
index bcd4588..bb108c8 100644
--- a/cmds/am/src/com/android/commands/am/Am.java
+++ b/cmds/am/src/com/android/commands/am/Am.java
@@ -36,6 +36,7 @@ import android.os.ParcelFileDescriptor;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.SystemProperties;
+import android.os.UserHandle;
import android.util.AndroidException;
import android.view.Display;
import android.view.IWindowManager;
@@ -147,6 +148,18 @@ public class Am {
}
}
+ int parseUserArg(String arg) {
+ int userId;
+ if ("all".equals(arg)) {
+ userId = UserHandle.USER_ALL;
+ } else if ("current".equals(arg) || "cur".equals(arg)) {
+ userId = UserHandle.USER_CURRENT;
+ } else {
+ userId = Integer.parseInt(arg);
+ }
+ return userId;
+ }
+
private Intent makeIntent() throws URISyntaxException {
Intent intent = new Intent();
Intent baseIntent = intent;
@@ -321,7 +334,7 @@ public class Am {
} else if (opt.equals("--opengl-trace")) {
mStartFlags |= ActivityManager.START_FLAG_OPENGL_TRACES;
} else if (opt.equals("--user")) {
- mUserId = Integer.parseInt(nextArgRequired());
+ mUserId = parseUserArg(nextArgRequired());
} else {
System.err.println("Error: Unknown option: " + opt);
return null;
@@ -392,8 +405,12 @@ public class Am {
private void runStartService() throws Exception {
Intent intent = makeIntent();
+ if (mUserId == UserHandle.USER_ALL) {
+ System.err.println("Error: Can't start activity with user 'all'");
+ return;
+ }
System.out.println("Starting service: " + intent);
- ComponentName cn = mAm.startService(null, intent, intent.getType(), 0);
+ ComponentName cn = mAm.startService(null, intent, intent.getType(), mUserId);
if (cn == null) {
System.err.println("Error: Not found; no service started.");
}
@@ -402,10 +419,15 @@ public class Am {
private void runStart() throws Exception {
Intent intent = makeIntent();
+ if (mUserId == UserHandle.USER_ALL) {
+ System.err.println("Error: Can't start service with user 'all'");
+ return;
+ }
+
String mimeType = intent.getType();
if (mimeType == null && intent.getData() != null
&& "content".equals(intent.getData().getScheme())) {
- mimeType = mAm.getProviderMimeType(intent.getData());
+ mimeType = mAm.getProviderMimeType(intent.getData(), mUserId);
}
do {
@@ -460,11 +482,11 @@ public class Am {
int res;
if (mWaitOption) {
result = mAm.startActivityAndWait(null, intent, mimeType,
- null, null, 0, mStartFlags, mProfileFile, fd, null);
+ null, null, 0, mStartFlags, mProfileFile, fd, null, mUserId);
res = result.result;
} else {
- res = mAm.startActivity(null, intent, mimeType,
- null, null, 0, mStartFlags, mProfileFile, fd, null);
+ res = mAm.startActivityAsUser(null, intent, mimeType,
+ null, null, 0, mStartFlags, mProfileFile, fd, null, mUserId);
}
PrintStream out = mWaitOption ? System.out : System.err;
boolean launched = false;
@@ -573,6 +595,7 @@ public class Am {
boolean wait = false;
boolean rawMode = false;
boolean no_window_animation = false;
+ int userId = 0;
Bundle args = new Bundle();
String argKey = null, argValue = null;
IWindowManager wm = IWindowManager.Stub.asInterface(ServiceManager.getService("window"));
@@ -592,12 +615,19 @@ public class Am {
} else if (opt.equals("--no_window_animation")
|| opt.equals("--no-window-animation")) {
no_window_animation = true;
+ } else if (opt.equals("--user")) {
+ userId = parseUserArg(nextArgRequired());
} else {
System.err.println("Error: Unknown option: " + opt);
return;
}
}
+ if (userId == UserHandle.USER_ALL) {
+ System.err.println("Error: Can't start instrumentation with user 'all'");
+ return;
+ }
+
String cnArg = nextArgRequired();
ComponentName cn = ComponentName.unflattenFromString(cnArg);
if (cn == null) throw new IllegalArgumentException("Bad component name: " + cnArg);
@@ -614,7 +644,7 @@ public class Am {
wm.setAnimationScale(1, 0.0f);
}
- if (!mAm.startInstrumentation(cn, profileFile, 0, args, watcher)) {
+ if (!mAm.startInstrumentation(cn, profileFile, 0, args, watcher, userId)) {
throw new AndroidException("INSTRUMENTATION_FAILED: " + cn.flattenToString());
}
@@ -1188,8 +1218,10 @@ public class Am {
if (data != null) line = line + ", data=\"" + data + "\"";
if (extras != null) line = line + ", extras: " + extras;
System.out.println(line);
- mFinished = true;
- notifyAll();
+ synchronized (this) {
+ mFinished = true;
+ notifyAll();
+ }
}
public synchronized void waitForFinish() {
@@ -1338,6 +1370,7 @@ public class Am {
" am kill-all\n" +
" am broadcast <INTENT>\n" +
" am instrument [-r] [-e <NAME> <VALUE>] [-p <FILE>] [-w]\n" +
+ " [--user <USER_ID> | all | current]\n" +
" [--no-window-animation] <COMPONENT>\n" +
" am profile start <PROCESS> <FILE>\n" +
" am profile stop [<PROCESS>]\n" +
@@ -1384,6 +1417,7 @@ public class Am {
" -p <FILE>: write profiling data to <FILE>\n" +
" -w: wait for instrumentation to finish before returning. Required for\n" +
" test runners.\n" +
+ " --user [<USER_ID> | all | current]: Specify user instrumentation runs in.\n" +
" --no-window-animation: turn off window animations will running.\n" +
"\n" +
"am profile: start and stop profiler on a process.\n" +
@@ -1431,6 +1465,7 @@ public class Am {
" [--ela <EXTRA_KEY> <EXTRA_LONG_VALUE>[,<EXTRA_LONG_VALUE...]]\n" +
" [--efa <EXTRA_KEY> <EXTRA_FLOAT_VALUE>[,<EXTRA_FLOAT_VALUE...]]\n" +
" [-n <COMPONENT>] [-f <FLAGS>]\n" +
+ " [--user [<USER_ID> | all | current]\n" +
" [--grant-read-uri-permission] [--grant-write-uri-permission]\n" +
" [--debug-log-resolution] [--exclude-stopped-packages]\n" +
" [--include-stopped-packages]\n" +
diff --git a/cmds/installd/commands.c b/cmds/installd/commands.c
index 9e83a67..68f8400 100644
--- a/cmds/installd/commands.c
+++ b/cmds/installd/commands.c
@@ -403,37 +403,6 @@ int rm_dex(const char *path)
}
}
-int protect(char *pkgname, gid_t gid)
-{
- struct stat s;
- char pkgpath[PKG_PATH_MAX];
-
- if (gid < AID_SYSTEM) return -1;
-
- if (create_pkg_path_in_dir(pkgpath, &android_app_private_dir, pkgname, ".apk"))
- return -1;
-
- if (stat(pkgpath, &s) < 0) return -1;
-
- if (chown(pkgpath, s.st_uid, gid) < 0) {
- ALOGE("failed to chgrp '%s': %s\n", pkgpath, strerror(errno));
- return -1;
- }
- if (chmod(pkgpath, S_IRUSR|S_IWUSR|S_IRGRP) < 0) {
- ALOGE("failed to chmod '%s': %s\n", pkgpath, strerror(errno));
- return -1;
- }
-
-#ifdef HAVE_SELINUX
- if (selinux_android_setfilecon(pkgpath, pkgname, s.st_uid) < 0) {
- ALOGE("cannot setfilecon dir '%s': %s\n", pkgpath, strerror(errno));
- return -1;
- }
-#endif
-
- return 0;
-}
-
int get_size(const char *pkgname, int persona, const char *apkpath,
const char *fwdlock_apkpath, const char *asecpath,
int64_t *_codesize, int64_t *_datasize, int64_t *_cachesize,
@@ -1014,13 +983,13 @@ int linklib(const char* dataDir, const char* asecLibDir)
if (stat(dataDir, &s) < 0) return -1;
- if (chown(dataDir, 0, 0) < 0) {
+ if (chown(dataDir, AID_INSTALL, AID_INSTALL) < 0) {
ALOGE("failed to chown '%s': %s\n", dataDir, strerror(errno));
return -1;
}
if (chmod(dataDir, 0700) < 0) {
- ALOGE("failed to chmod '%s': %s\n", dataDir, strerror(errno));
+ ALOGE("linklib() 1: failed to chmod '%s': %s\n", dataDir, strerror(errno));
rc = -1;
goto out;
}
@@ -1058,7 +1027,7 @@ int linklib(const char* dataDir, const char* asecLibDir)
out:
if (chmod(dataDir, s.st_mode) < 0) {
- ALOGE("failed to chmod '%s': %s\n", dataDir, strerror(errno));
+ ALOGE("linklib() 2: failed to chmod '%s': %s\n", dataDir, strerror(errno));
rc = -errno;
}
@@ -1091,13 +1060,13 @@ int unlinklib(const char* dataDir)
return -1;
}
- if (chown(dataDir, 0, 0) < 0) {
+ if (chown(dataDir, AID_INSTALL, AID_INSTALL) < 0) {
ALOGE("failed to chown '%s': %s\n", dataDir, strerror(errno));
return -1;
}
if (chmod(dataDir, 0700) < 0) {
- ALOGE("failed to chmod '%s': %s\n", dataDir, strerror(errno));
+ ALOGE("unlinklib() 1: failed to chmod '%s': %s\n", dataDir, strerror(errno));
rc = -1;
goto out;
}
@@ -1140,7 +1109,7 @@ int unlinklib(const char* dataDir)
out:
if (chmod(dataDir, s.st_mode) < 0) {
- ALOGE("failed to chmod '%s': %s\n", dataDir, strerror(errno));
+ ALOGE("unlinklib() 2: failed to chmod '%s': %s\n", dataDir, strerror(errno));
rc = -1;
}
diff --git a/cmds/installd/installd.c b/cmds/installd/installd.c
index 652543fd..cc8f014 100644
--- a/cmds/installd/installd.c
+++ b/cmds/installd/installd.c
@@ -75,11 +75,6 @@ static int do_rm_cache(char **arg, char reply[REPLY_MAX])
return delete_cache(arg[0]); /* pkgname */
}
-static int do_protect(char **arg, char reply[REPLY_MAX])
-{
- return protect(arg[0], atoi(arg[1])); /* pkgname, gid */
-}
-
static int do_get_size(char **arg, char reply[REPLY_MAX])
{
int64_t codesize = 0;
@@ -153,7 +148,6 @@ struct cmdinfo cmds[] = {
{ "fixuid", 3, do_fixuid },
{ "freecache", 1, do_free_cache },
{ "rmcache", 1, do_rm_cache },
- { "protect", 2, do_protect },
{ "getsize", 5, do_get_size },
{ "rmuserdata", 2, do_rm_user_data },
{ "movefiles", 0, do_movefiles },
diff --git a/cmds/pm/src/com/android/commands/pm/Pm.java b/cmds/pm/src/com/android/commands/pm/Pm.java
index 36bf38a..e0f54fb 100644
--- a/cmds/pm/src/com/android/commands/pm/Pm.java
+++ b/cmds/pm/src/com/android/commands/pm/Pm.java
@@ -20,7 +20,6 @@ import com.android.internal.content.PackageHelper;
import android.app.ActivityManagerNative;
import android.content.ComponentName;
-import android.content.Context;
import android.content.pm.ApplicationInfo;
import android.content.pm.ContainerEncryptionParams;
import android.content.pm.FeatureInfo;
@@ -40,12 +39,10 @@ import android.content.pm.VerificationParams;
import android.content.res.AssetManager;
import android.content.res.Resources;
import android.net.Uri;
-import android.os.Binder;
import android.os.IUserManager;
-import android.os.Process;
import android.os.RemoteException;
import android.os.ServiceManager;
-import android.os.UserManager;
+import android.os.UserHandle;
import java.io.File;
import java.lang.reflect.Field;
@@ -74,7 +71,6 @@ public final class Pm {
private static final String PM_NOT_RUNNING_ERR =
"Error: Could not access the Package Manager. Is the system running?";
- private static final int ROOT_UID = 0;
public static void main(String[] args) {
new Pm().run(args);
@@ -246,6 +242,7 @@ public final class Pm {
boolean listDisabled = false, listEnabled = false;
boolean listSystem = false, listThirdParty = false;
boolean listInstaller = false;
+ int userId = UserHandle.USER_OWNER;
try {
String opt;
while ((opt=nextOption()) != null) {
@@ -265,6 +262,8 @@ public final class Pm {
listThirdParty = true;
} else if (opt.equals("-i")) {
listInstaller = true;
+ } else if (opt.equals("--user")) {
+ userId = Integer.parseInt(nextArg());
} else if (opt.equals("-u")) {
getFlags |= PackageManager.GET_UNINSTALLED_PACKAGES;
} else {
@@ -280,7 +279,7 @@ public final class Pm {
String filter = nextArg();
try {
- final List<PackageInfo> packages = getInstalledPackages(mPm, getFlags);
+ final List<PackageInfo> packages = getInstalledPackages(mPm, getFlags, userId);
int count = packages.size();
for (int p = 0 ; p < count ; p++) {
@@ -314,7 +313,7 @@ public final class Pm {
}
@SuppressWarnings("unchecked")
- private List<PackageInfo> getInstalledPackages(IPackageManager pm, int flags)
+ private List<PackageInfo> getInstalledPackages(IPackageManager pm, int flags, int userId)
throws RemoteException {
final List<PackageInfo> packageInfos = new ArrayList<PackageInfo>();
PackageInfo lastItem = null;
@@ -322,7 +321,7 @@ public final class Pm {
do {
final String lastKey = lastItem != null ? lastItem.packageName : null;
- slice = pm.getInstalledPackages(flags, lastKey);
+ slice = pm.getInstalledPackages(flags, lastKey, userId);
lastItem = slice.populateList(packageInfos, PackageInfo.CREATOR);
} while (!slice.isLastSlice());
@@ -1054,11 +1053,16 @@ public final class Pm {
}
private void runUninstall() {
- int unInstallFlags = 0;
+ int unInstallFlags = PackageManager.DELETE_ALL_USERS;
- String opt = nextOption();
- if (opt != null && opt.equals("-k")) {
- unInstallFlags = PackageManager.DELETE_KEEP_DATA;
+ String opt;
+ while ((opt=nextOption()) != null) {
+ if (opt.equals("-k")) {
+ unInstallFlags |= PackageManager.DELETE_KEEP_DATA;
+ } else {
+ System.err.println("Error: Unknown option: " + opt);
+ return;
+ }
}
String pkg = nextArg();
@@ -1420,7 +1424,7 @@ public final class Pm {
}
private static void showUsage() {
- System.err.println("usage: pm list packages [-f] [-d] [-e] [-s] [-3] [-i] [-u] [FILTER]");
+ System.err.println("usage: pm list packages [-f] [-d] [-e] [-s] [-3] [-i] [-u] [--user USER_ID] [FILTER]");
System.err.println(" pm list permission-groups");
System.err.println(" pm list permissions [-g] [-f] [-d] [-u] [GROUP]");
System.err.println(" pm list instrumentation [-f] [TARGET-PACKAGE]");
diff --git a/cmds/svc/src/com/android/commands/svc/PowerCommand.java b/cmds/svc/src/com/android/commands/svc/PowerCommand.java
index ec3ec3e..58105fa 100644
--- a/cmds/svc/src/com/android/commands/svc/PowerCommand.java
+++ b/cmds/svc/src/com/android/commands/svc/PowerCommand.java
@@ -16,14 +16,12 @@
package com.android.commands.svc;
-import android.os.Binder;
-import android.os.IBinder;
+import android.content.Context;
+import android.os.BatteryManager;
import android.os.IPowerManager;
-import android.os.PowerManager;
-import android.os.ServiceManager;
import android.os.RemoteException;
-import android.os.BatteryManager;
-import android.content.Context;
+import android.os.ServiceManager;
+import android.os.SystemClock;
public class PowerCommand extends Svc.Command {
public PowerCommand() {
@@ -65,10 +63,12 @@ public class PowerCommand extends Svc.Command {
IPowerManager pm
= IPowerManager.Stub.asInterface(ServiceManager.getService(Context.POWER_SERVICE));
try {
- IBinder lock = new Binder();
- pm.acquireWakeLock(lock, PowerManager.FULL_WAKE_LOCK, "svc power", null);
+ if (val != 0) {
+ // if the request is not to set it to false, wake up the screen so that
+ // it can stay on as requested
+ pm.wakeUp(SystemClock.uptimeMillis());
+ }
pm.setStayOnSetting(val);
- pm.releaseWakeLock(lock, 0);
}
catch (RemoteException e) {
System.err.println("Faild to set setting: " + e);
diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java
index cd22aad..bb3c56a 100644
--- a/core/java/android/app/ActivityManager.java
+++ b/core/java/android/app/ActivityManager.java
@@ -1957,4 +1957,21 @@ public class ActivityManager {
return false;
}
}
+
+ /**
+ * Return whether the given user is actively running. This means that
+ * the user is in the "started" state, not "stopped" -- it is currently
+ * allowed to run code through scheduled alarms, receiving broadcasts,
+ * etc. A started user may be either the current foreground user or a
+ * background user; the result here does not distinguish between the two.
+ * @param userid the user's id. Zero indicates the default user.
+ * @hide
+ */
+ public boolean isUserRunning(int userid) {
+ try {
+ return ActivityManagerNative.getDefault().isUserRunning(userid);
+ } catch (RemoteException e) {
+ return false;
+ }
+ }
}
diff --git a/core/java/android/app/ActivityManagerNative.java b/core/java/android/app/ActivityManagerNative.java
index eed9254..e5dd7b1 100644
--- a/core/java/android/app/ActivityManagerNative.java
+++ b/core/java/android/app/ActivityManagerNative.java
@@ -177,9 +177,10 @@ public abstract class ActivityManagerNative extends Binder implements IActivityM
? data.readFileDescriptor() : null;
Bundle options = data.readInt() != 0
? Bundle.CREATOR.createFromParcel(data) : null;
+ int userId = data.readInt();
WaitResult result = startActivityAndWait(app, intent, resolvedType,
resultTo, resultWho, requestCode, startFlags,
- profileFile, profileFd, options);
+ profileFile, profileFd, options, userId);
reply.writeNoException();
result.writeToParcel(reply, 0);
return true;
@@ -811,7 +812,8 @@ public abstract class ActivityManagerNative extends Binder implements IActivityM
Bundle arguments = data.readBundle();
IBinder b = data.readStrongBinder();
IInstrumentationWatcher w = IInstrumentationWatcher.Stub.asInterface(b);
- boolean res = startInstrumentation(className, profileFile, fl, arguments, w);
+ int userId = data.readInt();
+ boolean res = startInstrumentation(className, profileFile, fl, arguments, w, userId);
reply.writeNoException();
reply.writeInt(res ? 1 : 0);
return true;
@@ -1323,11 +1325,11 @@ public abstract class ActivityManagerNative extends Binder implements IActivityM
return true;
}
- case KILL_APPLICATION_WITH_UID_TRANSACTION: {
+ case KILL_APPLICATION_WITH_APPID_TRANSACTION: {
data.enforceInterface(IActivityManager.descriptor);
String pkg = data.readString();
- int uid = data.readInt();
- killApplicationWithUid(pkg, uid);
+ int appid = data.readInt();
+ killApplicationWithAppId(pkg, appid);
reply.writeNoException();
return true;
}
@@ -1424,7 +1426,8 @@ public abstract class ActivityManagerNative extends Binder implements IActivityM
case GET_PROVIDER_MIME_TYPE_TRANSACTION: {
data.enforceInterface(IActivityManager.descriptor);
Uri uri = Uri.CREATOR.createFromParcel(data);
- String type = getProviderMimeType(uri);
+ int userId = data.readInt();
+ String type = getProviderMimeType(uri, userId);
reply.writeNoException();
reply.writeString(type);
return true;
@@ -1573,6 +1576,15 @@ public abstract class ActivityManagerNative extends Binder implements IActivityM
return true;
}
+ case IS_USER_RUNNING_TRANSACTION: {
+ data.enforceInterface(IActivityManager.descriptor);
+ int userid = data.readInt();
+ boolean result = isUserRunning(userid);
+ reply.writeNoException();
+ reply.writeInt(result ? 1 : 0);
+ return true;
+ }
+
case REMOVE_SUB_TASK_TRANSACTION:
{
data.enforceInterface(IActivityManager.descriptor);
@@ -1827,7 +1839,7 @@ class ActivityManagerProxy implements IActivityManager
public WaitResult startActivityAndWait(IApplicationThread caller, Intent intent,
String resolvedType, IBinder resultTo, String resultWho,
int requestCode, int startFlags, String profileFile,
- ParcelFileDescriptor profileFd, Bundle options) throws RemoteException {
+ ParcelFileDescriptor profileFd, Bundle options, int userId) throws RemoteException {
Parcel data = Parcel.obtain();
Parcel reply = Parcel.obtain();
data.writeInterfaceToken(IActivityManager.descriptor);
@@ -1851,6 +1863,7 @@ class ActivityManagerProxy implements IActivityManager
} else {
data.writeInt(0);
}
+ data.writeInt(userId);
mRemote.transact(START_ACTIVITY_AND_WAIT_TRANSACTION, data, reply, 0);
reply.readException();
WaitResult result = WaitResult.CREATOR.createFromParcel(reply);
@@ -2719,7 +2732,7 @@ class ActivityManagerProxy implements IActivityManager
}
public boolean startInstrumentation(ComponentName className, String profileFile,
- int flags, Bundle arguments, IInstrumentationWatcher watcher)
+ int flags, Bundle arguments, IInstrumentationWatcher watcher, int userId)
throws RemoteException {
Parcel data = Parcel.obtain();
Parcel reply = Parcel.obtain();
@@ -2729,6 +2742,7 @@ class ActivityManagerProxy implements IActivityManager
data.writeInt(flags);
data.writeBundle(arguments);
data.writeStrongBinder(watcher != null ? watcher.asBinder() : null);
+ data.writeInt(userId);
mRemote.transact(START_INSTRUMENTATION_TRANSACTION, data, reply, 0);
reply.readException();
boolean res = reply.readInt() != 0;
@@ -3366,13 +3380,13 @@ class ActivityManagerProxy implements IActivityManager
data.recycle();
}
- public void killApplicationWithUid(String pkg, int uid) throws RemoteException {
+ public void killApplicationWithAppId(String pkg, int appid) throws RemoteException {
Parcel data = Parcel.obtain();
Parcel reply = Parcel.obtain();
data.writeInterfaceToken(IActivityManager.descriptor);
data.writeString(pkg);
- data.writeInt(uid);
- mRemote.transact(KILL_APPLICATION_WITH_UID_TRANSACTION, data, reply, 0);
+ data.writeInt(appid);
+ mRemote.transact(KILL_APPLICATION_WITH_APPID_TRANSACTION, data, reply, 0);
reply.readException();
data.recycle();
reply.recycle();
@@ -3507,12 +3521,12 @@ class ActivityManagerProxy implements IActivityManager
reply.recycle();
}
- public String getProviderMimeType(Uri uri)
- throws RemoteException {
+ public String getProviderMimeType(Uri uri, int userId) throws RemoteException {
Parcel data = Parcel.obtain();
Parcel reply = Parcel.obtain();
data.writeInterfaceToken(IActivityManager.descriptor);
uri.writeToParcel(data, 0);
+ data.writeInt(userId);
mRemote.transact(GET_PROVIDER_MIME_TYPE_TRANSACTION, data, reply, 0);
reply.readException();
String res = reply.readString();
@@ -3747,6 +3761,19 @@ class ActivityManagerProxy implements IActivityManager
return userInfo;
}
+ public boolean isUserRunning(int userid) throws RemoteException {
+ Parcel data = Parcel.obtain();
+ Parcel reply = Parcel.obtain();
+ data.writeInterfaceToken(IActivityManager.descriptor);
+ data.writeInt(userid);
+ mRemote.transact(IS_USER_RUNNING_TRANSACTION, data, reply, 0);
+ reply.readException();
+ boolean result = reply.readInt() != 0;
+ reply.recycle();
+ data.recycle();
+ return result;
+ }
+
public boolean removeSubTask(int taskId, int subTaskIndex) throws RemoteException {
Parcel data = Parcel.obtain();
Parcel reply = Parcel.obtain();
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index 97dcec0..38e6970 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -1586,7 +1586,15 @@ public final class ActivityThread {
CompatibilityInfoHolder cih = new CompatibilityInfoHolder();
cih.set(ci);
Display d = displayManager.getCompatibleDisplay(displayId, cih);
- d.getMetrics(dm);
+ if (d != null) {
+ d.getMetrics(dm);
+ } else {
+ // Display no longer exists
+ // FIXME: This would not be a problem if we kept the Display object around
+ // instead of using the raw display id everywhere. The Display object caches
+ // its information even after the display has been removed.
+ dm.setToDefaults();
+ }
//Slog.i("foo", "New metrics: w=" + metrics.widthPixels + " h="
// + metrics.heightPixels + " den=" + metrics.density
// + " xdpi=" + metrics.xdpi + " ydpi=" + metrics.ydpi);
diff --git a/core/java/android/app/ApplicationPackageManager.java b/core/java/android/app/ApplicationPackageManager.java
index c4f1371..7870031 100644
--- a/core/java/android/app/ApplicationPackageManager.java
+++ b/core/java/android/app/ApplicationPackageManager.java
@@ -407,6 +407,12 @@ final class ApplicationPackageManager extends PackageManager {
@SuppressWarnings("unchecked")
@Override
public List<PackageInfo> getInstalledPackages(int flags) {
+ return getInstalledPackages(flags, UserHandle.myUserId());
+ }
+
+ /** @hide */
+ @Override
+ public List<PackageInfo> getInstalledPackages(int flags, int userId) {
try {
final List<PackageInfo> packageInfos = new ArrayList<PackageInfo>();
PackageInfo lastItem = null;
@@ -414,7 +420,7 @@ final class ApplicationPackageManager extends PackageManager {
do {
final String lastKey = lastItem != null ? lastItem.packageName : null;
- slice = mPM.getInstalledPackages(flags, lastKey);
+ slice = mPM.getInstalledPackages(flags, lastKey, userId);
lastItem = slice.populateList(packageInfos, PackageInfo.CREATOR);
} while (!slice.isLastSlice());
@@ -460,12 +466,19 @@ final class ApplicationPackageManager extends PackageManager {
@Override
public List<ResolveInfo> queryIntentActivities(Intent intent,
int flags) {
+ return queryIntentActivitiesForUser(intent, flags, UserHandle.myUserId());
+ }
+
+ /** @hide Same as above but for a specific user */
+ @Override
+ public List<ResolveInfo> queryIntentActivitiesForUser(Intent intent,
+ int flags, int userId) {
try {
return mPM.queryIntentActivities(
intent,
intent.resolveTypeIfNeeded(mContext.getContentResolver()),
flags,
- UserHandle.myUserId());
+ userId);
} catch (RemoteException e) {
throw new RuntimeException("Package manager has died", e);
}
diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java
index 65ea6a0..3498919 100644
--- a/core/java/android/app/ContextImpl.java
+++ b/core/java/android/app/ContextImpl.java
@@ -1428,7 +1428,7 @@ class ContextImpl extends Context {
arguments.setAllowFds(false);
}
return ActivityManagerNative.getDefault().startInstrumentation(
- className, profileFile, 0, arguments, null);
+ className, profileFile, 0, arguments, null, UserHandle.myUserId());
} catch (RemoteException e) {
// System has crashed, nothing we can do.
}
diff --git a/core/java/android/app/Fragment.java b/core/java/android/app/Fragment.java
index 3ff9df5..c5a382d 100644
--- a/core/java/android/app/Fragment.java
+++ b/core/java/android/app/Fragment.java
@@ -615,7 +615,7 @@ public class Fragment implements ComponentCallbacks2, OnCreateContextMenuListene
+ " did not call through to super.onViewStateRestored()");
}
}
-
+
final void setIndex(int index, Fragment parent) {
mIndex = index;
if (parent != null) {
@@ -623,8 +623,8 @@ public class Fragment implements ComponentCallbacks2, OnCreateContextMenuListene
} else {
mWho = "android:fragment:" + mIndex;
}
- }
-
+ }
+
final boolean isInBackStack() {
return mBackStackNesting > 0;
}
@@ -832,6 +832,14 @@ public class Fragment implements ComponentCallbacks2, OnCreateContextMenuListene
}
/**
+ * Returns the parent Fragment containing this Fragment. If this Fragment
+ * is attached directly to an Activity, returns null.
+ */
+ final public Fragment getParentFragment() {
+ return mParentFragment;
+ }
+
+ /**
* Return true if the fragment is currently added to its activity.
*/
final public boolean isAdded() {
@@ -1180,20 +1188,7 @@ public class Fragment implements ComponentCallbacks2, OnCreateContextMenuListene
public void onCreate(Bundle savedInstanceState) {
mCalled = true;
}
-
- /**
- * Called immediately after {@link #onCreateView(LayoutInflater, ViewGroup, Bundle)}
- * has returned, but before any saved state has been restored in to the view.
- * This gives subclasses a chance to initialize themselves once
- * they know their view hierarchy has been completely created. The fragment's
- * view hierarchy is not however attached to its parent at this point.
- * @param view The View returned by {@link #onCreateView(LayoutInflater, ViewGroup, Bundle)}.
- * @param savedInstanceState If non-null, this fragment is being re-constructed
- * from a previous saved state as given here.
- */
- public void onViewCreated(View view, Bundle savedInstanceState) {
- }
-
+
/**
* Called to have the fragment instantiate its user interface view.
* This is optional, and non-graphical fragments can return null (which
@@ -1217,6 +1212,19 @@ public class Fragment implements ComponentCallbacks2, OnCreateContextMenuListene
Bundle savedInstanceState) {
return null;
}
+
+ /**
+ * Called immediately after {@link #onCreateView(LayoutInflater, ViewGroup, Bundle)}
+ * has returned, but before any saved state has been restored in to the view.
+ * This gives subclasses a chance to initialize themselves once
+ * they know their view hierarchy has been completely created. The fragment's
+ * view hierarchy is not however attached to its parent at this point.
+ * @param view The View returned by {@link #onCreateView(LayoutInflater, ViewGroup, Bundle)}.
+ * @param savedInstanceState If non-null, this fragment is being re-constructed
+ * from a previous saved state as given here.
+ */
+ public void onViewCreated(View view, Bundle savedInstanceState) {
+ }
/**
* Get the root view for the fragment's layout (the one returned by {@link #onCreateView}),
@@ -1237,7 +1245,7 @@ public class Fragment implements ComponentCallbacks2, OnCreateContextMenuListene
* as this callback tells the fragment when it is fully associated with
* the new activity instance. This is called after {@link #onCreateView}
* and before {@link #onViewStateRestored(Bundle)}.
- *
+ *
* @param savedInstanceState If the fragment is being re-created from
* a previous saved state, this is the state.
*/
@@ -1252,7 +1260,7 @@ public class Fragment implements ComponentCallbacks2, OnCreateContextMenuListene
* whether check box widgets are currently checked. This is called
* after {@link #onActivityCreated(Bundle)} and before
* {@link #onStart()}.
- *
+ *
* @param savedInstanceState If the fragment is being re-created from
* a previous saved state, this is the state.
*/
@@ -1590,10 +1598,6 @@ public class Fragment implements ComponentCallbacks2, OnCreateContextMenuListene
writer.print(prefix); writer.print("mActivity=");
writer.println(mActivity);
}
- if (mChildFragmentManager != null) {
- writer.print(prefix); writer.print("mChildFragmentManager=");
- writer.println(mChildFragmentManager);
- }
if (mParentFragment != null) {
writer.print(prefix); writer.print("mParentFragment=");
writer.println(mParentFragment);
@@ -1633,7 +1637,7 @@ public class Fragment implements ComponentCallbacks2, OnCreateContextMenuListene
mLoaderManager.dump(prefix + " ", fd, writer, args);
}
if (mChildFragmentManager != null) {
- writer.print(prefix); writer.println("Child Fragment Manager:");
+ writer.print(prefix); writer.println("Child " + mChildFragmentManager + ":");
mChildFragmentManager.dump(prefix + " ", fd, writer, args);
}
}
@@ -1662,6 +1666,9 @@ public class Fragment implements ComponentCallbacks2, OnCreateContextMenuListene
}
void performCreate(Bundle savedInstanceState) {
+ if (mChildFragmentManager != null) {
+ mChildFragmentManager.noteStateNotSaved();
+ }
mCalled = false;
onCreate(savedInstanceState);
if (!mCalled) {
@@ -1680,7 +1687,18 @@ public class Fragment implements ComponentCallbacks2, OnCreateContextMenuListene
}
}
+ View performCreateView(LayoutInflater inflater, ViewGroup container,
+ Bundle savedInstanceState) {
+ if (mChildFragmentManager != null) {
+ mChildFragmentManager.noteStateNotSaved();
+ }
+ return onCreateView(inflater, container, savedInstanceState);
+ }
+
void performActivityCreated(Bundle savedInstanceState) {
+ if (mChildFragmentManager != null) {
+ mChildFragmentManager.noteStateNotSaved();
+ }
mCalled = false;
onActivityCreated(savedInstanceState);
if (!mCalled) {
@@ -1713,6 +1731,7 @@ public class Fragment implements ComponentCallbacks2, OnCreateContextMenuListene
void performResume() {
if (mChildFragmentManager != null) {
+ mChildFragmentManager.noteStateNotSaved();
mChildFragmentManager.execPendingActions();
}
mCalled = false;
diff --git a/core/java/android/app/FragmentManager.java b/core/java/android/app/FragmentManager.java
index eaaf0d7..7f11437 100644
--- a/core/java/android/app/FragmentManager.java
+++ b/core/java/android/app/FragmentManager.java
@@ -834,7 +834,9 @@ final class FragmentManagerImpl extends FragmentManager {
throw new SuperNotCalledException("Fragment " + f
+ " did not call through to super.onAttach()");
}
- mActivity.onAttachFragment(f);
+ if (f.mParentFragment == null) {
+ mActivity.onAttachFragment(f);
+ }
if (!f.mRetaining) {
f.performCreate(f.mSavedFragmentState);
@@ -844,8 +846,8 @@ final class FragmentManagerImpl extends FragmentManager {
// For fragments that are part of the content view
// layout, we need to instantiate the view immediately
// and the inflater will take care of adding it.
- f.mView = f.onCreateView(f.getLayoutInflater(f.mSavedFragmentState),
- null, f.mSavedFragmentState);
+ f.mView = f.performCreateView(f.getLayoutInflater(
+ f.mSavedFragmentState), null, f.mSavedFragmentState);
if (f.mView != null) {
f.mView.setSaveFromParentEnabled(false);
if (f.mHidden) f.mView.setVisibility(View.GONE);
@@ -868,8 +870,8 @@ final class FragmentManagerImpl extends FragmentManager {
}
}
f.mContainer = container;
- f.mView = f.onCreateView(f.getLayoutInflater(f.mSavedFragmentState),
- container, f.mSavedFragmentState);
+ f.mView = f.performCreateView(f.getLayoutInflater(
+ f.mSavedFragmentState), container, f.mSavedFragmentState);
if (f.mView != null) {
f.mView.setSaveFromParentEnabled(false);
if (container != null) {
@@ -885,7 +887,7 @@ final class FragmentManagerImpl extends FragmentManager {
f.onViewCreated(f.mView, f.mSavedFragmentState);
}
}
-
+
f.performActivityCreated(f.mSavedFragmentState);
if (f.mView != null) {
f.restoreViewState(f.mSavedFragmentState);
@@ -1824,7 +1826,7 @@ final class FragmentManagerImpl extends FragmentManager {
public void dispatchDestroyView() {
moveToState(Fragment.CREATED, false);
}
-
+
public void dispatchDestroy() {
mDestroyed = true;
execPendingActions();
diff --git a/core/java/android/app/IActivityManager.java b/core/java/android/app/IActivityManager.java
index 7a633ed..9cb3621 100644
--- a/core/java/android/app/IActivityManager.java
+++ b/core/java/android/app/IActivityManager.java
@@ -62,7 +62,7 @@ public interface IActivityManager extends IInterface {
public WaitResult startActivityAndWait(IApplicationThread caller,
Intent intent, String resolvedType, IBinder resultTo, String resultWho,
int requestCode, int flags, String profileFile,
- ParcelFileDescriptor profileFd, Bundle options) throws RemoteException;
+ ParcelFileDescriptor profileFd, Bundle options, int userId) throws RemoteException;
public int startActivityWithConfig(IApplicationThread caller,
Intent intent, String resolvedType, IBinder resultTo, String resultWho,
int requestCode, int startFlags, Configuration newConfig,
@@ -160,7 +160,7 @@ public interface IActivityManager extends IInterface {
public void killApplicationProcess(String processName, int uid) throws RemoteException;
public boolean startInstrumentation(ComponentName className, String profileFile,
- int flags, Bundle arguments, IInstrumentationWatcher watcher)
+ int flags, Bundle arguments, IInstrumentationWatcher watcher, int userId)
throws RemoteException;
public void finishInstrumentation(IApplicationThread target,
int resultCode, Bundle results) throws RemoteException;
@@ -275,7 +275,7 @@ public interface IActivityManager extends IInterface {
public void stopAppSwitches() throws RemoteException;
public void resumeAppSwitches() throws RemoteException;
- public void killApplicationWithUid(String pkg, int uid) throws RemoteException;
+ public void killApplicationWithAppId(String pkg, int appid) throws RemoteException;
public void closeSystemDialogs(String reason) throws RemoteException;
@@ -296,7 +296,7 @@ public interface IActivityManager extends IInterface {
public void crashApplication(int uid, int initialPid, String packageName,
String message) throws RemoteException;
- public String getProviderMimeType(Uri uri) throws RemoteException;
+ public String getProviderMimeType(Uri uri, int userId) throws RemoteException;
public IBinder newUriPermissionOwner(String name) throws RemoteException;
public void grantUriPermissionFromOwner(IBinder owner, int fromUid, String targetPkg,
@@ -328,6 +328,7 @@ public interface IActivityManager extends IInterface {
public boolean switchUser(int userid) throws RemoteException;
public int stopUser(int userid, IStopUserCallback callback) throws RemoteException;
public UserInfo getCurrentUser() throws RemoteException;
+ public boolean isUserRunning(int userid) throws RemoteException;
public boolean removeSubTask(int taskId, int subTaskIndex) throws RemoteException;
@@ -548,7 +549,7 @@ public interface IActivityManager extends IInterface {
int GET_UID_FOR_INTENT_SENDER_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+92;
int HANDLE_INCOMING_USER_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+93;
- int KILL_APPLICATION_WITH_UID_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+95;
+ int KILL_APPLICATION_WITH_APPID_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+95;
int CLOSE_SYSTEM_DIALOGS_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+96;
int GET_PROCESS_MEMORY_INFO_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+97;
int KILL_APPLICATION_PROCESS_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+98;
@@ -574,7 +575,7 @@ public interface IActivityManager extends IInterface {
int CHECK_GRANT_URI_PERMISSION_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+118;
int DUMP_HEAP_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+119;
int START_ACTIVITIES_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+120;
-
+ int IS_USER_RUNNING_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+121;
int ACTIVITY_SLEPT_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+122;
int GET_FRONT_ACTIVITY_SCREEN_COMPAT_MODE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+123;
int SET_FRONT_ACTIVITY_SCREEN_COMPAT_MODE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+124;
diff --git a/core/java/android/content/ContentResolver.java b/core/java/android/content/ContentResolver.java
index 0a5a26a..ece8841 100644
--- a/core/java/android/content/ContentResolver.java
+++ b/core/java/android/content/ContentResolver.java
@@ -39,6 +39,7 @@ import android.os.ParcelFileDescriptor;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.SystemClock;
+import android.os.UserHandle;
import android.text.TextUtils;
import android.util.EventLog;
import android.util.Log;
@@ -230,7 +231,8 @@ public abstract class ContentResolver {
}
try {
- String type = ActivityManagerNative.getDefault().getProviderMimeType(url);
+ String type = ActivityManagerNative.getDefault().getProviderMimeType(
+ url, UserHandle.myUserId());
return type;
} catch (RemoteException e) {
// Arbitrary and not worth documenting, as Activity
diff --git a/core/java/android/content/pm/ApplicationInfo.java b/core/java/android/content/pm/ApplicationInfo.java
index 1a82d58..a0283d3 100644
--- a/core/java/android/content/pm/ApplicationInfo.java
+++ b/core/java/android/content/pm/ApplicationInfo.java
@@ -308,6 +308,13 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable {
public static final int FLAG_INSTALLED = 1<<23;
/**
+ * Value for {@link #flags}: true if the application only has its
+ * data installed; the application package itself does not currently
+ * exist on the device.
+ */
+ public static final int FLAG_IS_DATA_ONLY = 1<<24;
+
+ /**
* Value for {@link #flags}: Set to true if the application has been
* installed using the forward lock option.
*
diff --git a/core/java/android/content/pm/IPackageManager.aidl b/core/java/android/content/pm/IPackageManager.aidl
index 0e1fe3e..b0ae5da 100644
--- a/core/java/android/content/pm/IPackageManager.aidl
+++ b/core/java/android/content/pm/IPackageManager.aidl
@@ -127,7 +127,7 @@ interface IPackageManager {
* limit that kicks in when flags are included that bloat up the data
* returned.
*/
- ParceledListSlice getInstalledPackages(int flags, in String lastRead);
+ ParceledListSlice getInstalledPackages(int flags, in String lastRead, in int userId);
/**
* This implements getInstalledApplications via a "last returned row"
diff --git a/core/java/android/content/pm/InstrumentationInfo.java b/core/java/android/content/pm/InstrumentationInfo.java
index ea47e8e..a977e41 100644
--- a/core/java/android/content/pm/InstrumentationInfo.java
+++ b/core/java/android/content/pm/InstrumentationInfo.java
@@ -18,10 +18,6 @@ package android.content.pm;
import android.os.Parcel;
import android.os.Parcelable;
-import android.text.TextUtils;
-
-import java.text.Collator;
-import java.util.Comparator;
/**
* Information you can retrieve about a particular piece of test
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index e5ddfda..5399583 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -1469,6 +1469,45 @@ public abstract class PackageManager {
public abstract List<PackageInfo> getInstalledPackages(int flags);
/**
+ * Return a List of all packages that are installed on the device, for a specific user.
+ * Requesting a list of installed packages for another user
+ * will require the permission INTERACT_ACROSS_USERS_FULL.
+ * @param flags Additional option flags. Use any combination of
+ * {@link #GET_ACTIVITIES},
+ * {@link #GET_GIDS},
+ * {@link #GET_CONFIGURATIONS},
+ * {@link #GET_INSTRUMENTATION},
+ * {@link #GET_PERMISSIONS},
+ * {@link #GET_PROVIDERS},
+ * {@link #GET_RECEIVERS},
+ * {@link #GET_SERVICES},
+ * {@link #GET_SIGNATURES},
+ * {@link #GET_UNINSTALLED_PACKAGES} to modify the data returned.
+ * @param userId The user for whom the installed packages are to be listed
+ *
+ * @return A List of PackageInfo objects, one for each package that is
+ * installed on the device. In the unlikely case of there being no
+ * installed packages, an empty list is returned.
+ * If flag GET_UNINSTALLED_PACKAGES is set, a list of all
+ * applications including those deleted with DONT_DELETE_DATA
+ * (partially installed apps with data directory) will be returned.
+ *
+ * @see #GET_ACTIVITIES
+ * @see #GET_GIDS
+ * @see #GET_CONFIGURATIONS
+ * @see #GET_INSTRUMENTATION
+ * @see #GET_PERMISSIONS
+ * @see #GET_PROVIDERS
+ * @see #GET_RECEIVERS
+ * @see #GET_SERVICES
+ * @see #GET_SIGNATURES
+ * @see #GET_UNINSTALLED_PACKAGES
+ *
+ * @hide
+ */
+ public abstract List<PackageInfo> getInstalledPackages(int flags, int userId);
+
+ /**
* Check whether a particular package has been granted a particular
* permission.
*
@@ -1755,6 +1794,29 @@ public abstract class PackageManager {
int flags);
/**
+ * Retrieve all activities that can be performed for the given intent, for a specific user.
+ *
+ * @param intent The desired intent as per resolveActivity().
+ * @param flags Additional option flags. The most important is
+ * {@link #MATCH_DEFAULT_ONLY}, to limit the resolution to only
+ * those activities that support the {@link android.content.Intent#CATEGORY_DEFAULT}.
+ *
+ * @return A List&lt;ResolveInfo&gt; containing one entry for each matching
+ * Activity. These are ordered from best to worst match -- that
+ * is, the first item in the list is what is returned by
+ * {@link #resolveActivity}. If there are no matching activities, an empty
+ * list is returned.
+ *
+ * @see #MATCH_DEFAULT_ONLY
+ * @see #GET_INTENT_FILTERS
+ * @see #GET_RESOLVED_FILTER
+ * @hide
+ */
+ public abstract List<ResolveInfo> queryIntentActivitiesForUser(Intent intent,
+ int flags, int userId);
+
+
+ /**
* Retrieve a set of activities that should be presented to the user as
* similar options. This is like {@link #queryIntentActivities}, except it
* also allows you to supply a list of more explicit Intents that you would
diff --git a/core/java/android/hardware/display/DisplayManager.java b/core/java/android/hardware/display/DisplayManager.java
index 2814301..4347e75 100644
--- a/core/java/android/hardware/display/DisplayManager.java
+++ b/core/java/android/hardware/display/DisplayManager.java
@@ -40,6 +40,28 @@ public final class DisplayManager {
private final Object mLock = new Object();
private final SparseArray<Display> mDisplays = new SparseArray<Display>();
+ /**
+ * Broadcast receiver that indicates when the Wifi display status changes.
+ * <p>
+ * The status is provided as a {@link WifiDisplayStatus} object in the
+ * {@link #EXTRA_WIFI_DISPLAY_STATUS} extra.
+ * </p><p>
+ * This broadcast is only sent to registered receivers with the
+ * {@link android.Manifest.permission#CONFIGURE_WIFI_DISPLAY} permission and can
+ * only be sent by the system.
+ * </p>
+ * @hide
+ */
+ public static final String ACTION_WIFI_DISPLAY_STATUS_CHANGED =
+ "android.hardware.display.action.WIFI_DISPLAY_STATUS_CHANGED";
+
+ /**
+ * Contains a {@link WifiDisplayStatus} object.
+ * @hide
+ */
+ public static final String EXTRA_WIFI_DISPLAY_STATUS =
+ "android.hardware.display.extra.WIFI_DISPLAY_STATUS";
+
/** @hide */
public DisplayManager(Context context) {
mContext = context;
@@ -127,6 +149,47 @@ public final class DisplayManager {
}
/**
+ * Initiates a fresh scan of availble Wifi displays.
+ * The results are sent as a {@link #ACTION_WIFI_DISPLAY_STATUS_CHANGED} broadcast.
+ * @hide
+ */
+ public void scanWifiDisplays() {
+ mGlobal.scanWifiDisplays();
+ }
+
+ /**
+ * Connects to a Wifi display.
+ * The results are sent as a {@link #ACTION_WIFI_DISPLAY_STATUS_CHANGED} broadcast.
+ *
+ * @param deviceAddress The MAC address of the device to which we should connect.
+ * @hide
+ */
+ public void connectWifiDisplay(String deviceAddress) {
+ mGlobal.connectWifiDisplay(deviceAddress);
+ }
+
+ /**
+ * Disconnects from the current Wifi display.
+ * The results are sent as a {@link #ACTION_WIFI_DISPLAY_STATUS_CHANGED} broadcast.
+ * @hide
+ */
+ public void disconnectWifiDisplay() {
+ mGlobal.disconnectWifiDisplay();
+ }
+
+ /**
+ * Gets the current Wifi display status.
+ * Watch for changes in the status by registering a broadcast receiver for
+ * {@link #ACTION_WIFI_DISPLAY_STATUS_CHANGED}.
+ *
+ * @return The current Wifi display status.
+ * @hide
+ */
+ public WifiDisplayStatus getWifiDisplayStatus() {
+ return mGlobal.getWifiDisplayStatus();
+ }
+
+ /**
* Listens for changes in available display devices.
*/
public interface DisplayListener {
diff --git a/core/java/android/hardware/display/DisplayManagerGlobal.java b/core/java/android/hardware/display/DisplayManagerGlobal.java
index 4077964..14b5440 100644
--- a/core/java/android/hardware/display/DisplayManagerGlobal.java
+++ b/core/java/android/hardware/display/DisplayManagerGlobal.java
@@ -253,6 +253,43 @@ public final class DisplayManagerGlobal {
}
}
+ public void scanWifiDisplays() {
+ try {
+ mDm.scanWifiDisplays();
+ } catch (RemoteException ex) {
+ Log.e(TAG, "Failed to scan for Wifi displays.", ex);
+ }
+ }
+
+ public void connectWifiDisplay(String deviceAddress) {
+ if (deviceAddress == null) {
+ throw new IllegalArgumentException("deviceAddress must not be null");
+ }
+
+ try {
+ mDm.connectWifiDisplay(deviceAddress);
+ } catch (RemoteException ex) {
+ Log.e(TAG, "Failed to connect to Wifi display " + deviceAddress + ".", ex);
+ }
+ }
+
+ public void disconnectWifiDisplay() {
+ try {
+ mDm.disconnectWifiDisplay();
+ } catch (RemoteException ex) {
+ Log.e(TAG, "Failed to disconnect from Wifi display.", ex);
+ }
+ }
+
+ public WifiDisplayStatus getWifiDisplayStatus() {
+ try {
+ return mDm.getWifiDisplayStatus();
+ } catch (RemoteException ex) {
+ Log.e(TAG, "Failed to get Wifi display status.", ex);
+ return new WifiDisplayStatus();
+ }
+ }
+
private final class DisplayManagerCallback extends IDisplayManagerCallback.Stub {
@Override
public void onDisplayEvent(int displayId, int event) {
diff --git a/core/java/android/hardware/display/IDisplayManager.aidl b/core/java/android/hardware/display/IDisplayManager.aidl
index d802aa1..36a9a7f 100644
--- a/core/java/android/hardware/display/IDisplayManager.aidl
+++ b/core/java/android/hardware/display/IDisplayManager.aidl
@@ -17,6 +17,8 @@
package android.hardware.display;
import android.hardware.display.IDisplayManagerCallback;
+import android.hardware.display.WifiDisplay;
+import android.hardware.display.WifiDisplayStatus;
import android.view.DisplayInfo;
/** @hide */
@@ -25,4 +27,16 @@ interface IDisplayManager {
int[] getDisplayIds();
void registerCallback(in IDisplayManagerCallback callback);
+
+ // Requires CONFIGURE_WIFI_DISPLAY permission.
+ void scanWifiDisplays();
+
+ // Requires CONFIGURE_WIFI_DISPLAY permission.
+ void connectWifiDisplay(String address);
+
+ // Requires CONFIGURE_WIFI_DISPLAY permission.
+ void disconnectWifiDisplay();
+
+ // Requires CONFIGURE_WIFI_DISPLAY permission.
+ WifiDisplayStatus getWifiDisplayStatus();
}
diff --git a/core/java/android/hardware/display/WifiDisplay.aidl b/core/java/android/hardware/display/WifiDisplay.aidl
new file mode 100644
index 0000000..7733075
--- /dev/null
+++ b/core/java/android/hardware/display/WifiDisplay.aidl
@@ -0,0 +1,19 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.display;
+
+parcelable WifiDisplay;
diff --git a/core/java/android/hardware/display/WifiDisplay.java b/core/java/android/hardware/display/WifiDisplay.java
new file mode 100644
index 0000000..e51e97e
--- /dev/null
+++ b/core/java/android/hardware/display/WifiDisplay.java
@@ -0,0 +1,107 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.display;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+/**
+ * Describes the properties of a Wifi display.
+ * <p>
+ * This object is immutable.
+ * </p>
+ *
+ * @hide
+ */
+public final class WifiDisplay implements Parcelable {
+ private final String mDeviceAddress;
+ private final String mDeviceName;
+
+ public static final WifiDisplay[] EMPTY_ARRAY = new WifiDisplay[0];
+
+ public static final Creator<WifiDisplay> CREATOR = new Creator<WifiDisplay>() {
+ public WifiDisplay createFromParcel(Parcel in) {
+ String deviceAddress = in.readString();
+ String deviceName = in.readString();
+ return new WifiDisplay(deviceAddress, deviceName);
+ }
+
+ public WifiDisplay[] newArray(int size) {
+ return size == 0 ? EMPTY_ARRAY : new WifiDisplay[size];
+ }
+ };
+
+ public WifiDisplay(String deviceAddress, String deviceName) {
+ if (deviceAddress == null) {
+ throw new IllegalArgumentException("deviceAddress must not be null");
+ }
+ if (deviceName == null) {
+ throw new IllegalArgumentException("deviceName must not be null");
+ }
+
+ mDeviceAddress = deviceAddress;
+ mDeviceName = deviceName;
+ }
+
+ /**
+ * Gets the MAC address of the Wifi display device.
+ */
+ public String getDeviceAddress() {
+ return mDeviceAddress;
+ }
+
+ /**
+ * Gets the name of the Wifi display device.
+ */
+ public String getDeviceName() {
+ return mDeviceName;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ return o instanceof WifiDisplay && equals((WifiDisplay)o);
+ }
+
+ public boolean equals(WifiDisplay other) {
+ return other != null
+ && mDeviceAddress.equals(other.mDeviceAddress)
+ && mDeviceName.equals(other.mDeviceName);
+ }
+
+ @Override
+ public int hashCode() {
+ // The address on its own should be sufficiently unique for hashing purposes.
+ return mDeviceAddress.hashCode();
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeString(mDeviceAddress);
+ dest.writeString(mDeviceName);
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ // For debugging purposes only.
+ @Override
+ public String toString() {
+ return mDeviceName + " (" + mDeviceAddress + ")";
+ }
+}
diff --git a/core/java/android/hardware/display/WifiDisplayStatus.aidl b/core/java/android/hardware/display/WifiDisplayStatus.aidl
new file mode 100644
index 0000000..35c633e
--- /dev/null
+++ b/core/java/android/hardware/display/WifiDisplayStatus.aidl
@@ -0,0 +1,19 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.display;
+
+parcelable WifiDisplayStatus;
diff --git a/core/java/android/hardware/display/WifiDisplayStatus.java b/core/java/android/hardware/display/WifiDisplayStatus.java
new file mode 100644
index 0000000..d5fe45d
--- /dev/null
+++ b/core/java/android/hardware/display/WifiDisplayStatus.java
@@ -0,0 +1,170 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.display;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import java.util.Arrays;
+
+/**
+ * Describes the current global state of Wifi display connectivity, including the
+ * currently connected display and all known displays.
+ * <p>
+ * This object is immutable.
+ * </p>
+ *
+ * @hide
+ */
+public final class WifiDisplayStatus implements Parcelable {
+ private final boolean mEnabled;
+ private final int mScanState;
+ private final int mActiveDisplayState;
+ private final WifiDisplay mActiveDisplay;
+ private final WifiDisplay[] mKnownDisplays;
+
+ public static final int SCAN_STATE_NOT_SCANNING = 0;
+ public static final int SCAN_STATE_SCANNING = 1;
+
+ public static final int DISPLAY_STATE_NOT_CONNECTED = 0;
+ public static final int DISPLAY_STATE_CONNECTING = 1;
+ public static final int DISPLAY_STATE_CONNECTED = 2;
+
+ public static final Creator<WifiDisplayStatus> CREATOR = new Creator<WifiDisplayStatus>() {
+ public WifiDisplayStatus createFromParcel(Parcel in) {
+ boolean enabled = (in.readInt() != 0);
+ int scanState = in.readInt();
+ int activeDisplayState= in.readInt();
+
+ WifiDisplay activeDisplay = null;
+ if (in.readInt() != 0) {
+ activeDisplay = WifiDisplay.CREATOR.createFromParcel(in);
+ }
+
+ WifiDisplay[] knownDisplays = WifiDisplay.CREATOR.newArray(in.readInt());
+ for (int i = 0; i < knownDisplays.length; i++) {
+ knownDisplays[i] = WifiDisplay.CREATOR.createFromParcel(in);
+ }
+
+ return new WifiDisplayStatus(enabled, scanState, activeDisplayState,
+ activeDisplay, knownDisplays);
+ }
+
+ public WifiDisplayStatus[] newArray(int size) {
+ return new WifiDisplayStatus[size];
+ }
+ };
+
+ public WifiDisplayStatus() {
+ this(false, SCAN_STATE_NOT_SCANNING, DISPLAY_STATE_NOT_CONNECTED,
+ null, WifiDisplay.EMPTY_ARRAY);
+ }
+
+ public WifiDisplayStatus(boolean enabled, int scanState, int activeDisplayState,
+ WifiDisplay activeDisplay, WifiDisplay[] knownDisplays) {
+ if (knownDisplays == null) {
+ throw new IllegalArgumentException("knownDisplays must not be null");
+ }
+
+ mEnabled = enabled;
+ mScanState = scanState;
+ mActiveDisplayState = activeDisplayState;
+ mActiveDisplay = activeDisplay;
+ mKnownDisplays = knownDisplays;
+ }
+
+ /**
+ * Returns true if the Wifi display feature is enabled and available for use.
+ * <p>
+ * The value of this property reflects whether Wifi and Wifi P2P functions
+ * are enabled. Enablement is not directly controllable by the user at this
+ * time, except indirectly such as by turning off Wifi altogether.
+ * </p>
+ */
+ public boolean isEnabled() {
+ return mEnabled;
+ }
+
+ /**
+ * Returns the current state of the Wifi display scan.
+ *
+ * @return One of: {@link #SCAN_STATE_NOT_SCANNING} or {@link #SCAN_STATE_SCANNING}.
+ */
+ public int getScanState() {
+ return mScanState;
+ }
+
+ /**
+ * Get the state of the currently active display.
+ *
+ * @return One of: {@link #DISPLAY_STATE_NOT_CONNECTED}, {@link #DISPLAY_STATE_CONNECTING},
+ * or {@link #DISPLAY_STATE_CONNECTED}.
+ */
+ public int getActiveDisplayState() {
+ return mActiveDisplayState;
+ }
+
+ /**
+ * Gets the Wifi display that is currently active. It may be connecting or
+ * connected.
+ */
+ public WifiDisplay getActiveDisplay() {
+ return mActiveDisplay;
+ }
+
+ /**
+ * Gets the list of all known Wifi displays, never null.
+ */
+ public WifiDisplay[] getKnownDisplays() {
+ return mKnownDisplays;
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeInt(mEnabled ? 1 : 0);
+ dest.writeInt(mScanState);
+ dest.writeInt(mActiveDisplayState);
+
+ if (mActiveDisplay != null) {
+ dest.writeInt(1);
+ mActiveDisplay.writeToParcel(dest, flags);
+ } else {
+ dest.writeInt(0);
+ }
+
+ dest.writeInt(mKnownDisplays.length);
+ for (WifiDisplay display : mKnownDisplays) {
+ display.writeToParcel(dest, flags);
+ }
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ // For debugging purposes only.
+ @Override
+ public String toString() {
+ return "WifiDisplayStatus{enabled=" + mEnabled
+ + ", scanState=" + mScanState
+ + ", activeDisplayState=" + mActiveDisplayState
+ + ", activeDisplay=" + mActiveDisplay
+ + ", knownDisplays=" + Arrays.toString(mKnownDisplays)
+ + "}";
+ }
+}
diff --git a/core/java/android/os/Binder.java b/core/java/android/os/Binder.java
index ea14098..16b4835 100644
--- a/core/java/android/os/Binder.java
+++ b/core/java/android/os/Binder.java
@@ -64,7 +64,7 @@ public class Binder implements IBinder {
public static final native int getCallingPid();
/**
- * Return the ID of the user assigned to the process that sent you the
+ * Return the Linux uid assigned to the process that sent you the
* current transaction that is being processed. This uid can be used with
* higher-level system services to determine its identity and check
* permissions. If the current thread is not currently executing an
@@ -73,6 +73,18 @@ public class Binder implements IBinder {
public static final native int getCallingUid();
/**
+ * Return the UserHandle assigned to the process that sent you the
+ * current transaction that is being processed. This is the user
+ * of the caller. It is distinct from {@link #getCallingUid()} in that a
+ * particular user will have multiple distinct apps running under it each
+ * with their own uid. If the current thread is not currently executing an
+ * incoming transaction, then its own UserHandle is returned.
+ */
+ public static final UserHandle getCallingUserHandle() {
+ return new UserHandle(UserHandle.getUserId(getCallingUid()));
+ }
+
+ /**
* Reset the identity of the incoming IPC on the current thread. This can
* be useful if, while handling an incoming call, you will be calling
* on interfaces of other objects that may be local to your process and
diff --git a/core/java/android/os/PowerManager.java b/core/java/android/os/PowerManager.java
index a1901a5..cc2c002 100644
--- a/core/java/android/os/PowerManager.java
+++ b/core/java/android/os/PowerManager.java
@@ -331,6 +331,15 @@ public final class PowerManager {
}
/**
+ * Returns true if the screen auto-brightness adjustment setting should
+ * be available in the UI. This setting is experimental and disabled by default.
+ * @hide
+ */
+ public static boolean useScreenAutoBrightnessAdjustmentFeature() {
+ return SystemProperties.getBoolean("persist.power.useautobrightadj", false);
+ }
+
+ /**
* Creates a new wake lock with the specified level and flags.
* <p>
* The {@code levelAndFlags} parameter specifies a wake lock level and optional flags
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index d7ae441..841a076 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -878,6 +878,8 @@ public final class Settings {
private static final HashSet<String> MOVED_TO_GLOBAL;
static {
MOVED_TO_GLOBAL = new HashSet<String>();
+ // these were originally in system but migrated to secure in the past,
+ // so are duplicated in the Secure.* namespace
MOVED_TO_GLOBAL.add(Global.ADB_ENABLED);
MOVED_TO_GLOBAL.add(Global.BLUETOOTH_ON);
MOVED_TO_GLOBAL.add(Global.DATA_ROAMING);
@@ -885,6 +887,7 @@ public final class Settings {
MOVED_TO_GLOBAL.add(Global.INSTALL_NON_MARKET_APPS);
MOVED_TO_GLOBAL.add(Global.USB_MASS_STORAGE_ENABLED);
+ // these are moving directly from system to global
MOVED_TO_GLOBAL.add(Settings.Global.AIRPLANE_MODE_ON);
MOVED_TO_GLOBAL.add(Settings.Global.AIRPLANE_MODE_RADIOS);
MOVED_TO_GLOBAL.add(Settings.Global.AIRPLANE_MODE_TOGGLEABLE_RADIOS);
@@ -4779,17 +4782,24 @@ public final class Settings {
/**
* Whether the package manager should send package verification broadcasts for verifiers to
* review apps prior to installation.
- *
+ * @deprecated moved to Settings.Global
* 1 = request apps to be verified prior to installation, if a verifier exists.
* 0 = do not verify apps before installation
* {@hide}
*/
+ @Deprecated
public static final String PACKAGE_VERIFIER_ENABLE = "package_verifier_enable";
- /** Timeout for package verification. {@hide} */
+ /** Timeout for package verification.
+ * @deprecated moved to Settings.Global
+ * {@hide} */
+ @Deprecated
public static final String PACKAGE_VERIFIER_TIMEOUT = "verifier_timeout";
- /** Default response code for package verification. {@hide} */
+ /** Default response code for package verification.
+ * @deprecated moved to Settings.Global
+ * {@hide} */
+ @Deprecated
public static final String PACKAGE_VERIFIER_DEFAULT_RESPONSE = "verifier_default_response";
/** {@hide} */
@@ -5269,6 +5279,23 @@ public final class Settings {
public static final String NTP_TIMEOUT = "ntp_timeout";
/**
+ * Whether the package manager should send package verification broadcasts for verifiers to
+ * review apps prior to installation.
+ * 1 = request apps to be verified prior to installation, if a verifier exists.
+ * 0 = do not verify apps before installation
+ * {@hide}
+ */
+ public static final String PACKAGE_VERIFIER_ENABLE = "package_verifier_enable";
+
+ /** Timeout for package verification.
+ * {@hide} */
+ public static final String PACKAGE_VERIFIER_TIMEOUT = "verifier_timeout";
+
+ /** Default response code for package verification.
+ * {@hide} */
+ public static final String PACKAGE_VERIFIER_DEFAULT_RESPONSE = "verifier_default_response";
+
+ /**
* The interval in milliseconds at which to check packet counts on the
* mobile data interface when screen is on, to detect possible data
* connection problems.
diff --git a/core/java/android/text/format/Time.java b/core/java/android/text/format/Time.java
index e9b0d32..b0b18da 100644
--- a/core/java/android/text/format/Time.java
+++ b/core/java/android/text/format/Time.java
@@ -437,6 +437,9 @@ public class Time {
* @throws android.util.TimeFormatException if s cannot be parsed.
*/
public boolean parse(String s) {
+ if (s == null) {
+ throw new NullPointerException("time string is null");
+ }
if (nativeParse(s)) {
timezone = TIMEZONE_UTC;
return true;
diff --git a/core/java/android/view/GLES20Canvas.java b/core/java/android/view/GLES20Canvas.java
index f4ab133..869cd00 100644
--- a/core/java/android/view/GLES20Canvas.java
+++ b/core/java/android/view/GLES20Canvas.java
@@ -152,6 +152,8 @@ class GLES20Canvas extends HardwareCanvas {
static native int nCreateLayer(int width, int height, boolean isOpaque, int[] layerInfo);
static native void nResizeLayer(int layerId, int width, int height, int[] layerInfo);
static native void nSetOpaqueLayer(int layerId, boolean isOpaque);
+ static native void nSetLayerPaint(int layerId, int nativePaint);
+ static native void nSetLayerColorFilter(int layerId, int nativeColorFilter);
static native void nUpdateTextureLayer(int layerId, int width, int height, boolean opaque,
SurfaceTexture surface);
static native void nSetTextureLayerTransform(int layerId, int matrix);
@@ -394,13 +396,8 @@ class GLES20Canvas extends HardwareCanvas {
void drawHardwareLayer(HardwareLayer layer, float x, float y, Paint paint) {
final GLES20Layer glLayer = (GLES20Layer) layer;
- int modifier = paint != null ? setupColorFilter(paint) : MODIFIER_NONE;
- try {
- final int nativePaint = paint == null ? 0 : paint.mNativePaint;
- nDrawLayer(mRenderer, glLayer.getLayer(), x, y, nativePaint);
- } finally {
- if (modifier != MODIFIER_NONE) nResetModifiers(mRenderer, modifier);
- }
+ final int nativePaint = paint == null ? 0 : paint.mNativePaint;
+ nDrawLayer(mRenderer, glLayer.getLayer(), x, y, nativePaint);
}
private static native void nDrawLayer(int renderer, int layer, float x, float y, int paint);
diff --git a/core/java/android/view/GLES20Layer.java b/core/java/android/view/GLES20Layer.java
index a0ae379..a462ed6 100644
--- a/core/java/android/view/GLES20Layer.java
+++ b/core/java/android/view/GLES20Layer.java
@@ -18,6 +18,7 @@
package android.view;
import android.graphics.Bitmap;
+import android.graphics.Paint;
/**
* An OpenGL ES 2.0 implementation of {@link HardwareLayer}.
@@ -43,6 +44,15 @@ abstract class GLES20Layer extends HardwareLayer {
}
@Override
+ void setLayerPaint(Paint paint) {
+ if (paint != null) {
+ GLES20Canvas.nSetLayerPaint(mLayer, paint.mNativePaint);
+ GLES20Canvas.nSetLayerColorFilter(mLayer, paint.getColorFilter() != null ?
+ paint.getColorFilter().nativeColorFilter : 0);
+ }
+ }
+
+ @Override
boolean copyInto(Bitmap bitmap) {
return GLES20Canvas.nCopyLayer(mLayer, bitmap.mNativeBitmap);
}
diff --git a/core/java/android/view/HardwareLayer.java b/core/java/android/view/HardwareLayer.java
index 06c6e7c..6e763b2 100644
--- a/core/java/android/view/HardwareLayer.java
+++ b/core/java/android/view/HardwareLayer.java
@@ -19,6 +19,7 @@ package android.view;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Matrix;
+import android.graphics.Paint;
import android.graphics.Rect;
/**
@@ -62,6 +63,14 @@ abstract class HardwareLayer {
}
/**
+ * Update the paint used when drawing this layer.
+ *
+ * @param paint The paint used when the layer is drawn into the destination canvas.
+ * @see View#setLayerPaint(android.graphics.Paint)
+ */
+ void setLayerPaint(Paint paint) {}
+
+ /**
* Returns the minimum width of the layer.
*
* @return The minimum desired width of the hardware layer
diff --git a/core/java/android/view/Surface.java b/core/java/android/view/Surface.java
index db05e10..8f4626f 100644
--- a/core/java/android/view/Surface.java
+++ b/core/java/android/view/Surface.java
@@ -259,7 +259,7 @@ public class Surface implements Parcelable {
private static native IBinder nativeGetBuiltInDisplay(int physicalDisplayId);
private static native IBinder nativeCreateDisplay(String name);
private static native void nativeSetDisplaySurface(
- IBinder displayToken, SurfaceTexture surfaceTexture);
+ IBinder displayToken, Surface surface);
private static native void nativeSetDisplayLayerStack(
IBinder displayToken, int layerStack);
private static native void nativeSetDisplayProjection(
@@ -597,11 +597,11 @@ public class Surface implements Parcelable {
}
/** @hide */
- public static void setDisplaySurface(IBinder displayToken, SurfaceTexture surfaceTexture) {
+ public static void setDisplaySurface(IBinder displayToken, Surface surface) {
if (displayToken == null) {
throw new IllegalArgumentException("displayToken must not be null");
}
- nativeSetDisplaySurface(displayToken, surfaceTexture);
+ nativeSetDisplaySurface(displayToken, surface);
}
/** @hide */
diff --git a/core/java/android/view/TextureView.java b/core/java/android/view/TextureView.java
index fe14c88..7e335f0 100644
--- a/core/java/android/view/TextureView.java
+++ b/core/java/android/view/TextureView.java
@@ -367,6 +367,7 @@ public class TextureView extends View {
if (mListener != null && !mUpdateSurface) {
mListener.onSurfaceTextureAvailable(mSurface, getWidth(), getHeight());
}
+ mLayer.setLayerPaint(mLayerPaint);
}
if (mUpdateSurface) {
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index d268fd2..236adab 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -11932,13 +11932,13 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
* {@link #setAlpha(float)}, the alpha value of the layer's paint is replaced by
* this view's alpha value. Calling {@link #setAlpha(float)} is therefore
* equivalent to setting a hardware layer on this view and providing a paint with
- * the desired alpha value.<p>
+ * the desired alpha value.</p>
*
* <p>Refer to the documentation of {@link #LAYER_TYPE_NONE disabled},
* {@link #LAYER_TYPE_SOFTWARE software} and {@link #LAYER_TYPE_HARDWARE hardware}
* for more information on when and how to use layers.</p>
*
- * @param layerType The ype of layer to use with this view, must be one of
+ * @param layerType The type of layer to use with this view, must be one of
* {@link #LAYER_TYPE_NONE}, {@link #LAYER_TYPE_SOFTWARE} or
* {@link #LAYER_TYPE_HARDWARE}
* @param paint The paint used to compose the layer. This argument is optional
@@ -11990,6 +11990,50 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
}
/**
+ * Updates the {@link Paint} object used with the current layer (used only if the current
+ * layer type is not set to {@link #LAYER_TYPE_NONE}). Changed properties of the Paint
+ * provided to {@link #setLayerType(int, android.graphics.Paint)} will be used the next time
+ * the View is redrawn, but {@link #setLayerPaint(android.graphics.Paint)} must be called to
+ * ensure that the view gets redrawn immediately.
+ *
+ * <p>A layer is associated with an optional {@link android.graphics.Paint}
+ * instance that controls how the layer is composed on screen. The following
+ * properties of the paint are taken into account when composing the layer:</p>
+ * <ul>
+ * <li>{@link android.graphics.Paint#getAlpha() Translucency (alpha)}</li>
+ * <li>{@link android.graphics.Paint#getXfermode() Blending mode}</li>
+ * <li>{@link android.graphics.Paint#getColorFilter() Color filter}</li>
+ * </ul>
+ *
+ * <p>If this view has an alpha value set to < 1.0 by calling
+ * {@link #setAlpha(float)}, the alpha value of the layer's paint is replaced by
+ * this view's alpha value. Calling {@link #setAlpha(float)} is therefore
+ * equivalent to setting a hardware layer on this view and providing a paint with
+ * the desired alpha value.</p>
+ *
+ * @param paint The paint used to compose the layer. This argument is optional
+ * and can be null. It is ignored when the layer type is
+ * {@link #LAYER_TYPE_NONE}
+ *
+ * @see #setLayerType(int, android.graphics.Paint)
+ */
+ public void setLayerPaint(Paint paint) {
+ int layerType = getLayerType();
+ if (layerType != LAYER_TYPE_NONE) {
+ mLayerPaint = paint == null ? new Paint() : paint;
+ if (layerType == LAYER_TYPE_HARDWARE) {
+ HardwareLayer layer = getHardwareLayer();
+ if (layer != null) {
+ layer.setLayerPaint(paint);
+ }
+ invalidateViewProperty(false, false);
+ } else {
+ invalidate();
+ }
+ }
+ }
+
+ /**
* Indicates whether this view has a static layer. A view with layer type
* {@link #LAYER_TYPE_NONE} is a static layer. Other types of layers are
* dynamic.
@@ -12101,6 +12145,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
if (!mHardwareLayer.isValid()) {
return null;
}
+ mHardwareLayer.setLayerPaint(mLayerPaint);
mHardwareLayer.redraw(getHardwareLayerDisplayList(mHardwareLayer), mLocalDirtyRect);
mLocalDirtyRect.setEmpty();
diff --git a/core/java/com/android/internal/util/DumpUtils.java b/core/java/com/android/internal/util/DumpUtils.java
new file mode 100644
index 0000000..7b8c582
--- /dev/null
+++ b/core/java/com/android/internal/util/DumpUtils.java
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.util;
+
+import android.os.Handler;
+
+import java.io.PrintWriter;
+import java.io.StringWriter;
+
+/**
+ * Helper functions for dumping the state of system services.
+ */
+public final class DumpUtils {
+ private DumpUtils() {
+ }
+
+ /**
+ * Helper for dumping state owned by a handler thread.
+ *
+ * Because the caller might be holding an important lock that the handler is
+ * trying to acquire, we use a short timeout to avoid deadlocks. The process
+ * is inelegant but this function is only used for debugging purposes.
+ */
+ public static void dumpAsync(Handler handler, final Dump dump, PrintWriter pw, long timeout) {
+ final StringWriter sw = new StringWriter();
+ if (handler.runWithScissors(new Runnable() {
+ @Override
+ public void run() {
+ PrintWriter lpw = new PrintWriter(sw);
+ dump.dump(lpw);
+ lpw.close();
+ }
+ }, timeout)) {
+ pw.print(sw.toString());
+ } else {
+ pw.println("... timed out");
+ }
+ }
+
+ public interface Dump {
+ void dump(PrintWriter pw);
+ }
+}
diff --git a/core/java/com/android/internal/util/IndentingPrintWriter.java b/core/java/com/android/internal/util/IndentingPrintWriter.java
index 699e9b3..dd5918b 100644
--- a/core/java/com/android/internal/util/IndentingPrintWriter.java
+++ b/core/java/com/android/internal/util/IndentingPrintWriter.java
@@ -28,7 +28,7 @@ public class IndentingPrintWriter extends PrintWriter {
private final String mIndent;
private StringBuilder mBuilder = new StringBuilder();
- private String mCurrent = new String();
+ private char[] mCurrent;
private boolean mEmptyLine = true;
public IndentingPrintWriter(Writer writer, String indent) {
@@ -38,12 +38,12 @@ public class IndentingPrintWriter extends PrintWriter {
public void increaseIndent() {
mBuilder.append(mIndent);
- mCurrent = mBuilder.toString();
+ mCurrent = null;
}
public void decreaseIndent() {
mBuilder.delete(0, mIndent.length());
- mCurrent = mBuilder.toString();
+ mCurrent = null;
}
public void printPair(String key, Object value) {
@@ -51,17 +51,35 @@ public class IndentingPrintWriter extends PrintWriter {
}
@Override
- public void println() {
- super.println();
- mEmptyLine = true;
+ public void write(char[] buf, int offset, int count) {
+ final int bufferEnd = offset + count;
+ int lineStart = offset;
+ int lineEnd = offset;
+ while (lineEnd < bufferEnd) {
+ char ch = buf[lineEnd++];
+ if (ch == '\n') {
+ writeIndent();
+ super.write(buf, lineStart, lineEnd - lineStart);
+ lineStart = lineEnd;
+ mEmptyLine = true;
+ }
+ }
+
+ if (lineStart != lineEnd) {
+ writeIndent();
+ super.write(buf, lineStart, lineEnd - lineStart);
+ }
}
- @Override
- public void write(char[] buf, int offset, int count) {
+ private void writeIndent() {
if (mEmptyLine) {
mEmptyLine = false;
- super.print(mCurrent);
+ if (mBuilder.length() != 0) {
+ if (mCurrent == null) {
+ mCurrent = mBuilder.toString().toCharArray();
+ }
+ super.write(mCurrent, 0, mCurrent.length);
+ }
}
- super.write(buf, offset, count);
}
}
diff --git a/core/jni/Android.mk b/core/jni/Android.mk
index 9d45479..5f6042d 100644
--- a/core/jni/Android.mk
+++ b/core/jni/Android.mk
@@ -126,6 +126,7 @@ LOCAL_SRC_FILES:= \
android_media_AudioSystem.cpp \
android_media_AudioTrack.cpp \
android_media_JetPlayer.cpp \
+ android_media_RemoteDisplay.cpp \
android_media_ToneGenerator.cpp \
android_hardware_Camera.cpp \
android_hardware_SensorManager.cpp \
diff --git a/core/jni/AndroidRuntime.cpp b/core/jni/AndroidRuntime.cpp
index 55563a8..27684d7 100644
--- a/core/jni/AndroidRuntime.cpp
+++ b/core/jni/AndroidRuntime.cpp
@@ -160,6 +160,7 @@ extern int register_android_backup_BackupHelperDispatcher(JNIEnv *env);
extern int register_android_app_backup_FullBackup(JNIEnv *env);
extern int register_android_app_ActivityThread(JNIEnv *env);
extern int register_android_app_NativeActivity(JNIEnv *env);
+extern int register_android_media_RemoteDisplay(JNIEnv *env);
extern int register_android_view_InputChannel(JNIEnv* env);
extern int register_android_view_InputDevice(JNIEnv* env);
extern int register_android_view_InputEventReceiver(JNIEnv* env);
@@ -1161,6 +1162,7 @@ static const RegJNIRec gRegJNI[] = {
REG_JNI(register_android_media_AudioSystem),
REG_JNI(register_android_media_AudioTrack),
REG_JNI(register_android_media_JetPlayer),
+ REG_JNI(register_android_media_RemoteDisplay),
REG_JNI(register_android_media_ToneGenerator),
REG_JNI(register_android_opengl_classes),
diff --git a/core/jni/android_media_RemoteDisplay.cpp b/core/jni/android_media_RemoteDisplay.cpp
new file mode 100644
index 0000000..5d24f61
--- /dev/null
+++ b/core/jni/android_media_RemoteDisplay.cpp
@@ -0,0 +1,182 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "RemoteDisplay"
+
+#include "jni.h"
+#include "JNIHelp.h"
+
+#include "android_os_Parcel.h"
+#include "android_util_Binder.h"
+
+#include <android_runtime/AndroidRuntime.h>
+#include <android_runtime/android_view_Surface.h>
+
+#include <binder/IServiceManager.h>
+
+#include <gui/ISurfaceTexture.h>
+
+#include <media/IMediaPlayerService.h>
+#include <media/IRemoteDisplay.h>
+#include <media/IRemoteDisplayClient.h>
+
+#include <utils/Log.h>
+
+#include <ScopedUtfChars.h>
+
+namespace android {
+
+static struct {
+ jmethodID notifyDisplayConnected;
+ jmethodID notifyDisplayDisconnected;
+ jmethodID notifyDisplayError;
+} gRemoteDisplayClassInfo;
+
+// ----------------------------------------------------------------------------
+
+class NativeRemoteDisplayClient : public BnRemoteDisplayClient {
+public:
+ NativeRemoteDisplayClient(JNIEnv* env, jobject remoteDisplayObj) :
+ mRemoteDisplayObjGlobal(env->NewGlobalRef(remoteDisplayObj)) {
+ }
+
+protected:
+ ~NativeRemoteDisplayClient() {
+ JNIEnv* env = AndroidRuntime::getJNIEnv();
+ env->DeleteGlobalRef(mRemoteDisplayObjGlobal);
+ }
+
+public:
+ virtual void onDisplayConnected(const sp<ISurfaceTexture>& surfaceTexture,
+ uint32_t width, uint32_t height, uint32_t flags) {
+ JNIEnv* env = AndroidRuntime::getJNIEnv();
+
+ jobject surfaceObj = android_view_Surface_createFromISurfaceTexture(env, surfaceTexture);
+ if (surfaceObj == NULL) {
+ ALOGE("Could not create Surface from surface texture %p provided by media server.",
+ surfaceTexture.get());
+ return;
+ }
+
+ env->CallVoidMethod(mRemoteDisplayObjGlobal,
+ gRemoteDisplayClassInfo.notifyDisplayConnected,
+ surfaceObj, width, height, flags);
+ env->DeleteLocalRef(surfaceObj);
+ checkAndClearExceptionFromCallback(env, "notifyDisplayConnected");
+ }
+
+ virtual void onDisplayDisconnected() {
+ JNIEnv* env = AndroidRuntime::getJNIEnv();
+
+ env->CallVoidMethod(mRemoteDisplayObjGlobal,
+ gRemoteDisplayClassInfo.notifyDisplayDisconnected);
+ checkAndClearExceptionFromCallback(env, "notifyDisplayDisconnected");
+ }
+
+ virtual void onDisplayError(int32_t error) {
+ JNIEnv* env = AndroidRuntime::getJNIEnv();
+
+ env->CallVoidMethod(mRemoteDisplayObjGlobal,
+ gRemoteDisplayClassInfo.notifyDisplayError, error);
+ checkAndClearExceptionFromCallback(env, "notifyDisplayError");
+ }
+
+private:
+ jobject mRemoteDisplayObjGlobal;
+
+ static void checkAndClearExceptionFromCallback(JNIEnv* env, const char* methodName) {
+ if (env->ExceptionCheck()) {
+ ALOGE("An exception was thrown by callback '%s'.", methodName);
+ LOGE_EX(env);
+ env->ExceptionClear();
+ }
+ }
+};
+
+class NativeRemoteDisplay {
+public:
+ NativeRemoteDisplay(const sp<IRemoteDisplay>& display,
+ const sp<NativeRemoteDisplayClient>& client) :
+ mDisplay(display), mClient(client) {
+ }
+
+ ~NativeRemoteDisplay() {
+ mDisplay->dispose();
+ }
+
+private:
+ sp<IRemoteDisplay> mDisplay;
+ sp<NativeRemoteDisplayClient> mClient;
+};
+
+
+// ----------------------------------------------------------------------------
+
+static jint nativeListen(JNIEnv* env, jobject remoteDisplayObj, jstring ifaceStr) {
+ ScopedUtfChars iface(env, ifaceStr);
+
+ sp<IServiceManager> sm = defaultServiceManager();
+ sp<IMediaPlayerService> service = interface_cast<IMediaPlayerService>(
+ sm->getService(String16("media.player")));
+ if (service == NULL) {
+ ALOGE("Could not obtain IMediaPlayerService from service manager");
+ return 0;
+ }
+
+ sp<NativeRemoteDisplayClient> client(new NativeRemoteDisplayClient(env, remoteDisplayObj));
+ sp<IRemoteDisplay> display = service->listenForRemoteDisplay(
+ client, String8(iface.c_str()));
+ if (display == NULL) {
+ ALOGE("Media player service rejected request to listen for remote display '%s'.",
+ iface.c_str());
+ return 0;
+ }
+
+ NativeRemoteDisplay* wrapper = new NativeRemoteDisplay(display, client);
+ return reinterpret_cast<jint>(wrapper);
+}
+
+static void nativeDispose(JNIEnv* env, jobject remoteDisplayObj, jint ptr) {
+ NativeRemoteDisplay* wrapper = reinterpret_cast<NativeRemoteDisplay*>(ptr);
+ delete wrapper;
+}
+
+// ----------------------------------------------------------------------------
+
+static JNINativeMethod gMethods[] = {
+ {"nativeListen", "(Ljava/lang/String;)I",
+ (void*)nativeListen },
+ {"nativeDispose", "(I)V",
+ (void*)nativeDispose },
+};
+
+int register_android_media_RemoteDisplay(JNIEnv* env)
+{
+ int err = AndroidRuntime::registerNativeMethods(env, "android/media/RemoteDisplay",
+ gMethods, NELEM(gMethods));
+
+ jclass clazz = env->FindClass("android/media/RemoteDisplay");
+ gRemoteDisplayClassInfo.notifyDisplayConnected =
+ env->GetMethodID(clazz, "notifyDisplayConnected",
+ "(Landroid/view/Surface;III)V");
+ gRemoteDisplayClassInfo.notifyDisplayDisconnected =
+ env->GetMethodID(clazz, "notifyDisplayDisconnected", "()V");
+ gRemoteDisplayClassInfo.notifyDisplayError =
+ env->GetMethodID(clazz, "notifyDisplayError", "(I)V");
+ return err;
+}
+
+};
diff --git a/core/jni/android_text_format_Time.cpp b/core/jni/android_text_format_Time.cpp
index 776733c..bb09421 100644
--- a/core/jni/android_text_format_Time.cpp
+++ b/core/jni/android_text_format_Time.cpp
@@ -23,6 +23,7 @@
#include "jni.h"
#include "utils/misc.h"
#include "android_runtime/AndroidRuntime.h"
+#include "ScopedStringChars.h"
#include "TimeUtils.h"
#include <nativehelper/JNIHelp.h>
#include <cutils/tztime.h>
@@ -71,11 +72,10 @@ static inline bool java2time(JNIEnv* env, Time* t, jobject o)
t->t.tm_gmtoff = env->GetLongField(o, g_gmtoffField);
bool allDay = env->GetBooleanField(o, g_allDayField);
if (allDay &&
- ((t->t.tm_sec !=0) || (t->t.tm_min != 0) || (t->t.tm_hour != 0))) {
- char msg[100];
- sprintf(msg, "allDay is true but sec, min, hour are not 0.");
- jniThrowException(env, "java/lang/IllegalArgumentException", msg);
- return false;
+ ((t->t.tm_sec !=0) || (t->t.tm_min != 0) || (t->t.tm_hour != 0))) {
+ jniThrowException(env, "java/lang/IllegalArgumentException",
+ "allDay is true but sec, min, hour are not 0.");
+ return false;
}
return true;
}
@@ -308,7 +308,7 @@ static jstring android_text_format_Time_format(JNIEnv* env, jobject This,
static jstring android_text_format_Time_toString(JNIEnv* env, jobject This)
{
Time t;
- if (!java2time(env, &t, This)) return env->NewStringUTF("");;
+ if (!java2time(env, &t, This)) return env->NewStringUTF("");
ACQUIRE_TIMEZONE(This, t)
String8 r = t.toString();
@@ -360,32 +360,30 @@ static void android_text_format_Time_set(JNIEnv* env, jobject This, jlong millis
// ============================================================================
// Just do this here because it's not worth recreating the strings
-static int get_char(JNIEnv* env, const jchar *s, int spos, int mul,
- bool *thrown)
+static int get_char(JNIEnv* env, const ScopedStringChars& s, int spos, int mul,
+ bool* thrown)
{
jchar c = s[spos];
if (c >= '0' && c <= '9') {
return (c - '0') * mul;
} else {
if (!*thrown) {
- char msg[100];
- sprintf(msg, "Parse error at pos=%d", spos);
- jniThrowException(env, "android/util/TimeFormatException", msg);
+ jniThrowExceptionFmt(env, "android/util/TimeFormatException",
+ "Parse error at pos=%d", spos);
*thrown = true;
}
return 0;
}
}
-static bool check_char(JNIEnv* env, const jchar *s, int spos, jchar expected)
+static bool check_char(JNIEnv* env, const ScopedStringChars& s, int spos, jchar expected)
{
jchar c = s[spos];
if (c != expected) {
- char msg[100];
- sprintf(msg, "Unexpected character 0x%02x at pos=%d. Expected %c.", c, spos,
- expected);
- jniThrowException(env, "android/util/TimeFormatException", msg);
- return false;
+ jniThrowExceptionFmt(env, "android/util/TimeFormatException",
+ "Unexpected character 0x%02x at pos=%d. Expected %c.",
+ c, spos, expected);
+ return false;
}
return true;
}
@@ -394,20 +392,19 @@ static bool check_char(JNIEnv* env, const jchar *s, int spos, jchar expected)
static jboolean android_text_format_Time_parse(JNIEnv* env, jobject This, jstring strObj)
{
jsize len = env->GetStringLength(strObj);
- const jchar *s = env->GetStringChars(strObj, NULL);
+ if (len < 8) {
+ jniThrowException(env, "android/util/TimeFormatException",
+ "String too short -- expected at least 8 characters.");
+ return false;
+ }
- bool thrown = false;
- int n;
jboolean inUtc = false;
- if (len < 8) {
- char msg[100];
- sprintf(msg, "String too short -- expected at least 8 characters.");
- jniThrowException(env, "android/util/TimeFormatException", msg);
- return false;
- }
+ ScopedStringChars s(env, strObj);
// year
+ int n;
+ bool thrown = false;
n = get_char(env, s, 0, 1000, &thrown);
n += get_char(env, s, 1, 100, &thrown);
n += get_char(env, s, 2, 10, &thrown);
@@ -454,7 +451,7 @@ static jboolean android_text_format_Time_parse(JNIEnv* env, jobject This, jstrin
if (len > 15) {
// Z
if (!check_char(env, s, 15, 'Z')) return false;
- inUtc = true;
+ inUtc = true;
}
} else {
env->SetBooleanField(This, g_allDayField, JNI_TRUE);
@@ -467,8 +464,7 @@ static jboolean android_text_format_Time_parse(JNIEnv* env, jobject This, jstrin
env->SetIntField(This, g_ydayField, 0);
env->SetIntField(This, g_isdstField, -1);
env->SetLongField(This, g_gmtoffField, 0);
-
- env->ReleaseStringChars(strObj, s);
+
return inUtc;
}
@@ -477,19 +473,19 @@ static jboolean android_text_format_Time_parse3339(JNIEnv* env,
jstring strObj)
{
jsize len = env->GetStringLength(strObj);
- const jchar *s = env->GetStringChars(strObj, NULL);
-
- bool thrown = false;
- int n;
- jboolean inUtc = false;
-
if (len < 10) {
jniThrowException(env, "android/util/TimeFormatException",
- "Time input is too short; must be at least 10 characters");
+ "String too short --- expected at least 10 characters.");
return false;
}
+ jboolean inUtc = false;
+
+ ScopedStringChars s(env, strObj);
+
// year
+ int n;
+ bool thrown = false;
n = get_char(env, s, 0, 1000, &thrown);
n += get_char(env, s, 1, 100, &thrown);
n += get_char(env, s, 2, 10, &thrown);
@@ -520,28 +516,28 @@ static jboolean android_text_format_Time_parse3339(JNIEnv* env,
// T
if (!check_char(env, s, 10, 'T')) return false;
- env->SetBooleanField(This, g_allDayField, JNI_FALSE);
+ env->SetBooleanField(This, g_allDayField, JNI_FALSE);
// hour
n = get_char(env, s, 11, 10, &thrown);
n += get_char(env, s, 12, 1, &thrown);
if (thrown) return false;
- int hour = n;
+ int hour = n;
// env->SetIntField(This, g_hourField, n);
-
- // :
- if (!check_char(env, s, 13, ':')) return false;
- // minute
+ // :
+ if (!check_char(env, s, 13, ':')) return false;
+
+ // minute
n = get_char(env, s, 14, 10, &thrown);
n += get_char(env, s, 15, 1, &thrown);
if (thrown) return false;
- int minute = n;
+ int minute = n;
// env->SetIntField(This, g_minField, n);
- // :
- if (!check_char(env, s, 16, ':')) return false;
+ // :
+ if (!check_char(env, s, 16, ':')) return false;
- // second
+ // second
n = get_char(env, s, 17, 10, &thrown);
n += get_char(env, s, 18, 1, &thrown);
if (thrown) return false;
@@ -561,64 +557,63 @@ static jboolean android_text_format_Time_parse3339(JNIEnv* env,
if (len > tz_index) {
char c = s[tz_index];
- // NOTE: the offset is meant to be subtracted to get from local time
- // to UTC. we therefore use 1 for '-' and -1 for '+'.
- switch (c) {
- case 'Z':
- // Zulu time -- UTC
- offset = 0;
- break;
- case '-':
+ // NOTE: the offset is meant to be subtracted to get from local time
+ // to UTC. we therefore use 1 for '-' and -1 for '+'.
+ switch (c) {
+ case 'Z':
+ // Zulu time -- UTC
+ offset = 0;
+ break;
+ case '-':
offset = 1;
- break;
- case '+':
+ break;
+ case '+':
offset = -1;
- break;
- default:
- char msg[100];
- sprintf(msg, "Unexpected character 0x%02x at position %d. Expected + or -",
- c, tz_index);
- jniThrowException(env, "android/util/TimeFormatException", msg);
- return false;
- }
+ break;
+ default:
+ jniThrowExceptionFmt(env, "android/util/TimeFormatException",
+ "Unexpected character 0x%02x at position %d. Expected + or -",
+ c, tz_index);
+ return false;
+ }
inUtc = true;
- if (offset != 0) {
- if (len < tz_index + 6) {
- char msg[100];
- sprintf(msg, "Unexpected length; should be %d characters", tz_index + 6);
- jniThrowException(env, "android/util/TimeFormatException", msg);
- return false;
- }
-
- // hour
- n = get_char(env, s, tz_index + 1, 10, &thrown);
- n += get_char(env, s, tz_index + 2, 1, &thrown);
- if (thrown) return false;
- n *= offset;
- hour += n;
-
- // :
- if (!check_char(env, s, tz_index + 3, ':')) return false;
-
- // minute
- n = get_char(env, s, tz_index + 4, 10, &thrown);
- n += get_char(env, s, tz_index + 5, 1, &thrown);
- if (thrown) return false;
- n *= offset;
- minute += n;
- }
- }
- env->SetIntField(This, g_hourField, hour);
+ if (offset != 0) {
+ if (len < tz_index + 6) {
+ jniThrowExceptionFmt(env, "android/util/TimeFormatException",
+ "Unexpected length; should be %d characters",
+ tz_index + 6);
+ return false;
+ }
+
+ // hour
+ n = get_char(env, s, tz_index + 1, 10, &thrown);
+ n += get_char(env, s, tz_index + 2, 1, &thrown);
+ if (thrown) return false;
+ n *= offset;
+ hour += n;
+
+ // :
+ if (!check_char(env, s, tz_index + 3, ':')) return false;
+
+ // minute
+ n = get_char(env, s, tz_index + 4, 10, &thrown);
+ n += get_char(env, s, tz_index + 5, 1, &thrown);
+ if (thrown) return false;
+ n *= offset;
+ minute += n;
+ }
+ }
+ env->SetIntField(This, g_hourField, hour);
env->SetIntField(This, g_minField, minute);
- if (offset != 0) {
- // we need to normalize after applying the hour and minute offsets
- android_text_format_Time_normalize(env, This, false /* use isdst */);
- // The timezone is set to UTC in the calling Java code.
- }
+ if (offset != 0) {
+ // we need to normalize after applying the hour and minute offsets
+ android_text_format_Time_normalize(env, This, false /* use isdst */);
+ // The timezone is set to UTC in the calling Java code.
+ }
} else {
- env->SetBooleanField(This, g_allDayField, JNI_TRUE);
+ env->SetBooleanField(This, g_allDayField, JNI_TRUE);
env->SetIntField(This, g_hourField, 0);
env->SetIntField(This, g_minField, 0);
env->SetIntField(This, g_secField, 0);
@@ -628,8 +623,7 @@ static jboolean android_text_format_Time_parse3339(JNIEnv* env,
env->SetIntField(This, g_ydayField, 0);
env->SetIntField(This, g_isdstField, -1);
env->SetLongField(This, g_gmtoffField, 0);
-
- env->ReleaseStringChars(strObj, s);
+
return inUtc;
}
diff --git a/core/jni/android_view_GLES20Canvas.cpp b/core/jni/android_view_GLES20Canvas.cpp
index 3538fef..7dbf9ec 100644
--- a/core/jni/android_view_GLES20Canvas.cpp
+++ b/core/jni/android_view_GLES20Canvas.cpp
@@ -776,6 +776,20 @@ static void android_view_GLES20Canvas_resizeLayer(JNIEnv* env, jobject clazz,
env->ReleaseIntArrayElements(layerInfo, storage, 0);
}
+static void android_view_GLES20Canvas_setLayerPaint(JNIEnv* env, jobject clazz,
+ Layer* layer, SkPaint* paint) {
+ if (layer) {
+ layer->setPaint(paint);
+ }
+}
+
+static void android_view_GLES20Canvas_setLayerColorFilter(JNIEnv* env, jobject clazz,
+ Layer* layer, SkiaColorFilter* colorFilter) {
+ if (layer) {
+ layer->setColorFilter(colorFilter);
+ }
+}
+
static void android_view_GLES20Canvas_setOpaqueLayer(JNIEnv* env, jobject clazz,
Layer* layer, jboolean isOpaque) {
if (layer) {
@@ -979,6 +993,8 @@ static JNINativeMethod gMethods[] = {
{ "nCreateLayerRenderer", "(I)I", (void*) android_view_GLES20Canvas_createLayerRenderer },
{ "nCreateLayer", "(IIZ[I)I", (void*) android_view_GLES20Canvas_createLayer },
{ "nResizeLayer", "(III[I)V" , (void*) android_view_GLES20Canvas_resizeLayer },
+ { "nSetLayerPaint", "(II)V", (void*) android_view_GLES20Canvas_setLayerPaint },
+ { "nSetLayerColorFilter", "(II)V", (void*) android_view_GLES20Canvas_setLayerColorFilter },
{ "nSetOpaqueLayer", "(IZ)V", (void*) android_view_GLES20Canvas_setOpaqueLayer },
{ "nCreateTextureLayer", "(Z[I)I", (void*) android_view_GLES20Canvas_createTextureLayer },
{ "nUpdateTextureLayer", "(IIIZLandroid/graphics/SurfaceTexture;)V",
diff --git a/core/jni/android_view_Surface.cpp b/core/jni/android_view_Surface.cpp
index 4fbfab6..90e85e6 100644
--- a/core/jni/android_view_Surface.cpp
+++ b/core/jni/android_view_Surface.cpp
@@ -66,6 +66,7 @@ static struct {
jfieldID mGenerationId;
jfieldID mCanvas;
jfieldID mCanvasSaveCount;
+ jmethodID ctor;
} gSurfaceClassInfo;
static struct {
@@ -231,6 +232,42 @@ static void setSurface(JNIEnv* env, jobject surfaceObj, const sp<Surface>& surfa
}
}
+static sp<ISurfaceTexture> getISurfaceTexture(JNIEnv* env, jobject surfaceObj) {
+ if (surfaceObj) {
+ sp<Surface> surface(getSurface(env, surfaceObj));
+ if (surface != NULL) {
+ return surface->getSurfaceTexture();
+ }
+ }
+ return NULL;
+}
+
+jobject android_view_Surface_createFromISurfaceTexture(JNIEnv* env,
+ const sp<ISurfaceTexture>& surfaceTexture) {
+ if (surfaceTexture == NULL) {
+ return NULL;
+ }
+
+ sp<Surface> surface(new Surface(surfaceTexture));
+ if (surface == NULL) {
+ return NULL;
+ }
+
+ jobject surfaceObj = env->NewObject(gSurfaceClassInfo.clazz, gSurfaceClassInfo.ctor);
+ if (surfaceObj == NULL) {
+ if (env->ExceptionCheck()) {
+ ALOGE("Could not create instance of Surface from ISurfaceTexture.");
+ LOGE_EX(env);
+ env->ExceptionClear();
+ }
+ return NULL;
+ }
+
+ setSurface(env, surfaceObj, surface);
+ return surfaceObj;
+}
+
+
// ----------------------------------------------------------------------------
static void nativeCreate(JNIEnv* env, jobject surfaceObj, jobject sessionObj,
@@ -619,24 +656,12 @@ static jobject nativeCreateDisplay(JNIEnv* env, jclass clazz, jstring nameObj) {
}
static void nativeSetDisplaySurface(JNIEnv* env, jclass clazz,
- jobject tokenObj, jobject surfaceTextureObj) {
+ jobject tokenObj, jobject surfaceObj) {
sp<IBinder> token(ibinderForJavaObject(env, tokenObj));
if (token == NULL) return;
- if (!surfaceTextureObj) {
- SurfaceComposerClient::setDisplaySurface(token, NULL);
- return;
- }
-
- sp<SurfaceTexture> st(SurfaceTexture_getSurfaceTexture(env, surfaceTextureObj));
- if (st == NULL) {
- jniThrowException(env, "java/lang/IllegalArgumentException",
- "SurfaceTexture has already been released");
- return;
- }
-
- sp<ISurfaceTexture> bq = st->getBufferQueue();
- SurfaceComposerClient::setDisplaySurface(token, bq);
+ sp<ISurfaceTexture> surfaceTexture(getISurfaceTexture(env, surfaceObj));
+ SurfaceComposerClient::setDisplaySurface(token, surfaceTexture);
}
static void nativeSetDisplayLayerStack(JNIEnv* env, jclass clazz,
@@ -648,23 +673,23 @@ static void nativeSetDisplayLayerStack(JNIEnv* env, jclass clazz,
}
static void nativeSetDisplayProjection(JNIEnv* env, jclass clazz,
- jobject tokenObj, jint orientation, jobject rect1Obj, jobject rect2Obj) {
+ jobject tokenObj, jint orientation, jobject layerStackRectObj, jobject displayRectObj) {
sp<IBinder> token(ibinderForJavaObject(env, tokenObj));
if (token == NULL) return;
- Rect rect1;
- rect1.left = env->GetIntField(rect1Obj, gRectClassInfo.left);
- rect1.top = env->GetIntField(rect1Obj, gRectClassInfo.top);
- rect1.right = env->GetIntField(rect1Obj, gRectClassInfo.right);
- rect1.bottom = env->GetIntField(rect1Obj, gRectClassInfo.bottom);
+ Rect layerStackRect;
+ layerStackRect.left = env->GetIntField(layerStackRectObj, gRectClassInfo.left);
+ layerStackRect.top = env->GetIntField(layerStackRectObj, gRectClassInfo.top);
+ layerStackRect.right = env->GetIntField(layerStackRectObj, gRectClassInfo.right);
+ layerStackRect.bottom = env->GetIntField(layerStackRectObj, gRectClassInfo.bottom);
- Rect rect2;
- rect2.left = env->GetIntField(rect2Obj, gRectClassInfo.left);
- rect2.top = env->GetIntField(rect2Obj, gRectClassInfo.top);
- rect2.right = env->GetIntField(rect2Obj, gRectClassInfo.right);
- rect2.bottom = env->GetIntField(rect2Obj, gRectClassInfo.bottom);
+ Rect displayRect;
+ displayRect.left = env->GetIntField(displayRectObj, gRectClassInfo.left);
+ displayRect.top = env->GetIntField(displayRectObj, gRectClassInfo.top);
+ displayRect.right = env->GetIntField(displayRectObj, gRectClassInfo.right);
+ displayRect.bottom = env->GetIntField(displayRectObj, gRectClassInfo.bottom);
- SurfaceComposerClient::setDisplayProjection(token, orientation, rect1, rect2);
+ SurfaceComposerClient::setDisplayProjection(token, orientation, layerStackRect, displayRect);
}
static jboolean nativeGetDisplayInfo(JNIEnv* env, jclass clazz,
@@ -800,7 +825,7 @@ static JNINativeMethod gSurfaceMethods[] = {
(void*)nativeGetBuiltInDisplay },
{"nativeCreateDisplay", "(Ljava/lang/String;)Landroid/os/IBinder;",
(void*)nativeCreateDisplay },
- {"nativeSetDisplaySurface", "(Landroid/os/IBinder;Landroid/graphics/SurfaceTexture;)V",
+ {"nativeSetDisplaySurface", "(Landroid/os/IBinder;Landroid/view/Surface;)V",
(void*)nativeSetDisplaySurface },
{"nativeSetDisplayLayerStack", "(Landroid/os/IBinder;I)V",
(void*)nativeSetDisplayLayerStack },
@@ -835,6 +860,7 @@ int register_android_view_Surface(JNIEnv* env)
env->GetFieldID(gSurfaceClassInfo.clazz, "mCanvas", "Landroid/graphics/Canvas;");
gSurfaceClassInfo.mCanvasSaveCount =
env->GetFieldID(gSurfaceClassInfo.clazz, "mCanvasSaveCount", "I");
+ gSurfaceClassInfo.ctor = env->GetMethodID(gSurfaceClassInfo.clazz, "<init>", "()V");
clazz = env->FindClass("android/graphics/Canvas");
gCanvasClassInfo.mNativeCanvas = env->GetFieldID(clazz, "mNativeCanvas", "I");
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 23a412f..560021d 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -108,6 +108,8 @@
<protected-broadcast
android:name="android.bluetooth.pan.profile.action.CONNECTION_STATE_CHANGED" />
+ <protected-broadcast android:name="android.hardware.display.action.WIFI_DISPLAY_STATUS_CHANGED" />
+
<protected-broadcast android:name="android.hardware.usb.action.USB_STATE" />
<protected-broadcast android:name="android.hardware.usb.action.USB_ACCESSORY_ATTACHED" />
<protected-broadcast android:name="android.hardware.usb.action.USB_ACCESSORY_ATTACHED" />
@@ -1446,6 +1448,22 @@
android:description="@string/permdesc_readFrameBuffer"
android:protectionLevel="signature|system" />
+ <!-- Allows an application to configure and connect to Wifi displays
+ @hide -->
+ <permission android:name="android.permission.CONFIGURE_WIFI_DISPLAY"
+ android:label="@string/permlab_configureWifiDisplay"
+ android:description="@string/permdesc_configureWifiDisplay"
+ android:protectionLevel="signature" />
+
+ <!-- Allows an application to control low-level features of Wifi displays
+ such as opening an RTSP socket. This permission should only be used
+ by the display manager.
+ @hide -->
+ <permission android:name="android.permission.CONTROL_WIFI_DISPLAY"
+ android:label="@string/permlab_controlWifiDisplay"
+ android:description="@string/permdesc_controlWifiDisplay"
+ android:protectionLevel="signature" />
+
<!-- Required to be able to disable the device (very dangerous!). -->
<permission android:name="android.permission.BRICK"
android:label="@string/permlab_brick"
diff --git a/core/res/res/layout-land/keyguard_host_view.xml b/core/res/res/layout-land/keyguard_host_view.xml
index b404155..0028a54 100644
--- a/core/res/res/layout-land/keyguard_host_view.xml
+++ b/core/res/res/layout-land/keyguard_host_view.xml
@@ -45,13 +45,8 @@
android:layout_weight="1"
android:gravity="center">
+ <!-- SelectorView is always used, so add it here. The rest are loaded dynamically -->
<include layout="@layout/keyguard_selector_view"/>
- <include layout="@layout/keyguard_account_view"/>
- <include layout="@layout/keyguard_pattern_view"/>
- <include layout="@layout/keyguard_password_view"/>
- <include layout="@layout/keyguard_sim_pin_view"/>
- <include layout="@layout/keyguard_sim_puk_view"/>
- <include layout="@layout/keyguard_face_unlock_view"/>
</ViewFlipper>
diff --git a/core/res/res/layout-port/keyguard_host_view.xml b/core/res/res/layout-port/keyguard_host_view.xml
index 5dc2225..5e467d1 100644
--- a/core/res/res/layout-port/keyguard_host_view.xml
+++ b/core/res/res/layout-port/keyguard_host_view.xml
@@ -33,13 +33,8 @@
android:layout_height="match_parent"
android:gravity="center">
+ <!-- SelectorView is always used, so add it here. The rest are loaded dynamically -->
<include layout="@layout/keyguard_selector_view"/>
- <include layout="@layout/keyguard_account_view"/>
- <include layout="@layout/keyguard_pattern_view"/>
- <include layout="@layout/keyguard_password_view"/>
- <include layout="@layout/keyguard_sim_pin_view"/>
- <include layout="@layout/keyguard_sim_puk_view"/>
- <include layout="@layout/keyguard_face_unlock_view"/>
</ViewFlipper>
diff --git a/core/res/res/layout-sw600dp-land/keyguard_host_view.xml b/core/res/res/layout-sw600dp-land/keyguard_host_view.xml
index e77f584..5b6bb2f 100644
--- a/core/res/res/layout-sw600dp-land/keyguard_host_view.xml
+++ b/core/res/res/layout-sw600dp-land/keyguard_host_view.xml
@@ -52,13 +52,8 @@
android:layout_weight="1"
android:gravity="center">
+ <!-- SelectorView is always used, so add it here. The rest are loaded dynamically -->
<include layout="@layout/keyguard_selector_view"/>
- <include layout="@layout/keyguard_account_view"/>
- <include layout="@layout/keyguard_pattern_view"/>
- <include layout="@layout/keyguard_password_view"/>
- <include layout="@layout/keyguard_sim_pin_view"/>
- <include layout="@layout/keyguard_sim_puk_view"/>
- <include layout="@layout/keyguard_face_unlock_view"/>
</ViewFlipper>
diff --git a/core/res/res/layout-sw600dp-port/keyguard_host_view.xml b/core/res/res/layout-sw600dp-port/keyguard_host_view.xml
index 082f481..397b881 100644
--- a/core/res/res/layout-sw600dp-port/keyguard_host_view.xml
+++ b/core/res/res/layout-sw600dp-port/keyguard_host_view.xml
@@ -47,13 +47,8 @@
android:layout_weight="0.6"
android:layout_gravity="center">
+ <!-- SelectorView is always used, so add it here. The rest are loaded dynamically -->
<include layout="@layout/keyguard_selector_view"/>
- <include layout="@layout/keyguard_account_view"/>
- <include layout="@layout/keyguard_pattern_view"/>
- <include layout="@layout/keyguard_password_view"/>
- <include layout="@layout/keyguard_sim_pin_view"/>
- <include layout="@layout/keyguard_sim_puk_view"/>
- <include layout="@layout/keyguard_face_unlock_view"/>
</ViewFlipper>
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index 4db8cd1..139715c 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -1366,6 +1366,13 @@
<java-symbol type="layout" name="keyguard_screen_tab_unlock_land" />
<java-symbol type="layout" name="keyguard_screen_unlock_landscape" />
<java-symbol type="layout" name="keyguard_screen_unlock_portrait" />
+ <java-symbol type="layout" name="keyguard_selector_view" />
+ <java-symbol type="layout" name="keyguard_pattern_view" />
+ <java-symbol type="layout" name="keyguard_password_view" />
+ <java-symbol type="layout" name="keyguard_face_unlock_view" />
+ <java-symbol type="layout" name="keyguard_sim_pin_view" />
+ <java-symbol type="layout" name="keyguard_sim_puk_view" />
+ <java-symbol type="layout" name="keyguard_account_view" />
<java-symbol type="layout" name="recent_apps_dialog" />
<java-symbol type="layout" name="screen_action_bar" />
<java-symbol type="layout" name="screen_action_bar_overlay" />
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index 9f254b6..f989e4e 100755
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -1191,6 +1191,16 @@
<string name="permdesc_readFrameBuffer">Allows the app to read the content of the frame buffer.</string>
<!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
+ <string name="permlab_configureWifiDisplay">configure Wifi displays</string>
+ <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
+ <string name="permdesc_configureWifiDisplay">Allows the app to configure and connect to Wifi displays.</string>
+
+ <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
+ <string name="permlab_controlWifiDisplay">control Wifi displays</string>
+ <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
+ <string name="permdesc_controlWifiDisplay">Allows the app to control low-level features of Wifi displays.</string>
+
+ <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
<string name="permlab_modifyAudioSettings">change your audio settings</string>
<!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
<string name="permdesc_modifyAudioSettings">Allows the app to modify global audio settings such as volume and which speaker is used for output.</string>
diff --git a/core/tests/coretests/apks/FrameworkCoreTests_apk.mk b/core/tests/coretests/apks/FrameworkCoreTests_apk.mk
index ac545ca..1e03270 100644
--- a/core/tests/coretests/apks/FrameworkCoreTests_apk.mk
+++ b/core/tests/coretests/apks/FrameworkCoreTests_apk.mk
@@ -7,6 +7,9 @@ LOCAL_DEX_PREOPT := false
# Make sure every package name gets the FrameworkCoreTests_ prefix.
LOCAL_PACKAGE_NAME := FrameworkCoreTests_$(LOCAL_PACKAGE_NAME)
+# Every package should have a native library
+LOCAL_JNI_SHARED_LIBRARIES := libframeworks_coretests_jni
+
FrameworkCoreTests_all_apks += $(LOCAL_PACKAGE_NAME)
include $(BUILD_PACKAGE)
diff --git a/core/tests/coretests/apks/install_jni_lib/Android.mk b/core/tests/coretests/apks/install_jni_lib/Android.mk
new file mode 100644
index 0000000..de2993a
--- /dev/null
+++ b/core/tests/coretests/apks/install_jni_lib/Android.mk
@@ -0,0 +1,28 @@
+# Copyright (C) 2012 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+LOCAL_PATH := $(call my-dir)
+
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := \
+ com_android_frameworks_coretests_JNITest.cpp
+
+LOCAL_SHARED_LIBRARIES := \
+ libnativehelper
+
+LOCAL_MODULE := libframeworks_coretests_jni
+LOCAL_MODULE_TAGS := optional
+
+include $(BUILD_SHARED_LIBRARY)
diff --git a/core/tests/coretests/apks/install_jni_lib/com_android_frameworks_coretests_JNITest.cpp b/core/tests/coretests/apks/install_jni_lib/com_android_frameworks_coretests_JNITest.cpp
new file mode 100644
index 0000000..957fc4a
--- /dev/null
+++ b/core/tests/coretests/apks/install_jni_lib/com_android_frameworks_coretests_JNITest.cpp
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "nativehelper/JNIHelp.h"
+
+namespace android {
+
+static jint checkFunction(JNIEnv*, jclass) {
+ return 1;
+}
+
+static JNINativeMethod sMethods[] = {
+ /* name, signature, funcPtr */
+ { "checkFunction", "()I", (void*) checkFunction },
+};
+
+int register_com_android_framework_coretests_JNITests(JNIEnv* env) {
+ return jniRegisterNativeMethods(env, "com/android/framework/coretests/JNITests", sMethods,
+ NELEM(sMethods));
+}
+
+}
+
+/*
+ * JNI Initialization
+ */
+jint JNI_OnLoad(JavaVM *jvm, void *reserved) {
+ JNIEnv *e;
+ int status;
+
+ // Check JNI version
+ if (jvm->GetEnv((void **) &e, JNI_VERSION_1_6)) {
+ return JNI_ERR;
+ }
+
+ if ((status = android::register_com_android_framework_coretests_JNITests(e)) < 0) {
+ return JNI_ERR;
+ }
+
+ return JNI_VERSION_1_6;
+}
diff --git a/core/tests/coretests/src/android/content/pm/PackageManagerTests.java b/core/tests/coretests/src/android/content/pm/PackageManagerTests.java
index a1fd14e..1868d1c 100755
--- a/core/tests/coretests/src/android/content/pm/PackageManagerTests.java
+++ b/core/tests/coretests/src/android/content/pm/PackageManagerTests.java
@@ -16,6 +16,8 @@
package android.content.pm;
+import static libcore.io.OsConstants.*;
+
import com.android.frameworks.coretests.R;
import com.android.internal.content.PackageHelper;
@@ -32,9 +34,11 @@ import android.net.Uri;
import android.os.Environment;
import android.os.FileUtils;
import android.os.IBinder;
+import android.os.Process;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.StatFs;
+import android.os.SystemClock;
import android.os.storage.IMountService;
import android.os.storage.StorageListener;
import android.os.storage.StorageManager;
@@ -52,22 +56,37 @@ import java.io.IOException;
import java.io.InputStream;
import java.util.List;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+import libcore.io.ErrnoException;
+import libcore.io.Libcore;
+import libcore.io.StructStat;
public class PackageManagerTests extends AndroidTestCase {
private static final boolean localLOGV = true;
- public static final String TAG="PackageManagerTests";
- public final long MAX_WAIT_TIME = 25*1000;
- public final long WAIT_TIME_INCR = 5*1000;
- private static final String SECURE_CONTAINERS_PREFIX = "/mnt/asec";
+
+ public static final String TAG = "PackageManagerTests";
+
+ public final long MAX_WAIT_TIME = 25 * 1000;
+
+ public final long WAIT_TIME_INCR = 5 * 1000;
+
+ private static final String SECURE_CONTAINERS_PREFIX = "/mnt/asec/";
+
private static final int APP_INSTALL_AUTO = PackageHelper.APP_INSTALL_AUTO;
+
private static final int APP_INSTALL_DEVICE = PackageHelper.APP_INSTALL_INTERNAL;
+
private static final int APP_INSTALL_SDCARD = PackageHelper.APP_INSTALL_EXTERNAL;
+
private boolean mOrigState;
void failStr(String errMsg) {
- Log.w(TAG, "errMsg="+errMsg);
+ Log.w(TAG, "errMsg=" + errMsg);
fail(errMsg);
}
+
void failStr(Exception e) {
failStr(e.getMessage());
}
@@ -97,10 +116,11 @@ public class PackageManagerTests extends AndroidTestCase {
private class PackageInstallObserver extends IPackageInstallObserver.Stub {
public int returnCode;
+
private boolean doneFlag = false;
public void packageInstalled(String packageName, int returnCode) {
- synchronized(this) {
+ synchronized (this) {
this.returnCode = returnCode;
doneFlag = true;
notifyAll();
@@ -114,10 +134,15 @@ public class PackageManagerTests extends AndroidTestCase {
abstract class GenericReceiver extends BroadcastReceiver {
private boolean doneFlag = false;
+
boolean received = false;
+
Intent intent;
+
IntentFilter filter;
+
abstract boolean notifyNow(Intent intent);
+
@Override
public void onReceive(Context context, Intent intent) {
if (notifyNow(intent)) {
@@ -179,11 +204,11 @@ public class PackageManagerTests extends AndroidTestCase {
mContext.registerReceiver(receiver, receiver.filter);
try {
// Wait on observer
- synchronized(observer) {
+ synchronized (observer) {
synchronized (receiver) {
getPm().installPackage(packageURI, observer, flags, null);
long waitTime = 0;
- while((!observer.isDone()) && (waitTime < MAX_WAIT_TIME) ) {
+ while ((!observer.isDone()) && (waitTime < MAX_WAIT_TIME)) {
try {
observer.wait(WAIT_TIME_INCR);
waitTime += WAIT_TIME_INCR;
@@ -191,7 +216,7 @@ public class PackageManagerTests extends AndroidTestCase {
Log.i(TAG, "Interrupted during sleep", e);
}
}
- if(!observer.isDone()) {
+ if (!observer.isDone()) {
fail("Timed out waiting for packageInstalled callback");
}
@@ -214,7 +239,7 @@ public class PackageManagerTests extends AndroidTestCase {
// Verify we received the broadcast
waitTime = 0;
- while((!receiver.isDone()) && (waitTime < MAX_WAIT_TIME) ) {
+ while ((!receiver.isDone()) && (waitTime < MAX_WAIT_TIME)) {
try {
receiver.wait(WAIT_TIME_INCR);
waitTime += WAIT_TIME_INCR;
@@ -222,7 +247,7 @@ public class PackageManagerTests extends AndroidTestCase {
Log.i(TAG, "Interrupted during sleep", e);
}
}
- if(!receiver.isDone()) {
+ if (!receiver.isDone()) {
fail("Timed out waiting for PACKAGE_ADDED notification");
}
}
@@ -236,10 +261,10 @@ public class PackageManagerTests extends AndroidTestCase {
PackageInstallObserver observer = new PackageInstallObserver();
try {
// Wait on observer
- synchronized(observer) {
+ synchronized (observer) {
getPm().installPackage(packageURI, observer, flags, null);
long waitTime = 0;
- while((!observer.isDone()) && (waitTime < MAX_WAIT_TIME) ) {
+ while ((!observer.isDone()) && (waitTime < MAX_WAIT_TIME)) {
try {
observer.wait(WAIT_TIME_INCR);
waitTime += WAIT_TIME_INCR;
@@ -247,7 +272,7 @@ public class PackageManagerTests extends AndroidTestCase {
Log.i(TAG, "Interrupted during sleep", e);
}
}
- if(!observer.isDone()) {
+ if (!observer.isDone()) {
fail("Timed out waiting for packageInstalled callback");
}
assertEquals(expectedResult, observer.returnCode);
@@ -280,39 +305,42 @@ public class PackageManagerTests extends AndroidTestCase {
File sourceFile = new File(archiveFilePath);
DisplayMetrics metrics = new DisplayMetrics();
metrics.setToDefaults();
- PackageParser.Package pkg = packageParser.parsePackage(sourceFile, archiveFilePath, metrics, 0);
+ PackageParser.Package pkg = packageParser.parsePackage(sourceFile, archiveFilePath,
+ metrics, 0);
packageParser = null;
return pkg;
}
+
private boolean checkSd(long pkgLen) {
String status = Environment.getExternalStorageState();
if (!status.equals(Environment.MEDIA_MOUNTED)) {
return false;
}
long sdSize = -1;
- StatFs sdStats = new StatFs(
- Environment.getExternalStorageDirectory().getPath());
- sdSize = (long)sdStats.getAvailableBlocks() *
- (long)sdStats.getBlockSize();
+ StatFs sdStats = new StatFs(Environment.getExternalStorageDirectory().getPath());
+ sdSize = (long) sdStats.getAvailableBlocks() * (long) sdStats.getBlockSize();
// TODO check for thresholds here
return pkgLen <= sdSize;
}
+
private boolean checkInt(long pkgLen) {
StatFs intStats = new StatFs(Environment.getDataDirectory().getPath());
- long intSize = (long)intStats.getBlockCount() *
- (long)intStats.getBlockSize();
- long iSize = (long)intStats.getAvailableBlocks() *
- (long)intStats.getBlockSize();
+ long intSize = (long) intStats.getBlockCount() * (long) intStats.getBlockSize();
+ long iSize = (long) intStats.getAvailableBlocks() * (long) intStats.getBlockSize();
// TODO check for thresholds here?
return pkgLen <= iSize;
}
+
private static final int INSTALL_LOC_INT = 1;
+
private static final int INSTALL_LOC_SD = 2;
+
private static final int INSTALL_LOC_ERR = -1;
+
private int getInstallLoc(int flags, int expInstallLocation, long pkgLen) {
// Flags explicitly over ride everything else.
- if ((flags & PackageManager.INSTALL_EXTERNAL) != 0 ) {
+ if ((flags & PackageManager.INSTALL_EXTERNAL) != 0) {
return INSTALL_LOC_SD;
} else if ((flags & PackageManager.INSTALL_INTERNAL) != 0) {
return INSTALL_LOC_INT;
@@ -320,7 +348,7 @@ public class PackageManagerTests extends AndroidTestCase {
// Manifest option takes precedence next
if (expInstallLocation == PackageInfo.INSTALL_LOCATION_PREFER_EXTERNAL) {
if (checkSd(pkgLen)) {
- return INSTALL_LOC_SD;
+ return INSTALL_LOC_SD;
}
if (checkInt(pkgLen)) {
return INSTALL_LOC_INT;
@@ -386,20 +414,32 @@ public class PackageManagerTests extends AndroidTestCase {
if ((flags & PackageManager.INSTALL_FORWARD_LOCK) != 0) {
assertTrue("The application should be installed forward locked",
(info.flags & ApplicationInfo.FLAG_FORWARD_LOCK) != 0);
- assertTrue("The APK path (" + srcPath + ") should start with "
- + SECURE_CONTAINERS_PREFIX,
- srcPath.startsWith(SECURE_CONTAINERS_PREFIX));
- assertTrue("The public APK path (" + publicSrcPath + ") should start with "
- + SECURE_CONTAINERS_PREFIX,
- publicSrcPath.startsWith(SECURE_CONTAINERS_PREFIX));
- assertTrue("The native library path (" + info.nativeLibraryDir
- + ") should start with " + SECURE_CONTAINERS_PREFIX,
- info.nativeLibraryDir.startsWith(SECURE_CONTAINERS_PREFIX));
+ assertStartsWith("The APK path should point to the ASEC",
+ SECURE_CONTAINERS_PREFIX, srcPath);
+ assertStartsWith("The public APK path should point to the ASEC",
+ SECURE_CONTAINERS_PREFIX, publicSrcPath);
+ assertStartsWith("The native library path should point to the ASEC",
+ SECURE_CONTAINERS_PREFIX, info.nativeLibraryDir);
+ try {
+ String compatLib = new File(info.dataDir + "/lib").getCanonicalPath();
+ assertEquals("The compatibility lib directory should be a symbolic link to "
+ + info.nativeLibraryDir,
+ info.nativeLibraryDir, compatLib);
+ } catch (IOException e) {
+ fail("compat check: Can't read " + info.dataDir + "/lib");
+ }
} else {
assertFalse((info.flags & ApplicationInfo.FLAG_FORWARD_LOCK) != 0);
assertEquals(srcPath, appInstallPath);
assertEquals(publicSrcPath, appInstallPath);
- assertTrue(info.nativeLibraryDir.startsWith(dataDir.getPath()));
+ assertStartsWith("Native library should point to shared lib directory",
+ dataDir.getPath(),
+ info.nativeLibraryDir);
+ assertDirOwnerGroupPerms(
+ "Native library directory should be owned by system:system and 0755",
+ Process.SYSTEM_UID, Process.SYSTEM_UID,
+ S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH,
+ info.nativeLibraryDir);
}
assertFalse((info.flags & ApplicationInfo.FLAG_EXTERNAL_STORAGE) != 0);
@@ -409,12 +449,11 @@ public class PackageManagerTests extends AndroidTestCase {
nativeLibDir.exists());
try {
assertEquals("Native library dir should not be a symlink",
- info.nativeLibraryDir,
- nativeLibDir.getCanonicalPath());
+ info.nativeLibraryDir, nativeLibDir.getCanonicalPath());
} catch (IOException e) {
fail("Can't read " + nativeLibDir.getPath());
}
- } else if (rLoc == INSTALL_LOC_SD){
+ } else if (rLoc == INSTALL_LOC_SD) {
if ((flags & PackageManager.INSTALL_FORWARD_LOCK) != 0) {
assertTrue("The application should be installed forward locked",
(info.flags & ApplicationInfo.FLAG_FORWARD_LOCK) != 0);
@@ -427,14 +466,12 @@ public class PackageManagerTests extends AndroidTestCase {
(info.flags & ApplicationInfo.FLAG_EXTERNAL_STORAGE) != 0);
// Might need to check:
// ((info.flags & ApplicationInfo.FLAG_FORWARD_LOCK) != 0)
- assertTrue("The APK path (" + srcPath + ") should start with "
- + SECURE_CONTAINERS_PREFIX, srcPath.startsWith(SECURE_CONTAINERS_PREFIX));
- assertTrue("The public APK path (" + publicSrcPath + ") should start with "
- + SECURE_CONTAINERS_PREFIX,
- publicSrcPath.startsWith(SECURE_CONTAINERS_PREFIX));
- assertTrue("The native library path (" + info.nativeLibraryDir
- + ") should start with " + SECURE_CONTAINERS_PREFIX,
- info.nativeLibraryDir.startsWith(SECURE_CONTAINERS_PREFIX));
+ assertStartsWith("The APK path should point to the ASEC",
+ SECURE_CONTAINERS_PREFIX, srcPath);
+ assertStartsWith("The public APK path should point to the ASEC",
+ SECURE_CONTAINERS_PREFIX, publicSrcPath);
+ assertStartsWith("The native library path should point to the ASEC",
+ SECURE_CONTAINERS_PREFIX, info.nativeLibraryDir);
// Make sure the native library in /data/data/<app>/lib is a
// symlink to the ASEC
@@ -443,8 +480,8 @@ public class PackageManagerTests extends AndroidTestCase {
nativeLibSymLink.exists());
try {
assertEquals(nativeLibSymLink.getPath() + " should be a symlink to "
- + info.nativeLibraryDir, info.nativeLibraryDir, nativeLibSymLink
- .getCanonicalPath());
+ + info.nativeLibraryDir, info.nativeLibraryDir,
+ nativeLibSymLink.getCanonicalPath());
} catch (IOException e) {
fail("Can't read " + nativeLibSymLink.getPath());
}
@@ -457,6 +494,66 @@ public class PackageManagerTests extends AndroidTestCase {
}
}
+ private void assertDirOwnerGroupPerms(String reason, int uid, int gid, int perms, String path) {
+ final StructStat stat;
+
+ try {
+ stat = Libcore.os.lstat(path);
+ } catch (ErrnoException e) {
+ throw new AssertionError(reason + "\n" + "Got: " + path + " does not exist");
+ }
+
+ StringBuilder sb = new StringBuilder();
+
+ if (!S_ISDIR(stat.st_mode)) {
+ sb.append("\nExpected type: ");
+ sb.append(S_IFDIR);
+ sb.append("\ngot type: ");
+ sb.append((stat.st_mode & S_IFMT));
+ }
+
+ if (stat.st_uid != uid) {
+ sb.append("\nExpected owner: ");
+ sb.append(uid);
+ sb.append("\nGot owner: ");
+ sb.append(stat.st_uid);
+ }
+
+ if (stat.st_gid != gid) {
+ sb.append("\nExpected group: ");
+ sb.append(gid);
+ sb.append("\nGot group: ");
+ sb.append(stat.st_gid);
+ }
+
+ if ((stat.st_mode & ~S_IFMT) != perms) {
+ sb.append("\nExpected permissions: ");
+ sb.append(Integer.toOctalString(perms));
+ sb.append("\nGot permissions: ");
+ sb.append(Integer.toOctalString(stat.st_mode & ~S_IFMT));
+ }
+
+ if (sb.length() > 0) {
+ throw new AssertionError(reason + sb.toString());
+ }
+ }
+
+ private static void assertStartsWith(String prefix, String actual) {
+ assertStartsWith("", prefix, actual);
+ }
+
+ private static void assertStartsWith(String description, String prefix, String actual) {
+ if (!actual.startsWith(prefix)) {
+ StringBuilder sb = new StringBuilder(description);
+ sb.append("\nExpected prefix: ");
+ sb.append(prefix);
+ sb.append("\n got: ");
+ sb.append(actual);
+ sb.append('\n');
+ throw new AssertionError(sb.toString());
+ }
+ }
+
private void assertNotInstalled(String pkgName) {
try {
ApplicationInfo info = getPm().getApplicationInfo(pkgName, 0);
@@ -467,30 +564,38 @@ public class PackageManagerTests extends AndroidTestCase {
class InstallParams {
Uri packageURI;
+
PackageParser.Package pkg;
+
InstallParams(String outFileName, int rawResId) {
this.pkg = getParsedPackage(outFileName, rawResId);
this.packageURI = Uri.fromFile(new File(pkg.mScanPath));
}
+
InstallParams(PackageParser.Package pkg) {
this.packageURI = Uri.fromFile(new File(pkg.mScanPath));
this.pkg = pkg;
}
+
long getApkSize() {
File file = new File(pkg.mScanPath);
return file.length();
}
}
- private InstallParams sampleInstallFromRawResource(int flags, boolean cleanUp) {
- return installFromRawResource("install.apk", R.raw.install, flags, cleanUp,
- false, -1, PackageInfo.INSTALL_LOCATION_UNSPECIFIED);
+ private InstallParams sampleInstallFromRawResource(int flags, boolean cleanUp) throws Exception {
+ return installFromRawResource("install.apk", R.raw.install, flags, cleanUp, false, -1,
+ PackageInfo.INSTALL_LOCATION_UNSPECIFIED);
}
static final String PERM_PACKAGE = "package";
+
static final String PERM_DEFINED = "defined";
+
static final String PERM_UNDEFINED = "undefined";
+
static final String PERM_USED = "used";
+
static final String PERM_NOTUSED = "notused";
private void assertPermissions(String[] cmds) {
@@ -522,7 +627,7 @@ public class PackageManagerTests extends AndroidTestCase {
assertEquals(pi.name, cmd);
assertNotNull(pkgInfo);
boolean found = false;
- for (int j=0; j<pkgInfo.permissions.length && !found; j++) {
+ for (int j = 0; j < pkgInfo.permissions.length && !found; j++) {
if (pkgInfo.permissions[j].name.equals(cmd)) {
found = true;
}
@@ -541,7 +646,7 @@ public class PackageManagerTests extends AndroidTestCase {
}
if (pkgInfo != null) {
boolean found = false;
- for (int j=0; j<pkgInfo.permissions.length && !found; j++) {
+ for (int j = 0; j < pkgInfo.permissions.length && !found; j++) {
if (pkgInfo.permissions[j].name.equals(cmd)) {
found = true;
}
@@ -552,7 +657,7 @@ public class PackageManagerTests extends AndroidTestCase {
}
} else if (mode == PERM_USED || mode == PERM_NOTUSED) {
boolean found = false;
- for (int j=0; j<pkgInfo.requestedPermissions.length && !found; j++) {
+ for (int j = 0; j < pkgInfo.requestedPermissions.length && !found; j++) {
if (pkgInfo.requestedPermissions[j].equals(cmd)) {
found = true;
}
@@ -561,13 +666,11 @@ public class PackageManagerTests extends AndroidTestCase {
fail("Permission not requested: " + cmd);
}
if (mode == PERM_USED) {
- if (pm.checkPermission(cmd, pkg)
- != PackageManager.PERMISSION_GRANTED) {
+ if (pm.checkPermission(cmd, pkg) != PackageManager.PERMISSION_GRANTED) {
fail("Permission not granted: " + cmd);
}
} else {
- if (pm.checkPermission(cmd, pkg)
- != PackageManager.PERMISSION_DENIED) {
+ if (pm.checkPermission(cmd, pkg) != PackageManager.PERMISSION_DENIED) {
fail("Permission granted: " + cmd);
}
}
@@ -590,9 +693,8 @@ public class PackageManagerTests extends AndroidTestCase {
* copies it into own data directory and invokes
* PackageManager api to install it.
*/
- private void installFromRawResource(InstallParams ip,
- int flags, boolean cleanUp, boolean fail, int result,
- int expInstallLocation) {
+ private void installFromRawResource(InstallParams ip, int flags, boolean cleanUp, boolean fail,
+ int result, int expInstallLocation) throws Exception {
PackageManager pm = mContext.getPackageManager();
PackageParser.Package pkg = ip.pkg;
Uri packageURI = ip.packageURI;
@@ -632,26 +734,25 @@ public class PackageManagerTests extends AndroidTestCase {
* copies it into own data directory and invokes
* PackageManager api to install it.
*/
- private InstallParams installFromRawResource(String outFileName,
- int rawResId, int flags, boolean cleanUp, boolean fail, int result,
- int expInstallLocation) {
+ private InstallParams installFromRawResource(String outFileName, int rawResId, int flags,
+ boolean cleanUp, boolean fail, int result, int expInstallLocation) throws Exception {
InstallParams ip = new InstallParams(outFileName, rawResId);
installFromRawResource(ip, flags, cleanUp, fail, result, expInstallLocation);
return ip;
}
@LargeTest
- public void testInstallNormalInternal() {
+ public void testInstallNormalInternal() throws Exception {
sampleInstallFromRawResource(0, true);
}
@LargeTest
- public void testInstallFwdLockedInternal() {
+ public void testInstallFwdLockedInternal() throws Exception {
sampleInstallFromRawResource(PackageManager.INSTALL_FORWARD_LOCK, true);
}
@LargeTest
- public void testInstallSdcard() {
+ public void testInstallSdcard() throws Exception {
// Do not run on devices with emulated external storage.
if (Environment.isExternalStorageEmulated()) {
return;
@@ -661,14 +762,20 @@ public class PackageManagerTests extends AndroidTestCase {
sampleInstallFromRawResource(PackageManager.INSTALL_EXTERNAL, true);
}
- /* ------------------------- Test replacing packages --------------*/
+ /* ------------------------- Test replacing packages -------------- */
class ReplaceReceiver extends GenericReceiver {
String pkgName;
+
final static int INVALID = -1;
+
final static int REMOVED = 1;
+
final static int ADDED = 2;
+
final static int REPLACED = 3;
+
int removed = INVALID;
+
// for updated system apps only
boolean update = false;
@@ -721,7 +828,7 @@ public class PackageManagerTests extends AndroidTestCase {
* PackageManager api to install first and then replace it
* again.
*/
- private void sampleReplaceFromRawResource(int flags) {
+ private void sampleReplaceFromRawResource(int flags) throws Exception {
InstallParams ip = sampleInstallFromRawResource(flags, false);
boolean replace = ((flags & PackageManager.INSTALL_REPLACE_EXISTING) != 0);
Log.i(TAG, "replace=" + replace);
@@ -743,17 +850,17 @@ public class PackageManagerTests extends AndroidTestCase {
}
@LargeTest
- public void testReplaceFailNormalInternal() {
+ public void testReplaceFailNormalInternal() throws Exception {
sampleReplaceFromRawResource(0);
}
@LargeTest
- public void testReplaceFailFwdLockedInternal() {
+ public void testReplaceFailFwdLockedInternal() throws Exception {
sampleReplaceFromRawResource(PackageManager.INSTALL_FORWARD_LOCK);
}
@LargeTest
- public void testReplaceFailSdcard() {
+ public void testReplaceFailSdcard() throws Exception {
// Do not run on devices with emulated external storage.
if (Environment.isExternalStorageEmulated()) {
return;
@@ -763,43 +870,72 @@ public class PackageManagerTests extends AndroidTestCase {
}
@LargeTest
- public void testReplaceNormalInternal() {
+ public void testReplaceNormalInternal() throws Exception {
sampleReplaceFromRawResource(PackageManager.INSTALL_REPLACE_EXISTING);
}
@LargeTest
- public void testReplaceFwdLockedInternal() {
- sampleReplaceFromRawResource(PackageManager.INSTALL_REPLACE_EXISTING |
- PackageManager.INSTALL_FORWARD_LOCK);
+ public void testReplaceFwdLockedInternal() throws Exception {
+ sampleReplaceFromRawResource(PackageManager.INSTALL_REPLACE_EXISTING
+ | PackageManager.INSTALL_FORWARD_LOCK);
}
@LargeTest
- public void testReplaceSdcard() {
+ public void testReplaceSdcard() throws Exception {
// Do not run on devices with emulated external storage.
if (Environment.isExternalStorageEmulated()) {
return;
}
- sampleReplaceFromRawResource(PackageManager.INSTALL_REPLACE_EXISTING |
- PackageManager.INSTALL_EXTERNAL);
+ sampleReplaceFromRawResource(PackageManager.INSTALL_REPLACE_EXISTING
+ | PackageManager.INSTALL_EXTERNAL);
}
- /* -------------- Delete tests ---*/
- class DeleteObserver extends IPackageDeleteObserver.Stub {
+ /* -------------- Delete tests --- */
+ private static class DeleteObserver extends IPackageDeleteObserver.Stub {
+ private CountDownLatch mLatch = new CountDownLatch(1);
- public boolean succeeded;
- private boolean doneFlag = false;
+ private int mReturnCode;
- public boolean isDone() {
- return doneFlag;
+ private final String mPackageName;
+
+ private String mObservedPackage;
+
+ public DeleteObserver(String packageName) {
+ mPackageName = packageName;
+ }
+
+ public boolean isSuccessful() {
+ return mReturnCode == PackageManager.DELETE_SUCCEEDED;
}
public void packageDeleted(String packageName, int returnCode) throws RemoteException {
- synchronized(this) {
- this.succeeded = returnCode == PackageManager.DELETE_SUCCEEDED;
- doneFlag = true;
- notifyAll();
+ mObservedPackage = packageName;
+
+ mReturnCode = returnCode;
+
+ mLatch.countDown();
+ }
+
+ public void waitForCompletion(long timeoutMillis) {
+ final long deadline = SystemClock.uptimeMillis() + timeoutMillis;
+
+ long waitTime = timeoutMillis;
+ while (waitTime > 0) {
+ try {
+ boolean done = mLatch.await(waitTime, TimeUnit.MILLISECONDS);
+ if (done) {
+ assertEquals(mPackageName, mObservedPackage);
+ return;
+ }
+ } catch (InterruptedException e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ }
+ waitTime = deadline - SystemClock.uptimeMillis();
}
+
+ throw new AssertionError("Timeout waiting for package deletion");
}
}
@@ -827,53 +963,51 @@ public class PackageManagerTests extends AndroidTestCase {
}
}
- public boolean invokeDeletePackage(final String pkgName, int flags,
- GenericReceiver receiver) throws Exception {
- DeleteObserver observer = new DeleteObserver();
- final boolean received = false;
+ public boolean invokeDeletePackage(final String pkgName, int flags, GenericReceiver receiver)
+ throws Exception {
+ ApplicationInfo info = getPm().getApplicationInfo(pkgName,
+ PackageManager.GET_UNINSTALLED_PACKAGES);
+
mContext.registerReceiver(receiver, receiver.filter);
try {
- // Wait on observer
- synchronized(observer) {
- synchronized (receiver) {
- getPm().deletePackage(pkgName, observer, flags);
- long waitTime = 0;
- while((!observer.isDone()) && (waitTime < MAX_WAIT_TIME) ) {
- observer.wait(WAIT_TIME_INCR);
- waitTime += WAIT_TIME_INCR;
- }
- if(!observer.isDone()) {
- throw new Exception("Timed out waiting for packageInstalled callback");
- }
- // Verify we received the broadcast
- waitTime = 0;
- while((!receiver.isDone()) && (waitTime < MAX_WAIT_TIME) ) {
- receiver.wait(WAIT_TIME_INCR);
- waitTime += WAIT_TIME_INCR;
- }
- if(!receiver.isDone()) {
- throw new Exception("Timed out waiting for PACKAGE_REMOVED notification");
- }
- return receiver.received;
- }
+ DeleteObserver observer = new DeleteObserver(pkgName);
+
+ getPm().deletePackage(pkgName, observer, flags);
+ observer.waitForCompletion(MAX_WAIT_TIME);
+
+ assertUninstalled(info);
+
+ // Verify we received the broadcast
+ long waitTime = 0;
+ while ((!receiver.isDone()) && (waitTime < MAX_WAIT_TIME)) {
+ receiver.wait(WAIT_TIME_INCR);
+ waitTime += WAIT_TIME_INCR;
+ }
+ if (!receiver.isDone()) {
+ throw new Exception("Timed out waiting for PACKAGE_REMOVED notification");
}
+ return receiver.received;
} finally {
mContext.unregisterReceiver(receiver);
}
}
- public void deleteFromRawResource(int iFlags, int dFlags) {
+ private static void assertUninstalled(ApplicationInfo info) throws Exception {
+ File nativeLibraryFile = new File(info.nativeLibraryDir);
+ assertFalse("Native library directory should be erased", nativeLibraryFile.exists());
+ }
+
+ public void deleteFromRawResource(int iFlags, int dFlags) throws Exception {
InstallParams ip = sampleInstallFromRawResource(iFlags, false);
boolean retainData = ((dFlags & PackageManager.DELETE_KEEP_DATA) != 0);
GenericReceiver receiver = new DeleteReceiver(ip.pkg.packageName);
- DeleteObserver observer = new DeleteObserver();
try {
assertTrue(invokeDeletePackage(ip.pkg.packageName, dFlags, receiver));
ApplicationInfo info = null;
Log.i(TAG, "okay4");
try {
- info = getPm().getApplicationInfo(ip.pkg.packageName,
- PackageManager.GET_UNINSTALLED_PACKAGES);
+ info = getPm().getApplicationInfo(ip.pkg.packageName,
+ PackageManager.GET_UNINSTALLED_PACKAGES);
} catch (NameNotFoundException e) {
info = null;
}
@@ -893,17 +1027,17 @@ public class PackageManagerTests extends AndroidTestCase {
}
@LargeTest
- public void testDeleteNormalInternal() {
+ public void testDeleteNormalInternal() throws Exception {
deleteFromRawResource(0, 0);
}
@LargeTest
- public void testDeleteFwdLockedInternal() {
+ public void testDeleteFwdLockedInternal() throws Exception {
deleteFromRawResource(PackageManager.INSTALL_FORWARD_LOCK, 0);
}
@LargeTest
- public void testDeleteSdcard() {
+ public void testDeleteSdcard() throws Exception {
// Do not run on devices with emulated external storage.
if (Environment.isExternalStorageEmulated()) {
return;
@@ -913,17 +1047,17 @@ public class PackageManagerTests extends AndroidTestCase {
}
@LargeTest
- public void testDeleteNormalInternalRetainData() {
+ public void testDeleteNormalInternalRetainData() throws Exception {
deleteFromRawResource(0, PackageManager.DELETE_KEEP_DATA);
}
@LargeTest
- public void testDeleteFwdLockedInternalRetainData() {
+ public void testDeleteFwdLockedInternalRetainData() throws Exception {
deleteFromRawResource(PackageManager.INSTALL_FORWARD_LOCK, PackageManager.DELETE_KEEP_DATA);
}
@LargeTest
- public void testDeleteSdcardRetainData() {
+ public void testDeleteSdcardRetainData() throws Exception {
// Do not run on devices with emulated external storage.
if (Environment.isExternalStorageEmulated()) {
return;
@@ -932,10 +1066,11 @@ public class PackageManagerTests extends AndroidTestCase {
deleteFromRawResource(PackageManager.INSTALL_EXTERNAL, PackageManager.DELETE_KEEP_DATA);
}
- /* sdcard mount/unmount tests ******/
+ /* sdcard mount/unmount tests ***** */
class SdMountReceiver extends GenericReceiver {
String pkgNames[];
+
boolean status = true;
SdMountReceiver(String[] pkgNames) {
@@ -970,6 +1105,7 @@ public class PackageManagerTests extends AndroidTestCase {
class SdUnMountReceiver extends GenericReceiver {
String pkgNames[];
+
boolean status = true;
SdUnMountReceiver(String[] pkgNames) {
@@ -1081,14 +1217,14 @@ public class PackageManagerTests extends AndroidTestCase {
sm.registerListener(observer);
try {
// Wait on observer
- synchronized(observer) {
+ synchronized (observer) {
getMs().unmountVolume(path, true, false);
long waitTime = 0;
- while((!observer.isDone()) && (waitTime < MAX_WAIT_TIME) ) {
+ while ((!observer.isDone()) && (waitTime < MAX_WAIT_TIME)) {
observer.wait(WAIT_TIME_INCR);
waitTime += WAIT_TIME_INCR;
}
- if(!observer.isDone()) {
+ if (!observer.isDone()) {
throw new Exception("Timed out waiting for unmount media notification");
}
return true;
@@ -1101,7 +1237,7 @@ public class PackageManagerTests extends AndroidTestCase {
}
}
- private boolean mountFromRawResource() {
+ private boolean mountFromRawResource() throws Exception {
// Install pkg on sdcard
InstallParams ip = sampleInstallFromRawResource(PackageManager.INSTALL_EXTERNAL, false);
if (localLOGV) Log.i(TAG, "Installed pkg on sdcard");
@@ -1128,7 +1264,7 @@ public class PackageManagerTests extends AndroidTestCase {
long waitTime = 0;
// Verify we received the broadcast
waitTime = 0;
- while((!receiver.isDone()) && (waitTime < MAX_WAIT_TIME) ) {
+ while ((!receiver.isDone()) && (waitTime < MAX_WAIT_TIME)) {
receiver.wait(WAIT_TIME_INCR);
waitTime += WAIT_TIME_INCR;
}
@@ -1141,7 +1277,9 @@ public class PackageManagerTests extends AndroidTestCase {
failStr(e);
return false;
} finally {
- if (registeredReceiver) mContext.unregisterReceiver(receiver);
+ if (registeredReceiver) {
+ mContext.unregisterReceiver(receiver);
+ }
// Restore original media state
if (origState) {
mountMedia();
@@ -1159,7 +1297,7 @@ public class PackageManagerTests extends AndroidTestCase {
* Make sure the installed package is available.
*/
@LargeTest
- public void testMountSdNormalInternal() {
+ public void testMountSdNormalInternal() throws Exception {
// Do not run on devices with emulated external storage.
if (Environment.isExternalStorageEmulated()) {
return;
@@ -1168,19 +1306,38 @@ public class PackageManagerTests extends AndroidTestCase {
assertTrue(mountFromRawResource());
}
- void cleanUpInstall(InstallParams ip) {
+ void cleanUpInstall(InstallParams ip) throws Exception {
if (ip == null) {
return;
}
Runtime.getRuntime().gc();
- Log.i(TAG, "Deleting package : " + ip.pkg.packageName);
- getPm().deletePackage(ip.pkg.packageName, null, 0);
- File outFile = new File(ip.pkg.mScanPath);
- if (outFile != null && outFile.exists()) {
- outFile.delete();
+
+ final String packageName = ip.pkg.packageName;
+ Log.i(TAG, "Deleting package : " + packageName);
+
+ ApplicationInfo info = null;
+ try {
+ info = getPm().getApplicationInfo(packageName, PackageManager.GET_UNINSTALLED_PACKAGES);
+ } catch (NameNotFoundException ignored) {
+ }
+
+ DeleteObserver observer = new DeleteObserver(packageName);
+ getPm().deletePackage(packageName, observer, 0);
+ observer.waitForCompletion(MAX_WAIT_TIME);
+
+ try {
+ if (info != null) {
+ assertUninstalled(info);
+ }
+ } finally {
+ File outFile = new File(ip.pkg.mScanPath);
+ if (outFile != null && outFile.exists()) {
+ outFile.delete();
+ }
}
}
- void cleanUpInstall(String pkgName) {
+
+ private void cleanUpInstall(String pkgName) throws Exception {
if (pkgName == null) {
return;
}
@@ -1188,20 +1345,25 @@ public class PackageManagerTests extends AndroidTestCase {
try {
ApplicationInfo info = getPm().getApplicationInfo(pkgName,
PackageManager.GET_UNINSTALLED_PACKAGES);
+
if (info != null) {
- getPm().deletePackage(pkgName, null, 0);
+ DeleteObserver observer = new DeleteObserver(pkgName);
+ getPm().deletePackage(pkgName, observer, 0);
+ observer.waitForCompletion(MAX_WAIT_TIME);
+ assertUninstalled(info);
}
- } catch (NameNotFoundException e) {}
+ } catch (NameNotFoundException e) {
+ }
}
@LargeTest
- public void testManifestInstallLocationInternal() {
+ public void testManifestInstallLocationInternal() throws Exception {
installFromRawResource("install.apk", R.raw.install_loc_internal,
0, true, false, -1, PackageInfo.INSTALL_LOCATION_INTERNAL_ONLY);
}
@LargeTest
- public void testManifestInstallLocationSdcard() {
+ public void testManifestInstallLocationSdcard() throws Exception {
// Do not run on devices with emulated external storage.
if (Environment.isExternalStorageEmulated()) {
return;
@@ -1212,19 +1374,19 @@ public class PackageManagerTests extends AndroidTestCase {
}
@LargeTest
- public void testManifestInstallLocationAuto() {
+ public void testManifestInstallLocationAuto() throws Exception {
installFromRawResource("install.apk", R.raw.install_loc_auto,
0, true, false, -1, PackageInfo.INSTALL_LOCATION_AUTO);
}
@LargeTest
- public void testManifestInstallLocationUnspecified() {
+ public void testManifestInstallLocationUnspecified() throws Exception {
installFromRawResource("install.apk", R.raw.install_loc_unspecified,
0, true, false, -1, PackageInfo.INSTALL_LOCATION_UNSPECIFIED);
}
@LargeTest
- public void testManifestInstallLocationFwdLockedFlagSdcard() {
+ public void testManifestInstallLocationFwdLockedFlagSdcard() throws Exception {
// Do not run on devices with emulated external storage.
if (Environment.isExternalStorageEmulated()) {
return;
@@ -1237,15 +1399,14 @@ public class PackageManagerTests extends AndroidTestCase {
}
@LargeTest
- public void testManifestInstallLocationFwdLockedSdcard() {
+ public void testManifestInstallLocationFwdLockedSdcard() throws Exception {
// Do not run on devices with emulated external storage.
if (Environment.isExternalStorageEmulated()) {
return;
}
installFromRawResource("install.apk", R.raw.install_loc_sdcard,
- PackageManager.INSTALL_FORWARD_LOCK, true, false,
- -1,
+ PackageManager.INSTALL_FORWARD_LOCK, true, false, -1,
PackageInfo.INSTALL_LOCATION_PREFER_EXTERNAL);
}
@@ -1255,7 +1416,7 @@ public class PackageManagerTests extends AndroidTestCase {
* the old install location.
*/
@LargeTest
- public void testReplaceFlagInternalSdcard() {
+ public void testReplaceFlagInternalSdcard() throws Exception {
// Do not run on devices with emulated external storage.
if (Environment.isExternalStorageEmulated()) {
return;
@@ -1282,7 +1443,7 @@ public class PackageManagerTests extends AndroidTestCase {
* install location is retained.
*/
@LargeTest
- public void testReplaceFlagSdcardInternal() {
+ public void testReplaceFlagSdcardInternal() throws Exception {
// Do not run on devices with emulated external storage.
if (Environment.isExternalStorageEmulated()) {
return;
@@ -1304,7 +1465,7 @@ public class PackageManagerTests extends AndroidTestCase {
}
@LargeTest
- public void testManifestInstallLocationReplaceInternalSdcard() {
+ public void testManifestInstallLocationReplaceInternalSdcard() throws Exception {
// Do not run on devices with emulated external storage.
if (Environment.isExternalStorageEmulated()) {
return;
@@ -1332,7 +1493,7 @@ public class PackageManagerTests extends AndroidTestCase {
}
@LargeTest
- public void testManifestInstallLocationReplaceSdcardInternal() {
+ public void testManifestInstallLocationReplaceSdcardInternal() throws Exception {
// Do not run on devices with emulated external storage.
if (Environment.isExternalStorageEmulated()) {
return;
@@ -1360,9 +1521,13 @@ public class PackageManagerTests extends AndroidTestCase {
class MoveReceiver extends GenericReceiver {
String pkgName;
+
final static int INVALID = -1;
+
final static int REMOVED = 1;
+
final static int ADDED = 2;
+
int removed = INVALID;
MoveReceiver(String pkgName) {
@@ -1406,17 +1571,21 @@ public class PackageManagerTests extends AndroidTestCase {
private class PackageMoveObserver extends IPackageMoveObserver.Stub {
public int returnCode;
+
private boolean doneFlag = false;
+
public String packageName;
+
public PackageMoveObserver(String pkgName) {
packageName = pkgName;
}
+
public void packageMoved(String packageName, int returnCode) {
Log.i("DEBUG_MOVE::", "pkg = " + packageName + ", " + "ret = " + returnCode);
if (!packageName.equals(this.packageName)) {
return;
}
- synchronized(this) {
+ synchronized (this) {
this.returnCode = returnCode;
doneFlag = true;
notifyAll();
@@ -1428,22 +1597,22 @@ public class PackageManagerTests extends AndroidTestCase {
}
}
- public boolean invokeMovePackage(String pkgName, int flags,
- GenericReceiver receiver) throws Exception {
+ public boolean invokeMovePackage(String pkgName, int flags, GenericReceiver receiver)
+ throws Exception {
PackageMoveObserver observer = new PackageMoveObserver(pkgName);
final boolean received = false;
mContext.registerReceiver(receiver, receiver.filter);
try {
// Wait on observer
- synchronized(observer) {
+ synchronized (observer) {
synchronized (receiver) {
getPm().movePackage(pkgName, observer, flags);
long waitTime = 0;
- while((!observer.isDone()) && (waitTime < MAX_WAIT_TIME) ) {
+ while ((!observer.isDone()) && (waitTime < MAX_WAIT_TIME)) {
observer.wait(WAIT_TIME_INCR);
waitTime += WAIT_TIME_INCR;
}
- if(!observer.isDone()) {
+ if (!observer.isDone()) {
throw new Exception("Timed out waiting for pkgmove callback");
}
if (observer.returnCode != PackageManager.MOVE_SUCCEEDED) {
@@ -1451,11 +1620,11 @@ public class PackageManagerTests extends AndroidTestCase {
}
// Verify we received the broadcast
waitTime = 0;
- while((!receiver.isDone()) && (waitTime < MAX_WAIT_TIME) ) {
+ while ((!receiver.isDone()) && (waitTime < MAX_WAIT_TIME)) {
receiver.wait(WAIT_TIME_INCR);
waitTime += WAIT_TIME_INCR;
}
- if(!receiver.isDone()) {
+ if (!receiver.isDone()) {
throw new Exception("Timed out waiting for MOVE notifications");
}
return receiver.received;
@@ -1465,18 +1634,19 @@ public class PackageManagerTests extends AndroidTestCase {
mContext.unregisterReceiver(receiver);
}
}
+
private boolean invokeMovePackageFail(String pkgName, int flags, int errCode) throws Exception {
PackageMoveObserver observer = new PackageMoveObserver(pkgName);
try {
// Wait on observer
- synchronized(observer) {
+ synchronized (observer) {
getPm().movePackage(pkgName, observer, flags);
long waitTime = 0;
- while((!observer.isDone()) && (waitTime < MAX_WAIT_TIME) ) {
+ while ((!observer.isDone()) && (waitTime < MAX_WAIT_TIME)) {
observer.wait(WAIT_TIME_INCR);
waitTime += WAIT_TIME_INCR;
}
- if(!observer.isDone()) {
+ if (!observer.isDone()) {
throw new Exception("Timed out waiting for pkgmove callback");
}
assertEquals(errCode, observer.returnCode);
@@ -1489,7 +1659,8 @@ public class PackageManagerTests extends AndroidTestCase {
private int getDefaultInstallLoc() {
int origDefaultLoc = PackageInfo.INSTALL_LOCATION_AUTO;
try {
- origDefaultLoc = Settings.System.getInt(mContext.getContentResolver(), Settings.Secure.DEFAULT_INSTALL_LOCATION);
+ origDefaultLoc = Settings.System.getInt(mContext.getContentResolver(),
+ Settings.Secure.DEFAULT_INSTALL_LOCATION);
} catch (SettingNotFoundException e1) {
}
return origDefaultLoc;
@@ -1499,6 +1670,7 @@ public class PackageManagerTests extends AndroidTestCase {
Settings.System.putInt(mContext.getContentResolver(),
Settings.Secure.DEFAULT_INSTALL_LOCATION, loc);
}
+
/*
* Tests for moving apps between internal and external storage
*/
@@ -1509,9 +1681,8 @@ public class PackageManagerTests extends AndroidTestCase {
* again.
*/
- private void moveFromRawResource(String outFileName,
- int rawResId, int installFlags, int moveFlags, boolean cleanUp,
- boolean fail, int result) {
+ private void moveFromRawResource(String outFileName, int rawResId, int installFlags,
+ int moveFlags, boolean cleanUp, boolean fail, int result) throws Exception {
int origDefaultLoc = getDefaultInstallLoc();
InstallParams ip = null;
try {
@@ -1528,8 +1699,7 @@ public class PackageManagerTests extends AndroidTestCase {
} else {
// Create receiver based on expRetCode
MoveReceiver receiver = new MoveReceiver(ip.pkg.packageName);
- boolean retCode = invokeMovePackage(ip.pkg.packageName, moveFlags,
- receiver);
+ boolean retCode = invokeMovePackage(ip.pkg.packageName, moveFlags, receiver);
assertTrue(retCode);
ApplicationInfo info = getPm().getApplicationInfo(ip.pkg.packageName, 0);
assertNotNull("ApplicationInfo for recently installed application should exist",
@@ -1537,16 +1707,16 @@ public class PackageManagerTests extends AndroidTestCase {
if ((moveFlags & PackageManager.MOVE_INTERNAL) != 0) {
assertTrue("ApplicationInfo.FLAG_EXTERNAL_STORAGE flag should NOT be set",
(info.flags & ApplicationInfo.FLAG_EXTERNAL_STORAGE) == 0);
- assertTrue("ApplicationInfo.nativeLibraryDir should start with " + info.dataDir,
- info.nativeLibraryDir.startsWith(info.dataDir));
- } else if ((moveFlags & PackageManager.MOVE_EXTERNAL_MEDIA) != 0){
+ assertStartsWith("Native library dir should be in dataDir",
+ info.dataDir, info.nativeLibraryDir);
+ } else if ((moveFlags & PackageManager.MOVE_EXTERNAL_MEDIA) != 0) {
assertTrue("ApplicationInfo.FLAG_EXTERNAL_STORAGE flag should be set",
(info.flags & ApplicationInfo.FLAG_EXTERNAL_STORAGE) != 0);
- assertTrue("ApplicationInfo.nativeLibraryDir should start with " + SECURE_CONTAINERS_PREFIX,
- info.nativeLibraryDir.startsWith(SECURE_CONTAINERS_PREFIX));
+ assertStartsWith("Native library dir should point to ASEC",
+ SECURE_CONTAINERS_PREFIX, info.nativeLibraryDir);
final File nativeLibSymLink = new File(info.dataDir, "lib");
- assertTrue("The data directory should have a 'lib' symlink that points to the ASEC container",
- nativeLibSymLink.getCanonicalPath().startsWith(SECURE_CONTAINERS_PREFIX));
+ assertStartsWith("The data directory should have a 'lib' symlink that points to the ASEC container",
+ SECURE_CONTAINERS_PREFIX, nativeLibSymLink.getCanonicalPath());
}
}
} catch (NameNotFoundException e) {
@@ -1561,15 +1731,16 @@ public class PackageManagerTests extends AndroidTestCase {
setInstallLoc(origDefaultLoc);
}
}
+
private void sampleMoveFromRawResource(int installFlags, int moveFlags, boolean fail,
- int result) {
+ int result) throws Exception {
moveFromRawResource("install.apk",
R.raw.install, installFlags, moveFlags, true,
fail, result);
}
@LargeTest
- public void testMoveAppInternalToExternal() {
+ public void testMoveAppInternalToExternal() throws Exception {
// Do not run on devices with emulated external storage.
if (Environment.isExternalStorageEmulated()) {
return;
@@ -1583,7 +1754,7 @@ public class PackageManagerTests extends AndroidTestCase {
}
@LargeTest
- public void testMoveAppInternalToInternal() {
+ public void testMoveAppInternalToInternal() throws Exception {
int installFlags = PackageManager.INSTALL_INTERNAL;
int moveFlags = PackageManager.MOVE_INTERNAL;
boolean fail = true;
@@ -1592,7 +1763,7 @@ public class PackageManagerTests extends AndroidTestCase {
}
@LargeTest
- public void testMoveAppExternalToExternal() {
+ public void testMoveAppExternalToExternal() throws Exception {
// Do not run on devices with emulated external storage.
if (Environment.isExternalStorageEmulated()) {
return;
@@ -1606,7 +1777,7 @@ public class PackageManagerTests extends AndroidTestCase {
}
@LargeTest
- public void testMoveAppExternalToInternal() {
+ public void testMoveAppExternalToInternal() throws Exception {
// Do not run on devices with emulated external storage.
if (Environment.isExternalStorageEmulated()) {
return;
@@ -1620,7 +1791,7 @@ public class PackageManagerTests extends AndroidTestCase {
}
@LargeTest
- public void testMoveAppForwardLocked() {
+ public void testMoveAppForwardLocked() throws Exception {
// Do not run on devices with emulated external storage.
if (Environment.isExternalStorageEmulated()) {
return;
@@ -1634,7 +1805,7 @@ public class PackageManagerTests extends AndroidTestCase {
}
@LargeTest
- public void testMoveAppFailInternalToExternalDelete() {
+ public void testMoveAppFailInternalToExternalDelete() throws Exception {
// Do not run on devices with emulated external storage.
if (Environment.isExternalStorageEmulated()) {
return;
@@ -1674,7 +1845,7 @@ public class PackageManagerTests extends AndroidTestCase {
* and package installed on sdcard via package manager flag.
*/
@LargeTest
- public void testInstallSdcardUnmount() {
+ public void testInstallSdcardUnmount() throws Exception {
// Do not run on devices with emulated external storage.
if (Environment.isExternalStorageEmulated()) {
return;
@@ -1704,7 +1875,7 @@ public class PackageManagerTests extends AndroidTestCase {
* on sdcard. Make sure it gets installed on internal flash.
*/
@LargeTest
- public void testInstallManifestSdcardUnmount() {
+ public void testInstallManifestSdcardUnmount() throws Exception {
// Do not run on devices with emulated external storage.
if (Environment.isExternalStorageEmulated()) {
return;
@@ -1727,22 +1898,22 @@ public class PackageManagerTests extends AndroidTestCase {
}
}
- /*---------- Recommended install location tests ----*/
- /* Precedence: FlagManifestExistingUser
- * PrecedenceSuffixes:
- * Flag : FlagI, FlagE, FlagF
- * I - internal, E - external, F - forward locked, Flag suffix absent if not using any option.
- * Manifest: ManifestI, ManifestE, ManifestA, Manifest suffix absent if not using any option.
- * Existing: Existing suffix absent if not existing.
- * User: UserI, UserE, UserA, User suffix absent if not existing.
- *
- */
+ /*---------- Recommended install location tests ----*/
+ /*
+ * PrecedenceSuffixes:
+ * Flag : FlagI, FlagE, FlagF
+ * I - internal, E - external, F - forward locked, Flag suffix absent if not using any option.
+ * Manifest: ManifestI, ManifestE, ManifestA, Manifest suffix absent if not using any option.
+ * Existing: Existing suffix absent if not existing.
+ * User: UserI, UserE, UserA, User suffix absent if not existing.
+ *
+ */
/*
* Install an app on internal flash
*/
@LargeTest
- public void testFlagI() {
+ public void testFlagI() throws Exception {
sampleInstallFromRawResource(PackageManager.INSTALL_INTERNAL, true);
}
@@ -1750,7 +1921,7 @@ public class PackageManagerTests extends AndroidTestCase {
* Install an app on sdcard.
*/
@LargeTest
- public void testFlagE() {
+ public void testFlagE() throws Exception {
// Do not run on devices with emulated external storage.
if (Environment.isExternalStorageEmulated()) {
return;
@@ -1763,7 +1934,7 @@ public class PackageManagerTests extends AndroidTestCase {
* Install an app forward-locked.
*/
@LargeTest
- public void testFlagF() {
+ public void testFlagF() throws Exception {
sampleInstallFromRawResource(PackageManager.INSTALL_FORWARD_LOCK, true);
}
@@ -1771,7 +1942,7 @@ public class PackageManagerTests extends AndroidTestCase {
* Install an app with both internal and external flags set. should fail
*/
@LargeTest
- public void testFlagIE() {
+ public void testFlagIE() throws Exception {
installFromRawResource("install.apk", R.raw.install,
PackageManager.INSTALL_EXTERNAL | PackageManager.INSTALL_INTERNAL,
false,
@@ -1783,7 +1954,7 @@ public class PackageManagerTests extends AndroidTestCase {
* Install an app with both internal and forward-lock flags set.
*/
@LargeTest
- public void testFlagIF() {
+ public void testFlagIF() throws Exception {
sampleInstallFromRawResource(PackageManager.INSTALL_FORWARD_LOCK
| PackageManager.INSTALL_INTERNAL, true);
}
@@ -1792,7 +1963,7 @@ public class PackageManagerTests extends AndroidTestCase {
* Install an app with both external and forward-lock flags set.
*/
@LargeTest
- public void testFlagEF() {
+ public void testFlagEF() throws Exception {
// Do not run on devices with emulated external storage.
if (Environment.isExternalStorageEmulated()) {
return;
@@ -1807,7 +1978,7 @@ public class PackageManagerTests extends AndroidTestCase {
* lock. Should fail.
*/
@LargeTest
- public void testFlagIEF() {
+ public void testFlagIEF() throws Exception {
installFromRawResource("install.apk", R.raw.install,
PackageManager.INSTALL_FORWARD_LOCK | PackageManager.INSTALL_INTERNAL |
PackageManager.INSTALL_EXTERNAL,
@@ -1816,66 +1987,66 @@ public class PackageManagerTests extends AndroidTestCase {
PackageInfo.INSTALL_LOCATION_AUTO);
}
- /*
- * Install an app with both internal and manifest option set.
- * should install on internal.
- */
- @LargeTest
- public void testFlagIManifestI() {
- installFromRawResource("install.apk", R.raw.install_loc_internal,
- PackageManager.INSTALL_INTERNAL,
- true,
- false, -1,
- PackageInfo.INSTALL_LOCATION_INTERNAL_ONLY);
- }
- /*
- * Install an app with both internal and manifest preference for
- * preferExternal. Should install on internal.
- */
- @LargeTest
- public void testFlagIManifestE() {
- installFromRawResource("install.apk", R.raw.install_loc_sdcard,
- PackageManager.INSTALL_INTERNAL,
- true,
- false, -1,
- PackageInfo.INSTALL_LOCATION_INTERNAL_ONLY);
- }
- /*
- * Install an app with both internal and manifest preference for
- * auto. should install internal.
- */
- @LargeTest
- public void testFlagIManifestA() {
- installFromRawResource("install.apk", R.raw.install_loc_auto,
- PackageManager.INSTALL_INTERNAL,
- true,
- false, -1,
- PackageInfo.INSTALL_LOCATION_INTERNAL_ONLY);
- }
- /*
- * Install an app with both external and manifest option set.
- * should install externally.
- */
- @LargeTest
- public void testFlagEManifestI() {
+ /*
+ * Install an app with both internal and manifest option set.
+ * should install on internal.
+ */
+ @LargeTest
+ public void testFlagIManifestI() throws Exception {
+ installFromRawResource("install.apk", R.raw.install_loc_internal,
+ PackageManager.INSTALL_INTERNAL,
+ true,
+ false, -1,
+ PackageInfo.INSTALL_LOCATION_INTERNAL_ONLY);
+ }
+ /*
+ * Install an app with both internal and manifest preference for
+ * preferExternal. Should install on internal.
+ */
+ @LargeTest
+ public void testFlagIManifestE() throws Exception {
+ installFromRawResource("install.apk", R.raw.install_loc_sdcard,
+ PackageManager.INSTALL_INTERNAL,
+ true,
+ false, -1,
+ PackageInfo.INSTALL_LOCATION_INTERNAL_ONLY);
+ }
+ /*
+ * Install an app with both internal and manifest preference for
+ * auto. should install internal.
+ */
+ @LargeTest
+ public void testFlagIManifestA() throws Exception {
+ installFromRawResource("install.apk", R.raw.install_loc_auto,
+ PackageManager.INSTALL_INTERNAL,
+ true,
+ false, -1,
+ PackageInfo.INSTALL_LOCATION_INTERNAL_ONLY);
+ }
+ /*
+ * Install an app with both external and manifest option set.
+ * should install externally.
+ */
+ @LargeTest
+ public void testFlagEManifestI() throws Exception {
// Do not run on devices with emulated external storage.
if (Environment.isExternalStorageEmulated()) {
return;
}
- installFromRawResource("install.apk", R.raw.install_loc_internal,
- PackageManager.INSTALL_EXTERNAL,
- true,
- false, -1,
- PackageInfo.INSTALL_LOCATION_PREFER_EXTERNAL);
- }
+ installFromRawResource("install.apk", R.raw.install_loc_internal,
+ PackageManager.INSTALL_EXTERNAL,
+ true,
+ false, -1,
+ PackageInfo.INSTALL_LOCATION_PREFER_EXTERNAL);
+ }
- /*
- * Install an app with both external and manifest preference for
- * preferExternal. Should install externally.
- */
- @LargeTest
- public void testFlagEManifestE() {
+ /*
+ * Install an app with both external and manifest preference for
+ * preferExternal. Should install externally.
+ */
+ @LargeTest
+ public void testFlagEManifestE() throws Exception {
// Do not run on devices with emulated external storage.
if (Environment.isExternalStorageEmulated()) {
return;
@@ -1893,7 +2064,7 @@ public class PackageManagerTests extends AndroidTestCase {
* auto. should install on external media.
*/
@LargeTest
- public void testFlagEManifestA() {
+ public void testFlagEManifestA() throws Exception {
// Do not run on devices with emulated external storage.
if (Environment.isExternalStorageEmulated()) {
return;
@@ -1911,7 +2082,7 @@ public class PackageManagerTests extends AndroidTestCase {
* internal. should install internally.
*/
@LargeTest
- public void testFlagFManifestI() {
+ public void testFlagFManifestI() throws Exception {
installFromRawResource("install.apk", R.raw.install_loc_internal,
PackageManager.INSTALL_FORWARD_LOCK,
true,
@@ -1924,7 +2095,7 @@ public class PackageManagerTests extends AndroidTestCase {
* preferExternal. Should install externally.
*/
@LargeTest
- public void testFlagFManifestE() {
+ public void testFlagFManifestE() throws Exception {
// Do not run on devices with emulated external storage.
if (Environment.isExternalStorageEmulated()) {
return;
@@ -1942,7 +2113,7 @@ public class PackageManagerTests extends AndroidTestCase {
* should install externally.
*/
@LargeTest
- public void testFlagFManifestA() {
+ public void testFlagFManifestA() throws Exception {
// Do not run on devices with emulated external storage.
if (Environment.isExternalStorageEmulated()) {
return;
@@ -1955,7 +2126,8 @@ public class PackageManagerTests extends AndroidTestCase {
PackageInfo.INSTALL_LOCATION_AUTO);
}
- /* The following test functions verify install location for existing apps.
+ /*
+ * The following test functions verify install location for existing apps.
* ie existing app can be installed internally or externally. If install
* flag is explicitly set it should override current location. If manifest location
* is set, that should over ride current location too. if not the existing install
@@ -1963,7 +2135,7 @@ public class PackageManagerTests extends AndroidTestCase {
* testFlagI/E/F/ExistingI/E -
*/
@LargeTest
- public void testFlagIExistingI() {
+ public void testFlagIExistingI() throws Exception {
int iFlags = PackageManager.INSTALL_INTERNAL;
int rFlags = PackageManager.INSTALL_INTERNAL | PackageManager.INSTALL_REPLACE_EXISTING;
// First install.
@@ -1981,7 +2153,7 @@ public class PackageManagerTests extends AndroidTestCase {
}
@LargeTest
- public void testFlagIExistingE() {
+ public void testFlagIExistingE() throws Exception {
// Do not run on devices with emulated external storage.
if (Environment.isExternalStorageEmulated()) {
return;
@@ -2004,7 +2176,7 @@ public class PackageManagerTests extends AndroidTestCase {
}
@LargeTest
- public void testFlagEExistingI() {
+ public void testFlagEExistingI() throws Exception {
// Do not run on devices with emulated external storage.
if (Environment.isExternalStorageEmulated()) {
return;
@@ -2027,7 +2199,7 @@ public class PackageManagerTests extends AndroidTestCase {
}
@LargeTest
- public void testFlagEExistingE() {
+ public void testFlagEExistingE() throws Exception {
// Do not run on devices with emulated external storage.
if (Environment.isExternalStorageEmulated()) {
return;
@@ -2050,7 +2222,7 @@ public class PackageManagerTests extends AndroidTestCase {
}
@LargeTest
- public void testFlagFExistingI() {
+ public void testFlagFExistingI() throws Exception {
int iFlags = PackageManager.INSTALL_INTERNAL;
int rFlags = PackageManager.INSTALL_FORWARD_LOCK | PackageManager.INSTALL_REPLACE_EXISTING;
// First install.
@@ -2068,7 +2240,7 @@ public class PackageManagerTests extends AndroidTestCase {
}
@LargeTest
- public void testFlagFExistingE() {
+ public void testFlagFExistingE() throws Exception {
// Do not run on devices with emulated external storage.
if (Environment.isExternalStorageEmulated()) {
return;
@@ -2098,7 +2270,7 @@ public class PackageManagerTests extends AndroidTestCase {
* TODO out of memory fall back behaviour.
*/
@LargeTest
- public void testManifestI() {
+ public void testManifestI() throws Exception {
installFromRawResource("install.apk", R.raw.install_loc_internal,
0,
true,
@@ -2107,7 +2279,7 @@ public class PackageManagerTests extends AndroidTestCase {
}
@LargeTest
- public void testManifestE() {
+ public void testManifestE() throws Exception {
// Do not run on devices with emulated external storage.
if (Environment.isExternalStorageEmulated()) {
return;
@@ -2121,7 +2293,7 @@ public class PackageManagerTests extends AndroidTestCase {
}
@LargeTest
- public void testManifestA() {
+ public void testManifestA() throws Exception {
installFromRawResource("install.apk", R.raw.install_loc_auto,
0,
true,
@@ -2137,7 +2309,7 @@ public class PackageManagerTests extends AndroidTestCase {
* testManifestI/E/AExistingI/E
*/
@LargeTest
- public void testManifestIExistingI() {
+ public void testManifestIExistingI() throws Exception {
int iFlags = PackageManager.INSTALL_INTERNAL;
int rFlags = PackageManager.INSTALL_REPLACE_EXISTING;
// First install.
@@ -2155,7 +2327,7 @@ public class PackageManagerTests extends AndroidTestCase {
}
@LargeTest
- public void testManifestIExistingE() {
+ public void testManifestIExistingE() throws Exception {
// Do not run on devices with emulated external storage.
if (Environment.isExternalStorageEmulated()) {
return;
@@ -2178,7 +2350,7 @@ public class PackageManagerTests extends AndroidTestCase {
}
@LargeTest
- public void testManifestEExistingI() {
+ public void testManifestEExistingI() throws Exception {
// Do not run on devices with emulated external storage.
if (Environment.isExternalStorageEmulated()) {
return;
@@ -2201,7 +2373,7 @@ public class PackageManagerTests extends AndroidTestCase {
}
@LargeTest
- public void testManifestEExistingE() {
+ public void testManifestEExistingE() throws Exception {
// Do not run on devices with emulated external storage.
if (Environment.isExternalStorageEmulated()) {
return;
@@ -2224,7 +2396,7 @@ public class PackageManagerTests extends AndroidTestCase {
}
@LargeTest
- public void testManifestAExistingI() {
+ public void testManifestAExistingI() throws Exception {
int iFlags = PackageManager.INSTALL_INTERNAL;
int rFlags = PackageManager.INSTALL_REPLACE_EXISTING;
// First install.
@@ -2242,7 +2414,7 @@ public class PackageManagerTests extends AndroidTestCase {
}
@LargeTest
- public void testManifestAExistingE() {
+ public void testManifestAExistingE() throws Exception {
// Do not run on devices with emulated external storage.
if (Environment.isExternalStorageEmulated()) {
return;
@@ -2264,55 +2436,56 @@ public class PackageManagerTests extends AndroidTestCase {
PackageInfo.INSTALL_LOCATION_PREFER_EXTERNAL);
}
- /*
- * The following set of tests check install location for existing
- * application based on user setting.
- */
- private int getExpectedInstallLocation(int userSetting) {
- int iloc = PackageInfo.INSTALL_LOCATION_UNSPECIFIED;
- boolean enable = getUserSettingSetInstallLocation();
- if (enable) {
- if (userSetting == PackageHelper.APP_INSTALL_AUTO) {
- iloc = PackageInfo.INSTALL_LOCATION_AUTO;
- } else if (userSetting == PackageHelper.APP_INSTALL_EXTERNAL) {
- iloc = PackageInfo.INSTALL_LOCATION_PREFER_EXTERNAL;
- } else if (userSetting == PackageHelper.APP_INSTALL_INTERNAL) {
- iloc = PackageInfo.INSTALL_LOCATION_INTERNAL_ONLY;
- }
- }
- return iloc;
- }
- private void setExistingXUserX(int userSetting, int iFlags, int iloc) {
- int rFlags = PackageManager.INSTALL_REPLACE_EXISTING;
- // First install.
- installFromRawResource("install.apk", R.raw.install,
- iFlags,
- false,
- false, -1,
- PackageInfo.INSTALL_LOCATION_UNSPECIFIED);
- int origSetting = getDefaultInstallLoc();
- try {
- // Set user setting
- setInstallLoc(userSetting);
- // Replace now
- installFromRawResource("install.apk", R.raw.install,
- rFlags,
- true,
- false, -1,
- iloc);
- } finally {
- setInstallLoc(origSetting);
- }
- }
- @LargeTest
- public void testExistingIUserI() {
- int userSetting = PackageHelper.APP_INSTALL_INTERNAL;
- int iFlags = PackageManager.INSTALL_INTERNAL;
- setExistingXUserX(userSetting, iFlags, PackageInfo.INSTALL_LOCATION_INTERNAL_ONLY);
- }
-
- @LargeTest
- public void testExistingIUserE() {
+ /*
+ * The following set of tests check install location for existing
+ * application based on user setting.
+ */
+ private int getExpectedInstallLocation(int userSetting) {
+ int iloc = PackageInfo.INSTALL_LOCATION_UNSPECIFIED;
+ boolean enable = getUserSettingSetInstallLocation();
+ if (enable) {
+ if (userSetting == PackageHelper.APP_INSTALL_AUTO) {
+ iloc = PackageInfo.INSTALL_LOCATION_AUTO;
+ } else if (userSetting == PackageHelper.APP_INSTALL_EXTERNAL) {
+ iloc = PackageInfo.INSTALL_LOCATION_PREFER_EXTERNAL;
+ } else if (userSetting == PackageHelper.APP_INSTALL_INTERNAL) {
+ iloc = PackageInfo.INSTALL_LOCATION_INTERNAL_ONLY;
+ }
+ }
+ return iloc;
+ }
+
+ private void setExistingXUserX(int userSetting, int iFlags, int iloc) throws Exception {
+ int rFlags = PackageManager.INSTALL_REPLACE_EXISTING;
+ // First install.
+ installFromRawResource("install.apk", R.raw.install,
+ iFlags,
+ false,
+ false, -1,
+ PackageInfo.INSTALL_LOCATION_UNSPECIFIED);
+ int origSetting = getDefaultInstallLoc();
+ try {
+ // Set user setting
+ setInstallLoc(userSetting);
+ // Replace now
+ installFromRawResource("install.apk", R.raw.install,
+ rFlags,
+ true,
+ false, -1,
+ iloc);
+ } finally {
+ setInstallLoc(origSetting);
+ }
+ }
+ @LargeTest
+ public void testExistingIUserI() throws Exception {
+ int userSetting = PackageHelper.APP_INSTALL_INTERNAL;
+ int iFlags = PackageManager.INSTALL_INTERNAL;
+ setExistingXUserX(userSetting, iFlags, PackageInfo.INSTALL_LOCATION_INTERNAL_ONLY);
+ }
+
+ @LargeTest
+ public void testExistingIUserE() throws Exception {
// Do not run on devices with emulated external storage.
if (Environment.isExternalStorageEmulated()) {
return;
@@ -2323,15 +2496,15 @@ public class PackageManagerTests extends AndroidTestCase {
setExistingXUserX(userSetting, iFlags, PackageInfo.INSTALL_LOCATION_INTERNAL_ONLY);
}
- @LargeTest
- public void testExistingIUserA() {
- int userSetting = PackageHelper.APP_INSTALL_AUTO;
- int iFlags = PackageManager.INSTALL_INTERNAL;
- setExistingXUserX(userSetting, iFlags, PackageInfo.INSTALL_LOCATION_INTERNAL_ONLY);
- }
+ @LargeTest
+ public void testExistingIUserA() throws Exception {
+ int userSetting = PackageHelper.APP_INSTALL_AUTO;
+ int iFlags = PackageManager.INSTALL_INTERNAL;
+ setExistingXUserX(userSetting, iFlags, PackageInfo.INSTALL_LOCATION_INTERNAL_ONLY);
+ }
@LargeTest
- public void testExistingEUserI() {
+ public void testExistingEUserI() throws Exception {
// Do not run on devices with emulated external storage.
if (Environment.isExternalStorageEmulated()) {
return;
@@ -2343,7 +2516,7 @@ public class PackageManagerTests extends AndroidTestCase {
}
@LargeTest
- public void testExistingEUserE() {
+ public void testExistingEUserE() throws Exception {
// Do not run on devices with emulated external storage.
if (Environment.isExternalStorageEmulated()) {
return;
@@ -2355,7 +2528,7 @@ public class PackageManagerTests extends AndroidTestCase {
}
@LargeTest
- public void testExistingEUserA() {
+ public void testExistingEUserA() throws Exception {
// Do not run on devices with emulated external storage.
if (Environment.isExternalStorageEmulated()) {
return;
@@ -2366,52 +2539,53 @@ public class PackageManagerTests extends AndroidTestCase {
setExistingXUserX(userSetting, iFlags, PackageInfo.INSTALL_LOCATION_PREFER_EXTERNAL);
}
- /*
- * The following set of tests verify that the user setting defines
- * the install location.
- *
- */
- private boolean getUserSettingSetInstallLocation() {
- try {
- return Settings.System.getInt(mContext.getContentResolver(), Settings.Secure.SET_INSTALL_LOCATION) != 0;
-
- } catch (SettingNotFoundException e1) {
- }
- return false;
- }
-
- private void setUserSettingSetInstallLocation(boolean value) {
- Settings.System.putInt(mContext.getContentResolver(),
- Settings.Secure.SET_INSTALL_LOCATION, value ? 1 : 0);
- }
- private void setUserX(boolean enable, int userSetting, int iloc) {
- boolean origUserSetting = getUserSettingSetInstallLocation();
- int origSetting = getDefaultInstallLoc();
- try {
- setUserSettingSetInstallLocation(enable);
- // Set user setting
- setInstallLoc(userSetting);
- // Replace now
- installFromRawResource("install.apk", R.raw.install,
- 0,
- true,
- false, -1,
- iloc);
- } finally {
- // Restore original setting
- setUserSettingSetInstallLocation(origUserSetting);
- setInstallLoc(origSetting);
- }
- }
- @LargeTest
- public void testUserI() {
- int userSetting = PackageHelper.APP_INSTALL_INTERNAL;
- int iloc = getExpectedInstallLocation(userSetting);
- setUserX(true, userSetting, iloc);
- }
-
- @LargeTest
- public void testUserE() {
+ /*
+ * The following set of tests verify that the user setting defines
+ * the install location.
+ *
+ */
+ private boolean getUserSettingSetInstallLocation() {
+ try {
+ return Settings.System.getInt(mContext.getContentResolver(), Settings.Secure.SET_INSTALL_LOCATION) != 0;
+
+ } catch (SettingNotFoundException e1) {
+ }
+ return false;
+ }
+
+ private void setUserSettingSetInstallLocation(boolean value) {
+ Settings.System.putInt(mContext.getContentResolver(),
+ Settings.Secure.SET_INSTALL_LOCATION, value ? 1 : 0);
+ }
+
+ private void setUserX(boolean enable, int userSetting, int iloc) throws Exception {
+ boolean origUserSetting = getUserSettingSetInstallLocation();
+ int origSetting = getDefaultInstallLoc();
+ try {
+ setUserSettingSetInstallLocation(enable);
+ // Set user setting
+ setInstallLoc(userSetting);
+ // Replace now
+ installFromRawResource("install.apk", R.raw.install,
+ 0,
+ true,
+ false, -1,
+ iloc);
+ } finally {
+ // Restore original setting
+ setUserSettingSetInstallLocation(origUserSetting);
+ setInstallLoc(origSetting);
+ }
+ }
+ @LargeTest
+ public void testUserI() throws Exception {
+ int userSetting = PackageHelper.APP_INSTALL_INTERNAL;
+ int iloc = getExpectedInstallLocation(userSetting);
+ setUserX(true, userSetting, iloc);
+ }
+
+ @LargeTest
+ public void testUserE() throws Exception {
// Do not run on devices with emulated external storage.
if (Environment.isExternalStorageEmulated()) {
return;
@@ -2422,25 +2596,26 @@ public class PackageManagerTests extends AndroidTestCase {
setUserX(true, userSetting, iloc);
}
- @LargeTest
- public void testUserA() {
- int userSetting = PackageHelper.APP_INSTALL_AUTO;
- int iloc = getExpectedInstallLocation(userSetting);
- setUserX(true, userSetting, iloc);
- }
- /*
- * The following set of tests turn on/off the basic
- * user setting for turning on install location.
- */
- @LargeTest
- public void testUserPrefOffUserI() {
- int userSetting = PackageHelper.APP_INSTALL_INTERNAL;
- int iloc = PackageInfo.INSTALL_LOCATION_UNSPECIFIED;
- setUserX(false, userSetting, iloc);
- }
-
- @LargeTest
- public void testUserPrefOffUserE() {
+ @LargeTest
+ public void testUserA() throws Exception {
+ int userSetting = PackageHelper.APP_INSTALL_AUTO;
+ int iloc = getExpectedInstallLocation(userSetting);
+ setUserX(true, userSetting, iloc);
+ }
+
+ /*
+ * The following set of tests turn on/off the basic
+ * user setting for turning on install location.
+ */
+ @LargeTest
+ public void testUserPrefOffUserI() throws Exception {
+ int userSetting = PackageHelper.APP_INSTALL_INTERNAL;
+ int iloc = PackageInfo.INSTALL_LOCATION_UNSPECIFIED;
+ setUserX(false, userSetting, iloc);
+ }
+
+ @LargeTest
+ public void testUserPrefOffUserE() throws Exception {
// Do not run on devices with emulated external storage.
if (Environment.isExternalStorageEmulated()) {
return;
@@ -2451,12 +2626,12 @@ public class PackageManagerTests extends AndroidTestCase {
setUserX(false, userSetting, iloc);
}
- @LargeTest
- public void testUserPrefOffA() {
- int userSetting = PackageHelper.APP_INSTALL_AUTO;
- int iloc = PackageInfo.INSTALL_LOCATION_UNSPECIFIED;
- setUserX(false, userSetting, iloc);
- }
+ @LargeTest
+ public void testUserPrefOffA() throws Exception {
+ int userSetting = PackageHelper.APP_INSTALL_AUTO;
+ int iloc = PackageInfo.INSTALL_LOCATION_UNSPECIFIED;
+ setUserX(false, userSetting, iloc);
+ }
static final String BASE_PERMISSIONS_DEFINED[] = new String[] {
PERM_PACKAGE, "com.android.unit_tests.install_decl_perm",
@@ -2503,7 +2678,7 @@ public class PackageManagerTests extends AndroidTestCase {
* Ensure that permissions are properly declared.
*/
@LargeTest
- public void testInstallDeclaresPermissions() {
+ public void testInstallDeclaresPermissions() throws Exception {
InstallParams ip = null;
InstallParams ip2 = null;
try {
@@ -2629,7 +2804,7 @@ public class PackageManagerTests extends AndroidTestCase {
* Ensure that permissions are properly declared.
*/
@LargeTest
- public void testInstallOnSdPermissionsUnmount() {
+ public void testInstallOnSdPermissionsUnmount() throws Exception {
InstallParams ip = null;
boolean origMediaState = checkMediaState(Environment.MEDIA_MOUNTED);
try {
@@ -2661,7 +2836,7 @@ public class PackageManagerTests extends AndroidTestCase {
* naming convention for secure containers.
*/
@LargeTest
- public void testInstallSdcardStaleContainer() {
+ public void testInstallSdcardStaleContainer() throws Exception {
// Do not run on devices with emulated external storage.
if (Environment.isExternalStorageEmulated()) {
return;
@@ -2710,7 +2885,7 @@ public class PackageManagerTests extends AndroidTestCase {
* and verified that the re-installation on internal storage takes precedence.
*/
@LargeTest
- public void testInstallSdcardStaleContainerReinstall() {
+ public void testInstallSdcardStaleContainerReinstall() throws Exception {
// Do not run on devices with emulated external storage.
if (Environment.isExternalStorageEmulated()) {
return;
@@ -2740,7 +2915,7 @@ public class PackageManagerTests extends AndroidTestCase {
false, -1, PackageInfo.INSTALL_LOCATION_UNSPECIFIED);
mountMedia();
// Verify that the app installed is on internal storage.
- assertInstall(pkg, 0, PackageInfo.INSTALL_LOCATION_INTERNAL_ONLY);
+ assertInstall(pkg, 0, PackageInfo.INSTALL_LOCATION_INTERNAL_ONLY);
} catch (Exception e) {
failStr(e.getMessage());
} finally {
@@ -2757,18 +2932,29 @@ public class PackageManagerTests extends AndroidTestCase {
* different certificates.
*/
private int APP1_UNSIGNED = R.raw.install_app1_unsigned;
+
private int APP1_CERT1 = R.raw.install_app1_cert1;
+
private int APP1_CERT2 = R.raw.install_app1_cert2;
+
private int APP1_CERT1_CERT2 = R.raw.install_app1_cert1_cert2;
+
private int APP1_CERT3_CERT4 = R.raw.install_app1_cert3_cert4;
+
private int APP1_CERT3 = R.raw.install_app1_cert3;
+
private int APP2_UNSIGNED = R.raw.install_app2_unsigned;
+
private int APP2_CERT1 = R.raw.install_app2_cert1;
+
private int APP2_CERT2 = R.raw.install_app2_cert2;
+
private int APP2_CERT1_CERT2 = R.raw.install_app2_cert1_cert2;
+
private int APP2_CERT3 = R.raw.install_app2_cert3;
- private InstallParams replaceCerts(int apk1, int apk2, boolean cleanUp, boolean fail, int retCode) {
+ private InstallParams replaceCerts(int apk1, int apk2, boolean cleanUp, boolean fail,
+ int retCode) throws Exception {
int rFlags = PackageManager.INSTALL_REPLACE_EXISTING;
String apk1Name = "install1.apk";
String apk2Name = "install2.apk";
@@ -2788,12 +2974,13 @@ public class PackageManagerTests extends AndroidTestCase {
}
return null;
}
+
/*
* Test that an app signed with two certificates can be upgraded by the
* same app signed with two certificates.
*/
@LargeTest
- public void testReplaceMatchAllCerts() {
+ public void testReplaceMatchAllCerts() throws Exception {
replaceCerts(APP1_CERT1_CERT2, APP1_CERT1_CERT2, true, false, -1);
}
@@ -2802,53 +2989,58 @@ public class PackageManagerTests extends AndroidTestCase {
* by an app signed with a different certificate.
*/
@LargeTest
- public void testReplaceMatchNoCerts1() {
+ public void testReplaceMatchNoCerts1() throws Exception {
replaceCerts(APP1_CERT1_CERT2, APP1_CERT3, true, true,
PackageManager.INSTALL_PARSE_FAILED_INCONSISTENT_CERTIFICATES);
}
+
/*
* Test that an app signed with two certificates cannot be upgraded
* by an app signed with a different certificate.
*/
@LargeTest
- public void testReplaceMatchNoCerts2() {
+ public void testReplaceMatchNoCerts2() throws Exception {
replaceCerts(APP1_CERT1_CERT2, APP1_CERT3_CERT4, true, true,
PackageManager.INSTALL_PARSE_FAILED_INCONSISTENT_CERTIFICATES);
}
+
/*
* Test that an app signed with two certificates cannot be upgraded by
* an app signed with a subset of initial certificates.
*/
@LargeTest
- public void testReplaceMatchSomeCerts1() {
+ public void testReplaceMatchSomeCerts1() throws Exception {
replaceCerts(APP1_CERT1_CERT2, APP1_CERT1, true, true,
PackageManager.INSTALL_PARSE_FAILED_INCONSISTENT_CERTIFICATES);
}
+
/*
* Test that an app signed with two certificates cannot be upgraded by
* an app signed with the last certificate.
*/
@LargeTest
- public void testReplaceMatchSomeCerts2() {
+ public void testReplaceMatchSomeCerts2() throws Exception {
replaceCerts(APP1_CERT1_CERT2, APP1_CERT2, true, true,
PackageManager.INSTALL_PARSE_FAILED_INCONSISTENT_CERTIFICATES);
}
+
/*
* Test that an app signed with a certificate can be upgraded by app
* signed with a superset of certificates.
*/
@LargeTest
- public void testReplaceMatchMoreCerts() {
+ public void testReplaceMatchMoreCerts() throws Exception {
replaceCerts(APP1_CERT1, APP1_CERT1_CERT2, true, true,
PackageManager.INSTALL_PARSE_FAILED_INCONSISTENT_CERTIFICATES);
}
+
/*
* Test that an app signed with a certificate can be upgraded by app
* signed with a superset of certificates. Then verify that the an app
* signed with the original set of certs cannot upgrade the new one.
*/
@LargeTest
- public void testReplaceMatchMoreCertsReplaceSomeCerts() {
+ public void testReplaceMatchMoreCertsReplaceSomeCerts() throws Exception {
InstallParams ip = replaceCerts(APP1_CERT1, APP1_CERT1_CERT2, false, true,
PackageManager.INSTALL_PARSE_FAILED_INCONSISTENT_CERTIFICATES);
try {
@@ -2864,45 +3056,51 @@ public class PackageManagerTests extends AndroidTestCase {
}
}
}
- /*
- * The following tests are related to testing the checkSignatures
- * api.
+
+ /**
+ * The following tests are related to testing the checkSignatures api.
*/
- private void checkSignatures(int apk1, int apk2, int expMatchResult) {
+ private void checkSignatures(int apk1, int apk2, int expMatchResult) throws Exception {
checkSharedSignatures(apk1, apk2, true, false, -1, expMatchResult);
}
+
@LargeTest
- public void testCheckSignaturesAllMatch() {
+ public void testCheckSignaturesAllMatch() throws Exception {
int apk1 = APP1_CERT1_CERT2;
int apk2 = APP2_CERT1_CERT2;
checkSignatures(apk1, apk2, PackageManager.SIGNATURE_MATCH);
}
+
@LargeTest
- public void testCheckSignaturesNoMatch() {
+ public void testCheckSignaturesNoMatch() throws Exception {
int apk1 = APP1_CERT1;
int apk2 = APP2_CERT2;
checkSignatures(apk1, apk2, PackageManager.SIGNATURE_NO_MATCH);
}
+
@LargeTest
- public void testCheckSignaturesSomeMatch1() {
+ public void testCheckSignaturesSomeMatch1() throws Exception {
int apk1 = APP1_CERT1_CERT2;
int apk2 = APP2_CERT1;
checkSignatures(apk1, apk2, PackageManager.SIGNATURE_NO_MATCH);
}
+
@LargeTest
- public void testCheckSignaturesSomeMatch2() {
+ public void testCheckSignaturesSomeMatch2() throws Exception {
int apk1 = APP1_CERT1_CERT2;
int apk2 = APP2_CERT2;
checkSignatures(apk1, apk2, PackageManager.SIGNATURE_NO_MATCH);
}
+
@LargeTest
- public void testCheckSignaturesMoreMatch() {
+ public void testCheckSignaturesMoreMatch() throws Exception {
int apk1 = APP1_CERT1;
int apk2 = APP2_CERT1_CERT2;
checkSignatures(apk1, apk2, PackageManager.SIGNATURE_NO_MATCH);
}
+
@LargeTest
- public void testCheckSignaturesUnknown() {
+ public void testCheckSignaturesUnknown() throws Exception {
int apk1 = APP1_CERT1_CERT2;
int apk2 = APP2_CERT1_CERT2;
String apk1Name = "install1.apk";
@@ -2930,8 +3128,9 @@ public class PackageManagerTests extends AndroidTestCase {
}
}
}
+
@LargeTest
- public void testInstallNoCertificates() {
+ public void testInstallNoCertificates() throws Exception {
int apk1 = APP1_UNSIGNED;
String apk1Name = "install1.apk";
InstallParams ip1 = null;
@@ -2943,18 +3142,29 @@ public class PackageManagerTests extends AndroidTestCase {
} finally {
}
}
- /* The following tests are related to apps using shared uids signed
- * with different certs.
+
+ /*
+ * The following tests are related to apps using shared uids signed with
+ * different certs.
*/
private int SHARED1_UNSIGNED = R.raw.install_shared1_unsigned;
+
private int SHARED1_CERT1 = R.raw.install_shared1_cert1;
+
private int SHARED1_CERT2 = R.raw.install_shared1_cert2;
+
private int SHARED1_CERT1_CERT2 = R.raw.install_shared1_cert1_cert2;
+
private int SHARED2_UNSIGNED = R.raw.install_shared2_unsigned;
+
private int SHARED2_CERT1 = R.raw.install_shared2_cert1;
+
private int SHARED2_CERT2 = R.raw.install_shared2_cert2;
+
private int SHARED2_CERT1_CERT2 = R.raw.install_shared2_cert1_cert2;
- private void checkSharedSignatures(int apk1, int apk2, boolean cleanUp, boolean fail, int retCode, int expMatchResult) {
+
+ private void checkSharedSignatures(int apk1, int apk2, boolean cleanUp, boolean fail,
+ int retCode, int expMatchResult) throws Exception {
String apk1Name = "install1.apk";
String apk2Name = "install2.apk";
PackageParser.Package pkg1 = getParsedPackage(apk1Name, apk1);
@@ -2964,16 +3174,16 @@ public class PackageManagerTests extends AndroidTestCase {
// Clean up before testing first.
cleanUpInstall(pkg1.packageName);
cleanUpInstall(pkg2.packageName);
- installFromRawResource(apk1Name, apk1, 0, false,
- false, -1, PackageInfo.INSTALL_LOCATION_UNSPECIFIED);
+ installFromRawResource(apk1Name, apk1, 0, false, false, -1,
+ PackageInfo.INSTALL_LOCATION_UNSPECIFIED);
if (fail) {
- installFromRawResource(apk2Name, apk2, 0, false,
- true, retCode, PackageInfo.INSTALL_LOCATION_UNSPECIFIED);
+ installFromRawResource(apk2Name, apk2, 0, false, true, retCode,
+ PackageInfo.INSTALL_LOCATION_UNSPECIFIED);
} else {
- installFromRawResource(apk2Name, apk2, 0, false,
- false, -1, PackageInfo.INSTALL_LOCATION_UNSPECIFIED);
- int match = mContext.getPackageManager().checkSignatures(
- pkg1.packageName, pkg2.packageName);
+ installFromRawResource(apk2Name, apk2, 0, false, false, -1,
+ PackageInfo.INSTALL_LOCATION_UNSPECIFIED);
+ int match = mContext.getPackageManager().checkSignatures(pkg1.packageName,
+ pkg2.packageName);
assertEquals(expMatchResult, match);
}
} finally {
@@ -2983,8 +3193,9 @@ public class PackageManagerTests extends AndroidTestCase {
}
}
}
+
@LargeTest
- public void testCheckSignaturesSharedAllMatch() {
+ public void testCheckSignaturesSharedAllMatch() throws Exception {
int apk1 = SHARED1_CERT1_CERT2;
int apk2 = SHARED2_CERT1_CERT2;
boolean fail = false;
@@ -2992,8 +3203,9 @@ public class PackageManagerTests extends AndroidTestCase {
int expMatchResult = PackageManager.SIGNATURE_MATCH;
checkSharedSignatures(apk1, apk2, true, fail, retCode, expMatchResult);
}
+
@LargeTest
- public void testCheckSignaturesSharedNoMatch() {
+ public void testCheckSignaturesSharedNoMatch() throws Exception {
int apk1 = SHARED1_CERT1;
int apk2 = SHARED2_CERT2;
boolean fail = true;
@@ -3001,11 +3213,13 @@ public class PackageManagerTests extends AndroidTestCase {
int expMatchResult = -1;
checkSharedSignatures(apk1, apk2, true, fail, retCode, expMatchResult);
}
+
/*
- * Test that an app signed with cert1 and cert2 cannot be replaced when signed with cert1 alone.
+ * Test that an app signed with cert1 and cert2 cannot be replaced when
+ * signed with cert1 alone.
*/
@LargeTest
- public void testCheckSignaturesSharedSomeMatch1() {
+ public void testCheckSignaturesSharedSomeMatch1() throws Exception {
int apk1 = SHARED1_CERT1_CERT2;
int apk2 = SHARED2_CERT1;
boolean fail = true;
@@ -3013,11 +3227,13 @@ public class PackageManagerTests extends AndroidTestCase {
int expMatchResult = -1;
checkSharedSignatures(apk1, apk2, true, fail, retCode, expMatchResult);
}
+
/*
- * Test that an app signed with cert1 and cert2 cannot be replaced when signed with cert2 alone.
+ * Test that an app signed with cert1 and cert2 cannot be replaced when
+ * signed with cert2 alone.
*/
@LargeTest
- public void testCheckSignaturesSharedSomeMatch2() {
+ public void testCheckSignaturesSharedSomeMatch2() throws Exception {
int apk1 = SHARED1_CERT1_CERT2;
int apk2 = SHARED2_CERT2;
boolean fail = true;
@@ -3025,8 +3241,9 @@ public class PackageManagerTests extends AndroidTestCase {
int expMatchResult = -1;
checkSharedSignatures(apk1, apk2, true, fail, retCode, expMatchResult);
}
+
@LargeTest
- public void testCheckSignaturesSharedUnknown() {
+ public void testCheckSignaturesSharedUnknown() throws Exception {
int apk1 = SHARED1_CERT1_CERT2;
int apk2 = SHARED2_CERT1_CERT2;
String apk1Name = "install1.apk";
@@ -3052,23 +3269,25 @@ public class PackageManagerTests extends AndroidTestCase {
}
@LargeTest
- public void testReplaceFirstSharedMatchAllCerts() {
+ public void testReplaceFirstSharedMatchAllCerts() throws Exception {
int apk1 = SHARED1_CERT1;
int apk2 = SHARED2_CERT1;
int rapk1 = SHARED1_CERT1;
checkSignatures(apk1, apk2, PackageManager.SIGNATURE_MATCH);
replaceCerts(apk1, rapk1, true, false, -1);
}
+
@LargeTest
- public void testReplaceSecondSharedMatchAllCerts() {
+ public void testReplaceSecondSharedMatchAllCerts() throws Exception {
int apk1 = SHARED1_CERT1;
int apk2 = SHARED2_CERT1;
int rapk2 = SHARED2_CERT1;
checkSignatures(apk1, apk2, PackageManager.SIGNATURE_MATCH);
replaceCerts(apk2, rapk2, true, false, -1);
}
+
@LargeTest
- public void testReplaceFirstSharedMatchSomeCerts() {
+ public void testReplaceFirstSharedMatchSomeCerts() throws Exception {
int apk1 = SHARED1_CERT1_CERT2;
int apk2 = SHARED2_CERT1_CERT2;
int rapk1 = SHARED1_CERT1;
@@ -3078,8 +3297,9 @@ public class PackageManagerTests extends AndroidTestCase {
installFromRawResource("install.apk", rapk1, PackageManager.INSTALL_REPLACE_EXISTING, true,
fail, retCode, PackageInfo.INSTALL_LOCATION_UNSPECIFIED);
}
+
@LargeTest
- public void testReplaceSecondSharedMatchSomeCerts() {
+ public void testReplaceSecondSharedMatchSomeCerts() throws Exception {
int apk1 = SHARED1_CERT1_CERT2;
int apk2 = SHARED2_CERT1_CERT2;
int rapk2 = SHARED2_CERT1;
@@ -3089,8 +3309,9 @@ public class PackageManagerTests extends AndroidTestCase {
installFromRawResource("install.apk", rapk2, PackageManager.INSTALL_REPLACE_EXISTING, true,
fail, retCode, PackageInfo.INSTALL_LOCATION_UNSPECIFIED);
}
+
@LargeTest
- public void testReplaceFirstSharedMatchNoCerts() {
+ public void testReplaceFirstSharedMatchNoCerts() throws Exception {
int apk1 = SHARED1_CERT1;
int apk2 = SHARED2_CERT1;
int rapk1 = SHARED1_CERT2;
@@ -3100,8 +3321,9 @@ public class PackageManagerTests extends AndroidTestCase {
installFromRawResource("install.apk", rapk1, PackageManager.INSTALL_REPLACE_EXISTING, true,
fail, retCode, PackageInfo.INSTALL_LOCATION_UNSPECIFIED);
}
+
@LargeTest
- public void testReplaceSecondSharedMatchNoCerts() {
+ public void testReplaceSecondSharedMatchNoCerts() throws Exception {
int apk1 = SHARED1_CERT1;
int apk2 = SHARED2_CERT1;
int rapk2 = SHARED2_CERT2;
@@ -3111,8 +3333,9 @@ public class PackageManagerTests extends AndroidTestCase {
installFromRawResource("install.apk", rapk2, PackageManager.INSTALL_REPLACE_EXISTING, true,
fail, retCode, PackageInfo.INSTALL_LOCATION_UNSPECIFIED);
}
+
@LargeTest
- public void testReplaceFirstSharedMatchMoreCerts() {
+ public void testReplaceFirstSharedMatchMoreCerts() throws Exception {
int apk1 = SHARED1_CERT1;
int apk2 = SHARED2_CERT1;
int rapk1 = SHARED1_CERT1_CERT2;
@@ -3122,8 +3345,9 @@ public class PackageManagerTests extends AndroidTestCase {
installFromRawResource("install.apk", rapk1, PackageManager.INSTALL_REPLACE_EXISTING, true,
fail, retCode, PackageInfo.INSTALL_LOCATION_UNSPECIFIED);
}
+
@LargeTest
- public void testReplaceSecondSharedMatchMoreCerts() {
+ public void testReplaceSecondSharedMatchMoreCerts() throws Exception {
int apk1 = SHARED1_CERT1;
int apk2 = SHARED2_CERT1;
int rapk2 = SHARED2_CERT1_CERT2;
@@ -3144,34 +3368,34 @@ public class PackageManagerTests extends AndroidTestCase {
* features.
*/
@LargeTest
- public void testUsesFeatureUnknownFeature() {
+ public void testUsesFeatureUnknownFeature() throws Exception {
int retCode = PackageManager.INSTALL_SUCCEEDED;
installFromRawResource("install.apk", R.raw.install_uses_feature, 0, true, false, retCode,
PackageInfo.INSTALL_LOCATION_UNSPECIFIED);
}
@LargeTest
- public void testInstallNonexistentFile() {
+ public void testInstallNonexistentFile() throws Exception {
int retCode = PackageManager.INSTALL_FAILED_INVALID_URI;
File invalidFile = new File("/nonexistent-file.apk");
invokeInstallPackageFail(Uri.fromFile(invalidFile), 0, retCode);
}
@SmallTest
- public void testGetVerifierDeviceIdentity() {
+ public void testGetVerifierDeviceIdentity() throws Exception {
PackageManager pm = getPm();
VerifierDeviceIdentity id = pm.getVerifierDeviceIdentity();
assertNotNull("Verifier device identity should not be null", id);
}
- public void testGetInstalledPackages() {
+ public void testGetInstalledPackages() throws Exception {
List<PackageInfo> packages = getPm().getInstalledPackages(0);
assertNotNull("installed packages cannot be null", packages);
assertTrue("installed packages cannot be empty", packages.size() > 0);
}
- public void testGetUnInstalledPackages() {
+ public void testGetUnInstalledPackages() throws Exception {
List<PackageInfo> packages = getPm().getInstalledPackages(
PackageManager.GET_UNINSTALLED_PACKAGES);
assertNotNull("installed packages cannot be null", packages);
@@ -3179,10 +3403,9 @@ public class PackageManagerTests extends AndroidTestCase {
}
/**
- * Test that getInstalledPackages returns all the data specified in
- * flags.
+ * Test that getInstalledPackages returns all the data specified in flags.
*/
- public void testGetInstalledPackagesAll() {
+ public void testGetInstalledPackagesAll() throws Exception {
int flags = PackageManager.GET_ACTIVITIES | PackageManager.GET_GIDS
| PackageManager.GET_CONFIGURATIONS | PackageManager.GET_INSTRUMENTATION
| PackageManager.GET_PERMISSIONS | PackageManager.GET_PROVIDERS
@@ -3218,7 +3441,7 @@ public class PackageManagerTests extends AndroidTestCase {
* Test that getInstalledPackages returns all the data specified in
* flags when the GET_UNINSTALLED_PACKAGES flag is set.
*/
- public void testGetUnInstalledPackagesAll() {
+ public void testGetUnInstalledPackagesAll() throws Exception {
int flags = PackageManager.GET_UNINSTALLED_PACKAGES
| PackageManager.GET_ACTIVITIES | PackageManager.GET_GIDS
| PackageManager.GET_CONFIGURATIONS | PackageManager.GET_INSTRUMENTATION
diff --git a/docs/downloads/training/BitmapFun.zip b/docs/downloads/training/BitmapFun.zip
index e7e71f9..e48bfd3 100644
--- a/docs/downloads/training/BitmapFun.zip
+++ b/docs/downloads/training/BitmapFun.zip
Binary files differ
diff --git a/docs/html/training/displaying-bitmaps/cache-bitmap.jd b/docs/html/training/displaying-bitmaps/cache-bitmap.jd
index 94abe21..2a333cc 100644
--- a/docs/html/training/displaying-bitmaps/cache-bitmap.jd
+++ b/docs/html/training/displaying-bitmaps/cache-bitmap.jd
@@ -96,7 +96,7 @@ and leave the rest of your app little memory to work with.</p>
<p>Here’s an example of setting up a {@link android.util.LruCache} for bitmaps:</p>
<pre>
-private LruCache<String, Bitmap> mMemoryCache;
+private LruCache&lt;String, Bitmap&gt; mMemoryCache;
&#64;Override
protected void onCreate(Bundle savedInstanceState) {
@@ -109,7 +109,7 @@ protected void onCreate(Bundle savedInstanceState) {
// Use 1/8th of the available memory for this memory cache.
final int cacheSize = 1024 * 1024 * memClass / 8;
- mMemoryCache = new LruCache<String, Bitmap>(cacheSize) {
+ mMemoryCache = new LruCache&lt;String, Bitmap&gt;(cacheSize) {
&#64;Override
protected int sizeOf(String key, Bitmap bitmap) {
// The cache size will be measured in bytes rather than number of items.
@@ -159,7 +159,7 @@ public void loadBitmap(int resId, ImageView imageView) {
updated to add entries to the memory cache:</p>
<pre>
-class BitmapWorkerTask extends AsyncTask<Integer, Void, Bitmap> {
+class BitmapWorkerTask extends AsyncTask&lt;Integer, Void, Bitmap&gt; {
...
// Decode image in background.
&#64;Override
@@ -179,7 +179,7 @@ class BitmapWorkerTask extends AsyncTask<Integer, Void, Bitmap> {
rely on images being available in this cache. Components like {@link android.widget.GridView} with
larger datasets can easily fill up a memory cache. Your application could be interrupted by another
task like a phone call, and while in the background it might be killed and the memory cache
-destroyed. Once the user resumes, your application it has to process each image again.</p>
+destroyed. Once the user resumes, your application has to process each image again.</p>
<p>A disk cache can be used in these cases to persist processed bitmaps and help decrease loading
times where images are no longer available in a memory cache. Of course, fetching images from disk
@@ -190,18 +190,14 @@ be unpredictable.</p>
appropriate place to store cached images if they are accessed more frequently, for example in an
image gallery application.</p>
-<p>Included in the sample code of this class is a basic {@code DiskLruCache} implementation.
-However, a more robust and recommended {@code DiskLruCache} solution is included in the Android 4.0
-source code ({@code libcore/luni/src/main/java/libcore/io/DiskLruCache.java}). Back-porting this
-class for use on previous Android releases should be fairly straightforward (a <a
-href="http://www.google.com/search?q=disklrucache">quick search</a> shows others who have already
-implemented this solution).</p>
-
-<p>Here’s updated example code that uses the simple {@code DiskLruCache} included in the sample
-application of this class:</p>
+<p>The sample code of this class uses a {@code DiskLruCache} implementation that is pulled from the
+<a href="https://android.googlesource.com/platform/libcore/+/master/luni/src/main/java/libcore/io/DiskLruCache.java">Android source</a>. Here’s updated example code that adds a disk cache in addition
+to the existing memory cache:</p>
<pre>
-private DiskLruCache mDiskCache;
+private DiskLruCache mDiskLruCache;
+private final Object mDiskCacheLock = new Object();
+private boolean mDiskCacheStarting = true;
private static final int DISK_CACHE_SIZE = 1024 * 1024 * 10; // 10MB
private static final String DISK_CACHE_SUBDIR = "thumbnails";
@@ -210,12 +206,26 @@ protected void onCreate(Bundle savedInstanceState) {
...
// Initialize memory cache
...
- File cacheDir = getCacheDir(this, DISK_CACHE_SUBDIR);
- mDiskCache = DiskLruCache.openCache(this, cacheDir, DISK_CACHE_SIZE);
+ // Initialize disk cache on background thread
+ File cacheDir = getDiskCacheDir(this, DISK_CACHE_SUBDIR);
+ new InitDiskCacheTask().execute(cacheDir);
...
}
-class BitmapWorkerTask extends AsyncTask<Integer, Void, Bitmap> {
+class InitDiskCacheTask extends AsyncTask&lt;File, Void, Void&gt; {
+ &#64;Override
+ protected Void doInBackground(File... params) {
+ synchronized (mDiskCacheLock) {
+ File cacheDir = params[0];
+ mDiskLruCache = DiskLruCache.open(cacheDir, DISK_CACHE_SIZE);
+ mDiskCacheStarting = false; // Finished initialization
+ mDiskCacheLock.notifyAll(); // Wake any waiting threads
+ }
+ return null;
+ }
+}
+
+class BitmapWorkerTask extends AsyncTask&lt;Integer, Void, Bitmap&gt; {
...
// Decode image in background.
&#64;Override
@@ -232,7 +242,7 @@ class BitmapWorkerTask extends AsyncTask<Integer, Void, Bitmap> {
}
// Add final bitmap to caches
- addBitmapToCache(String.valueOf(imageKey, bitmap);
+ addBitmapToCache(imageKey, bitmap);
return bitmap;
}
@@ -246,28 +256,48 @@ public void addBitmapToCache(String key, Bitmap bitmap) {
}
// Also add to disk cache
- if (!mDiskCache.containsKey(key)) {
- mDiskCache.put(key, bitmap);
+ synchronized (mDiskCacheLock) {
+ if (mDiskLruCache != null && mDiskLruCache.get(key) == null) {
+ mDiskLruCache.put(key, bitmap);
+ }
}
}
public Bitmap getBitmapFromDiskCache(String key) {
- return mDiskCache.get(key);
+ synchronized (mDiskCacheLock) {
+ // Wait while disk cache is started from background thread
+ while (mDiskCacheStarting) {
+ try {
+ mDiskCacheLock.wait();
+ } catch (InterruptedException e) {}
+ }
+ if (mDiskLruCache != null) {
+ return mDiskLruCache.get(key);
+ }
+ }
+ return null;
}
// Creates a unique subdirectory of the designated app cache directory. Tries to use external
// but if not mounted, falls back on internal storage.
-public static File getCacheDir(Context context, String uniqueName) {
+public static File getDiskCacheDir(Context context, String uniqueName) {
// Check if media is mounted or storage is built-in, if so, try and use external cache dir
// otherwise use internal cache dir
- final String cachePath = Environment.getExternalStorageState() == Environment.MEDIA_MOUNTED
- || !Environment.isExternalStorageRemovable() ?
- context.getExternalCacheDir().getPath() : context.getCacheDir().getPath();
+ final String cachePath =
+ Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState()) ||
+ !isExternalStorageRemovable() ? getExternalCacheDir(context).getPath() :
+ context.getCacheDir().getPath();
return new File(cachePath + File.separator + uniqueName);
}
</pre>
+<p class="note"><strong>Note:</strong> Even initializing the disk cache requires disk operations
+and therefore should not take place on the main thread. However, this does mean there's a chance
+the cache is accessed before initialization. To address this, in the above implementation, a lock
+object ensures that the app does not read from the disk cache until the cache has been
+initialized.</p>
+
<p>While the memory cache is checked in the UI thread, the disk cache is checked in the background
thread. Disk operations should never take place on the UI thread. When image processing is
complete, the final bitmap is added to both the memory and disk cache for future use.</p>
@@ -292,7 +322,7 @@ android.widget.ImageView} objects.</p>
changes using a {@link android.app.Fragment}:</p>
<pre>
-private LruCache<String, Bitmap> mMemoryCache;
+private LruCache&lt;String, Bitmap&gt; mMemoryCache;
&#64;Override
protected void onCreate(Bundle savedInstanceState) {
@@ -301,7 +331,7 @@ protected void onCreate(Bundle savedInstanceState) {
RetainFragment.findOrCreateRetainFragment(getFragmentManager());
mMemoryCache = RetainFragment.mRetainedCache;
if (mMemoryCache == null) {
- mMemoryCache = new LruCache<String, Bitmap>(cacheSize) {
+ mMemoryCache = new LruCache&lt;String, Bitmap&gt;(cacheSize) {
... // Initialize cache here as usual
}
mRetainFragment.mRetainedCache = mMemoryCache;
@@ -311,7 +341,7 @@ protected void onCreate(Bundle savedInstanceState) {
class RetainFragment extends Fragment {
private static final String TAG = "RetainFragment";
- public LruCache<String, Bitmap> mRetainedCache;
+ public LruCache&lt;String, Bitmap&gt; mRetainedCache;
public RetainFragment() {}
diff --git a/docs/html/training/displaying-bitmaps/display-bitmap.jd b/docs/html/training/displaying-bitmaps/display-bitmap.jd
index 5eac04c..4572c42 100644
--- a/docs/html/training/displaying-bitmaps/display-bitmap.jd
+++ b/docs/html/training/displaying-bitmaps/display-bitmap.jd
@@ -103,7 +103,8 @@ public class ImageDetailActivity extends FragmentActivity {
}
</pre>
-<p>The details {@link android.app.Fragment} holds the {@link android.widget.ImageView} children:</p>
+<p>Here is an implementation of the details {@link android.app.Fragment} which holds the {@link android.widget.ImageView} children. This might seem like a perfectly reasonable approach, but can
+you see the drawbacks of this implementation? How could it be improved?</p>
<pre>
public class ImageDetailFragment extends Fragment {
@@ -146,11 +147,11 @@ public class ImageDetailFragment extends Fragment {
}
</pre>
-<p>Hopefully you noticed the issue with this implementation; The images are being read from
-resources on the UI thread which can lead to an application hanging and being force closed. Using an
-{@link android.os.AsyncTask} as described in the <a href="process-bitmap.html">Processing Bitmaps Off
-the UI Thread</a> lesson, it’s straightforward to move image loading and processing to a background
-thread:</p>
+<p>Hopefully you noticed the issue: the images are being read from resources on the UI thread,
+which can lead to an application hanging and being force closed. Using an
+{@link android.os.AsyncTask} as described in the <a href="process-bitmap.html">Processing Bitmaps
+Off the UI Thread</a> lesson, it’s straightforward to move image loading and processing to a
+background thread:</p>
<pre>
public class ImageDetailActivity extends FragmentActivity {
@@ -190,7 +191,7 @@ modifications for a memory cache:</p>
<pre>
public class ImageDetailActivity extends FragmentActivity {
...
- private LruCache<String, Bitmap> mMemoryCache;
+ private LruCache&lt;String, Bitmap&gt; mMemoryCache;
&#64;Override
public void onCreate(Bundle savedInstanceState) {
@@ -229,7 +230,8 @@ UI remains fluid, memory usage remains under control and concurrency is handled
the way {@link android.widget.GridView} recycles its children views).</p>
<p>To start with, here is a standard {@link android.widget.GridView} implementation with {@link
-android.widget.ImageView} children placed inside a {@link android.app.Fragment}:</p>
+android.widget.ImageView} children placed inside a {@link android.app.Fragment}. Again, this might
+seem like a perfectly reasonable approach, but what would make it better?</p>
<pre>
public class ImageGridFragment extends Fragment implements AdapterView.OnItemClickListener {
@@ -261,7 +263,7 @@ public class ImageGridFragment extends Fragment implements AdapterView.OnItemCli
}
&#64;Override
- public void onItemClick(AdapterView<?> parent, View v, int position, long id) {
+ public void onItemClick(AdapterView&lt;?&gt; parent, View v, int position, long id) {
final Intent i = new Intent(getActivity(), ImageDetailActivity.class);
i.putExtra(ImageDetailActivity.EXTRA_IMAGE, position);
startActivity(i);
@@ -345,13 +347,13 @@ public class ImageGridFragment extends Fragment implements AdapterView.OnItemCli
}
static class AsyncDrawable extends BitmapDrawable {
- private final WeakReference<BitmapWorkerTask> bitmapWorkerTaskReference;
+ private final WeakReference&lt;BitmapWorkerTask&gt; bitmapWorkerTaskReference;
public AsyncDrawable(Resources res, Bitmap bitmap,
BitmapWorkerTask bitmapWorkerTask) {
super(res, bitmap);
bitmapWorkerTaskReference =
- new WeakReference<BitmapWorkerTask>(bitmapWorkerTask);
+ new WeakReference&lt;BitmapWorkerTask&gt;(bitmapWorkerTask);
}
public BitmapWorkerTask getBitmapWorkerTask() {
diff --git a/docs/html/training/displaying-bitmaps/index.jd b/docs/html/training/displaying-bitmaps/index.jd
index 78371ad..b91172b 100644
--- a/docs/html/training/displaying-bitmaps/index.jd
+++ b/docs/html/training/displaying-bitmaps/index.jd
@@ -43,8 +43,8 @@ exception:<br />{@code java.lang.OutofMemoryError: bitmap size exceeds VM budget
perform under this minimum memory limit. However, keep in mind many devices are configured with
higher limits.</li>
<li>Bitmaps take up a lot of memory, especially for rich images like photographs. For example, the
- camera on the <a href="http://www.google.com/nexus/">Galaxy Nexus</a> takes photos up to 2592x1936
- pixels (5 megapixels). If the bitmap configuration used is {@link
+ camera on the <a href="http://www.android.com/devices/detail/galaxy-nexus">Galaxy Nexus</a> takes
+ photos up to 2592x1936 pixels (5 megapixels). If the bitmap configuration used is {@link
android.graphics.Bitmap.Config ARGB_8888} (the default from the Android 2.3 onward) then loading
this image into memory takes about 19MB of memory (2592*1936*4 bytes), immediately exhausting the
per-app limit on some devices.</li>
@@ -75,4 +75,4 @@ exception:<br />{@code java.lang.OutofMemoryError: bitmap size exceeds VM budget
components like {@link android.support.v4.view.ViewPager} and {@link android.widget.GridView}
using a background thread and bitmap cache.</dd>
-</dl> \ No newline at end of file
+</dl>
diff --git a/docs/html/training/displaying-bitmaps/process-bitmap.jd b/docs/html/training/displaying-bitmaps/process-bitmap.jd
index d1e346c..d4fcff3 100644
--- a/docs/html/training/displaying-bitmaps/process-bitmap.jd
+++ b/docs/html/training/displaying-bitmaps/process-bitmap.jd
@@ -62,13 +62,13 @@ decodeSampledBitmapFromResource()}</a>: </p>
<a name="BitmapWorkerTask"></a>
<pre>
-class BitmapWorkerTask extends AsyncTask<Integer, Void, Bitmap> {
- private final WeakReference<ImageView> imageViewReference;
+class BitmapWorkerTask extends AsyncTask&lt;Integer, Void, Bitmap&gt; {
+ private final WeakReference&lt;ImageView&gt; imageViewReference;
private int data = 0;
public BitmapWorkerTask(ImageView imageView) {
// Use a WeakReference to ensure the ImageView can be garbage collected
- imageViewReference = new WeakReference<ImageView>(imageView);
+ imageViewReference = new WeakReference&lt;ImageView&gt;(imageView);
}
// Decode image in background.
@@ -133,13 +133,13 @@ completes:</p>
<a name="AsyncDrawable"></a>
<pre>
static class AsyncDrawable extends BitmapDrawable {
- private final WeakReference<BitmapWorkerTask> bitmapWorkerTaskReference;
+ private final WeakReference&lt;BitmapWorkerTask&gt; bitmapWorkerTaskReference;
public AsyncDrawable(Resources res, Bitmap bitmap,
BitmapWorkerTask bitmapWorkerTask) {
super(res, bitmap);
bitmapWorkerTaskReference =
- new WeakReference<BitmapWorkerTask>(bitmapWorkerTask);
+ new WeakReference&lt;BitmapWorkerTask&gt;(bitmapWorkerTask);
}
public BitmapWorkerTask getBitmapWorkerTask() {
@@ -211,7 +211,7 @@ one associated with the {@link android.widget.ImageView}:</p>
<a name="BitmapWorkerTaskUpdated"></a>
<pre>
-class BitmapWorkerTask extends AsyncTask<Integer, Void, Bitmap> {
+class BitmapWorkerTask extends AsyncTask&lt;Integer, Void, Bitmap&gt; {
...
&#64;Override
@@ -236,4 +236,4 @@ class BitmapWorkerTask extends AsyncTask<Integer, Void, Bitmap> {
android.widget.GridView} components as well as any other components that recycle their child
views. Simply call {@code loadBitmap} where you normally set an image to your {@link
android.widget.ImageView}. For example, in a {@link android.widget.GridView} implementation this
-would be in the {@link android.widget.Adapter#getView getView()} method of the backing adapter.</p> \ No newline at end of file
+would be in the {@link android.widget.Adapter#getView getView()} method of the backing adapter.</p>
diff --git a/graphics/java/android/graphics/drawable/ShapeDrawable.java b/graphics/java/android/graphics/drawable/ShapeDrawable.java
index a3622a2..2ec1293 100644
--- a/graphics/java/android/graphics/drawable/ShapeDrawable.java
+++ b/graphics/java/android/graphics/drawable/ShapeDrawable.java
@@ -373,8 +373,16 @@ public class ShapeDrawable extends Drawable {
@Override
public Drawable mutate() {
if (!mMutated && super.mutate() == this) {
- mShapeState.mPaint = new Paint(mShapeState.mPaint);
- mShapeState.mPadding = new Rect(mShapeState.mPadding);
+ if (mShapeState.mPaint != null) {
+ mShapeState.mPaint = new Paint(mShapeState.mPaint);
+ } else {
+ mShapeState.mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
+ }
+ if (mShapeState.mPadding != null) {
+ mShapeState.mPadding = new Rect(mShapeState.mPadding);
+ } else {
+ mShapeState.mPadding = new Rect();
+ }
try {
mShapeState.mShape = mShapeState.mShape.clone();
} catch (CloneNotSupportedException e) {
diff --git a/graphics/java/android/renderscript/Matrix4f.java b/graphics/java/android/renderscript/Matrix4f.java
index a85d464..4600424 100644
--- a/graphics/java/android/renderscript/Matrix4f.java
+++ b/graphics/java/android/renderscript/Matrix4f.java
@@ -113,6 +113,34 @@ public class Matrix4f {
}
/**
+ * Sets the values of the matrix to those of the parameter
+ *
+ * @param src matrix to load the values from
+ * @hide
+ */
+ public void load(Matrix3f src) {
+ mMat[0] = src.mMat[0];
+ mMat[1] = src.mMat[1];
+ mMat[2] = src.mMat[2];
+ mMat[3] = 0;
+
+ mMat[4] = src.mMat[3];
+ mMat[5] = src.mMat[4];
+ mMat[6] = src.mMat[5];
+ mMat[7] = 0;
+
+ mMat[8] = src.mMat[6];
+ mMat[9] = src.mMat[7];
+ mMat[10] = src.mMat[8];
+ mMat[11] = 0;
+
+ mMat[12] = 0;
+ mMat[13] = 0;
+ mMat[14] = 0;
+ mMat[15] = 1;
+ }
+
+ /**
* Sets current values to be a rotation matrix of certain angle
* about a given axis
*
diff --git a/graphics/java/android/renderscript/ScriptIntrinsicColorMatrix.java b/graphics/java/android/renderscript/ScriptIntrinsicColorMatrix.java
index 41e7e00..8cac28e 100644
--- a/graphics/java/android/renderscript/ScriptIntrinsicColorMatrix.java
+++ b/graphics/java/android/renderscript/ScriptIntrinsicColorMatrix.java
@@ -39,8 +39,7 @@ public class ScriptIntrinsicColorMatrix extends ScriptIntrinsic {
}
/**
- * Supported elements types are float, float4, uchar, uchar4
- *
+ * Supported elements types are uchar4
*
* @param rs
* @param e
@@ -53,13 +52,98 @@ public class ScriptIntrinsicColorMatrix extends ScriptIntrinsic {
}
- public void setColorMatrix(Matrix4f m) {
- mMatrix.load(m);
+ private void setMatrix() {
FieldPacker fp = new FieldPacker(16*4);
- fp.addMatrix(m);
+ fp.addMatrix(mMatrix);
setVar(0, fp);
}
+ /**
+ * Set the color matrix which will be applied to each cell of the image.
+ *
+ * @param m The 4x4 matrix to set.
+ */
+ public void setColorMatrix(Matrix4f m) {
+ mMatrix.load(m);
+ setMatrix();
+ }
+
+ /**
+ * Set the color matrix which will be applied to each cell of the image.
+ * This will set the alpha channel to be a copy.
+ *
+ * @param m The 3x3 matrix to set.
+ */
+ public void setColorMatrix(Matrix3f m) {
+ mMatrix.load(m);
+ setMatrix();
+ }
+
+ /**
+ * Set a color matrix to convert from RGB to luminance. The alpha channel
+ * will be a copy.
+ *
+ */
+ public void setGreyscale() {
+ mMatrix.loadIdentity();
+ mMatrix.set(0, 0, 0.299f);
+ mMatrix.set(1, 0, 0.587f);
+ mMatrix.set(2, 0, 0.114f);
+ mMatrix.set(0, 1, 0.299f);
+ mMatrix.set(1, 1, 0.587f);
+ mMatrix.set(2, 1, 0.114f);
+ mMatrix.set(0, 2, 0.299f);
+ mMatrix.set(1, 2, 0.587f);
+ mMatrix.set(2, 2, 0.114f);
+ setMatrix();
+ }
+
+ /**
+ * Set the matrix to convert from YUV to RGB with a direct copy of the 4th
+ * channel.
+ *
+ */
+ public void setYUVtoRGB() {
+ mMatrix.loadIdentity();
+ mMatrix.set(0, 0, 1.f);
+ mMatrix.set(1, 0, 0.f);
+ mMatrix.set(2, 0, 1.13983f);
+ mMatrix.set(0, 1, 1.f);
+ mMatrix.set(1, 1, -0.39465f);
+ mMatrix.set(2, 1, -0.5806f);
+ mMatrix.set(0, 2, 1.f);
+ mMatrix.set(1, 2, 2.03211f);
+ mMatrix.set(2, 2, 0.f);
+ setMatrix();
+ }
+
+ /**
+ * Set the matrix to convert from RGB to YUV with a direct copy of the 4th
+ * channel.
+ *
+ */
+ public void setRGBtoYUV() {
+ mMatrix.loadIdentity();
+ mMatrix.set(0, 0, 0.299f);
+ mMatrix.set(1, 0, 0.587f);
+ mMatrix.set(2, 0, 0.114f);
+ mMatrix.set(0, 1, -0.14713f);
+ mMatrix.set(1, 1, -0.28886f);
+ mMatrix.set(2, 1, 0.436f);
+ mMatrix.set(0, 2, 0.615f);
+ mMatrix.set(1, 2, -0.51499f);
+ mMatrix.set(2, 2, -0.10001f);
+ setMatrix();
+ }
+
+
+ /**
+ * Invoke the kernel and apply the matrix to each cell of ain and copy to
+ * aout.
+ *
+ * @param ain Input allocation
+ * @param aout Output allocation
+ */
public void forEach(Allocation ain, Allocation aout) {
forEach(0, ain, aout, null);
}
diff --git a/graphics/java/android/renderscript/ScriptIntrinsicYuvToRGB.java b/graphics/java/android/renderscript/ScriptIntrinsicYuvToRGB.java
index ee5f938..b4a228b 100644
--- a/graphics/java/android/renderscript/ScriptIntrinsicYuvToRGB.java
+++ b/graphics/java/android/renderscript/ScriptIntrinsicYuvToRGB.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2008 The Android Open Source Project
+ * Copyright (C) 2012 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/include/android_runtime/android_view_Surface.h b/include/android_runtime/android_view_Surface.h
index e50186d..df0fe72 100644
--- a/include/android_runtime/android_view_Surface.h
+++ b/include/android_runtime/android_view_Surface.h
@@ -24,6 +24,7 @@
namespace android {
class Surface;
+class ISurfaceTexture;
/* Gets the underlying ANativeWindow for a Surface. */
extern sp<ANativeWindow> android_view_Surface_getNativeWindow(
@@ -35,6 +36,10 @@ extern bool android_view_Surface_isInstanceOf(JNIEnv* env, jobject obj);
/* Gets the underlying Surface from a Surface Java object. */
extern sp<Surface> android_view_Surface_getSurface(JNIEnv* env, jobject surfaceObj);
+/* Creates a Surface from an ISurfaceTexture. */
+extern jobject android_view_Surface_createFromISurfaceTexture(JNIEnv* env,
+ const sp<ISurfaceTexture>& surfaceTexture);
+
} // namespace android
#endif // _ANDROID_VIEW_SURFACE_H
diff --git a/libs/hwui/Android.mk b/libs/hwui/Android.mk
index c0f79df..e032ae4 100644
--- a/libs/hwui/Android.mk
+++ b/libs/hwui/Android.mk
@@ -16,6 +16,7 @@ ifeq ($(USE_OPENGL_RENDERER),true)
Dither.cpp \
FboCache.cpp \
GradientCache.cpp \
+ Layer.cpp \
LayerCache.cpp \
LayerRenderer.cpp \
Matrix.cpp \
diff --git a/libs/hwui/DisplayListRenderer.cpp b/libs/hwui/DisplayListRenderer.cpp
index 2de70d4..755170f 100644
--- a/libs/hwui/DisplayListRenderer.cpp
+++ b/libs/hwui/DisplayListRenderer.cpp
@@ -149,6 +149,7 @@ void DisplayList::clearResources() {
delete mTransformMatrix3D;
delete mStaticMatrix;
delete mAnimationMatrix;
+
mTransformMatrix = NULL;
mTransformCamera = NULL;
mTransformMatrix3D = NULL;
@@ -156,50 +157,54 @@ void DisplayList::clearResources() {
mAnimationMatrix = NULL;
Caches& caches = Caches::getInstance();
+ caches.resourceCache.lock();
for (size_t i = 0; i < mBitmapResources.size(); i++) {
- caches.resourceCache.decrementRefcount(mBitmapResources.itemAt(i));
+ caches.resourceCache.decrementRefcountLocked(mBitmapResources.itemAt(i));
}
- mBitmapResources.clear();
for (size_t i = 0; i < mOwnedBitmapResources.size(); i++) {
SkBitmap* bitmap = mOwnedBitmapResources.itemAt(i);
- caches.resourceCache.decrementRefcount(bitmap);
- caches.resourceCache.destructor(bitmap);
+ caches.resourceCache.decrementRefcountLocked(bitmap);
+ caches.resourceCache.destructorLocked(bitmap);
}
- mOwnedBitmapResources.clear();
for (size_t i = 0; i < mFilterResources.size(); i++) {
- caches.resourceCache.decrementRefcount(mFilterResources.itemAt(i));
+ caches.resourceCache.decrementRefcountLocked(mFilterResources.itemAt(i));
}
- mFilterResources.clear();
for (size_t i = 0; i < mShaders.size(); i++) {
- caches.resourceCache.decrementRefcount(mShaders.itemAt(i));
- caches.resourceCache.destructor(mShaders.itemAt(i));
+ caches.resourceCache.decrementRefcountLocked(mShaders.itemAt(i));
+ caches.resourceCache.destructorLocked(mShaders.itemAt(i));
}
- mShaders.clear();
+
+ for (size_t i = 0; i < mSourcePaths.size(); i++) {
+ caches.resourceCache.decrementRefcountLocked(mSourcePaths.itemAt(i));
+ }
+
+ caches.resourceCache.unlock();
for (size_t i = 0; i < mPaints.size(); i++) {
delete mPaints.itemAt(i);
}
- mPaints.clear();
for (size_t i = 0; i < mPaths.size(); i++) {
SkPath* path = mPaths.itemAt(i);
caches.pathCache.remove(path);
delete path;
}
- mPaths.clear();
-
- for (size_t i = 0; i < mSourcePaths.size(); i++) {
- caches.resourceCache.decrementRefcount(mSourcePaths.itemAt(i));
- }
- mSourcePaths.clear();
for (size_t i = 0; i < mMatrices.size(); i++) {
delete mMatrices.itemAt(i);
}
+
+ mBitmapResources.clear();
+ mOwnedBitmapResources.clear();
+ mFilterResources.clear();
+ mShaders.clear();
+ mSourcePaths.clear();
+ mPaints.clear();
+ mPaths.clear();
mMatrices.clear();
}
@@ -223,35 +228,44 @@ void DisplayList::initFromDisplayListRenderer(const DisplayListRenderer& recorde
mReader.setMemory(buffer, mSize);
Caches& caches = Caches::getInstance();
+ caches.resourceCache.lock();
const Vector<SkBitmap*>& bitmapResources = recorder.getBitmapResources();
for (size_t i = 0; i < bitmapResources.size(); i++) {
SkBitmap* resource = bitmapResources.itemAt(i);
mBitmapResources.add(resource);
- caches.resourceCache.incrementRefcount(resource);
+ caches.resourceCache.incrementRefcountLocked(resource);
}
const Vector<SkBitmap*> &ownedBitmapResources = recorder.getOwnedBitmapResources();
for (size_t i = 0; i < ownedBitmapResources.size(); i++) {
SkBitmap* resource = ownedBitmapResources.itemAt(i);
mOwnedBitmapResources.add(resource);
- caches.resourceCache.incrementRefcount(resource);
+ caches.resourceCache.incrementRefcountLocked(resource);
}
const Vector<SkiaColorFilter*>& filterResources = recorder.getFilterResources();
for (size_t i = 0; i < filterResources.size(); i++) {
SkiaColorFilter* resource = filterResources.itemAt(i);
mFilterResources.add(resource);
- caches.resourceCache.incrementRefcount(resource);
+ caches.resourceCache.incrementRefcountLocked(resource);
}
const Vector<SkiaShader*>& shaders = recorder.getShaders();
for (size_t i = 0; i < shaders.size(); i++) {
SkiaShader* resource = shaders.itemAt(i);
mShaders.add(resource);
- caches.resourceCache.incrementRefcount(resource);
+ caches.resourceCache.incrementRefcountLocked(resource);
}
+ const SortedVector<SkPath*>& sourcePaths = recorder.getSourcePaths();
+ for (size_t i = 0; i < sourcePaths.size(); i++) {
+ mSourcePaths.add(sourcePaths.itemAt(i));
+ caches.resourceCache.incrementRefcountLocked(sourcePaths.itemAt(i));
+ }
+
+ caches.resourceCache.unlock();
+
const Vector<SkPaint*>& paints = recorder.getPaints();
for (size_t i = 0; i < paints.size(); i++) {
mPaints.add(paints.itemAt(i));
@@ -262,12 +276,6 @@ void DisplayList::initFromDisplayListRenderer(const DisplayListRenderer& recorde
mPaths.add(paths.itemAt(i));
}
- const SortedVector<SkPath*>& sourcePaths = recorder.getSourcePaths();
- for (size_t i = 0; i < sourcePaths.size(); i++) {
- mSourcePaths.add(sourcePaths.itemAt(i));
- caches.resourceCache.incrementRefcount(sourcePaths.itemAt(i));
- }
-
const Vector<SkMatrix*>& matrices = recorder.getMatrices();
for (size_t i = 0; i < matrices.size(); i++) {
mMatrices.add(matrices.itemAt(i));
@@ -1004,29 +1012,39 @@ status_t DisplayList::replay(OpenGLRenderer& renderer, Rect& dirty, int32_t flag
}
break;
case DrawLayer: {
+ int oldAlpha = -1;
Layer* layer = (Layer*) getInt();
float x = getFloat();
float y = getFloat();
SkPaint* paint = getPaint(renderer);
- if (mCaching) {
- paint->setAlpha(mMultipliedAlpha);
+ if (mCaching && mMultipliedAlpha < 255) {
+ oldAlpha = layer->getAlpha();
+ layer->setAlpha(mMultipliedAlpha);
}
DISPLAY_LIST_LOGD("%s%s %p, %.2f, %.2f, %p", (char*) indent, OP_NAMES[op],
layer, x, y, paint);
drawGlStatus |= renderer.drawLayer(layer, x, y, paint);
+ if (oldAlpha >= 0) {
+ layer->setAlpha(oldAlpha);
+ }
}
break;
case DrawBitmap: {
+ int oldAlpha = -1;
SkBitmap* bitmap = getBitmap();
float x = getFloat();
float y = getFloat();
SkPaint* paint = getPaint(renderer);
- if (mCaching) {
+ if (mCaching && mMultipliedAlpha < 255) {
+ oldAlpha = paint->getAlpha();
paint->setAlpha(mMultipliedAlpha);
}
DISPLAY_LIST_LOGD("%s%s %p, %.2f, %.2f, %p", (char*) indent, OP_NAMES[op],
bitmap, x, y, paint);
drawGlStatus |= renderer.drawBitmap(bitmap, x, y, paint);
+ if (oldAlpha >= 0) {
+ paint->setAlpha(oldAlpha);
+ }
}
break;
case DrawBitmapMatrix: {
@@ -1309,7 +1327,8 @@ status_t DisplayList::replay(OpenGLRenderer& renderer, Rect& dirty, int32_t flag
// Base structure
///////////////////////////////////////////////////////////////////////////////
-DisplayListRenderer::DisplayListRenderer() : mWriter(MIN_WRITER_SIZE),
+DisplayListRenderer::DisplayListRenderer():
+ mCaches(Caches::getInstance()), mWriter(MIN_WRITER_SIZE),
mTranslateX(0.0f), mTranslateY(0.0f), mHasTranslate(false), mHasDrawOps(false) {
}
@@ -1320,34 +1339,38 @@ DisplayListRenderer::~DisplayListRenderer() {
void DisplayListRenderer::reset() {
mWriter.reset();
- Caches& caches = Caches::getInstance();
+ mCaches.resourceCache.lock();
+
for (size_t i = 0; i < mBitmapResources.size(); i++) {
- caches.resourceCache.decrementRefcount(mBitmapResources.itemAt(i));
+ mCaches.resourceCache.decrementRefcountLocked(mBitmapResources.itemAt(i));
}
- mBitmapResources.clear();
for (size_t i = 0; i < mOwnedBitmapResources.size(); i++) {
- SkBitmap* bitmap = mOwnedBitmapResources.itemAt(i);
- caches.resourceCache.decrementRefcount(bitmap);
+ mCaches.resourceCache.decrementRefcountLocked(mOwnedBitmapResources.itemAt(i));
}
- mOwnedBitmapResources.clear();
for (size_t i = 0; i < mFilterResources.size(); i++) {
- caches.resourceCache.decrementRefcount(mFilterResources.itemAt(i));
+ mCaches.resourceCache.decrementRefcountLocked(mFilterResources.itemAt(i));
}
- mFilterResources.clear();
for (size_t i = 0; i < mShaders.size(); i++) {
- caches.resourceCache.decrementRefcount(mShaders.itemAt(i));
+ mCaches.resourceCache.decrementRefcountLocked(mShaders.itemAt(i));
}
- mShaders.clear();
- mShaderMap.clear();
for (size_t i = 0; i < mSourcePaths.size(); i++) {
- caches.resourceCache.decrementRefcount(mSourcePaths.itemAt(i));
+ mCaches.resourceCache.decrementRefcountLocked(mSourcePaths.itemAt(i));
}
+
+ mCaches.resourceCache.unlock();
+
+ mBitmapResources.clear();
+ mOwnedBitmapResources.clear();
+ mFilterResources.clear();
mSourcePaths.clear();
+ mShaders.clear();
+ mShaderMap.clear();
+
mPaints.clear();
mPaintMap.clear();
diff --git a/libs/hwui/DisplayListRenderer.h b/libs/hwui/DisplayListRenderer.h
index c8b3e47..8e4f2d3 100644
--- a/libs/hwui/DisplayListRenderer.h
+++ b/libs/hwui/DisplayListRenderer.h
@@ -763,7 +763,7 @@ private:
mPaths.add(pathCopy);
}
if (mSourcePaths.indexOf(path) < 0) {
- Caches::getInstance().resourceCache.incrementRefcount(path);
+ mCaches.resourceCache.incrementRefcount(path);
mSourcePaths.add(path);
}
@@ -811,13 +811,13 @@ private:
// which doesn't seem worth the extra cycles for this unlikely case.
addInt((int) bitmap);
mBitmapResources.add(bitmap);
- Caches::getInstance().resourceCache.incrementRefcount(bitmap);
+ mCaches.resourceCache.incrementRefcount(bitmap);
}
void addBitmapData(SkBitmap* bitmap) {
addInt((int) bitmap);
mOwnedBitmapResources.add(bitmap);
- Caches::getInstance().resourceCache.incrementRefcount(bitmap);
+ mCaches.resourceCache.incrementRefcount(bitmap);
}
inline void addShader(SkiaShader* shader) {
@@ -833,7 +833,7 @@ private:
// replaceValueFor() performs an add if the entry doesn't exist
mShaderMap.replaceValueFor(shader, shaderCopy);
mShaders.add(shaderCopy);
- Caches::getInstance().resourceCache.incrementRefcount(shaderCopy);
+ mCaches.resourceCache.incrementRefcount(shaderCopy);
}
addInt((int) shaderCopy);
@@ -842,7 +842,7 @@ private:
inline void addColorFilter(SkiaColorFilter* colorFilter) {
addInt((int) colorFilter);
mFilterResources.add(colorFilter);
- Caches::getInstance().resourceCache.incrementRefcount(colorFilter);
+ mCaches.resourceCache.incrementRefcount(colorFilter);
}
Vector<SkBitmap*> mBitmapResources;
@@ -862,15 +862,16 @@ private:
Vector<SkMatrix*> mMatrices;
- SkWriter32 mWriter;
uint32_t mBufferSize;
int mRestoreSaveCount;
+ Caches& mCaches;
+ SkWriter32 mWriter;
+
float mTranslateX;
float mTranslateY;
bool mHasTranslate;
-
bool mHasDrawOps;
friend class DisplayList;
diff --git a/libs/hwui/Layer.cpp b/libs/hwui/Layer.cpp
new file mode 100644
index 0000000..31e169b
--- /dev/null
+++ b/libs/hwui/Layer.cpp
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "OpenGLRenderer"
+
+#include <utils/Log.h>
+
+#include "Layer.h"
+#include "OpenGLRenderer.h"
+#include "Caches.h"
+
+namespace android {
+namespace uirenderer {
+
+Layer::~Layer() {
+ if (mesh) delete mesh;
+ if (meshIndices) delete meshIndices;
+ if (colorFilter) Caches::getInstance().resourceCache.decrementRefcount(colorFilter);
+}
+
+void Layer::setPaint(SkPaint* paint) {
+ OpenGLRenderer::getAlphaAndModeDirect(paint, &alpha, &mode);
+}
+
+void Layer::setColorFilter(SkiaColorFilter* filter) {
+ if (colorFilter) {
+ Caches::getInstance().resourceCache.decrementRefcount(colorFilter);
+ }
+ colorFilter = filter;
+ if (colorFilter) {
+ Caches::getInstance().resourceCache.incrementRefcount(colorFilter);
+ }
+}
+
+
+
+}; // namespace uirenderer
+}; // namespace android
diff --git a/libs/hwui/Layer.h b/libs/hwui/Layer.h
index f243177..76da671 100644
--- a/libs/hwui/Layer.h
+++ b/libs/hwui/Layer.h
@@ -45,6 +45,7 @@ class DisplayList;
* A layer has dimensions and is backed by an OpenGL texture or FBO.
*/
struct Layer {
+
Layer(const uint32_t layerWidth, const uint32_t layerHeight) {
mesh = NULL;
meshIndices = NULL;
@@ -60,10 +61,7 @@ struct Layer {
displayList = NULL;
}
- ~Layer() {
- if (mesh) delete mesh;
- if (meshIndices) delete meshIndices;
- }
+ ~Layer();
/**
* Sets this layer's region to a rectangle. Computes the appropriate
@@ -106,6 +104,8 @@ struct Layer {
texture.height = height;
}
+ ANDROID_API void setPaint(SkPaint* paint);
+
inline void setBlend(bool blend) {
texture.blend = blend;
}
@@ -191,9 +191,7 @@ struct Layer {
return colorFilter;
}
- inline void setColorFilter(SkiaColorFilter* filter) {
- colorFilter = filter;
- }
+ ANDROID_API void setColorFilter(SkiaColorFilter* filter);
inline void bindTexture() {
glBindTexture(renderTarget, texture.id);
diff --git a/libs/hwui/LayerRenderer.cpp b/libs/hwui/LayerRenderer.cpp
index f81640b..5a8f2b7 100644
--- a/libs/hwui/LayerRenderer.cpp
+++ b/libs/hwui/LayerRenderer.cpp
@@ -400,6 +400,8 @@ bool LayerRenderer::copyLayer(Layer* layer, SkBitmap* bitmap) {
caches.activeTexture(0);
glBindTexture(GL_TEXTURE_2D, texture);
+ glPixelStorei(GL_PACK_ALIGNMENT, bitmap->bytesPerPixel());
+
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
diff --git a/libs/hwui/OpenGLRenderer.cpp b/libs/hwui/OpenGLRenderer.cpp
index b66c898..9f8b87c 100644
--- a/libs/hwui/OpenGLRenderer.cpp
+++ b/libs/hwui/OpenGLRenderer.cpp
@@ -1978,6 +1978,10 @@ status_t OpenGLRenderer::drawLines(float* points, int count, SkPaint* paint) {
// Find the normal to the line
vec2 n = (b - a).copyNormalized() * halfStrokeWidth;
+ float x = n.x;
+ n.x = -n.y;
+ n.y = x;
+
if (isHairLine) {
if (isAA) {
float wideningFactor;
@@ -2002,14 +2006,10 @@ status_t OpenGLRenderer::drawLines(float* points, int count, SkPaint* paint) {
float extendedNLength = extendedN.length();
// We need to set this value on the shader prior to drawing
- boundaryWidthProportion = extendedNLength / (halfStrokeWidth + extendedNLength);
+ boundaryWidthProportion = .5 - extendedNLength / (halfStrokeWidth + extendedNLength);
n += extendedN;
}
- float x = n.x;
- n.x = -n.y;
- n.y = x;
-
// aa lines expand the endpoint vertices to encompass the AA boundary
if (isAA) {
vec2 abVector = (b - a);
@@ -2593,17 +2593,13 @@ status_t OpenGLRenderer::drawLayer(Layer* layer, float x, float y, SkPaint* pain
mCaches.activeTexture(0);
- int alpha;
- SkXfermode::Mode mode;
- getAlphaAndMode(paint, &alpha, &mode);
-
- layer->setAlpha(alpha, mode);
-
if (CC_LIKELY(!layer->region.isEmpty())) {
if (layer->region.isRect()) {
composeLayerRect(layer, layer->regionRect);
} else if (layer->mesh) {
- const float a = alpha / 255.0f;
+ const float a = layer->getAlpha() / 255.0f;
+ SkiaColorFilter *oldFilter = mColorFilter;
+ mColorFilter = layer->getColorFilter();
setupDraw();
setupDrawWithTexture();
@@ -2633,6 +2629,8 @@ status_t OpenGLRenderer::drawLayer(Layer* layer, float x, float y, SkPaint* pain
finishDrawTexture();
+ mColorFilter = oldFilter;
+
#if DEBUG_LAYERS_AS_REGIONS
drawRegionRects(layer->region);
#endif
diff --git a/libs/hwui/OpenGLRenderer.h b/libs/hwui/OpenGLRenderer.h
index f2b5f0a..7f9405f 100644
--- a/libs/hwui/OpenGLRenderer.h
+++ b/libs/hwui/OpenGLRenderer.h
@@ -227,6 +227,32 @@ public:
*/
void endMark() const;
+ /**
+ * Gets the alpha and xfermode out of a paint object. If the paint is null
+ * alpha will be 255 and the xfermode will be SRC_OVER. This method does
+ * not multiply the paint's alpha by the current snapshot's alpha.
+ *
+ * @param paint The paint to extract values from
+ * @param alpha Where to store the resulting alpha
+ * @param mode Where to store the resulting xfermode
+ */
+ static inline void getAlphaAndModeDirect(SkPaint* paint, int* alpha, SkXfermode::Mode* mode) {
+ if (paint) {
+ *mode = getXfermode(paint->getXfermode());
+
+ // Skia draws using the color's alpha channel if < 255
+ // Otherwise, it uses the paint's alpha
+ int color = paint->getColor();
+ *alpha = (color >> 24) & 0xFF;
+ if (*alpha == 255) {
+ *alpha = paint->getAlpha();
+ }
+ } else {
+ *mode = SkXfermode::kSrcOver_Mode;
+ *alpha = 255;
+ }
+ }
+
protected:
/**
* Compose the layer defined in the current snapshot with the layer
@@ -291,32 +317,6 @@ protected:
inline void getAlphaAndMode(SkPaint* paint, int* alpha, SkXfermode::Mode* mode);
/**
- * Gets the alpha and xfermode out of a paint object. If the paint is null
- * alpha will be 255 and the xfermode will be SRC_OVER. This method does
- * not multiply the paint's alpha by the current snapshot's alpha.
- *
- * @param paint The paint to extract values from
- * @param alpha Where to store the resulting alpha
- * @param mode Where to store the resulting xfermode
- */
- static inline void getAlphaAndModeDirect(SkPaint* paint, int* alpha, SkXfermode::Mode* mode) {
- if (paint) {
- *mode = getXfermode(paint->getXfermode());
-
- // Skia draws using the color's alpha channel if < 255
- // Otherwise, it uses the paint's alpha
- int color = paint->getColor();
- *alpha = (color >> 24) & 0xFF;
- if (*alpha == 255) {
- *alpha = paint->getAlpha();
- }
- } else {
- *mode = SkXfermode::kSrcOver_Mode;
- *alpha = 255;
- }
- }
-
- /**
* Safely retrieves the mode from the specified xfermode. If the specified
* xfermode is null, the mode is assumed to be SkXfermode::kSrcOver_Mode.
*/
diff --git a/libs/hwui/ResourceCache.cpp b/libs/hwui/ResourceCache.cpp
index 2153a8b..b0c57d1 100644
--- a/libs/hwui/ResourceCache.cpp
+++ b/libs/hwui/ResourceCache.cpp
@@ -38,7 +38,7 @@ void ResourceCache::logCache() {
ResourceCache::ResourceCache() {
Mutex::Autolock _l(mLock);
- mCache = new KeyedVector<void *, ResourceReference *>();
+ mCache = new KeyedVector<void*, ResourceReference*>();
}
ResourceCache::~ResourceCache() {
@@ -46,15 +46,17 @@ ResourceCache::~ResourceCache() {
delete mCache;
}
+void ResourceCache::lock() {
+ mLock.lock();
+}
+
+void ResourceCache::unlock() {
+ mLock.unlock();
+}
+
void ResourceCache::incrementRefcount(void* resource, ResourceType resourceType) {
Mutex::Autolock _l(mLock);
- ssize_t index = mCache->indexOfKey(resource);
- ResourceReference* ref = index >= 0 ? mCache->valueAt(index) : NULL;
- if (ref == NULL || mCache->size() == 0) {
- ref = new ResourceReference(resourceType);
- mCache->add(resource, ref);
- }
- ref->refCount++;
+ incrementRefcountLocked(resource, resourceType);
}
void ResourceCache::incrementRefcount(SkBitmap* bitmapResource) {
@@ -77,18 +79,39 @@ void ResourceCache::incrementRefcount(SkiaColorFilter* filterResource) {
incrementRefcount((void*) filterResource, kColorFilter);
}
-void ResourceCache::decrementRefcount(void* resource) {
- Mutex::Autolock _l(mLock);
+void ResourceCache::incrementRefcountLocked(void* resource, ResourceType resourceType) {
ssize_t index = mCache->indexOfKey(resource);
ResourceReference* ref = index >= 0 ? mCache->valueAt(index) : NULL;
- if (ref == NULL) {
- // Should not get here - shouldn't get a call to decrement if we're not yet tracking it
- return;
- }
- ref->refCount--;
- if (ref->refCount == 0) {
- deleteResourceReference(resource, ref);
+ if (ref == NULL || mCache->size() == 0) {
+ ref = new ResourceReference(resourceType);
+ mCache->add(resource, ref);
}
+ ref->refCount++;
+}
+
+void ResourceCache::incrementRefcountLocked(SkBitmap* bitmapResource) {
+ SkSafeRef(bitmapResource->pixelRef());
+ SkSafeRef(bitmapResource->getColorTable());
+ incrementRefcountLocked((void*) bitmapResource, kBitmap);
+}
+
+void ResourceCache::incrementRefcountLocked(SkPath* pathResource) {
+ incrementRefcountLocked((void*) pathResource, kPath);
+}
+
+void ResourceCache::incrementRefcountLocked(SkiaShader* shaderResource) {
+ SkSafeRef(shaderResource->getSkShader());
+ incrementRefcountLocked((void*) shaderResource, kShader);
+}
+
+void ResourceCache::incrementRefcountLocked(SkiaColorFilter* filterResource) {
+ SkSafeRef(filterResource->getSkColorFilter());
+ incrementRefcountLocked((void*) filterResource, kColorFilter);
+}
+
+void ResourceCache::decrementRefcount(void* resource) {
+ Mutex::Autolock _l(mLock);
+ decrementRefcountLocked(resource);
}
void ResourceCache::decrementRefcount(SkBitmap* bitmapResource) {
@@ -111,27 +134,45 @@ void ResourceCache::decrementRefcount(SkiaColorFilter* filterResource) {
decrementRefcount((void*) filterResource);
}
-void ResourceCache::recycle(SkBitmap* resource) {
- Mutex::Autolock _l(mLock);
+void ResourceCache::decrementRefcountLocked(void* resource) {
ssize_t index = mCache->indexOfKey(resource);
- if (index < 0) {
- // not tracking this resource; just recycle the pixel data
- resource->setPixels(NULL, NULL);
- return;
- }
- ResourceReference* ref = mCache->valueAt(index);
+ ResourceReference* ref = index >= 0 ? mCache->valueAt(index) : NULL;
if (ref == NULL) {
- // Should not get here - shouldn't get a call to recycle if we're not yet tracking it
+ // Should not get here - shouldn't get a call to decrement if we're not yet tracking it
return;
}
- ref->recycled = true;
+ ref->refCount--;
if (ref->refCount == 0) {
deleteResourceReference(resource, ref);
}
}
+void ResourceCache::decrementRefcountLocked(SkBitmap* bitmapResource) {
+ SkSafeUnref(bitmapResource->pixelRef());
+ SkSafeUnref(bitmapResource->getColorTable());
+ decrementRefcountLocked((void*) bitmapResource);
+}
+
+void ResourceCache::decrementRefcountLocked(SkPath* pathResource) {
+ decrementRefcountLocked((void*) pathResource);
+}
+
+void ResourceCache::decrementRefcountLocked(SkiaShader* shaderResource) {
+ SkSafeUnref(shaderResource->getSkShader());
+ decrementRefcountLocked((void*) shaderResource);
+}
+
+void ResourceCache::decrementRefcountLocked(SkiaColorFilter* filterResource) {
+ SkSafeUnref(filterResource->getSkColorFilter());
+ decrementRefcountLocked((void*) filterResource);
+}
+
void ResourceCache::destructor(SkPath* resource) {
Mutex::Autolock _l(mLock);
+ destructorLocked(resource);
+}
+
+void ResourceCache::destructorLocked(SkPath* resource) {
ssize_t index = mCache->indexOfKey(resource);
ResourceReference* ref = index >= 0 ? mCache->valueAt(index) : NULL;
if (ref == NULL) {
@@ -150,6 +191,10 @@ void ResourceCache::destructor(SkPath* resource) {
void ResourceCache::destructor(SkBitmap* resource) {
Mutex::Autolock _l(mLock);
+ destructorLocked(resource);
+}
+
+void ResourceCache::destructorLocked(SkBitmap* resource) {
ssize_t index = mCache->indexOfKey(resource);
ResourceReference* ref = index >= 0 ? mCache->valueAt(index) : NULL;
if (ref == NULL) {
@@ -168,6 +213,10 @@ void ResourceCache::destructor(SkBitmap* resource) {
void ResourceCache::destructor(SkiaShader* resource) {
Mutex::Autolock _l(mLock);
+ destructorLocked(resource);
+}
+
+void ResourceCache::destructorLocked(SkiaShader* resource) {
ssize_t index = mCache->indexOfKey(resource);
ResourceReference* ref = index >= 0 ? mCache->valueAt(index) : NULL;
if (ref == NULL) {
@@ -183,6 +232,10 @@ void ResourceCache::destructor(SkiaShader* resource) {
void ResourceCache::destructor(SkiaColorFilter* resource) {
Mutex::Autolock _l(mLock);
+ destructorLocked(resource);
+}
+
+void ResourceCache::destructorLocked(SkiaColorFilter* resource) {
ssize_t index = mCache->indexOfKey(resource);
ResourceReference* ref = index >= 0 ? mCache->valueAt(index) : NULL;
if (ref == NULL) {
@@ -196,6 +249,29 @@ void ResourceCache::destructor(SkiaColorFilter* resource) {
}
}
+void ResourceCache::recycle(SkBitmap* resource) {
+ Mutex::Autolock _l(mLock);
+ recycleLocked(resource);
+}
+
+void ResourceCache::recycleLocked(SkBitmap* resource) {
+ ssize_t index = mCache->indexOfKey(resource);
+ if (index < 0) {
+ // not tracking this resource; just recycle the pixel data
+ resource->setPixels(NULL, NULL);
+ return;
+ }
+ ResourceReference* ref = mCache->valueAt(index);
+ if (ref == NULL) {
+ // Should not get here - shouldn't get a call to recycle if we're not yet tracking it
+ return;
+ }
+ ref->recycled = true;
+ if (ref->refCount == 0) {
+ deleteResourceReference(resource, ref);
+ }
+}
+
/**
* This method should only be called while the mLock mutex is held (that mutex is grabbed
* by the various destructor() and recycle() methods which call this method).
diff --git a/libs/hwui/ResourceCache.h b/libs/hwui/ResourceCache.h
index 8cf466b..60ffa7d 100644
--- a/libs/hwui/ResourceCache.h
+++ b/libs/hwui/ResourceCache.h
@@ -52,28 +52,59 @@ public:
};
class ANDROID_API ResourceCache {
- KeyedVector<void *, ResourceReference *>* mCache;
public:
ResourceCache();
~ResourceCache();
+
+ /**
+ * When using these two methods, make sure to only invoke the *Locked()
+ * variants of increment/decrementRefcount(), recyle() and destructor()
+ */
+ void lock();
+ void unlock();
+
void incrementRefcount(SkPath* resource);
void incrementRefcount(SkBitmap* resource);
void incrementRefcount(SkiaShader* resource);
void incrementRefcount(SkiaColorFilter* resource);
- void incrementRefcount(const void* resource, ResourceType resourceType);
- void decrementRefcount(void* resource);
+
+ void incrementRefcountLocked(SkPath* resource);
+ void incrementRefcountLocked(SkBitmap* resource);
+ void incrementRefcountLocked(SkiaShader* resource);
+ void incrementRefcountLocked(SkiaColorFilter* resource);
+
void decrementRefcount(SkBitmap* resource);
void decrementRefcount(SkPath* resource);
void decrementRefcount(SkiaShader* resource);
void decrementRefcount(SkiaColorFilter* resource);
- void recycle(SkBitmap* resource);
+
+ void decrementRefcountLocked(SkBitmap* resource);
+ void decrementRefcountLocked(SkPath* resource);
+ void decrementRefcountLocked(SkiaShader* resource);
+ void decrementRefcountLocked(SkiaColorFilter* resource);
+
void destructor(SkPath* resource);
void destructor(SkBitmap* resource);
void destructor(SkiaShader* resource);
void destructor(SkiaColorFilter* resource);
+
+ void destructorLocked(SkPath* resource);
+ void destructorLocked(SkBitmap* resource);
+ void destructorLocked(SkiaShader* resource);
+ void destructorLocked(SkiaColorFilter* resource);
+
+ void recycle(SkBitmap* resource);
+ void recycleLocked(SkBitmap* resource);
+
private:
void deleteResourceReference(void* resource, ResourceReference* ref);
+
void incrementRefcount(void* resource, ResourceType resourceType);
+ void incrementRefcountLocked(void* resource, ResourceType resourceType);
+
+ void decrementRefcount(void* resource);
+ void decrementRefcountLocked(void* resource);
+
void logCache();
/**
@@ -82,6 +113,8 @@ private:
* or a reference queue finalization thread.
*/
mutable Mutex mLock;
+
+ KeyedVector<void*, ResourceReference*>* mCache;
};
}; // namespace uirenderer
diff --git a/media/java/android/media/AudioSystem.java b/media/java/android/media/AudioSystem.java
index 1ca0df4..f3a8558 100644
--- a/media/java/android/media/AudioSystem.java
+++ b/media/java/android/media/AudioSystem.java
@@ -188,6 +188,13 @@ public class AudioSystem
* AudioPolicyService methods
*/
+ //
+ // audio device definitions: must be kept in sync with values in system/core/audio.h
+ //
+
+ // reserved bits
+ public static final int DEVICE_BIT_IN = 0x80000000;
+ public static final int DEVICE_BIT_DEFAULT = 0x40000000;
// output devices, be sure to update AudioManager.java also
public static final int DEVICE_OUT_EARPIECE = 0x1;
public static final int DEVICE_OUT_SPEAKER = 0x2;
@@ -204,8 +211,9 @@ public class AudioSystem
public static final int DEVICE_OUT_DGTL_DOCK_HEADSET = 0x1000;
public static final int DEVICE_OUT_USB_ACCESSORY = 0x2000;
public static final int DEVICE_OUT_USB_DEVICE = 0x4000;
+ public static final int DEVICE_OUT_REMOTE_SUBMIX = 0x8000;
- public static final int DEVICE_OUT_DEFAULT = 0x8000;
+ public static final int DEVICE_OUT_DEFAULT = DEVICE_BIT_DEFAULT;
public static final int DEVICE_OUT_ALL = (DEVICE_OUT_EARPIECE |
DEVICE_OUT_SPEAKER |
DEVICE_OUT_WIRED_HEADSET |
@@ -221,6 +229,7 @@ public class AudioSystem
DEVICE_OUT_DGTL_DOCK_HEADSET |
DEVICE_OUT_USB_ACCESSORY |
DEVICE_OUT_USB_DEVICE |
+ DEVICE_OUT_REMOTE_SUBMIX |
DEVICE_OUT_DEFAULT);
public static final int DEVICE_OUT_ALL_A2DP = (DEVICE_OUT_BLUETOOTH_A2DP |
DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES |
@@ -232,15 +241,36 @@ public class AudioSystem
DEVICE_OUT_USB_DEVICE);
// input devices
- public static final int DEVICE_IN_COMMUNICATION = 0x10000;
- public static final int DEVICE_IN_AMBIENT = 0x20000;
- public static final int DEVICE_IN_BUILTIN_MIC1 = 0x40000;
- public static final int DEVICE_IN_BUILTIN_MIC2 = 0x80000;
- public static final int DEVICE_IN_MIC_ARRAY = 0x100000;
- public static final int DEVICE_IN_BLUETOOTH_SCO_HEADSET = 0x200000;
- public static final int DEVICE_IN_WIRED_HEADSET = 0x400000;
- public static final int DEVICE_IN_AUX_DIGITAL = 0x800000;
- public static final int DEVICE_IN_DEFAULT = 0x80000000;
+ public static final int DEVICE_IN_COMMUNICATION = DEVICE_BIT_IN | 0x1;
+ public static final int DEVICE_IN_AMBIENT = DEVICE_BIT_IN | 0x2;
+ public static final int DEVICE_IN_BUILTIN_MIC = DEVICE_BIT_IN | 0x4;
+ public static final int DEVICE_IN_BLUETOOTH_SCO_HEADSET = DEVICE_BIT_IN | 0x8;
+ public static final int DEVICE_IN_WIRED_HEADSET = DEVICE_BIT_IN | 0x10;
+ public static final int DEVICE_IN_AUX_DIGITAL = DEVICE_BIT_IN | 0x20;
+ public static final int DEVICE_IN_VOICE_CALL = DEVICE_BIT_IN | 0x40;
+ public static final int DEVICE_IN_BACK_MIC = DEVICE_BIT_IN | 0x80;
+ public static final int DEVICE_IN_REMOTE_SUBMIX = DEVICE_BIT_IN | 0x100;
+ public static final int DEVICE_IN_ANLG_DOCK_HEADSET = DEVICE_BIT_IN | 0x200;
+ public static final int DEVICE_IN_DGTL_DOCK_HEADSET = DEVICE_BIT_IN | 0x400;
+ public static final int DEVICE_IN_USB_ACCESSORY = DEVICE_BIT_IN | 0x800;
+ public static final int DEVICE_IN_USB_DEVICE = DEVICE_BIT_IN | 0x1000;
+ public static final int DEVICE_IN_DEFAULT = DEVICE_BIT_IN | DEVICE_BIT_DEFAULT;
+
+ public static final int DEVICE_IN_ALL = (DEVICE_IN_COMMUNICATION |
+ DEVICE_IN_AMBIENT |
+ DEVICE_IN_BUILTIN_MIC |
+ DEVICE_IN_BLUETOOTH_SCO_HEADSET |
+ DEVICE_IN_WIRED_HEADSET |
+ DEVICE_IN_AUX_DIGITAL |
+ DEVICE_IN_VOICE_CALL |
+ DEVICE_IN_BACK_MIC |
+ DEVICE_IN_REMOTE_SUBMIX |
+ DEVICE_IN_ANLG_DOCK_HEADSET |
+ DEVICE_IN_DGTL_DOCK_HEADSET |
+ DEVICE_IN_USB_ACCESSORY |
+ DEVICE_IN_USB_DEVICE |
+ DEVICE_IN_DEFAULT);
+ public static final int DEVICE_IN_ALL_SCO = DEVICE_IN_BLUETOOTH_SCO_HEADSET;
// device states, must match AudioSystem::device_connection_state
public static final int DEVICE_STATE_UNAVAILABLE = 0;
@@ -262,6 +292,7 @@ public class AudioSystem
public static final String DEVICE_OUT_DGTL_DOCK_HEADSET_NAME = "digital_dock";
public static final String DEVICE_OUT_USB_ACCESSORY_NAME = "usb_accessory";
public static final String DEVICE_OUT_USB_DEVICE_NAME = "usb_device";
+ public static final String DEVICE_OUT_REMOTE_SUBMIX_NAME = "remote_submix";
public static String getDeviceName(int device)
{
@@ -296,7 +327,9 @@ public class AudioSystem
return DEVICE_OUT_USB_ACCESSORY_NAME;
case DEVICE_OUT_USB_DEVICE:
return DEVICE_OUT_USB_DEVICE_NAME;
- case DEVICE_IN_DEFAULT:
+ case DEVICE_OUT_REMOTE_SUBMIX:
+ return DEVICE_OUT_REMOTE_SUBMIX_NAME;
+ case DEVICE_OUT_DEFAULT:
default:
return "";
}
diff --git a/media/java/android/media/RemoteDisplay.java b/media/java/android/media/RemoteDisplay.java
new file mode 100644
index 0000000..b463d26
--- /dev/null
+++ b/media/java/android/media/RemoteDisplay.java
@@ -0,0 +1,153 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.media;
+
+import dalvik.system.CloseGuard;
+
+import android.os.Handler;
+import android.view.Surface;
+
+/**
+ * Listens for Wifi remote display connections managed by the media server.
+ *
+ * @hide
+ */
+public final class RemoteDisplay {
+ /* these constants must be kept in sync with IRemoteDisplayClient.h */
+
+ public static final int DISPLAY_FLAG_SECURE = 1 << 0;
+
+ public static final int DISPLAY_ERROR_UNKOWN = 1;
+ public static final int DISPLAY_ERROR_CONNECTION_DROPPED = 2;
+
+ private final CloseGuard mGuard = CloseGuard.get();
+ private final Listener mListener;
+ private final Handler mHandler;
+
+ private int mPtr;
+
+ private native int nativeListen(String iface);
+ private native void nativeDispose(int ptr);
+
+ private RemoteDisplay(Listener listener, Handler handler) {
+ mListener = listener;
+ mHandler = handler;
+ }
+
+ @Override
+ protected void finalize() throws Throwable {
+ try {
+ dispose(true);
+ } finally {
+ super.finalize();
+ }
+ }
+
+ /**
+ * Starts listening for displays to be connected on the specified interface.
+ *
+ * @param iface The interface address and port in the form "x.x.x.x:y".
+ * @param listener The listener to invoke when displays are connected or disconnected.
+ * @param handler The handler on which to invoke the listener.
+ */
+ public static RemoteDisplay listen(String iface, Listener listener, Handler handler) {
+ if (iface == null) {
+ throw new IllegalArgumentException("iface must not be null");
+ }
+ if (listener == null) {
+ throw new IllegalArgumentException("listener must not be null");
+ }
+ if (handler == null) {
+ throw new IllegalArgumentException("handler must not be null");
+ }
+
+ RemoteDisplay display = new RemoteDisplay(listener, handler);
+ display.startListening(iface);
+ return display;
+ }
+
+ /**
+ * Disconnects the remote display and stops listening for new connections.
+ */
+ public void dispose() {
+ dispose(false);
+ }
+
+ private void dispose(boolean finalized) {
+ if (mPtr != 0) {
+ if (mGuard != null) {
+ if (finalized) {
+ mGuard.warnIfOpen();
+ } else {
+ mGuard.close();
+ }
+ }
+
+ nativeDispose(mPtr);
+ mPtr = 0;
+ }
+ }
+
+ private void startListening(String iface) {
+ mPtr = nativeListen(iface);
+ if (mPtr == 0) {
+ throw new IllegalStateException("Could not start listening for "
+ + "remote display connection on \"" + iface + "\"");
+ }
+ mGuard.open("dispose");
+ }
+
+ // Called from native.
+ private void notifyDisplayConnected(final Surface surface,
+ final int width, final int height, final int flags) {
+ mHandler.post(new Runnable() {
+ @Override
+ public void run() {
+ mListener.onDisplayConnected(surface, width, height, flags);
+ }
+ });
+ }
+
+ // Called from native.
+ private void notifyDisplayDisconnected() {
+ mHandler.post(new Runnable() {
+ @Override
+ public void run() {
+ mListener.onDisplayDisconnected();
+ }
+ });
+ }
+
+ // Called from native.
+ private void notifyDisplayError(final int error) {
+ mHandler.post(new Runnable() {
+ @Override
+ public void run() {
+ mListener.onDisplayError(error);
+ }
+ });
+ }
+
+ /**
+ * Listener invoked when the remote display connection changes state.
+ */
+ public interface Listener {
+ void onDisplayConnected(Surface surface, int width, int height, int flags);
+ void onDisplayDisconnected();
+ void onDisplayError(int error);
+ }
+}
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java b/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java
index f153904..05673c3 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java
@@ -67,7 +67,7 @@ public class DatabaseHelper extends SQLiteOpenHelper {
// database gets upgraded properly. At a minimum, please confirm that 'upgradeVersion'
// is properly propagated through your change. Not doing so will result in a loss of user
// settings.
- private static final int DATABASE_VERSION = 85;
+ private static final int DATABASE_VERSION = 87;
private Context mContext;
private int mUserHandle;
@@ -308,7 +308,7 @@ public class DatabaseHelper extends SQLiteOpenHelper {
Settings.Secure.WIFI_WATCHDOG_PING_DELAY_MS,
Settings.Secure.WIFI_WATCHDOG_PING_TIMEOUT_MS,
};
- moveSettingsToNewTable(db, TABLE_SYSTEM, TABLE_SECURE, settingsToMove);
+ moveSettingsToNewTable(db, TABLE_SYSTEM, TABLE_SECURE, settingsToMove, false);
upgradeVersion = 28;
}
@@ -674,7 +674,7 @@ public class DatabaseHelper extends SQLiteOpenHelper {
"lockscreen.lockedoutpermanently",
"lockscreen.password_salt"
};
- moveSettingsToNewTable(db, TABLE_SYSTEM, TABLE_SECURE, settingsToMove);
+ moveSettingsToNewTable(db, TABLE_SYSTEM, TABLE_SECURE, settingsToMove, false);
upgradeVersion = 52;
}
@@ -724,7 +724,7 @@ public class DatabaseHelper extends SQLiteOpenHelper {
Secure.SET_INSTALL_LOCATION,
Secure.DEFAULT_INSTALL_LOCATION
};
- moveSettingsToNewTable(db, TABLE_SYSTEM, TABLE_SECURE, settingsToMove);
+ moveSettingsToNewTable(db, TABLE_SYSTEM, TABLE_SECURE, settingsToMove, false);
db.beginTransaction();
SQLiteStatement stmt = null;
try {
@@ -1209,9 +1209,9 @@ public class DatabaseHelper extends SQLiteOpenHelper {
// new users can be created.
createGlobalTable(db);
String[] settingsToMove = hashsetToStringArray(SettingsProvider.sSystemGlobalKeys);
- moveSettingsToNewTable(db, TABLE_SYSTEM, TABLE_GLOBAL, settingsToMove);
+ moveSettingsToNewTable(db, TABLE_SYSTEM, TABLE_GLOBAL, settingsToMove, false);
settingsToMove = hashsetToStringArray(SettingsProvider.sSecureGlobalKeys);
- moveSettingsToNewTable(db, TABLE_SECURE, TABLE_GLOBAL, settingsToMove);
+ moveSettingsToNewTable(db, TABLE_SECURE, TABLE_GLOBAL, settingsToMove, false);
db.setTransactionSuccessful();
} finally {
@@ -1254,7 +1254,8 @@ public class DatabaseHelper extends SQLiteOpenHelper {
db.beginTransaction();
SQLiteStatement stmt = null;
try {
- // Patch up the slightly-wrong key migration from 82 -> 83
+ // Patch up the slightly-wrong key migration from 82 -> 83 for those
+ // devices that missed it, ignoring if the move is redundant
String[] settingsToMove = {
Settings.Secure.ADB_ENABLED,
Settings.Secure.BLUETOOTH_ON,
@@ -1263,7 +1264,7 @@ public class DatabaseHelper extends SQLiteOpenHelper {
Settings.Secure.INSTALL_NON_MARKET_APPS,
Settings.Secure.USB_MASS_STORAGE_ENABLED
};
- moveSettingsToNewTable(db, TABLE_SECURE, TABLE_GLOBAL, settingsToMove);
+ moveSettingsToNewTable(db, TABLE_SECURE, TABLE_GLOBAL, settingsToMove, true);
db.setTransactionSuccessful();
} finally {
db.endTransaction();
@@ -1272,6 +1273,38 @@ public class DatabaseHelper extends SQLiteOpenHelper {
upgradeVersion = 85;
}
+ if (upgradeVersion == 85) {
+ db.beginTransaction();
+ try {
+ // Fix up the migration, ignoring already-migrated elements, to snap up to
+ // date with new changes to the set of global versus system/secure settings
+ String[] settingsToMove = { Settings.System.STAY_ON_WHILE_PLUGGED_IN };
+ moveSettingsToNewTable(db, TABLE_SYSTEM, TABLE_GLOBAL, settingsToMove, true);
+
+ db.setTransactionSuccessful();
+ } finally {
+ db.endTransaction();
+ }
+ upgradeVersion = 86;
+ }
+
+ if (upgradeVersion == 86) {
+ db.beginTransaction();
+ try {
+ String[] settingsToMove = {
+ Settings.Secure.PACKAGE_VERIFIER_ENABLE,
+ Settings.Secure.PACKAGE_VERIFIER_TIMEOUT,
+ Settings.Secure.PACKAGE_VERIFIER_DEFAULT_RESPONSE
+ };
+ moveSettingsToNewTable(db, TABLE_SECURE, TABLE_GLOBAL, settingsToMove, true);
+
+ db.setTransactionSuccessful();
+ } finally {
+ db.endTransaction();
+ }
+ upgradeVersion = 87;
+ }
+
// *** Remember to update DATABASE_VERSION above!
if (upgradeVersion != currentVersion) {
@@ -1306,15 +1339,16 @@ public class DatabaseHelper extends SQLiteOpenHelper {
private void moveSettingsToNewTable(SQLiteDatabase db,
String sourceTable, String destTable,
- String[] settingsToMove) {
+ String[] settingsToMove, boolean doIgnore) {
// Copy settings values from the source table to the dest, and remove from the source
SQLiteStatement insertStmt = null;
SQLiteStatement deleteStmt = null;
db.beginTransaction();
try {
- insertStmt = db.compileStatement("INSERT INTO "
- + destTable + " (name,value) SELECT name,value FROM "
+ insertStmt = db.compileStatement("INSERT "
+ + (doIgnore ? " OR IGNORE " : "")
+ + " INTO " + destTable + " (name,value) SELECT name,value FROM "
+ sourceTable + " WHERE name=?");
deleteStmt = db.compileStatement("DELETE FROM " + sourceTable + " WHERE name=?");
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsBackupAgent.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsBackupAgent.java
index 0165977..1096540 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsBackupAgent.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsBackupAgent.java
@@ -563,7 +563,7 @@ public class SettingsBackupAgent extends BackupAgentHelper {
getContentResolver().insert(contentUri, contentValues);
}
- if (DEBUG) {
+ if (DEBUG || true) {
Log.d(TAG, "Restored setting: " + key + "=" + value);
}
}
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
index b444eb1..f859f41 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
@@ -113,17 +113,22 @@ public class SettingsProvider extends ContentProvider {
// table, shared across all users
// These must match Settings.Secure.MOVED_TO_GLOBAL
sSecureGlobalKeys = new HashSet<String>();
+ sSecureGlobalKeys.add(Settings.Secure.ADB_ENABLED);
sSecureGlobalKeys.add(Settings.Secure.ASSISTED_GPS_ENABLED);
+ sSecureGlobalKeys.add(Settings.Secure.BLUETOOTH_ON);
sSecureGlobalKeys.add(Settings.Secure.CDMA_CELL_BROADCAST_SMS);
sSecureGlobalKeys.add(Settings.Secure.CDMA_ROAMING_MODE);
sSecureGlobalKeys.add(Settings.Secure.CDMA_SUBSCRIPTION_MODE);
sSecureGlobalKeys.add(Settings.Secure.DATA_ACTIVITY_TIMEOUT_MOBILE);
sSecureGlobalKeys.add(Settings.Secure.DATA_ACTIVITY_TIMEOUT_WIFI);
+ sSecureGlobalKeys.add(Settings.Secure.DATA_ROAMING);
sSecureGlobalKeys.add(Settings.Secure.DEVELOPMENT_SETTINGS_ENABLED);
+ sSecureGlobalKeys.add(Settings.Secure.DEVICE_PROVISIONED);
sSecureGlobalKeys.add(Settings.Secure.DISPLAY_DENSITY_FORCED);
sSecureGlobalKeys.add(Settings.Secure.DISPLAY_SIZE_FORCED);
sSecureGlobalKeys.add(Settings.Secure.DOWNLOAD_MAX_BYTES_OVER_MOBILE);
sSecureGlobalKeys.add(Settings.Secure.DOWNLOAD_RECOMMENDED_MAX_BYTES_OVER_MOBILE);
+ sSecureGlobalKeys.add(Settings.Secure.INSTALL_NON_MARKET_APPS);
sSecureGlobalKeys.add(Settings.Secure.MOBILE_DATA);
sSecureGlobalKeys.add(Settings.Secure.NETSTATS_DEV_BUCKET_DURATION);
sSecureGlobalKeys.add(Settings.Secure.NETSTATS_DEV_DELETE_AGE);
@@ -167,6 +172,7 @@ public class SettingsProvider extends ContentProvider {
sSecureGlobalKeys.add(Settings.Secure.THROTTLE_RESET_DAY);
sSecureGlobalKeys.add(Settings.Secure.THROTTLE_THRESHOLD_BYTES);
sSecureGlobalKeys.add(Settings.Secure.THROTTLE_VALUE_KBITSPS);
+ sSecureGlobalKeys.add(Settings.Secure.USB_MASS_STORAGE_ENABLED);
sSecureGlobalKeys.add(Settings.Secure.USE_GOOGLE_MAIL);
sSecureGlobalKeys.add(Settings.Secure.WEB_AUTOFILL_QUERY_URL);
sSecureGlobalKeys.add(Settings.Secure.WIFI_COUNTRY_CODE);
@@ -193,12 +199,6 @@ public class SettingsProvider extends ContentProvider {
// Keys from the 'system' table now moved to 'global'
// These must match Settings.System.MOVED_TO_GLOBAL
sSystemGlobalKeys = new HashSet<String>();
- sSystemGlobalKeys.add(Settings.Secure.ADB_ENABLED);
- sSystemGlobalKeys.add(Settings.Secure.BLUETOOTH_ON);
- sSystemGlobalKeys.add(Settings.Secure.DATA_ROAMING);
- sSystemGlobalKeys.add(Settings.Secure.DEVICE_PROVISIONED);
- sSystemGlobalKeys.add(Settings.Secure.INSTALL_NON_MARKET_APPS);
- sSystemGlobalKeys.add(Settings.Secure.USB_MASS_STORAGE_ENABLED);
sSystemGlobalKeys.add(Settings.System.AIRPLANE_MODE_ON);
sSystemGlobalKeys.add(Settings.System.AIRPLANE_MODE_RADIOS);
@@ -214,6 +214,7 @@ public class SettingsProvider extends ContentProvider {
sSystemGlobalKeys.add(Settings.System.UNLOCK_SOUND);
sSystemGlobalKeys.add(Settings.System.LOW_BATTERY_SOUND);
sSystemGlobalKeys.add(Settings.System.POWER_SOUNDS_ENABLED);
+ sSystemGlobalKeys.add(Settings.System.STAY_ON_WHILE_PLUGGED_IN);
sSystemGlobalKeys.add(Settings.System.WIFI_SLEEP_POLICY);
}
diff --git a/packages/SystemUI/AndroidManifest.xml b/packages/SystemUI/AndroidManifest.xml
index 13800a6..22a97bd 100644
--- a/packages/SystemUI/AndroidManifest.xml
+++ b/packages/SystemUI/AndroidManifest.xml
@@ -16,6 +16,9 @@
<uses-permission android:name="android.permission.REMOTE_AUDIO_PLAYBACK" />
<uses-permission android:name="android.permission.MANAGE_USERS" />
+ <uses-permission android:name="android.permission.READ_PROFILE" />
+ <uses-permission android:name="android.permission.READ_CONTACTS" />
+ <uses-permission android:name="android.permission.CONFIGURE_WIFI_DISPLAY" />
<!-- Networking and telephony -->
<uses-permission android:name="android.permission.BLUETOOTH" />
diff --git a/packages/SystemUI/res/drawable-hdpi/ic_qs_airplane_enabled.png b/packages/SystemUI/res/drawable-hdpi/ic_qs_airplane_enabled.png
new file mode 100644
index 0000000..c47f70a
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/ic_qs_airplane_enabled.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/ic_qs_airplane_normal.png b/packages/SystemUI/res/drawable-hdpi/ic_qs_airplane_normal.png
new file mode 100644
index 0000000..c87e162
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/ic_qs_airplane_normal.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/ic_qs_bluetooth_enabled.png b/packages/SystemUI/res/drawable-hdpi/ic_qs_bluetooth_enabled.png
new file mode 100644
index 0000000..8baece6
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/ic_qs_bluetooth_enabled.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/ic_qs_bluetooth_normal.png b/packages/SystemUI/res/drawable-hdpi/ic_qs_bluetooth_normal.png
new file mode 100644
index 0000000..03f8b9c
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/ic_qs_bluetooth_normal.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/ic_qs_rssi_enabled.png b/packages/SystemUI/res/drawable-hdpi/ic_qs_rssi_enabled.png
new file mode 100644
index 0000000..8348455
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/ic_qs_rssi_enabled.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/ic_qs_rssi_normal.png b/packages/SystemUI/res/drawable-hdpi/ic_qs_rssi_normal.png
new file mode 100644
index 0000000..0dfcfd2
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/ic_qs_rssi_normal.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/ic_qs_wifi_enabled.png b/packages/SystemUI/res/drawable-hdpi/ic_qs_wifi_enabled.png
new file mode 100644
index 0000000..0276e42
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/ic_qs_wifi_enabled.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/ic_qs_wifi_normal.png b/packages/SystemUI/res/drawable-hdpi/ic_qs_wifi_normal.png
new file mode 100644
index 0000000..112279a
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/ic_qs_wifi_normal.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_qs_airplane_enabled.png b/packages/SystemUI/res/drawable-mdpi/ic_qs_airplane_enabled.png
new file mode 100644
index 0000000..06ed0a8
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/ic_qs_airplane_enabled.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_qs_airplane_normal.png b/packages/SystemUI/res/drawable-mdpi/ic_qs_airplane_normal.png
new file mode 100644
index 0000000..1c83e5b
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/ic_qs_airplane_normal.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_qs_bluetooth_enabled.png b/packages/SystemUI/res/drawable-mdpi/ic_qs_bluetooth_enabled.png
new file mode 100644
index 0000000..9cff183
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/ic_qs_bluetooth_enabled.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_qs_bluetooth_normal.png b/packages/SystemUI/res/drawable-mdpi/ic_qs_bluetooth_normal.png
new file mode 100644
index 0000000..1e6c564
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/ic_qs_bluetooth_normal.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_qs_rssi_enabled.png b/packages/SystemUI/res/drawable-mdpi/ic_qs_rssi_enabled.png
new file mode 100644
index 0000000..afe6e98
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/ic_qs_rssi_enabled.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_qs_rssi_normal.png b/packages/SystemUI/res/drawable-mdpi/ic_qs_rssi_normal.png
new file mode 100644
index 0000000..3bec266
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/ic_qs_rssi_normal.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_qs_wifi_enabled.png b/packages/SystemUI/res/drawable-mdpi/ic_qs_wifi_enabled.png
new file mode 100644
index 0000000..6c94754
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/ic_qs_wifi_enabled.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_qs_wifi_normal.png b/packages/SystemUI/res/drawable-mdpi/ic_qs_wifi_normal.png
new file mode 100644
index 0000000..d6b47fc
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/ic_qs_wifi_normal.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_qs_airplane_enabled.png b/packages/SystemUI/res/drawable-xhdpi/ic_qs_airplane_enabled.png
new file mode 100644
index 0000000..7ee9290
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/ic_qs_airplane_enabled.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_qs_airplane_normal.png b/packages/SystemUI/res/drawable-xhdpi/ic_qs_airplane_normal.png
new file mode 100644
index 0000000..41d7498
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/ic_qs_airplane_normal.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_qs_bluetooth_enabled.png b/packages/SystemUI/res/drawable-xhdpi/ic_qs_bluetooth_enabled.png
new file mode 100644
index 0000000..8811e62
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/ic_qs_bluetooth_enabled.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_qs_bluetooth_normal.png b/packages/SystemUI/res/drawable-xhdpi/ic_qs_bluetooth_normal.png
new file mode 100644
index 0000000..0026596
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/ic_qs_bluetooth_normal.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_qs_rssi_enabled.png b/packages/SystemUI/res/drawable-xhdpi/ic_qs_rssi_enabled.png
new file mode 100644
index 0000000..4a2789d
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/ic_qs_rssi_enabled.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_qs_rssi_normal.png b/packages/SystemUI/res/drawable-xhdpi/ic_qs_rssi_normal.png
new file mode 100644
index 0000000..ee4b21f
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/ic_qs_rssi_normal.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_qs_wifi_enabled.png b/packages/SystemUI/res/drawable-xhdpi/ic_qs_wifi_enabled.png
new file mode 100644
index 0000000..114ee29
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/ic_qs_wifi_enabled.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_qs_wifi_normal.png b/packages/SystemUI/res/drawable-xhdpi/ic_qs_wifi_normal.png
new file mode 100644
index 0000000..0719b21
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/ic_qs_wifi_normal.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable/ic_qs_battery.xml b/packages/SystemUI/res/drawable/ic_qs_battery.xml
new file mode 100644
index 0000000..4e2a265
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_qs_battery.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2012 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<clip
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:drawable="@drawable/stat_sys_battery_100"
+ android:clipOrientation="vertical"
+ android:gravity="bottom" />
diff --git a/packages/SystemUI/res/layout/quick_settings.xml b/packages/SystemUI/res/layout/quick_settings.xml
index 8c6258a..d89f279 100644
--- a/packages/SystemUI/res/layout/quick_settings.xml
+++ b/packages/SystemUI/res/layout/quick_settings.xml
@@ -19,14 +19,18 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="@+id/settings_panel"
- android:background="#80000080"
+ android:background="@drawable/notification_panel_bg"
>
- <ImageView
+ <!-- TODO: Put into ScrollView -->
+ <com.android.systemui.statusbar.phone.QuickSettingsContainerView
+ android:id="@+id/quick_settings_container"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:scaleType="centerInside"
- android:src="@drawable/qs_coming_soon"
- android:padding="4dp"
+ android:paddingBottom="@dimen/quick_settings_container_padding"
+ android:paddingLeft="@dimen/quick_settings_container_padding"
+ android:paddingRight="@dimen/quick_settings_container_padding"
+ android:animateLayoutChanges="true"
+ android:columnCount="@integer/quick_settings_num_columns"
/>
<LinearLayout android:id="@+id/handle"
android:layout_width="match_parent"
diff --git a/packages/SystemUI/res/layout/quick_settings_tile.xml b/packages/SystemUI/res/layout/quick_settings_tile.xml
new file mode 100644
index 0000000..a571393
--- /dev/null
+++ b/packages/SystemUI/res/layout/quick_settings_tile.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2012 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<com.android.systemui.statusbar.phone.QuickSettingsTileView
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="wrap_content"
+ android:layout_height="@dimen/quick_settings_cell_height"
+ android:background="#1B1D1B" /> \ No newline at end of file
diff --git a/packages/SystemUI/res/layout/quick_settings_tile_airplane.xml b/packages/SystemUI/res/layout/quick_settings_tile_airplane.xml
new file mode 100644
index 0000000..3e3a9c2
--- /dev/null
+++ b/packages/SystemUI/res/layout/quick_settings_tile_airplane.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2012 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<TextView
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/airplane_mode_textview"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:layout_gravity="center"
+ android:gravity="center"
+ android:text="@string/quick_settings_airplane_mode_label"
+ android:textAppearance="@style/TextAppearance.QuickSettings.TileView"
+ /> \ No newline at end of file
diff --git a/packages/SystemUI/res/layout/quick_settings_tile_battery.xml b/packages/SystemUI/res/layout/quick_settings_tile_battery.xml
new file mode 100644
index 0000000..680a1bb
--- /dev/null
+++ b/packages/SystemUI/res/layout/quick_settings_tile_battery.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2012 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<TextView
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/battery_textview"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:layout_gravity="center"
+ android:gravity="center"
+ android:drawableTop="@drawable/ic_qs_battery"
+ android:text="@string/quick_settings_battery_label"
+ android:textAppearance="@style/TextAppearance.QuickSettings.TileView"
+ /> \ No newline at end of file
diff --git a/packages/SystemUI/res/layout/quick_settings_tile_bluetooth.xml b/packages/SystemUI/res/layout/quick_settings_tile_bluetooth.xml
new file mode 100644
index 0000000..4472484
--- /dev/null
+++ b/packages/SystemUI/res/layout/quick_settings_tile_bluetooth.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2012 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<TextView
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/bluetooth_textview"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:layout_gravity="center"
+ android:gravity="center"
+ android:text="@string/quick_settings_bluetooth_label"
+ android:textAppearance="@style/TextAppearance.QuickSettings.TileView"
+ /> \ No newline at end of file
diff --git a/packages/SystemUI/res/layout/quick_settings_tile_brightness.xml b/packages/SystemUI/res/layout/quick_settings_tile_brightness.xml
new file mode 100644
index 0000000..216930d
--- /dev/null
+++ b/packages/SystemUI/res/layout/quick_settings_tile_brightness.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2012 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<TextView
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:layout_gravity="center"
+ android:gravity="center"
+ android:drawableTop="@drawable/ic_sysbar_brightness"
+ android:text="@string/quick_settings_brightness_label"
+ android:textAppearance="@style/TextAppearance.QuickSettings.TileView"
+ /> \ No newline at end of file
diff --git a/packages/SystemUI/res/layout/quick_settings_tile_ime.xml b/packages/SystemUI/res/layout/quick_settings_tile_ime.xml
new file mode 100644
index 0000000..93db6db
--- /dev/null
+++ b/packages/SystemUI/res/layout/quick_settings_tile_ime.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2012 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<TextView
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:gravity="center"
+ android:text="@string/quick_settings_ime_label"
+ android:singleLine="true"
+ /> \ No newline at end of file
diff --git a/packages/SystemUI/res/layout/quick_settings_tile_location.xml b/packages/SystemUI/res/layout/quick_settings_tile_location.xml
new file mode 100644
index 0000000..1a40642
--- /dev/null
+++ b/packages/SystemUI/res/layout/quick_settings_tile_location.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2012 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<TextView
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/location_textview"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:layout_gravity="center"
+ android:gravity="center"
+ android:drawableTop="@drawable/stat_sys_gps_acquiring"
+ android:text="@string/quick_settings_location_label"
+ android:textAppearance="@style/TextAppearance.QuickSettings.TileView"
+ /> \ No newline at end of file
diff --git a/packages/SystemUI/res/layout/quick_settings_tile_media.xml b/packages/SystemUI/res/layout/quick_settings_tile_media.xml
new file mode 100644
index 0000000..0810d02
--- /dev/null
+++ b/packages/SystemUI/res/layout/quick_settings_tile_media.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2012 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<TextView
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:gravity="center"
+ android:text="@string/quick_settings_media_device_label"
+ android:singleLine="true"
+ /> \ No newline at end of file
diff --git a/packages/SystemUI/res/layout/quick_settings_tile_rssi.xml b/packages/SystemUI/res/layout/quick_settings_tile_rssi.xml
new file mode 100644
index 0000000..3e541cb
--- /dev/null
+++ b/packages/SystemUI/res/layout/quick_settings_tile_rssi.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2012 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<TextView
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/rssi_textview"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:layout_gravity="center"
+ android:gravity="center"
+ android:text="@string/quick_settings_rssi_label"
+ android:textAppearance="@style/TextAppearance.QuickSettings.TileView"
+ /> \ No newline at end of file
diff --git a/packages/SystemUI/res/layout/quick_settings_tile_settings.xml b/packages/SystemUI/res/layout/quick_settings_tile_settings.xml
new file mode 100644
index 0000000..1c2f827
--- /dev/null
+++ b/packages/SystemUI/res/layout/quick_settings_tile_settings.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2012 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<TextView
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:layout_gravity="center"
+ android:gravity="center"
+ android:drawableTop="@drawable/ic_notify_quicksettings"
+ android:text="@string/quick_settings_settings_label"
+ android:textAppearance="@style/TextAppearance.QuickSettings.TileView"
+ /> \ No newline at end of file
diff --git a/packages/SystemUI/res/layout/quick_settings_tile_time.xml b/packages/SystemUI/res/layout/quick_settings_tile_time.xml
new file mode 100644
index 0000000..ab0c52d
--- /dev/null
+++ b/packages/SystemUI/res/layout/quick_settings_tile_time.xml
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2012 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<LinearLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center"
+ android:orientation="vertical">
+ <com.android.systemui.statusbar.policy.Clock
+ android:textAppearance="@style/TextAppearance.QuickSettings.Clock"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center_horizontal"
+ android:singleLine="true"
+ />
+ <com.android.systemui.statusbar.policy.QuickSettingsDateView
+ android:textAppearance="@style/TextAppearance.QuickSettings.Date"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center_horizontal"
+ />
+</LinearLayout> \ No newline at end of file
diff --git a/packages/SystemUI/res/layout/quick_settings_tile_user.xml b/packages/SystemUI/res/layout/quick_settings_tile_user.xml
new file mode 100644
index 0000000..8edc978
--- /dev/null
+++ b/packages/SystemUI/res/layout/quick_settings_tile_user.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2012 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<TextView
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/user_textview"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center_horizontal|bottom"
+ android:gravity="center"
+ android:text="@string/quick_settings_user_label"
+ android:textAppearance="@style/TextAppearance.QuickSettings.TileView"
+ android:background="#33000000"
+ /> \ No newline at end of file
diff --git a/packages/SystemUI/res/layout/quick_settings_tile_wifi.xml b/packages/SystemUI/res/layout/quick_settings_tile_wifi.xml
new file mode 100644
index 0000000..42eb45a
--- /dev/null
+++ b/packages/SystemUI/res/layout/quick_settings_tile_wifi.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2012 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<TextView
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/wifi_textview"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:layout_gravity="center"
+ android:gravity="center"
+ android:text="@string/quick_settings_wifi_label"
+ android:textAppearance="@style/TextAppearance.QuickSettings.TileView"
+ /> \ No newline at end of file
diff --git a/packages/SystemUI/res/layout/quick_settings_tile_wifi_display.xml b/packages/SystemUI/res/layout/quick_settings_tile_wifi_display.xml
new file mode 100644
index 0000000..929dd94
--- /dev/null
+++ b/packages/SystemUI/res/layout/quick_settings_tile_wifi_display.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2012 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<TextView
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/wifi_display_textview"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:layout_gravity="center"
+ android:gravity="center"
+ android:drawableTop="@drawable/ic_qs_wifi_normal"
+ android:text="@string/quick_settings_wifi_display_label"
+ android:textAppearance="@style/TextAppearance.QuickSettings.TileView"
+ /> \ No newline at end of file
diff --git a/packages/SystemUI/res/layout/wifi_display_dialog.xml b/packages/SystemUI/res/layout/wifi_display_dialog.xml
new file mode 100644
index 0000000..a78096e
--- /dev/null
+++ b/packages/SystemUI/res/layout/wifi_display_dialog.xml
@@ -0,0 +1,38 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2012 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="vertical">
+
+ <ListView android:id="@+id/list"
+ android:layout_width="match_parent"
+ android:layout_height="0dp"
+ android:layout_weight="2" />
+
+ <Button android:id="@+id/scan"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_weight="1"
+ android:text="@string/wifi_display_scan" />
+
+ <Button android:id="@+id/disconnect"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_weight="1"
+ android:text="@string/wifi_display_disconnect" />
+</LinearLayout>
diff --git a/packages/SystemUI/res/values-land/config.xml b/packages/SystemUI/res/values-land/config.xml
index bbae18d..6476d88 100644
--- a/packages/SystemUI/res/values-land/config.xml
+++ b/packages/SystemUI/res/values-land/config.xml
@@ -23,5 +23,11 @@
<!-- Whether we're using the tablet-optimized recents interface (we use this
value at runtime for some things) -->
<integer name="status_bar_recents_bg_gradient_degrees">90</integer>
+
+ <!-- The number of columns in the QuickSettings -->
+ <integer name="quick_settings_num_columns">6</integer>
+
+ <!-- The number of columns that the top level tiles span in the QuickSettings -->
+ <integer name="quick_settings_user_time_settings_tile_span">2</integer>
</resources>
diff --git a/packages/SystemUI/res/values-land/dimens.xml b/packages/SystemUI/res/values-land/dimens.xml
index e7c8b1f..ab71371 100644
--- a/packages/SystemUI/res/values-land/dimens.xml
+++ b/packages/SystemUI/res/values-land/dimens.xml
@@ -37,4 +37,7 @@
<!-- Where to place the app icon over the thumbnail -->
<dimen name="status_bar_recents_app_icon_left_margin">8dp</dimen>
<dimen name="status_bar_recents_app_icon_top_margin">8dp</dimen>
+
+ <!-- The fixed height of each tile -->
+ <dimen name="quick_settings_cell_height">100dp</dimen>
</resources>
diff --git a/packages/SystemUI/res/values/config.xml b/packages/SystemUI/res/values/config.xml
index 34e58a3..734e68c 100644
--- a/packages/SystemUI/res/values/config.xml
+++ b/packages/SystemUI/res/values/config.xml
@@ -81,5 +81,11 @@
<!-- Min alpha % that recent items will fade to while being dismissed -->
<integer name="config_recent_item_min_alpha">3</integer>
+
+ <!-- The number of columns in the QuickSettings -->
+ <integer name="quick_settings_num_columns">3</integer>
+
+ <!-- The number of columns that the top level tiles span in the QuickSettings -->
+ <integer name="quick_settings_user_time_settings_tile_span">1</integer>
</resources>
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index 0d7cdb1..63ce2a9 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -174,4 +174,14 @@
<!-- The distance you can pull a notificaiton before it pops open -->
<dimen name="one_finger_pop_limit">32dp</dimen>
+
+ <!-- The amount of padding around the QuickSettings tiles -->
+ <dimen name="quick_settings_container_padding">12dp</dimen>
+
+ <!-- The fixed height of each tile -->
+ <dimen name="quick_settings_cell_height">110dp</dimen>
+
+ <!-- The padding between each tile within the QuickSettings layout -->
+ <dimen name="quick_settings_cell_gap">5dp</dimen>
+
</resources>
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index 43070c6..2bcf951 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -401,4 +401,54 @@
<!-- Name of the launcher shortcut icon that allows dreams to be started immediately [CHAR LIMIT=20] -->
<string name="start_dreams">Start dreams</string>
+ <!-- QuickSettings: Airplane mode [CHAR LIMIT=NONE] -->
+ <string name="quick_settings_airplane_mode_label">Airplane mode</string>
+ <!-- QuickSettings: Battery [CHAR LIMIT=NONE] -->
+ <string name="quick_settings_battery_label">Battery</string>
+ <!-- QuickSettings: Bluetooth [CHAR LIMIT=NONE] -->
+ <string name="quick_settings_bluetooth_label">Bluetooth</string>
+ <!-- QuickSettings: Brightness [CHAR LIMIT=NONE] -->
+ <string name="quick_settings_brightness_label">Brightness</string>
+ <!-- QuickSettings: IME [CHAR LIMIT=NONE] -->
+ <string name="quick_settings_ime_label">IME</string>
+ <!-- QuickSettings: Location [CHAR LIMIT=NONE] -->
+ <string name="quick_settings_location_label">Location in use</string>
+ <!-- QuickSettings: Media device [CHAR LIMIT=NONE] -->
+ <string name="quick_settings_media_device_label">Media device</string>
+ <!-- QuickSettings: RSSI [CHAR LIMIT=NONE] -->
+ <string name="quick_settings_rssi_label">RSSI</string>
+ <!-- QuickSettings: RSSI (No network) [CHAR LIMIT=NONE] -->
+ <string name="quick_settings_rssi_emergency_only">Emergency Calls Only</string>
+ <!-- QuickSettings: Settings [CHAR LIMIT=NONE] -->
+ <string name="quick_settings_settings_label">Settings</string>
+ <!-- QuickSettings: Time [CHAR LIMIT=NONE] -->
+ <string name="quick_settings_time_label">Time</string>
+ <!-- QuickSettings: User [CHAR LIMIT=NONE] -->
+ <string name="quick_settings_user_label">Me</string>
+ <!-- QuickSettings: Wifi [CHAR LIMIT=NONE] -->
+ <string name="quick_settings_wifi_label">Wifi</string>
+ <!-- QuickSettings: Wifi (No network) [CHAR LIMIT=NONE] -->
+ <string name="quick_settings_wifi_no_network">No Network</string>
+ <!-- QuickSettings: Wifi display [CHAR LIMIT=NONE] -->
+ <string name="quick_settings_wifi_display_label">Wifi Display</string>
+ <!-- QuickSettings: Wifi display [CHAR LIMIT=NONE] -->
+ <string name="quick_settings_wifi_display_no_connection_label">No Wifi Display Connection</string>
+
+ <!-- Wifi display: Scan button text [CHAR LIMIT=15] -->
+ <string name="wifi_display_scan">Scan</string>
+
+ <!-- Wifi display: Disconnect button text [CHAR LIMIT=15] -->
+ <string name="wifi_display_disconnect">Disconnect</string>
+
+ <!-- Wifi display: Quick setting dialog title [CHAR LIMIT=30] -->
+ <string name="wifi_display_dialog_title">Wifi Display</string>
+
+ <!-- Wifi display: Subtitle text shown to indicate that a display is available [CHAR LIMIT=30] -->
+ <string name="wifi_display_state_available">Available</string>
+
+ <!-- Wifi display: Subtitle text shown to indicate that a display is connecting [CHAR LIMIT=30] -->
+ <string name="wifi_display_state_connecting">Connecting</string>
+
+ <!-- Wifi display: Subtitle text shown to indicate that a display is connected [CHAR LIMIT=30] -->
+ <string name="wifi_display_state_connected">Connected</string>
</resources>
diff --git a/packages/SystemUI/res/values/styles.xml b/packages/SystemUI/res/values/styles.xml
index 2564003..34bd627 100644
--- a/packages/SystemUI/res/values/styles.xml
+++ b/packages/SystemUI/res/values/styles.xml
@@ -70,6 +70,28 @@
<style name="TextAppearance.StatusBar.Expanded.Network.EmergencyOnly">
</style>
+ <style name="TextAppearance" />
+ <style name="TextAppearance.QuickSettings" />
+
+ <style name="TextAppearance.QuickSettings.TileView">
+ <item name="android:padding">8dp</item>
+ <item name="android:textSize">13dp</item>
+ <item name="android:textStyle">normal</item>
+ <item name="android:textColor">#ff8d908c</item>
+ <item name="android:singleLine">true</item>
+ <item name="android:ellipsize">marquee</item>
+ <item name="android:fadingEdge">horizontal</item>
+ </style>
+
+ <style name="TextAppearance.QuickSettings.Clock" parent="@style/TextAppearance.QuickSettings.TileView">
+ <item name="android:textSize">24dp</item>
+ <item name="android:textColor">@android:color/holo_blue_light</item>
+ </style>
+
+ <style name="TextAppearance.QuickSettings.Date" parent="@style/TextAppearance.QuickSettings.TileView">
+ <item name="android:textSize">14dp</item>
+ </style>
+
<style name="Animation" />
<style name="Animation.ShirtPocketPanel">
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java
index 2f551e1..bee63ee 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java
@@ -12,6 +12,10 @@ import android.view.View;
import android.widget.FrameLayout;
import com.android.systemui.R;
+import com.android.systemui.statusbar.policy.BatteryController;
+import com.android.systemui.statusbar.policy.BluetoothController;
+import com.android.systemui.statusbar.policy.LocationController;
+import com.android.systemui.statusbar.policy.NetworkController;
public class PanelView extends FrameLayout {
public static final boolean DEBUG = false;
@@ -356,6 +360,11 @@ public class PanelView extends FrameLayout {
mBar = panelBar;
}
+ public void setup(NetworkController network, BluetoothController bt, BatteryController batt,
+ LocationController location) {
+ // To be implemented by classes extending PanelView
+ }
+
public void collapse() {
// TODO: abort animation or ongoing touch
if (mExpandedHeight > 0) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
index 5646c55..a5d4a8e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
@@ -19,11 +19,10 @@ package com.android.systemui.statusbar.phone;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.AnimatorSet;
+import android.animation.LayoutTransition;
import android.animation.ObjectAnimator;
import android.app.ActivityManager;
import android.app.ActivityManagerNative;
-import android.app.Dialog;
-import android.app.KeyguardManager;
import android.app.Notification;
import android.app.PendingIntent;
import android.app.StatusBarManager;
@@ -31,7 +30,6 @@ import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
-import android.content.res.Configuration;
import android.content.res.Resources;
import android.graphics.Canvas;
import android.graphics.ColorFilter;
@@ -54,13 +52,11 @@ import android.util.Log;
import android.util.Slog;
import android.view.Display;
import android.view.Gravity;
-import android.view.IWindowManager;
-import android.view.KeyEvent;
+import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.VelocityTracker;
import android.view.View;
import android.view.ViewGroup;
-import android.view.WindowManagerGlobal;
import android.view.ViewGroup.LayoutParams;
import android.view.WindowManager;
import android.view.animation.AccelerateInterpolator;
@@ -76,7 +72,6 @@ import android.widget.TextView;
import com.android.internal.statusbar.StatusBarIcon;
import com.android.internal.statusbar.StatusBarNotification;
import com.android.systemui.R;
-import com.android.systemui.recent.RecentTasksLoader;
import com.android.systemui.statusbar.BaseStatusBar;
import com.android.systemui.statusbar.CommandQueue;
import com.android.systemui.statusbar.GestureRecorder;
@@ -86,6 +81,7 @@ import com.android.systemui.statusbar.RotationToggle;
import com.android.systemui.statusbar.SignalClusterView;
import com.android.systemui.statusbar.StatusBarIconView;
import com.android.systemui.statusbar.policy.BatteryController;
+import com.android.systemui.statusbar.policy.BluetoothController;
import com.android.systemui.statusbar.policy.DateView;
import com.android.systemui.statusbar.policy.IntruderAlertView;
import com.android.systemui.statusbar.policy.LocationController;
@@ -139,6 +135,7 @@ public class PhoneStatusBar extends BaseStatusBar {
PhoneStatusBarPolicy mIconPolicy;
// These are no longer handled by the policy, because we need custom strategies for them
+ BluetoothController mBluetoothController;
BatteryController mBatteryController;
LocationController mLocationController;
NetworkController mNetworkController;
@@ -317,9 +314,6 @@ public class PhoneStatusBar extends BaseStatusBar {
View.STATUS_BAR_DISABLE_NOTIFICATION_TICKER
| (mNotificationPanelIsFullScreenWidth ? 0 : View.STATUS_BAR_DISABLE_SYSTEM_INFO));
- // quick settings (WIP)
- mSettingsPanel = (PanelView) mStatusBarWindow.findViewById(R.id.settings_panel);
-
if (!ActivityManager.isHighEndGfx()) {
mStatusBarWindow.setBackground(null);
mNotificationPanel.setBackground(new FastColorDrawable(context.getResources().getColor(
@@ -394,9 +388,11 @@ public class PhoneStatusBar extends BaseStatusBar {
mBatteryController = new BatteryController(mContext);
mBatteryController.addIconView((ImageView)mStatusBarView.findViewById(R.id.battery));
mNetworkController = new NetworkController(mContext);
+ mBluetoothController = new BluetoothController(mContext);
final SignalClusterView signalCluster =
(SignalClusterView)mStatusBarView.findViewById(R.id.signal_cluster);
+
mNetworkController.addSignalCluster(signalCluster);
signalCluster.setNetworkController(mNetworkController);
@@ -434,6 +430,12 @@ public class PhoneStatusBar extends BaseStatusBar {
});
}
+ // Quick Settings (WIP)
+ mSettingsPanel = (PanelView) mStatusBarWindow.findViewById(R.id.settings_panel);
+ mSettingsPanel.setBar(mStatusBarView);
+ mSettingsPanel.setup(mNetworkController, mBluetoothController, mBatteryController,
+ mLocationController);
+
// final ImageView wimaxRSSI =
// (ImageView)sb.findViewById(R.id.wimax_signal);
// if (wimaxRSSI != null) {
@@ -1844,6 +1846,10 @@ public class PhoneStatusBar extends BaseStatusBar {
if (mClearButton instanceof TextView) {
((TextView)mClearButton).setText(context.getText(R.string.status_bar_clear_all_button));
}
+
+ // Update the QuickSettings container
+ ((SettingsPanelView) mSettingsPanel).updateResources();
+
loadDimens();
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickSettings.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickSettings.java
new file mode 100644
index 0000000..b0e7a9e
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickSettings.java
@@ -0,0 +1,787 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.phone;
+
+import android.app.Dialog;
+import android.bluetooth.BluetoothAdapter;
+import android.bluetooth.BluetoothAdapter.BluetoothStateChangeCallback;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.CursorLoader;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.Loader;
+import android.content.res.Resources;
+import android.database.Cursor;
+import android.graphics.drawable.ClipDrawable;
+import android.hardware.display.DisplayManager;
+import android.hardware.display.WifiDisplay;
+import android.hardware.display.WifiDisplayStatus;
+import android.net.Uri;
+import android.provider.ContactsContract;
+import android.provider.Settings;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.WindowManager;
+import android.widget.AdapterView;
+import android.widget.ArrayAdapter;
+import android.widget.Button;
+import android.widget.ListView;
+import android.widget.TextView;
+
+import java.util.ArrayList;
+import java.util.Comparator;
+
+import com.android.systemui.R;
+import com.android.systemui.statusbar.phone.QuickSettingsModel.State;
+import com.android.systemui.statusbar.policy.BatteryController;
+import com.android.systemui.statusbar.policy.BatteryController.BatteryStateChangeCallback;
+import com.android.systemui.statusbar.policy.BluetoothController;
+import com.android.systemui.statusbar.policy.LocationController;
+import com.android.systemui.statusbar.policy.LocationController.LocationGpsStateChangeCallback;
+import com.android.systemui.statusbar.policy.NetworkController;
+import com.android.systemui.statusbar.policy.NetworkController.NetworkSignalChangedCallback;
+
+class QuickSettingsModel implements BluetoothStateChangeCallback,
+ NetworkSignalChangedCallback,
+ BatteryStateChangeCallback,
+ LocationGpsStateChangeCallback {
+
+ /** Represents the state of a given attribute. */
+ static class State {
+ int iconId;
+ String label;
+ boolean enabled;
+ }
+ static class BatteryState extends State {
+ int batteryLevel;
+ boolean pluggedIn;
+ }
+
+ /** The callback to update a given tile. */
+ interface RefreshCallback {
+ public void refreshView(QuickSettingsTileView view, State state);
+ }
+
+ private Context mContext;
+
+ private QuickSettingsTileView mUserTile;
+ private RefreshCallback mUserCallback;
+ private State mUserState = new State();
+
+ private QuickSettingsTileView mAirplaneModeTile;
+ private RefreshCallback mAirplaneModeCallback;
+ private State mAirplaneModeState = new State();
+
+ private QuickSettingsTileView mWifiTile;
+ private RefreshCallback mWifiCallback;
+ private State mWifiState = new State();
+
+ private QuickSettingsTileView mWifiDisplayTile;
+ private RefreshCallback mWifiDisplayCallback;
+ private State mWifiDisplayState = new State();
+
+ private QuickSettingsTileView mRSSITile;
+ private RefreshCallback mRSSICallback;
+ private State mRSSIState = new State();
+
+ private QuickSettingsTileView mBluetoothTile;
+ private RefreshCallback mBluetoothCallback;
+ private State mBluetoothState = new State();
+
+ private QuickSettingsTileView mBatteryTile;
+ private RefreshCallback mBatteryCallback;
+ private BatteryState mBatteryState = new BatteryState();
+
+ private QuickSettingsTileView mLocationTile;
+ private RefreshCallback mLocationCallback;
+ private State mLocationState = new State();
+
+ public QuickSettingsModel(Context context) {
+ mContext = context;
+ }
+
+ // User
+ void addUserTile(QuickSettingsTileView view, RefreshCallback cb) {
+ mUserTile = view;
+ mUserCallback = cb;
+ mUserCallback.refreshView(mUserTile, mUserState);
+ }
+ void setUserTileInfo(String name) {
+ mUserState.label = name;
+ mUserCallback.refreshView(mUserTile, mUserState);
+ }
+
+ // Airplane Mode
+ void addAirplaneModeTile(QuickSettingsTileView view, RefreshCallback cb) {
+ mAirplaneModeTile = view;
+ mAirplaneModeTile.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ if (mAirplaneModeState.enabled) {
+ setAirplaneModeState(false);
+ } else {
+ setAirplaneModeState(true);
+ }
+ }
+ });
+ mAirplaneModeCallback = cb;
+ mAirplaneModeCallback.refreshView(mAirplaneModeTile, mAirplaneModeState);
+ }
+ private void setAirplaneModeState(boolean enabled) {
+ // TODO: Sets the view to be "awaiting" if not already awaiting
+
+ // Change the system setting
+ Settings.System.putInt(mContext.getContentResolver(), Settings.System.AIRPLANE_MODE_ON,
+ enabled ? 1 : 0);
+
+ // TODO: Update the UI to reflect system setting
+ // mCheckBoxPref.setChecked(enabled);
+
+ // Post the intent
+ Intent intent = new Intent(Intent.ACTION_AIRPLANE_MODE_CHANGED);
+ intent.putExtra("state", enabled);
+ mContext.sendBroadcast(intent);
+ }
+ // NetworkSignalChanged callback
+ @Override
+ public void onAirplaneModeChanged(boolean enabled) {
+ // TODO: If view is in awaiting state, disable
+ Resources r = mContext.getResources();
+ mAirplaneModeState.enabled = enabled;
+ mAirplaneModeState.iconId = (enabled ?
+ R.drawable.ic_qs_airplane_enabled :
+ R.drawable.ic_qs_airplane_normal);
+ mAirplaneModeCallback.refreshView(mAirplaneModeTile, mAirplaneModeState);
+ }
+
+ // Wifi
+ void addWifiTile(QuickSettingsTileView view, RefreshCallback cb) {
+ mWifiTile = view;
+ mWifiCallback = cb;
+ mWifiCallback.refreshView(mWifiTile, mWifiState);
+ }
+ // NetworkSignalChanged callback
+ @Override
+ public void onWifiSignalChanged(boolean enabled, String description) {
+ // TODO: If view is in awaiting state, disable
+ Resources r = mContext.getResources();
+ // TODO: Check if wifi is enabled
+ mWifiState.enabled = enabled;
+ mWifiState.iconId = (enabled ?
+ R.drawable.ic_qs_wifi_enabled :
+ R.drawable.ic_qs_wifi_normal);
+ mWifiState.label = (enabled ?
+ description :
+ r.getString(R.string.quick_settings_wifi_no_network));
+ mWifiCallback.refreshView(mWifiTile, mWifiState);
+ }
+
+ // RSSI
+ void addRSSITile(QuickSettingsTileView view, RefreshCallback cb) {
+ mRSSITile = view;
+ mRSSICallback = cb;
+ mRSSICallback.refreshView(mRSSITile, mRSSIState);
+ }
+ private void setRSSIState(boolean enabled) {
+ // TODO: Set RSSI enabled
+ // TODO: Sets the view to be "awaiting" if not already awaiting
+ }
+ // NetworkSignalChanged callback
+ @Override
+ public void onMobileDataSignalChanged(boolean enabled, String description) {
+ // TODO: If view is in awaiting state, disable
+ Resources r = mContext.getResources();
+ // TODO: Check if RSSI is enabled
+ mRSSIState.enabled = enabled;
+ mRSSIState.iconId = (enabled ?
+ R.drawable.ic_qs_rssi_enabled :
+ R.drawable.ic_qs_rssi_normal);
+ mRSSIState.label = (enabled ?
+ description :
+ r.getString(R.string.quick_settings_rssi_emergency_only));
+ mRSSICallback.refreshView(mRSSITile, mRSSIState);
+ }
+
+ // Bluetooth
+ void addBluetoothTile(QuickSettingsTileView view, RefreshCallback cb) {
+ mBluetoothTile = view;
+ mBluetoothTile.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ if (mBluetoothState.enabled) {
+ setBluetoothState(false);
+ } else {
+ setBluetoothState(true);
+ }
+ }
+ });
+ mBluetoothCallback = cb;
+
+ final BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
+ onBluetoothStateChange(adapter.isEnabled());
+ }
+ private void setBluetoothState(boolean enabled) {
+ // TODO: Sets the view to be "awaiting" if not already awaiting
+ final BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
+ if (adapter != null) {
+ if (enabled) {
+ adapter.enable();
+ } else {
+ adapter.disable();
+ }
+ }
+ }
+ // BluetoothController callback
+ @Override
+ public void onBluetoothStateChange(boolean on) {
+ // TODO: If view is in awaiting state, disable
+ Resources r = mContext.getResources();
+ mBluetoothState.enabled = on;
+ if (on) {
+ mBluetoothState.iconId = R.drawable.ic_qs_bluetooth_enabled;
+ } else {
+ mBluetoothState.iconId = R.drawable.ic_qs_bluetooth_normal;
+ }
+ mBluetoothCallback.refreshView(mBluetoothTile, mBluetoothState);
+ }
+
+ // Battery
+ void addBatteryTile(QuickSettingsTileView view, RefreshCallback cb) {
+ mBatteryTile = view;
+ mBatteryCallback = cb;
+ mBatteryCallback.refreshView(mBatteryTile, mBatteryState);
+ }
+ // BatteryController callback
+ @Override
+ public void onBatteryLevelChanged(int level, boolean pluggedIn) {
+ mBatteryState.batteryLevel = level;
+ mBatteryState.pluggedIn = pluggedIn;
+ mBatteryCallback.refreshView(mBatteryTile, mBatteryState);
+ }
+
+ // Location
+ void addLocationTile(QuickSettingsTileView view, RefreshCallback cb) {
+ mLocationTile = view;
+ mLocationCallback = cb;
+ mLocationCallback.refreshView(mLocationTile, mLocationState);
+ disableLocationTile();
+ }
+ private void enableLocationTile() {
+ mLocationTile.setVisibility(View.VISIBLE);
+ }
+ private void disableLocationTile() {
+ mLocationTile.setVisibility(View.GONE);
+ }
+ // LocationController callback
+ @Override
+ public void onLocationGpsStateChanged(boolean inUse, String description) {
+ if (inUse) {
+ mLocationState.enabled = inUse;
+ mLocationState.label = description;
+ mLocationCallback.refreshView(mLocationTile, mLocationState);
+ enableLocationTile();
+ } else {
+ disableLocationTile();
+ }
+ }
+
+ // Wifi Display
+ void addWifiDisplayTile(QuickSettingsTileView view, RefreshCallback cb) {
+ mWifiDisplayTile = view;
+ mWifiDisplayCallback = cb;
+ }
+ private void enableWifiDisplayTile() {
+ mWifiDisplayTile.setVisibility(View.VISIBLE);
+ }
+ private void disableWifiDisplayTile() {
+ mWifiDisplayTile.setVisibility(View.GONE);
+ }
+ public void onWifiDisplayStateChanged(WifiDisplayStatus status) {
+ if (status.isEnabled()) {
+ if (status.getActiveDisplay() != null) {
+ mWifiDisplayState.label = status.getActiveDisplay().getDeviceName();
+ } else {
+ mWifiDisplayState.label = mContext.getString(
+ R.string.quick_settings_wifi_display_no_connection_label);
+ }
+ mWifiDisplayCallback.refreshView(mWifiDisplayTile, mWifiDisplayState);
+ enableWifiDisplayTile();
+ } else {
+ disableWifiDisplayTile();
+ }
+ }
+
+}
+
+/**
+ *
+ */
+class QuickSettings {
+
+ private Context mContext;
+ private PanelBar mBar;
+ private QuickSettingsModel mModel;
+ private QuickSettingsContainerView mContainerView;
+
+ private DisplayManager mDisplayManager;
+ private WifiDisplayStatus mWifiDisplayStatus;
+ private WifiDisplayListAdapter mWifiDisplayListAdapter;
+
+ private CursorLoader mUserInfoLoader;
+
+ // The set of QuickSettingsTiles that have dynamic spans (and need to be updated on
+ // configuration change)
+ private final ArrayList<QuickSettingsTileView> mDynamicSpannedTiles =
+ new ArrayList<QuickSettingsTileView>();
+
+ public QuickSettings(Context context, QuickSettingsContainerView container) {
+ mDisplayManager = (DisplayManager) context.getSystemService(Context.DISPLAY_SERVICE);
+ mContext = context;
+ mContainerView = container;
+ mModel = new QuickSettingsModel(context);
+ mWifiDisplayStatus = new WifiDisplayStatus();
+ mWifiDisplayListAdapter = new WifiDisplayListAdapter(context);
+
+ IntentFilter filter = new IntentFilter();
+ filter.addAction(DisplayManager.ACTION_WIFI_DISPLAY_STATUS_CHANGED);
+ mContext.registerReceiver(mReceiver, filter);
+
+ setupQuickSettings();
+ updateWifiDisplayStatus();
+ updateResources();
+ }
+
+ void setBar(PanelBar bar) {
+ mBar = bar;
+ }
+
+ void setup(NetworkController networkController, BluetoothController bluetoothController,
+ BatteryController batteryController, LocationController locationController) {
+ networkController.addNetworkSignalChangedCallback(mModel);
+ bluetoothController.addStateChangedCallback(mModel);
+ batteryController.addStateChangedCallback(mModel);
+ locationController.addStateChangedCallback(mModel);
+ }
+
+ private void queryForUserInformation() {
+ Uri userContactUri = Uri.withAppendedPath(
+ ContactsContract.Profile.CONTENT_URI,
+ ContactsContract.Contacts.Data.CONTENT_DIRECTORY);
+
+ String[] selectArgs = {
+ ContactsContract.CommonDataKinds.StructuredName.DISPLAY_NAME,
+ ContactsContract.CommonDataKinds.Photo.PHOTO
+ };
+ String where = String.format("(%s = ? OR %s = ?) AND %s IS NULL",
+ ContactsContract.Contacts.Data.MIMETYPE,
+ ContactsContract.Contacts.Data.MIMETYPE,
+ ContactsContract.RawContacts.ACCOUNT_TYPE);
+ String[] whereArgs = {
+ ContactsContract.CommonDataKinds.StructuredName.CONTENT_ITEM_TYPE,
+ ContactsContract.CommonDataKinds.Photo.CONTENT_ITEM_TYPE
+ };
+
+ mUserInfoLoader = new CursorLoader(mContext, userContactUri, selectArgs, where, whereArgs,
+ null);
+ mUserInfoLoader.registerListener(0,
+ new Loader.OnLoadCompleteListener<Cursor>() {
+ @Override
+ public void onLoadComplete(Loader<Cursor> loader,
+ Cursor cursor) {
+ if (cursor.moveToFirst()) {
+ String name = cursor.getString(0); // DISPLAY_NAME
+ mModel.setUserTileInfo(name);
+ /*
+ byte[] photoData = cursor.getBlob(0);
+ Bitmap b =
+ BitmapFactory.decodeByteArray(photoData, 0, photoData.length);
+ */
+ }
+ mUserInfoLoader.stopLoading();
+ }
+ });
+ mUserInfoLoader.startLoading();
+ }
+
+ private void setupQuickSettings() {
+ // Setup the tiles that we are going to be showing (including the temporary ones)
+ LayoutInflater inflater = LayoutInflater.from(mContext);
+
+ addUserTiles(mContainerView, inflater);
+ addSystemTiles(mContainerView, inflater);
+ addTemporaryTiles(mContainerView, inflater);
+
+ queryForUserInformation();
+ }
+
+ private void addUserTiles(ViewGroup parent, LayoutInflater inflater) {
+ QuickSettingsTileView userTile = (QuickSettingsTileView)
+ inflater.inflate(R.layout.quick_settings_tile, parent, false);
+ userTile.setContent(R.layout.quick_settings_tile_user, inflater);
+ mModel.addUserTile(userTile, new QuickSettingsModel.RefreshCallback() {
+ @Override
+ public void refreshView(QuickSettingsTileView view, State state) {
+ TextView tv = (TextView) view.findViewById(R.id.user_textview);
+ tv.setText(state.label);
+ }
+ });
+ parent.addView(userTile);
+ mDynamicSpannedTiles.add(userTile);
+
+ // Time tile
+ QuickSettingsTileView timeTile = (QuickSettingsTileView)
+ inflater.inflate(R.layout.quick_settings_tile, parent, false);
+ timeTile.setContent(R.layout.quick_settings_tile_time, inflater);
+ parent.addView(timeTile);
+ mDynamicSpannedTiles.add(timeTile);
+
+ // Settings tile
+ QuickSettingsTileView settingsTile = (QuickSettingsTileView)
+ inflater.inflate(R.layout.quick_settings_tile, parent, false);
+ settingsTile.setContent(R.layout.quick_settings_tile_settings, inflater);
+ settingsTile.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ Intent intent = new Intent(android.provider.Settings.ACTION_SETTINGS);
+ intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+ mContext.startActivity(intent);
+ mBar.collapseAllPanels(true);
+ }
+ });
+ parent.addView(settingsTile);
+ mDynamicSpannedTiles.add(settingsTile);
+ }
+
+ private void addSystemTiles(ViewGroup parent, LayoutInflater inflater) {
+ // Wi-fi
+ QuickSettingsTileView wifiTile = (QuickSettingsTileView)
+ inflater.inflate(R.layout.quick_settings_tile, parent, false);
+ wifiTile.setContent(R.layout.quick_settings_tile_wifi, inflater);
+ wifiTile.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ Intent intent = new Intent(android.provider.Settings.ACTION_WIFI_SETTINGS);
+ intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+ mContext.startActivity(intent);
+ mBar.collapseAllPanels(true);
+ }
+ });
+ mModel.addWifiTile(wifiTile, new QuickSettingsModel.RefreshCallback() {
+ @Override
+ public void refreshView(QuickSettingsTileView view, State state) {
+ TextView tv = (TextView) view.findViewById(R.id.wifi_textview);
+ tv.setCompoundDrawablesRelativeWithIntrinsicBounds(0, state.iconId, 0, 0);
+ tv.setText(state.label);
+ }
+ });
+ parent.addView(wifiTile);
+
+ // RSSI
+ QuickSettingsTileView rssiTile = (QuickSettingsTileView)
+ inflater.inflate(R.layout.quick_settings_tile, parent, false);
+ rssiTile.setContent(R.layout.quick_settings_tile_rssi, inflater);
+ rssiTile.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ Intent intent = new Intent(android.provider.Settings.ACTION_WIRELESS_SETTINGS);
+ intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+ mContext.startActivity(intent);
+ mBar.collapseAllPanels(true);
+ }
+ });
+ mModel.addRSSITile(rssiTile, new QuickSettingsModel.RefreshCallback() {
+ @Override
+ public void refreshView(QuickSettingsTileView view, State state) {
+ TextView tv = (TextView) view.findViewById(R.id.rssi_textview);
+ tv.setCompoundDrawablesRelativeWithIntrinsicBounds(0, state.iconId, 0, 0);
+ tv.setText(state.label);
+ }
+ });
+ parent.addView(rssiTile);
+
+ // Battery
+ QuickSettingsTileView batteryTile = (QuickSettingsTileView)
+ inflater.inflate(R.layout.quick_settings_tile, parent, false);
+ batteryTile.setContent(R.layout.quick_settings_tile_battery, inflater);
+ batteryTile.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ Intent intent = new Intent(Intent.ACTION_POWER_USAGE_SUMMARY);
+ intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+ mContext.startActivity(intent);
+ mBar.collapseAllPanels(true);
+ }
+ });
+ mModel.addBatteryTile(batteryTile, new QuickSettingsModel.RefreshCallback() {
+ @Override
+ public void refreshView(QuickSettingsTileView view, State state) {
+ QuickSettingsModel.BatteryState batteryState =
+ (QuickSettingsModel.BatteryState) state;
+ TextView tv = (TextView) view.findViewById(R.id.battery_textview);
+ ClipDrawable drawable = (ClipDrawable) tv.getCompoundDrawables()[1];
+ drawable.setLevel((int) (10000 * (batteryState.batteryLevel / 100.0f)));
+ // TODO: use format string
+ tv.setText(batteryState.batteryLevel + "%");
+ }
+ });
+ parent.addView(batteryTile);
+
+ // Airplane Mode
+ QuickSettingsTileView airplaneTile = (QuickSettingsTileView)
+ inflater.inflate(R.layout.quick_settings_tile, parent, false);
+ airplaneTile.setContent(R.layout.quick_settings_tile_airplane, inflater);
+ mModel.addAirplaneModeTile(airplaneTile, new QuickSettingsModel.RefreshCallback() {
+ @Override
+ public void refreshView(QuickSettingsTileView view, State state) {
+ TextView tv = (TextView) view.findViewById(R.id.airplane_mode_textview);
+ tv.setCompoundDrawablesRelativeWithIntrinsicBounds(0, state.iconId, 0, 0);
+ }
+ });
+ parent.addView(airplaneTile);
+
+ // Bluetooth
+ QuickSettingsTileView bluetoothTile = (QuickSettingsTileView)
+ inflater.inflate(R.layout.quick_settings_tile, parent, false);
+ bluetoothTile.setContent(R.layout.quick_settings_tile_bluetooth, inflater);
+ mModel.addBluetoothTile(bluetoothTile, new QuickSettingsModel.RefreshCallback() {
+ @Override
+ public void refreshView(QuickSettingsTileView view, State state) {
+ TextView tv = (TextView) view.findViewById(R.id.bluetooth_textview);
+ tv.setCompoundDrawablesRelativeWithIntrinsicBounds(0, state.iconId, 0, 0);
+ }
+ });
+ parent.addView(bluetoothTile);
+
+ // Brightness
+ QuickSettingsTileView brightnessTile = (QuickSettingsTileView)
+ inflater.inflate(R.layout.quick_settings_tile, parent, false);
+ brightnessTile.setContent(R.layout.quick_settings_tile_brightness, inflater);
+ brightnessTile.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ Intent intent = new Intent(android.provider.Settings.ACTION_DISPLAY_SETTINGS);
+ intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+ mContext.startActivity(intent);
+ mBar.collapseAllPanels(true);
+ }
+ });
+ parent.addView(brightnessTile);
+ }
+
+ private void addTemporaryTiles(final ViewGroup parent, final LayoutInflater inflater) {
+ // Location
+ QuickSettingsTileView locationTile = (QuickSettingsTileView)
+ inflater.inflate(R.layout.quick_settings_tile, parent, false);
+ locationTile.setContent(R.layout.quick_settings_tile_location, inflater);
+ locationTile.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ Intent intent =
+ new Intent(android.provider.Settings.ACTION_LOCATION_SOURCE_SETTINGS);
+ intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+ mContext.startActivity(intent);
+ mBar.collapseAllPanels(true);
+ }
+ });
+ mModel.addLocationTile(locationTile, new QuickSettingsModel.RefreshCallback() {
+ @Override
+ public void refreshView(QuickSettingsTileView view, State state) {
+ TextView tv = (TextView) view.findViewById(R.id.location_textview);
+ tv.setText(state.label);
+ }
+ });
+ parent.addView(locationTile);
+
+ // Wifi Display
+ QuickSettingsTileView wifiDisplayTile = (QuickSettingsTileView)
+ inflater.inflate(R.layout.quick_settings_tile, parent, false);
+ wifiDisplayTile.setContent(R.layout.quick_settings_tile_wifi_display, inflater);
+ wifiDisplayTile.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ showWifiDisplayDialog();
+ mBar.collapseAllPanels(true);
+ }
+ });
+ mModel.addWifiDisplayTile(wifiDisplayTile, new QuickSettingsModel.RefreshCallback() {
+ @Override
+ public void refreshView(QuickSettingsTileView view, State state) {
+ TextView tv = (TextView) view.findViewById(R.id.wifi_display_textview);
+ tv.setText(state.label);
+ }
+ });
+ parent.addView(wifiDisplayTile);
+
+ /*
+ QuickSettingsTileView mediaTile = (QuickSettingsTileView)
+ inflater.inflate(R.layout.quick_settings_tile, parent, false);
+ mediaTile.setContent(R.layout.quick_settings_tile_media, inflater);
+ parent.addView(mediaTile);
+ QuickSettingsTileView imeTile = (QuickSettingsTileView)
+ inflater.inflate(R.layout.quick_settings_tile, parent, false);
+ imeTile.setContent(R.layout.quick_settings_tile_ime, inflater);
+ imeTile.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ parent.removeViewAt(0);
+ }
+ });
+ parent.addView(imeTile);
+ */
+ }
+
+ void updateResources() {
+ Resources r = mContext.getResources();
+
+ // Update the User, Time, and Settings tiles spans, and reset everything else
+ int span = r.getInteger(R.integer.quick_settings_user_time_settings_tile_span);
+ for (QuickSettingsTileView v : mDynamicSpannedTiles) {
+ v.setColumnSpan(span);
+ }
+ mContainerView.requestLayout();
+ }
+
+ private void showWifiDisplayDialog() {
+ mDisplayManager.scanWifiDisplays();
+ updateWifiDisplayStatus();
+
+ Dialog dialog = new Dialog(mContext);
+ dialog.setContentView(R.layout.wifi_display_dialog);
+ dialog.setCanceledOnTouchOutside(true);
+ dialog.setTitle(R.string.wifi_display_dialog_title);
+
+ Button scanButton = (Button)dialog.findViewById(R.id.scan);
+ scanButton.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ mDisplayManager.scanWifiDisplays();
+ }
+ });
+
+ Button disconnectButton = (Button)dialog.findViewById(R.id.disconnect);
+ disconnectButton.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ mDisplayManager.disconnectWifiDisplay();
+ }
+ });
+
+ ListView list = (ListView)dialog.findViewById(R.id.list);
+ list.setAdapter(mWifiDisplayListAdapter);
+ list.setOnItemClickListener(new AdapterView.OnItemClickListener() {
+ @Override
+ public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
+ WifiDisplay display = mWifiDisplayListAdapter.getItem(position);
+ mDisplayManager.connectWifiDisplay(display.getDeviceAddress());
+ }
+ });
+
+ dialog.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT);
+ dialog.show();
+ }
+
+ private void updateWifiDisplayStatus() {
+ applyWifiDisplayStatus(mDisplayManager.getWifiDisplayStatus());
+ }
+
+ private void applyWifiDisplayStatus(WifiDisplayStatus status) {
+ mWifiDisplayStatus = status;
+
+ mWifiDisplayListAdapter.clear();
+ mWifiDisplayListAdapter.addAll(status.getKnownDisplays());
+ if (status.getActiveDisplay() != null
+ && !contains(status.getKnownDisplays(), status.getActiveDisplay())) {
+ mWifiDisplayListAdapter.add(status.getActiveDisplay());
+ }
+ mWifiDisplayListAdapter.sort(mWifiDisplayComparator);
+
+ mModel.onWifiDisplayStateChanged(status);
+ }
+
+ private static boolean contains(WifiDisplay[] displays, WifiDisplay display) {
+ for (WifiDisplay d : displays) {
+ if (d.equals(display)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ if (intent.getAction().equals(DisplayManager.ACTION_WIFI_DISPLAY_STATUS_CHANGED)) {
+ WifiDisplayStatus status = (WifiDisplayStatus)intent.getParcelableExtra(
+ DisplayManager.EXTRA_WIFI_DISPLAY_STATUS);
+ applyWifiDisplayStatus(status);
+ }
+ }
+ };
+
+ private final class WifiDisplayListAdapter extends ArrayAdapter<WifiDisplay> {
+ private final LayoutInflater mInflater;
+
+ public WifiDisplayListAdapter(Context context) {
+ super(context, android.R.layout.simple_list_item_2);
+ mInflater = LayoutInflater.from(context);
+ }
+
+ @Override
+ public View getView(int position, View convertView, ViewGroup parent) {
+ WifiDisplay item = getItem(position);
+ View view = convertView;
+ if (view == null) {
+ view = mInflater.inflate(android.R.layout.simple_list_item_2,
+ parent, false);
+ }
+ TextView headline = (TextView) view.findViewById(android.R.id.text1);
+ TextView subText = (TextView) view.findViewById(android.R.id.text2);
+ headline.setText(item.getDeviceName());
+
+ int state = WifiDisplayStatus.DISPLAY_STATE_NOT_CONNECTED;
+ if (item.equals(mWifiDisplayStatus.getActiveDisplay())) {
+ state = mWifiDisplayStatus.getActiveDisplayState();
+ }
+ switch (state) {
+ case WifiDisplayStatus.DISPLAY_STATE_CONNECTING:
+ subText.setText(R.string.wifi_display_state_connecting);
+ break;
+ case WifiDisplayStatus.DISPLAY_STATE_CONNECTED:
+ subText.setText(R.string.wifi_display_state_connected);
+ break;
+ case WifiDisplayStatus.DISPLAY_STATE_NOT_CONNECTED:
+ default:
+ subText.setText(R.string.wifi_display_state_available);
+ break;
+ }
+ return view;
+ }
+ }
+
+ private final Comparator<WifiDisplay> mWifiDisplayComparator = new Comparator<WifiDisplay>() {
+ @Override
+ public int compare(WifiDisplay lhs, WifiDisplay rhs) {
+ int c = lhs.getDeviceName().compareToIgnoreCase(rhs.getDeviceName());
+ if (c == 0) {
+ c = lhs.getDeviceAddress().compareToIgnoreCase(rhs.getDeviceAddress());
+ }
+ return c;
+ }
+ };
+} \ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickSettingsContainerView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickSettingsContainerView.java
new file mode 100644
index 0000000..105ceb1
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickSettingsContainerView.java
@@ -0,0 +1,138 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.phone;
+
+import android.animation.LayoutTransition;
+import android.content.Context;
+import android.content.res.Resources;
+import android.util.AttributeSet;
+import android.view.ViewGroup;
+import android.widget.FrameLayout;
+
+import com.android.systemui.R;
+
+/**
+ *
+ */
+class QuickSettingsContainerView extends FrameLayout {
+
+ // The number of columns in the QuickSettings grid
+ private int mNumColumns;
+
+ // The gap between tiles in the QuickSettings grid
+ private float mCellGap;
+
+ public QuickSettingsContainerView(Context context, AttributeSet attrs) {
+ super(context, attrs);
+
+ updateResources();
+ }
+
+ @Override
+ protected void onFinishInflate() {
+ super.onFinishInflate();
+
+ // TODO: Setup the layout transitions
+ LayoutTransition transitions = getLayoutTransition();
+ }
+
+ void updateResources() {
+ Resources r = getContext().getResources();
+ mCellGap = r.getDimension(R.dimen.quick_settings_cell_gap);
+ mNumColumns = r.getInteger(R.integer.quick_settings_num_columns);
+ requestLayout();
+ }
+
+ @Override
+ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+ // Calculate the cell width dynamically
+ int width = MeasureSpec.getSize(widthMeasureSpec);
+ int height = MeasureSpec.getSize(heightMeasureSpec);
+ int availableWidth = (int) (width - getPaddingLeft() - getPaddingRight() -
+ (mNumColumns - 1) * mCellGap);
+ float cellWidth = availableWidth / mNumColumns;
+
+ // Update each of the children's widths accordingly to the cell width
+ int N = getChildCount();
+ int cellHeight = 0;
+ int cursor = 0;
+ for (int i = 0; i < N; ++i) {
+ // Update the child's width
+ QuickSettingsTileView v = (QuickSettingsTileView) getChildAt(i);
+ ViewGroup.MarginLayoutParams lp = (ViewGroup.MarginLayoutParams) v.getLayoutParams();
+ int colSpan = v.getColumnSpan();
+ lp.width = (int) ((colSpan * cellWidth) + (colSpan - 1) * mCellGap);
+
+ // Measure the child
+ v.setMinimumWidth(lp.width);
+ v.setMinimumHeight(lp.height);
+ int newWidthSpec = MeasureSpec.makeMeasureSpec(lp.width, MeasureSpec.AT_MOST);
+ int newHeightSpec = MeasureSpec.makeMeasureSpec(lp.height, MeasureSpec.AT_MOST);
+ v.measure(newWidthSpec, newHeightSpec);
+
+ // Save the cell height
+ if (cellHeight <= 0) {
+ cellHeight = v.getMeasuredHeight();
+ }
+ cursor += colSpan;
+ }
+
+ // Set the measured dimensions. We always fill the tray width, but wrap to the height of
+ // all the tiles.
+ int numRows = (int) Math.ceil((float) cursor / mNumColumns);
+ int newHeight = (int) ((numRows * cellHeight) + ((numRows - 1) * mCellGap)) +
+ getPaddingTop() + getPaddingBottom();
+ setMeasuredDimension(width, newHeight);
+ }
+
+ @Override
+ protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
+ int N = getChildCount();
+ int x = getPaddingLeft();
+ int y = getPaddingTop();
+ int cursor = 0;
+ for (int i = 0; i < N; ++i) {
+ QuickSettingsTileView v = (QuickSettingsTileView) getChildAt(i);
+ ViewGroup.LayoutParams lp = (ViewGroup.LayoutParams) v.getLayoutParams();
+ if (v.getVisibility() != GONE) {
+ int col = cursor % mNumColumns;
+ int colSpan = v.getColumnSpan();
+ int row = (int) (cursor / mNumColumns);
+
+ // Push the item to the next row if it can't fit on this one
+ if ((col + colSpan) > mNumColumns) {
+ x = getPaddingLeft();
+ y += lp.height + mCellGap;
+ row++;
+ }
+
+ // Layout the container
+ v.layout(x, y, x + lp.width, y + lp.height);
+
+ // Offset the position by the cell gap or reset the position and cursor when we
+ // reach the end of the row
+ cursor += v.getColumnSpan();
+ if (cursor < (((row + 1) * mNumColumns))) {
+ x += lp.width + mCellGap;
+ } else {
+ x = getPaddingLeft();
+ y += lp.height + mCellGap;
+ }
+ }
+ }
+ }
+} \ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickSettingsTileView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickSettingsTileView.java
new file mode 100644
index 0000000..8f5cde6
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickSettingsTileView.java
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.phone;
+
+import android.content.Context;
+import android.util.AttributeSet;
+import android.view.LayoutInflater;
+import android.widget.FrameLayout;
+
+/**
+ *
+ */
+class QuickSettingsTileView extends FrameLayout {
+
+ private int mColSpan;
+ private int mRowSpan;
+ private int mCellWidth;
+
+ public QuickSettingsTileView(Context context, AttributeSet attrs) {
+ super(context, attrs);
+
+ mColSpan = 1;
+ mRowSpan = 1;
+ }
+
+ void setColumnSpan(int span) {
+ mColSpan = span;
+ }
+
+ int getColumnSpan() {
+ return mColSpan;
+ }
+
+ void setContent(int layoutId, LayoutInflater inflater) {
+ inflater.inflate(layoutId, this);
+ }
+} \ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/SettingsPanelView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/SettingsPanelView.java
index fb1528f..f896d57 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/SettingsPanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/SettingsPanelView.java
@@ -16,15 +16,70 @@
package com.android.systemui.statusbar.phone;
+import android.animation.LayoutTransition;
import android.content.Context;
+import android.content.Intent;
+import android.content.res.Resources;
import android.util.AttributeSet;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+
+import com.android.systemui.R;
+import com.android.systemui.statusbar.BaseStatusBar;
+import com.android.systemui.statusbar.policy.BatteryController;
+import com.android.systemui.statusbar.policy.BluetoothController;
+import com.android.systemui.statusbar.policy.LocationController;
+import com.android.systemui.statusbar.policy.NetworkController;
public class SettingsPanelView extends PanelView {
+
+ private QuickSettings mQS;
+ private QuickSettingsContainerView mQSContainer;
+
public SettingsPanelView(Context context, AttributeSet attrs) {
super(context, attrs);
}
@Override
+ protected void onFinishInflate() {
+ super.onFinishInflate();
+
+ mQSContainer = (QuickSettingsContainerView) findViewById(R.id.quick_settings_container);
+ mQS = new QuickSettings(getContext(), mQSContainer);
+ }
+
+ @Override
+ public void setBar(PanelBar panelBar) {
+ super.setBar(panelBar);
+
+ if (mQS != null) {
+ mQS.setBar(panelBar);
+ }
+ }
+
+ @Override
+ public void setup(NetworkController networkController, BluetoothController bluetoothController,
+ BatteryController batteryController, LocationController locationController) {
+ super.setup(networkController, bluetoothController, batteryController, locationController);
+
+ if (mQS != null) {
+ mQS.setup(networkController, bluetoothController, batteryController,
+ locationController);
+ }
+ }
+
+ void updateResources() {
+ if (mQS != null) {
+ mQS.updateResources();
+ }
+ if (mQSContainer != null) {
+ mQSContainer.updateResources();
+ }
+ requestLayout();
+ }
+
+ @Override
public void fling(float vel, boolean always) {
((PhoneStatusBarView) mBar).mBar.getGestureRecorder().tag(
"fling " + ((vel > 0) ? "open" : "closed"),
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BatteryController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BatteryController.java
index ff418c4..7f9bcac 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BatteryController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BatteryController.java
@@ -18,6 +18,7 @@ package com.android.systemui.statusbar.policy;
import java.util.ArrayList;
+import android.bluetooth.BluetoothAdapter.BluetoothStateChangeCallback;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
@@ -36,6 +37,13 @@ public class BatteryController extends BroadcastReceiver {
private ArrayList<ImageView> mIconViews = new ArrayList<ImageView>();
private ArrayList<TextView> mLabelViews = new ArrayList<TextView>();
+ private ArrayList<BatteryStateChangeCallback> mChangeCallbacks =
+ new ArrayList<BatteryStateChangeCallback>();
+
+ public interface BatteryStateChangeCallback {
+ public void onBatteryLevelChanged(int level, boolean pluggedIn);
+ }
+
public BatteryController(Context context) {
mContext = context;
@@ -52,6 +60,10 @@ public class BatteryController extends BroadcastReceiver {
mLabelViews.add(v);
}
+ public void addStateChangedCallback(BatteryStateChangeCallback cb) {
+ mChangeCallbacks.add(cb);
+ }
+
public void onReceive(Context context, Intent intent) {
final String action = intent.getAction();
if (action.equals(Intent.ACTION_BATTERY_CHANGED)) {
@@ -73,6 +85,10 @@ public class BatteryController extends BroadcastReceiver {
v.setText(mContext.getString(R.string.status_bar_settings_battery_meter_format,
level));
}
+
+ for (BatteryStateChangeCallback cb : mChangeCallbacks) {
+ cb.onBatteryLevelChanged(level, plugged);
+ }
}
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BluetoothController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BluetoothController.java
index 603808e..e517dde 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BluetoothController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BluetoothController.java
@@ -16,9 +16,8 @@
package com.android.systemui.statusbar.policy;
-import java.util.ArrayList;
-
import android.bluetooth.BluetoothAdapter;
+import android.bluetooth.BluetoothAdapter.BluetoothStateChangeCallback;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
@@ -26,6 +25,8 @@ import android.content.IntentFilter;
import android.view.View;
import android.widget.ImageView;
+import java.util.ArrayList;
+
import com.android.systemui.R;
public class BluetoothController extends BroadcastReceiver {
@@ -38,6 +39,9 @@ public class BluetoothController extends BroadcastReceiver {
private int mContentDescriptionId = 0;
private boolean mEnabled = false;
+ private ArrayList<BluetoothStateChangeCallback> mChangeCallbacks =
+ new ArrayList<BluetoothStateChangeCallback>();
+
public BluetoothController(Context context) {
mContext = context;
@@ -58,6 +62,10 @@ public class BluetoothController extends BroadcastReceiver {
mIconViews.add(v);
}
+ public void addStateChangedCallback(BluetoothStateChangeCallback cb) {
+ mChangeCallbacks.add(cb);
+ }
+
@Override
public void onReceive(Context context, Intent intent) {
final String action = intent.getAction();
@@ -98,5 +106,8 @@ public class BluetoothController extends BroadcastReceiver {
? null
: mContext.getString(mContentDescriptionId));
}
+ for (BluetoothStateChangeCallback cb : mChangeCallbacks) {
+ cb.onBluetoothStateChange(mEnabled);
+ }
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/DateView.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/DateView.java
index c19550b..640dcca 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/DateView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/DateView.java
@@ -30,7 +30,7 @@ import com.android.systemui.R;
import java.util.Date;
-public final class DateView extends TextView {
+public class DateView extends TextView {
private static final String TAG = "DateView";
private boolean mAttachedToWindow;
@@ -86,7 +86,7 @@ public final class DateView extends TextView {
return 0;
}
- private final void updateClock() {
+ protected void updateClock() {
final Context context = getContext();
Date now = new Date();
CharSequence dow = DateFormat.format("EEEE", now);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/LocationController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/LocationController.java
index bec5d72..4bf03e7 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/LocationController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/LocationController.java
@@ -37,6 +37,7 @@ import android.app.INotificationManager;
import com.android.internal.statusbar.StatusBarNotification;
import com.android.systemui.R;
+import com.android.systemui.statusbar.policy.BatteryController.BatteryStateChangeCallback;
public class LocationController extends BroadcastReceiver {
private static final String TAG = "StatusBar.LocationController";
@@ -47,6 +48,13 @@ public class LocationController extends BroadcastReceiver {
private INotificationManager mNotificationService;
+ private ArrayList<LocationGpsStateChangeCallback> mChangeCallbacks =
+ new ArrayList<LocationGpsStateChangeCallback>();
+
+ public interface LocationGpsStateChangeCallback {
+ public void onLocationGpsStateChanged(boolean inUse, String description);
+ }
+
public LocationController(Context context) {
mContext = context;
@@ -60,6 +68,10 @@ public class LocationController extends BroadcastReceiver {
mNotificationService = nm.getService();
}
+ public void addStateChangedCallback(LocationGpsStateChangeCallback cb) {
+ mChangeCallbacks.add(cb);
+ }
+
@Override
public void onReceive(Context context, Intent intent) {
final String action = intent.getAction();
@@ -89,12 +101,14 @@ public class LocationController extends BroadcastReceiver {
if (visible) {
Intent gpsIntent = new Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS);
gpsIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+
PendingIntent pendingIntent = PendingIntent.getActivityAsUser(context, 0,
gpsIntent, 0, null, UserHandle.CURRENT);
+ String text = mContext.getText(textResId).toString();
Notification n = new Notification.Builder(mContext)
.setSmallIcon(iconId)
- .setContentTitle(mContext.getText(textResId))
+ .setContentTitle(text)
.setOngoing(true)
.setContentIntent(pendingIntent)
.getNotification();
@@ -117,6 +131,10 @@ public class LocationController extends BroadcastReceiver {
mNotificationService.cancelNotificationWithTag(
mContext.getPackageName(), null,
GPS_NOTIFICATION_ID, UserHandle.USER_CURRENT);
+
+ for (LocationGpsStateChangeCallback cb : mChangeCallbacks) {
+ cb.onLocationGpsStateChanged(false, null);
+ }
}
} catch (android.os.RemoteException ex) {
// well, it was worth a shot
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkController.java
index d94c6b2..23f27e7 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkController.java
@@ -148,6 +148,8 @@ public class NetworkController extends BroadcastReceiver {
ArrayList<TextView> mWifiLabelViews = new ArrayList<TextView>();
ArrayList<TextView> mEmergencyLabelViews = new ArrayList<TextView>();
ArrayList<SignalCluster> mSignalClusters = new ArrayList<SignalCluster>();
+ ArrayList<NetworkSignalChangedCallback> mSignalsChangedCallbacks =
+ new ArrayList<NetworkSignalChangedCallback>();
int mLastPhoneSignalIconId = -1;
int mLastDataDirectionIconId = -1;
int mLastDataDirectionOverlayIconId = -1;
@@ -172,6 +174,12 @@ public class NetworkController extends BroadcastReceiver {
void setIsAirplaneMode(boolean is, int airplaneIcon);
}
+ public interface NetworkSignalChangedCallback {
+ void onWifiSignalChanged(boolean enabled, String description);
+ void onMobileDataSignalChanged(boolean enabled, String description);
+ void onAirplaneModeChanged(boolean enabled);
+ }
+
/**
* Construct this controller object and register for updates.
*/
@@ -299,6 +307,11 @@ public class NetworkController extends BroadcastReceiver {
refreshSignalCluster(cluster);
}
+ public void addNetworkSignalChangedCallback(NetworkSignalChangedCallback cb) {
+ mSignalsChangedCallbacks.add(cb);
+ notifySignalsChangedCallbacks(cb);
+ }
+
public void refreshSignalCluster(SignalCluster cluster) {
cluster.setWifiIndicators(
// only show wifi in the cluster if connected or if wifi-only
@@ -329,6 +342,27 @@ public class NetworkController extends BroadcastReceiver {
cluster.setIsAirplaneMode(mAirplaneMode, mAirplaneIconId);
}
+ void notifySignalsChangedCallbacks(NetworkSignalChangedCallback cb) {
+ // only show wifi in the cluster if connected or if wifi-only
+ boolean wifiEnabled = mWifiEnabled && (mWifiConnected || !mHasMobileDataFeature);
+ String wifiDesc = wifiEnabled ?
+ mWifiSsid : null;
+ cb.onWifiSignalChanged(wifiEnabled, wifiDesc);
+
+ if (isEmergencyOnly()) {
+ cb.onMobileDataSignalChanged(false, null);
+ } else {
+ if (mIsWimaxEnabled && mWimaxConnected) {
+ // wimax is special
+ cb.onMobileDataSignalChanged(true, mNetworkName);
+ } else {
+ // normal mobile data
+ cb.onMobileDataSignalChanged(mHasMobileDataFeature, mNetworkName);
+ }
+ }
+ cb.onAirplaneModeChanged(mAirplaneMode);
+ }
+
public void setStackedMode(boolean stacked) {
mDataAndWifiStacked = true;
}
@@ -1124,6 +1158,9 @@ public class NetworkController extends BroadcastReceiver {
for (SignalCluster cluster : mSignalClusters) {
refreshSignalCluster(cluster);
}
+ for (NetworkSignalChangedCallback cb : mSignalsChangedCallbacks) {
+ notifySignalsChangedCallbacks(cb);
+ }
}
if (mLastAirplaneMode != mAirplaneMode) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/QuickSettingsDateView.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/QuickSettingsDateView.java
new file mode 100644
index 0000000..c52f94b
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/QuickSettingsDateView.java
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.policy;
+
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.text.format.DateFormat;
+import android.util.AttributeSet;
+import android.view.View;
+import android.view.ViewParent;
+import android.widget.TextView;
+
+import com.android.systemui.R;
+
+import java.util.Date;
+
+public final class QuickSettingsDateView extends DateView {
+
+ public QuickSettingsDateView(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ }
+
+ protected void updateClock() {
+ final Context context = getContext();
+ Date now = new Date();
+ CharSequence dow = DateFormat.format("MMM d, yyyy", now);
+ setText(dow);
+ }
+}
diff --git a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
index 54cf73a..6c62680 100755
--- a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
+++ b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
@@ -4152,7 +4152,7 @@ public class PhoneWindowManager implements WindowManagerPolicy {
} catch (ActivityNotFoundException e) {
}
}
- mContext.startActivity(mHomeIntent);
+ mContext.startActivityAsUser(mHomeIntent, UserHandle.CURRENT);
}
/**
@@ -4181,22 +4181,22 @@ public class PhoneWindowManager implements WindowManagerPolicy {
Intent dock = createHomeDockIntent();
if (dock != null) {
int result = ActivityManagerNative.getDefault()
- .startActivity(null, dock,
+ .startActivityAsUser(null, dock,
dock.resolveTypeIfNeeded(mContext.getContentResolver()),
null, null, 0,
ActivityManager.START_FLAG_ONLY_IF_NEEDED,
- null, null, null);
+ null, null, null, UserHandle.USER_CURRENT);
if (result == ActivityManager.START_RETURN_INTENT_TO_CALLER) {
return false;
}
}
}
int result = ActivityManagerNative.getDefault()
- .startActivity(null, mHomeIntent,
+ .startActivityAsUser(null, mHomeIntent,
mHomeIntent.resolveTypeIfNeeded(mContext.getContentResolver()),
null, null, 0,
ActivityManager.START_FLAG_ONLY_IF_NEEDED,
- null, null, null);
+ null, null, null, UserHandle.USER_CURRENT);
if (result == ActivityManager.START_RETURN_INTENT_TO_CALLER) {
return false;
}
diff --git a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardHostView.java b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardHostView.java
index 00bc9be..e170ec1 100644
--- a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardHostView.java
+++ b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardHostView.java
@@ -62,35 +62,13 @@ public class KeyguardHostView extends KeyguardViewBase {
private static final String KEYGUARD_WIDGET_PREFS = "keyguard_widget_prefs";
private static final String TAG = "KeyguardViewHost";
-
- private static final int SECURITY_SELECTOR_ID = R.id.keyguard_selector_view;
- private static final int SECURITY_PATTERN_ID = R.id.keyguard_pattern_view;
- private static final int SECURITY_PASSWORD_ID = R.id.keyguard_password_view;
- private static final int SECURITY_BIOMETRIC_ID = R.id.keyguard_face_unlock_view;
- private static final int SECURITY_SIM_PIN_ID = R.id.keyguard_sim_pin_view;
- private static final int SECURITY_SIM_PUK_ID = R.id.keyguard_sim_puk_view;
- private static final int SECURITY_ACCOUNT_ID = R.id.keyguard_account_view;
-
private AppWidgetHost mAppWidgetHost;
private KeyguardWidgetPager mAppWidgetContainer;
- private ViewFlipper mViewFlipper;
+ private ViewFlipper mSecurityViewContainer;
private boolean mEnableMenuKey;
private boolean mIsVerifyUnlockOnly;
private boolean mEnableFallback; // TODO: This should get the value from KeyguardPatternView
- private int mCurrentSecurityId = SECURITY_SELECTOR_ID;
-
- // KeyguardSecurityViews
- final private int [] mViewIds = {
- SECURITY_SELECTOR_ID,
- SECURITY_PATTERN_ID,
- SECURITY_PASSWORD_ID,
- SECURITY_BIOMETRIC_ID,
- SECURITY_SIM_PIN_ID,
- SECURITY_SIM_PUK_ID,
- SECURITY_ACCOUNT_ID,
- };
-
- private ArrayList<View> mViews = new ArrayList<View>(mViewIds.length);
+ private SecurityMode mCurrentSecuritySelection = SecurityMode.None;
protected Runnable mLaunchRunnable;
@@ -125,33 +103,31 @@ public class KeyguardHostView extends KeyguardViewBase {
protected void onFinishInflate() {
mAppWidgetContainer = (KeyguardWidgetPager) findViewById(R.id.app_widget_container);
mAppWidgetContainer.setVisibility(VISIBLE);
+ mSecurityViewContainer = (ViewFlipper) findViewById(R.id.view_flipper);
+ updateSecurityViews();
+ }
- // View Flipper
- mViewFlipper = (ViewFlipper) findViewById(R.id.view_flipper);
+ private void updateSecurityViews() {
+ int children = mSecurityViewContainer.getChildCount();
+ for (int i = 0; i < children; i++) {
+ updateSecurityView(mSecurityViewContainer.getChildAt(i));
+ }
+ }
- // Initialize all security views
- for (int i = 0; i < mViewIds.length; i++) {
- View view = findViewById(mViewIds[i]);
- mViews.add(view);
- if (view != null) {
- ((KeyguardSecurityView) view).setKeyguardCallback(mCallback);
- } else {
- Log.v("*********", "Can't find view id " + mViewIds[i]);
- }
+ private void updateSecurityView(View view) {
+ if (view instanceof KeyguardSecurityView) {
+ KeyguardSecurityView ksv = (KeyguardSecurityView) view;
+ ksv.setKeyguardCallback(mCallback);
+ ksv.setLockPatternUtils(mLockPatternUtils);
+ } else {
+ Log.w(TAG, "View " + view + " is not a KeyguardSecurityView");
}
}
void setLockPatternUtils(LockPatternUtils utils) {
mSecurityModel.setLockPatternUtils(utils);
mLockPatternUtils = utils;
- for (int i = 0; i < mViews.size(); i++) {
- KeyguardSecurityView ksv = (KeyguardSecurityView) mViews.get(i);
- if (ksv != null) {
- ksv.setLockPatternUtils(utils);
- } else {
- Log.w(TAG, "**** ksv was null at " + i);
- }
- }
+ updateSecurityViews();
}
@Override
@@ -313,7 +289,7 @@ public class KeyguardHostView extends KeyguardViewBase {
showTimeout = false; // don't show both dialogs
} else if (failedAttempts >= LockPatternUtils.FAILED_ATTEMPTS_BEFORE_RESET) {
mLockPatternUtils.setPermanentlyLocked(true);
- showSecurityScreen(SECURITY_ACCOUNT_ID);
+ showSecurityScreen(SecurityMode.Account);
// don't show timeout dialog because we show account unlock screen next
showTimeout = false;
}
@@ -333,56 +309,53 @@ public class KeyguardHostView extends KeyguardViewBase {
*/
private void showBackupSecurity() {
SecurityMode currentMode = mSecurityModel.getAlternateFor(mSecurityModel.getSecurityMode());
- SecurityMode backup = mSecurityModel.getBackupFor(currentMode);
- showSecurityScreen(getSecurityViewIdForMode(backup));
+ showSecurityScreen(mSecurityModel.getBackupFor(currentMode));
}
private void showNextSecurityScreenOrFinish(boolean authenticated) {
boolean finish = false;
- if (SECURITY_SELECTOR_ID == mCurrentSecurityId) {
+ if (SecurityMode.None == mCurrentSecuritySelection) {
SecurityMode securityMode = mSecurityModel.getSecurityMode();
// Allow an alternate, such as biometric unlock
securityMode = mSecurityModel.getAlternateFor(securityMode);
- int realSecurityId = getSecurityViewIdForMode(securityMode);
- if (SECURITY_SELECTOR_ID == realSecurityId) {
+ if (SecurityMode.None == securityMode) {
finish = true; // no security required
} else {
- showSecurityScreen(realSecurityId); // switch to the "real" security view
+ showSecurityScreen(securityMode); // switch to the alternate security view
}
} else if (authenticated) {
- switch (mCurrentSecurityId) {
- case SECURITY_PATTERN_ID:
- case SECURITY_PASSWORD_ID:
- case SECURITY_ACCOUNT_ID:
- case SECURITY_BIOMETRIC_ID:
+ switch (mCurrentSecuritySelection) {
+ case Pattern:
+ case Password:
+ case Account:
+ case Biometric:
finish = true;
break;
- case SECURITY_SIM_PIN_ID:
- case SECURITY_SIM_PUK_ID:
+ case SimPin:
+ case SimPuk:
// Shortcut for SIM PIN/PUK to go to directly to user's security screen or home
SecurityMode securityMode = mSecurityModel.getSecurityMode();
if (securityMode != SecurityMode.None) {
- showSecurityScreen(getSecurityViewIdForMode(securityMode));
+ showSecurityScreen(securityMode);
} else {
finish = true;
}
break;
default:
- showSecurityScreen(SECURITY_SELECTOR_ID);
+ showSecurityScreen(SecurityMode.None);
break;
}
} else {
// Not authenticated but we were asked to dismiss so go back to selector screen.
- showSecurityScreen(SECURITY_SELECTOR_ID);
+ showSecurityScreen(SecurityMode.None);
}
if (finish) {
// If there's a pending runnable because the user interacted with a widget
// and we're leaving keyguard, then run it.
if (mLaunchRunnable != null) {
mLaunchRunnable.run();
- mViewFlipper.setDisplayedChild(0);
mLaunchRunnable = null;
}
mViewMediatorCallback.keyguardDone(true);
@@ -438,28 +411,38 @@ public class KeyguardHostView extends KeyguardViewBase {
mLaunchRunnable = runnable;
}
- private KeyguardSecurityView getSecurityView(int securitySelectorId) {
- final int children = mViewFlipper.getChildCount();
+ private KeyguardSecurityView getSecurityView(SecurityMode securityMode) {
+ final int securityViewIdForMode = getSecurityViewIdForMode(securityMode);
+ KeyguardSecurityView view = null;
+ final int children = mSecurityViewContainer.getChildCount();
for (int child = 0; child < children; child++) {
- if (mViewFlipper.getChildAt(child).getId() == securitySelectorId) {
- return ((KeyguardSecurityView)mViewFlipper.getChildAt(child));
+ if (mSecurityViewContainer.getChildAt(child).getId() == securityViewIdForMode) {
+ view = ((KeyguardSecurityView)mSecurityViewContainer.getChildAt(child));
+ break;
}
}
- return null;
+ if (view == null) {
+ final LayoutInflater inflater = LayoutInflater.from(mContext);
+ View v = inflater.inflate(getLayoutIdFor(securityMode), this, false);
+ mSecurityViewContainer.addView(v);
+ updateSecurityView(v);
+ view = (KeyguardSecurityView) v;
+ }
+ return view;
}
/**
* Switches to the given security view unless it's already being shown, in which case
* this is a no-op.
*
- * @param securityViewId
+ * @param securityMode
*/
- private void showSecurityScreen(int securityViewId) {
+ private void showSecurityScreen(SecurityMode securityMode) {
- if (securityViewId == mCurrentSecurityId) return;
+ if (securityMode == mCurrentSecuritySelection) return;
- KeyguardSecurityView oldView = getSecurityView(mCurrentSecurityId);
- KeyguardSecurityView newView = getSecurityView(securityViewId);
+ KeyguardSecurityView oldView = getSecurityView(mCurrentSecuritySelection);
+ KeyguardSecurityView newView = getSecurityView(securityMode);
// Emulate Activity life cycle
oldView.onPause();
@@ -468,45 +451,46 @@ public class KeyguardHostView extends KeyguardViewBase {
mViewMediatorCallback.setNeedsInput(newView.needsInput());
// Find and show this child.
- final int childCount = mViewFlipper.getChildCount();
+ final int childCount = mSecurityViewContainer.getChildCount();
// If we're go to/from the selector view, do flip animation, otherwise use fade animation.
- final boolean doFlip = mCurrentSecurityId == SECURITY_SELECTOR_ID
- || securityViewId == SECURITY_SELECTOR_ID;
+ final boolean doFlip = mCurrentSecuritySelection == SecurityMode.None
+ || securityMode == SecurityMode.None;
final int inAnimation = doFlip ? R.anim.keyguard_security_animate_in
: R.anim.keyguard_security_fade_in;
final int outAnimation = doFlip ? R.anim.keyguard_security_animate_out
: R.anim.keyguard_security_fade_out;
- mViewFlipper.setInAnimation(AnimationUtils.loadAnimation(mContext, inAnimation));
- mViewFlipper.setOutAnimation(AnimationUtils.loadAnimation(mContext, outAnimation));
+ mSecurityViewContainer.setInAnimation(AnimationUtils.loadAnimation(mContext, inAnimation));
+ mSecurityViewContainer.setOutAnimation(AnimationUtils.loadAnimation(mContext, outAnimation));
+ final int securityViewIdForMode = getSecurityViewIdForMode(securityMode);
for (int i = 0; i < childCount; i++) {
- if (securityViewId == mViewFlipper.getChildAt(i).getId()) {
- mViewFlipper.setDisplayedChild(i);
+ if (mSecurityViewContainer.getChildAt(i).getId() == securityViewIdForMode) {
+ mSecurityViewContainer.setDisplayedChild(i);
break;
}
}
// Discard current runnable if we're switching back to the selector view
- if (securityViewId == SECURITY_SELECTOR_ID) {
+ if (securityMode == SecurityMode.None) {
setOnDismissRunnable(null);
}
- mCurrentSecurityId = securityViewId;
+ mCurrentSecuritySelection = securityMode;
}
@Override
public void onScreenTurnedOn() {
if (DEBUG) Log.d(TAG, "screen on");
- showSecurityScreen(mCurrentSecurityId);
- getSecurityView(mCurrentSecurityId).onResume();
+ showSecurityScreen(mCurrentSecuritySelection);
+ getSecurityView(mCurrentSecuritySelection).onResume();
}
@Override
public void onScreenTurnedOff() {
if (DEBUG) Log.d(TAG, "screen off");
- showSecurityScreen(SECURITY_SELECTOR_ID);
- getSecurityView(mCurrentSecurityId).onPause();
+ showSecurityScreen(SecurityMode.None);
+ getSecurityView(mCurrentSecuritySelection).onPause();
}
@Override
@@ -537,7 +521,7 @@ public class KeyguardHostView extends KeyguardViewBase {
if (DEBUG) Log.d(TAG, "onWakeKey");
if (keyCode == KeyEvent.KEYCODE_MENU && isSecure()) {
if (DEBUG) Log.d(TAG, "switching screens to unlock screen because wake key was MENU");
- showSecurityScreen(SECURITY_SELECTOR_ID);
+ showSecurityScreen(SecurityMode.None);
mViewMediatorCallback.pokeWakelock();
} else {
if (DEBUG) Log.d(TAG, "poking wake lock immediately");
@@ -557,23 +541,37 @@ public class KeyguardHostView extends KeyguardViewBase {
} else {
// otherwise, go to the unlock screen, see if they can verify it
mIsVerifyUnlockOnly = true;
- showSecurityScreen(getSecurityViewIdForMode(securityMode));
+ showSecurityScreen(securityMode);
}
}
private int getSecurityViewIdForMode(SecurityMode securityMode) {
switch (securityMode) {
- case None: return SECURITY_SELECTOR_ID;
- case Pattern: return SECURITY_PATTERN_ID;
- case Password: return SECURITY_PASSWORD_ID;
- case Biometric: return SECURITY_BIOMETRIC_ID;
- case Account: return SECURITY_ACCOUNT_ID;
- case SimPin: return SECURITY_SIM_PIN_ID;
- case SimPuk: return SECURITY_SIM_PUK_ID;
+ case None: return R.id.keyguard_selector_view;
+ case Pattern: return R.id.keyguard_pattern_view;
+ case Password: return R.id.keyguard_password_view;
+ case Biometric: return R.id.keyguard_face_unlock_view;
+ case Account: return R.id.keyguard_account_view;
+ case SimPin: return R.id.keyguard_sim_pin_view;
+ case SimPuk: return R.id.keyguard_sim_puk_view;
}
return 0;
}
+ private int getLayoutIdFor(SecurityMode securityMode) {
+ switch (securityMode) {
+ case None: return R.layout.keyguard_selector_view;
+ case Pattern: return R.layout.keyguard_pattern_view;
+ case Password: return R.layout.keyguard_password_view;
+ case Biometric: return R.layout.keyguard_face_unlock_view;
+ case Account: return R.layout.keyguard_account_view;
+ case SimPin: return R.layout.keyguard_sim_pin_view;
+ case SimPuk: return R.layout.keyguard_sim_puk_view;
+ default:
+ throw new RuntimeException("No layout for securityMode " + securityMode);
+ }
+ }
+
private void addWidget(int appId) {
AppWidgetManager appWidgetManager = AppWidgetManager.getInstance(mContext);
AppWidgetProviderInfo appWidgetInfo = appWidgetManager.getAppWidgetInfo(appId);
diff --git a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardPasswordView.java b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardPasswordView.java
index b2ce73e..7e9aa43 100644
--- a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardPasswordView.java
+++ b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardPasswordView.java
@@ -68,6 +68,9 @@ public class KeyguardPasswordView extends LinearLayout
// any passwords with length less than or equal to this length.
private static final int MINIMUM_PASSWORD_LENGTH_BEFORE_REPORT = 3;
+ // Enable this if we want to hide the on-screen PIN keyboard when a physical one is showing
+ private static final boolean ENABLE_HIDE_KEYBOARD = false;
+
public KeyguardPasswordView(Context context) {
super(context);
}
@@ -123,10 +126,13 @@ public class KeyguardPasswordView extends LinearLayout
mKeyboardHelper.setKeyboardMode(PasswordEntryKeyboardHelper.KEYBOARD_MODE_ALPHA);
mKeyboardView.setVisibility(View.GONE);
} else {
- // Use lockscreen's numeric keyboard if the physical keyboard isn't showing
mKeyboardHelper.setKeyboardMode(PasswordEntryKeyboardHelper.KEYBOARD_MODE_NUMERIC);
- mKeyboardView.setVisibility(getResources().getConfiguration().hardKeyboardHidden
- == Configuration.HARDKEYBOARDHIDDEN_NO ? View.INVISIBLE : View.VISIBLE);
+
+ // Use lockscreen's numeric keyboard if the physical keyboard isn't showing
+ boolean hardKeyboardVisible = getResources().getConfiguration().hardKeyboardHidden
+ == Configuration.HARDKEYBOARDHIDDEN_NO;
+ mKeyboardView.setVisibility(
+ (ENABLE_HIDE_KEYBOARD && hardKeyboardVisible) ? View.INVISIBLE : View.VISIBLE);
// The delete button is of the PIN keyboard itself in some (e.g. tablet) layouts,
// not a separate view
diff --git a/services/input/InputReader.cpp b/services/input/InputReader.cpp
index 6d63998..513dc13 100644
--- a/services/input/InputReader.cpp
+++ b/services/input/InputReader.cpp
@@ -203,34 +203,18 @@ static void synthesizeButtonKeys(InputReaderContext* context, int32_t action,
// --- InputReaderConfiguration ---
-bool InputReaderConfiguration::getDisplayInfo(int32_t displayId, bool external,
- int32_t* width, int32_t* height, int32_t* orientation) const {
- if (displayId == 0) {
- const DisplayInfo& info = external ? mExternalDisplay : mInternalDisplay;
- if (info.width > 0 && info.height > 0) {
- if (width) {
- *width = info.width;
- }
- if (height) {
- *height = info.height;
- }
- if (orientation) {
- *orientation = info.orientation;
- }
- return true;
- }
+bool InputReaderConfiguration::getDisplayInfo(bool external, DisplayViewport* outViewport) const {
+ const DisplayViewport& viewport = external ? mExternalDisplay : mInternalDisplay;
+ if (viewport.displayId >= 0) {
+ *outViewport = viewport;
+ return true;
}
return false;
}
-void InputReaderConfiguration::setDisplayInfo(int32_t displayId, bool external,
- int32_t width, int32_t height, int32_t orientation) {
- if (displayId == 0) {
- DisplayInfo& info = external ? mExternalDisplay : mInternalDisplay;
- info.width = width;
- info.height = height;
- info.orientation = orientation;
- }
+void InputReaderConfiguration::setDisplayInfo(bool external, const DisplayViewport& viewport) {
+ DisplayViewport& v = external ? mExternalDisplay : mInternalDisplay;
+ v = viewport;
}
@@ -2001,9 +1985,11 @@ void KeyboardInputMapper::configure(nsecs_t when,
}
if (!changes || (changes & InputReaderConfiguration::CHANGE_DISPLAY_INFO)) {
- if (mParameters.orientationAware && mParameters.associatedDisplayId >= 0) {
- if (!config->getDisplayInfo(mParameters.associatedDisplayId,
- false /*external*/, NULL, NULL, &mOrientation)) {
+ if (mParameters.orientationAware && mParameters.hasAssociatedDisplay) {
+ DisplayViewport v;
+ if (config->getDisplayInfo(false /*external*/, &v)) {
+ mOrientation = v.orientation;
+ } else {
mOrientation = DISPLAY_ORIENTATION_0;
}
} else {
@@ -2017,16 +2003,16 @@ void KeyboardInputMapper::configureParameters() {
getDevice()->getConfiguration().tryGetProperty(String8("keyboard.orientationAware"),
mParameters.orientationAware);
- mParameters.associatedDisplayId = -1;
+ mParameters.hasAssociatedDisplay = false;
if (mParameters.orientationAware) {
- mParameters.associatedDisplayId = 0;
+ mParameters.hasAssociatedDisplay = true;
}
}
void KeyboardInputMapper::dumpParameters(String8& dump) {
dump.append(INDENT3 "Parameters:\n");
- dump.appendFormat(INDENT4 "AssociatedDisplayId: %d\n",
- mParameters.associatedDisplayId);
+ dump.appendFormat(INDENT4 "HasAssociatedDisplay: %s\n",
+ toString(mParameters.hasAssociatedDisplay));
dump.appendFormat(INDENT4 "OrientationAware: %s\n",
toString(mParameters.orientationAware));
}
@@ -2086,7 +2072,7 @@ void KeyboardInputMapper::processKey(nsecs_t when, bool down, int32_t keyCode,
if (down) {
// Rotate key codes according to orientation if needed.
- if (mParameters.orientationAware && mParameters.associatedDisplayId >= 0) {
+ if (mParameters.orientationAware && mParameters.hasAssociatedDisplay) {
keyCode = rotateKeyCode(keyCode, mOrientation);
}
@@ -2317,9 +2303,11 @@ void CursorInputMapper::configure(nsecs_t when,
}
if (!changes || (changes & InputReaderConfiguration::CHANGE_DISPLAY_INFO)) {
- if (mParameters.orientationAware && mParameters.associatedDisplayId >= 0) {
- if (!config->getDisplayInfo(mParameters.associatedDisplayId,
- false /*external*/, NULL, NULL, &mOrientation)) {
+ if (mParameters.orientationAware && mParameters.hasAssociatedDisplay) {
+ DisplayViewport v;
+ if (config->getDisplayInfo(false /*external*/, &v)) {
+ mOrientation = v.orientation;
+ } else {
mOrientation = DISPLAY_ORIENTATION_0;
}
} else {
@@ -2344,16 +2332,16 @@ void CursorInputMapper::configureParameters() {
getDevice()->getConfiguration().tryGetProperty(String8("cursor.orientationAware"),
mParameters.orientationAware);
- mParameters.associatedDisplayId = -1;
+ mParameters.hasAssociatedDisplay = false;
if (mParameters.mode == Parameters::MODE_POINTER || mParameters.orientationAware) {
- mParameters.associatedDisplayId = 0;
+ mParameters.hasAssociatedDisplay = true;
}
}
void CursorInputMapper::dumpParameters(String8& dump) {
dump.append(INDENT3 "Parameters:\n");
- dump.appendFormat(INDENT4 "AssociatedDisplayId: %d\n",
- mParameters.associatedDisplayId);
+ dump.appendFormat(INDENT4 "HasAssociatedDisplay: %s\n",
+ toString(mParameters.hasAssociatedDisplay));
switch (mParameters.mode) {
case Parameters::MODE_POINTER:
@@ -2420,7 +2408,7 @@ void CursorInputMapper::sync(nsecs_t when) {
bool moved = deltaX != 0 || deltaY != 0;
// Rotate delta according to orientation if needed.
- if (mParameters.orientationAware && mParameters.associatedDisplayId >= 0
+ if (mParameters.orientationAware && mParameters.hasAssociatedDisplay
&& (deltaX != 0.0f || deltaY != 0.0f)) {
rotateDelta(mOrientation, &deltaX, &deltaY);
}
@@ -2782,15 +2770,15 @@ void TouchInputMapper::configureParameters() {
getDevice()->getConfiguration().tryGetProperty(String8("touch.orientationAware"),
mParameters.orientationAware);
- mParameters.associatedDisplayId = -1;
+ mParameters.hasAssociatedDisplay = false;
mParameters.associatedDisplayIsExternal = false;
if (mParameters.orientationAware
|| mParameters.deviceType == Parameters::DEVICE_TYPE_TOUCH_SCREEN
|| mParameters.deviceType == Parameters::DEVICE_TYPE_POINTER) {
+ mParameters.hasAssociatedDisplay = true;
mParameters.associatedDisplayIsExternal =
mParameters.deviceType == Parameters::DEVICE_TYPE_TOUCH_SCREEN
&& getDevice()->isExternal();
- mParameters.associatedDisplayId = 0;
}
}
@@ -2822,8 +2810,9 @@ void TouchInputMapper::dumpParameters(String8& dump) {
ALOG_ASSERT(false);
}
- dump.appendFormat(INDENT4 "AssociatedDisplay: id=%d, isExternal=%s\n",
- mParameters.associatedDisplayId, toString(mParameters.associatedDisplayIsExternal));
+ dump.appendFormat(INDENT4 "AssociatedDisplay: present=%s, isExternal=%s\n",
+ toString(mParameters.hasAssociatedDisplay),
+ toString(mParameters.associatedDisplayIsExternal));
dump.appendFormat(INDENT4 "OrientationAware: %s\n",
toString(mParameters.orientationAware));
}
@@ -2861,7 +2850,7 @@ void TouchInputMapper::configureSurface(nsecs_t when, bool* outResetNeeded) {
mSource |= AINPUT_SOURCE_STYLUS;
}
} else if (mParameters.deviceType == Parameters::DEVICE_TYPE_TOUCH_SCREEN
- && mParameters.associatedDisplayId >= 0) {
+ && mParameters.hasAssociatedDisplay) {
mSource = AINPUT_SOURCE_TOUCHSCREEN;
mDeviceMode = DEVICE_MODE_DIRECT;
if (hasStylus()) {
@@ -2881,15 +2870,13 @@ void TouchInputMapper::configureSurface(nsecs_t when, bool* outResetNeeded) {
}
// Get associated display dimensions.
- if (mParameters.associatedDisplayId >= 0) {
- if (!mConfig.getDisplayInfo(mParameters.associatedDisplayId,
- mParameters.associatedDisplayIsExternal,
- &mAssociatedDisplayWidth, &mAssociatedDisplayHeight,
- &mAssociatedDisplayOrientation)) {
+ if (mParameters.hasAssociatedDisplay) {
+ if (!mConfig.getDisplayInfo(mParameters.associatedDisplayIsExternal,
+ &mAssociatedDisplayViewport)) {
ALOGI(INDENT "Touch device '%s' could not query the properties of its associated "
- "display %d. The device will be inoperable until the display size "
+ "display. The device will be inoperable until the display size "
"becomes available.",
- getDeviceName().string(), mParameters.associatedDisplayId);
+ getDeviceName().string());
mDeviceMode = DEVICE_MODE_DISABLED;
return;
}
@@ -2898,10 +2885,16 @@ void TouchInputMapper::configureSurface(nsecs_t when, bool* outResetNeeded) {
// Configure dimensions.
int32_t width, height, orientation;
if (mDeviceMode == DEVICE_MODE_DIRECT || mDeviceMode == DEVICE_MODE_POINTER) {
- width = mAssociatedDisplayWidth;
- height = mAssociatedDisplayHeight;
+ width = mAssociatedDisplayViewport.logicalRight - mAssociatedDisplayViewport.logicalLeft;
+ height = mAssociatedDisplayViewport.logicalBottom - mAssociatedDisplayViewport.logicalTop;
+ if (mAssociatedDisplayViewport.orientation == DISPLAY_ORIENTATION_90
+ || mAssociatedDisplayViewport.orientation == DISPLAY_ORIENTATION_270) {
+ int32_t temp = height;
+ height = width;
+ width = temp;
+ }
orientation = mParameters.orientationAware ?
- mAssociatedDisplayOrientation : DISPLAY_ORIENTATION_0;
+ mAssociatedDisplayViewport.orientation : DISPLAY_ORIENTATION_0;
} else {
width = mRawPointerAxes.x.maxValue - mRawPointerAxes.x.minValue + 1;
height = mRawPointerAxes.y.maxValue - mRawPointerAxes.y.minValue + 1;
@@ -3163,8 +3156,7 @@ void TouchInputMapper::configureSurface(nsecs_t when, bool* outResetNeeded) {
int32_t rawWidth = mRawPointerAxes.x.maxValue - mRawPointerAxes.x.minValue + 1;
int32_t rawHeight = mRawPointerAxes.y.maxValue - mRawPointerAxes.y.minValue + 1;
float rawDiagonal = hypotf(rawWidth, rawHeight);
- float displayDiagonal = hypotf(mAssociatedDisplayWidth,
- mAssociatedDisplayHeight);
+ float displayDiagonal = hypotf(width, height);
// Scale movements such that one whole swipe of the touch pad covers a
// given area relative to the diagonal size of the display when no acceleration
diff --git a/services/input/InputReader.h b/services/input/InputReader.h
index 6c06986..e345a5f 100644
--- a/services/input/InputReader.h
+++ b/services/input/InputReader.h
@@ -24,7 +24,6 @@
#include <androidfw/Input.h>
#include <androidfw/VelocityControl.h>
#include <androidfw/VelocityTracker.h>
-#include <ui/DisplayInfo.h>
#include <utils/KeyedVector.h>
#include <utils/threads.h>
#include <utils/Timers.h>
@@ -48,6 +47,45 @@ namespace android {
class InputDevice;
class InputMapper;
+/*
+ * Describes how coordinates are mapped on a physical display.
+ * See com.android.server.display.DisplayViewport.
+ */
+struct DisplayViewport {
+ int32_t displayId; // -1 if invalid
+ int32_t orientation;
+ int32_t logicalLeft;
+ int32_t logicalTop;
+ int32_t logicalRight;
+ int32_t logicalBottom;
+ int32_t physicalLeft;
+ int32_t physicalTop;
+ int32_t physicalRight;
+ int32_t physicalBottom;
+
+ DisplayViewport() :
+ displayId(-1), orientation(DISPLAY_ORIENTATION_0),
+ logicalLeft(0), logicalTop(0), logicalRight(0), logicalBottom(0),
+ physicalLeft(0), physicalTop(0), physicalRight(0), physicalBottom(0) {
+ }
+
+ bool operator==(const DisplayViewport& other) const {
+ return displayId == other.displayId
+ && orientation == other.orientation
+ && logicalLeft == other.logicalLeft
+ && logicalTop == other.logicalTop
+ && logicalRight == other.logicalRight
+ && logicalBottom == other.logicalBottom
+ && physicalLeft == other.physicalLeft
+ && physicalTop == other.physicalTop
+ && physicalRight == other.physicalRight
+ && physicalBottom == other.physicalBottom;
+ }
+
+ bool operator!=(const DisplayViewport& other) const {
+ return !(*this == other);
+ }
+};
/*
* Input reader configuration.
@@ -180,25 +218,12 @@ struct InputReaderConfiguration {
pointerGestureZoomSpeedRatio(0.3f),
showTouches(false) { }
- bool getDisplayInfo(int32_t displayId, bool external,
- int32_t* width, int32_t* height, int32_t* orientation) const;
-
- void setDisplayInfo(int32_t displayId, bool external,
- int32_t width, int32_t height, int32_t orientation);
+ bool getDisplayInfo(bool external, DisplayViewport* outViewport) const;
+ void setDisplayInfo(bool external, const DisplayViewport& viewport);
private:
- struct DisplayInfo {
- int32_t width;
- int32_t height;
- int32_t orientation;
-
- DisplayInfo() :
- width(-1), height(-1), orientation(DISPLAY_ORIENTATION_0) {
- }
- };
-
- DisplayInfo mInternalDisplay;
- DisplayInfo mExternalDisplay;
+ DisplayViewport mInternalDisplay;
+ DisplayViewport mExternalDisplay;
};
@@ -992,7 +1017,7 @@ private:
// Immutable configuration parameters.
struct Parameters {
- int32_t associatedDisplayId;
+ bool hasAssociatedDisplay;
bool orientationAware;
} mParameters;
@@ -1042,7 +1067,7 @@ private:
};
Mode mode;
- int32_t associatedDisplayId;
+ bool hasAssociatedDisplay;
bool orientationAware;
} mParameters;
@@ -1143,7 +1168,7 @@ protected:
};
DeviceType deviceType;
- int32_t associatedDisplayId;
+ bool hasAssociatedDisplay;
bool associatedDisplayIsExternal;
bool orientationAware;
@@ -1277,10 +1302,8 @@ private:
int32_t mSurfaceWidth;
int32_t mSurfaceHeight;
- // The associated display orientation and width and height set by configureSurface().
- int32_t mAssociatedDisplayOrientation;
- int32_t mAssociatedDisplayWidth;
- int32_t mAssociatedDisplayHeight;
+ // The associated display viewport set by configureSurface().
+ DisplayViewport mAssociatedDisplayViewport;
// Translation and scaling factors, orientation-independent.
float mXScale;
diff --git a/services/input/PointerController.cpp b/services/input/PointerController.cpp
index fc828a6..9af521b 100644
--- a/services/input/PointerController.cpp
+++ b/services/input/PointerController.cpp
@@ -307,9 +307,17 @@ void PointerController::setInactivityTimeout(InactivityTimeout inactivityTimeout
}
}
-void PointerController::setDisplaySize(int32_t width, int32_t height) {
+void PointerController::setDisplayViewport(int32_t width, int32_t height, int32_t orientation) {
AutoMutex _l(mLock);
+ // Adjust to use the display's unrotated coordinate frame.
+ if (orientation == DISPLAY_ORIENTATION_90
+ || orientation == DISPLAY_ORIENTATION_270) {
+ int32_t temp = height;
+ height = width;
+ width = temp;
+ }
+
if (mLocked.displayWidth != width || mLocked.displayHeight != height) {
mLocked.displayWidth = width;
mLocked.displayHeight = height;
@@ -324,12 +332,7 @@ void PointerController::setDisplaySize(int32_t width, int32_t height) {
}
fadeOutAndReleaseAllSpotsLocked();
- updatePointerLocked();
}
-}
-
-void PointerController::setDisplayOrientation(int32_t orientation) {
- AutoMutex _l(mLock);
if (mLocked.displayOrientation != orientation) {
// Apply offsets to convert from the pixel top-left corner position to the pixel center.
@@ -380,9 +383,9 @@ void PointerController::setDisplayOrientation(int32_t orientation) {
mLocked.pointerX = x - 0.5f;
mLocked.pointerY = y - 0.5f;
mLocked.displayOrientation = orientation;
-
- updatePointerLocked();
}
+
+ updatePointerLocked();
}
void PointerController::setPointerIcon(const SpriteIcon& icon) {
diff --git a/services/input/PointerController.h b/services/input/PointerController.h
index 4c307c4..fd68b61 100644
--- a/services/input/PointerController.h
+++ b/services/input/PointerController.h
@@ -170,8 +170,7 @@ public:
const uint32_t* spotIdToIndex, BitSet32 spotIdBits);
virtual void clearSpots();
- void setDisplaySize(int32_t width, int32_t height);
- void setDisplayOrientation(int32_t orientation);
+ void setDisplayViewport(int32_t width, int32_t height, int32_t orientation);
void setPointerIcon(const SpriteIcon& icon);
void setInactivityTimeout(InactivityTimeout inactivityTimeout);
diff --git a/services/input/tests/InputReader_test.cpp b/services/input/tests/InputReader_test.cpp
index abda10b..03516af 100644
--- a/services/input/tests/InputReader_test.cpp
+++ b/services/input/tests/InputReader_test.cpp
@@ -138,8 +138,21 @@ public:
void setDisplayInfo(int32_t displayId, int32_t width, int32_t height, int32_t orientation) {
// Set the size of both the internal and external display at the same time.
- mConfig.setDisplayInfo(displayId, false /*external*/, width, height, orientation);
- mConfig.setDisplayInfo(displayId, true /*external*/, width, height, orientation);
+ bool isRotated = (orientation == DISPLAY_ORIENTATION_90
+ || orientation == DISPLAY_ORIENTATION_270);
+ DisplayViewport v;
+ v.displayId = displayId;
+ v.orientation = orientation;
+ v.logicalLeft = 0;
+ v.logicalTop = 0;
+ v.logicalRight = isRotated ? height : width;
+ v.logicalBottom = isRotated ? width : height;
+ v.physicalLeft = 0;
+ v.physicalTop = 0;
+ v.physicalRight = isRotated ? height : width;
+ v.physicalBottom = isRotated ? width : height;
+ mConfig.setDisplayInfo(false /*external*/, v);
+ mConfig.setDisplayInfo(true /*external*/, v);
}
void addExcludedDeviceName(const String8& deviceName) {
diff --git a/services/java/com/android/server/BackupManagerService.java b/services/java/com/android/server/BackupManagerService.java
index 955ea23..1d40f4f 100644
--- a/services/java/com/android/server/BackupManagerService.java
+++ b/services/java/com/android/server/BackupManagerService.java
@@ -4401,6 +4401,18 @@ class BackupManagerService extends IBackupManager.Stub {
return;
}
+ if (packageInfo.applicationInfo.backupAgentName == null
+ || "".equals(packageInfo.applicationInfo.backupAgentName)) {
+ if (DEBUG) {
+ Slog.i(TAG, "Data exists for package " + packageName
+ + " but app has no agent; skipping");
+ }
+ EventLog.writeEvent(EventLogTags.RESTORE_AGENT_FAILURE, packageName,
+ "Package has no agent");
+ executeNextState(RestoreState.RUNNING_QUEUE);
+ return;
+ }
+
if (metaInfo.versionCode > packageInfo.versionCode) {
// Data is from a "newer" version of the app than we have currently
// installed. If the app has not declared that it is prepared to
diff --git a/services/java/com/android/server/DevicePolicyManagerService.java b/services/java/com/android/server/DevicePolicyManagerService.java
index 61517b1..fd6060a 100644
--- a/services/java/com/android/server/DevicePolicyManagerService.java
+++ b/services/java/com/android/server/DevicePolicyManagerService.java
@@ -1628,8 +1628,8 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
} else {
// Make sure KEEP_SCREEN_ON is disabled, since that
// would allow bypassing of the maximum time to lock.
- Settings.System.putInt(mContext.getContentResolver(),
- Settings.System.STAY_ON_WHILE_PLUGGED_IN, 0);
+ Settings.Global.putInt(mContext.getContentResolver(),
+ Settings.Global.STAY_ON_WHILE_PLUGGED_IN, 0);
}
mLastMaximumTimeToLock = timeMs;
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index 1aad9b3..c28afb2 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -304,6 +304,7 @@ class ServerThread extends Thread {
ActivityManagerService.self().setWindowManager(wm);
display.setWindowManager(wm);
+ display.setInputManager(inputManager);
// Skip Bluetooth if we have an emulator kernel
// TODO: Use a more reliable check to see if this product should
diff --git a/services/java/com/android/server/UiModeManagerService.java b/services/java/com/android/server/UiModeManagerService.java
index f618263..3e83baa 100644
--- a/services/java/com/android/server/UiModeManagerService.java
+++ b/services/java/com/android/server/UiModeManagerService.java
@@ -463,7 +463,7 @@ class UiModeManagerService extends IUiModeManager.Stub {
if (homeIntent != null) {
try {
- mContext.startActivity(homeIntent);
+ mContext.startActivityAsUser(homeIntent, UserHandle.CURRENT);
} catch (ActivityNotFoundException e) {
}
}
diff --git a/services/java/com/android/server/accessibility/ScreenMagnifier.java b/services/java/com/android/server/accessibility/ScreenMagnifier.java
index bd7f276..f33517b 100644
--- a/services/java/com/android/server/accessibility/ScreenMagnifier.java
+++ b/services/java/com/android/server/accessibility/ScreenMagnifier.java
@@ -236,7 +236,6 @@ public final class ScreenMagnifier implements EventStreamTransformation {
mDetectingStateHandler.clear();
mStateViewportDraggingHandler.clear();
mGestureDetector.clear();
-
if (mNext != null) {
mNext.clear();
}
@@ -244,6 +243,9 @@ public final class ScreenMagnifier implements EventStreamTransformation {
@Override
public void onDestroy() {
+ mMagnificationController.setScaleAndMagnifiedRegionCenter(1.0f,
+ 0, 0, true);
+ mViewport.setFrameShown(false, true);
mDisplayProvider.destroy();
mDisplayContentObserver.destroy();
}
@@ -286,7 +288,11 @@ public final class ScreenMagnifier implements EventStreamTransformation {
private PointerCoords[] getTempPointerCoordsWithMinSize(int size) {
final int oldSize = (mTempPointerCoords != null) ? mTempPointerCoords.length : 0;
if (oldSize < size) {
+ PointerCoords[] oldTempPointerCoords = mTempPointerCoords;
mTempPointerCoords = new PointerCoords[size];
+ if (oldTempPointerCoords != null) {
+ System.arraycopy(oldTempPointerCoords, 0, mTempPointerCoords, 0, oldSize);
+ }
}
for (int i = oldSize; i < size; i++) {
mTempPointerCoords[i] = new PointerCoords();
@@ -297,7 +303,11 @@ public final class ScreenMagnifier implements EventStreamTransformation {
private PointerProperties[] getTempPointerPropertiesWithMinSize(int size) {
final int oldSize = (mTempPointerProperties != null) ? mTempPointerProperties.length : 0;
if (oldSize < size) {
+ PointerProperties[] oldTempPointerProperties = mTempPointerProperties;
mTempPointerProperties = new PointerProperties[size];
+ if (oldTempPointerProperties != null) {
+ System.arraycopy(oldTempPointerProperties, 0, mTempPointerProperties, 0, oldSize);
+ }
}
for (int i = oldSize; i < size; i++) {
mTempPointerProperties[i] = new PointerProperties();
@@ -324,7 +334,7 @@ public final class ScreenMagnifier implements EventStreamTransformation {
Slog.i(LOG_TAG, "mCurrentState: STATE_PANNING");
} break;
case STATE_DECIDE_PAN_OR_SCALE: {
- Slog.i(LOG_TAG, "mCurrentState: STATE_DETECTING_PAN_OR_SCALE");
+ Slog.i(LOG_TAG, "mCurrentState: STATE_DECIDE_PAN_OR_SCALE");
} break;
default: {
throw new IllegalArgumentException("Unknown state: " + state);
@@ -397,6 +407,7 @@ public final class ScreenMagnifier implements EventStreamTransformation {
}
if (scaleDelta > DETECT_SCALING_THRESHOLD) {
performScale(detector, true);
+ clear();
transitionToState(STATE_SCALING);
return false;
}
@@ -409,8 +420,9 @@ public final class ScreenMagnifier implements EventStreamTransformation {
Slog.i(LOG_TAG, "panDelta: " + panDelta);
}
if (panDelta > mScaledDetectPanningThreshold) {
- transitionToState(STATE_PANNING);
performPan(detector, true);
+ clear();
+ transitionToState(STATE_PANNING);
return false;
}
} break;
diff --git a/services/java/com/android/server/am/ActiveServices.java b/services/java/com/android/server/am/ActiveServices.java
index 6a3010b..7144808 100644
--- a/services/java/com/android/server/am/ActiveServices.java
+++ b/services/java/com/android/server/am/ActiveServices.java
@@ -185,7 +185,7 @@ public class ActiveServices {
}
private HashMap<ComponentName, ServiceRecord> getServices(int callingUser) {
- HashMap map = mServicesByNamePerUser.get(callingUser);
+ HashMap<ComponentName, ServiceRecord> map = mServicesByNamePerUser.get(callingUser);
if (map == null) {
map = new HashMap<ComponentName, ServiceRecord>();
mServicesByNamePerUser.put(callingUser, map);
@@ -195,7 +195,8 @@ public class ActiveServices {
private HashMap<Intent.FilterComparison, ServiceRecord> getServicesByIntent(
int callingUser) {
- HashMap map = mServicesByIntentPerUser.get(callingUser);
+ HashMap<Intent.FilterComparison, ServiceRecord> map
+ = mServicesByIntentPerUser.get(callingUser);
if (map == null) {
map = new HashMap<Intent.FilterComparison, ServiceRecord>();
mServicesByIntentPerUser.put(callingUser, map);
@@ -1514,10 +1515,12 @@ public class ActiveServices {
}
}
- boolean forceStopLocked(String name, int userId, boolean evenPersistent, boolean doit) {
+ private boolean collectForceStopServicesLocked(String name, int userId,
+ boolean evenPersistent, boolean doit,
+ HashMap<ComponentName, ServiceRecord> services,
+ ArrayList<ServiceRecord> result) {
boolean didSomething = false;
- ArrayList<ServiceRecord> services = new ArrayList<ServiceRecord>();
- for (ServiceRecord service : mServiceMap.getAllServices(userId)) {
+ for (ServiceRecord service : services.values()) {
if ((name == null || service.packageName.equals(name))
&& (service.app == null || evenPersistent || !service.app.persistent)) {
if (!doit) {
@@ -1530,9 +1533,27 @@ public class ActiveServices {
}
service.app = null;
service.isolatedProc = null;
- services.add(service);
+ result.add(service);
}
}
+ return didSomething;
+ }
+
+ boolean forceStopLocked(String name, int userId, boolean evenPersistent, boolean doit) {
+ boolean didSomething = false;
+ ArrayList<ServiceRecord> services = new ArrayList<ServiceRecord>();
+ if (userId == UserHandle.USER_ALL) {
+ for (int i=0; i<mServiceMap.mServicesByNamePerUser.size(); i++) {
+ didSomething |= collectForceStopServicesLocked(name, userId, evenPersistent,
+ doit, mServiceMap.mServicesByNamePerUser.valueAt(i), services);
+ if (!doit && didSomething) {
+ return true;
+ }
+ }
+ } else {
+ didSomething = collectForceStopServicesLocked(name, userId, evenPersistent,
+ doit, mServiceMap.mServicesByNamePerUser.get(userId), services);
+ }
int N = services.size();
for (int i=0; i<N; i++) {
diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java
index 614b93a..ca45946 100644
--- a/services/java/com/android/server/am/ActivityManagerService.java
+++ b/services/java/com/android/server/am/ActivityManagerService.java
@@ -116,13 +116,11 @@ import android.os.UserManager;
import android.provider.Settings;
import android.text.format.Time;
import android.util.EventLog;
-import android.util.LocaleUtil;
import android.util.Log;
import android.util.Pair;
import android.util.PrintWriterPrinter;
import android.util.Slog;
import android.util.SparseArray;
-import android.util.SparseIntArray;
import android.util.TimeUtils;
import android.view.Gravity;
import android.view.LayoutInflater;
@@ -434,6 +432,11 @@ public final class ActivityManagerService extends ActivityManagerNative
final SparseArray<UserStartedState> mStartedUsers = new SparseArray<UserStartedState>();
/**
+ * LRU list of history of current users. Most recently current is at the end.
+ */
+ final ArrayList<Integer> mUserLru = new ArrayList<Integer>();
+
+ /**
* Packages that the user has asked to have run in screen size
* compatibility mode instead of filling the screen.
*/
@@ -1094,11 +1097,11 @@ public final class ActivityManagerService extends ActivityManagerNative
} break;
case KILL_APPLICATION_MSG: {
synchronized (ActivityManagerService.this) {
- int uid = msg.arg1;
+ int appid = msg.arg1;
boolean restart = (msg.arg2 == 1);
String pkg = (String) msg.obj;
- forceStopPackageLocked(pkg, uid, restart, false, true, false,
- UserHandle.getUserId(uid));
+ forceStopPackageLocked(pkg, appid, restart, false, true, false,
+ UserHandle.USER_ALL);
}
} break;
case FINALIZE_PENDING_INTENT_MSG: {
@@ -1526,6 +1529,7 @@ public final class ActivityManagerService extends ActivityManagerNative
// User 0 is the first and only user that runs at boot.
mStartedUsers.put(0, new UserStartedState(new UserHandle(0), true));
+ mUserLru.add(Integer.valueOf(0));
GL_ES_VERSION = SystemProperties.getInt("ro.opengles.version",
ConfigurationInfo.GL_ES_VERSION_UNDEFINED);
@@ -2146,8 +2150,7 @@ public final class ActivityManagerService extends ActivityManagerNative
intent.addCategory(Intent.CATEGORY_HOME);
}
ActivityInfo aInfo =
- intent.resolveActivityInfo(mContext.getPackageManager(),
- STOCK_PM_FLAGS);
+ resolveActivityInfo(intent, STOCK_PM_FLAGS, userId);
if (aInfo != null) {
intent.setComponent(new ComponentName(
aInfo.applicationInfo.packageName, aInfo.name));
@@ -2170,6 +2173,29 @@ public final class ActivityManagerService extends ActivityManagerNative
return true;
}
+ private ActivityInfo resolveActivityInfo(Intent intent, int flags, int userId) {
+ ActivityInfo ai = null;
+ ComponentName comp = intent.getComponent();
+ try {
+ if (comp != null) {
+ ai = AppGlobals.getPackageManager().getActivityInfo(comp, flags, userId);
+ } else {
+ ResolveInfo info = AppGlobals.getPackageManager().resolveIntent(
+ intent,
+ intent.resolveTypeIfNeeded(mContext.getContentResolver()),
+ flags, userId);
+
+ if (info != null) {
+ ai = info.activityInfo;
+ }
+ }
+ } catch (RemoteException e) {
+ // ignore
+ }
+
+ return ai;
+ }
+
/**
* Starts the "new version setup screen" if appropriate.
*/
@@ -2366,17 +2392,8 @@ public final class ActivityManagerService extends ActivityManagerNative
String resultWho, int requestCode, int startFlags,
String profileFile, ParcelFileDescriptor profileFd, Bundle options, int userId) {
enforceNotIsolatedCaller("startActivity");
- if (userId != UserHandle.getCallingUserId()) {
- userId = handleIncomingUserLocked(Binder.getCallingPid(), Binder.getCallingUid(), userId,
- false, true, "startActivity", null);
- } else {
- if (intent.getCategories() != null
- && intent.getCategories().contains(Intent.CATEGORY_HOME)) {
- // Requesting home, set the identity to the current user
- // HACK!
- userId = mCurrentUserId;
- }
- }
+ userId = handleIncomingUserLocked(Binder.getCallingPid(), Binder.getCallingUid(), userId,
+ false, true, "startActivity", null);
return mMainStack.startActivityMayWait(caller, -1, intent, resolvedType,
resultTo, resultWho, requestCode, startFlags, profileFile, profileFd,
null, null, options, userId);
@@ -2385,8 +2402,10 @@ public final class ActivityManagerService extends ActivityManagerNative
public final WaitResult startActivityAndWait(IApplicationThread caller,
Intent intent, String resolvedType, IBinder resultTo,
String resultWho, int requestCode, int startFlags, String profileFile,
- ParcelFileDescriptor profileFd, Bundle options) {
+ ParcelFileDescriptor profileFd, Bundle options, int userId) {
enforceNotIsolatedCaller("startActivityAndWait");
+ userId = handleIncomingUserLocked(Binder.getCallingPid(), Binder.getCallingUid(), userId,
+ false, true, "startActivityAndWait", null);
WaitResult res = new WaitResult();
mMainStack.startActivityMayWait(caller, -1, intent, resolvedType,
resultTo, resultWho, requestCode, startFlags, profileFile, profileFd,
@@ -3542,16 +3561,15 @@ public final class ActivityManagerService extends ActivityManagerNative
}
/*
- * The pkg name and uid have to be specified.
- * @see android.app.IActivityManager#killApplicationWithUid(java.lang.String, int)
+ * The pkg name and app id have to be specified.
*/
- public void killApplicationWithUid(String pkg, int uid) {
+ public void killApplicationWithAppId(String pkg, int appid) {
if (pkg == null) {
return;
}
// Make sure the uid is valid.
- if (uid < 0) {
- Slog.w(TAG, "Invalid uid specified for pkg : " + pkg);
+ if (appid < 0) {
+ Slog.w(TAG, "Invalid appid specified for pkg : " + pkg);
return;
}
int callerUid = Binder.getCallingUid();
@@ -3559,7 +3577,7 @@ public final class ActivityManagerService extends ActivityManagerNative
if (callerUid == Process.SYSTEM_UID) {
// Post an aysnc message to kill the application
Message msg = mHandler.obtainMessage(KILL_APPLICATION_MSG);
- msg.arg1 = uid;
+ msg.arg1 = appid;
msg.arg2 = 0;
msg.obj = pkg;
mHandler.sendMessage(msg);
@@ -3691,7 +3709,7 @@ public final class ActivityManagerService extends ActivityManagerNative
MY_PID, Process.SYSTEM_UID, userId);
}
- private final boolean killPackageProcessesLocked(String packageName, int uid,
+ private final boolean killPackageProcessesLocked(String packageName, int appId,
int userId, int minOomAdj, boolean callerWillRestart, boolean allowRestart,
boolean doit, boolean evenPersistent, String reason) {
ArrayList<ProcessRecord> procs = new ArrayList<ProcessRecord>();
@@ -3712,32 +3730,41 @@ public final class ActivityManagerService extends ActivityManagerNative
if (doit) {
procs.add(app);
}
+ continue;
+ }
+
+ // Skip process if it doesn't meet our oom adj requirement.
+ if (app.setAdj < minOomAdj) {
+ continue;
+ }
+
// If no package is specified, we call all processes under the
// give user id.
- } else if (packageName == null) {
- if (app.userId == userId) {
- if (app.setAdj >= minOomAdj) {
- if (!doit) {
- return true;
- }
- app.removed = true;
- procs.add(app);
- }
+ if (packageName == null) {
+ if (app.userId != userId) {
+ continue;
}
- // If uid is specified and the uid and process name match
- // Or, the uid is not specified and the process name matches
- } else if (((uid > 0 && uid != Process.SYSTEM_UID && app.info.uid == uid)
- || ((app.processName.equals(packageName)
- || app.processName.startsWith(procNamePrefix))
- && uid < 0))) {
- if (app.setAdj >= minOomAdj) {
- if (!doit) {
- return true;
- }
- app.removed = true;
- procs.add(app);
+ // Package has been specified, we want to hit all processes
+ // that match it. We need to qualify this by the processes
+ // that are running under the specified app and user ID.
+ } else {
+ if (UserHandle.getAppId(app.uid) != appId) {
+ continue;
}
+ if (userId != UserHandle.USER_ALL && app.userId != userId) {
+ continue;
+ }
+ if (!app.pkgList.contains(packageName)) {
+ continue;
+ }
+ }
+
+ // Process has passed all conditions, kill it!
+ if (!doit) {
+ return true;
}
+ app.removed = true;
+ procs.add(app);
}
}
@@ -3748,22 +3775,28 @@ public final class ActivityManagerService extends ActivityManagerNative
return N > 0;
}
- private final boolean forceStopPackageLocked(String name, int uid,
+ private final boolean forceStopPackageLocked(String name, int appId,
boolean callerWillRestart, boolean purgeCache, boolean doit,
boolean evenPersistent, int userId) {
int i;
int N;
- if (uid < 0 && name != null) {
+ if (userId == UserHandle.USER_ALL && name == null) {
+ Slog.w(TAG, "Can't force stop all processes of all users, that is insane!");
+ }
+
+ if (appId < 0 && name != null) {
try {
- uid = AppGlobals.getPackageManager().getPackageUid(name, userId);
+ appId = UserHandle.getAppId(
+ AppGlobals.getPackageManager().getPackageUid(name, 0));
} catch (RemoteException e) {
}
}
if (doit) {
if (name != null) {
- Slog.i(TAG, "Force stopping package " + name + " uid=" + uid);
+ Slog.i(TAG, "Force stopping package " + name + " appid=" + appId
+ + " user=" + userId);
} else {
Slog.i(TAG, "Force stopping user " + userId);
}
@@ -3775,8 +3808,14 @@ public final class ActivityManagerService extends ActivityManagerNative
boolean remove = false;
final int entUid = ba.keyAt(i);
if (name != null) {
- if (entUid == uid) {
- remove = true;
+ if (userId == UserHandle.USER_ALL) {
+ if (UserHandle.getAppId(entUid) == appId) {
+ remove = true;
+ }
+ } else {
+ if (entUid == UserHandle.getUid(userId, appId)) {
+ remove = true;
+ }
}
} else if (UserHandle.getUserId(entUid) == userId) {
remove = true;
@@ -3791,9 +3830,8 @@ public final class ActivityManagerService extends ActivityManagerNative
}
}
- boolean didSomething = killPackageProcessesLocked(name, uid,
- name == null ? userId : -1 , -100, callerWillRestart, false,
- doit, evenPersistent,
+ boolean didSomething = killPackageProcessesLocked(name, appId, userId,
+ -100, callerWillRestart, false, doit, evenPersistent,
name == null ? ("force stop user " + userId) : ("force stop " + name));
TaskRecord lastTask = null;
@@ -3801,7 +3839,7 @@ public final class ActivityManagerService extends ActivityManagerNative
ActivityRecord r = (ActivityRecord)mMainStack.mHistory.get(i);
final boolean samePackage = r.packageName.equals(name)
|| (name == null && r.userId == userId);
- if (r.userId == userId
+ if ((userId == UserHandle.USER_ALL || r.userId == userId)
&& (samePackage || r.task == lastTask)
&& (r.app == null || evenPersistent || !r.app.persistent)) {
if (!doit) {
@@ -3841,22 +3879,64 @@ public final class ActivityManagerService extends ActivityManagerNative
}
ArrayList<ContentProviderRecord> providers = new ArrayList<ContentProviderRecord>();
- for (ContentProviderRecord provider : mProviderMap.getProvidersByClass(userId).values()) {
- if ((name == null || provider.info.packageName.equals(name))
- && (provider.proc == null || evenPersistent || !provider.proc.persistent)) {
- if (!doit) {
- return true;
- }
- didSomething = true;
- providers.add(provider);
+ if (mProviderMap.collectForceStopProviders(name, appId, doit, evenPersistent,
+ userId, providers)) {
+ if (!doit) {
+ return true;
}
+ didSomething = true;
}
-
N = providers.size();
for (i=0; i<N; i++) {
removeDyingProviderLocked(null, providers.get(i), true);
}
+ if (mIntentSenderRecords.size() > 0) {
+ Iterator<WeakReference<PendingIntentRecord>> it
+ = mIntentSenderRecords.values().iterator();
+ while (it.hasNext()) {
+ WeakReference<PendingIntentRecord> wpir = it.next();
+ if (wpir == null) {
+ it.remove();
+ continue;
+ }
+ PendingIntentRecord pir = wpir.get();
+ if (pir == null) {
+ it.remove();
+ continue;
+ }
+ if (name == null) {
+ // Stopping user, remove all objects for the user.
+ if (pir.key.userId != userId) {
+ // Not the same user, skip it.
+ continue;
+ }
+ } else {
+ if (UserHandle.getAppId(pir.uid) != appId) {
+ // Different app id, skip it.
+ continue;
+ }
+ if (userId != UserHandle.USER_ALL && pir.key.userId != userId) {
+ // Different user, skip it.
+ continue;
+ }
+ if (!pir.key.packageName.equals(name)) {
+ // Different package, skip it.
+ continue;
+ }
+ }
+ if (!doit) {
+ return true;
+ }
+ didSomething = true;
+ it.remove();
+ pir.canceled = true;
+ if (pir.key.activity != null) {
+ pir.key.activity.pendingResults.remove(pir.ref);
+ }
+ }
+ }
+
if (doit) {
if (purgeCache && name != null) {
AttributeCache ac = AttributeCache.instance();
@@ -6778,10 +6858,11 @@ public final class ActivityManagerService extends ActivityManagerNative
* Test cases are at cts/tests/appsecurity-tests/test-apps/UsePermissionDiffCert/
* src/com/android/cts/usespermissiondiffcertapp/AccessPermissionWithDiffSigTest.java
*/
- public String getProviderMimeType(Uri uri) {
+ public String getProviderMimeType(Uri uri, int userId) {
enforceNotIsolatedCaller("getProviderMimeType");
+ userId = handleIncomingUserLocked(Binder.getCallingPid(), Binder.getCallingUid(),
+ userId, false, true, "getProviderMimeType", null);
final String name = uri.getAuthority();
- final int userId = UserHandle.getCallingUserId();
final long ident = Binder.clearCallingIdentity();
ContentProviderHolder holder = null;
@@ -7134,7 +7215,8 @@ public final class ActivityManagerService extends ActivityManagerNative
mDebugTransient = !persistent;
if (packageName != null) {
final long origId = Binder.clearCallingIdentity();
- forceStopPackageLocked(packageName, -1, false, false, true, true, 0);
+ forceStopPackageLocked(packageName, -1, false, false, true, true,
+ UserHandle.USER_ALL);
Binder.restoreCallingIdentity(origId);
}
}
@@ -9129,9 +9211,14 @@ public final class ActivityManagerService extends ActivityManagerNative
for (int i=0; i<mStartedUsers.size(); i++) {
UserStartedState uss = mStartedUsers.valueAt(i);
pw.print(" User #"); pw.print(uss.mHandle.getIdentifier());
- pw.println(":");
- uss.dump(" ", pw);
+ pw.print(": "); uss.dump("", pw);
+ }
+ pw.print(" mUserLru: [");
+ for (int i=0; i<mUserLru.size(); i++) {
+ if (i > 0) pw.print(", ");
+ pw.print(mUserLru.get(i));
}
+ pw.println("]");
pw.println(" mHomeProcess: " + mHomeProcess);
pw.println(" mPreviousProcess: " + mPreviousProcess);
if (dumpAll) {
@@ -10764,7 +10851,7 @@ public final class ActivityManagerService extends ActivityManagerNative
builder.append("; this requires ");
builder.append(android.Manifest.permission.INTERACT_ACROSS_USERS_FULL);
if (!requireFull) {
- builder.append("or");
+ builder.append(" or ");
builder.append(android.Manifest.permission.INTERACT_ACROSS_USERS);
}
String msg = builder.toString();
@@ -11815,8 +11902,10 @@ public final class ActivityManagerService extends ActivityManagerNative
public boolean startInstrumentation(ComponentName className,
String profileFile, int flags, Bundle arguments,
- IInstrumentationWatcher watcher) {
+ IInstrumentationWatcher watcher, int userId) {
enforceNotIsolatedCaller("startInstrumentation");
+ userId = handleIncomingUserLocked(Binder.getCallingPid(), Binder.getCallingUid(),
+ userId, false, true, "startInstrumentation", null);
// Refuse possible leaked file descriptors
if (arguments != null && arguments.hasFileDescriptors()) {
throw new IllegalArgumentException("File descriptors passed in Bundle");
@@ -11828,9 +11917,10 @@ public final class ActivityManagerService extends ActivityManagerNative
try {
ii = mContext.getPackageManager().getInstrumentationInfo(
className, STOCK_PM_FLAGS);
- ai = mContext.getPackageManager().getApplicationInfo(
- ii.targetPackage, STOCK_PM_FLAGS);
+ ai = AppGlobals.getPackageManager().getApplicationInfo(
+ ii.targetPackage, STOCK_PM_FLAGS, userId);
} catch (PackageManager.NameNotFoundException e) {
+ } catch (RemoteException e) {
}
if (ii == null) {
reportStartInstrumentationFailure(watcher, className,
@@ -11857,7 +11947,6 @@ public final class ActivityManagerService extends ActivityManagerNative
throw new SecurityException(msg);
}
- int userId = UserHandle.getCallingUserId();
final long origId = Binder.clearCallingIdentity();
// Instrumentation can kill and relaunch even persistent processes
forceStopPackageLocked(ii.targetPackage, -1, true, false, true, true, userId);
@@ -13780,6 +13869,9 @@ public final class ActivityManagerService extends ActivityManagerNative
}
mCurrentUserId = userId;
+ Integer userIdInt = Integer.valueOf(userId);
+ mUserLru.remove(userIdInt);
+ mUserLru.add(userIdInt);
boolean haveActivities = mMainStack.switchUser(userId);
if (!haveActivities) {
startHomeActivityLocked(userId, mStartedUsers.get(userId));
@@ -13928,6 +14020,23 @@ public final class ActivityManagerService extends ActivityManagerNative
}
}
+ @Override
+ public boolean isUserRunning(int userId) {
+ if (checkCallingPermission(android.Manifest.permission.INTERACT_ACROSS_USERS)
+ != PackageManager.PERMISSION_GRANTED) {
+ String msg = "Permission Denial: isUserRunning() from pid="
+ + Binder.getCallingPid()
+ + ", uid=" + Binder.getCallingUid()
+ + " requires " + android.Manifest.permission.INTERACT_ACROSS_USERS;
+ Slog.w(TAG, msg);
+ throw new SecurityException(msg);
+ }
+ synchronized (this) {
+ UserStartedState state = mStartedUsers.get(userId);
+ return state != null && state.mState != UserStartedState.STATE_STOPPING;
+ }
+ }
+
private boolean userExists(int userId) {
UserInfo user = getUserManager().getUserInfo(userId);
return user != null;
diff --git a/services/java/com/android/server/am/ActivityStack.java b/services/java/com/android/server/am/ActivityStack.java
index 399ea59..895b52a 100755
--- a/services/java/com/android/server/am/ActivityStack.java
+++ b/services/java/com/android/server/am/ActivityStack.java
@@ -422,11 +422,10 @@ final class ActivityStack {
}
final ActivityRecord topRunningActivityLocked(ActivityRecord notTop) {
- // TODO: Don't look for any tasks from other users
int i = mHistory.size()-1;
while (i >= 0) {
ActivityRecord r = mHistory.get(i);
- if (!r.finishing && r != notTop) {
+ if (!r.finishing && r != notTop && r.userId == mCurrentUser) {
return r;
}
i--;
@@ -435,11 +434,10 @@ final class ActivityStack {
}
final ActivityRecord topRunningNonDelayedActivityLocked(ActivityRecord notTop) {
- // TODO: Don't look for any tasks from other users
int i = mHistory.size()-1;
while (i >= 0) {
ActivityRecord r = mHistory.get(i);
- if (!r.finishing && !r.delayedResume && r != notTop) {
+ if (!r.finishing && !r.delayedResume && r != notTop && r.userId == mCurrentUser) {
return r;
}
i--;
@@ -457,12 +455,12 @@ final class ActivityStack {
* @return Returns the HistoryRecord of the next activity on the stack.
*/
final ActivityRecord topRunningActivityLocked(IBinder token, int taskId) {
- // TODO: Don't look for any tasks from other users
int i = mHistory.size()-1;
while (i >= 0) {
ActivityRecord r = mHistory.get(i);
// Note: the taskId check depends on real taskId fields being non-zero
- if (!r.finishing && (token != r.appToken) && (taskId != r.task.taskId)) {
+ if (!r.finishing && (token != r.appToken) && (taskId != r.task.taskId)
+ && r.userId == mCurrentUser) {
return r;
}
i--;
@@ -1400,7 +1398,7 @@ final class ActivityStack {
// Launcher...
if (mMainStack) {
ActivityOptions.abort(options);
- return mService.startHomeActivityLocked(0, null);
+ return mService.startHomeActivityLocked(mCurrentUser, null);
}
}
diff --git a/services/java/com/android/server/am/ContentProviderRecord.java b/services/java/com/android/server/am/ContentProviderRecord.java
index c80d63a..de306b5 100644
--- a/services/java/com/android/server/am/ContentProviderRecord.java
+++ b/services/java/com/android/server/am/ContentProviderRecord.java
@@ -85,7 +85,7 @@ class ContentProviderRecord {
public boolean canRunHere(ProcessRecord app) {
return (info.multiprocess || info.processName.equals(app.processName))
- && (uid == Process.SYSTEM_UID || uid == app.info.uid);
+ && uid == app.info.uid;
}
public void addExternalProcessHandleLocked(IBinder token) {
diff --git a/services/java/com/android/server/am/PendingIntentRecord.java b/services/java/com/android/server/am/PendingIntentRecord.java
index 0f72409..c61f13c 100644
--- a/services/java/com/android/server/am/PendingIntentRecord.java
+++ b/services/java/com/android/server/am/PendingIntentRecord.java
@@ -25,7 +25,6 @@ import android.os.Binder;
import android.os.Bundle;
import android.os.IBinder;
import android.os.RemoteException;
-import android.os.UserHandle;
import android.util.Slog;
import java.io.PrintWriter;
diff --git a/services/java/com/android/server/am/ProviderMap.java b/services/java/com/android/server/am/ProviderMap.java
index 7a4fef6..2d7167b 100644
--- a/services/java/com/android/server/am/ProviderMap.java
+++ b/services/java/com/android/server/am/ProviderMap.java
@@ -180,6 +180,49 @@ public class ProviderMap {
}
}
+ private boolean collectForceStopProvidersLocked(String name, int appId,
+ boolean doit, boolean evenPersistent, int userId,
+ HashMap<ComponentName, ContentProviderRecord> providers,
+ ArrayList<ContentProviderRecord> result) {
+ boolean didSomething = false;
+ for (ContentProviderRecord provider : providers.values()) {
+ if ((name == null || provider.info.packageName.equals(name))
+ && (provider.proc == null || evenPersistent || !provider.proc.persistent)) {
+ if (!doit) {
+ return true;
+ }
+ didSomething = true;
+ result.add(provider);
+ }
+ }
+ return didSomething;
+ }
+
+ boolean collectForceStopProviders(String name, int appId,
+ boolean doit, boolean evenPersistent, int userId,
+ ArrayList<ContentProviderRecord> result) {
+ boolean didSomething = collectForceStopProvidersLocked(name, appId, doit,
+ evenPersistent, userId, mSingletonByClass, result);
+ if (!doit && didSomething) {
+ return true;
+ }
+ if (userId == UserHandle.USER_ALL) {
+ for (int i=0; i<mProvidersByClassPerUser.size(); i++) {
+ if (collectForceStopProvidersLocked(name, appId, doit, evenPersistent,
+ userId, mProvidersByClassPerUser.valueAt(i), result)) {
+ if (!doit) {
+ return true;
+ }
+ didSomething = true;
+ }
+ }
+ } else {
+ didSomething |= collectForceStopProvidersLocked(name, appId, doit, evenPersistent,
+ userId, getProvidersByClass(userId), result);
+ }
+ return didSomething;
+ }
+
private void dumpProvidersByClassLocked(PrintWriter pw, boolean dumpAll,
HashMap<ComponentName, ContentProviderRecord> map) {
Iterator<Map.Entry<ComponentName, ContentProviderRecord>> it = map.entrySet().iterator();
diff --git a/services/java/com/android/server/display/DisplayDevice.java b/services/java/com/android/server/display/DisplayDevice.java
index bdc87f9..8eeefb4 100644
--- a/services/java/com/android/server/display/DisplayDevice.java
+++ b/services/java/com/android/server/display/DisplayDevice.java
@@ -17,7 +17,6 @@
package com.android.server.display;
import android.graphics.Rect;
-import android.graphics.SurfaceTexture;
import android.os.IBinder;
import android.view.Surface;
@@ -41,9 +40,9 @@ abstract class DisplayDevice {
private Rect mCurrentLayerStackRect;
private Rect mCurrentDisplayRect;
- // The display device does own its surface texture, but it should only set it
+ // The display device owns its surface, but it should only set it
// within a transaction from performTraversalInTransactionLocked.
- private SurfaceTexture mCurrentSurfaceTexture;
+ private Surface mCurrentSurface;
public DisplayDevice(DisplayAdapter displayAdapter, IBinder displayToken) {
mDisplayAdapter = displayAdapter;
@@ -109,11 +108,10 @@ abstract class DisplayDevice {
* Sets the display layer stack while in a transaction.
*/
public final void setLayerStackInTransactionLocked(int layerStack) {
- if (mCurrentLayerStack == layerStack) {
- return;
+ if (mCurrentLayerStack != layerStack) {
+ mCurrentLayerStack = layerStack;
+ Surface.setDisplayLayerStack(mDisplayToken, layerStack);
}
- mCurrentLayerStack = layerStack;
- Surface.setDisplayLayerStack(mDisplayToken, layerStack);
}
/**
@@ -126,28 +124,58 @@ abstract class DisplayDevice {
* mapped to. displayRect is specified post-orientation, that is
* it uses the orientation seen by the end-user
*/
- public final void setProjectionInTransactionLocked(int orientation, Rect layerStackRect, Rect displayRect) {
- mCurrentOrientation = orientation;
- if (mCurrentLayerStackRect == null) {
- mCurrentLayerStackRect = new Rect();
+ public final void setProjectionInTransactionLocked(int orientation,
+ Rect layerStackRect, Rect displayRect) {
+ if (mCurrentOrientation != orientation
+ || mCurrentLayerStackRect == null
+ || !mCurrentLayerStackRect.equals(layerStackRect)
+ || mCurrentDisplayRect == null
+ || !mCurrentDisplayRect.equals(displayRect)) {
+ mCurrentOrientation = orientation;
+
+ if (mCurrentLayerStackRect == null) {
+ mCurrentLayerStackRect = new Rect();
+ }
+ mCurrentLayerStackRect.set(layerStackRect);
+
+ if (mCurrentDisplayRect == null) {
+ mCurrentDisplayRect = new Rect();
+ }
+ mCurrentDisplayRect.set(displayRect);
+
+ Surface.setDisplayProjection(mDisplayToken,
+ orientation, layerStackRect, displayRect);
}
- mCurrentLayerStackRect.set(layerStackRect);
- if (mCurrentDisplayRect == null) {
- mCurrentDisplayRect = new Rect();
+ }
+
+ /**
+ * Sets the display surface while in a transaction.
+ */
+ public final void setSurfaceInTransactionLocked(Surface surface) {
+ if (mCurrentSurface != surface) {
+ mCurrentSurface = surface;
+ Surface.setDisplaySurface(mDisplayToken, surface);
}
- mCurrentDisplayRect.set(displayRect);
- Surface.setDisplayProjection(mDisplayToken, orientation, layerStackRect, displayRect);
}
/**
- * Sets the surface texture while in a transaction.
+ * Populates the specified viewport object with orientation,
+ * physical and logical rects based on the display's current projection.
*/
- public final void setSurfaceTextureInTransactionLocked(SurfaceTexture surfaceTexture) {
- if (mCurrentSurfaceTexture == surfaceTexture) {
- return;
+ public final void populateViewportLocked(DisplayViewport viewport) {
+ viewport.orientation = mCurrentOrientation;
+
+ if (mCurrentLayerStackRect != null) {
+ viewport.logicalFrame.set(mCurrentLayerStackRect);
+ } else {
+ viewport.logicalFrame.setEmpty();
+ }
+
+ if (mCurrentDisplayRect != null) {
+ viewport.physicalFrame.set(mCurrentDisplayRect);
+ } else {
+ viewport.physicalFrame.setEmpty();
}
- mCurrentSurfaceTexture = surfaceTexture;
- Surface.setDisplaySurface(mDisplayToken, surfaceTexture);
}
/**
@@ -156,10 +184,11 @@ abstract class DisplayDevice {
*/
public void dumpLocked(PrintWriter pw) {
pw.println("mAdapter=" + mDisplayAdapter.getName());
+ pw.println("mDisplayToken=" + mDisplayToken);
pw.println("mCurrentLayerStack=" + mCurrentLayerStack);
pw.println("mCurrentOrientation=" + mCurrentOrientation);
- pw.println("mCurrentViewport=" + mCurrentLayerStackRect);
- pw.println("mCurrentFrame=" + mCurrentDisplayRect);
- pw.println("mCurrentSurfaceTexture=" + mCurrentSurfaceTexture);
+ pw.println("mCurrentLayerStackRect=" + mCurrentLayerStackRect);
+ pw.println("mCurrentDisplayRect=" + mCurrentDisplayRect);
+ pw.println("mCurrentSurface=" + mCurrentSurface);
}
}
diff --git a/services/java/com/android/server/display/DisplayDeviceInfo.java b/services/java/com/android/server/display/DisplayDeviceInfo.java
index 6f82119..7c57694 100644
--- a/services/java/com/android/server/display/DisplayDeviceInfo.java
+++ b/services/java/com/android/server/display/DisplayDeviceInfo.java
@@ -16,6 +16,8 @@
package com.android.server.display;
+import android.util.DisplayMetrics;
+
import libcore.util.Objects;
/**
@@ -41,6 +43,21 @@ final class DisplayDeviceInfo {
public static final int FLAG_SUPPORTS_ROTATION = 1 << 2;
/**
+ * Touch attachment: Display does not receive touch.
+ */
+ public static final int TOUCH_NONE = 0;
+
+ /**
+ * Touch attachment: Touch input is via the internal interface.
+ */
+ public static final int TOUCH_INTERNAL = 1;
+
+ /**
+ * Touch attachment: Touch input is via an external interface, such as USB.
+ */
+ public static final int TOUCH_EXTERNAL = 2;
+
+ /**
* Gets the name of the display device, which may be derived from
* EDID or other sources. The name may be displayed to the user.
*/
@@ -58,13 +75,49 @@ final class DisplayDeviceInfo {
*/
public int height;
+ /**
+ * The refresh rate of the display.
+ */
public float refreshRate;
+
+ /**
+ * The nominal apparent density of the display in DPI used for layout calculations.
+ * This density is sensitive to the viewing distance. A big TV and a tablet may have
+ * the same apparent density even though the pixels on the TV are much bigger than
+ * those on the tablet.
+ */
public int densityDpi;
+
+ /**
+ * The physical density of the display in DPI in the X direction.
+ * This density should specify the physical size of each pixel.
+ */
public float xDpi;
+
+ /**
+ * The physical density of the display in DPI in the X direction.
+ * This density should specify the physical size of each pixel.
+ */
public float yDpi;
+ /**
+ * Display flags.
+ */
public int flags;
+ /**
+ * The touch attachment, per {@link DisplayViewport#touch}.
+ */
+ public int touch;
+
+ public void setAssumedDensityForExternalDisplay(int width, int height) {
+ densityDpi = Math.min(width, height) * DisplayMetrics.DENSITY_XHIGH / 1080;
+ // Technically, these values should be smaller than the apparent density
+ // but we don't know the physical size of the display.
+ xDpi = densityDpi;
+ yDpi = densityDpi;
+ }
+
@Override
public boolean equals(Object o) {
return o instanceof DisplayDeviceInfo && equals((DisplayDeviceInfo)o);
@@ -79,7 +132,8 @@ final class DisplayDeviceInfo {
&& densityDpi == other.densityDpi
&& xDpi == other.xDpi
&& yDpi == other.yDpi
- && flags == other.flags;
+ && flags == other.flags
+ && touch == other.touch;
}
@Override
@@ -96,6 +150,7 @@ final class DisplayDeviceInfo {
xDpi = other.xDpi;
yDpi = other.yDpi;
flags = other.flags;
+ touch = other.touch;
}
// For debugging purposes
@@ -103,7 +158,20 @@ final class DisplayDeviceInfo {
public String toString() {
return "DisplayDeviceInfo{\"" + name + "\": " + width + " x " + height + ", " + refreshRate + " fps, "
+ "density " + densityDpi + ", " + xDpi + " x " + yDpi + " dpi"
- + flagsToString(flags) + "}";
+ + ", touch " + touchToString(touch) + flagsToString(flags) + "}";
+ }
+
+ private static String touchToString(int touch) {
+ switch (touch) {
+ case TOUCH_NONE:
+ return "NONE";
+ case TOUCH_INTERNAL:
+ return "INTERNAL";
+ case TOUCH_EXTERNAL:
+ return "EXTERNAL";
+ default:
+ return Integer.toString(touch);
+ }
}
private static String flagsToString(int flags) {
diff --git a/services/java/com/android/server/display/DisplayManagerService.java b/services/java/com/android/server/display/DisplayManagerService.java
index 706007a..39f2418 100644
--- a/services/java/com/android/server/display/DisplayManagerService.java
+++ b/services/java/com/android/server/display/DisplayManagerService.java
@@ -24,6 +24,7 @@ import android.content.pm.PackageManager;
import android.hardware.display.DisplayManagerGlobal;
import android.hardware.display.IDisplayManager;
import android.hardware.display.IDisplayManagerCallback;
+import android.hardware.display.WifiDisplayStatus;
import android.os.Binder;
import android.os.Handler;
import android.os.IBinder;
@@ -58,7 +59,7 @@ import java.util.ArrayList;
* </p><p>
* Display adapters are only weakly coupled to the display manager service.
* Display adapters communicate changes in display device state to the display manager
- * service asynchronously via a {@link DisplayAdapter.DisplayAdapterListener} registered
+ * service asynchronously via a {@link DisplayAdapter.Listener} registered
* by the display manager service. This separation of concerns is important for
* two main reasons. First, it neatly encapsulates the responsibilities of these
* two classes: display adapters handle individual display devices whereas
@@ -95,6 +96,7 @@ public final class DisplayManagerService extends IDisplayManager.Stub {
private static final int MSG_REGISTER_ADDITIONAL_DISPLAY_ADAPTERS = 2;
private static final int MSG_DELIVER_DISPLAY_EVENT = 3;
private static final int MSG_REQUEST_TRAVERSAL = 4;
+ private static final int MSG_UPDATE_VIEWPORT = 5;
private final Context mContext;
private final boolean mHeadless;
@@ -102,6 +104,7 @@ public final class DisplayManagerService extends IDisplayManager.Stub {
private final Handler mUiHandler;
private final DisplayAdapterListener mDisplayAdapterListener;
private WindowManagerFuncs mWindowManagerFuncs;
+ private InputManagerFuncs mInputManagerFuncs;
// The synchronization root for the display manager.
// This lock guards most of the display manager's state.
@@ -137,6 +140,14 @@ public final class DisplayManagerService extends IDisplayManager.Stub {
// to the surface flinger state.
private boolean mPendingTraversal;
+ // The Wifi display adapter, or null if not registered.
+ private WifiDisplayAdapter mWifiDisplayAdapter;
+
+ // Viewports of the default display and the display that should receive touch
+ // input from an external source. Used by the input system.
+ private final DisplayViewport mDefaultViewport = new DisplayViewport();
+ private final DisplayViewport mExternalTouchViewport = new DisplayViewport();
+
// Temporary callback list, used when sending display events to applications.
// May be used outside of the lock but only on the handler thread.
private final ArrayList<CallbackRecord> mTempCallbacks = new ArrayList<CallbackRecord>();
@@ -144,6 +155,11 @@ public final class DisplayManagerService extends IDisplayManager.Stub {
// Temporary display info, used for comparing display configurations.
private final DisplayInfo mTempDisplayInfo = new DisplayInfo();
+ // Temporary viewports, used when sending new viewport information to the
+ // input system. May be used outside of the lock but only on the handler thread.
+ private final DisplayViewport mTempDefaultViewport = new DisplayViewport();
+ private final DisplayViewport mTempExternalTouchViewport = new DisplayViewport();
+
public DisplayManagerService(Context context, Handler mainHandler, Handler uiHandler) {
mContext = context;
mHeadless = SystemProperties.get(SYSTEM_HEADLESS).equals("1");
@@ -179,7 +195,7 @@ public final class DisplayManagerService extends IDisplayManager.Stub {
}
/**
- * Called during initialization to associated the display manager with the
+ * Called during initialization to associate the display manager with the
* window manager.
*/
public void setWindowManager(WindowManagerFuncs windowManagerFuncs) {
@@ -190,6 +206,17 @@ public final class DisplayManagerService extends IDisplayManager.Stub {
}
/**
+ * Called during initialization to associate the display manager with the
+ * input manager.
+ */
+ public void setInputManager(InputManagerFuncs inputManagerFuncs) {
+ synchronized (mSyncRoot) {
+ mInputManagerFuncs = inputManagerFuncs;
+ scheduleTraversalLocked();
+ }
+ }
+
+ /**
* Called when the system is ready to go.
*/
public void systemReady(boolean safeMode, boolean onlyCore) {
@@ -254,8 +281,8 @@ public final class DisplayManagerService extends IDisplayManager.Stub {
* Returns information about the specified logical display.
*
* @param displayId The logical display id.
- * @param The logical display info, or null if the display does not exist.
- * This object must be treated as immutable.
+ * @return The logical display info, or null if the display does not exist. The
+ * returned object must be treated as immutable.
*/
@Override // Binder call
public DisplayInfo getDisplayInfo(int displayId) {
@@ -315,6 +342,87 @@ public final class DisplayManagerService extends IDisplayManager.Stub {
}
}
+ @Override // Binder call
+ public void scanWifiDisplays() {
+ if (mContext.checkCallingPermission(android.Manifest.permission.CONFIGURE_WIFI_DISPLAY)
+ != PackageManager.PERMISSION_GRANTED) {
+ throw new SecurityException("Requires CONFIGURE_WIFI_DISPLAY permission");
+ }
+
+ final long token = Binder.clearCallingIdentity();
+ try {
+ synchronized (mSyncRoot) {
+ if (mWifiDisplayAdapter != null) {
+ mWifiDisplayAdapter.requestScanLocked();
+ }
+ }
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
+ }
+
+ @Override // Binder call
+ public void connectWifiDisplay(String address) {
+ if (mContext.checkCallingPermission(android.Manifest.permission.CONFIGURE_WIFI_DISPLAY)
+ != PackageManager.PERMISSION_GRANTED) {
+ throw new SecurityException("Requires CONFIGURE_WIFI_DISPLAY permission");
+ }
+ if (address == null) {
+ throw new IllegalArgumentException("address must not be null");
+ }
+
+ final long token = Binder.clearCallingIdentity();
+ try {
+ synchronized (mSyncRoot) {
+ if (mWifiDisplayAdapter != null) {
+ mWifiDisplayAdapter.requestConnectLocked(address);
+ }
+ }
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
+ }
+
+ @Override // Binder call
+ public void disconnectWifiDisplay() {
+ if (mContext.checkCallingPermission(android.Manifest.permission.CONFIGURE_WIFI_DISPLAY)
+ != PackageManager.PERMISSION_GRANTED) {
+ throw new SecurityException("Requires CONFIGURE_WIFI_DISPLAY permission");
+ }
+
+ final long token = Binder.clearCallingIdentity();
+ try {
+ synchronized (mSyncRoot) {
+ if (mWifiDisplayAdapter != null) {
+ mWifiDisplayAdapter.requestDisconnectLocked();
+ }
+ }
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
+ }
+
+ @Override // Binder call
+ public WifiDisplayStatus getWifiDisplayStatus() {
+ if (mContext.checkCallingPermission(android.Manifest.permission.CONFIGURE_WIFI_DISPLAY)
+ != PackageManager.PERMISSION_GRANTED) {
+ throw new SecurityException("Requires CONFIGURE_WIFI_DISPLAY permission");
+ }
+
+ final long token = Binder.clearCallingIdentity();
+ try {
+ synchronized (mSyncRoot) {
+ if (mWifiDisplayAdapter != null) {
+ return mWifiDisplayAdapter.getWifiDisplayStatusLocked();
+ } else {
+ return new WifiDisplayStatus();
+ }
+ }
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
+ }
+
private void registerDefaultDisplayAdapter() {
// Register default display adapter.
synchronized (mSyncRoot) {
@@ -333,6 +441,9 @@ public final class DisplayManagerService extends IDisplayManager.Stub {
if (shouldRegisterNonEssentialDisplayAdaptersLocked()) {
registerDisplayAdapterLocked(new OverlayDisplayAdapter(
mSyncRoot, mContext, mHandler, mDisplayAdapterListener, mUiHandler));
+ mWifiDisplayAdapter = new WifiDisplayAdapter(
+ mSyncRoot, mContext, mHandler, mDisplayAdapterListener);
+ registerDisplayAdapterLocked(mWifiDisplayAdapter);
}
}
}
@@ -409,7 +520,7 @@ public final class DisplayManagerService extends IDisplayManager.Stub {
final int displayId = assignDisplayIdLocked(isDefault);
final int layerStack = assignLayerStackLocked(displayId);
- LogicalDisplay display = new LogicalDisplay(layerStack, device);
+ LogicalDisplay display = new LogicalDisplay(displayId, layerStack, device);
display.updateLocked(mDisplayDevices);
if (!display.isValidLocked()) {
// This should never happen currently.
@@ -470,6 +581,10 @@ public final class DisplayManagerService extends IDisplayManager.Stub {
}
mRemovedDisplayDevices.clear();
+ // Clear all viewports before configuring displays so that we can keep
+ // track of which ones we have configured.
+ clearViewportsLocked();
+
// Configure each display device.
final int count = mDisplayDevices.size();
for (int i = 0; i < count; i++) {
@@ -477,16 +592,45 @@ public final class DisplayManagerService extends IDisplayManager.Stub {
configureDisplayInTransactionLocked(device);
device.performTraversalInTransactionLocked();
}
+
+ // Tell the input system about these new viewports.
+ if (mInputManagerFuncs != null) {
+ mHandler.sendEmptyMessage(MSG_UPDATE_VIEWPORT);
+ }
}
- private void configureDisplayInTransactionLocked(DisplayDevice device) {
- // TODO: add a proper per-display mirroring control
- boolean isMirroring = SystemProperties.getBoolean("debug.display.mirror", true);
+ /**
+ * Tells the display manager whether there is interesting unique content on the
+ * specified logical display. This is used to control automatic mirroring.
+ * <p>
+ * If the display has unique content, then the display manager arranges for it
+ * to be presented on a physical display if appropriate. Otherwise, the display manager
+ * may choose to make the physical display mirror some other logical display.
+ * </p>
+ *
+ * @param displayId The logical display id to update.
+ * @param hasContent True if the logical display has content.
+ */
+ public void setDisplayHasContent(int displayId, boolean hasContent) {
+ synchronized (mSyncRoot) {
+ LogicalDisplay display = mLogicalDisplays.get(displayId);
+ if (display != null && display.hasContentLocked() != hasContent) {
+ display.setHasContentLocked(hasContent);
+ scheduleTraversalLocked();
+ }
+ }
+ }
+ private void clearViewportsLocked() {
+ mDefaultViewport.valid = false;
+ mExternalTouchViewport.valid = false;
+ }
+
+ private void configureDisplayInTransactionLocked(DisplayDevice device) {
// Find the logical display that the display device is showing.
- LogicalDisplay display = null;
- if (!isMirroring) {
- display = findLogicalDisplayForDeviceLocked(device);
+ LogicalDisplay display = findLogicalDisplayForDeviceLocked(device);
+ if (display != null && !display.hasContentLocked()) {
+ display = null;
}
if (display == null) {
display = mLogicalDisplays.get(Display.DEFAULT_DISPLAY);
@@ -495,11 +639,30 @@ public final class DisplayManagerService extends IDisplayManager.Stub {
// Apply the logical display configuration to the display device.
if (display == null) {
// TODO: no logical display for the device, blank it
- Slog.d(TAG, "Missing logical display to use for physical display device: "
+ Slog.w(TAG, "Missing logical display to use for physical display device: "
+ device.getDisplayDeviceInfoLocked());
+ return;
} else {
display.configureDisplayInTransactionLocked(device);
}
+
+ // Update the viewports if needed.
+ DisplayDeviceInfo info = device.getDisplayDeviceInfoLocked();
+ if (!mDefaultViewport.valid
+ && (info.flags & DisplayDeviceInfo.FLAG_DEFAULT_DISPLAY) != 0) {
+ setViewportLocked(mDefaultViewport, display, device);
+ }
+ if (!mExternalTouchViewport.valid
+ && info.touch == DisplayDeviceInfo.TOUCH_EXTERNAL) {
+ setViewportLocked(mExternalTouchViewport, display, device);
+ }
+ }
+
+ private static void setViewportLocked(DisplayViewport viewport,
+ LogicalDisplay display, DisplayDevice device) {
+ viewport.valid = true;
+ viewport.displayId = display.getDisplayIdLocked();
+ device.populateViewportLocked(viewport);
}
private LogicalDisplay findLogicalDisplayForDeviceLocked(DisplayDevice device) {
@@ -592,6 +755,10 @@ public final class DisplayManagerService extends IDisplayManager.Stub {
pw.println(" Display " + displayId + ":");
display.dumpLocked(ipw);
}
+
+ pw.println();
+ pw.println("Default viewport: " + mDefaultViewport);
+ pw.println("External touch viewport: " + mExternalTouchViewport);
}
}
@@ -609,12 +776,25 @@ public final class DisplayManagerService extends IDisplayManager.Stub {
*/
public interface WindowManagerFuncs {
/**
- * Request that the window manager call {@link #performTraversalInTransaction}
- * within a surface transaction at a later time.
+ * Request that the window manager call
+ * {@link #performTraversalInTransactionFromWindowManager} within a surface
+ * transaction at a later time.
*/
void requestTraversal();
}
+ /**
+ * Private interface to the input manager.
+ */
+ public interface InputManagerFuncs {
+ /**
+ * Sets information about the displays as needed by the input system.
+ * The input system should copy this information if required.
+ */
+ void setDisplayViewports(DisplayViewport defaultViewport,
+ DisplayViewport externalTouchViewport);
+ }
+
private final class DisplayManagerHandler extends Handler {
public DisplayManagerHandler(Looper looper) {
super(looper, null, true /*async*/);
@@ -638,6 +818,16 @@ public final class DisplayManagerService extends IDisplayManager.Stub {
case MSG_REQUEST_TRAVERSAL:
mWindowManagerFuncs.requestTraversal();
break;
+
+ case MSG_UPDATE_VIEWPORT: {
+ synchronized (mSyncRoot) {
+ mTempDefaultViewport.copyFrom(mDefaultViewport);
+ mTempExternalTouchViewport.copyFrom(mExternalTouchViewport);
+ }
+ mInputManagerFuncs.setDisplayViewports(
+ mTempDefaultViewport, mTempExternalTouchViewport);
+ break;
+ }
}
}
}
diff --git a/services/java/com/android/server/display/DisplayViewport.java b/services/java/com/android/server/display/DisplayViewport.java
new file mode 100644
index 0000000..ed4016d
--- /dev/null
+++ b/services/java/com/android/server/display/DisplayViewport.java
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.display;
+
+import android.graphics.Rect;
+
+/**
+ * Describes how the pixels of physical display device reflects the content of
+ * a logical display.
+ * <p>
+ * This information is used by the input system to translate touch input from
+ * physical display coordinates into logical display coordinates.
+ * </p>
+ */
+public final class DisplayViewport {
+ // True if this viewport is valid.
+ public boolean valid;
+
+ // The logical display id.
+ public int displayId;
+
+ // The rotation applied to the physical coordinate system.
+ public int orientation;
+
+ // The portion of the logical display that are presented on this physical display.
+ public final Rect logicalFrame = new Rect();
+
+ // The portion of the (rotated) physical display that shows the logical display contents.
+ // The relation between logical and physical frame defines how the coordinate system
+ // should be scaled or translated after rotation.
+ public final Rect physicalFrame = new Rect();
+
+ public void copyFrom(DisplayViewport viewport) {
+ valid = viewport.valid;
+ displayId = viewport.displayId;
+ orientation = viewport.orientation;
+ logicalFrame.set(viewport.logicalFrame);
+ physicalFrame.set(viewport.physicalFrame);
+ }
+
+ // For debugging purposes.
+ @Override
+ public String toString() {
+ return "DisplayViewport{valid=" + valid
+ + ", displayId=" + displayId
+ + ", orientation=" + orientation
+ + ", logicalFrame=" + logicalFrame
+ + ", physicalFrame=" + physicalFrame
+ + "}";
+ }
+}
diff --git a/services/java/com/android/server/display/HeadlessDisplayAdapter.java b/services/java/com/android/server/display/HeadlessDisplayAdapter.java
index 3aaacf1..7629db6 100644
--- a/services/java/com/android/server/display/HeadlessDisplayAdapter.java
+++ b/services/java/com/android/server/display/HeadlessDisplayAdapter.java
@@ -61,6 +61,7 @@ final class HeadlessDisplayAdapter extends DisplayAdapter {
mInfo.yDpi = 160;
mInfo.flags = DisplayDeviceInfo.FLAG_DEFAULT_DISPLAY
| DisplayDeviceInfo.FLAG_SECURE;
+ mInfo.touch = DisplayDeviceInfo.TOUCH_NONE;
}
return mInfo;
}
diff --git a/services/java/com/android/server/display/LocalDisplayAdapter.java b/services/java/com/android/server/display/LocalDisplayAdapter.java
index 4a8829a..80c860b 100644
--- a/services/java/com/android/server/display/LocalDisplayAdapter.java
+++ b/services/java/com/android/server/display/LocalDisplayAdapter.java
@@ -120,19 +120,22 @@ final class LocalDisplayAdapter extends DisplayAdapter {
mInfo.width = mPhys.width;
mInfo.height = mPhys.height;
mInfo.refreshRate = mPhys.refreshRate;
- mInfo.densityDpi = (int)(mPhys.density * 160 + 0.5f);
- mInfo.xDpi = mPhys.xDpi;
- mInfo.yDpi = mPhys.yDpi;
if (mBuiltInDisplayId == Surface.BUILT_IN_DISPLAY_ID_MAIN) {
mInfo.name = getContext().getResources().getString(
com.android.internal.R.string.display_manager_built_in_display_name);
mInfo.flags = DisplayDeviceInfo.FLAG_DEFAULT_DISPLAY
| DisplayDeviceInfo.FLAG_SECURE
| DisplayDeviceInfo.FLAG_SUPPORTS_ROTATION;
+ mInfo.densityDpi = (int)(mPhys.density * 160 + 0.5f);
+ mInfo.xDpi = mPhys.xDpi;
+ mInfo.yDpi = mPhys.yDpi;
+ mInfo.touch = DisplayDeviceInfo.TOUCH_INTERNAL;
} else {
mInfo.name = getContext().getResources().getString(
com.android.internal.R.string.display_manager_hdmi_display_name);
mInfo.flags = DisplayDeviceInfo.FLAG_SECURE;
+ mInfo.touch = DisplayDeviceInfo.TOUCH_EXTERNAL;
+ mInfo.setAssumedDensityForExternalDisplay(mPhys.width, mPhys.height);
}
}
return mInfo;
diff --git a/services/java/com/android/server/display/LogicalDisplay.java b/services/java/com/android/server/display/LogicalDisplay.java
index c864189..2e75260 100644
--- a/services/java/com/android/server/display/LogicalDisplay.java
+++ b/services/java/com/android/server/display/LogicalDisplay.java
@@ -54,6 +54,7 @@ import libcore.util.Objects;
final class LogicalDisplay {
private final DisplayInfo mBaseDisplayInfo = new DisplayInfo();
+ private final int mDisplayId;
private final int mLayerStack;
private DisplayInfo mOverrideDisplayInfo; // set by the window manager
private DisplayInfo mInfo;
@@ -63,16 +64,29 @@ final class LogicalDisplay {
private DisplayDevice mPrimaryDisplayDevice;
private DisplayDeviceInfo mPrimaryDisplayDeviceInfo;
+ // True if the logical display has unique content.
+ private boolean mHasContent;
+
// Temporary rectangle used when needed.
private final Rect mTempLayerStackRect = new Rect();
private final Rect mTempDisplayRect = new Rect();
- public LogicalDisplay(int layerStack, DisplayDevice primaryDisplayDevice) {
+ public LogicalDisplay(int displayId, int layerStack, DisplayDevice primaryDisplayDevice) {
+ mDisplayId = displayId;
mLayerStack = layerStack;
mPrimaryDisplayDevice = primaryDisplayDevice;
}
/**
+ * Gets the logical display id of this logical display.
+ *
+ * @return The logical display id.
+ */
+ public int getDisplayIdLocked() {
+ return mDisplayId;
+ }
+
+ /**
* Gets the primary display device associated with this logical display.
*
* @return The primary display device.
@@ -126,7 +140,7 @@ final class LogicalDisplay {
/**
* Returns true if the logical display is in a valid state.
- * This method should be checked after calling {@link #update} to handle the
+ * This method should be checked after calling {@link #updateLocked} to handle the
* case where a logical display should be removed because all of its associated
* display devices are gone or if it is otherwise no longer needed.
*
@@ -256,6 +270,29 @@ final class LogicalDisplay {
device.setProjectionInTransactionLocked(orientation, mTempLayerStackRect, mTempDisplayRect);
}
+ /**
+ * Returns true if the logical display has unique content.
+ * <p>
+ * If the display has unique content then we will try to ensure that it is
+ * visible on at least its primary display device. Otherwise we will ignore the
+ * logical display and perhaps show mirrored content on the primary display device.
+ * </p>
+ *
+ * @return True if the display has unique content.
+ */
+ public boolean hasContentLocked() {
+ return mHasContent;
+ }
+
+ /**
+ * Sets whether the logical display has unique content.
+ *
+ * @param hasContent True if the display has unique content.
+ */
+ public void setHasContentLocked(boolean hasContent) {
+ mHasContent = hasContent;
+ }
+
public void dumpLocked(PrintWriter pw) {
pw.println("mLayerStack=" + mLayerStack);
pw.println("mPrimaryDisplayDevice=" + (mPrimaryDisplayDevice != null ?
diff --git a/services/java/com/android/server/display/OverlayDisplayAdapter.java b/services/java/com/android/server/display/OverlayDisplayAdapter.java
index ea7e88d..9b0e534 100644
--- a/services/java/com/android/server/display/OverlayDisplayAdapter.java
+++ b/services/java/com/android/server/display/OverlayDisplayAdapter.java
@@ -16,9 +16,11 @@
package com.android.server.display;
+import com.android.internal.util.DumpUtils;
+import com.android.internal.util.IndentingPrintWriter;
+
import android.content.Context;
import android.database.ContentObserver;
-import android.graphics.SurfaceTexture;
import android.os.Handler;
import android.os.IBinder;
import android.provider.Settings;
@@ -28,7 +30,6 @@ import android.view.Gravity;
import android.view.Surface;
import java.io.PrintWriter;
-import java.io.StringWriter;
import java.util.ArrayList;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
@@ -71,6 +72,7 @@ final class OverlayDisplayAdapter extends DisplayAdapter {
@Override
public void dumpLocked(PrintWriter pw) {
super.dumpLocked(pw);
+
pw.println("mCurrentOverlaySetting=" + mCurrentOverlaySetting);
pw.println("mOverlays: size=" + mOverlays.size());
for (OverlayDisplayHandle overlay : mOverlays) {
@@ -81,17 +83,19 @@ final class OverlayDisplayAdapter extends DisplayAdapter {
@Override
public void registerLocked() {
super.registerLocked();
- getContext().getContentResolver().registerContentObserver(
- Settings.System.getUriFor(Settings.Secure.OVERLAY_DISPLAY_DEVICES), true,
- new ContentObserver(getHandler()) {
- @Override
- public void onChange(boolean selfChange) {
- synchronized (getSyncRoot()) {
- updateOverlayDisplayDevicesLocked();
- }
- }
- });
- updateOverlayDisplayDevicesLocked();
+
+ getHandler().post(new Runnable() {
+ @Override
+ public void run() {
+ getContext().getContentResolver().registerContentObserver(
+ Settings.System.getUriFor(Settings.Secure.OVERLAY_DISPLAY_DEVICES),
+ true, new SettingsObserver(getHandler()));
+
+ synchronized (getSyncRoot()) {
+ updateOverlayDisplayDevicesLocked();
+ }
+ }
+ });
}
private void updateOverlayDisplayDevicesLocked() {
@@ -167,6 +171,19 @@ final class OverlayDisplayAdapter extends DisplayAdapter {
}
}
+ private final class SettingsObserver extends ContentObserver {
+ public SettingsObserver(Handler handler) {
+ super(handler);
+ }
+
+ @Override
+ public void onChange(boolean selfChange) {
+ synchronized (getSyncRoot()) {
+ updateOverlayDisplayDevicesLocked();
+ }
+ }
+ }
+
private final class OverlayDisplayDevice extends DisplayDevice {
private final String mName;
private final int mWidth;
@@ -174,35 +191,29 @@ final class OverlayDisplayAdapter extends DisplayAdapter {
private final float mRefreshRate;
private final int mDensityDpi;
- private SurfaceTexture mSurfaceTexture;
- private boolean mSurfaceTextureChanged;
-
+ private Surface mSurface;
private DisplayDeviceInfo mInfo;
public OverlayDisplayDevice(IBinder displayToken, String name,
- int width, int height, float refreshRate, int densityDpi) {
+ int width, int height, float refreshRate, int densityDpi,
+ Surface surface) {
super(OverlayDisplayAdapter.this, displayToken);
mName = name;
mWidth = width;
mHeight = height;
mRefreshRate = refreshRate;
mDensityDpi = densityDpi;
+ mSurface = surface;
}
- public void setSurfaceTextureLocked(SurfaceTexture surfaceTexture) {
- if (surfaceTexture != mSurfaceTexture) {
- mSurfaceTexture = surfaceTexture;
- mSurfaceTextureChanged = true;
- sendTraversalRequestLocked();
- }
+ public void clearSurfaceLocked() {
+ mSurface = null;
+ sendTraversalRequestLocked();
}
@Override
public void performTraversalInTransactionLocked() {
- if (mSurfaceTextureChanged) {
- setSurfaceTextureInTransactionLocked(mSurfaceTexture);
- mSurfaceTextureChanged = false;
- }
+ setSurfaceInTransactionLocked(mSurface);
}
@Override
@@ -217,6 +228,7 @@ final class OverlayDisplayAdapter extends DisplayAdapter {
mInfo.xDpi = mDensityDpi;
mInfo.yDpi = mDensityDpi;
mInfo.flags = DisplayDeviceInfo.FLAG_SECURE;
+ mInfo.touch = DisplayDeviceInfo.TOUCH_NONE;
}
return mInfo;
}
@@ -256,12 +268,11 @@ final class OverlayDisplayAdapter extends DisplayAdapter {
// Called on the UI thread.
@Override
- public void onWindowCreated(SurfaceTexture surfaceTexture, float refreshRate) {
+ public void onWindowCreated(Surface surface, float refreshRate) {
synchronized (getSyncRoot()) {
IBinder displayToken = Surface.createDisplay(mName);
mDevice = new OverlayDisplayDevice(displayToken, mName,
- mWidth, mHeight, refreshRate, mDensityDpi);
- mDevice.setSurfaceTextureLocked(surfaceTexture);
+ mWidth, mHeight, refreshRate, mDensityDpi, surface);
sendDisplayDeviceEventLocked(mDevice, DISPLAY_DEVICE_EVENT_ADDED);
}
@@ -272,40 +283,24 @@ final class OverlayDisplayAdapter extends DisplayAdapter {
public void onWindowDestroyed() {
synchronized (getSyncRoot()) {
if (mDevice != null) {
- mDevice.setSurfaceTextureLocked(null);
-
+ mDevice.clearSurfaceLocked();
sendDisplayDeviceEventLocked(mDevice, DISPLAY_DEVICE_EVENT_REMOVED);
}
}
}
public void dumpLocked(PrintWriter pw) {
- pw.println(" " + mName + ": ");
+ pw.println(" " + mName + ":");
pw.println(" mWidth=" + mWidth);
pw.println(" mHeight=" + mHeight);
pw.println(" mDensityDpi=" + mDensityDpi);
pw.println(" mGravity=" + mGravity);
// Try to dump the window state.
- // This call may hang if the UI thread is waiting to acquire our lock so
- // we use a short timeout to recover just in case.
if (mWindow != null) {
- final StringWriter sw = new StringWriter();
- final OverlayDisplayWindow window = mWindow;
- if (mUiHandler.runWithScissors(new Runnable() {
- @Override
- public void run() {
- PrintWriter lpw = new PrintWriter(sw);
- window.dump(lpw);
- lpw.close();
- }
- }, 200)) {
- for (String line : sw.toString().split("\n")) {
- pw.println(line);
- }
- } else {
- pw.println(" ... timed out while attempting to dump window state");
- }
+ final IndentingPrintWriter ipw = new IndentingPrintWriter(pw, " ");
+ ipw.increaseIndent();
+ DumpUtils.dumpAsync(mUiHandler, mWindow, ipw, 200);
}
}
diff --git a/services/java/com/android/server/display/OverlayDisplayWindow.java b/services/java/com/android/server/display/OverlayDisplayWindow.java
index 6adfa0f..d08f65f 100644
--- a/services/java/com/android/server/display/OverlayDisplayWindow.java
+++ b/services/java/com/android/server/display/OverlayDisplayWindow.java
@@ -16,6 +16,8 @@
package com.android.server.display;
+import com.android.internal.util.DumpUtils;
+
import android.content.Context;
import android.graphics.SurfaceTexture;
import android.hardware.display.DisplayManager;
@@ -27,6 +29,7 @@ import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.ScaleGestureDetector;
+import android.view.Surface;
import android.view.TextureView;
import android.view.View;
import android.view.WindowManager;
@@ -42,7 +45,7 @@ import java.io.PrintWriter;
* No locks are held by this object and locks must not be held while making called into it.
* </p>
*/
-final class OverlayDisplayWindow {
+final class OverlayDisplayWindow implements DumpUtils.Dump {
private static final String TAG = "OverlayDisplayWindow";
private static final boolean DEBUG = false;
@@ -144,18 +147,18 @@ final class OverlayDisplayWindow {
}
public void dump(PrintWriter pw) {
- pw.println(" mWindowVisible=" + mWindowVisible);
- pw.println(" mWindowX=" + mWindowX);
- pw.println(" mWindowY=" + mWindowY);
- pw.println(" mWindowScale=" + mWindowScale);
- pw.println(" mWindowParams=" + mWindowParams);
+ pw.println("mWindowVisible=" + mWindowVisible);
+ pw.println("mWindowX=" + mWindowX);
+ pw.println("mWindowY=" + mWindowY);
+ pw.println("mWindowScale=" + mWindowScale);
+ pw.println("mWindowParams=" + mWindowParams);
if (mTextureView != null) {
- pw.println(" mTextureView.getScaleX()=" + mTextureView.getScaleX());
- pw.println(" mTextureView.getScaleY()=" + mTextureView.getScaleY());
+ pw.println("mTextureView.getScaleX()=" + mTextureView.getScaleX());
+ pw.println("mTextureView.getScaleY()=" + mTextureView.getScaleY());
}
- pw.println(" mLiveTranslationX=" + mLiveTranslationX);
- pw.println(" mLiveTranslationY=" + mLiveTranslationY);
- pw.println(" mLiveScale=" + mLiveScale);
+ pw.println("mLiveTranslationX=" + mLiveTranslationX);
+ pw.println("mLiveTranslationY=" + mLiveTranslationY);
+ pw.println("mLiveScale=" + mLiveScale);
}
private boolean updateDefaultDisplayInfo() {
@@ -286,22 +289,25 @@ final class OverlayDisplayWindow {
private final SurfaceTextureListener mSurfaceTextureListener =
new SurfaceTextureListener() {
@Override
- public void onSurfaceTextureAvailable(SurfaceTexture surface, int width, int height) {
- mListener.onWindowCreated(surface, mDefaultDisplayInfo.refreshRate);
+ public void onSurfaceTextureAvailable(SurfaceTexture surfaceTexture,
+ int width, int height) {
+ mListener.onWindowCreated(new Surface(surfaceTexture),
+ mDefaultDisplayInfo.refreshRate);
}
@Override
- public boolean onSurfaceTextureDestroyed(SurfaceTexture surface) {
+ public boolean onSurfaceTextureDestroyed(SurfaceTexture surfaceTexture) {
mListener.onWindowDestroyed();
return true;
}
@Override
- public void onSurfaceTextureSizeChanged(SurfaceTexture surface, int width, int height) {
+ public void onSurfaceTextureSizeChanged(SurfaceTexture surfaceTexture,
+ int width, int height) {
}
@Override
- public void onSurfaceTextureUpdated(SurfaceTexture surface) {
+ public void onSurfaceTextureUpdated(SurfaceTexture surfaceTexture) {
}
};
@@ -355,7 +361,7 @@ final class OverlayDisplayWindow {
* Watches for significant changes in the overlay display window lifecycle.
*/
public interface Listener {
- public void onWindowCreated(SurfaceTexture surfaceTexture, float refreshRate);
+ public void onWindowCreated(Surface surface, float refreshRate);
public void onWindowDestroyed();
}
} \ No newline at end of file
diff --git a/services/java/com/android/server/display/WifiDisplayAdapter.java b/services/java/com/android/server/display/WifiDisplayAdapter.java
new file mode 100644
index 0000000..ee82050
--- /dev/null
+++ b/services/java/com/android/server/display/WifiDisplayAdapter.java
@@ -0,0 +1,428 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.display;
+
+import com.android.internal.util.DumpUtils;
+import com.android.internal.util.IndentingPrintWriter;
+
+import android.content.Context;
+import android.content.Intent;
+import android.hardware.display.DisplayManager;
+import android.hardware.display.WifiDisplay;
+import android.hardware.display.WifiDisplayStatus;
+import android.media.RemoteDisplay;
+import android.os.Handler;
+import android.os.IBinder;
+import android.util.Slog;
+import android.view.Surface;
+
+import java.io.PrintWriter;
+import java.util.Arrays;
+
+/**
+ * Connects to Wifi displays that implement the Miracast protocol.
+ * <p>
+ * The Wifi display protocol relies on Wifi direct for discovering and pairing
+ * with the display. Once connected, the Media Server opens an RTSP socket and accepts
+ * a connection from the display. After session negotiation, the Media Server
+ * streams encoded buffers to the display.
+ * </p><p>
+ * This class is responsible for connecting to Wifi displays and mediating
+ * the interactions between Media Server, Surface Flinger and the Display Manager Service.
+ * </p><p>
+ * Display adapters are guarded by the {@link DisplayManagerService.SyncRoot} lock.
+ * </p>
+ */
+final class WifiDisplayAdapter extends DisplayAdapter {
+ private static final String TAG = "WifiDisplayAdapter";
+
+ private WifiDisplayHandle mDisplayHandle;
+ private WifiDisplayController mDisplayController;
+
+ private WifiDisplayStatus mCurrentStatus;
+ private boolean mEnabled;
+ private int mScanState;
+ private int mActiveDisplayState;
+ private WifiDisplay mActiveDisplay;
+ private WifiDisplay[] mKnownDisplays = WifiDisplay.EMPTY_ARRAY;
+
+ private boolean mPendingStatusChangeBroadcast;
+
+ public WifiDisplayAdapter(DisplayManagerService.SyncRoot syncRoot,
+ Context context, Handler handler, Listener listener) {
+ super(syncRoot, context, handler, listener, TAG);
+ }
+
+ @Override
+ public void dumpLocked(PrintWriter pw) {
+ super.dumpLocked(pw);
+
+ if (mDisplayHandle == null) {
+ pw.println("mDisplayHandle=null");
+ } else {
+ pw.println("mDisplayHandle:");
+ mDisplayHandle.dumpLocked(pw);
+ }
+
+ pw.println("mCurrentStatus=" + getWifiDisplayStatusLocked());
+ pw.println("mEnabled=" + mEnabled);
+ pw.println("mScanState=" + mScanState);
+ pw.println("mActiveDisplayState=" + mActiveDisplayState);
+ pw.println("mActiveDisplay=" + mActiveDisplay);
+ pw.println("mKnownDisplays=" + Arrays.toString(mKnownDisplays));
+ pw.println("mPendingStatusChangeBroadcast=" + mPendingStatusChangeBroadcast);
+
+ // Try to dump the controller state.
+ if (mDisplayController == null) {
+ pw.println("mDisplayController=null");
+ } else {
+ pw.println("mDisplayController:");
+ final IndentingPrintWriter ipw = new IndentingPrintWriter(pw, " ");
+ ipw.increaseIndent();
+ DumpUtils.dumpAsync(getHandler(), mDisplayController, ipw, 200);
+ }
+ }
+
+ @Override
+ public void registerLocked() {
+ super.registerLocked();
+
+ getHandler().post(new Runnable() {
+ @Override
+ public void run() {
+ mDisplayController = new WifiDisplayController(
+ getContext(), getHandler(), mWifiDisplayListener);
+ }
+ });
+ }
+
+ public void requestScanLocked() {
+ getHandler().post(new Runnable() {
+ @Override
+ public void run() {
+ if (mDisplayController != null) {
+ mDisplayController.requestScan();
+ }
+ }
+ });
+ }
+
+ public void requestConnectLocked(final String address) {
+ getHandler().post(new Runnable() {
+ @Override
+ public void run() {
+ if (mDisplayController != null) {
+ mDisplayController.requestConnect(address);
+ }
+ }
+ });
+ }
+
+ public void requestDisconnectLocked() {
+ getHandler().post(new Runnable() {
+ @Override
+ public void run() {
+ if (mDisplayController != null) {
+ mDisplayController.requestDisconnect();
+ }
+ }
+ });
+ }
+
+ public WifiDisplayStatus getWifiDisplayStatusLocked() {
+ if (mCurrentStatus == null) {
+ mCurrentStatus = new WifiDisplayStatus(mEnabled, mScanState, mActiveDisplayState,
+ mActiveDisplay, mKnownDisplays);
+ }
+ return mCurrentStatus;
+ }
+
+ private void handleConnectLocked(WifiDisplay display, String iface) {
+ handleDisconnectLocked();
+
+ mDisplayHandle = new WifiDisplayHandle(display.getDeviceName(), iface);
+ }
+
+ private void handleDisconnectLocked() {
+ if (mDisplayHandle != null) {
+ mDisplayHandle.disposeLocked();
+ mDisplayHandle = null;
+ }
+ }
+
+ private void scheduleStatusChangedBroadcastLocked() {
+ if (!mPendingStatusChangeBroadcast) {
+ mPendingStatusChangeBroadcast = true;
+ getHandler().post(mStatusChangeBroadcast);
+ }
+ }
+
+ private final Runnable mStatusChangeBroadcast = new Runnable() {
+ @Override
+ public void run() {
+ final Intent intent;
+ synchronized (getSyncRoot()) {
+ if (!mPendingStatusChangeBroadcast) {
+ return;
+ }
+
+ mPendingStatusChangeBroadcast = false;
+ intent = new Intent(DisplayManager.ACTION_WIFI_DISPLAY_STATUS_CHANGED);
+ intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
+ intent.putExtra(DisplayManager.EXTRA_WIFI_DISPLAY_STATUS,
+ getWifiDisplayStatusLocked());
+ }
+
+ // Send protected broadcast about wifi display status to receivers that
+ // have the required permission.
+ getContext().sendBroadcast(intent,
+ android.Manifest.permission.CONFIGURE_WIFI_DISPLAY);
+ }
+ };
+
+ private final WifiDisplayController.Listener mWifiDisplayListener =
+ new WifiDisplayController.Listener() {
+ @Override
+ public void onEnablementChanged(boolean enabled) {
+ synchronized (getSyncRoot()) {
+ if (mEnabled != enabled) {
+ mCurrentStatus = null;
+ mEnabled = enabled;
+ scheduleStatusChangedBroadcastLocked();
+ }
+ }
+ }
+
+ @Override
+ public void onScanStarted() {
+ synchronized (getSyncRoot()) {
+ if (mScanState != WifiDisplayStatus.SCAN_STATE_SCANNING) {
+ mCurrentStatus = null;
+ mScanState = WifiDisplayStatus.SCAN_STATE_SCANNING;
+ scheduleStatusChangedBroadcastLocked();
+ }
+ }
+ }
+
+ public void onScanFinished(WifiDisplay[] knownDisplays) {
+ synchronized (getSyncRoot()) {
+ if (mScanState != WifiDisplayStatus.SCAN_STATE_NOT_SCANNING
+ || !Arrays.equals(mKnownDisplays, knownDisplays)) {
+ mCurrentStatus = null;
+ mScanState = WifiDisplayStatus.SCAN_STATE_NOT_SCANNING;
+ mKnownDisplays = knownDisplays;
+ scheduleStatusChangedBroadcastLocked();
+ }
+ }
+ }
+
+ @Override
+ public void onDisplayConnecting(WifiDisplay display) {
+ synchronized (getSyncRoot()) {
+ if (mActiveDisplayState != WifiDisplayStatus.DISPLAY_STATE_CONNECTING
+ || mActiveDisplay == null
+ || !mActiveDisplay.equals(display)) {
+ mCurrentStatus = null;
+ mActiveDisplayState = WifiDisplayStatus.DISPLAY_STATE_CONNECTING;
+ mActiveDisplay = display;
+ scheduleStatusChangedBroadcastLocked();
+ }
+ }
+ }
+
+ @Override
+ public void onDisplayConnectionFailed() {
+ synchronized (getSyncRoot()) {
+ if (mActiveDisplayState != WifiDisplayStatus.DISPLAY_STATE_NOT_CONNECTED
+ || mActiveDisplay != null) {
+ mCurrentStatus = null;
+ mActiveDisplayState = WifiDisplayStatus.DISPLAY_STATE_NOT_CONNECTED;
+ mActiveDisplay = null;
+ scheduleStatusChangedBroadcastLocked();
+ }
+ }
+ }
+
+ @Override
+ public void onDisplayConnected(WifiDisplay display, String iface) {
+ synchronized (getSyncRoot()) {
+ handleConnectLocked(display, iface);
+
+ if (mActiveDisplayState != WifiDisplayStatus.DISPLAY_STATE_CONNECTED
+ || mActiveDisplay == null
+ || !mActiveDisplay.equals(display)) {
+ mCurrentStatus = null;
+ mActiveDisplayState = WifiDisplayStatus.DISPLAY_STATE_CONNECTED;
+ mActiveDisplay = display;
+ scheduleStatusChangedBroadcastLocked();
+ }
+ }
+ }
+
+ @Override
+ public void onDisplayDisconnected() {
+ // Stop listening.
+ synchronized (getSyncRoot()) {
+ handleDisconnectLocked();
+
+ if (mActiveDisplayState != WifiDisplayStatus.DISPLAY_STATE_NOT_CONNECTED
+ || mActiveDisplay != null) {
+ mCurrentStatus = null;
+ mActiveDisplayState = WifiDisplayStatus.DISPLAY_STATE_NOT_CONNECTED;
+ mActiveDisplay = null;
+ scheduleStatusChangedBroadcastLocked();
+ }
+ }
+ }
+ };
+
+ private final class WifiDisplayDevice extends DisplayDevice {
+ private final String mName;
+ private final int mWidth;
+ private final int mHeight;
+ private final float mRefreshRate;
+ private final int mFlags;
+
+ private Surface mSurface;
+ private DisplayDeviceInfo mInfo;
+
+ public WifiDisplayDevice(IBinder displayToken, String name,
+ int width, int height, float refreshRate, int flags,
+ Surface surface) {
+ super(WifiDisplayAdapter.this, displayToken);
+ mName = name;
+ mWidth = width;
+ mHeight = height;
+ mRefreshRate = refreshRate;
+ mFlags = flags;
+ mSurface = surface;
+ }
+
+ public void clearSurfaceLocked() {
+ mSurface = null;
+ sendTraversalRequestLocked();
+ }
+
+ @Override
+ public void performTraversalInTransactionLocked() {
+ setSurfaceInTransactionLocked(mSurface);
+ }
+
+ @Override
+ public DisplayDeviceInfo getDisplayDeviceInfoLocked() {
+ if (mInfo == null) {
+ mInfo = new DisplayDeviceInfo();
+ mInfo.name = mName;
+ mInfo.width = mWidth;
+ mInfo.height = mHeight;
+ mInfo.refreshRate = mRefreshRate;
+ mInfo.flags = mFlags;
+ mInfo.touch = DisplayDeviceInfo.TOUCH_EXTERNAL;
+ mInfo.setAssumedDensityForExternalDisplay(mWidth, mHeight);
+ }
+ return mInfo;
+ }
+ }
+
+ private final class WifiDisplayHandle implements RemoteDisplay.Listener {
+ private final String mName;
+ private final String mIface;
+ private final RemoteDisplay mRemoteDisplay;
+
+ private WifiDisplayDevice mDevice;
+ private int mLastError;
+
+ public WifiDisplayHandle(String name, String iface) {
+ mName = name;
+ mIface = iface;
+ mRemoteDisplay = RemoteDisplay.listen(iface, this, getHandler());
+
+ Slog.i(TAG, "Listening for Wifi display connections on " + iface
+ + " from " + mName);
+ }
+
+ public void disposeLocked() {
+ Slog.i(TAG, "Stopped listening for Wifi display connections on " + mIface
+ + " from " + mName);
+
+ removeDisplayLocked();
+ mRemoteDisplay.dispose();
+ }
+
+ public void dumpLocked(PrintWriter pw) {
+ pw.println(" " + mName + ": " + (mDevice != null ? "connected" : "disconnected"));
+ pw.println(" mIface=" + mIface);
+ pw.println(" mLastError=" + mLastError);
+ }
+
+ // Called on the handler thread.
+ @Override
+ public void onDisplayConnected(Surface surface, int width, int height, int flags) {
+ synchronized (getSyncRoot()) {
+ mLastError = 0;
+ removeDisplayLocked();
+ addDisplayLocked(surface, width, height, flags);
+
+ Slog.i(TAG, "Wifi display connected: " + mName);
+ }
+ }
+
+ // Called on the handler thread.
+ @Override
+ public void onDisplayDisconnected() {
+ synchronized (getSyncRoot()) {
+ mLastError = 0;
+ removeDisplayLocked();
+
+ Slog.i(TAG, "Wifi display disconnected: " + mName);
+ }
+ }
+
+ // Called on the handler thread.
+ @Override
+ public void onDisplayError(int error) {
+ synchronized (getSyncRoot()) {
+ mLastError = error;
+ removeDisplayLocked();
+
+ Slog.i(TAG, "Wifi display disconnected due to error " + error + ": " + mName);
+ }
+ }
+
+ private void addDisplayLocked(Surface surface, int width, int height, int flags) {
+ int deviceFlags = 0;
+ if ((flags & RemoteDisplay.DISPLAY_FLAG_SECURE) != 0) {
+ deviceFlags |= DisplayDeviceInfo.FLAG_SECURE;
+ }
+
+ float refreshRate = 60.0f; // TODO: get this for real
+
+ IBinder displayToken = Surface.createDisplay(mName);
+ mDevice = new WifiDisplayDevice(displayToken, mName, width, height,
+ refreshRate, deviceFlags, surface);
+ sendDisplayDeviceEventLocked(mDevice, DISPLAY_DEVICE_EVENT_ADDED);
+ }
+
+ private void removeDisplayLocked() {
+ if (mDevice != null) {
+ mDevice.clearSurfaceLocked();
+ sendDisplayDeviceEventLocked(mDevice, DISPLAY_DEVICE_EVENT_REMOVED);
+ mDevice = null;
+ }
+ }
+ }
+}
diff --git a/services/java/com/android/server/display/WifiDisplayController.java b/services/java/com/android/server/display/WifiDisplayController.java
new file mode 100644
index 0000000..b617d00
--- /dev/null
+++ b/services/java/com/android/server/display/WifiDisplayController.java
@@ -0,0 +1,712 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.display;
+
+import com.android.internal.util.DumpUtils;
+
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.hardware.display.WifiDisplay;
+import android.net.NetworkInfo;
+import android.net.wifi.p2p.WifiP2pConfig;
+import android.net.wifi.p2p.WifiP2pDevice;
+import android.net.wifi.p2p.WifiP2pDeviceList;
+import android.net.wifi.p2p.WifiP2pGroup;
+import android.net.wifi.p2p.WifiP2pManager;
+import android.net.wifi.p2p.WifiP2pWfdInfo;
+import android.net.wifi.p2p.WifiP2pManager.ActionListener;
+import android.net.wifi.p2p.WifiP2pManager.Channel;
+import android.net.wifi.p2p.WifiP2pManager.GroupInfoListener;
+import android.net.wifi.p2p.WifiP2pManager.PeerListListener;
+import android.os.Handler;
+import android.util.Slog;
+
+import java.io.PrintWriter;
+import java.net.Inet4Address;
+import java.net.InetAddress;
+import java.net.NetworkInterface;
+import java.net.SocketException;
+import java.util.ArrayList;
+import java.util.Enumeration;
+
+/**
+ * Manages all of the various asynchronous interactions with the {@link WifiP2pManager}
+ * on behalf of {@link WifiDisplayAdapter}.
+ * <p>
+ * This code is isolated from {@link WifiDisplayAdapter} so that we can avoid
+ * accidentally introducing any deadlocks due to the display manager calling
+ * outside of itself while holding its lock. It's also way easier to write this
+ * asynchronous code if we can assume that it is single-threaded.
+ * </p><p>
+ * The controller must be instantiated on the handler thread.
+ * </p>
+ */
+final class WifiDisplayController implements DumpUtils.Dump {
+ private static final String TAG = "WifiDisplayController";
+ private static final boolean DEBUG = true;
+
+ private static final int DEFAULT_CONTROL_PORT = 7236;
+ private static final int MAX_THROUGHPUT = 50;
+ private static final int CONNECTION_TIMEOUT_SECONDS = 30;
+
+ private static final int DISCOVER_PEERS_MAX_RETRIES = 10;
+ private static final int DISCOVER_PEERS_RETRY_DELAY_MILLIS = 500;
+
+ private static final int CONNECT_MAX_RETRIES = 3;
+ private static final int CONNECT_RETRY_DELAY_MILLIS = 500;
+
+ private final Context mContext;
+ private final Handler mHandler;
+ private final Listener mListener;
+ private final WifiP2pManager mWifiP2pManager;
+ private final Channel mWifiP2pChannel;
+
+ private boolean mWifiP2pEnabled;
+ private boolean mWfdEnabled;
+ private boolean mWfdEnabling;
+ private NetworkInfo mNetworkInfo;
+
+ private final ArrayList<WifiP2pDevice> mKnownWifiDisplayPeers =
+ new ArrayList<WifiP2pDevice>();
+
+ // True if there is a call to discoverPeers in progress.
+ private boolean mDiscoverPeersInProgress;
+
+ // Number of discover peers retries remaining.
+ private int mDiscoverPeersRetriesLeft;
+
+ // The device to which we want to connect, or null if we want to be disconnected.
+ private WifiP2pDevice mDesiredDevice;
+
+ // The device to which we are currently connecting, or null if we have already connected
+ // or are not trying to connect.
+ private WifiP2pDevice mConnectingDevice;
+
+ // The device to which we are currently connected, which means we have an active P2P group.
+ private WifiP2pDevice mConnectedDevice;
+
+ // The group info obtained after connecting.
+ private WifiP2pGroup mConnectedDeviceGroupInfo;
+
+ // The device that we announced to the rest of the system.
+ private WifiP2pDevice mPublishedDevice;
+
+ // Number of connection retries remaining.
+ private int mConnectionRetriesLeft;
+
+ public WifiDisplayController(Context context, Handler handler, Listener listener) {
+ mContext = context;
+ mHandler = handler;
+ mListener = listener;
+
+ mWifiP2pManager = (WifiP2pManager)context.getSystemService(Context.WIFI_P2P_SERVICE);
+ mWifiP2pChannel = mWifiP2pManager.initialize(context, handler.getLooper(), null);
+
+ IntentFilter intentFilter = new IntentFilter();
+ intentFilter.addAction(WifiP2pManager.WIFI_P2P_STATE_CHANGED_ACTION);
+ intentFilter.addAction(WifiP2pManager.WIFI_P2P_PEERS_CHANGED_ACTION);
+ intentFilter.addAction(WifiP2pManager.WIFI_P2P_CONNECTION_CHANGED_ACTION);
+ context.registerReceiver(mWifiP2pReceiver, intentFilter);
+ }
+
+ public void dump(PrintWriter pw) {
+ pw.println("mWifiP2pEnabled=" + mWifiP2pEnabled);
+ pw.println("mWfdEnabled=" + mWfdEnabled);
+ pw.println("mWfdEnabling=" + mWfdEnabling);
+ pw.println("mNetworkInfo=" + mNetworkInfo);
+ pw.println("mDiscoverPeersInProgress=" + mDiscoverPeersInProgress);
+ pw.println("mDiscoverPeersRetriesLeft=" + mDiscoverPeersRetriesLeft);
+ pw.println("mDesiredDevice=" + describeWifiP2pDevice(mDesiredDevice));
+ pw.println("mConnectingDisplay=" + describeWifiP2pDevice(mConnectingDevice));
+ pw.println("mConnectedDevice=" + describeWifiP2pDevice(mConnectedDevice));
+ pw.println("mPublishedDevice=" + describeWifiP2pDevice(mPublishedDevice));
+ pw.println("mConnectionRetriesLeft=" + mConnectionRetriesLeft);
+
+ pw.println("mKnownWifiDisplayPeers: size=" + mKnownWifiDisplayPeers.size());
+ for (WifiP2pDevice device : mKnownWifiDisplayPeers) {
+ pw.println(" " + describeWifiP2pDevice(device));
+ }
+ }
+
+ public void requestScan() {
+ discoverPeers();
+ }
+
+ public void requestConnect(String address) {
+ for (WifiP2pDevice device : mKnownWifiDisplayPeers) {
+ if (device.deviceAddress.equals(address)) {
+ connect(device);
+ }
+ }
+ }
+
+ public void requestDisconnect() {
+ disconnect();
+ }
+
+ private void enableWfd() {
+ if (!mWfdEnabled && !mWfdEnabling) {
+ mWfdEnabling = true;
+
+ WifiP2pWfdInfo wfdInfo = new WifiP2pWfdInfo();
+ wfdInfo.setWfdEnabled(true);
+ wfdInfo.setDeviceType(WifiP2pWfdInfo.WFD_SOURCE);
+ wfdInfo.setSessionAvailable(true);
+ wfdInfo.setControlPort(DEFAULT_CONTROL_PORT);
+ wfdInfo.setMaxThroughput(MAX_THROUGHPUT);
+ mWifiP2pManager.setWFDInfo(mWifiP2pChannel, wfdInfo, new ActionListener() {
+ @Override
+ public void onSuccess() {
+ if (DEBUG) {
+ Slog.d(TAG, "Successfully set WFD info.");
+ }
+ if (mWfdEnabling) {
+ mWfdEnabling = false;
+ setWfdEnabled(true);
+ discoverPeers();
+ }
+ }
+
+ @Override
+ public void onFailure(int reason) {
+ if (DEBUG) {
+ Slog.d(TAG, "Failed to set WFD info with reason " + reason + ".");
+ }
+ mWfdEnabling = false;
+ }
+ });
+ }
+ }
+
+ private void setWfdEnabled(final boolean enabled) {
+ if (mWfdEnabled != enabled) {
+ mWfdEnabled = enabled;
+ mHandler.post(new Runnable() {
+ @Override
+ public void run() {
+ mListener.onEnablementChanged(enabled);
+ }
+ });
+ }
+ }
+
+ private void discoverPeers() {
+ if (!mDiscoverPeersInProgress) {
+ mDiscoverPeersInProgress = true;
+ mDiscoverPeersRetriesLeft = DISCOVER_PEERS_MAX_RETRIES;
+ handleScanStarted();
+ tryDiscoverPeers();
+ }
+ }
+
+ private void tryDiscoverPeers() {
+ mWifiP2pManager.discoverPeers(mWifiP2pChannel, new ActionListener() {
+ @Override
+ public void onSuccess() {
+ if (DEBUG) {
+ Slog.d(TAG, "Discover peers succeeded. Requesting peers now.");
+ }
+
+ mDiscoverPeersInProgress = false;
+ requestPeers();
+ }
+
+ @Override
+ public void onFailure(int reason) {
+ if (DEBUG) {
+ Slog.d(TAG, "Discover peers failed with reason " + reason + ".");
+ }
+
+ if (mDiscoverPeersInProgress) {
+ if (reason == 0 && mDiscoverPeersRetriesLeft > 0 && mWfdEnabled) {
+ mHandler.postDelayed(new Runnable() {
+ @Override
+ public void run() {
+ if (mDiscoverPeersInProgress) {
+ if (mDiscoverPeersRetriesLeft > 0 && mWfdEnabled) {
+ mDiscoverPeersRetriesLeft -= 1;
+ if (DEBUG) {
+ Slog.d(TAG, "Retrying discovery. Retries left: "
+ + mDiscoverPeersRetriesLeft);
+ }
+ tryDiscoverPeers();
+ } else {
+ handleScanFinished();
+ mDiscoverPeersInProgress = false;
+ }
+ }
+ }
+ }, DISCOVER_PEERS_RETRY_DELAY_MILLIS);
+ } else {
+ handleScanFinished();
+ mDiscoverPeersInProgress = false;
+ }
+ }
+ }
+ });
+ }
+
+ private void requestPeers() {
+ mWifiP2pManager.requestPeers(mWifiP2pChannel, new PeerListListener() {
+ @Override
+ public void onPeersAvailable(WifiP2pDeviceList peers) {
+ if (DEBUG) {
+ Slog.d(TAG, "Received list of peers.");
+ }
+
+ mKnownWifiDisplayPeers.clear();
+ for (WifiP2pDevice device : peers.getDeviceList()) {
+ if (DEBUG) {
+ Slog.d(TAG, " " + describeWifiP2pDevice(device));
+ }
+
+ if (isWifiDisplay(device)) {
+ mKnownWifiDisplayPeers.add(device);
+ }
+ }
+
+ handleScanFinished();
+ }
+ });
+ }
+
+ private void handleScanStarted() {
+ mHandler.post(new Runnable() {
+ @Override
+ public void run() {
+ mListener.onScanStarted();
+ }
+ });
+ }
+
+ private void handleScanFinished() {
+ final int count = mKnownWifiDisplayPeers.size();
+ final WifiDisplay[] displays = WifiDisplay.CREATOR.newArray(count);
+ for (int i = 0; i < count; i++) {
+ displays[i] = createWifiDisplay(mKnownWifiDisplayPeers.get(i));
+ }
+
+ mHandler.post(new Runnable() {
+ @Override
+ public void run() {
+ mListener.onScanFinished(displays);
+ }
+ });
+ }
+
+ private void connect(final WifiP2pDevice device) {
+ if (mDesiredDevice != null
+ && !mDesiredDevice.deviceAddress.equals(device.deviceAddress)) {
+ if (DEBUG) {
+ Slog.d(TAG, "connect: nothing to do, already connecting to "
+ + describeWifiP2pDevice(device));
+ }
+ return;
+ }
+
+ if (mConnectedDevice != null
+ && !mConnectedDevice.deviceAddress.equals(device.deviceAddress)
+ && mDesiredDevice == null) {
+ if (DEBUG) {
+ Slog.d(TAG, "connect: nothing to do, already connected to "
+ + describeWifiP2pDevice(device) + " and not part way through "
+ + "connecting to a different device.");
+ }
+ return;
+ }
+
+ mDesiredDevice = device;
+ mConnectionRetriesLeft = CONNECT_MAX_RETRIES;
+ updateConnection();
+ }
+
+ private void disconnect() {
+ mDesiredDevice = null;
+ updateConnection();
+ }
+
+ private void retryConnection() {
+ if (mDesiredDevice != null && mPublishedDevice != mDesiredDevice
+ && mConnectionRetriesLeft > 0) {
+ mConnectionRetriesLeft -= 1;
+ Slog.i(TAG, "Retrying Wifi display connection. Retries left: "
+ + mConnectionRetriesLeft);
+
+ // Cheap hack. Make a new instance of the device object so that we
+ // can distinguish it from the previous connection attempt.
+ // This will cause us to tear everything down before we try again.
+ mDesiredDevice = new WifiP2pDevice(mDesiredDevice);
+ updateConnection();
+ }
+ }
+
+ /**
+ * This function is called repeatedly after each asynchronous operation
+ * until all preconditions for the connection have been satisfied and the
+ * connection is established (or not).
+ */
+ private void updateConnection() {
+ // Step 1. Before we try to connect to a new device, tell the system we
+ // have disconnected from the old one.
+ if (mPublishedDevice != null && mPublishedDevice != mDesiredDevice) {
+ mHandler.post(new Runnable() {
+ @Override
+ public void run() {
+ mListener.onDisplayDisconnected();
+ }
+ });
+ mPublishedDevice = null;
+
+ // continue to next step
+ }
+
+ // Step 2. Before we try to connect to a new device, disconnect from the old one.
+ if (mConnectedDevice != null && mConnectedDevice != mDesiredDevice) {
+ Slog.i(TAG, "Disconnecting from Wifi display: " + mConnectedDevice.deviceName);
+
+ final WifiP2pDevice oldDevice = mConnectedDevice;
+ mWifiP2pManager.removeGroup(mWifiP2pChannel, new ActionListener() {
+ @Override
+ public void onSuccess() {
+ Slog.i(TAG, "Disconnected from Wifi display: " + oldDevice.deviceName);
+ next();
+ }
+
+ @Override
+ public void onFailure(int reason) {
+ Slog.i(TAG, "Failed to disconnect from Wifi display: "
+ + oldDevice.deviceName + ", reason=" + reason);
+ next();
+ }
+
+ private void next() {
+ if (mConnectedDevice == oldDevice) {
+ mConnectedDevice = null;
+ updateConnection();
+ }
+ }
+ });
+ return; // wait for asynchronous callback
+ }
+
+ // Step 3. Before we try to connect to a new device, stop trying to connect
+ // to the old one.
+ if (mConnectingDevice != null && mConnectingDevice != mDesiredDevice) {
+ Slog.i(TAG, "Canceling connection to Wifi display: " + mConnectingDevice.deviceName);
+
+ mHandler.removeCallbacks(mConnectionTimeout);
+
+ final WifiP2pDevice oldDevice = mConnectingDevice;
+ mWifiP2pManager.cancelConnect(mWifiP2pChannel, new ActionListener() {
+ @Override
+ public void onSuccess() {
+ Slog.i(TAG, "Canceled connection to Wifi display: " + oldDevice.deviceName);
+ next();
+ }
+
+ @Override
+ public void onFailure(int reason) {
+ Slog.i(TAG, "Failed to cancel connection to Wifi display: "
+ + oldDevice.deviceName + ", reason=" + reason);
+ next();
+ }
+
+ private void next() {
+ if (mConnectingDevice == oldDevice) {
+ mConnectingDevice = null;
+ updateConnection();
+ }
+ }
+ });
+ return; // wait for asynchronous callback
+ }
+
+ // Step 4. If we wanted to disconnect, then mission accomplished.
+ if (mDesiredDevice == null) {
+ return; // done
+ }
+
+ // Step 5. Try to connect.
+ if (mConnectedDevice == null && mConnectingDevice == null) {
+ Slog.i(TAG, "Connecting to Wifi display: " + mDesiredDevice.deviceName);
+
+ mConnectingDevice = mDesiredDevice;
+ WifiP2pConfig config = new WifiP2pConfig();
+ config.deviceAddress = mConnectingDevice.deviceAddress;
+
+ final WifiDisplay display = createWifiDisplay(mConnectingDevice);
+ mHandler.post(new Runnable() {
+ @Override
+ public void run() {
+ mListener.onDisplayConnecting(display);
+ }
+ });
+
+ final WifiP2pDevice newDevice = mDesiredDevice;
+ mWifiP2pManager.connect(mWifiP2pChannel, config, new ActionListener() {
+ @Override
+ public void onSuccess() {
+ // The connection may not yet be established. We still need to wait
+ // for WIFI_P2P_CONNECTION_CHANGED_ACTION. However, we might never
+ // get that broadcast, so we register a timeout.
+ Slog.i(TAG, "Initiated connection to Wifi display: " + newDevice.deviceName);
+
+ mHandler.postDelayed(mConnectionTimeout, CONNECTION_TIMEOUT_SECONDS * 1000);
+ }
+
+ @Override
+ public void onFailure(int reason) {
+ Slog.i(TAG, "Failed to initiate connection to Wifi display: "
+ + newDevice.deviceName + ", reason=" + reason);
+ if (mConnectingDevice == newDevice) {
+ mConnectingDevice = null;
+ handleConnectionFailure(false);
+ }
+ }
+ });
+ return; // wait for asynchronous callback
+ }
+
+ // Step 6. Publish the new connection.
+ if (mConnectedDevice != null && mPublishedDevice == null) {
+ Inet4Address addr = getInterfaceAddress(mConnectedDeviceGroupInfo);
+ if (addr == null) {
+ Slog.i(TAG, "Failed to get local interface address for communicating "
+ + "with Wifi display: " + mConnectedDevice.deviceName);
+ handleConnectionFailure(false);
+ return; // done
+ }
+
+ WifiP2pWfdInfo wfdInfo = mConnectedDevice.wfdInfo;
+ int port = (wfdInfo != null ? wfdInfo.getControlPort() : DEFAULT_CONTROL_PORT);
+ final WifiDisplay display = createWifiDisplay(mConnectedDevice);
+ final String iface = addr.getHostAddress() + ":" + port;
+
+ mPublishedDevice = mConnectedDevice;
+ mHandler.post(new Runnable() {
+ @Override
+ public void run() {
+ mListener.onDisplayConnected(display, iface);
+ }
+ });
+ }
+ }
+
+ private void handleStateChanged(boolean enabled) {
+ if (mWifiP2pEnabled != enabled) {
+ mWifiP2pEnabled = enabled;
+ if (enabled) {
+ if (mWfdEnabled) {
+ discoverPeers();
+ } else {
+ enableWfd();
+ }
+ } else {
+ setWfdEnabled(false);
+ disconnect();
+ }
+ }
+ }
+
+ private void handlePeersChanged() {
+ if (mWifiP2pEnabled) {
+ if (mWfdEnabled) {
+ requestPeers();
+ } else {
+ enableWfd();
+ }
+ }
+ }
+
+ private void handleConnectionChanged(NetworkInfo networkInfo) {
+ mNetworkInfo = networkInfo;
+ if (mWfdEnabled && networkInfo.isConnected()) {
+ if (mDesiredDevice != null) {
+ mWifiP2pManager.requestGroupInfo(mWifiP2pChannel, new GroupInfoListener() {
+ @Override
+ public void onGroupInfoAvailable(WifiP2pGroup info) {
+ if (DEBUG) {
+ Slog.d(TAG, "Received group info: " + describeWifiP2pGroup(info));
+ }
+
+ if (mConnectingDevice != null && !info.contains(mConnectingDevice)) {
+ Slog.i(TAG, "Aborting connection to Wifi display because "
+ + "the current P2P group does not contain the device "
+ + "we expected to find: " + mConnectingDevice.deviceName);
+ handleConnectionFailure(false);
+ return;
+ }
+
+ if (mDesiredDevice != null && !info.contains(mDesiredDevice)) {
+ disconnect();
+ return;
+ }
+
+ if (mConnectingDevice != null && mConnectingDevice == mDesiredDevice) {
+ Slog.i(TAG, "Connected to Wifi display: "
+ + mConnectingDevice.deviceName);
+
+ mHandler.removeCallbacks(mConnectionTimeout);
+ mConnectedDeviceGroupInfo = info;
+ mConnectedDevice = mConnectingDevice;
+ mConnectingDevice = null;
+ updateConnection();
+ }
+ }
+ });
+ }
+ } else {
+ disconnect();
+
+ // After disconnection for a group, for some reason we have a tendency
+ // to get a peer change notification with an empty list of peers.
+ // Perform a fresh scan.
+ if (mWfdEnabled) {
+ requestPeers();
+ }
+ }
+ }
+
+ private final Runnable mConnectionTimeout = new Runnable() {
+ @Override
+ public void run() {
+ if (mConnectingDevice != null && mConnectingDevice == mDesiredDevice) {
+ Slog.i(TAG, "Timed out waiting for Wifi display connection after "
+ + CONNECTION_TIMEOUT_SECONDS + " seconds: "
+ + mConnectingDevice.deviceName);
+ handleConnectionFailure(true);
+ }
+ }
+ };
+
+ private void handleConnectionFailure(boolean timeoutOccurred) {
+ if (mDesiredDevice != null) {
+ Slog.i(TAG, "Wifi display connection failed!");
+
+ mHandler.post(new Runnable() {
+ @Override
+ public void run() {
+ mListener.onDisplayConnectionFailed();
+ }
+ });
+
+ if (mConnectionRetriesLeft > 0) {
+ mHandler.postDelayed(new Runnable() {
+ @Override
+ public void run() {
+ retryConnection();
+ }
+ }, timeoutOccurred ? 0 : CONNECT_RETRY_DELAY_MILLIS);
+ } else {
+ disconnect();
+ }
+ }
+ }
+
+ private static Inet4Address getInterfaceAddress(WifiP2pGroup info) {
+ NetworkInterface iface;
+ try {
+ iface = NetworkInterface.getByName(info.getInterface());
+ } catch (SocketException ex) {
+ Slog.w(TAG, "Could not obtain address of network interface "
+ + info.getInterface(), ex);
+ return null;
+ }
+
+ Enumeration<InetAddress> addrs = iface.getInetAddresses();
+ while (addrs.hasMoreElements()) {
+ InetAddress addr = addrs.nextElement();
+ if (addr instanceof Inet4Address) {
+ return (Inet4Address)addr;
+ }
+ }
+
+ Slog.w(TAG, "Could not obtain address of network interface "
+ + info.getInterface() + " because it had no IPv4 addresses.");
+ return null;
+ }
+
+ private static boolean isWifiDisplay(WifiP2pDevice device) {
+ // FIXME: the wfdInfo API doesn't work yet
+ return device.deviceName.startsWith("DWD-")
+ || device.deviceName.startsWith("DIRECT-")
+ || device.deviceName.startsWith("CAVM-");
+ //device.wfdInfo != null && device.wfdInfo.isWfdEnabled();
+ }
+
+ private static String describeWifiP2pDevice(WifiP2pDevice device) {
+ return device != null ? device.toString().replace('\n', ',') : "null";
+ }
+
+ private static String describeWifiP2pGroup(WifiP2pGroup group) {
+ return group != null ? group.toString().replace('\n', ',') : "null";
+ }
+
+ private static WifiDisplay createWifiDisplay(WifiP2pDevice device) {
+ return new WifiDisplay(device.deviceAddress, device.deviceName);
+ }
+
+ private final BroadcastReceiver mWifiP2pReceiver = new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ final String action = intent.getAction();
+ if (action.equals(WifiP2pManager.WIFI_P2P_STATE_CHANGED_ACTION)) {
+ boolean enabled = (intent.getIntExtra(WifiP2pManager.EXTRA_WIFI_STATE,
+ WifiP2pManager.WIFI_P2P_STATE_DISABLED)) ==
+ WifiP2pManager.WIFI_P2P_STATE_ENABLED;
+ if (DEBUG) {
+ Slog.d(TAG, "Received WIFI_P2P_STATE_CHANGED_ACTION: enabled="
+ + enabled);
+ }
+
+ handleStateChanged(enabled);
+ } else if (action.equals(WifiP2pManager.WIFI_P2P_PEERS_CHANGED_ACTION)) {
+ if (DEBUG) {
+ Slog.d(TAG, "Received WIFI_P2P_PEERS_CHANGED_ACTION.");
+ }
+
+ handlePeersChanged();
+ } else if (action.equals(WifiP2pManager.WIFI_P2P_CONNECTION_CHANGED_ACTION)) {
+ NetworkInfo networkInfo = (NetworkInfo)intent.getParcelableExtra(
+ WifiP2pManager.EXTRA_NETWORK_INFO);
+ if (DEBUG) {
+ Slog.d(TAG, "Received WIFI_P2P_CONNECTION_CHANGED_ACTION: networkInfo="
+ + networkInfo);
+ }
+
+ handleConnectionChanged(networkInfo);
+ }
+ }
+ };
+
+ /**
+ * Called on the handler thread when displays are connected or disconnected.
+ */
+ public interface Listener {
+ void onEnablementChanged(boolean enabled);
+
+ void onScanStarted();
+ void onScanFinished(WifiDisplay[] knownDisplays);
+
+ void onDisplayConnecting(WifiDisplay display);
+ void onDisplayConnectionFailed();
+ void onDisplayConnected(WifiDisplay display, String iface);
+ void onDisplayDisconnected();
+ }
+}
diff --git a/services/java/com/android/server/input/InputManagerService.java b/services/java/com/android/server/input/InputManagerService.java
index fd4f5fc..95655a5 100644
--- a/services/java/com/android/server/input/InputManagerService.java
+++ b/services/java/com/android/server/input/InputManagerService.java
@@ -19,6 +19,8 @@ package com.android.server.input;
import com.android.internal.R;
import com.android.internal.util.XmlUtils;
import com.android.server.Watchdog;
+import com.android.server.display.DisplayManagerService;
+import com.android.server.display.DisplayViewport;
import org.xmlpull.v1.XmlPullParser;
@@ -90,7 +92,8 @@ import libcore.util.Objects;
/*
* Wraps the C++ InputManager and provides its callbacks.
*/
-public class InputManagerService extends IInputManager.Stub implements Watchdog.Monitor {
+public class InputManagerService extends IInputManager.Stub
+ implements Watchdog.Monitor, DisplayManagerService.InputManagerFuncs {
static final String TAG = "InputManager";
static final boolean DEBUG = false;
@@ -143,11 +146,11 @@ public class InputManagerService extends IInputManager.Stub implements Watchdog.
private static native int nativeInit(InputManagerService service,
Context context, MessageQueue messageQueue);
private static native void nativeStart(int ptr);
- private static native void nativeSetDisplaySize(int ptr, int displayId,
- int width, int height, int externalWidth, int externalHeight);
- private static native void nativeSetDisplayOrientation(int ptr, int displayId,
- int rotation, int externalRotation);
-
+ private static native void nativeSetDisplayViewport(int ptr, boolean external,
+ int displayId, int rotation,
+ int logicalLeft, int logicalTop, int logicalRight, int logicalBottom,
+ int physicalLeft, int physicalTop, int physicalRight, int physicalBottom);
+
private static native int nativeGetScanCodeState(int ptr,
int deviceId, int sourceMask, int scanCode);
private static native int nativeGetKeyCodeState(int ptr,
@@ -282,28 +285,27 @@ public class InputManagerService extends IInputManager.Stub implements Watchdog.
nativeReloadDeviceAliases(mPtr);
}
- public void setDisplaySize(int displayId, int width, int height) {
- if (width <= 0 || height <= 0) {
- throw new IllegalArgumentException("Invalid display id or dimensions.");
+ @Override
+ public void setDisplayViewports(DisplayViewport defaultViewport,
+ DisplayViewport externalTouchViewport) {
+ if (defaultViewport.valid) {
+ setDisplayViewport(false, defaultViewport);
}
-
- if (DEBUG) {
- Slog.d(TAG, "Setting display #" + displayId + " size to " + width + "x" + height);
+
+ if (externalTouchViewport.valid) {
+ setDisplayViewport(true, externalTouchViewport);
+ } else if (defaultViewport.valid) {
+ setDisplayViewport(true, defaultViewport);
}
- // FIXME: external size is deprecated
- nativeSetDisplaySize(mPtr, displayId, width, height, 1280, 720);
}
- public void setDisplayOrientation(int displayId, int rotation) {
- if (rotation < Surface.ROTATION_0 || rotation > Surface.ROTATION_270) {
- throw new IllegalArgumentException("Invalid rotation.");
- }
-
- if (DEBUG) {
- Slog.d(TAG, "Setting display #" + displayId + " orientation to rotation " + rotation);
- }
- // FIXME: external rotation is deprecated
- nativeSetDisplayOrientation(mPtr, displayId, rotation, Surface.ROTATION_0);
+ private void setDisplayViewport(boolean external, DisplayViewport viewport) {
+ nativeSetDisplayViewport(mPtr, external,
+ viewport.displayId, viewport.orientation,
+ viewport.logicalFrame.left, viewport.logicalFrame.top,
+ viewport.logicalFrame.right, viewport.logicalFrame.bottom,
+ viewport.physicalFrame.left, viewport.physicalFrame.top,
+ viewport.physicalFrame.right, viewport.physicalFrame.bottom);
}
/**
diff --git a/services/java/com/android/server/pm/Installer.java b/services/java/com/android/server/pm/Installer.java
index d4fe3fb..3329acb 100644
--- a/services/java/com/android/server/pm/Installer.java
+++ b/services/java/com/android/server/pm/Installer.java
@@ -324,20 +324,6 @@ class Installer {
return execute(builder.toString());
}
- /*
- * @param packagePathSuffix The name of the path relative to install
- * directory. Say if the path name is /data/app/com.test-1.apk, the package
- * suffix path will be com.test-1
- */
- public int setForwardLockPerm(String packagePathSuffix, int gid) {
- StringBuilder builder = new StringBuilder("protect");
- builder.append(' ');
- builder.append(packagePathSuffix);
- builder.append(' ');
- builder.append(gid);
- return execute(builder.toString());
- }
-
public int getSizeInfo(String pkgName, int persona, String apkPath, String fwdLockApkPath,
String asecPath, PackageStats pStats) {
StringBuilder builder = new StringBuilder("getsize");
diff --git a/services/java/com/android/server/pm/PackageManagerService.java b/services/java/com/android/server/pm/PackageManagerService.java
index 55da11f..4bb6e38 100644
--- a/services/java/com/android/server/pm/PackageManagerService.java
+++ b/services/java/com/android/server/pm/PackageManagerService.java
@@ -1193,7 +1193,7 @@ public class PackageManagerService extends IPackageManager.Stub {
if (mSettings.isDisabledSystemPackageLPr(ps.name)) {
Slog.i(TAG, "Expecting better updatd system app for " + ps.name
+ "; removing system app");
- removePackageLI(scannedPkg, true);
+ removePackageLI(ps, true);
}
continue;
@@ -1822,7 +1822,7 @@ public class PackageManagerService extends IPackageManager.Stub {
}
pkg = new PackageParser.Package(packageName);
pkg.applicationInfo.packageName = packageName;
- pkg.applicationInfo.flags = ps.pkgFlags;
+ pkg.applicationInfo.flags = ps.pkgFlags | ApplicationInfo.FLAG_IS_DATA_ONLY;
pkg.applicationInfo.publicSourceDir = ps.resourcePathString;
pkg.applicationInfo.sourceDir = ps.codePathString;
pkg.applicationInfo.dataDir =
@@ -2891,11 +2891,14 @@ public class PackageManagerService extends IPackageManager.Stub {
return index;
}
- public ParceledListSlice<PackageInfo> getInstalledPackages(int flags, String lastRead) {
+ @Override
+ public ParceledListSlice<PackageInfo> getInstalledPackages(int flags, String lastRead,
+ int userId) {
final ParceledListSlice<PackageInfo> list = new ParceledListSlice<PackageInfo>();
final boolean listUninstalled = (flags & PackageManager.GET_UNINSTALLED_PACKAGES) != 0;
final String[] keys;
- int userId = UserHandle.getCallingUserId();
+
+ enforceCrossUserPermission(Binder.getCallingUid(), userId, true, "get installed packages");
// writer
synchronized (mPackages) {
@@ -4110,8 +4113,13 @@ public class PackageManagerService extends IPackageManager.Stub {
NativeLibraryHelper.copyNativeBinariesIfNeededLI(scanFile, nativeLibraryDir);
} else {
Slog.i(TAG, "Linking native library dir for " + path);
- mInstaller.linkNativeLibraryDirectory(dataPathString,
+ int ret = mInstaller.linkNativeLibraryDirectory(dataPathString,
pkg.applicationInfo.nativeLibraryDir);
+ if (ret < 0) {
+ Slog.w(TAG, "Failed linking native library dir for " + path);
+ mLastScanError = PackageManager.MOVE_FAILED_INSUFFICIENT_STORAGE;
+ return null;
+ }
}
} catch (IOException ioe) {
Log.e(TAG, "Unable to get canonical file " + ioe.toString());
@@ -4429,20 +4437,40 @@ public class PackageManagerService extends IPackageManager.Stub {
return pkg;
}
- private void killApplication(String pkgName, int uid) {
+ private void killApplication(String pkgName, int appId) {
// Request the ActivityManager to kill the process(only for existing packages)
// so that we do not end up in a confused state while the user is still using the older
// version of the application while the new one gets installed.
IActivityManager am = ActivityManagerNative.getDefault();
if (am != null) {
try {
- am.killApplicationWithUid(pkgName, uid);
+ am.killApplicationWithAppId(pkgName, appId);
} catch (RemoteException e) {
}
}
}
- void removePackageLI(PackageParser.Package pkg, boolean chatty) {
+ void removePackageLI(PackageSetting ps, boolean chatty) {
+ if (DEBUG_INSTALL) {
+ if (chatty)
+ Log.d(TAG, "Removing package " + ps.name);
+ }
+
+ // writer
+ synchronized (mPackages) {
+ mPackages.remove(ps.name);
+ if (ps.codePathString != null) {
+ mAppDirs.remove(ps.codePathString);
+ }
+
+ final PackageParser.Package pkg = ps.pkg;
+ if (pkg != null) {
+ cleanPackageDataStructuresLILPw(pkg, chatty);
+ }
+ }
+ }
+
+ void removeInstalledPackageLI(PackageParser.Package pkg, boolean chatty) {
if (DEBUG_INSTALL) {
if (chatty)
Log.d(TAG, "Removing package " + pkg.applicationInfo.packageName);
@@ -4454,143 +4482,146 @@ public class PackageManagerService extends IPackageManager.Stub {
if (pkg.mPath != null) {
mAppDirs.remove(pkg.mPath);
}
+ cleanPackageDataStructuresLILPw(pkg, chatty);
+ }
+ }
- int N = pkg.providers.size();
- StringBuilder r = null;
- int i;
- for (i=0; i<N; i++) {
- PackageParser.Provider p = pkg.providers.get(i);
- mProvidersByComponent.remove(new ComponentName(p.info.packageName,
- p.info.name));
- if (p.info.authority == null) {
-
- /* The is another ContentProvider with this authority when
- * this app was installed so this authority is null,
- * Ignore it as we don't have to unregister the provider.
- */
- continue;
- }
- String names[] = p.info.authority.split(";");
- for (int j = 0; j < names.length; j++) {
- if (mProviders.get(names[j]) == p) {
- mProviders.remove(names[j]);
- if (DEBUG_REMOVE) {
- if (chatty)
- Log.d(TAG, "Unregistered content provider: " + names[j]
- + ", className = " + p.info.name + ", isSyncable = "
- + p.info.isSyncable);
- }
- }
- }
- if (chatty) {
- if (r == null) {
- r = new StringBuilder(256);
- } else {
- r.append(' ');
- }
- r.append(p.info.name);
- }
- }
- if (r != null) {
- if (DEBUG_REMOVE) Log.d(TAG, " Providers: " + r);
+ void cleanPackageDataStructuresLILPw(PackageParser.Package pkg, boolean chatty) {
+ int N = pkg.providers.size();
+ StringBuilder r = null;
+ int i;
+ for (i=0; i<N; i++) {
+ PackageParser.Provider p = pkg.providers.get(i);
+ mProvidersByComponent.remove(new ComponentName(p.info.packageName,
+ p.info.name));
+ if (p.info.authority == null) {
+
+ /* There was another ContentProvider with this authority when
+ * this app was installed so this authority is null,
+ * Ignore it as we don't have to unregister the provider.
+ */
+ continue;
}
-
- N = pkg.services.size();
- r = null;
- for (i=0; i<N; i++) {
- PackageParser.Service s = pkg.services.get(i);
- mServices.removeService(s);
- if (chatty) {
- if (r == null) {
- r = new StringBuilder(256);
- } else {
- r.append(' ');
+ String names[] = p.info.authority.split(";");
+ for (int j = 0; j < names.length; j++) {
+ if (mProviders.get(names[j]) == p) {
+ mProviders.remove(names[j]);
+ if (DEBUG_REMOVE) {
+ if (chatty)
+ Log.d(TAG, "Unregistered content provider: " + names[j]
+ + ", className = " + p.info.name + ", isSyncable = "
+ + p.info.isSyncable);
}
- r.append(s.info.name);
}
}
- if (r != null) {
- if (DEBUG_REMOVE) Log.d(TAG, " Services: " + r);
+ if (chatty) {
+ if (r == null) {
+ r = new StringBuilder(256);
+ } else {
+ r.append(' ');
+ }
+ r.append(p.info.name);
}
+ }
+ if (r != null) {
+ if (DEBUG_REMOVE) Log.d(TAG, " Providers: " + r);
+ }
- N = pkg.receivers.size();
- r = null;
- for (i=0; i<N; i++) {
- PackageParser.Activity a = pkg.receivers.get(i);
- mReceivers.removeActivity(a, "receiver");
- if (chatty) {
- if (r == null) {
- r = new StringBuilder(256);
- } else {
- r.append(' ');
- }
- r.append(a.info.name);
+ N = pkg.services.size();
+ r = null;
+ for (i=0; i<N; i++) {
+ PackageParser.Service s = pkg.services.get(i);
+ mServices.removeService(s);
+ if (chatty) {
+ if (r == null) {
+ r = new StringBuilder(256);
+ } else {
+ r.append(' ');
}
+ r.append(s.info.name);
}
- if (r != null) {
- if (DEBUG_REMOVE) Log.d(TAG, " Receivers: " + r);
- }
+ }
+ if (r != null) {
+ if (DEBUG_REMOVE) Log.d(TAG, " Services: " + r);
+ }
- N = pkg.activities.size();
- r = null;
- for (i=0; i<N; i++) {
- PackageParser.Activity a = pkg.activities.get(i);
- mActivities.removeActivity(a, "activity");
- if (chatty) {
- if (r == null) {
- r = new StringBuilder(256);
- } else {
- r.append(' ');
- }
- r.append(a.info.name);
+ N = pkg.receivers.size();
+ r = null;
+ for (i=0; i<N; i++) {
+ PackageParser.Activity a = pkg.receivers.get(i);
+ mReceivers.removeActivity(a, "receiver");
+ if (chatty) {
+ if (r == null) {
+ r = new StringBuilder(256);
+ } else {
+ r.append(' ');
}
+ r.append(a.info.name);
}
- if (r != null) {
- if (DEBUG_REMOVE) Log.d(TAG, " Activities: " + r);
- }
+ }
+ if (r != null) {
+ if (DEBUG_REMOVE) Log.d(TAG, " Receivers: " + r);
+ }
- N = pkg.permissions.size();
- r = null;
- for (i=0; i<N; i++) {
- PackageParser.Permission p = pkg.permissions.get(i);
- BasePermission bp = mSettings.mPermissions.get(p.info.name);
- if (bp == null) {
- bp = mSettings.mPermissionTrees.get(p.info.name);
- }
- if (bp != null && bp.perm == p) {
- bp.perm = null;
- if (chatty) {
- if (r == null) {
- r = new StringBuilder(256);
- } else {
- r.append(' ');
- }
- r.append(p.info.name);
- }
+ N = pkg.activities.size();
+ r = null;
+ for (i=0; i<N; i++) {
+ PackageParser.Activity a = pkg.activities.get(i);
+ mActivities.removeActivity(a, "activity");
+ if (chatty) {
+ if (r == null) {
+ r = new StringBuilder(256);
+ } else {
+ r.append(' ');
}
+ r.append(a.info.name);
}
- if (r != null) {
- if (DEBUG_REMOVE) Log.d(TAG, " Permissions: " + r);
- }
+ }
+ if (r != null) {
+ if (DEBUG_REMOVE) Log.d(TAG, " Activities: " + r);
+ }
- N = pkg.instrumentation.size();
- r = null;
- for (i=0; i<N; i++) {
- PackageParser.Instrumentation a = pkg.instrumentation.get(i);
- mInstrumentation.remove(a.getComponentName());
+ N = pkg.permissions.size();
+ r = null;
+ for (i=0; i<N; i++) {
+ PackageParser.Permission p = pkg.permissions.get(i);
+ BasePermission bp = mSettings.mPermissions.get(p.info.name);
+ if (bp == null) {
+ bp = mSettings.mPermissionTrees.get(p.info.name);
+ }
+ if (bp != null && bp.perm == p) {
+ bp.perm = null;
if (chatty) {
if (r == null) {
r = new StringBuilder(256);
} else {
r.append(' ');
}
- r.append(a.info.name);
+ r.append(p.info.name);
}
}
- if (r != null) {
- if (DEBUG_REMOVE) Log.d(TAG, " Instrumentation: " + r);
+ }
+ if (r != null) {
+ if (DEBUG_REMOVE) Log.d(TAG, " Permissions: " + r);
+ }
+
+ N = pkg.instrumentation.size();
+ r = null;
+ for (i=0; i<N; i++) {
+ PackageParser.Instrumentation a = pkg.instrumentation.get(i);
+ mInstrumentation.remove(a.getComponentName());
+ if (chatty) {
+ if (r == null) {
+ r = new StringBuilder(256);
+ } else {
+ r.append(' ');
+ }
+ r.append(a.info.name);
}
}
+ if (r != null) {
+ if (DEBUG_REMOVE) Log.d(TAG, " Instrumentation: " + r);
+ }
}
private static final boolean isPackageFilename(String name) {
@@ -5424,10 +5455,10 @@ public class PackageManagerService extends IPackageManager.Stub {
public void onEvent(int event, String path) {
String removedPackage = null;
- int removedUid = -1;
+ int removedAppId = -1;
int[] removedUsers = null;
String addedPackage = null;
- int addedUid = -1;
+ int addedAppId = -1;
int[] addedUsers = null;
// TODO post a message to the handler to obtain serial ordering
@@ -5454,11 +5485,12 @@ public class PackageManagerService extends IPackageManager.Stub {
return;
}
PackageParser.Package p = null;
+ PackageSetting ps = null;
// reader
synchronized (mPackages) {
p = mAppDirs.get(fullPathStr);
if (p != null) {
- PackageSetting ps = mSettings.mPackages.get(p.applicationInfo.packageName);
+ ps = mSettings.mPackages.get(p.applicationInfo.packageName);
if (ps != null) {
removedUsers = ps.queryInstalledUsers(sUserManager.getUserIds(), true);
} else {
@@ -5468,10 +5500,10 @@ public class PackageManagerService extends IPackageManager.Stub {
addedUsers = sUserManager.getUserIds();
}
if ((event&REMOVE_EVENTS) != 0) {
- if (p != null) {
- removePackageLI(p, true);
- removedPackage = p.applicationInfo.packageName;
- removedUid = p.applicationInfo.uid;
+ if (ps != null) {
+ removePackageLI(ps, true);
+ removedPackage = ps.name;
+ removedAppId = ps.appId;
}
}
@@ -5496,7 +5528,7 @@ public class PackageManagerService extends IPackageManager.Stub {
p.permissions.size() > 0 ? UPDATE_PERMISSIONS_ALL : 0);
}
addedPackage = p.applicationInfo.packageName;
- addedUid = p.applicationInfo.uid;
+ addedAppId = UserHandle.getAppId(p.applicationInfo.uid);
}
}
}
@@ -5509,14 +5541,14 @@ public class PackageManagerService extends IPackageManager.Stub {
if (removedPackage != null) {
Bundle extras = new Bundle(1);
- extras.putInt(Intent.EXTRA_UID, removedUid);
+ extras.putInt(Intent.EXTRA_UID, removedAppId);
extras.putBoolean(Intent.EXTRA_DATA_REMOVED, false);
sendPackageBroadcast(Intent.ACTION_PACKAGE_REMOVED, removedPackage,
extras, null, null, removedUsers);
}
if (addedPackage != null) {
Bundle extras = new Bundle(1);
- extras.putInt(Intent.EXTRA_UID, addedUid);
+ extras.putInt(Intent.EXTRA_UID, addedAppId);
sendPackageBroadcast(Intent.ACTION_PACKAGE_ADDED, addedPackage,
extras, null, null, addedUsers);
}
@@ -5791,8 +5823,8 @@ public class PackageManagerService extends IPackageManager.Stub {
* @return verification timeout in milliseconds
*/
private long getVerificationTimeout() {
- return android.provider.Settings.Secure.getLong(mContext.getContentResolver(),
- android.provider.Settings.Secure.PACKAGE_VERIFIER_TIMEOUT,
+ return android.provider.Settings.Global.getLong(mContext.getContentResolver(),
+ android.provider.Settings.Global.PACKAGE_VERIFIER_TIMEOUT,
DEFAULT_VERIFICATION_TIMEOUT);
}
@@ -5802,8 +5834,8 @@ public class PackageManagerService extends IPackageManager.Stub {
* @return default verification response code
*/
private int getDefaultVerificationResponse() {
- return android.provider.Settings.Secure.getInt(mContext.getContentResolver(),
- android.provider.Settings.Secure.PACKAGE_VERIFIER_DEFAULT_RESPONSE,
+ return android.provider.Settings.Global.getInt(mContext.getContentResolver(),
+ android.provider.Settings.Global.PACKAGE_VERIFIER_DEFAULT_RESPONSE,
DEFAULT_VERIFICATION_RESPONSE);
}
@@ -5813,8 +5845,8 @@ public class PackageManagerService extends IPackageManager.Stub {
* @return true if verification should be performed
*/
private boolean isVerificationEnabled() {
- return android.provider.Settings.Secure.getInt(mContext.getContentResolver(),
- android.provider.Settings.Secure.PACKAGE_VERIFIER_ENABLE,
+ return android.provider.Settings.Global.getInt(mContext.getContentResolver(),
+ android.provider.Settings.Global.PACKAGE_VERIFIER_ENABLE,
DEFAULT_VERIFY_ENABLE ? 1 : 0) == 1 ? true : false;
}
@@ -7527,7 +7559,7 @@ public class PackageManagerService extends IPackageManager.Stub {
res.removedInfo.uid = oldPkg.applicationInfo.uid;
res.removedInfo.removedPackage = packageName;
// Remove existing system package
- removePackageLI(oldPkg, true);
+ removePackageLI(oldPkgSetting, true);
// writer
synchronized (mPackages) {
if (!mSettings.disableSystemPackageLPw(packageName) && deletedPackage != null) {
@@ -7566,7 +7598,7 @@ public class PackageManagerService extends IPackageManager.Stub {
// Re installation failed. Restore old information
// Remove new pkg information
if (newPackage != null) {
- removePackageLI(newPackage, true);
+ removeInstalledPackageLI(newPackage, true);
}
// Add back the old system package
scanPackageLI(oldPkg, parseFlags, SCAN_MONITOR | SCAN_UPDATE_SIGNATURE, 0, user);
@@ -7967,10 +7999,10 @@ public class PackageManagerService extends IPackageManager.Stub {
* make sure this flag is set for partially installed apps. If not its meaningless to
* delete a partially installed application.
*/
- private void removePackageDataLI(PackageParser.Package p, PackageRemovedInfo outInfo,
+ private void removePackageDataLI(PackageSetting ps, PackageRemovedInfo outInfo,
int flags, boolean writeSettings) {
- String packageName = p.packageName;
- removePackageLI(p, (flags&REMOVE_CHATTY) != 0);
+ String packageName = ps.name;
+ removePackageLI(ps, (flags&REMOVE_CHATTY) != 0);
// Retrieve object to delete permissions for shared user later on
final PackageSetting deletedPs;
// reader
@@ -8015,38 +8047,32 @@ public class PackageManagerService extends IPackageManager.Stub {
/*
* Tries to delete system package.
*/
- private boolean deleteSystemPackageLI(PackageParser.Package p,
+ private boolean deleteSystemPackageLI(PackageSetting newPs,
int flags, PackageRemovedInfo outInfo, boolean writeSettings) {
- ApplicationInfo applicationInfo = p.applicationInfo;
- //applicable for non-partially installed applications only
- if (applicationInfo == null) {
- Slog.w(TAG, "Package " + p.packageName + " has no applicationInfo.");
- return false;
- }
- PackageSetting ps = null;
+ PackageSetting disabledPs = null;
// Confirm if the system package has been updated
// An updated system app can be deleted. This will also have to restore
// the system pkg from system partition
// reader
synchronized (mPackages) {
- ps = mSettings.getDisabledSystemPkgLPr(p.packageName);
+ disabledPs = mSettings.getDisabledSystemPkgLPr(newPs.name);
}
- if (ps == null) {
- Slog.w(TAG, "Attempt to delete unknown system package "+ p.packageName);
+ if (disabledPs == null) {
+ Slog.w(TAG, "Attempt to delete unknown system package "+ newPs.name);
return false;
} else {
Log.i(TAG, "Deleting system pkg from data partition");
}
// Delete the updated package
outInfo.isRemovedPackageSystemUpdate = true;
- if (ps.versionCode < p.mVersionCode) {
+ if (disabledPs.versionCode < newPs.versionCode) {
// Delete data for downgrades
flags &= ~PackageManager.DELETE_KEEP_DATA;
} else {
// Preserve data by setting flag
flags |= PackageManager.DELETE_KEEP_DATA;
}
- boolean ret = deleteInstalledPackageLI(p, true, flags, outInfo,
+ boolean ret = deleteInstalledPackageLI(newPs, true, flags, outInfo,
writeSettings);
if (!ret) {
return false;
@@ -8054,17 +8080,18 @@ public class PackageManagerService extends IPackageManager.Stub {
// writer
synchronized (mPackages) {
// Reinstate the old system package
- mSettings.enableSystemPackageLPw(p.packageName);
+ mSettings.enableSystemPackageLPw(newPs.name);
// Remove any native libraries from the upgraded package.
- NativeLibraryHelper.removeNativeBinariesLI(p.applicationInfo.nativeLibraryDir);
+ NativeLibraryHelper.removeNativeBinariesLI(newPs.nativeLibraryPathString);
}
// Install the system package
- PackageParser.Package newPkg = scanPackageLI(ps.codePath,
+ PackageParser.Package newPkg = scanPackageLI(disabledPs.codePath,
PackageParser.PARSE_MUST_BE_APK | PackageParser.PARSE_IS_SYSTEM,
SCAN_MONITOR | SCAN_NO_PATHS, 0, null);
if (newPkg == null) {
- Slog.w(TAG, "Failed to restore system package:"+p.packageName+" with error:" + mLastScanError);
+ Slog.w(TAG, "Failed to restore system package:" + newPs.name
+ + " with error:" + mLastScanError);
return false;
}
// writer
@@ -8079,28 +8106,20 @@ public class PackageManagerService extends IPackageManager.Stub {
return true;
}
- private boolean deleteInstalledPackageLI(PackageParser.Package p,
+ private boolean deleteInstalledPackageLI(PackageSetting ps,
boolean deleteCodeAndResources, int flags, PackageRemovedInfo outInfo,
boolean writeSettings) {
- ApplicationInfo applicationInfo = p.applicationInfo;
- if (applicationInfo == null) {
- Slog.w(TAG, "Package " + p.packageName + " has no applicationInfo.");
- return false;
- }
if (outInfo != null) {
- outInfo.uid = applicationInfo.uid;
+ outInfo.uid = ps.appId;
}
// Delete package data from internal structures and also remove data if flag is set
- removePackageDataLI(p, outInfo, flags, writeSettings);
+ removePackageDataLI(ps, outInfo, flags, writeSettings);
// Delete application code and resources
if (deleteCodeAndResources) {
- // TODO can pick up from PackageSettings as well
- int installFlags = isExternal(p) ? PackageManager.INSTALL_EXTERNAL : 0;
- installFlags |= isForwardLocked(p) ? PackageManager.INSTALL_FORWARD_LOCK : 0;
- outInfo.args = createInstallArgs(installFlags, applicationInfo.sourceDir,
- applicationInfo.publicSourceDir, applicationInfo.nativeLibraryDir);
+ outInfo.args = createInstallArgs(packageFlagsToInstallFlags(ps), ps.codePathString,
+ ps.resourcePathString, ps.nativeLibraryPathString);
}
return true;
}
@@ -8115,28 +8134,17 @@ public class PackageManagerService extends IPackageManager.Stub {
Slog.w(TAG, "Attempt to delete null packageName.");
return false;
}
- PackageParser.Package p;
+ PackageSetting ps;
boolean dataOnly = false;
int removeUser = -1;
int appId = -1;
synchronized (mPackages) {
- p = mPackages.get(packageName);
- if (p == null) {
- //this retrieves partially installed apps
- dataOnly = true;
- PackageSetting ps = mSettings.mPackages.get(packageName);
- if (ps == null) {
- Slog.w(TAG, "Package named '" + packageName + "' doesn't exist.");
- return false;
- }
- p = ps.pkg;
- }
- if (p == null) {
+ ps = mSettings.mPackages.get(packageName);
+ if (ps == null) {
Slog.w(TAG, "Package named '" + packageName + "' doesn't exist.");
return false;
}
- final PackageSetting ps = (PackageSetting)p.mExtras;
- if (!isSystemApp(p) && ps != null && user != null
+ if (!isSystemApp(ps) && user != null
&& user.getIdentifier() != UserHandle.USER_ALL) {
// The caller is asking that the package only be deleted for a single
// user. To do this, we just mark its uninstalled state and delete
@@ -8177,25 +8185,20 @@ public class PackageManagerService extends IPackageManager.Stub {
if (dataOnly) {
// Delete application data first
- removePackageDataLI(p, outInfo, flags, writeSettings);
+ removePackageDataLI(ps, outInfo, flags, writeSettings);
return true;
}
- // At this point the package should have ApplicationInfo associated with it
- if (p.applicationInfo == null) {
- Slog.w(TAG, "Package " + p.packageName + " has no applicationInfo.");
- return false;
- }
boolean ret = false;
- if (isSystemApp(p)) {
- Log.i(TAG, "Removing system package:"+p.packageName);
+ if (isSystemApp(ps)) {
+ Log.i(TAG, "Removing system package:" + ps.name);
// When an updated system application is deleted we delete the existing resources as well and
// fall back to existing code in system partition
- ret = deleteSystemPackageLI(p, flags, outInfo, writeSettings);
+ ret = deleteSystemPackageLI(ps, flags, outInfo, writeSettings);
} else {
- Log.i(TAG, "Removing non-system package:"+p.packageName);
+ Log.i(TAG, "Removing non-system package:" + ps.name);
// Kill application pre-emptively especially for apps on sd.
- killApplication(packageName, p.applicationInfo.uid);
- ret = deleteInstalledPackageLI(p, deleteCodeAndResources, flags, outInfo,
+ killApplication(packageName, ps.appId);
+ ret = deleteInstalledPackageLI(ps, deleteCodeAndResources, flags, outInfo,
writeSettings);
}
return ret;
diff --git a/services/java/com/android/server/pm/Settings.java b/services/java/com/android/server/pm/Settings.java
index 5f10d44..b075da3 100644
--- a/services/java/com/android/server/pm/Settings.java
+++ b/services/java/com/android/server/pm/Settings.java
@@ -32,7 +32,6 @@ import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
import org.xmlpull.v1.XmlSerializer;
-import android.app.AppGlobals;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
@@ -50,7 +49,6 @@ import android.os.Binder;
import android.os.Environment;
import android.os.FileUtils;
import android.os.Process;
-import android.os.RemoteException;
import android.os.UserHandle;
import android.util.Log;
import android.util.Slog;
@@ -568,6 +566,10 @@ final class Settings {
if (p.signatures.mSignatures == null) {
p.signatures.assignSignatures(pkg.mSignatures);
}
+ // Update flags if needed.
+ if (pkg.applicationInfo.flags != p.pkgFlags) {
+ p.pkgFlags = pkg.applicationInfo.flags;
+ }
// If this app defines a shared user id initialize
// the shared user signatures as well.
if (p.sharedUser != null && p.sharedUser.signatures.mSignatures == null) {
@@ -1261,7 +1263,7 @@ final class Settings {
final ArrayList<PackageCleanItem> pkgs = mPackagesToBeCleaned.valueAt(i);
for (int j=0; j<pkgs.size(); j++) {
serializer.startTag(null, "cleaning-package");
- PackageCleanItem item = pkgs.get(i);
+ PackageCleanItem item = pkgs.get(j);
serializer.attribute(null, ATTR_NAME, item.packageName);
serializer.attribute(null, ATTR_CODE, item.andCode ? "true" : "false");
serializer.attribute(null, ATTR_USER, userStr);
@@ -2603,8 +2605,8 @@ final class Settings {
first = false;
pw.print("anyDensity");
}
+ pw.println("]");
}
- pw.println("]");
pw.print(" timeStamp=");
date.setTime(ps.timeStamp);
pw.println(sdf.format(date));
@@ -2618,10 +2620,10 @@ final class Settings {
pw.print(" installerPackageName="); pw.println(ps.installerPackageName);
}
pw.print(" signatures="); pw.println(ps.signatures);
- pw.print(" permissionsFixed="); pw.print(ps.permissionsFixed);
- pw.print(" haveGids="); pw.println(ps.haveGids);
- pw.print(" pkgFlags=0x"); pw.print(Integer.toHexString(ps.pkgFlags));
- pw.print(" installStatus="); pw.println(ps.installStatus);
+ pw.print(" permissionsFixed="); pw.println(ps.permissionsFixed);
+ pw.print(" haveGids="); pw.println(ps.haveGids);
+ pw.print(" pkgFlags="); printFlags(pw, ps.pkgFlags, FLAG_DUMP_SPEC);
+ pw.print(" installStatus="); pw.println(ps.installStatus);
for (UserInfo user : users) {
pw.print(" User "); pw.print(user.id); pw.print(": ");
pw.print(" installed=");
diff --git a/services/java/com/android/server/power/DisplayPowerController.java b/services/java/com/android/server/power/DisplayPowerController.java
index 4f5561a..5f4a786 100644
--- a/services/java/com/android/server/power/DisplayPowerController.java
+++ b/services/java/com/android/server/power/DisplayPowerController.java
@@ -83,7 +83,8 @@ final class DisplayPowerController {
private static final boolean USE_ELECTRON_BEAM_ON_ANIMATION = false;
// If true, enables the use of the screen auto-brightness adjustment setting.
- private static final boolean USE_SCREEN_AUTO_BRIGHTNESS_ADJUSTMENT = false;
+ private static final boolean USE_SCREEN_AUTO_BRIGHTNESS_ADJUSTMENT =
+ PowerManager.useScreenAutoBrightnessAdjustmentFeature();
// The maximum range of gamma adjustment possible using the screen
// auto-brightness adjustment setting.
diff --git a/services/java/com/android/server/power/PowerManagerService.java b/services/java/com/android/server/power/PowerManagerService.java
index 59d0954..fda619c 100644
--- a/services/java/com/android/server/power/PowerManagerService.java
+++ b/services/java/com/android/server/power/PowerManagerService.java
@@ -372,8 +372,8 @@ public final class PowerManagerService extends IPowerManager.Stub
Settings.Secure.SCREENSAVER_ACTIVATE_ON_SLEEP), false, mSettingsObserver);
resolver.registerContentObserver(Settings.System.getUriFor(
Settings.System.SCREEN_OFF_TIMEOUT), false, mSettingsObserver);
- resolver.registerContentObserver(Settings.System.getUriFor(
- Settings.System.STAY_ON_WHILE_PLUGGED_IN), false, mSettingsObserver);
+ resolver.registerContentObserver(Settings.Global.getUriFor(
+ Settings.Global.STAY_ON_WHILE_PLUGGED_IN), false, mSettingsObserver);
resolver.registerContentObserver(Settings.System.getUriFor(
Settings.System.SCREEN_BRIGHTNESS), false, mSettingsObserver);
resolver.registerContentObserver(Settings.System.getUriFor(
@@ -405,8 +405,8 @@ public final class PowerManagerService extends IPowerManager.Stub
Settings.Secure.SCREENSAVER_ACTIVATE_ON_SLEEP, 0) != 0);
mScreenOffTimeoutSetting = Settings.System.getInt(resolver,
Settings.System.SCREEN_OFF_TIMEOUT, DEFAULT_SCREEN_OFF_TIMEOUT);
- mStayOnWhilePluggedInSetting = Settings.System.getInt(resolver,
- Settings.System.STAY_ON_WHILE_PLUGGED_IN,
+ mStayOnWhilePluggedInSetting = Settings.Global.getInt(resolver,
+ Settings.Global.STAY_ON_WHILE_PLUGGED_IN,
BatteryManager.BATTERY_PLUGGED_AC);
final int oldScreenBrightnessSetting = mScreenBrightnessSetting;
@@ -1585,8 +1585,8 @@ public final class PowerManagerService extends IPowerManager.Stub
}
private void setStayOnSettingInternal(int val) {
- Settings.System.putInt(mContext.getContentResolver(),
- Settings.System.STAY_ON_WHILE_PLUGGED_IN, val);
+ Settings.Global.putInt(mContext.getContentResolver(),
+ Settings.Global.STAY_ON_WHILE_PLUGGED_IN, val);
}
/**
diff --git a/services/java/com/android/server/wm/DisplayContent.java b/services/java/com/android/server/wm/DisplayContent.java
index 0ea051f..4df692b 100644
--- a/services/java/com/android/server/wm/DisplayContent.java
+++ b/services/java/com/android/server/wm/DisplayContent.java
@@ -94,10 +94,13 @@ class DisplayContent {
}
DisplayInfo getDisplayInfo() {
- // TODO: Add a listener for changes to Display and update mDisplayInfo when appropriate.
return mDisplayInfo;
}
+ public void updateDisplayInfo() {
+ mDisplay.getDisplayInfo(mDisplayInfo);
+ }
+
public void dump(PrintWriter pw) {
pw.print(" Display: mDisplayId="); pw.println(mDisplayId);
pw.print(" init="); pw.print(mInitialDisplayWidth); pw.print("x");
@@ -121,7 +124,7 @@ class DisplayContent {
pw.print("-"); pw.print(mDisplayInfo.largestNominalAppWidth);
pw.print("x"); pw.println(mDisplayInfo.largestNominalAppHeight);
pw.print(" layoutNeeded="); pw.println(layoutNeeded);
- pw.print("magnificationSpec="); pw.println(mMagnificationSpec.toString());
+ pw.print("magnificationSpec="); pw.println(mMagnificationSpec);
pw.println();
}
}
diff --git a/services/java/com/android/server/wm/WindowManagerService.java b/services/java/com/android/server/wm/WindowManagerService.java
index 9a0d280..cdca8bc 100755
--- a/services/java/com/android/server/wm/WindowManagerService.java
+++ b/services/java/com/android/server/wm/WindowManagerService.java
@@ -165,7 +165,7 @@ import java.util.NoSuchElementException;
/** {@hide} */
public class WindowManagerService extends IWindowManager.Stub
implements Watchdog.Monitor, WindowManagerPolicy.WindowManagerFuncs,
- DisplayManagerService.WindowManagerFuncs {
+ DisplayManagerService.WindowManagerFuncs, DisplayManager.DisplayListener {
static final String TAG = "WindowManager";
static final boolean DEBUG = false;
static final boolean DEBUG_ADD_REMOVE = false;
@@ -782,9 +782,15 @@ public class WindowManagerService extends IWindowManager.Stub
mLimitedAlphaCompositing = context.getResources().getBoolean(
com.android.internal.R.bool.config_sf_limitedAlpha);
mDisplayManagerService = displayManager;
- mDisplayManager = (DisplayManager)context.getSystemService(Context.DISPLAY_SERVICE);
mHeadless = displayManager.isHeadless();
+ mDisplayManager = (DisplayManager)context.getSystemService(Context.DISPLAY_SERVICE);
+ mDisplayManager.registerDisplayListener(this, null);
+ Display[] displays = mDisplayManager.getDisplays();
+ for (Display display : displays) {
+ createDisplayContent(display);
+ }
+
mKeyguardDisableHandler = new KeyguardDisableHandler(mContext, mPolicy);
mPowerManager = pm;
@@ -887,6 +893,12 @@ public class WindowManagerService extends IWindowManager.Stub
return -1;
}
+ /**
+ * Return the list of Windows from the passed token on the given Display.
+ * @param token The token with all the windows.
+ * @param displayContent The display we are interested in.
+ * @return List of windows from token that are on displayContent.
+ */
WindowList getTokenWindowsOnDisplay(WindowToken token, DisplayContent displayContent) {
final WindowList windowList = new WindowList();
final int count = token.windows.size();
@@ -928,7 +940,7 @@ public class WindowManagerService extends IWindowManager.Stub
WindowState lastWindow = tokenWindowList.get(index);
if (atoken != null && lastWindow == atoken.startingWindow) {
placeWindowBefore(lastWindow, win);
- tokenWindowsPos = token.windows.indexOf(lastWindow) - 1;
+ tokenWindowsPos = token.windows.indexOf(lastWindow);
} else {
int newIdx = findIdxBasedOnAppTokens(win);
//there is a window above this one associated with the same
@@ -937,10 +949,15 @@ public class WindowManagerService extends IWindowManager.Stub
//windows associated with this token.
if (DEBUG_FOCUS || DEBUG_WINDOW_MOVEMENT || DEBUG_ADD_REMOVE) {
Slog.v(TAG, "Adding window " + win + " at "
- + (newIdx+1) + " of " + N);
+ + (newIdx + 1) + " of " + N);
+ }
+ windows.add(newIdx + 1, win);
+ if (newIdx < 0) {
+ // No window from token found on win's display.
+ tokenWindowsPos = 0;
+ } else {
+ tokenWindowsPos = token.windows.indexOf(windows.get(newIdx)) + 1;
}
- windows.add(newIdx+1, win);
- tokenWindowsPos = token.windows.indexOf(windows.get(newIdx)) + 1;
mWindowsChanged = true;
}
}
@@ -1109,6 +1126,10 @@ public class WindowManagerService extends IWindowManager.Stub
if (win.mAppToken != null && addToToken) {
win.mAppToken.allAppWindows.add(win);
}
+
+ if (windows.size() == 1) {
+ mDisplayManagerService.setDisplayHasContent(win.getDisplayId(), true);
+ }
}
/** TODO(cmautner): Is this the same as {@link WindowState#canReceiveKeys()} */
@@ -2397,6 +2418,9 @@ public class WindowManagerService extends IWindowManager.Stub
final WindowList windows = win.getWindowList();
windows.remove(win);
+ if (windows.isEmpty()) {
+ mDisplayManagerService.setDisplayHasContent(win.getDisplayId(), false);
+ }
mPendingRemove.remove(win);
mWindowsChanged = true;
if (DEBUG_WINDOW_MOVEMENT) Slog.v(TAG, "Final remove of window: " + win);
@@ -5923,7 +5947,6 @@ public class WindowManagerService extends IWindowManager.Stub
mWaitingForConfig = true;
getDefaultDisplayContent().layoutNeeded = true;
startFreezingDisplayLocked(inTransaction);
- mInputManager.setDisplayOrientation(0, rotation);
// We need to update our screen size information to match the new
// rotation. Note that this is redundant with the later call to
@@ -7097,10 +7120,6 @@ public class WindowManagerService extends IWindowManager.Stub
displayInfo.appWidth, displayInfo.appHeight);
final DisplayContent displayContent = getDefaultDisplayContent();
- mInputManager.setDisplaySize(displayContent.getDisplayId(),
- displayContent.mInitialDisplayWidth, displayContent.mInitialDisplayHeight);
- mInputManager.setDisplayOrientation(displayContent.getDisplayId(),
- mDefaultDisplay.getRotation());
mPolicy.setInitialDisplaySize(mDefaultDisplay, displayContent.mInitialDisplayWidth,
displayContent.mInitialDisplayHeight, displayContent.mInitialDisplayDensity);
}
@@ -7183,6 +7202,10 @@ public class WindowManagerService extends IWindowManager.Stub
public static final int NOTIFY_WINDOW_TRANSITION = 29;
public static final int NOTIFY_RECTANGLE_ON_SCREEN_REQUESTED = 30;
+ public static final int DO_DISPLAY_ADDED = 31;
+ public static final int DO_DISPLAY_REMOVED = 32;
+ public static final int DO_DISPLAY_CHANGED = 33;
+
public static final int ANIMATOR_WHAT_OFFSET = 100000;
public static final int SET_TRANSPARENT_REGION = ANIMATOR_WHAT_OFFSET + 1;
public static final int CLEAR_PENDING_ACTIONS = ANIMATOR_WHAT_OFFSET + 2;
@@ -7620,18 +7643,21 @@ public class WindowManagerService extends IWindowManager.Stub
}
break;
}
+
case NOTIFY_ROTATION_CHANGED: {
final int displayId = msg.arg1;
final int rotation = msg.arg2;
handleNotifyRotationChanged(displayId, rotation);
break;
}
+
case NOTIFY_WINDOW_TRANSITION: {
final int transition = msg.arg1;
WindowInfo info = (WindowInfo) msg.obj;
handleNotifyWindowTranstion(transition, info);
break;
}
+
case NOTIFY_RECTANGLE_ON_SCREEN_REQUESTED: {
final int displayId = msg.arg1;
final boolean immediate = (msg.arg2 == 1);
@@ -7639,6 +7665,24 @@ public class WindowManagerService extends IWindowManager.Stub
handleNotifyRectangleOnScreenRequested(displayId, rectangle, immediate);
break;
}
+
+ case DO_DISPLAY_ADDED:
+ synchronized (mWindowMap) {
+ handleDisplayAddedLocked(msg.arg1);
+ }
+ break;
+
+ case DO_DISPLAY_REMOVED:
+ synchronized (mWindowMap) {
+ handleDisplayRemovedLocked(msg.arg1);
+ }
+ break;
+
+ case DO_DISPLAY_CHANGED:
+ synchronized (mWindowMap) {
+ handleDisplayChangedLocked(msg.arg1);
+ }
+ break;
}
if (DEBUG_WINDOW_TRACE) {
Slog.v(TAG, "handleMessage: exit");
@@ -8855,8 +8899,6 @@ public class WindowManagerService extends IWindowManager.Stub
final DisplayInfo defaultInfo = defaultDisplay.getDisplayInfo();
final int defaultDw = defaultInfo.logicalWidth;
final int defaultDh = defaultInfo.logicalHeight;
- final int defaultInnerDw = defaultInfo.appWidth;
- final int defaultInnerDh = defaultInfo.appHeight;
if (SHOW_LIGHT_TRANSACTIONS) Slog.i(TAG,
">>> OPEN TRANSACTION performLayoutAndPlaceSurfaces");
@@ -9430,6 +9472,7 @@ public class WindowManagerService extends IWindowManager.Stub
}
}
+ @Override
public void requestTraversal() {
synchronized (mWindowMap) {
requestTraversalLocked();
@@ -10454,7 +10497,7 @@ public class WindowManagerService extends IWindowManager.Stub
boolean dumpWindows(PrintWriter pw, String name, String[] args,
int opti, boolean dumpAll) {
- ArrayList<WindowState> windows = new ArrayList<WindowState>();
+ WindowList windows = new WindowList();
if ("visible".equals(name)) {
synchronized(mWindowMap) {
final AllWindowsIterator iterator = new AllWindowsIterator(REVERSE_ITERATOR);
@@ -10662,6 +10705,14 @@ public class WindowManagerService extends IWindowManager.Stub
}
}
+ public void createDisplayContent(final Display display) {
+ if (display == null) {
+ throw new IllegalArgumentException("getDisplayContent: display must not be null");
+ }
+ final DisplayContent displayContent = new DisplayContent(display);
+ mDisplayContents.put(display.getDisplayId(), displayContent);
+ }
+
public DisplayContent getDisplayContent(final int displayId) {
DisplayContent displayContent = mDisplayContents.get(displayId);
if (displayContent == null) {
@@ -10769,4 +10820,40 @@ public class WindowManagerService extends IWindowManager.Stub
public WindowList getWindowList(final Display display) {
return getDisplayContent(display.getDisplayId()).getWindowList();
}
+
+ @Override
+ public void onDisplayAdded(int displayId) {
+ mH.sendMessage(mH.obtainMessage(H.DO_DISPLAY_ADDED, displayId, 0));
+ }
+
+ private void handleDisplayAddedLocked(int displayId) {
+ createDisplayContent(mDisplayManager.getDisplay(displayId));
+ }
+
+ @Override
+ public void onDisplayRemoved(int displayId) {
+ mH.sendMessage(mH.obtainMessage(H.DO_DISPLAY_REMOVED, displayId, 0));
+ }
+
+ private void handleDisplayRemovedLocked(int displayId) {
+ final DisplayContent displayContent = getDisplayContent(displayId);
+ mDisplayContents.delete(displayId);
+ WindowList windows = displayContent.getWindowList();
+ for (int i = windows.size() - 1; i >= 0; --i) {
+ final WindowState win = windows.get(i);
+ removeWindowLocked(win.mSession, win);
+ }
+ }
+
+ @Override
+ public void onDisplayChanged(int displayId) {
+ mH.sendMessage(mH.obtainMessage(H.DO_DISPLAY_CHANGED, displayId, 0));
+ }
+
+ private void handleDisplayChangedLocked(int displayId) {
+ final DisplayContent displayContent = getDisplayContent(displayId);
+ if (displayContent != null) {
+ displayContent.updateDisplayInfo();
+ }
+ }
}
diff --git a/services/jni/com_android_server_input_InputManagerService.cpp b/services/jni/com_android_server_input_InputManagerService.cpp
index 495d4ab..5e36bf8 100644
--- a/services/jni/com_android_server_input_InputManagerService.cpp
+++ b/services/jni/com_android_server_input_InputManagerService.cpp
@@ -164,9 +164,7 @@ public:
void dump(String8& dump);
- void setDisplaySize(int32_t displayId, int32_t width, int32_t height,
- int32_t externalWidth, int32_t externalHeight);
- void setDisplayOrientation(int32_t displayId, int32_t orientation, int32_t externalOrientation);
+ void setDisplayViewport(bool external, const DisplayViewport& viewport);
status_t registerInputChannel(JNIEnv* env, const sp<InputChannel>& inputChannel,
const sp<InputWindowHandle>& inputWindowHandle, bool monitor);
@@ -223,10 +221,8 @@ private:
Mutex mLock;
struct Locked {
// Display size information.
- int32_t displayWidth, displayHeight; // -1 when not initialized
- int32_t displayOrientation;
- int32_t displayExternalWidth, displayExternalHeight; // -1 when not initialized
- int32_t displayExternalOrientation;
+ DisplayViewport internalViewport;
+ DisplayViewport externalViewport;
// System UI visibility.
int32_t systemUiVisibility;
@@ -274,13 +270,6 @@ NativeInputManager::NativeInputManager(jobject contextObj,
{
AutoMutex _l(mLock);
- mLocked.displayWidth = -1;
- mLocked.displayHeight = -1;
- mLocked.displayOrientation = DISPLAY_ORIENTATION_0;
- mLocked.displayExternalWidth = -1;
- mLocked.displayExternalHeight = -1;
- mLocked.displayExternalOrientation = DISPLAY_ORIENTATION_0;
-
mLocked.systemUiVisibility = ASYSTEM_UI_VISIBILITY_STATUS_BAR_VISIBLE;
mLocked.pointerSpeed = 0;
mLocked.pointerGesturesEnabled = true;
@@ -316,57 +305,26 @@ bool NativeInputManager::checkAndClearExceptionFromCallback(JNIEnv* env, const c
return false;
}
-void NativeInputManager::setDisplaySize(int32_t displayId, int32_t width, int32_t height,
- int32_t externalWidth, int32_t externalHeight) {
+void NativeInputManager::setDisplayViewport(bool external, const DisplayViewport& viewport) {
bool changed = false;
- if (displayId == 0) {
- AutoMutex _l(mLock);
-
- if (mLocked.displayWidth != width || mLocked.displayHeight != height) {
- changed = true;
- mLocked.displayWidth = width;
- mLocked.displayHeight = height;
-
- sp<PointerController> controller = mLocked.pointerController.promote();
- if (controller != NULL) {
- controller->setDisplaySize(width, height);
- }
- }
-
- if (mLocked.displayExternalWidth != externalWidth
- || mLocked.displayExternalHeight != externalHeight) {
- changed = true;
- mLocked.displayExternalWidth = externalWidth;
- mLocked.displayExternalHeight = externalHeight;
- }
- }
-
- if (changed) {
- mInputManager->getReader()->requestRefreshConfiguration(
- InputReaderConfiguration::CHANGE_DISPLAY_INFO);
- }
-}
-
-void NativeInputManager::setDisplayOrientation(int32_t displayId, int32_t orientation,
- int32_t externalOrientation) {
- bool changed = false;
- if (displayId == 0) {
+ {
AutoMutex _l(mLock);
- if (mLocked.displayOrientation != orientation) {
+ DisplayViewport& v = external ? mLocked.externalViewport : mLocked.internalViewport;
+ if (v != viewport) {
changed = true;
- mLocked.displayOrientation = orientation;
-
- sp<PointerController> controller = mLocked.pointerController.promote();
- if (controller != NULL) {
- controller->setDisplayOrientation(orientation);
+ v = viewport;
+
+ if (!external) {
+ sp<PointerController> controller = mLocked.pointerController.promote();
+ if (controller != NULL) {
+ controller->setDisplayViewport(
+ viewport.logicalRight - viewport.logicalLeft,
+ viewport.logicalBottom - viewport.logicalTop,
+ viewport.orientation);
+ }
}
}
-
- if (mLocked.displayExternalOrientation != externalOrientation) {
- changed = true;
- mLocked.displayExternalOrientation = externalOrientation;
- }
}
if (changed) {
@@ -448,11 +406,8 @@ void NativeInputManager::getReaderConfiguration(InputReaderConfiguration* outCon
outConfig->showTouches = mLocked.showTouches;
- outConfig->setDisplayInfo(0, false /*external*/,
- mLocked.displayWidth, mLocked.displayHeight, mLocked.displayOrientation);
- outConfig->setDisplayInfo(0, true /*external*/,
- mLocked.displayExternalWidth, mLocked.displayExternalHeight,
- mLocked.displayExternalOrientation);
+ outConfig->setDisplayInfo(false /*external*/, mLocked.internalViewport);
+ outConfig->setDisplayInfo(true /*external*/, mLocked.externalViewport);
} // release lock
}
@@ -466,8 +421,11 @@ sp<PointerControllerInterface> NativeInputManager::obtainPointerController(int32
controller = new PointerController(this, mLooper, mLocked.spriteController);
mLocked.pointerController = controller;
- controller->setDisplaySize(mLocked.displayWidth, mLocked.displayHeight);
- controller->setDisplayOrientation(mLocked.displayOrientation);
+ DisplayViewport& v = mLocked.internalViewport;
+ controller->setDisplayViewport(
+ v.logicalRight - v.logicalLeft,
+ v.logicalBottom - v.logicalTop,
+ v.orientation);
JNIEnv* env = jniEnv();
jobject pointerIconObj = env->CallObjectMethod(mServiceObj,
@@ -1032,22 +990,24 @@ static void nativeStart(JNIEnv* env, jclass clazz, jint ptr) {
}
}
-static void nativeSetDisplaySize(JNIEnv* env, jclass clazz, jint ptr,
- jint displayId, jint width, jint height, jint externalWidth, jint externalHeight) {
- NativeInputManager* im = reinterpret_cast<NativeInputManager*>(ptr);
-
- // XXX we could get this from the SurfaceFlinger directly instead of requiring it
- // to be passed in like this, not sure which is better but leaving it like this
- // keeps the window manager in direct control of when display transitions propagate down
- // to the input dispatcher
- im->setDisplaySize(displayId, width, height, externalWidth, externalHeight);
-}
-
-static void nativeSetDisplayOrientation(JNIEnv* env, jclass clazz,
- jint ptr, jint displayId, jint orientation, jint externalOrientation) {
+static void nativeSetDisplayViewport(JNIEnv* env, jclass clazz, jint ptr, jboolean external,
+ jint displayId, jint orientation,
+ jint logicalLeft, jint logicalTop, jint logicalRight, jint logicalBottom,
+ jint physicalLeft, jint physicalTop, jint physicalRight, jint physicalBottom) {
NativeInputManager* im = reinterpret_cast<NativeInputManager*>(ptr);
- im->setDisplayOrientation(displayId, orientation, externalOrientation);
+ DisplayViewport v;
+ v.displayId = displayId;
+ v.orientation = orientation;
+ v.logicalLeft = logicalLeft;
+ v.logicalTop = logicalTop;
+ v.logicalRight = logicalRight;
+ v.logicalBottom = logicalBottom;
+ v.physicalLeft = physicalLeft;
+ v.physicalTop = physicalTop;
+ v.physicalRight = physicalRight;
+ v.physicalBottom = physicalBottom;
+ im->setDisplayViewport(external, v);
}
static jint nativeGetScanCodeState(JNIEnv* env, jclass clazz,
@@ -1328,10 +1288,8 @@ static JNINativeMethod gInputManagerMethods[] = {
(void*) nativeInit },
{ "nativeStart", "(I)V",
(void*) nativeStart },
- { "nativeSetDisplaySize", "(IIIIII)V",
- (void*) nativeSetDisplaySize },
- { "nativeSetDisplayOrientation", "(IIII)V",
- (void*) nativeSetDisplayOrientation },
+ { "nativeSetDisplayViewport", "(IZIIIIIIIIII)V",
+ (void*) nativeSetDisplayViewport },
{ "nativeGetScanCodeState", "(IIII)I",
(void*) nativeGetScanCodeState },
{ "nativeGetKeyCodeState", "(IIII)I",
diff --git a/test-runner/src/android/test/mock/MockPackageManager.java b/test-runner/src/android/test/mock/MockPackageManager.java
index 19eb8d2..cd7ee76 100644
--- a/test-runner/src/android/test/mock/MockPackageManager.java
+++ b/test-runner/src/android/test/mock/MockPackageManager.java
@@ -140,6 +140,12 @@ public class MockPackageManager extends PackageManager {
throw new UnsupportedOperationException();
}
+ /** @hide */
+ @Override
+ public List<PackageInfo> getInstalledPackages(int flags, int userId) {
+ throw new UnsupportedOperationException();
+ }
+
@Override
public int checkPermission(String permName, String pkgName) {
throw new UnsupportedOperationException();
@@ -215,6 +221,13 @@ public class MockPackageManager extends PackageManager {
throw new UnsupportedOperationException();
}
+ /** @hide */
+ @Override
+ public List<ResolveInfo> queryIntentActivitiesForUser(Intent intent,
+ int flags, int userId) {
+ throw new UnsupportedOperationException();
+ }
+
@Override
public List<ResolveInfo> queryIntentActivityOptions(ComponentName caller,
Intent[] specifics, Intent intent, int flags) {
diff --git a/tests/HwAccelerationTest/AndroidManifest.xml b/tests/HwAccelerationTest/AndroidManifest.xml
index aebc594..4e229ec 100644
--- a/tests/HwAccelerationTest/AndroidManifest.xml
+++ b/tests/HwAccelerationTest/AndroidManifest.xml
@@ -42,6 +42,15 @@
</activity>
<activity
+ android:name="TJunctionActivity"
+ android:label="_T-Junction">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.LAUNCHER" />
+ </intent-filter>
+ </activity>
+
+ <activity
android:name="TextPathActivity"
android:label="_TextPath">
<intent-filter>
diff --git a/tests/HwAccelerationTest/src/com/android/test/hwui/LinesActivity.java b/tests/HwAccelerationTest/src/com/android/test/hwui/LinesActivity.java
index f0abb50..eed0ec8 100644
--- a/tests/HwAccelerationTest/src/com/android/test/hwui/LinesActivity.java
+++ b/tests/HwAccelerationTest/src/com/android/test/hwui/LinesActivity.java
@@ -153,6 +153,14 @@ public class LinesActivity extends Activity {
canvas.drawLine(10.0f, 45.0f, 20.0f, 55.0f, mSmallPaint);
canvas.drawLine(10.0f, 60.0f, 50.0f, 60.0f, mHairLinePaint);
canvas.restore();
+
+ canvas.save();
+ canvas.scale(10.0f, 50.0f);
+ mSmallPaint.setStrokeWidth(0.0f);
+ canvas.drawLine(20.0f, 9.0f, 30.0f, 11.0f, mSmallPaint);
+ mSmallPaint.setStrokeWidth(1.0f);
+ canvas.drawLine(30.0f, 9.0f, 40.0f, 11.0f, mSmallPaint);
+ canvas.restore();
}
}
}
diff --git a/tests/HwAccelerationTest/src/com/android/test/hwui/TJunctionActivity.java b/tests/HwAccelerationTest/src/com/android/test/hwui/TJunctionActivity.java
new file mode 100644
index 0000000..d2bcae9
--- /dev/null
+++ b/tests/HwAccelerationTest/src/com/android/test/hwui/TJunctionActivity.java
@@ -0,0 +1,81 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.test.hwui;
+
+import android.app.Activity;
+import android.content.Context;
+import android.graphics.Canvas;
+import android.graphics.Paint;
+import android.os.Bundle;
+import android.view.View;
+
+@SuppressWarnings("UnusedDeclaration")
+public class TJunctionActivity extends Activity {
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(new TJunctionView(this));
+ }
+
+ private class TJunctionView extends View {
+ private final Paint mPaint;
+
+ public TJunctionView(Context context) {
+ super(context);
+
+ setLayerType(LAYER_TYPE_HARDWARE, null);
+
+ mPaint = new Paint();
+ }
+
+ @Override
+ protected void onDraw(Canvas canvas) {
+ super.onDraw(canvas);
+
+ mPaint.setColor(0xffff0000);
+
+ canvas.translate(10.0f, 10.0f);
+ canvas.drawRect(0.0f, 0.0f, 100.0f, 50.0f, mPaint);
+
+ mPaint.setColor(0xff00ff00);
+
+ canvas.translate(50.0f, 50.0f);
+ canvas.drawRect(0.0f, 0.0f, 100.0f, 50.0f, mPaint);
+
+ mPaint.setColor(0xff0000ff);
+
+ canvas.translate(-25.0f, 50.0f);
+ canvas.drawRect(0.0f, 0.0f, 100.0f, 50.0f, mPaint);
+
+ mPaint.setColor(0xffffffff);
+
+ canvas.translate(150.0f, 75.0f);
+ canvas.drawRect(0.0f, 0.0f, 100.0f, 50.0f, mPaint);
+
+ canvas.translate(-50.0f, 75.0f);
+ canvas.drawRect(0.0f, 0.0f, 100.0f, 50.0f, mPaint);
+
+ canvas.translate(-75.0f, 50.0f);
+ canvas.drawRect(0.0f, 0.0f, 100.0f, 50.0f, mPaint);
+
+ canvas.translate(150.0f, 0.0f);
+ canvas.drawRect(0.0f, 0.0f, 100.0f, 50.0f, mPaint);
+
+ invalidate();
+ }
+ }
+}
diff --git a/tests/RenderScriptTests/ImageProcessing/res/drawable-nodpi/city.png b/tests/RenderScriptTests/ImageProcessing/res/drawable-nodpi/city.png
deleted file mode 100644
index 856eeff..0000000
--- a/tests/RenderScriptTests/ImageProcessing/res/drawable-nodpi/city.png
+++ /dev/null
Binary files differ
diff --git a/tests/RenderScriptTests/ImageProcessing/res/drawable-nodpi/img1600x1067.jpg b/tests/RenderScriptTests/ImageProcessing/res/drawable-nodpi/img1600x1067.jpg
new file mode 100644
index 0000000..05d3ee2
--- /dev/null
+++ b/tests/RenderScriptTests/ImageProcessing/res/drawable-nodpi/img1600x1067.jpg
Binary files differ
diff --git a/tests/RenderScriptTests/ImageProcessing/res/drawable-nodpi/img640x427.jpg b/tests/RenderScriptTests/ImageProcessing/res/drawable-nodpi/img640x427.jpg
new file mode 100644
index 0000000..5bce392
--- /dev/null
+++ b/tests/RenderScriptTests/ImageProcessing/res/drawable-nodpi/img640x427.jpg
Binary files differ
diff --git a/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/ColorMatrix.java b/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/ColorMatrix.java
index 87a2de1..2ac40a1 100644
--- a/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/ColorMatrix.java
+++ b/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/ColorMatrix.java
@@ -33,9 +33,11 @@ public class ColorMatrix extends TestBase {
private ScriptC_colormatrix mScript;
private ScriptIntrinsicColorMatrix mIntrinsic;
private boolean mUseIntrinsic;
+ private boolean mUseGrey;
- public ColorMatrix(boolean useIntrinsic) {
+ public ColorMatrix(boolean useIntrinsic, boolean useGrey) {
mUseIntrinsic = useIntrinsic;
+ mUseGrey = useGrey;
}
public void createTest(android.content.res.Resources res) {
@@ -46,7 +48,11 @@ public class ColorMatrix extends TestBase {
if (mUseIntrinsic) {
mIntrinsic = ScriptIntrinsicColorMatrix.create(mRS, Element.U8_4(mRS));
- mIntrinsic.setColorMatrix(m);
+ if (mUseGrey) {
+ mIntrinsic.setGreyscale();
+ } else {
+ mIntrinsic.setColorMatrix(m);
+ }
} else {
mScript = new ScriptC_colormatrix(mRS, res, R.raw.colormatrix);
mScript.invoke_setMatrix(m);
diff --git a/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/ImageProcessingActivity.java b/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/ImageProcessingActivity.java
index 001dea8..37577eb 100644
--- a/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/ImageProcessingActivity.java
+++ b/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/ImageProcessingActivity.java
@@ -180,12 +180,15 @@ public class ImageProcessingActivity extends Activity
mTest = new Convolve3x3(true);
break;
case 19:
- mTest = new ColorMatrix(false);
+ mTest = new ColorMatrix(false, false);
break;
case 20:
- mTest = new ColorMatrix(true);
+ mTest = new ColorMatrix(true, false);
break;
case 21:
+ mTest = new ColorMatrix(true, true);
+ break;
+ case 22:
mTest = new Copy();
break;
}
@@ -200,7 +203,7 @@ public class ImageProcessingActivity extends Activity
}
void setupTests() {
- mTestNames = new String[22];
+ mTestNames = new String[23];
mTestNames[0] = "Levels Vec3 Relaxed";
mTestNames[1] = "Levels Vec4 Relaxed";
mTestNames[2] = "Levels Vec3 Full";
@@ -222,7 +225,8 @@ public class ImageProcessingActivity extends Activity
mTestNames[18] = "Intrinsics Convolve 3x3";
mTestNames[19] = "ColorMatrix";
mTestNames[20] = "Intrinsics ColorMatrix";
- mTestNames[21] = "Copy";
+ mTestNames[21] = "Intrinsics ColorMatrix Grey";
+ mTestNames[22] = "Copy";
mTestSpinner.setAdapter(new ArrayAdapter<String>(
this, R.layout.spinner_layout, mTestNames));
}
@@ -243,8 +247,8 @@ public class ImageProcessingActivity extends Activity
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
- mBitmapIn = loadBitmap(R.drawable.city);
- mBitmapOut = loadBitmap(R.drawable.city);
+ mBitmapIn = loadBitmap(R.drawable.img1600x1067);
+ mBitmapOut = loadBitmap(R.drawable.img1600x1067);
mSurfaceView = (SurfaceView) findViewById(R.id.surface);
diff --git a/tools/aapt/Android.mk b/tools/aapt/Android.mk
index 482f43e..d9b0681 100644
--- a/tools/aapt/Android.mk
+++ b/tools/aapt/Android.mk
@@ -34,7 +34,6 @@ LOCAL_CFLAGS += -D_DARWIN_UNLIMITED_STREAMS
endif
-LOCAL_C_INCLUDES += external/expat/lib
LOCAL_C_INCLUDES += external/libpng
LOCAL_C_INCLUDES += external/zlib
LOCAL_C_INCLUDES += build/libs/host/include
diff --git a/tools/aapt/StringPool.h b/tools/aapt/StringPool.h
index d501008..16050b2 100644
--- a/tools/aapt/StringPool.h
+++ b/tools/aapt/StringPool.h
@@ -21,7 +21,7 @@
#include <ctype.h>
#include <errno.h>
-#include <expat.h>
+#include <libexpat/expat.h>
using namespace android;
diff --git a/wifi/java/android/net/wifi/p2p/WifiP2pDeviceList.java b/wifi/java/android/net/wifi/p2p/WifiP2pDeviceList.java
index 48cdbc2..157dc50 100644
--- a/wifi/java/android/net/wifi/p2p/WifiP2pDeviceList.java
+++ b/wifi/java/android/net/wifi/p2p/WifiP2pDeviceList.java
@@ -35,10 +35,9 @@ import java.util.HashMap;
*/
public class WifiP2pDeviceList implements Parcelable {
- private HashMap<String, WifiP2pDevice> mDevices;
+ private final HashMap<String, WifiP2pDevice> mDevices = new HashMap<String, WifiP2pDevice>();
public WifiP2pDeviceList() {
- mDevices = new HashMap<String, WifiP2pDevice>();
}
/** copy constructor */
@@ -52,7 +51,6 @@ public class WifiP2pDeviceList implements Parcelable {
/** @hide */
public WifiP2pDeviceList(ArrayList<WifiP2pDevice> devices) {
- mDevices = new HashMap<String, WifiP2pDevice>();
for (WifiP2pDevice device : devices) {
if (device.deviceAddress != null) {
mDevices.put(device.deviceAddress, device);
diff --git a/wifi/java/android/net/wifi/p2p/WifiP2pGroupList.java b/wifi/java/android/net/wifi/p2p/WifiP2pGroupList.java
index 3459a5a..98f0972 100644
--- a/wifi/java/android/net/wifi/p2p/WifiP2pGroupList.java
+++ b/wifi/java/android/net/wifi/p2p/WifiP2pGroupList.java
@@ -16,6 +16,7 @@
package android.net.wifi.p2p;
import java.util.Collection;
+import java.util.Map;
import android.os.Parcel;
import android.os.Parcelable;
@@ -32,8 +33,9 @@ public class WifiP2pGroupList implements Parcelable {
private static final int CREDENTIAL_MAX_NUM = 32;
- private LruCache<Integer, WifiP2pGroup> mGroups;
- private GroupDeleteListener mListener;
+ private final LruCache<Integer, WifiP2pGroup> mGroups;
+ private final GroupDeleteListener mListener;
+
private boolean isClearCalled = false;
public interface GroupDeleteListener {
@@ -41,10 +43,10 @@ public class WifiP2pGroupList implements Parcelable {
}
WifiP2pGroupList() {
- this(null);
+ this(null, null);
}
- WifiP2pGroupList(GroupDeleteListener listener) {
+ WifiP2pGroupList(WifiP2pGroupList source, GroupDeleteListener listener) {
mListener = listener;
mGroups = new LruCache<Integer, WifiP2pGroup>(CREDENTIAL_MAX_NUM) {
@Override
@@ -55,6 +57,12 @@ public class WifiP2pGroupList implements Parcelable {
}
}
};
+
+ if (source != null) {
+ for (Map.Entry<Integer, WifiP2pGroup> item : source.mGroups.snapshot().entrySet()) {
+ mGroups.put(item.getKey(), item.getValue());
+ }
+ }
}
/**
diff --git a/wifi/java/android/net/wifi/p2p/WifiP2pService.java b/wifi/java/android/net/wifi/p2p/WifiP2pService.java
index a6770bd..3575d97 100644
--- a/wifi/java/android/net/wifi/p2p/WifiP2pService.java
+++ b/wifi/java/android/net/wifi/p2p/WifiP2pService.java
@@ -359,8 +359,8 @@ public class WifiP2pService extends IWifiP2pManager.Stub {
private WifiNative mWifiNative = new WifiNative(mInterface);
private WifiMonitor mWifiMonitor = new WifiMonitor(this, mWifiNative);
- private WifiP2pDeviceList mPeers = new WifiP2pDeviceList();
- private WifiP2pGroupList mGroups = new WifiP2pGroupList(
+ private final WifiP2pDeviceList mPeers = new WifiP2pDeviceList();
+ private final WifiP2pGroupList mGroups = new WifiP2pGroupList(null,
new GroupDeleteListener() {
@Override
public void onDeleteGroup(int netId) {
@@ -370,7 +370,7 @@ public class WifiP2pService extends IWifiP2pManager.Stub {
sendP2pPersistentGroupsChangedBroadcast();
}
});
- private WifiP2pInfo mWifiP2pInfo = new WifiP2pInfo();
+ private final WifiP2pInfo mWifiP2pInfo = new WifiP2pInfo();
private WifiP2pGroup mGroup;
// Saved WifiP2pConfig for a peer connection
@@ -501,17 +501,20 @@ public class WifiP2pService extends IWifiP2pManager.Stub {
WifiP2pManager.BUSY);
break;
case WifiP2pManager.REQUEST_PEERS:
- replyToMessage(message, WifiP2pManager.RESPONSE_PEERS, mPeers);
+ replyToMessage(message, WifiP2pManager.RESPONSE_PEERS,
+ new WifiP2pDeviceList(mPeers));
break;
case WifiP2pManager.REQUEST_CONNECTION_INFO:
- replyToMessage(message, WifiP2pManager.RESPONSE_CONNECTION_INFO, mWifiP2pInfo);
+ replyToMessage(message, WifiP2pManager.RESPONSE_CONNECTION_INFO,
+ new WifiP2pInfo(mWifiP2pInfo));
break;
case WifiP2pManager.REQUEST_GROUP_INFO:
- replyToMessage(message, WifiP2pManager.RESPONSE_GROUP_INFO, mGroup);
+ replyToMessage(message, WifiP2pManager.RESPONSE_GROUP_INFO,
+ mGroup != null ? new WifiP2pGroup(mGroup) : null);
break;
case WifiP2pManager.REQUEST_PERSISTENT_GROUP_INFO:
replyToMessage(message, WifiP2pManager.RESPONSE_PERSISTENT_GROUP_INFO,
- mGroups);
+ new WifiP2pGroupList(mGroups, null));
break;
case WifiP2pManager.SET_DIALOG_LISTENER:
String appPkgName = (String)message.getData().getString(