summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--api/current.txt16
-rw-r--r--core/java/android/app/backup/BackupAgent.java1
-rw-r--r--core/java/android/app/backup/FullBackup.java7
-rw-r--r--core/java/android/app/backup/FullBackupAgent.java26
-rw-r--r--core/java/android/content/Intent.java15
-rw-r--r--core/java/android/content/pm/PackageParser.java3
-rw-r--r--core/java/android/net/ConnectivityManager.java53
-rw-r--r--core/java/android/net/IConnectivityManager.aidl3
-rw-r--r--core/java/android/net/INetworkStatsService.aidl10
-rw-r--r--core/java/android/net/NetworkState.aidl19
-rw-r--r--core/java/android/net/NetworkState.java68
-rw-r--r--core/java/android/net/NetworkStats.java20
-rw-r--r--core/java/android/net/NetworkStatsHistory.java127
-rw-r--r--core/java/android/net/TrafficStats.java36
-rw-r--r--core/java/android/os/storage/StorageVolume.java24
-rw-r--r--core/java/android/provider/Calendar.java43
-rw-r--r--core/java/android/provider/Settings.java37
-rw-r--r--core/java/android/speech/tts/AudioMessageParams.java37
-rw-r--r--core/java/android/speech/tts/AudioPlaybackHandler.java358
-rw-r--r--core/java/android/speech/tts/MessageParams.java36
-rw-r--r--core/java/android/speech/tts/PlaybackSynthesisRequest.java289
-rw-r--r--core/java/android/speech/tts/SilenceMessageParams.java43
-rw-r--r--core/java/android/speech/tts/SynthesisMessageParams.java92
-rw-r--r--core/java/android/speech/tts/TextToSpeechService.java71
-rw-r--r--core/java/android/view/Gravity.java14
-rw-r--r--core/java/android/view/View.java94
-rw-r--r--core/java/android/view/ViewConfiguration.java40
-rw-r--r--core/java/android/view/inputmethod/InputMethodSubtype.java49
-rw-r--r--core/java/android/webkit/WebView.java2
-rw-r--r--core/java/android/widget/LinearLayout.java4
-rw-r--r--core/java/com/android/internal/util/Objects.java45
-rw-r--r--core/java/com/android/internal/util/Preconditions.java57
-rw-r--r--core/jni/android_app_backup_FullBackup.cpp2
-rw-r--r--core/res/res/layout/volume_adjust.xml20
-rw-r--r--core/res/res/layout/volume_adjust_item.xml5
-rwxr-xr-xcore/res/res/values/attrs.xml16
-rw-r--r--core/res/res/values/public.xml8
-rwxr-xr-xcore/res/res/values/strings.xml2
-rw-r--r--core/tests/coretests/Android.mk2
-rw-r--r--core/tests/coretests/src/android/net/NetworkStatsHistoryTest.java129
-rw-r--r--core/tests/coretests/src/android/net/http/AbstractProxyTest.java8
-rw-r--r--core/tests/coretests/src/android/net/http/CookiesTest.java6
-rw-r--r--core/tests/coretests/src/android/net/http/DefaultHttpClientTest.java12
-rw-r--r--docs/html/guide/topics/graphics/renderscript.jd2
-rw-r--r--include/ui/Input.h5
-rw-r--r--keystore/java/android/security/Credentials.java47
-rw-r--r--keystore/java/android/security/KeyChain.java9
-rw-r--r--libs/ui/Input.cpp9
-rw-r--r--media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/MediaFrameworkTest.java57
-rwxr-xr-xmedia/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/MediaNames.java277
-rw-r--r--media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/MediaMetadataTest.java83
-rw-r--r--media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/MediaPlayerApiTest.java8
-rw-r--r--media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/performance/MediaPlayerPerformance.java110
-rw-r--r--packages/BackupRestoreConfirmation/src/com/android/backupconfirm/BackupRestoreConfirmation.java31
-rw-r--r--packages/SharedStorageBackup/Android.mk33
-rw-r--r--packages/SharedStorageBackup/AndroidManifest.xml29
-rw-r--r--packages/SharedStorageBackup/proguard.flags1
-rw-r--r--packages/SharedStorageBackup/src/com/android/sharedstoragebackup/SharedStorageAgent.java93
-rw-r--r--packages/SystemUI/res/drawable-sw600dp-hdpi/ic_sysbar_zoom_default.pngbin0 -> 4050 bytes
-rw-r--r--packages/SystemUI/res/drawable-sw600dp-hdpi/ic_sysbar_zoom_pressed.pngbin0 -> 7760 bytes
-rw-r--r--packages/SystemUI/res/drawable-sw600dp-mdpi/ic_sysbar_zoom_default.pngbin0 -> 2642 bytes
-rw-r--r--packages/SystemUI/res/drawable-sw600dp-mdpi/ic_sysbar_zoom_pressed.pngbin0 -> 4140 bytes
-rw-r--r--packages/SystemUI/res/drawable/ic_sysbar_zoom.xml21
-rw-r--r--packages/SystemUI/res/layout-sw600dp/status_bar.xml7
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/policy/CompatModeButton.java63
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkController.java16
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletStatusBar.java5
-rw-r--r--services/camera/libcameraservice/CameraHardwareInterface.h88
-rw-r--r--services/input/InputReader.cpp418
-rw-r--r--services/input/InputReader.h21
-rw-r--r--services/input/PointerController.cpp8
-rw-r--r--services/input/PointerController.h39
-rw-r--r--services/input/tests/InputReader_test.cpp4
-rw-r--r--services/java/com/android/server/BackupManagerService.java177
-rw-r--r--services/java/com/android/server/ConnectivityService.java79
-rw-r--r--services/java/com/android/server/MountService.java8
-rw-r--r--services/java/com/android/server/SystemBackupAgent.java2
-rw-r--r--services/java/com/android/server/SystemServer.java1
-rw-r--r--services/java/com/android/server/WifiService.java14
-rw-r--r--services/java/com/android/server/WifiWatchdogService.java69
-rw-r--r--services/java/com/android/server/accessibility/TouchExplorer.java20
-rw-r--r--services/java/com/android/server/am/ActivityManagerService.java1
-rw-r--r--services/java/com/android/server/connectivity/Tethering.java7
-rw-r--r--services/java/com/android/server/net/InterfaceIdentity.java73
-rw-r--r--services/java/com/android/server/net/NetworkIdentity.java208
-rw-r--r--services/java/com/android/server/net/NetworkPolicyManagerService.java2
-rw-r--r--services/java/com/android/server/net/NetworkStatsService.java447
-rw-r--r--services/java/com/android/server/wm/InputManager.java14
-rw-r--r--services/java/com/android/server/wm/WindowManagerService.java43
-rw-r--r--services/jni/com_android_server_InputManager.cpp34
-rw-r--r--telephony/java/android/telephony/TelephonyManager.java47
-rw-r--r--telephony/java/com/android/internal/telephony/BaseCommands.java6
-rw-r--r--telephony/java/com/android/internal/telephony/RIL.java24
-rw-r--r--tests/BiDiTests/res/layout/frame_layout_ltr.xml10
-rw-r--r--tests/BiDiTests/res/layout/frame_layout_rtl.xml10
-rw-r--r--tests/BiDiTests/res/layout/linear_layout_ltr.xml14
-rw-r--r--tests/BiDiTests/res/layout/linear_layout_rtl.xml14
-rw-r--r--tests/BiDiTests/res/layout/relative_layout_ltr.xml10
-rw-r--r--tests/BiDiTests/res/layout/relative_layout_ltr_2.xml8
-rw-r--r--tests/BiDiTests/res/layout/relative_layout_rtl.xml10
-rw-r--r--tests/BiDiTests/res/layout/relative_layout_rtl_2.xml8
-rw-r--r--tests/BiDiTests/res/layout/table_layout_ltr.xml8
-rw-r--r--tests/BiDiTests/res/layout/table_layout_rtl.xml8
-rw-r--r--tools/layoutlib/bridge/src/android/graphics/Canvas_Delegate.java4
-rw-r--r--tools/layoutlib/bridge/src/android/os/HandlerThread_Delegate.java80
-rw-r--r--tools/layoutlib/bridge/src/android/view/LayoutInflater_Delegate.java129
-rw-r--r--tools/layoutlib/bridge/src/com/android/layoutlib/bridge/Bridge.java2
-rw-r--r--tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java114
-rw-r--r--tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeInflater.java4
-rw-r--r--tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeResources.java9
-rw-r--r--tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeTypedArray.java93
-rw-r--r--tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/CustomBar.java2
-rw-r--r--tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/RenderAction.java5
-rw-r--r--tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/ResourceHelper.java5
-rw-r--r--tools/layoutlib/bridge/tests/src/com/android/layoutlib/bridge/android/BridgeXmlBlockParserTest.java2
-rw-r--r--tools/layoutlib/create/src/com/android/tools/layoutlib/create/CreateInfo.java2
116 files changed, 3423 insertions, 1837 deletions
diff --git a/api/current.txt b/api/current.txt
index 852a53366d1f..80d0687a8873 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -486,7 +486,6 @@ package android {
field public static final int hint = 16843088; // 0x1010150
field public static final int homeAsUpIndicator = 16843531; // 0x101030b
field public static final int homeLayout = 16843549; // 0x101031d
- field public static final int horizontalDirection = 16843631; // 0x101036f
field public static final int horizontalDivider = 16843053; // 0x101012d
field public static final int horizontalGap = 16843327; // 0x101023f
field public static final int horizontalScrollViewStyle = 16843603; // 0x1010353
@@ -571,6 +570,7 @@ package android {
field public static final int layerType = 16843604; // 0x1010354
field public static final int layout = 16842994; // 0x10100f2
field public static final int layoutAnimation = 16842988; // 0x10100ec
+ field public static final int layoutDirection = 16843631; // 0x101036f
field public static final int layout_above = 16843140; // 0x1010184
field public static final int layout_alignBaseline = 16843142; // 0x1010186
field public static final int layout_alignBottom = 16843146; // 0x101018a
@@ -1516,12 +1516,13 @@ package android {
field public static final int Theme_Holo_Light_Dialog_NoActionBar = 16973941; // 0x1030075
field public static final int Theme_Holo_Light_Dialog_NoActionBar_MinWidth = 16973942; // 0x1030076
field public static final int Theme_Holo_Light_NoActionBar = 16974064; // 0x10300f0
+ field public static final int Theme_Holo_Light_NoActionBar_Fullscreen = 16974065; // 0x10300f1
field public static final int Theme_Holo_Light_Panel = 16973948; // 0x103007c
- field public static final int Theme_Holo_Light_SplitActionBarWhenNarrow = 16974067; // 0x10300f3
+ field public static final int Theme_Holo_Light_SplitActionBarWhenNarrow = 16974068; // 0x10300f4
field public static final int Theme_Holo_NoActionBar = 16973932; // 0x103006c
field public static final int Theme_Holo_NoActionBar_Fullscreen = 16973933; // 0x103006d
field public static final int Theme_Holo_Panel = 16973947; // 0x103007b
- field public static final int Theme_Holo_SplitActionBarWhenNarrow = 16974066; // 0x10300f2
+ field public static final int Theme_Holo_SplitActionBarWhenNarrow = 16974067; // 0x10300f3
field public static final int Theme_Holo_Wallpaper = 16973949; // 0x103007d
field public static final int Theme_Holo_Wallpaper_NoTitleBar = 16973950; // 0x103007e
field public static final int Theme_InputMethod = 16973908; // 0x1030054
@@ -4967,6 +4968,7 @@ package android.content {
field public static final java.lang.String ACTION_INSERT_OR_EDIT = "android.intent.action.INSERT_OR_EDIT";
field public static final java.lang.String ACTION_LOCALE_CHANGED = "android.intent.action.LOCALE_CHANGED";
field public static final java.lang.String ACTION_MAIN = "android.intent.action.MAIN";
+ field public static final java.lang.String ACTION_MANAGE_NETWORK_USAGE = "android.intent.action.MANAGE_NETWORK_USAGE";
field public static final java.lang.String ACTION_MANAGE_PACKAGE_STORAGE = "android.intent.action.MANAGE_PACKAGE_STORAGE";
field public static final java.lang.String ACTION_MEDIA_BAD_REMOVAL = "android.intent.action.MEDIA_BAD_REMOVAL";
field public static final java.lang.String ACTION_MEDIA_BUTTON = "android.intent.action.MEDIA_BUTTON";
@@ -5015,8 +5017,8 @@ package android.content {
field public static final java.lang.String ACTION_TIME_CHANGED = "android.intent.action.TIME_SET";
field public static final java.lang.String ACTION_TIME_TICK = "android.intent.action.TIME_TICK";
field public static final java.lang.String ACTION_UID_REMOVED = "android.intent.action.UID_REMOVED";
- field public static final java.lang.String ACTION_UMS_CONNECTED = "android.intent.action.UMS_CONNECTED";
- field public static final java.lang.String ACTION_UMS_DISCONNECTED = "android.intent.action.UMS_DISCONNECTED";
+ field public static final deprecated java.lang.String ACTION_UMS_CONNECTED = "android.intent.action.UMS_CONNECTED";
+ field public static final deprecated java.lang.String ACTION_UMS_DISCONNECTED = "android.intent.action.UMS_DISCONNECTED";
field public static final java.lang.String ACTION_USER_PRESENT = "android.intent.action.USER_PRESENT";
field public static final java.lang.String ACTION_VIEW = "android.intent.action.VIEW";
field public static final java.lang.String ACTION_VOICE_COMMAND = "android.intent.action.VOICE_COMMAND";
@@ -20458,8 +20460,8 @@ package android.view {
field public static final int HORIZONTAL_GRAVITY_MASK = 7; // 0x7
field public static final int LEFT = 3; // 0x3
field public static final int NO_GRAVITY = 0; // 0x0
- field public static final int RELATIVE_HORIZONTAL_DIRECTION = 8388608; // 0x800000
field public static final int RELATIVE_HORIZONTAL_GRAVITY_MASK = 8388615; // 0x800007
+ field public static final int RELATIVE_LAYOUT_DIRECTION = 8388608; // 0x800000
field public static final int RIGHT = 5; // 0x5
field public static final int START = 8388611; // 0x800003
field public static final int TOP = 48; // 0x30
@@ -23276,6 +23278,8 @@ package android.view.inputmethod {
}
public final class InputMethodSubtype implements android.os.Parcelable {
+ ctor public InputMethodSubtype(int, int, java.lang.String, java.lang.String, java.lang.String);
+ ctor public InputMethodSubtype(int, int, java.lang.String, java.lang.String, java.lang.String, boolean);
method public boolean containsExtraValueKey(java.lang.String);
method public int describeContents();
method public java.lang.CharSequence getDisplayName(android.content.Context, java.lang.String, android.content.pm.ApplicationInfo);
diff --git a/core/java/android/app/backup/BackupAgent.java b/core/java/android/app/backup/BackupAgent.java
index 17f8adbb0ccf..63f325870f91 100644
--- a/core/java/android/app/backup/BackupAgent.java
+++ b/core/java/android/app/backup/BackupAgent.java
@@ -278,7 +278,6 @@ public abstract class BackupAgent extends ContextWrapper {
int token, IBackupManager callbackBinder) throws RemoteException {
long ident = Binder.clearCallingIdentity();
try {
-Log.d(TAG, "doRestoreFile() => onRestoreFile()");
BackupAgent.this.onRestoreFile(data, size, type, domain, path, mode, mtime);
} catch (IOException e) {
throw new RuntimeException(e);
diff --git a/core/java/android/app/backup/FullBackup.java b/core/java/android/app/backup/FullBackup.java
index dfb0dd7f5f04..3b70e19ad244 100644
--- a/core/java/android/app/backup/FullBackup.java
+++ b/core/java/android/app/backup/FullBackup.java
@@ -46,7 +46,7 @@ public class FullBackup {
public static final String SHARED_STORAGE_TOKEN = "shared";
public static final String APPS_PREFIX = "apps/";
- public static final String SHARED_PREFIX = "shared/";
+ public static final String SHARED_PREFIX = SHARED_STORAGE_TOKEN + "/";
public static final String FULL_BACKUP_INTENT_ACTION = "fullback";
public static final String FULL_RESTORE_INTENT_ACTION = "fullrest";
@@ -61,7 +61,8 @@ public class FullBackup {
String linkdomain, String rootpath, String path, BackupDataOutput output);
static public void restoreToFile(ParcelFileDescriptor data,
- long size, int type, long mode, long mtime, File outFile) throws IOException {
+ long size, int type, long mode, long mtime, File outFile,
+ boolean doChmod) throws IOException {
if (type == FullBackup.TYPE_DIRECTORY) {
// Canonically a directory has no associated content, so we don't need to read
// anything from the pipe in this case. Just create the directory here and
@@ -116,7 +117,7 @@ public class FullBackup {
}
// Now twiddle the state to match the backup, assuming all went well
- if (outFile != null) {
+ if (doChmod && outFile != null) {
try {
Libcore.os.chmod(outFile.getPath(), (int)mode);
} catch (ErrnoException e) {
diff --git a/core/java/android/app/backup/FullBackupAgent.java b/core/java/android/app/backup/FullBackupAgent.java
index 4dca5936dbc3..df1c3639bc58 100644
--- a/core/java/android/app/backup/FullBackupAgent.java
+++ b/core/java/android/app/backup/FullBackupAgent.java
@@ -28,8 +28,6 @@ import libcore.io.OsConstants;
import libcore.io.StructStat;
import java.io.File;
-import java.io.FileInputStream;
-import java.io.FileOutputStream;
import java.io.IOException;
import java.util.HashSet;
import java.util.LinkedList;
@@ -84,9 +82,10 @@ public class FullBackupAgent extends BackupAgent {
@Override
public void onBackup(ParcelFileDescriptor oldState, BackupDataOutput data,
- ParcelFileDescriptor newState) {
+ ParcelFileDescriptor newState) throws IOException {
// Filters, the scan queue, and the set of resulting entities
HashSet<String> filterSet = new HashSet<String>();
+ String packageName = getPackageName();
// Okay, start with the app's root tree, but exclude all of the canonical subdirs
if (mLibDir != null) {
@@ -96,25 +95,28 @@ public class FullBackupAgent extends BackupAgent {
filterSet.add(mDatabaseDir);
filterSet.add(mSharedPrefsDir);
filterSet.add(mFilesDir);
- processTree(FullBackup.ROOT_TREE_TOKEN, mMainDir, filterSet, data);
+ processTree(packageName, FullBackup.ROOT_TREE_TOKEN, mMainDir, filterSet, data);
// Now do the same for the files dir, db dir, and shared prefs dir
filterSet.add(mMainDir);
filterSet.remove(mFilesDir);
- processTree(FullBackup.DATA_TREE_TOKEN, mFilesDir, filterSet, data);
+ processTree(packageName, FullBackup.DATA_TREE_TOKEN, mFilesDir, filterSet, data);
filterSet.add(mFilesDir);
filterSet.remove(mDatabaseDir);
- processTree(FullBackup.DATABASE_TREE_TOKEN, mDatabaseDir, filterSet, data);
+ processTree(packageName, FullBackup.DATABASE_TREE_TOKEN, mDatabaseDir, filterSet, data);
filterSet.add(mDatabaseDir);
filterSet.remove(mSharedPrefsDir);
- processTree(FullBackup.SHAREDPREFS_TREE_TOKEN, mSharedPrefsDir, filterSet, data);
+ processTree(packageName, FullBackup.SHAREDPREFS_TREE_TOKEN, mSharedPrefsDir, filterSet, data);
}
- private void processTree(String domain, String rootPath,
+ // Scan the dir tree (if it actually exists) and process each entry we find. If the
+ // 'excludes' parameter is non-null, it is consulted each time a new file system entity
+ // is visited to see whether that entity (and its subtree, if appropriate) should be
+ // omitted from the backup process.
+ protected void processTree(String packageName, String domain, String rootPath,
HashSet<String> excludes, BackupDataOutput data) {
- // Scan the dir tree (if it actually exists) and process each entry we find
File rootFile = new File(rootPath);
if (rootFile.exists()) {
LinkedList<File> scanQueue = new LinkedList<File>();
@@ -125,7 +127,7 @@ public class FullBackupAgent extends BackupAgent {
String filePath = file.getAbsolutePath();
// prune this subtree?
- if (excludes.contains(filePath)) {
+ if (excludes != null && excludes.contains(filePath)) {
continue;
}
@@ -149,7 +151,7 @@ public class FullBackupAgent extends BackupAgent {
}
// Finally, back this file up before proceeding
- FullBackup.backupToTar(getPackageName(), domain, null, rootPath, filePath, data);
+ FullBackup.backupToTar(packageName, domain, null, rootPath, filePath, data);
}
}
}
@@ -218,6 +220,6 @@ public class FullBackupAgent extends BackupAgent {
if (DEBUG) Log.i(TAG, "[" + domain + " : " + relpath + "] mapped to " + outFile.getPath());
// Now that we've figured out where the data goes, send it on its way
- FullBackup.restoreToFile(data, size, type, mode, mtime, outFile);
+ FullBackup.restoreToFile(data, size, type, mode, mtime, outFile, true);
}
}
diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java
index 3d637e9e5dd8..2f9627a4403d 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -1160,6 +1160,15 @@ public class Intent implements Parcelable, Cloneable {
public static final String ACTION_UPGRADE_SETUP = "android.intent.action.UPGRADE_SETUP";
/**
+ * Activity Action: Show settings for managing network data usage of a
+ * specific application. Applications should define an activity that offers
+ * options to control data usage.
+ */
+ @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
+ public static final String ACTION_MANAGE_NETWORK_USAGE =
+ "android.intent.action.MANAGE_NETWORK_USAGE";
+
+ /**
* A string associated with a {@link #ACTION_UPGRADE_SETUP} activity
* describing the last run version of the platform that was setup.
* @hide
@@ -1654,8 +1663,9 @@ public class Intent implements Parcelable, Cloneable {
* This is used mainly for the USB Settings panel.
* Apps should listen for ACTION_MEDIA_MOUNTED and ACTION_MEDIA_UNMOUNTED broadcasts to be notified
* when the SD card file system is mounted or unmounted
+ * @deprecated replaced by android.os.storage.StorageEventListener
*/
- @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
+ @Deprecated
public static final String ACTION_UMS_CONNECTED = "android.intent.action.UMS_CONNECTED";
/**
@@ -1663,8 +1673,9 @@ public class Intent implements Parcelable, Cloneable {
* This is used mainly for the USB Settings panel.
* Apps should listen for ACTION_MEDIA_MOUNTED and ACTION_MEDIA_UNMOUNTED broadcasts to be notified
* when the SD card file system is mounted or unmounted
+ * @deprecated replaced by android.os.storage.StorageEventListener
*/
- @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
+ @Deprecated
public static final String ACTION_UMS_DISCONNECTED = "android.intent.action.UMS_DISCONNECTED";
/**
diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java
index 09fede0d616b..31ad6e95dad6 100644
--- a/core/java/android/content/pm/PackageParser.java
+++ b/core/java/android/content/pm/PackageParser.java
@@ -1517,11 +1517,12 @@ public class PackageParser {
}
}
+ // fullBackupAgent is explicitly handled even if allowBackup is false
name = sa.getNonConfigurationString(
com.android.internal.R.styleable.AndroidManifestApplication_fullBackupAgent, 0);
if (name != null) {
ai.fullBackupAgentName = buildClassName(pkgName, name, outError);
- if (true) {
+ if (false) {
Log.v(TAG, "android:fullBackupAgent=" + ai.fullBackupAgentName
+ " from " + pkgName + "+" + name);
}
diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java
index c72c4b0fad5e..21cce44a158a 100644
--- a/core/java/android/net/ConnectivityManager.java
+++ b/core/java/android/net/ConnectivityManager.java
@@ -256,10 +256,61 @@ public class ConnectivityManager {
private final IConnectivityManager mService;
- static public boolean isNetworkTypeValid(int networkType) {
+ public static boolean isNetworkTypeValid(int networkType) {
return networkType >= 0 && networkType <= MAX_NETWORK_TYPE;
}
+ /** {@hide} */
+ public static String getNetworkTypeName(int type) {
+ switch (type) {
+ case TYPE_MOBILE:
+ return "MOBILE";
+ case TYPE_WIFI:
+ return "WIFI";
+ case TYPE_MOBILE_MMS:
+ return "MOBILE_MMS";
+ case TYPE_MOBILE_SUPL:
+ return "MOBILE_SUPL";
+ case TYPE_MOBILE_DUN:
+ return "MOBILE_DUN";
+ case TYPE_MOBILE_HIPRI:
+ return "MOBILE_HIPRI";
+ case TYPE_WIMAX:
+ return "WIMAX";
+ case TYPE_BLUETOOTH:
+ return "BLUETOOTH";
+ case TYPE_DUMMY:
+ return "DUMMY";
+ case TYPE_ETHERNET:
+ return "ETHERNET";
+ case TYPE_MOBILE_FOTA:
+ return "MOBILE_FOTA";
+ case TYPE_MOBILE_IMS:
+ return "MOBILE_IMS";
+ case TYPE_MOBILE_CBS:
+ return "MOBILE_CBS";
+ default:
+ return Integer.toString(type);
+ }
+ }
+
+ /** {@hide} */
+ public static boolean isNetworkTypeMobile(int networkType) {
+ switch (networkType) {
+ case TYPE_MOBILE:
+ case TYPE_MOBILE_MMS:
+ case TYPE_MOBILE_SUPL:
+ case TYPE_MOBILE_DUN:
+ case TYPE_MOBILE_HIPRI:
+ case TYPE_MOBILE_FOTA:
+ case TYPE_MOBILE_IMS:
+ case TYPE_MOBILE_CBS:
+ return true;
+ default:
+ return false;
+ }
+ }
+
public void setNetworkPreference(int preference) {
try {
mService.setNetworkPreference(preference);
diff --git a/core/java/android/net/IConnectivityManager.aidl b/core/java/android/net/IConnectivityManager.aidl
index 647a60a97d73..07f6cecea5d3 100644
--- a/core/java/android/net/IConnectivityManager.aidl
+++ b/core/java/android/net/IConnectivityManager.aidl
@@ -18,6 +18,7 @@ package android.net;
import android.net.LinkProperties;
import android.net.NetworkInfo;
+import android.net.NetworkState;
import android.net.ProxyProperties;
import android.os.IBinder;
@@ -40,6 +41,8 @@ interface IConnectivityManager
LinkProperties getActiveLinkProperties();
LinkProperties getLinkProperties(int networkType);
+ NetworkState[] getAllNetworkState();
+
boolean setRadios(boolean onOff);
boolean setRadio(int networkType, boolean turnOn);
diff --git a/core/java/android/net/INetworkStatsService.aidl b/core/java/android/net/INetworkStatsService.aidl
index 6d57036fbde7..d38d16c4e759 100644
--- a/core/java/android/net/INetworkStatsService.aidl
+++ b/core/java/android/net/INetworkStatsService.aidl
@@ -16,12 +16,18 @@
package android.net;
+import android.net.NetworkStats;
import android.net.NetworkStatsHistory;
/** {@hide} */
interface INetworkStatsService {
- NetworkStatsHistory[] getNetworkStatsSummary(int networkType);
- NetworkStatsHistory getNetworkStatsUid(int uid);
+ /** Return historical stats for traffic that matches template. */
+ NetworkStatsHistory getHistoryForNetwork(int networkTemplate);
+ /** Return historical stats for specific UID traffic that matches template. */
+ NetworkStatsHistory getHistoryForUid(int uid, int networkTemplate);
+
+ /** Return usage summary per UID for traffic that matches template. */
+ NetworkStats getSummaryPerUid(long start, long end, int networkTemplate);
}
diff --git a/core/java/android/net/NetworkState.aidl b/core/java/android/net/NetworkState.aidl
new file mode 100644
index 000000000000..c0b6cdc88e4f
--- /dev/null
+++ b/core/java/android/net/NetworkState.aidl
@@ -0,0 +1,19 @@
+/**
+ * Copyright (c) 2011, 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.net;
+
+parcelable NetworkState;
diff --git a/core/java/android/net/NetworkState.java b/core/java/android/net/NetworkState.java
new file mode 100644
index 000000000000..749039a1afe3
--- /dev/null
+++ b/core/java/android/net/NetworkState.java
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2011 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.net;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+/**
+ * Snapshot of network state.
+ *
+ * @hide
+ */
+public class NetworkState implements Parcelable {
+
+ public final NetworkInfo networkInfo;
+ public final LinkProperties linkProperties;
+ public final LinkCapabilities linkCapabilities;
+
+ public NetworkState(NetworkInfo networkInfo, LinkProperties linkProperties,
+ LinkCapabilities linkCapabilities) {
+ this.networkInfo = networkInfo;
+ this.linkProperties = linkProperties;
+ this.linkCapabilities = linkCapabilities;
+ }
+
+ public NetworkState(Parcel in) {
+ networkInfo = in.readParcelable(null);
+ linkProperties = in.readParcelable(null);
+ linkCapabilities = in.readParcelable(null);
+ }
+
+ /** {@inheritDoc} */
+ public int describeContents() {
+ return 0;
+ }
+
+ /** {@inheritDoc} */
+ public void writeToParcel(Parcel out, int flags) {
+ out.writeParcelable(networkInfo, flags);
+ out.writeParcelable(linkProperties, flags);
+ out.writeParcelable(linkCapabilities, flags);
+ }
+
+ public static final Creator<NetworkState> CREATOR = new Creator<NetworkState>() {
+ public NetworkState createFromParcel(Parcel in) {
+ return new NetworkState(in);
+ }
+
+ public NetworkState[] newArray(int size) {
+ return new NetworkState[size];
+ }
+ };
+
+}
diff --git a/core/java/android/net/NetworkStats.java b/core/java/android/net/NetworkStats.java
index 588bf64b4a3e..ee415fa6bc65 100644
--- a/core/java/android/net/NetworkStats.java
+++ b/core/java/android/net/NetworkStats.java
@@ -19,6 +19,7 @@ package android.net;
import android.os.Parcel;
import android.os.Parcelable;
import android.os.SystemClock;
+import android.util.SparseBooleanArray;
import java.io.CharArrayWriter;
import java.io.PrintWriter;
@@ -125,7 +126,7 @@ public class NetworkStats implements Parcelable {
/**
* Return list of unique interfaces known by this data structure.
*/
- public String[] getKnownIfaces() {
+ public String[] getUniqueIfaces() {
final HashSet<String> ifaces = new HashSet<String>();
for (String iface : this.iface) {
if (iface != IFACE_ALL) {
@@ -136,6 +137,23 @@ public class NetworkStats implements Parcelable {
}
/**
+ * Return list of unique UIDs known by this data structure.
+ */
+ public int[] getUniqueUids() {
+ final SparseBooleanArray uids = new SparseBooleanArray();
+ for (int uid : this.uid) {
+ uids.put(uid, true);
+ }
+
+ final int size = uids.size();
+ final int[] result = new int[size];
+ for (int i = 0; i < size; i++) {
+ result[i] = uids.keyAt(i);
+ }
+ return result;
+ }
+
+ /**
* Subtract the given {@link NetworkStats}, effectively leaving the delta
* between two snapshots in time. Assumes that statistics rows collect over
* time, and that none of them have disappeared.
diff --git a/core/java/android/net/NetworkStatsHistory.java b/core/java/android/net/NetworkStatsHistory.java
index b16101fae6d5..5edbf5830dfe 100644
--- a/core/java/android/net/NetworkStatsHistory.java
+++ b/core/java/android/net/NetworkStatsHistory.java
@@ -24,7 +24,9 @@ import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.PrintWriter;
+import java.net.ProtocolException;
import java.util.Arrays;
+import java.util.Random;
/**
* Collection of historical network statistics, recorded into equally-sized
@@ -38,28 +40,19 @@ import java.util.Arrays;
* @hide
*/
public class NetworkStatsHistory implements Parcelable {
- private static final int VERSION = 1;
-
- /** {@link #uid} value when UID details unavailable. */
- public static final int UID_ALL = -1;
+ private static final int VERSION_CURRENT = 1;
// TODO: teach about zigzag encoding to use less disk space
// TODO: teach how to convert between bucket sizes
- public final int networkType;
- public final String identity;
- public final int uid;
public final long bucketDuration;
- int bucketCount;
- long[] bucketStart;
- long[] rx;
- long[] tx;
+ public int bucketCount;
+ public long[] bucketStart;
+ public long[] rx;
+ public long[] tx;
- public NetworkStatsHistory(int networkType, String identity, int uid, long bucketDuration) {
- this.networkType = networkType;
- this.identity = identity;
- this.uid = uid;
+ public NetworkStatsHistory(long bucketDuration) {
this.bucketDuration = bucketDuration;
bucketStart = new long[0];
rx = new long[0];
@@ -68,9 +61,6 @@ public class NetworkStatsHistory implements Parcelable {
}
public NetworkStatsHistory(Parcel in) {
- networkType = in.readInt();
- identity = in.readString();
- uid = in.readInt();
bucketDuration = in.readLong();
bucketStart = readLongArray(in);
rx = in.createLongArray();
@@ -80,9 +70,6 @@ public class NetworkStatsHistory implements Parcelable {
/** {@inheritDoc} */
public void writeToParcel(Parcel out, int flags) {
- out.writeInt(networkType);
- out.writeString(identity);
- out.writeInt(uid);
out.writeLong(bucketDuration);
writeLongArray(out, bucketStart, bucketCount);
writeLongArray(out, rx, bucketCount);
@@ -91,21 +78,23 @@ public class NetworkStatsHistory implements Parcelable {
public NetworkStatsHistory(DataInputStream in) throws IOException {
final int version = in.readInt();
- networkType = in.readInt();
- identity = in.readUTF();
- uid = in.readInt();
- bucketDuration = in.readLong();
- bucketStart = readLongArray(in);
- rx = readLongArray(in);
- tx = readLongArray(in);
- bucketCount = bucketStart.length;
+ switch (version) {
+ case VERSION_CURRENT: {
+ bucketDuration = in.readLong();
+ bucketStart = readLongArray(in);
+ rx = readLongArray(in);
+ tx = readLongArray(in);
+ bucketCount = bucketStart.length;
+ break;
+ }
+ default: {
+ throw new ProtocolException("unexpected version: " + version);
+ }
+ }
}
public void writeToStream(DataOutputStream out) throws IOException {
- out.writeInt(VERSION);
- out.writeInt(networkType);
- out.writeUTF(identity);
- out.writeInt(uid);
+ out.writeInt(VERSION_CURRENT);
out.writeLong(bucketDuration);
writeLongArray(out, bucketStart, bucketCount);
writeLongArray(out, rx, bucketCount);
@@ -145,6 +134,18 @@ public class NetworkStatsHistory implements Parcelable {
}
/**
+ * Record an entire {@link NetworkStatsHistory} into this history. Usually
+ * for combining together stats for external reporting.
+ */
+ public void recordEntireHistory(NetworkStatsHistory input) {
+ for (int i = 0; i < input.bucketCount; i++) {
+ final long start = input.bucketStart[i];
+ final long end = start + input.bucketDuration;
+ recordData(start, end, input.rx[i], input.tx[i]);
+ }
+ }
+
+ /**
* Ensure that buckets exist for given time range, creating as needed.
*/
private void ensureBuckets(long start, long end) {
@@ -213,15 +214,65 @@ public class NetworkStatsHistory implements Parcelable {
}
}
+ /**
+ * Return interpolated data usage across the requested range. Interpolates
+ * across buckets, so values may be rounded slightly.
+ */
+ public void getTotalData(long start, long end, long[] outTotal) {
+ long rx = 0;
+ long tx = 0;
+
+ for (int i = bucketCount - 1; i >= 0; i--) {
+ final long curStart = bucketStart[i];
+ final long curEnd = curStart + bucketDuration;
+
+ // bucket is older than record; we're finished
+ if (curEnd < start) break;
+ // bucket is newer than record; keep looking
+ if (curStart > end) continue;
+
+ final long overlap = Math.min(curEnd, end) - Math.max(curStart, start);
+ if (overlap > 0) {
+ rx += this.rx[i] * overlap / bucketDuration;
+ tx += this.tx[i] * overlap / bucketDuration;
+ }
+ }
+
+ outTotal[0] = rx;
+ outTotal[1] = tx;
+ }
+
+ /**
+ * @deprecated only for temporary testing
+ */
+ @Deprecated
+ public void generateRandom(long start, long end, long rx, long tx) {
+ ensureBuckets(start, end);
+
+ final Random r = new Random();
+ while (rx > 1024 && tx > 1024) {
+ final long curStart = randomLong(r, start, end);
+ final long curEnd = randomLong(r, curStart, end);
+ final long curRx = randomLong(r, 0, rx);
+ final long curTx = randomLong(r, 0, tx);
+
+ recordData(curStart, curEnd, curRx, curTx);
+
+ rx -= curRx;
+ tx -= curTx;
+ }
+ }
+
+ private static long randomLong(Random r, long start, long end) {
+ return (long) (start + (r.nextFloat() * (end - start)));
+ }
+
public void dump(String prefix, PrintWriter pw) {
- // TODO: consider stripping identity when dumping
pw.print(prefix);
- pw.print("NetworkStatsHistory: networkType="); pw.print(networkType);
- pw.print(" identity="); pw.print(identity);
- pw.print(" uid="); pw.println(uid);
+ pw.print("NetworkStatsHistory: bucketDuration="); pw.println(bucketDuration);
for (int i = 0; i < bucketCount; i++) {
pw.print(prefix);
- pw.print(" timestamp="); pw.print(bucketStart[i]);
+ pw.print(" bucketStart="); pw.print(bucketStart[i]);
pw.print(" rx="); pw.print(rx[i]);
pw.print(" tx="); pw.println(tx[i]);
}
diff --git a/core/java/android/net/TrafficStats.java b/core/java/android/net/TrafficStats.java
index 8ab64fabd245..a0738c1da2d6 100644
--- a/core/java/android/net/TrafficStats.java
+++ b/core/java/android/net/TrafficStats.java
@@ -41,6 +41,42 @@ public class TrafficStats {
*/
public final static int UNSUPPORTED = -1;
+ // TODO: find better home for these template constants
+
+ /**
+ * Template to combine all {@link ConnectivityManager#TYPE_MOBILE} style
+ * networks together. Only uses statistics for currently active IMSI.
+ *
+ * @hide
+ */
+ public static final int TEMPLATE_MOBILE_ALL = 1;
+
+ /**
+ * Template to combine all {@link ConnectivityManager#TYPE_MOBILE} style
+ * networks together that roughly meet a "3G" definition, or lower. Only
+ * uses statistics for currently active IMSI.
+ *
+ * @hide
+ */
+ public static final int TEMPLATE_MOBILE_3G_LOWER = 2;
+
+ /**
+ * Template to combine all {@link ConnectivityManager#TYPE_MOBILE} style
+ * networks together that meet a "4G" definition. Only uses statistics for
+ * currently active IMSI.
+ *
+ * @hide
+ */
+ public static final int TEMPLATE_MOBILE_4G = 3;
+
+ /**
+ * Template to combine all {@link ConnectivityManager#TYPE_WIFI} style
+ * networks together.
+ *
+ * @hide
+ */
+ public static final int TEMPLATE_WIFI = 4;
+
/**
* Snapshot of {@link NetworkStats} when the currently active profiling
* session started, or {@code null} if no session active.
diff --git a/core/java/android/os/storage/StorageVolume.java b/core/java/android/os/storage/StorageVolume.java
index bc4208a045f3..792e4c1f5003 100644
--- a/core/java/android/os/storage/StorageVolume.java
+++ b/core/java/android/os/storage/StorageVolume.java
@@ -32,6 +32,7 @@ public class StorageVolume implements Parcelable {
private final boolean mRemovable;
private final boolean mEmulated;
private final int mMtpReserveSpace;
+ private final boolean mAllowMassStorage;
private int mStorageId;
// StorageVolume extra for ACTION_MEDIA_REMOVED, ACTION_MEDIA_UNMOUNTED, ACTION_MEDIA_CHECKING,
@@ -39,23 +40,25 @@ public class StorageVolume implements Parcelable {
// ACTION_MEDIA_BAD_REMOVAL, ACTION_MEDIA_UNMOUNTABLE and ACTION_MEDIA_EJECT broadcasts.
public static final String EXTRA_STORAGE_VOLUME = "storage_volume";
- public StorageVolume(String path, String description,
- boolean removable, boolean emulated, int mtpReserveSpace) {
+ public StorageVolume(String path, String description, boolean removable,
+ boolean emulated, int mtpReserveSpace, boolean allowMassStorage) {
mPath = path;
mDescription = description;
mRemovable = removable;
mEmulated = emulated;
mMtpReserveSpace = mtpReserveSpace;
+ mAllowMassStorage = allowMassStorage;
}
// for parcelling only
- private StorageVolume(String path, String description,
- boolean removable, boolean emulated, int mtpReserveSpace, int storageId) {
+ private StorageVolume(String path, String description, boolean removable,
+ boolean emulated, int mtpReserveSpace, int storageId, boolean allowMassStorage) {
mPath = path;
mDescription = description;
mRemovable = removable;
mEmulated = emulated;
mMtpReserveSpace = mtpReserveSpace;
+ mAllowMassStorage = allowMassStorage;
mStorageId = storageId;
}
@@ -130,6 +133,15 @@ public class StorageVolume implements Parcelable {
return mMtpReserveSpace;
}
+ /**
+ * Returns true if this volume can be shared via USB mass storage.
+ *
+ * @return whether mass storage is allowed
+ */
+ public boolean allowMassStorage() {
+ return mAllowMassStorage;
+ }
+
@Override
public boolean equals(Object obj) {
if (obj instanceof StorageVolume && mPath != null) {
@@ -158,9 +170,10 @@ public class StorageVolume implements Parcelable {
int emulated = in.readInt();
int storageId = in.readInt();
int mtpReserveSpace = in.readInt();
+ int allowMassStorage = in.readInt();
return new StorageVolume(path, description,
removable == 1, emulated == 1,
- mtpReserveSpace, storageId);
+ mtpReserveSpace, storageId, allowMassStorage == 1);
}
public StorageVolume[] newArray(int size) {
@@ -179,5 +192,6 @@ public class StorageVolume implements Parcelable {
parcel.writeInt(mEmulated ? 1 : 0);
parcel.writeInt(mStorageId);
parcel.writeInt(mMtpReserveSpace);
+ parcel.writeInt(mAllowMassStorage ? 1 : 0);
}
}
diff --git a/core/java/android/provider/Calendar.java b/core/java/android/provider/Calendar.java
index 2df2688b15bf..a06d0f6af732 100644
--- a/core/java/android/provider/Calendar.java
+++ b/core/java/android/provider/Calendar.java
@@ -183,6 +183,15 @@ public final class Calendar {
*/
public static final String DIRTY = "dirty";
+ /**
+ * If set to 1 this causes events on this calendar to be duplicated with
+ * {@link EventsColumns#LAST_SYNCED} set to 1 whenever the event transitions from non-dirty
+ * to dirty. The duplicated event will not be expanded in the instances table and will only
+ * show up in sync adapter queries of the events table. It will also be deleted when the
+ * originating event has its dirty flag cleared by the sync adapter.
+ * <P>Type: INTEGER (boolean)</P>
+ */
+ public static final String CAN_PARTIALLY_UPDATE = "canPartiallyUpdate";
}
/**
@@ -317,7 +326,8 @@ public final class Calendar {
DatabaseUtils.cursorStringToContentValuesIfPresent(cursor, cv, Calendars.NAME);
DatabaseUtils.cursorStringToContentValuesIfPresent(cursor, cv,
Calendars.DISPLAY_NAME);
- DatabaseUtils.cursorIntToContentValuesIfPresent(cursor, cv, Calendars.CALENDAR_COLOR);
+ DatabaseUtils.cursorIntToContentValuesIfPresent(cursor, cv,
+ Calendars.CALENDAR_COLOR);
DatabaseUtils.cursorIntToContentValuesIfPresent(cursor, cv, ACCESS_LEVEL);
DatabaseUtils.cursorIntToContentValuesIfPresent(cursor, cv, VISIBLE);
DatabaseUtils.cursorIntToContentValuesIfPresent(cursor, cv, SYNC_EVENTS);
@@ -332,6 +342,8 @@ public final class Calendar {
Calendars.CAN_MODIFY_TIME_ZONE);
DatabaseUtils.cursorIntToContentValuesIfPresent(cursor, cv,
Calendars.MAX_REMINDERS);
+ DatabaseUtils.cursorIntToContentValuesIfPresent(cursor, cv,
+ Calendars.CAN_PARTIALLY_UPDATE);
DatabaseUtils.cursorIntToContentValuesIfPresent(cursor, cv, DELETED);
@@ -512,6 +524,7 @@ public final class Calendar {
MAX_REMINDERS,
CAN_MODIFY_TIME_ZONE,
CAN_ORGANIZER_RESPOND,
+ CAN_PARTIALLY_UPDATE,
CALENDAR_LOCATION,
CALENDAR_TIMEZONE,
ACCESS_LEVEL,
@@ -686,6 +699,23 @@ public final class Calendar {
public static final String SYNC_DATA1 = "sync_data1";
/**
+ * This column is available for use by sync adapters
+ * <P>Type: TEXT</P>
+ */
+ public static final String SYNC_DATA7 = "sync_data7";
+
+ /**
+ * Used to indicate that a row is not a real event but an original copy of a locally
+ * modified event. A copy is made when an event changes from non-dirty to dirty and the
+ * event is on a calendar with {@link Calendars#CAN_PARTIALLY_UPDATE} set to 1. This copy
+ * does not get expanded in the instances table and is only visible in queries made by a
+ * sync adapter. The copy gets removed when the event is changed back to non-dirty by a
+ * sync adapter.
+ * <P>Type: INTEGER (boolean)</P>
+ */
+ public static final String LAST_SYNCED = "lastSynced";
+
+ /**
* The comments feed uri. Column name.
* TODO change to sync_data6
* <P>Type: TEXT</P>
@@ -1030,7 +1060,9 @@ public final class Calendar {
DatabaseUtils.cursorStringToContentValuesIfPresent(cursor, cv, ORGANIZER);
DatabaseUtils.cursorStringToContentValuesIfPresent(cursor, cv, _SYNC_ID);
DatabaseUtils.cursorStringToContentValuesIfPresent(cursor, cv, _SYNC_DATA);
+ DatabaseUtils.cursorLongToContentValuesIfPresent(cursor, cv, SYNC_DATA7);
DatabaseUtils.cursorLongToContentValuesIfPresent(cursor, cv, DIRTY);
+ DatabaseUtils.cursorLongToContentValuesIfPresent(cursor, cv, LAST_SYNCED);
DatabaseUtils.cursorStringToContentValuesIfPresent(cursor, cv, _SYNC_VERSION);
DatabaseUtils.cursorIntToContentValuesIfPresent(cursor, cv, DELETED);
DatabaseUtils.cursorStringToContentValuesIfPresent(cursor, cv, CAL_SYNC1);
@@ -1191,7 +1223,8 @@ public final class Calendar {
CAL_SYNC3,
CAL_SYNC4,
CAL_SYNC5,
- CAL_SYNC6
+ CAL_SYNC6,
+ CAN_PARTIALLY_UPDATE,
};
/**
@@ -1706,9 +1739,9 @@ public final class Calendar {
public static final String NOTIFY_TIME = "notifyTime";
/**
- * The state of this alert. It starts out as {@link SCHEDULED}, then
- * when the alarm goes off, it changes to {@link FIRED}, and then when
- * the user dismisses the alarm it changes to {@link DISMISSED}. Column
+ * The state of this alert. It starts out as {@link #SCHEDULED}, then
+ * when the alarm goes off, it changes to {@link #FIRED}, and then when
+ * the user dismisses the alarm it changes to {@link #DISMISSED}. Column
* name.
* <P>Type: INTEGER</P>
*/
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 893947d4ad07..6ab7738896cc 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -2924,6 +2924,30 @@ public final class Settings {
public static final String WIFI_WATCHDOG_PING_TIMEOUT_MS = "wifi_watchdog_ping_timeout_ms";
/**
+ * Setting to turn off walled garden test on Wi-Fi. Feature is enabled by default and
+ * the setting needs to be set to 0 to disable it.
+ * @hide
+ */
+ public static final String WIFI_WATCHDOG_WALLED_GARDEN_TEST_ENABLED =
+ "wifi_watchdog_walled_garden_test_enabled";
+
+ /**
+ * The URL used for walled garden check upon a new conection. WifiWatchdogService
+ * fetches the URL and checks to see if {@link #WIFI_WATCHDOG_WALLED_GARDEN_PATTERN}
+ * is not part of the title string to notify the user on the presence of a walled garden.
+ * @hide
+ */
+ public static final String WIFI_WATCHDOG_WALLED_GARDEN_URL =
+ "wifi_watchdog_walled_garden_url";
+
+ /**
+ * The pattern string in the fetched URL used to detect a walled garden
+ * @hide
+ */
+ public static final String WIFI_WATCHDOG_WALLED_GARDEN_PATTERN =
+ "wifi_watchdog_walled_garden_pattern";
+
+ /**
* The maximum number of times we will retry a connection to an access
* point for which we have failed in acquiring an IP address from DHCP.
* A value of N means that we will make N+1 connection attempts in all.
@@ -3771,6 +3795,19 @@ public final class Settings {
public static final String DREAM_TIMEOUT =
"dream_timeout";
+ /** {@hide} */
+ public static final String NETSTATS_POLL_INTERVAL = "netstats_poll_interval";
+ /** {@hide} */
+ public static final String NETSTATS_PERSIST_THRESHOLD = "netstats_persist_threshold";
+ /** {@hide} */
+ public static final String NETSTATS_SUMMARY_BUCKET_DURATION = "netstats_summary_bucket_duration";
+ /** {@hide} */
+ public static final String NETSTATS_SUMMARY_MAX_HISTORY = "netstats_summary_max_history";
+ /** {@hide} */
+ public static final String NETSTATS_DETAIL_BUCKET_DURATION = "netstats_detail_bucket_duration";
+ /** {@hide} */
+ public static final String NETSTATS_DETAIL_MAX_HISTORY = "netstats_detail_max_history";
+
/**
* @hide
*/
diff --git a/core/java/android/speech/tts/AudioMessageParams.java b/core/java/android/speech/tts/AudioMessageParams.java
new file mode 100644
index 000000000000..db4d6226df15
--- /dev/null
+++ b/core/java/android/speech/tts/AudioMessageParams.java
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2011 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.speech.tts;
+
+import android.speech.tts.TextToSpeechService.UtteranceCompletedDispatcher;
+
+class AudioMessageParams extends MessageParams {
+ private final BlockingMediaPlayer mPlayer;
+
+ AudioMessageParams(UtteranceCompletedDispatcher dispatcher, BlockingMediaPlayer player) {
+ super(dispatcher);
+ mPlayer = player;
+ }
+
+ BlockingMediaPlayer getPlayer() {
+ return mPlayer;
+ }
+
+ @Override
+ int getType() {
+ return TYPE_AUDIO;
+ }
+
+}
diff --git a/core/java/android/speech/tts/AudioPlaybackHandler.java b/core/java/android/speech/tts/AudioPlaybackHandler.java
new file mode 100644
index 000000000000..924bbbc05325
--- /dev/null
+++ b/core/java/android/speech/tts/AudioPlaybackHandler.java
@@ -0,0 +1,358 @@
+/*
+ * Copyright (C) 2011 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.speech.tts;
+
+import android.media.AudioFormat;
+import android.media.AudioTrack;
+import android.os.Handler;
+import android.os.Looper;
+import android.os.Message;
+import android.speech.tts.SynthesisMessageParams.ListEntry;
+import android.util.Log;
+
+class AudioPlaybackHandler extends Handler {
+ private static final String TAG = "TTS.AudioPlaybackHandler";
+ private static final boolean DBG = false;
+
+ private static final int MIN_AUDIO_BUFFER_SIZE = 8192;
+
+ private static final int SYNTHESIS_START = 1;
+ private static final int SYNTHESIS_DATA_AVAILABLE = 2;
+ private static final int SYNTHESIS_COMPLETE_DATA_AVAILABLE = 3;
+ private static final int SYNTHESIS_DONE = 4;
+
+ private static final int PLAY_AUDIO = 5;
+ private static final int PLAY_SILENCE = 6;
+
+ // Accessed by multiple threads, synchronized by "this".
+ private MessageParams mCurrentParams;
+ // Used only for book keeping and error detection.
+ private SynthesisMessageParams mLastSynthesisRequest;
+
+ AudioPlaybackHandler(Looper looper) {
+ super(looper);
+ }
+
+ @Override
+ public synchronized void handleMessage(Message msg) {
+ if (msg.what == SYNTHESIS_START) {
+ mCurrentParams = (SynthesisMessageParams) msg.obj;
+ handleSynthesisStart(msg);
+ } else if (msg.what == SYNTHESIS_DATA_AVAILABLE) {
+ handleSynthesisDataAvailable(msg);
+ } else if (msg.what == SYNTHESIS_DONE) {
+ handleSynthesisDone(msg);
+ } else if (msg.what == SYNTHESIS_COMPLETE_DATA_AVAILABLE) {
+ handleSynthesisCompleteDataAvailable(msg);
+ } else if (msg.what == PLAY_AUDIO) {
+ handleAudio(msg);
+ } else if (msg.what == PLAY_SILENCE) {
+ handleSilence(msg);
+ }
+
+ mCurrentParams = null;
+ }
+
+ /**
+ * Stops all synthesis for a given {@code token}. If the current token
+ * is currently being processed, an effort will be made to stop it but
+ * that is not guaranteed.
+ */
+ synchronized public void stop(MessageParams token) {
+ removeCallbacksAndMessages(token);
+
+ if (token.getType() == MessageParams.TYPE_SYNTHESIS) {
+ sendMessageAtFrontOfQueue(obtainMessage(SYNTHESIS_DONE, token));
+ } else if (token == mCurrentParams) {
+ if (token.getType() == MessageParams.TYPE_AUDIO) {
+ ((AudioMessageParams) mCurrentParams).getPlayer().stop();
+ } else if (token.getType() == MessageParams.TYPE_SILENCE) {
+ ((SilenceMessageParams) mCurrentParams).getConditionVariable().open();
+ }
+ }
+ }
+
+ /**
+ * Shut down the audio playback thread.
+ */
+ synchronized public void quit() {
+ if (mCurrentParams != null) {
+ stop(mCurrentParams);
+ }
+ getLooper().quit();
+ }
+
+ void enqueueSynthesisStart(SynthesisMessageParams token) {
+ sendMessage(obtainMessage(SYNTHESIS_START, token));
+ }
+
+ void enqueueSynthesisDataAvailable(SynthesisMessageParams token) {
+ sendMessage(obtainMessage(SYNTHESIS_DATA_AVAILABLE, token));
+ }
+
+ void enqueueSynthesisCompleteDataAvailable(SynthesisMessageParams token) {
+ sendMessage(obtainMessage(SYNTHESIS_COMPLETE_DATA_AVAILABLE, token));
+ }
+
+ void enqueueSynthesisDone(SynthesisMessageParams token) {
+ sendMessage(obtainMessage(SYNTHESIS_DONE, token));
+ }
+
+ void enqueueAudio(AudioMessageParams token) {
+ sendMessage(obtainMessage(PLAY_AUDIO, token));
+ }
+
+ void enqueueSilence(SilenceMessageParams token) {
+ sendMessage(obtainMessage(PLAY_SILENCE, token));
+ }
+
+ // -----------------------------------------
+ // End of public API methods.
+ // -----------------------------------------
+
+ // Currently implemented as blocking the audio playback thread for the
+ // specified duration. If a call to stop() is made, the thread
+ // unblocks.
+ private void handleSilence(Message msg) {
+ if (DBG) Log.d(TAG, "handleSilence()");
+ SilenceMessageParams params = (SilenceMessageParams) msg.obj;
+ if (params.getSilenceDurationMs() > 0) {
+ params.getConditionVariable().block(params.getSilenceDurationMs());
+ }
+ params.getDispatcher().dispatchUtteranceCompleted();
+ if (DBG) Log.d(TAG, "handleSilence() done.");
+ }
+
+ // Plays back audio from a given URI. No TTS engine involvement here.
+ private void handleAudio(Message msg) {
+ if (DBG) Log.d(TAG, "handleAudio()");
+ AudioMessageParams params = (AudioMessageParams) msg.obj;
+ // Note that the BlockingMediaPlayer spawns a separate thread.
+ //
+ // TODO: This can be avoided.
+ params.getPlayer().startAndWait();
+ params.getDispatcher().dispatchUtteranceCompleted();
+ if (DBG) Log.d(TAG, "handleAudio() done.");
+ }
+
+ // Denotes the start of a new synthesis request. We create a new
+ // audio track, and prepare it for incoming data.
+ //
+ // Note that since all TTS synthesis happens on a single thread, we
+ // should ALWAYS see the following order :
+ //
+ // handleSynthesisStart -> handleSynthesisDataAvailable(*) -> handleSynthesisDone
+ // OR
+ // handleSynthesisCompleteDataAvailable.
+ private void handleSynthesisStart(Message msg) {
+ if (DBG) Log.d(TAG, "handleSynthesisStart()");
+ final SynthesisMessageParams param = (SynthesisMessageParams) msg.obj;
+
+ // Oops, looks like the engine forgot to call done(). We go through
+ // extra trouble to clean the data to prevent the AudioTrack resources
+ // from being leaked.
+ if (mLastSynthesisRequest != null) {
+ Log.w(TAG, "Error : Missing call to done() for request : " +
+ mLastSynthesisRequest);
+ handleSynthesisDone(mLastSynthesisRequest);
+ }
+
+ mLastSynthesisRequest = param;
+
+ // Create the audio track.
+ final AudioTrack audioTrack = createStreamingAudioTrack(
+ param.mStreamType, param.mSampleRateInHz, param.mAudioFormat,
+ param.mChannelCount, param.mVolume, param.mPan);
+
+ param.setAudioTrack(audioTrack);
+ }
+
+ // More data available to be flushed to the audio track.
+ private void handleSynthesisDataAvailable(Message msg) {
+ final SynthesisMessageParams param = (SynthesisMessageParams) msg.obj;
+ if (param.getAudioTrack() == null) {
+ Log.w(TAG, "Error : null audio track in handleDataAvailable.");
+ return;
+ }
+
+ if (param != mLastSynthesisRequest) {
+ Log.e(TAG, "Call to dataAvailable without done() / start()");
+ return;
+ }
+
+ final AudioTrack audioTrack = param.getAudioTrack();
+ final ListEntry bufferCopy = param.getNextBuffer();
+
+ if (bufferCopy == null) {
+ Log.e(TAG, "No buffers available to play.");
+ return;
+ }
+
+ int playState = audioTrack.getPlayState();
+ if (playState == AudioTrack.PLAYSTATE_STOPPED) {
+ if (DBG) Log.d(TAG, "AudioTrack stopped, restarting : " + audioTrack.hashCode());
+ audioTrack.play();
+ }
+ int count = 0;
+ while (count < bufferCopy.mLength) {
+ // Note that we don't take bufferCopy.mOffset into account because
+ // it is guaranteed to be 0.
+ int written = audioTrack.write(bufferCopy.mBytes, count, bufferCopy.mLength);
+ if (written <= 0) {
+ break;
+ }
+ count += written;
+ }
+ }
+
+ private void handleSynthesisDone(Message msg) {
+ final SynthesisMessageParams params = (SynthesisMessageParams) msg.obj;
+ handleSynthesisDone(params);
+ }
+
+ // Flush all remaining data to the audio track, stop it and release
+ // all it's resources.
+ private void handleSynthesisDone(SynthesisMessageParams params) {
+ if (DBG) Log.d(TAG, "handleSynthesisDone()");
+ final AudioTrack audioTrack = params.getAudioTrack();
+
+ try {
+ if (audioTrack != null) {
+ audioTrack.flush();
+ audioTrack.stop();
+ audioTrack.release();
+ }
+ } finally {
+ params.setAudioTrack(null);
+ params.getDispatcher().dispatchUtteranceCompleted();
+ mLastSynthesisRequest = null;
+ }
+ }
+
+ private void handleSynthesisCompleteDataAvailable(Message msg) {
+ final SynthesisMessageParams params = (SynthesisMessageParams) msg.obj;
+ if (DBG) Log.d(TAG, "completeAudioAvailable(" + params + ")");
+
+ // Channel config and bytes per frame are checked before
+ // this message is sent.
+ int channelConfig = AudioPlaybackHandler.getChannelConfig(params.mChannelCount);
+ int bytesPerFrame = AudioPlaybackHandler.getBytesPerFrame(params.mAudioFormat);
+
+ ListEntry entry = params.getNextBuffer();
+
+ if (entry == null) {
+ Log.w(TAG, "completeDataAvailable : No buffers available to play.");
+ return;
+ }
+
+ final AudioTrack audioTrack = new AudioTrack(params.mStreamType, params.mSampleRateInHz,
+ channelConfig, params.mAudioFormat, entry.mLength, AudioTrack.MODE_STATIC);
+
+ // So that handleDone can access this correctly.
+ params.mAudioTrack = audioTrack;
+
+ try {
+ audioTrack.write(entry.mBytes, entry.mOffset, entry.mLength);
+ setupVolume(audioTrack, params.mVolume, params.mPan);
+ audioTrack.play();
+ blockUntilDone(audioTrack, bytesPerFrame, entry.mLength);
+ if (DBG) Log.d(TAG, "Wrote data to audio track successfully : " + entry.mLength);
+ } catch (IllegalStateException ex) {
+ Log.e(TAG, "Playback error", ex);
+ } finally {
+ handleSynthesisDone(msg);
+ }
+ }
+
+
+ private static void blockUntilDone(AudioTrack audioTrack, int bytesPerFrame, int length) {
+ int lengthInFrames = length / bytesPerFrame;
+ int currentPosition = 0;
+ while ((currentPosition = audioTrack.getPlaybackHeadPosition()) < lengthInFrames) {
+ long estimatedTimeMs = ((lengthInFrames - currentPosition) * 1000) /
+ audioTrack.getSampleRate();
+ audioTrack.getPlayState();
+ if (DBG) Log.d(TAG, "About to sleep for : " + estimatedTimeMs + " ms," +
+ " Playback position : " + currentPosition);
+ try {
+ Thread.sleep(estimatedTimeMs);
+ } catch (InterruptedException ie) {
+ break;
+ }
+ }
+ }
+
+ private static AudioTrack createStreamingAudioTrack(int streamType, int sampleRateInHz,
+ int audioFormat, int channelCount, float volume, float pan) {
+ int channelConfig = getChannelConfig(channelCount);
+
+ int minBufferSizeInBytes
+ = AudioTrack.getMinBufferSize(sampleRateInHz, channelConfig, audioFormat);
+ int bufferSizeInBytes = Math.max(MIN_AUDIO_BUFFER_SIZE, minBufferSizeInBytes);
+
+ AudioTrack audioTrack = new AudioTrack(streamType, sampleRateInHz, channelConfig,
+ audioFormat, bufferSizeInBytes, AudioTrack.MODE_STREAM);
+ if (audioTrack.getState() != AudioTrack.STATE_INITIALIZED) {
+ Log.w(TAG, "Unable to create audio track.");
+ audioTrack.release();
+ return null;
+ }
+
+ setupVolume(audioTrack, volume, pan);
+ return audioTrack;
+ }
+
+ static int getChannelConfig(int channelCount) {
+ if (channelCount == 1) {
+ return AudioFormat.CHANNEL_OUT_MONO;
+ } else if (channelCount == 2){
+ return AudioFormat.CHANNEL_OUT_STEREO;
+ }
+
+ return 0;
+ }
+
+ static int getBytesPerFrame(int audioFormat) {
+ if (audioFormat == AudioFormat.ENCODING_PCM_8BIT) {
+ return 1;
+ } else if (audioFormat == AudioFormat.ENCODING_PCM_16BIT) {
+ return 2;
+ }
+
+ return -1;
+ }
+
+ private static void setupVolume(AudioTrack audioTrack, float volume, float pan) {
+ float vol = clip(volume, 0.0f, 1.0f);
+ float panning = clip(pan, -1.0f, 1.0f);
+ float volLeft = vol;
+ float volRight = vol;
+ if (panning > 0.0f) {
+ volLeft *= (1.0f - panning);
+ } else if (panning < 0.0f) {
+ volRight *= (1.0f + panning);
+ }
+ if (DBG) Log.d(TAG, "volLeft=" + volLeft + ",volRight=" + volRight);
+ if (audioTrack.setStereoVolume(volLeft, volRight) != AudioTrack.SUCCESS) {
+ Log.e(TAG, "Failed to set volume");
+ }
+ }
+
+ private static float clip(float value, float min, float max) {
+ return value > max ? max : (value < min ? min : value);
+ }
+
+}
diff --git a/core/java/android/speech/tts/MessageParams.java b/core/java/android/speech/tts/MessageParams.java
new file mode 100644
index 000000000000..2d96df43b957
--- /dev/null
+++ b/core/java/android/speech/tts/MessageParams.java
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2011 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.speech.tts;
+
+import android.speech.tts.TextToSpeechService.UtteranceCompletedDispatcher;
+
+abstract class MessageParams {
+ private final UtteranceCompletedDispatcher mDispatcher;
+
+ static final int TYPE_SYNTHESIS = 1;
+ static final int TYPE_AUDIO = 2;
+ static final int TYPE_SILENCE = 3;
+
+ MessageParams(UtteranceCompletedDispatcher dispatcher) {
+ mDispatcher = dispatcher;
+ }
+
+ UtteranceCompletedDispatcher getDispatcher() {
+ return mDispatcher;
+ }
+
+ abstract int getType();
+}
diff --git a/core/java/android/speech/tts/PlaybackSynthesisRequest.java b/core/java/android/speech/tts/PlaybackSynthesisRequest.java
index d698b5428002..34b263cb74ef 100644
--- a/core/java/android/speech/tts/PlaybackSynthesisRequest.java
+++ b/core/java/android/speech/tts/PlaybackSynthesisRequest.java
@@ -15,10 +15,8 @@
*/
package android.speech.tts;
-import android.media.AudioFormat;
-import android.media.AudioTrack;
import android.os.Bundle;
-import android.os.Handler;
+import android.speech.tts.TextToSpeechService.UtteranceCompletedDispatcher;
import android.util.Log;
/**
@@ -49,54 +47,48 @@ class PlaybackSynthesisRequest extends SynthesisRequest {
*/
private final float mPan;
+ /**
+ * Guards {@link #mAudioTrackHandler}, {@link #mToken} and {@link #mStopped}.
+ */
private final Object mStateLock = new Object();
- private final Handler mAudioTrackHandler;
- private volatile AudioTrack mAudioTrack = null;
+
+ // Handler associated with a thread that plays back audio requests.
+ private final AudioPlaybackHandler mAudioTrackHandler;
+ // A request "token", which will be non null after start() or
+ // completeAudioAvailable() have been called.
+ private SynthesisMessageParams mToken = null;
+ // Whether this request has been stopped. This is useful for keeping
+ // track whether stop() has been called before start(). In all other cases,
+ // a non-null value of mToken will provide the same information.
private boolean mStopped = false;
- private boolean mDone = false;
- private volatile boolean mWriteErrorOccured;
- PlaybackSynthesisRequest(String text, Bundle params,
- int streamType, float volume, float pan, Handler audioTrackHandler) {
+ private volatile boolean mDone = false;
+
+ private final UtteranceCompletedDispatcher mDispatcher;
+
+ PlaybackSynthesisRequest(String text, Bundle params, int streamType, float volume, float pan,
+ AudioPlaybackHandler audioTrackHandler, UtteranceCompletedDispatcher dispatcher) {
super(text, params);
mStreamType = streamType;
mVolume = volume;
mPan = pan;
mAudioTrackHandler = audioTrackHandler;
- mWriteErrorOccured = false;
+ mDispatcher = dispatcher;
}
@Override
void stop() {
if (DBG) Log.d(TAG, "stop()");
+
synchronized (mStateLock) {
+ if (mToken == null || mStopped) {
+ Log.w(TAG, "stop() called twice, before start(), or after done()");
+ return;
+ }
+ mAudioTrackHandler.stop(mToken);
+ mToken = null;
mStopped = true;
- cleanUp();
- }
- }
-
- // Always guarded by mStateLock.
- private void cleanUp() {
- if (DBG) Log.d(TAG, "cleanUp()");
- if (mAudioTrack == null) {
- return;
}
-
- final AudioTrack audioTrack = mAudioTrack;
- mAudioTrack = null;
-
- // Clean up on the audiotrack handler thread.
- //
- // NOTE: It isn't very clear whether AudioTrack is thread safe.
- // If it is we can clean up on the current (synthesis) thread.
- mAudioTrackHandler.post(new Runnable() {
- @Override
- public void run() {
- audioTrack.flush();
- audioTrack.stop();
- audioTrack.release();
- }
- });
}
@Override
@@ -111,7 +103,6 @@ class PlaybackSynthesisRequest extends SynthesisRequest {
return mDone;
}
- // TODO: add a thread that writes to the AudioTrack?
@Override
public int start(int sampleRateInHz, int audioFormat, int channelCount) {
if (DBG) {
@@ -119,45 +110,28 @@ class PlaybackSynthesisRequest extends SynthesisRequest {
+ "," + channelCount + ")");
}
+ int channelConfig = AudioPlaybackHandler.getChannelConfig(channelCount);
+ if (channelConfig == 0) {
+ Log.e(TAG, "Unsupported number of channels :" + channelCount);
+ return TextToSpeech.ERROR;
+ }
+
synchronized (mStateLock) {
if (mStopped) {
- if (DBG) Log.d(TAG, "Request has been aborted.");
- return TextToSpeech.ERROR;
- }
- if (mAudioTrack != null) {
- Log.e(TAG, "start() called twice");
- cleanUp();
+ if (DBG) Log.d(TAG, "stop() called before start(), returning.");
return TextToSpeech.ERROR;
}
+ SynthesisMessageParams params = new SynthesisMessageParams(
+ mStreamType, sampleRateInHz, audioFormat, channelCount, mVolume, mPan,
+ mDispatcher);
+ mAudioTrackHandler.enqueueSynthesisStart(params);
- mAudioTrack = createStreamingAudioTrack(sampleRateInHz, audioFormat, channelCount);
- if (mAudioTrack == null) {
- return TextToSpeech.ERROR;
- }
+ mToken = params;
}
return TextToSpeech.SUCCESS;
}
- private void setupVolume(AudioTrack audioTrack, float volume, float pan) {
- float vol = clip(volume, 0.0f, 1.0f);
- float panning = clip(pan, -1.0f, 1.0f);
- float volLeft = vol;
- float volRight = vol;
- if (panning > 0.0f) {
- volLeft *= (1.0f - panning);
- } else if (panning < 0.0f) {
- volRight *= (1.0f + panning);
- }
- if (DBG) Log.d(TAG, "volLeft=" + volLeft + ",volRight=" + volRight);
- if (audioTrack.setStereoVolume(volLeft, volRight) != AudioTrack.SUCCESS) {
- Log.e(TAG, "Failed to set volume");
- }
- }
-
- private float clip(float value, float min, float max) {
- return value > max ? max : (value < min ? min : value);
- }
@Override
public int audioAvailable(byte[] buffer, int offset, int length) {
@@ -169,195 +143,78 @@ class PlaybackSynthesisRequest extends SynthesisRequest {
throw new IllegalArgumentException("buffer is too large or of zero length (" +
+ length + " bytes)");
}
+
synchronized (mStateLock) {
- if (mWriteErrorOccured) {
- if (DBG) Log.d(TAG, "Error writing to audio track, count < 0");
- return TextToSpeech.ERROR;
- }
- if (mStopped) {
- if (DBG) Log.d(TAG, "Request has been aborted.");
+ if (mToken == null) {
return TextToSpeech.ERROR;
}
- if (mAudioTrack == null) {
- Log.e(TAG, "audioAvailable(): Not started");
- return TextToSpeech.ERROR;
- }
- final AudioTrack audioTrack = mAudioTrack;
+
// Sigh, another copy.
final byte[] bufferCopy = new byte[length];
System.arraycopy(buffer, offset, bufferCopy, 0, length);
-
- mAudioTrackHandler.post(new Runnable() {
- @Override
- public void run() {
- int playState = audioTrack.getPlayState();
- if (playState == AudioTrack.PLAYSTATE_STOPPED) {
- if (DBG) Log.d(TAG, "AudioTrack stopped, restarting");
- audioTrack.play();
- }
- // TODO: loop until all data is written?
- if (DBG) Log.d(TAG, "AudioTrack.write()");
- int count = audioTrack.write(bufferCopy, 0, bufferCopy.length);
- // The semantics of this change very slightly. Earlier, we would
- // report an error immediately, Now we will return an error on
- // the next API call, usually done( ) or another audioAvailable( )
- // call.
- if (count < 0) {
- mWriteErrorOccured = true;
- }
- }
- });
-
- return TextToSpeech.SUCCESS;
+ mToken.addBuffer(bufferCopy);
+ mAudioTrackHandler.enqueueSynthesisDataAvailable(mToken);
}
+
+ return TextToSpeech.SUCCESS;
}
@Override
public int done() {
if (DBG) Log.d(TAG, "done()");
+
synchronized (mStateLock) {
- if (mWriteErrorOccured) {
- if (DBG) Log.d(TAG, "Error writing to audio track, count < 0");
- return TextToSpeech.ERROR;
- }
- if (mStopped) {
- if (DBG) Log.d(TAG, "Request has been aborted.");
+ if (mDone) {
+ Log.w(TAG, "Duplicate call to done()");
return TextToSpeech.ERROR;
}
- if (mAudioTrack == null) {
- Log.e(TAG, "done(): Not started");
+
+ mDone = true;
+
+ if (mToken == null) {
return TextToSpeech.ERROR;
}
- mDone = true;
- cleanUp();
+
+ mAudioTrackHandler.enqueueSynthesisDone(mToken);
}
return TextToSpeech.SUCCESS;
}
@Override
public void error() {
- if (DBG) Log.d(TAG, "error()");
- synchronized (mStateLock) {
- cleanUp();
- }
+ if (DBG) Log.d(TAG, "error() [will call stop]");
+ stop();
}
@Override
public int completeAudioAvailable(int sampleRateInHz, int audioFormat, int channelCount,
byte[] buffer, int offset, int length) {
- if (DBG) {
- Log.d(TAG, "completeAudioAvailable(" + sampleRateInHz + "," + audioFormat
- + "," + channelCount + "byte[" + buffer.length + "],"
- + offset + "," + length + ")");
+ int channelConfig = AudioPlaybackHandler.getChannelConfig(channelCount);
+ if (channelConfig == 0) {
+ Log.e(TAG, "Unsupported number of channels :" + channelCount);
+ return TextToSpeech.ERROR;
+ }
+
+ int bytesPerFrame = AudioPlaybackHandler.getBytesPerFrame(audioFormat);
+ if (bytesPerFrame < 0) {
+ Log.e(TAG, "Unsupported audio format :" + audioFormat);
+ return TextToSpeech.ERROR;
}
synchronized (mStateLock) {
if (mStopped) {
- if (DBG) Log.d(TAG, "Request has been aborted.");
- return TextToSpeech.ERROR;
- }
- if (mAudioTrack != null) {
- Log.e(TAG, "start() called before completeAudioAvailable()");
- cleanUp();
return TextToSpeech.ERROR;
}
+ SynthesisMessageParams params = new SynthesisMessageParams(
+ mStreamType, sampleRateInHz, audioFormat, channelCount, mVolume, mPan,
+ mDispatcher);
+ params.addBuffer(buffer, offset, length);
- int channelConfig = getChannelConfig(channelCount);
- if (channelConfig < 0) {
- Log.e(TAG, "Unsupported number of channels :" + channelCount);
- cleanUp();
- return TextToSpeech.ERROR;
- }
- int bytesPerFrame = getBytesPerFrame(audioFormat);
- if (bytesPerFrame < 0) {
- Log.e(TAG, "Unsupported audio format :" + audioFormat);
- cleanUp();
- return TextToSpeech.ERROR;
- }
-
- mAudioTrack = new AudioTrack(mStreamType, sampleRateInHz, channelConfig,
- audioFormat, buffer.length, AudioTrack.MODE_STATIC);
- if (mAudioTrack == null) {
- return TextToSpeech.ERROR;
- }
-
- try {
- mAudioTrack.write(buffer, offset, length);
- setupVolume(mAudioTrack, mVolume, mPan);
- mAudioTrack.play();
- blockUntilDone(mAudioTrack, bytesPerFrame, length);
- mDone = true;
- if (DBG) Log.d(TAG, "Wrote data to audio track succesfully : " + length);
- } catch (IllegalStateException ex) {
- Log.e(TAG, "Playback error", ex);
- return TextToSpeech.ERROR;
- } finally {
- cleanUp();
- }
+ mAudioTrackHandler.enqueueSynthesisCompleteDataAvailable(params);
+ mToken = params;
}
return TextToSpeech.SUCCESS;
}
- private void blockUntilDone(AudioTrack audioTrack, int bytesPerFrame, int length) {
- int lengthInFrames = length / bytesPerFrame;
- int currentPosition = 0;
- while ((currentPosition = audioTrack.getPlaybackHeadPosition()) < lengthInFrames) {
- long estimatedTimeMs = ((lengthInFrames - currentPosition) * 1000) /
- audioTrack.getSampleRate();
- if (DBG) Log.d(TAG, "About to sleep for : " + estimatedTimeMs + " ms," +
- " Playback position : " + currentPosition);
- try {
- Thread.sleep(estimatedTimeMs);
- } catch (InterruptedException ie) {
- break;
- }
- }
- }
-
- private int getBytesPerFrame(int audioFormat) {
- if (audioFormat == AudioFormat.ENCODING_PCM_8BIT) {
- return 1;
- } else if (audioFormat == AudioFormat.ENCODING_PCM_16BIT) {
- return 2;
- }
-
- return -1;
- }
-
- private int getChannelConfig(int channelCount) {
- if (channelCount == 1) {
- return AudioFormat.CHANNEL_OUT_MONO;
- } else if (channelCount == 2){
- return AudioFormat.CHANNEL_OUT_STEREO;
- }
-
- return -1;
- }
-
- private AudioTrack createStreamingAudioTrack(int sampleRateInHz, int audioFormat,
- int channelCount) {
- int channelConfig = getChannelConfig(channelCount);
-
- if (channelConfig < 0) {
- Log.e(TAG, "Unsupported number of channels : " + channelCount);
- return null;
- }
-
- int minBufferSizeInBytes
- = AudioTrack.getMinBufferSize(sampleRateInHz, channelConfig, audioFormat);
- int bufferSizeInBytes = Math.max(MIN_AUDIO_BUFFER_SIZE, minBufferSizeInBytes);
- AudioTrack audioTrack = new AudioTrack(mStreamType, sampleRateInHz, channelConfig,
- audioFormat, bufferSizeInBytes, AudioTrack.MODE_STREAM);
- if (audioTrack == null) {
- return null;
- }
-
- if (audioTrack.getState() != AudioTrack.STATE_INITIALIZED) {
- audioTrack.release();
- return null;
- }
- setupVolume(audioTrack, mVolume, mPan);
- return audioTrack;
- }
}
diff --git a/core/java/android/speech/tts/SilenceMessageParams.java b/core/java/android/speech/tts/SilenceMessageParams.java
new file mode 100644
index 000000000000..eee8b6816438
--- /dev/null
+++ b/core/java/android/speech/tts/SilenceMessageParams.java
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2011 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.speech.tts;
+
+import android.os.ConditionVariable;
+import android.speech.tts.TextToSpeechService.UtteranceCompletedDispatcher;
+
+class SilenceMessageParams extends MessageParams {
+ private final ConditionVariable mCondVar = new ConditionVariable();
+ private final long mSilenceDurationMs;
+
+ SilenceMessageParams(UtteranceCompletedDispatcher dispatcher, long silenceDurationMs) {
+ super(dispatcher);
+ mSilenceDurationMs = silenceDurationMs;
+ }
+
+ long getSilenceDurationMs() {
+ return mSilenceDurationMs;
+ }
+
+ @Override
+ int getType() {
+ return TYPE_SILENCE;
+ }
+
+ ConditionVariable getConditionVariable() {
+ return mCondVar;
+ }
+
+}
diff --git a/core/java/android/speech/tts/SynthesisMessageParams.java b/core/java/android/speech/tts/SynthesisMessageParams.java
new file mode 100644
index 000000000000..aabaa5ae5efc
--- /dev/null
+++ b/core/java/android/speech/tts/SynthesisMessageParams.java
@@ -0,0 +1,92 @@
+/*
+ * Copyright (C) 2011 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.speech.tts;
+
+import android.media.AudioTrack;
+import android.speech.tts.TextToSpeechService.UtteranceCompletedDispatcher;
+
+import java.util.LinkedList;
+
+/**
+ * Params required to play back a synthesis request.
+ */
+final class SynthesisMessageParams extends MessageParams {
+ final int mStreamType;
+ final int mSampleRateInHz;
+ final int mAudioFormat;
+ final int mChannelCount;
+ final float mVolume;
+ final float mPan;
+
+ public volatile AudioTrack mAudioTrack;
+
+ private final LinkedList<ListEntry> mDataBufferList = new LinkedList<ListEntry>();
+
+ SynthesisMessageParams(int streamType, int sampleRate,
+ int audioFormat, int channelCount,
+ float volume, float pan, UtteranceCompletedDispatcher dispatcher) {
+ super(dispatcher);
+
+ mStreamType = streamType;
+ mSampleRateInHz = sampleRate;
+ mAudioFormat = audioFormat;
+ mChannelCount = channelCount;
+ mVolume = volume;
+ mPan = pan;
+
+ // initially null.
+ mAudioTrack = null;
+ }
+
+ @Override
+ int getType() {
+ return TYPE_SYNTHESIS;
+ }
+
+ synchronized void addBuffer(byte[] buffer, int offset, int length) {
+ mDataBufferList.add(new ListEntry(buffer, offset, length));
+ }
+
+ synchronized void addBuffer(byte[] buffer) {
+ mDataBufferList.add(new ListEntry(buffer, 0, buffer.length));
+ }
+
+ synchronized ListEntry getNextBuffer() {
+ return mDataBufferList.poll();
+ }
+
+
+ void setAudioTrack(AudioTrack audioTrack) {
+ mAudioTrack = audioTrack;
+ }
+
+ AudioTrack getAudioTrack() {
+ return mAudioTrack;
+ }
+
+ static final class ListEntry {
+ final byte[] mBytes;
+ final int mOffset;
+ final int mLength;
+
+ ListEntry(byte[] bytes, int offset, int length) {
+ mBytes = bytes;
+ mOffset = offset;
+ mLength = length;
+ }
+ }
+}
+
diff --git a/core/java/android/speech/tts/TextToSpeechService.java b/core/java/android/speech/tts/TextToSpeechService.java
index ddd32521891d..e553f7735b35 100644
--- a/core/java/android/speech/tts/TextToSpeechService.java
+++ b/core/java/android/speech/tts/TextToSpeechService.java
@@ -51,7 +51,10 @@ public abstract class TextToSpeechService extends Service {
private static final String SYNTH_THREAD_NAME = "SynthThread";
private SynthHandler mSynthHandler;
- private Handler mAudioTrackHandler;
+ // A thread and it's associated handler for playing back any audio
+ // associated with this TTS engine. Will handle all requests except synthesis
+ // to file requests, which occur on the synthesis thread.
+ private AudioPlaybackHandler mAudioPlaybackHandler;
private CallbackMap mCallbacks;
@@ -68,7 +71,7 @@ public abstract class TextToSpeechService extends Service {
HandlerThread audioTrackThread = new HandlerThread("TTS.audioTrackThread");
audioTrackThread.start();
- mAudioTrackHandler = new Handler(audioTrackThread.getLooper());
+ mAudioPlaybackHandler = new AudioPlaybackHandler(audioTrackThread.getLooper());
mCallbacks = new CallbackMap();
@@ -83,8 +86,8 @@ public abstract class TextToSpeechService extends Service {
// Tell the synthesizer to stop
mSynthHandler.quit();
- mAudioTrackHandler.getLooper().quit();
-
+ // Tell the audio playback thread to stop.
+ mAudioPlaybackHandler.quit();
// Unregister all callbacks.
mCallbacks.kill();
@@ -236,13 +239,6 @@ public abstract class TextToSpeechService extends Service {
super(looper);
}
- private void dispatchUtteranceCompleted(SpeechItem item) {
- String utteranceId = item.getUtteranceId();
- if (!TextUtils.isEmpty(utteranceId)) {
- mCallbacks.dispatchUtteranceCompleted(item.getCallingApp(), utteranceId);
- }
- }
-
private synchronized SpeechItem getCurrentSpeechItem() {
return mCurrentSpeechItem;
}
@@ -286,9 +282,7 @@ public abstract class TextToSpeechService extends Service {
@Override
public void run() {
setCurrentSpeechItem(speechItem);
- if (speechItem.play() == TextToSpeech.SUCCESS) {
- dispatchUtteranceCompleted(speechItem);
- }
+ speechItem.play();
setCurrentSpeechItem(null);
}
};
@@ -318,14 +312,19 @@ public abstract class TextToSpeechService extends Service {
if (current != null && TextUtils.equals(callingApp, current.getCallingApp())) {
current.stop();
}
+
return TextToSpeech.SUCCESS;
}
}
+ interface UtteranceCompletedDispatcher {
+ public void dispatchUtteranceCompleted();
+ }
+
/**
* An item in the synth thread queue.
*/
- private static abstract class SpeechItem {
+ private abstract class SpeechItem implements UtteranceCompletedDispatcher {
private final String mCallingApp;
protected final Bundle mParams;
private boolean mStarted = false;
@@ -380,6 +379,13 @@ public abstract class TextToSpeechService extends Service {
stopImpl();
}
+ public void dispatchUtteranceCompleted() {
+ final String utteranceId = getUtteranceId();
+ if (!TextUtils.isEmpty(utteranceId)) {
+ mCallbacks.dispatchUtteranceCompleted(getCallingApp(), utteranceId);
+ }
+ }
+
protected abstract int playImpl();
protected abstract void stopImpl();
@@ -413,7 +419,7 @@ public abstract class TextToSpeechService extends Service {
}
}
- private class SynthesisSpeechItem extends SpeechItem {
+ class SynthesisSpeechItem extends SpeechItem {
private final String mText;
private SynthesisRequest mSynthesisRequest;
@@ -453,7 +459,8 @@ public abstract class TextToSpeechService extends Service {
protected SynthesisRequest createSynthesisRequest() {
return new PlaybackSynthesisRequest(mText, mParams,
- getStreamType(), getVolume(), getPan(), mAudioTrackHandler);
+ getStreamType(), getVolume(), getPan(), mAudioPlaybackHandler,
+ this);
}
private void setRequestParams(SynthesisRequest request) {
@@ -526,6 +533,15 @@ public abstract class TextToSpeechService extends Service {
return new FileSynthesisRequest(getText(), mParams, mFile);
}
+ @Override
+ protected int playImpl() {
+ int status = super.playImpl();
+ if (status == TextToSpeech.SUCCESS) {
+ dispatchUtteranceCompleted();
+ }
+ return status;
+ }
+
/**
* Checks that the given file can be used for synthesis output.
*/
@@ -557,6 +573,7 @@ public abstract class TextToSpeechService extends Service {
private class AudioSpeechItem extends SpeechItem {
private final BlockingMediaPlayer mPlayer;
+ private AudioMessageParams mToken;
public AudioSpeechItem(String callingApp, Bundle params, Uri uri) {
super(callingApp, params);
@@ -570,23 +587,26 @@ public abstract class TextToSpeechService extends Service {
@Override
protected int playImpl() {
- return mPlayer.startAndWait() ? TextToSpeech.SUCCESS : TextToSpeech.ERROR;
+ mToken = new AudioMessageParams(this, mPlayer);
+ mAudioPlaybackHandler.enqueueAudio(mToken);
+ return TextToSpeech.SUCCESS;
}
@Override
protected void stopImpl() {
- mPlayer.stop();
+ if (mToken != null) {
+ mAudioPlaybackHandler.stop(mToken);
+ }
}
}
private class SilenceSpeechItem extends SpeechItem {
private final long mDuration;
- private final ConditionVariable mDone;
+ private SilenceMessageParams mToken;
public SilenceSpeechItem(String callingApp, Bundle params, long duration) {
super(callingApp, params);
mDuration = duration;
- mDone = new ConditionVariable();
}
@Override
@@ -596,13 +616,16 @@ public abstract class TextToSpeechService extends Service {
@Override
protected int playImpl() {
- boolean aborted = mDone.block(mDuration);
- return aborted ? TextToSpeech.ERROR : TextToSpeech.SUCCESS;
+ mToken = new SilenceMessageParams(this, mDuration);
+ mAudioPlaybackHandler.enqueueSilence(mToken);
+ return TextToSpeech.SUCCESS;
}
@Override
protected void stopImpl() {
- mDone.open();
+ if (mToken != null) {
+ mAudioPlaybackHandler.stop(mToken);
+ }
}
}
diff --git a/core/java/android/view/Gravity.java b/core/java/android/view/Gravity.java
index ba067956f6d5..69e64898e343 100644
--- a/core/java/android/view/Gravity.java
+++ b/core/java/android/view/Gravity.java
@@ -81,8 +81,10 @@ public class Gravity
* horizontal axis. */
public static final int CLIP_HORIZONTAL = AXIS_CLIP<<AXIS_X_SHIFT;
- /** Raw bit controlling whether the horizontal direction is relative (before/after) or not. */
- public static final int RELATIVE_HORIZONTAL_DIRECTION = 0x00800000;
+ /** Raw bit controlling whether the layout direction is relative or not (START/END instead of
+ * absolute LEFT/RIGHT).
+ */
+ public static final int RELATIVE_LAYOUT_DIRECTION = 0x00800000;
/**
* Binary mask to get the absolute horizontal gravity of a gravity.
@@ -110,10 +112,10 @@ public class Gravity
public static final int DISPLAY_CLIP_HORIZONTAL = 0x01000000;
/** Push object to x-axis position at the start of its container, not changing its size. */
- public static final int START = RELATIVE_HORIZONTAL_DIRECTION | LEFT;
+ public static final int START = RELATIVE_LAYOUT_DIRECTION | LEFT;
/** Push object to x-axis position at the end of its container, not changing its size. */
- public static final int END = RELATIVE_HORIZONTAL_DIRECTION | RIGHT;
+ public static final int END = RELATIVE_LAYOUT_DIRECTION | RIGHT;
/**
* Binary mask for the horizontal gravity and script specific direction bit.
@@ -352,7 +354,7 @@ public class Gravity
public static int getAbsoluteGravity(int gravity, boolean isRtl) {
int result = gravity;
// If layout is script specific and gravity is horizontal relative (START or END)
- if ((result & RELATIVE_HORIZONTAL_DIRECTION) > 0) {
+ if ((result & RELATIVE_LAYOUT_DIRECTION) > 0) {
if ((result & Gravity.START) == Gravity.START) {
// Remove the START bit
result &= ~START;
@@ -376,7 +378,7 @@ public class Gravity
}
// Don't need the script specific bit any more, so remove it as we are converting to
// absolute values (LEFT or RIGHT)
- result &= ~RELATIVE_HORIZONTAL_DIRECTION;
+ result &= ~RELATIVE_LAYOUT_DIRECTION;
}
return result;
}
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 51eb13b6a7ea..70218acaa938 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -951,51 +951,51 @@ public class View implements Drawable.Callback2, KeyEvent.Callback, Accessibilit
/**
* Horizontal direction of this view is from Left to Right.
- * Use with {@link #setHorizontalDirection}.
+ * Use with {@link #setLayoutDirection}.
* {@hide}
*/
- public static final int HORIZONTAL_DIRECTION_LTR = 0x00000000;
+ public static final int LAYOUT_DIRECTION_LTR = 0x00000000;
/**
* Horizontal direction of this view is from Right to Left.
- * Use with {@link #setHorizontalDirection}.
+ * Use with {@link #setLayoutDirection}.
* {@hide}
*/
- public static final int HORIZONTAL_DIRECTION_RTL = 0x40000000;
+ public static final int LAYOUT_DIRECTION_RTL = 0x40000000;
/**
* Horizontal direction of this view is inherited from its parent.
- * Use with {@link #setHorizontalDirection}.
+ * Use with {@link #setLayoutDirection}.
* {@hide}
*/
- public static final int HORIZONTAL_DIRECTION_INHERIT = 0x80000000;
+ public static final int LAYOUT_DIRECTION_INHERIT = 0x80000000;
/**
* Horizontal direction of this view is from deduced from the default language
- * script for the locale. Use with {@link #setHorizontalDirection}.
+ * script for the locale. Use with {@link #setLayoutDirection}.
* {@hide}
*/
- public static final int HORIZONTAL_DIRECTION_LOCALE = 0xC0000000;
+ public static final int LAYOUT_DIRECTION_LOCALE = 0xC0000000;
/**
* Mask for use with setFlags indicating bits used for horizontalDirection.
* {@hide}
*/
- static final int HORIZONTAL_DIRECTION_MASK = 0xC0000000;
+ static final int LAYOUT_DIRECTION_MASK = 0xC0000000;
/*
* Array of horizontal direction flags for mapping attribute "horizontalDirection" to correct
* flag value.
* {@hide}
*/
- private static final int[] HORIZONTAL_DIRECTION_FLAGS = { HORIZONTAL_DIRECTION_LTR,
- HORIZONTAL_DIRECTION_RTL, HORIZONTAL_DIRECTION_INHERIT, HORIZONTAL_DIRECTION_LOCALE};
+ private static final int[] LAYOUT_DIRECTION_FLAGS = {LAYOUT_DIRECTION_LTR,
+ LAYOUT_DIRECTION_RTL, LAYOUT_DIRECTION_INHERIT, LAYOUT_DIRECTION_LOCALE};
/**
* Default horizontalDirection.
* {@hide}
*/
- private static final int HORIZONTAL_DIRECTION_DEFAULT = HORIZONTAL_DIRECTION_INHERIT;
+ private static final int LAYOUT_DIRECTION_DEFAULT = LAYOUT_DIRECTION_INHERIT;
/**
* View flag indicating whether {@link #addFocusables(ArrayList, int, int)}
@@ -2464,7 +2464,7 @@ public class View implements Drawable.Callback2, KeyEvent.Callback, Accessibilit
public View(Context context) {
mContext = context;
mResources = context != null ? context.getResources() : null;
- mViewFlags = SOUND_EFFECTS_ENABLED | HAPTIC_FEEDBACK_ENABLED | HORIZONTAL_DIRECTION_INHERIT;
+ mViewFlags = SOUND_EFFECTS_ENABLED | HAPTIC_FEEDBACK_ENABLED | LAYOUT_DIRECTION_INHERIT;
mTouchSlop = ViewConfiguration.get(context).getScaledTouchSlop();
setOverScrollMode(OVER_SCROLL_IF_CONTENT_SCROLLS);
}
@@ -2662,18 +2662,18 @@ public class View implements Drawable.Callback2, KeyEvent.Callback, Accessibilit
viewFlagMasks |= VISIBILITY_MASK;
}
break;
- case com.android.internal.R.styleable.View_horizontalDirection:
+ case com.android.internal.R.styleable.View_layoutDirection:
// Clear any HORIZONTAL_DIRECTION flag already set
- viewFlagValues &= ~HORIZONTAL_DIRECTION_MASK;
+ viewFlagValues &= ~LAYOUT_DIRECTION_MASK;
// Set the HORIZONTAL_DIRECTION flags depending on the value of the attribute
- final int horizontalDirection = a.getInt(attr, -1);
- if (horizontalDirection != -1) {
- viewFlagValues |= HORIZONTAL_DIRECTION_FLAGS[horizontalDirection];
+ final int layoutDirection = a.getInt(attr, -1);
+ if (layoutDirection != -1) {
+ viewFlagValues |= LAYOUT_DIRECTION_FLAGS[layoutDirection];
} else {
- // Set to default (HORIZONTAL_DIRECTION_INHERIT)
- viewFlagValues |= HORIZONTAL_DIRECTION_DEFAULT;
+ // Set to default (LAYOUT_DIRECTION_INHERIT)
+ viewFlagValues |= LAYOUT_DIRECTION_DEFAULT;
}
- viewFlagMasks |= HORIZONTAL_DIRECTION_MASK;
+ viewFlagMasks |= LAYOUT_DIRECTION_MASK;
break;
case com.android.internal.R.styleable.View_drawingCacheQuality:
final int cacheQuality = a.getInt(attr, 0);
@@ -4256,38 +4256,38 @@ public class View implements Drawable.Callback2, KeyEvent.Callback, Accessibilit
}
/**
- * Returns the horizontal direction for this view.
+ * Returns the layout direction for this view.
*
- * @return One of {@link #HORIZONTAL_DIRECTION_LTR},
- * {@link #HORIZONTAL_DIRECTION_RTL},
- * {@link #HORIZONTAL_DIRECTION_INHERIT} or
- * {@link #HORIZONTAL_DIRECTION_LOCALE}.
- * @attr ref android.R.styleable#View_horizontalDirection
+ * @return One of {@link #LAYOUT_DIRECTION_LTR},
+ * {@link #LAYOUT_DIRECTION_RTL},
+ * {@link #LAYOUT_DIRECTION_INHERIT} or
+ * {@link #LAYOUT_DIRECTION_LOCALE}.
+ * @attr ref android.R.styleable#View_layoutDirection
* @hide
*/
@ViewDebug.ExportedProperty(category = "layout", mapping = {
- @ViewDebug.IntToString(from = HORIZONTAL_DIRECTION_LTR, to = "LTR"),
- @ViewDebug.IntToString(from = HORIZONTAL_DIRECTION_RTL, to = "RTL"),
- @ViewDebug.IntToString(from = HORIZONTAL_DIRECTION_INHERIT, to = "INHERIT"),
- @ViewDebug.IntToString(from = HORIZONTAL_DIRECTION_LOCALE, to = "LOCALE")
+ @ViewDebug.IntToString(from = LAYOUT_DIRECTION_LTR, to = "LTR"),
+ @ViewDebug.IntToString(from = LAYOUT_DIRECTION_RTL, to = "RTL"),
+ @ViewDebug.IntToString(from = LAYOUT_DIRECTION_INHERIT, to = "INHERIT"),
+ @ViewDebug.IntToString(from = LAYOUT_DIRECTION_LOCALE, to = "LOCALE")
})
- public int getHorizontalDirection() {
- return mViewFlags & HORIZONTAL_DIRECTION_MASK;
+ public int getLayoutDirection() {
+ return mViewFlags & LAYOUT_DIRECTION_MASK;
}
/**
- * Set the horizontal direction for this view.
+ * Set the layout direction for this view.
*
- * @param horizontalDirection One of {@link #HORIZONTAL_DIRECTION_LTR},
- * {@link #HORIZONTAL_DIRECTION_RTL},
- * {@link #HORIZONTAL_DIRECTION_INHERIT} or
- * {@link #HORIZONTAL_DIRECTION_LOCALE}.
- * @attr ref android.R.styleable#View_horizontalDirection
+ * @param layoutDirection One of {@link #LAYOUT_DIRECTION_LTR},
+ * {@link #LAYOUT_DIRECTION_RTL},
+ * {@link #LAYOUT_DIRECTION_INHERIT} or
+ * {@link #LAYOUT_DIRECTION_LOCALE}.
+ * @attr ref android.R.styleable#View_layoutDirection
* @hide
*/
@RemotableViewMethod
- public void setHorizontalDirection(int horizontalDirection) {
- setFlags(horizontalDirection, HORIZONTAL_DIRECTION_MASK);
+ public void setLayoutDirection(int layoutDirection) {
+ setFlags(layoutDirection, LAYOUT_DIRECTION_MASK);
}
/**
@@ -6103,7 +6103,7 @@ public class View implements Drawable.Callback2, KeyEvent.Callback, Accessibilit
}
}
- if ((changed & HORIZONTAL_DIRECTION_MASK) != 0) {
+ if ((changed & LAYOUT_DIRECTION_MASK) != 0) {
requestLayout();
}
}
@@ -8658,24 +8658,24 @@ public class View implements Drawable.Callback2, KeyEvent.Callback, Accessibilit
mPrivateFlags &= ~AWAKEN_SCROLL_BARS_ON_ATTACH;
}
jumpDrawablesToCurrentState();
- resolveHorizontalDirection();
+ resolveLayoutDirection();
}
/**
* Resolving the layout direction. LTR is set initially.
* We are supposing here that the parent directionality will be resolved before its children
*/
- private void resolveHorizontalDirection() {
+ private void resolveLayoutDirection() {
mPrivateFlags2 &= ~RESOLVED_LAYOUT_RTL;
- switch (getHorizontalDirection()) {
- case HORIZONTAL_DIRECTION_INHERIT:
+ switch (getLayoutDirection()) {
+ case LAYOUT_DIRECTION_INHERIT:
// If this is root view, no need to look at parent's layout dir.
if (mParent != null && mParent instanceof ViewGroup &&
((ViewGroup) mParent).isLayoutRtl()) {
mPrivateFlags2 |= RESOLVED_LAYOUT_RTL;
}
break;
- case HORIZONTAL_DIRECTION_RTL:
+ case LAYOUT_DIRECTION_RTL:
mPrivateFlags2 |= RESOLVED_LAYOUT_RTL;
break;
}
diff --git a/core/java/android/view/ViewConfiguration.java b/core/java/android/view/ViewConfiguration.java
index 36bb046c0f68..5919150dbfae 100644
--- a/core/java/android/view/ViewConfiguration.java
+++ b/core/java/android/view/ViewConfiguration.java
@@ -110,7 +110,21 @@ public class ViewConfiguration {
* double-tap.
*/
private static final int DOUBLE_TAP_TIMEOUT = 300;
-
+
+ /**
+ * Defines the maximum duration in milliseconds between a touch pad
+ * touch and release for a given touch to be considered a tap (click) as
+ * opposed to a hover movement gesture.
+ */
+ private static final int HOVER_TAP_TIMEOUT = 150;
+
+ /**
+ * Defines the maximum distance in pixels that a touch pad touch can move
+ * before being released for it to be considered a tap (click) as opposed
+ * to a hover movement gesture.
+ */
+ private static final int HOVER_TAP_SLOP = 20;
+
/**
* Defines the duration in milliseconds we want to display zoom controls in response
* to a user panning within an application.
@@ -369,7 +383,7 @@ public class ViewConfiguration {
public static int getTapTimeout() {
return TAP_TIMEOUT;
}
-
+
/**
* @return the duration in milliseconds we will wait to see if a touch event
* is a jump tap. If the user does not move within this interval, it is
@@ -387,7 +401,27 @@ public class ViewConfiguration {
public static int getDoubleTapTimeout() {
return DOUBLE_TAP_TIMEOUT;
}
-
+
+ /**
+ * @return the maximum duration in milliseconds between a touch pad
+ * touch and release for a given touch to be considered a tap (click) as
+ * opposed to a hover movement gesture.
+ * @hide
+ */
+ public static int getHoverTapTimeout() {
+ return HOVER_TAP_TIMEOUT;
+ }
+
+ /**
+ * @return the maximum distance in pixels that a touch pad touch can move
+ * before being released for it to be considered a tap (click) as opposed
+ * to a hover movement gesture.
+ * @hide
+ */
+ public static int getHoverTapSlop() {
+ return HOVER_TAP_SLOP;
+ }
+
/**
* @return Inset in pixels to look for touchable content when the user touches the edge of the
* screen
diff --git a/core/java/android/view/inputmethod/InputMethodSubtype.java b/core/java/android/view/inputmethod/InputMethodSubtype.java
index 20cf93d36067..9d84c3e2ba63 100644
--- a/core/java/android/view/inputmethod/InputMethodSubtype.java
+++ b/core/java/android/view/inputmethod/InputMethodSubtype.java
@@ -28,6 +28,7 @@ import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
+import java.util.Locale;
/**
* This class is used to specify meta information of a subtype contained in an input method.
@@ -54,10 +55,11 @@ public final class InputMethodSubtype implements Parcelable {
* @param nameId The name of the subtype
* @param iconId The icon of the subtype
* @param locale The locale supported by the subtype
- * @param modeId The mode supported by the subtype
+ * @param mode The mode supported by the subtype
* @param extraValue The extra value of the subtype
*/
- InputMethodSubtype(int nameId, int iconId, String locale, String mode, String extraValue) {
+ public InputMethodSubtype(
+ int nameId, int iconId, String locale, String mode, String extraValue) {
this(nameId, iconId, locale, mode, extraValue, false);
}
@@ -66,19 +68,20 @@ public final class InputMethodSubtype implements Parcelable {
* @param nameId The name of the subtype
* @param iconId The icon of the subtype
* @param locale The locale supported by the subtype
- * @param modeId The mode supported by the subtype
+ * @param mode The mode supported by the subtype
* @param extraValue The extra value of the subtype
* @param isAuxiliary true when this subtype is one shot subtype.
*/
- InputMethodSubtype(int nameId, int iconId, String locale, String mode, String extraValue,
+ public InputMethodSubtype(int nameId, int iconId, String locale, String mode, String extraValue,
boolean isAuxiliary) {
mSubtypeNameResId = nameId;
mSubtypeIconResId = iconId;
mSubtypeLocale = locale != null ? locale : "";
mSubtypeMode = mode != null ? mode : "";
mSubtypeExtraValue = extraValue != null ? extraValue : "";
- mSubtypeHashCode = hashCodeInternal(mSubtypeLocale, mSubtypeMode, mSubtypeExtraValue);
mIsAuxiliary = isAuxiliary;
+ mSubtypeHashCode = hashCodeInternal(mSubtypeLocale, mSubtypeMode, mSubtypeExtraValue,
+ mIsAuxiliary);
}
InputMethodSubtype(Parcel source) {
@@ -91,8 +94,9 @@ public final class InputMethodSubtype implements Parcelable {
mSubtypeMode = s != null ? s : "";
s = source.readString();
mSubtypeExtraValue = s != null ? s : "";
- mSubtypeHashCode = hashCodeInternal(mSubtypeLocale, mSubtypeMode, mSubtypeExtraValue);
mIsAuxiliary = (source.readInt() == 1);
+ mSubtypeHashCode = hashCodeInternal(mSubtypeLocale, mSubtypeMode, mSubtypeExtraValue,
+ mIsAuxiliary);
}
/**
@@ -151,16 +155,17 @@ public final class InputMethodSubtype implements Parcelable {
*/
public CharSequence getDisplayName(
Context context, String packageName, ApplicationInfo appInfo) {
- final String locale = context.getResources().getConfiguration().locale.getDisplayName();
+ final Locale locale = constructLocaleFromString(mSubtypeLocale);
+ final String localeStr = locale != null ? locale.getDisplayName() : mSubtypeLocale;
if (mSubtypeNameResId == 0) {
- return locale;
+ return localeStr;
}
final String subtypeName = context.getPackageManager().getText(
packageName, mSubtypeNameResId, appInfo).toString();
if (!TextUtils.isEmpty(subtypeName)) {
- return String.format(subtypeName, locale);
+ return String.format(subtypeName, localeStr);
} else {
- return locale;
+ return localeStr;
}
}
@@ -218,7 +223,8 @@ public final class InputMethodSubtype implements Parcelable {
&& (subtype.getMode().equals(getMode()))
&& (subtype.getIconResId() == getIconResId())
&& (subtype.getLocale().equals(getLocale()))
- && (subtype.getExtraValue().equals(getExtraValue()));
+ && (subtype.getExtraValue().equals(getExtraValue()))
+ && (subtype.isAuxiliary() == isAuxiliary());
}
return false;
}
@@ -251,8 +257,25 @@ public final class InputMethodSubtype implements Parcelable {
}
};
- private static int hashCodeInternal(String locale, String mode, String extraValue) {
- return Arrays.hashCode(new Object[] {locale, mode, extraValue});
+ private static Locale constructLocaleFromString(String localeStr) {
+ if (TextUtils.isEmpty(localeStr))
+ return null;
+ String[] localeParams = localeStr.split("_", 3);
+ // The length of localeStr is guaranteed to always return a 1 <= value <= 3
+ // because localeStr is not empty.
+ if (localeParams.length == 1) {
+ return new Locale(localeParams[0]);
+ } else if (localeParams.length == 2) {
+ return new Locale(localeParams[0], localeParams[1]);
+ } else if (localeParams.length == 3) {
+ return new Locale(localeParams[0], localeParams[1], localeParams[2]);
+ }
+ return null;
+ }
+
+ private static int hashCodeInternal(String locale, String mode, String extraValue,
+ boolean isAuxiliary) {
+ return Arrays.hashCode(new Object[] {locale, mode, extraValue, isAuxiliary});
}
/**
diff --git a/core/java/android/webkit/WebView.java b/core/java/android/webkit/WebView.java
index a68ca600f823..4aad02256fc9 100644
--- a/core/java/android/webkit/WebView.java
+++ b/core/java/android/webkit/WebView.java
@@ -6461,7 +6461,7 @@ public class WebView extends AbsoluteLayout
if (hscroll != 0 || vscroll != 0) {
final int vdelta = (int) (vscroll * getVerticalScrollFactor());
final int hdelta = (int) (hscroll * getHorizontalScrollFactor());
- if (pinScrollBy(hdelta, vdelta, true, 0)) {
+ if (pinScrollBy(hdelta, vdelta, false, 0)) {
return true;
}
}
diff --git a/core/java/android/widget/LinearLayout.java b/core/java/android/widget/LinearLayout.java
index 38767351fdc2..0cdbc5b53f1d 100644
--- a/core/java/android/widget/LinearLayout.java
+++ b/core/java/android/widget/LinearLayout.java
@@ -132,8 +132,8 @@ public class LinearLayout extends ViewGroup {
equals = Gravity.CENTER, name = "CENTER"),
@ViewDebug.FlagToString(mask = Gravity.FILL,
equals = Gravity.FILL, name = "FILL"),
- @ViewDebug.FlagToString(mask = Gravity.RELATIVE_HORIZONTAL_DIRECTION,
- equals = Gravity.RELATIVE_HORIZONTAL_DIRECTION, name = "RELATIVE")
+ @ViewDebug.FlagToString(mask = Gravity.RELATIVE_LAYOUT_DIRECTION,
+ equals = Gravity.RELATIVE_LAYOUT_DIRECTION, name = "RELATIVE")
})
private int mGravity = Gravity.START | Gravity.TOP;
diff --git a/core/java/com/android/internal/util/Objects.java b/core/java/com/android/internal/util/Objects.java
index 598a079c84af..2664182c5ea8 100644
--- a/core/java/com/android/internal/util/Objects.java
+++ b/core/java/com/android/internal/util/Objects.java
@@ -16,34 +16,47 @@
package com.android.internal.util;
+import java.util.Arrays;
+
/**
* Object utility methods.
*/
public class Objects {
/**
- * Ensures the given object isn't {@code null}.
+ * Determines whether two possibly-null objects are equal. Returns:
+ *
+ * <ul>
+ * <li>{@code true} if {@code a} and {@code b} are both null.
+ * <li>{@code true} if {@code a} and {@code b} are both non-null and they are
+ * equal according to {@link Object#equals(Object)}.
+ * <li>{@code false} in all other situations.
+ * </ul>
*
- * @return the given object
- * @throws NullPointerException if the object is null
+ * <p>This assumes that any non-null objects passed to this function conform
+ * to the {@code equals()} contract.
*/
- public static <T> T nonNull(T t) {
- if (t == null) {
- throw new NullPointerException();
- }
- return t;
+ public static boolean equal(Object a, Object b) {
+ return a == b || (a != null && a.equals(b));
}
/**
- * Ensures the given object isn't {@code null}.
+ * Generates a hash code for multiple values. The hash code is generated by
+ * calling {@link Arrays#hashCode(Object[])}.
*
- * @return the given object
- * @throws NullPointerException if the object is null
+ * <p>This is useful for implementing {@link Object#hashCode()}. For example,
+ * in an object that has three properties, {@code x}, {@code y}, and
+ * {@code z}, one could write:
+ * <pre>
+ * public int hashCode() {
+ * return Objects.hashCode(getX(), getY(), getZ());
+ * }</pre>
+ *
+ * <b>Warning</b>: When a single object is supplied, the returned hash code
+ * does not equal the hash code of that object.
*/
- public static <T> T nonNull(T t, String message) {
- if (t == null) {
- throw new NullPointerException(message);
- }
- return t;
+ public static int hashCode(Object... objects) {
+ return Arrays.hashCode(objects);
}
+
}
diff --git a/core/java/com/android/internal/util/Preconditions.java b/core/java/com/android/internal/util/Preconditions.java
new file mode 100644
index 000000000000..a53a9c0c6eb6
--- /dev/null
+++ b/core/java/com/android/internal/util/Preconditions.java
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2011 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;
+
+/**
+ * Simple static methods to be called at the start of your own methods to verify
+ * correct arguments and state.
+ */
+public class Preconditions {
+
+ /**
+ * Ensures that an object reference passed as a parameter to the calling
+ * method is not null.
+ *
+ * @param reference an object reference
+ * @return the non-null reference that was validated
+ * @throws NullPointerException if {@code reference} is null
+ */
+ public static <T> T checkNotNull(T reference) {
+ if (reference == null) {
+ throw new NullPointerException();
+ }
+ return reference;
+ }
+
+ /**
+ * Ensures that an object reference passed as a parameter to the calling
+ * method is not null.
+ *
+ * @param reference an object reference
+ * @param errorMessage the exception message to use if the check fails; will
+ * be converted to a string using {@link String#valueOf(Object)}
+ * @return the non-null reference that was validated
+ * @throws NullPointerException if {@code reference} is null
+ */
+ public static <T> T checkNotNull(T reference, Object errorMessage) {
+ if (reference == null) {
+ throw new NullPointerException(String.valueOf(errorMessage));
+ }
+ return reference;
+ }
+
+}
diff --git a/core/jni/android_app_backup_FullBackup.cpp b/core/jni/android_app_backup_FullBackup.cpp
index ecfe5ff1a0ca..b36fa3e2f6b2 100644
--- a/core/jni/android_app_backup_FullBackup.cpp
+++ b/core/jni/android_app_backup_FullBackup.cpp
@@ -73,6 +73,8 @@ static struct {
static int backupToTar(JNIEnv* env, jobject clazz, jstring packageNameObj,
jstring domainObj, jstring linkdomain,
jstring rootpathObj, jstring pathObj, jobject dataOutputObj) {
+ int ret;
+
// Extract the various strings, allowing for null object pointers
const char* packagenamechars = env->GetStringUTFChars(packageNameObj, NULL);
const char* rootchars = env->GetStringUTFChars(rootpathObj, NULL);
diff --git a/core/res/res/layout/volume_adjust.xml b/core/res/res/layout/volume_adjust.xml
index b0ca3e8e71ff..7303003f00b7 100644
--- a/core/res/res/layout/volume_adjust.xml
+++ b/core/res/res/layout/volume_adjust.xml
@@ -15,22 +15,21 @@
-->
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:gravity="left">
-
+ android:layout_width="480dp"
+ android:layout_height="wrap_content">
<LinearLayout
- android:layout_width="wrap_content"
+ android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:layout_marginTop="80dip"
+ android:layout_marginTop="80dp"
android:background="@android:drawable/dialog_full_holo_dark"
android:orientation="horizontal"
>
<LinearLayout
android:id="@+id/slider_group"
- android:layout_width="wrap_content"
+ android:layout_width="0dp"
android:layout_height="wrap_content"
+ android:layout_weight="1"
android:orientation="vertical"
>
<!-- Sliders go here -->
@@ -56,9 +55,6 @@
android:background="?attr/selectableItemBackground"
android:src="@drawable/ic_sysbar_quicksettings"
/>
-
- </LinearLayout>
-
-</FrameLayout>
-
+ </LinearLayout>
+</FrameLayout> \ No newline at end of file
diff --git a/core/res/res/layout/volume_adjust_item.xml b/core/res/res/layout/volume_adjust_item.xml
index e841d878af0c..beb511db72c1 100644
--- a/core/res/res/layout/volume_adjust_item.xml
+++ b/core/res/res/layout/volume_adjust_item.xml
@@ -15,7 +15,7 @@
-->
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="wrap_content"
+ android:layout_width="match_parent"
android:layout_height="80dip"
android:orientation="horizontal"
android:layout_marginTop="8dip"
@@ -34,8 +34,9 @@
<SeekBar
style="?android:attr/seekBarStyle"
android:id="@+id/seekbar"
- android:layout_width="300dip"
+ android:layout_width="300dp"
android:layout_height="wrap_content"
+ android:layout_weight="1"
android:padding="16dip"
android:layout_marginLeft="8dip"
android:layout_marginRight="8dip" />
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index 9c5562779ece..4a7c6909ba56 100755
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -1191,9 +1191,9 @@
edge, a right gravity will clip the left edge, and neither will clip both edges. -->
<flag name="clip_horizontal" value="0x08" />
<!-- Push object to the beginning of its container, not changing its size. -->
- <flag name="before" value="0x00800003" />
+ <flag name="start" value="0x00800003" />
<!-- Push object to the end of its container, not changing its size. -->
- <flag name="after" value="0x00800005" />
+ <flag name="end" value="0x00800005" />
</attr>
<!-- Standard orientation constant. -->
@@ -1932,11 +1932,11 @@
</attr>
<!-- Defines the direction of layout drawing. This typically is associated with writing
- direction of the language script used. The possible values are Left-to-Right,
- Right-to-Left, Locale and Inherit from parent view. If there is nothing to inherit,
- Locale is used. Locale fallsback to 'en-US'. Left-to-Right is the direction used in
- 'en-US'. The default for this attribute is 'inherit'. -->
- <attr name="horizontalDirection">
+ direction of the language script used. The possible values are "ltr" for Left-to-Right,
+ "rtl" for Right-to-Left, "locale" and "inherit" from parent view. If there is nothing
+ to inherit, "locale" is used. "locale" falls back to "en-US". "ltr" is the direction
+ used in "en-US". The default for this attribute is "inherit". -->
+ <attr name="layoutDirection">
<!-- Left-to-Right -->
<enum name="ltr" value="0" />
<!-- Right-to-Left -->
@@ -5156,6 +5156,8 @@
<!-- number of megabytes of storage MTP should reserve for free storage
(used for emulated storage that is shared with system's data partition) -->
<attr name="mtpReserve" format="integer" />
+ <!-- true if the storage can be shared via USB mass storage -->
+ <attr name="allowMassStorage" format="boolean" />
</declare-styleable>
</resources>
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index 81f888de98c6..55312e32815e 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -1657,6 +1657,9 @@
<public type="attr" name="compatibleWidthLimitDp" />
<public type="attr" name="largestWidthLimitDp" />
+ <public type="style" name="Theme.Holo.Light.NoActionBar" />
+ <public type="style" name="Theme.Holo.Light.NoActionBar.Fullscreen" />
+
<!-- ===============================================================
Resources added in version 13 of the platform (Ice Cream Sandwich)
=============================================================== -->
@@ -1666,7 +1669,6 @@
<public type="attr" name="state_drag_hovered" />
<public type="attr" name="stopWithTask" />
- <public type="style" name="Theme.Holo.Light.NoActionBar" />
<public type="style" name="TextAppearance.SuggestionHighlight" />
<public type="style" name="Theme.Holo.SplitActionBarWhenNarrow" />
<public type="style" name="Theme.Holo.Light.SplitActionBarWhenNarrow" />
@@ -1675,7 +1677,8 @@
<public type="attr" name="textEditSuggestionsBottomWindowLayout" />
<public type="attr" name="textEditSuggestionsTopWindowLayout" />
<public type="attr" name="textEditSuggestionItemLayout" />
- <public type="attr" name="horizontalDirection" />
+
+ <public type="attr" name="layoutDirection" />
<public type="attr" name="fullBackupAgent" />
<public type="attr" name="suggestionsEnabled" />
@@ -1703,4 +1706,5 @@
<public type="attr" name="notificationTimeout" />
<public type="attr" name="accessibilityFlags" />
<public type="attr" name="canRetrieveWindowContent" />
+
</resources>
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index 29c23a683df2..65a1e44abe5d 100755
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -1866,7 +1866,7 @@
<!-- Do not translate. WebView User Agent string -->
<string name="web_user_agent" translatable="false">Mozilla/5.0 (Linux; U; <xliff:g id="x">Android %s</xliff:g>)
- AppleWebKit/534.24 (KHTML, like Gecko) Version/4.0 <xliff:g id="mobile">%s</xliff:g>Safari/534.24</string>
+ AppleWebKit/534.27 (KHTML, like Gecko) Version/4.0 <xliff:g id="mobile">%s</xliff:g>Safari/534.27</string>
<!-- Do not translate. WebView User Agent targeted content -->
<string name="web_user_agent_target_content" translatable="false">"Mobile "</string>
diff --git a/core/tests/coretests/Android.mk b/core/tests/coretests/Android.mk
index b02d9044bd4d..00f47facb576 100644
--- a/core/tests/coretests/Android.mk
+++ b/core/tests/coretests/Android.mk
@@ -12,7 +12,7 @@ LOCAL_SRC_FILES := \
$(call all-java-files-under, EnabledTestApp/src)
LOCAL_DX_FLAGS := --core-library
-LOCAL_STATIC_JAVA_LIBRARIES := core-tests android-common frameworks-core-util-lib
+LOCAL_STATIC_JAVA_LIBRARIES := core-tests android-common frameworks-core-util-lib mockwebserver
LOCAL_JAVA_LIBRARIES := android.test.runner
LOCAL_PACKAGE_NAME := FrameworksCoreTests
diff --git a/core/tests/coretests/src/android/net/NetworkStatsHistoryTest.java b/core/tests/coretests/src/android/net/NetworkStatsHistoryTest.java
index eb63c0d66e66..0b72c3c5b0d4 100644
--- a/core/tests/coretests/src/android/net/NetworkStatsHistoryTest.java
+++ b/core/tests/coretests/src/android/net/NetworkStatsHistoryTest.java
@@ -16,8 +16,6 @@
package android.net;
-import static android.net.ConnectivityManager.TYPE_MOBILE;
-import static android.net.NetworkStatsHistory.UID_ALL;
import static android.text.format.DateUtils.DAY_IN_MILLIS;
import static android.text.format.DateUtils.HOUR_IN_MILLIS;
import static android.text.format.DateUtils.MINUTE_IN_MILLIS;
@@ -51,7 +49,7 @@ public class NetworkStatsHistoryTest extends TestCase {
public void testRecordSingleBucket() throws Exception {
final long BUCKET_SIZE = HOUR_IN_MILLIS;
- stats = buildStats(BUCKET_SIZE);
+ stats = new NetworkStatsHistory(BUCKET_SIZE);
// record data into narrow window to get single bucket
stats.recordData(TEST_START, TEST_START + SECOND_IN_MILLIS, 1024L, 2048L);
@@ -62,7 +60,7 @@ public class NetworkStatsHistoryTest extends TestCase {
public void testRecordEqualBuckets() throws Exception {
final long bucketDuration = HOUR_IN_MILLIS;
- stats = buildStats(bucketDuration);
+ stats = new NetworkStatsHistory(bucketDuration);
// split equally across two buckets
final long recordStart = TEST_START + (bucketDuration / 2);
@@ -75,7 +73,7 @@ public class NetworkStatsHistoryTest extends TestCase {
public void testRecordTouchingBuckets() throws Exception {
final long BUCKET_SIZE = 15 * MINUTE_IN_MILLIS;
- stats = buildStats(BUCKET_SIZE);
+ stats = new NetworkStatsHistory(BUCKET_SIZE);
// split almost completely into middle bucket, but with a few minutes
// overlap into neighboring buckets. total record is 20 minutes.
@@ -94,7 +92,7 @@ public class NetworkStatsHistoryTest extends TestCase {
public void testRecordGapBuckets() throws Exception {
final long BUCKET_SIZE = HOUR_IN_MILLIS;
- stats = buildStats(BUCKET_SIZE);
+ stats = new NetworkStatsHistory(BUCKET_SIZE);
// record some data today and next week with large gap
final long firstStart = TEST_START;
@@ -122,7 +120,7 @@ public class NetworkStatsHistoryTest extends TestCase {
public void testRecordOverlapBuckets() throws Exception {
final long BUCKET_SIZE = HOUR_IN_MILLIS;
- stats = buildStats(BUCKET_SIZE);
+ stats = new NetworkStatsHistory(BUCKET_SIZE);
// record some data in one bucket, and another overlapping buckets
stats.recordData(TEST_START, TEST_START + SECOND_IN_MILLIS, 256L, 256L);
@@ -135,9 +133,80 @@ public class NetworkStatsHistoryTest extends TestCase {
assertBucket(stats, 1, 512L, 512L);
}
+ public void testRecordEntireGapIdentical() throws Exception {
+ final long[] total = new long[2];
+
+ // first, create two separate histories far apart
+ final NetworkStatsHistory stats1 = new NetworkStatsHistory(HOUR_IN_MILLIS);
+ stats1.recordData(TEST_START, TEST_START + 2 * HOUR_IN_MILLIS, 2000L, 1000L);
+
+ final long TEST_START_2 = TEST_START + DAY_IN_MILLIS;
+ final NetworkStatsHistory stats2 = new NetworkStatsHistory(HOUR_IN_MILLIS);
+ stats2.recordData(TEST_START_2, TEST_START_2 + 2 * HOUR_IN_MILLIS, 1000L, 500L);
+
+ // combine together with identical bucket size
+ stats = new NetworkStatsHistory(HOUR_IN_MILLIS);
+ stats.recordEntireHistory(stats1);
+ stats.recordEntireHistory(stats2);
+
+ // first verify that totals match up
+ stats.getTotalData(TEST_START - WEEK_IN_MILLIS, TEST_START + WEEK_IN_MILLIS, total);
+ assertTotalEquals(total, 3000L, 1500L);
+
+ // now inspect internal buckets
+ assertBucket(stats, 0, 1000L, 500L);
+ assertBucket(stats, 1, 1000L, 500L);
+ assertBucket(stats, 2, 500L, 250L);
+ assertBucket(stats, 3, 500L, 250L);
+ }
+
+ public void testRecordEntireOverlapVaryingBuckets() throws Exception {
+ final long[] total = new long[2];
+
+ // create history just over hour bucket boundary
+ final NetworkStatsHistory stats1 = new NetworkStatsHistory(HOUR_IN_MILLIS);
+ stats1.recordData(TEST_START, TEST_START + MINUTE_IN_MILLIS * 60, 600L, 600L);
+
+ final long TEST_START_2 = TEST_START + MINUTE_IN_MILLIS;
+ final NetworkStatsHistory stats2 = new NetworkStatsHistory(MINUTE_IN_MILLIS);
+ stats2.recordData(TEST_START_2, TEST_START_2 + MINUTE_IN_MILLIS * 5, 50L, 50L);
+
+ // combine together with minute bucket size
+ stats = new NetworkStatsHistory(MINUTE_IN_MILLIS);
+ stats.recordEntireHistory(stats1);
+ stats.recordEntireHistory(stats2);
+
+ // first verify that totals match up
+ stats.getTotalData(TEST_START - WEEK_IN_MILLIS, TEST_START + WEEK_IN_MILLIS, total);
+ assertTotalEquals(total, 650L, 650L);
+
+ // now inspect internal buckets
+ assertBucket(stats, 0, 10L, 10L);
+ assertBucket(stats, 1, 20L, 20L);
+ assertBucket(stats, 2, 20L, 20L);
+ assertBucket(stats, 3, 20L, 20L);
+ assertBucket(stats, 4, 20L, 20L);
+ assertBucket(stats, 5, 20L, 20L);
+ assertBucket(stats, 6, 10L, 10L);
+
+ // now combine using 15min buckets
+ stats = new NetworkStatsHistory(HOUR_IN_MILLIS / 4);
+ stats.recordEntireHistory(stats1);
+ stats.recordEntireHistory(stats2);
+
+ // first verify that totals match up
+ stats.getTotalData(TEST_START - WEEK_IN_MILLIS, TEST_START + WEEK_IN_MILLIS, total);
+ assertTotalEquals(total, 650L, 650L);
+
+ // and inspect buckets
+ assertBucket(stats, 0, 200L, 200L);
+ assertBucket(stats, 1, 150L, 150L);
+ assertBucket(stats, 2, 150L, 150L);
+ assertBucket(stats, 3, 150L, 150L);
+ }
+
public void testRemove() throws Exception {
- final long BUCKET_SIZE = HOUR_IN_MILLIS;
- stats = buildStats(BUCKET_SIZE);
+ stats = new NetworkStatsHistory(HOUR_IN_MILLIS);
// record some data across 24 buckets
stats.recordData(TEST_START, TEST_START + DAY_IN_MILLIS, 24L, 24L);
@@ -165,13 +234,44 @@ public class NetworkStatsHistoryTest extends TestCase {
assertEquals(0, stats.bucketCount);
}
+ public void testTotalData() throws Exception {
+ final long BUCKET_SIZE = HOUR_IN_MILLIS;
+ stats = new NetworkStatsHistory(BUCKET_SIZE);
+
+ // record uniform data across day
+ stats.recordData(TEST_START, TEST_START + DAY_IN_MILLIS, 2400L, 4800L);
+
+ final long[] total = new long[2];
+
+ // verify that total outside range is 0
+ stats.getTotalData(TEST_START - WEEK_IN_MILLIS, TEST_START - DAY_IN_MILLIS, total);
+ assertTotalEquals(total, 0, 0);
+
+ // verify total in first hour
+ stats.getTotalData(TEST_START, TEST_START + HOUR_IN_MILLIS, total);
+ assertTotalEquals(total, 100, 200);
+
+ // verify total across 1.5 hours
+ stats.getTotalData(TEST_START, TEST_START + (long) (1.5 * HOUR_IN_MILLIS), total);
+ assertTotalEquals(total, 150, 300);
+
+ // verify total beyond end
+ stats.getTotalData(TEST_START + (23 * HOUR_IN_MILLIS), TEST_START + WEEK_IN_MILLIS, total);
+ assertTotalEquals(total, 100, 200);
+
+ // verify everything total
+ stats.getTotalData(TEST_START - WEEK_IN_MILLIS, TEST_START + WEEK_IN_MILLIS, total);
+ assertTotalEquals(total, 2400, 4800);
+
+ }
+
@Suppress
public void testFuzzing() throws Exception {
try {
// fuzzing with random events, looking for crashes
final Random r = new Random();
for (int i = 0; i < 500; i++) {
- stats = buildStats(r.nextLong());
+ stats = new NetworkStatsHistory(r.nextLong());
for (int j = 0; j < 10000; j++) {
if (r.nextBoolean()) {
// add range
@@ -191,10 +291,6 @@ public class NetworkStatsHistoryTest extends TestCase {
}
}
- private static NetworkStatsHistory buildStats(long bucketSize) {
- return new NetworkStatsHistory(TYPE_MOBILE, null, UID_ALL, bucketSize);
- }
-
private static void assertConsistent(NetworkStatsHistory stats) {
// verify timestamps are monotonic
for (int i = 1; i < stats.bucketCount; i++) {
@@ -202,6 +298,11 @@ public class NetworkStatsHistoryTest extends TestCase {
}
}
+ private static void assertTotalEquals(long[] total, long rx, long tx) {
+ assertEquals("unexpected rx", rx, total[0]);
+ assertEquals("unexpected tx", tx, total[1]);
+ }
+
private static void assertBucket(NetworkStatsHistory stats, int index, long rx, long tx) {
assertEquals("unexpected rx", rx, stats.rx[index]);
assertEquals("unexpected tx", tx, stats.tx[index]);
diff --git a/core/tests/coretests/src/android/net/http/AbstractProxyTest.java b/core/tests/coretests/src/android/net/http/AbstractProxyTest.java
index ee8941439d6e..ee4ce95202fd 100644
--- a/core/tests/coretests/src/android/net/http/AbstractProxyTest.java
+++ b/core/tests/coretests/src/android/net/http/AbstractProxyTest.java
@@ -16,6 +16,10 @@
package android.net.http;
+import com.google.mockwebserver.MockResponse;
+import com.google.mockwebserver.MockWebServer;
+import com.google.mockwebserver.RecordedRequest;
+import com.google.mockwebserver.SocketPolicy;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.Reader;
@@ -33,10 +37,6 @@ import org.apache.http.conn.params.ConnRouteParams;
import org.apache.http.conn.scheme.Scheme;
import org.apache.http.conn.ssl.AllowAllHostnameVerifier;
import org.apache.http.conn.ssl.SSLSocketFactory;
-import tests.http.MockResponse;
-import tests.http.MockWebServer;
-import tests.http.RecordedRequest;
-import tests.http.SocketPolicy;
public abstract class AbstractProxyTest extends TestCase {
diff --git a/core/tests/coretests/src/android/net/http/CookiesTest.java b/core/tests/coretests/src/android/net/http/CookiesTest.java
index e736bc9f6e93..29e590f74612 100644
--- a/core/tests/coretests/src/android/net/http/CookiesTest.java
+++ b/core/tests/coretests/src/android/net/http/CookiesTest.java
@@ -16,6 +16,9 @@
package android.net.http;
+import com.google.mockwebserver.MockResponse;
+import com.google.mockwebserver.MockWebServer;
+import com.google.mockwebserver.RecordedRequest;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.net.URISyntaxException;
@@ -30,9 +33,6 @@ import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.conn.params.ConnRoutePNames;
import org.apache.http.impl.client.DefaultHttpClient;
-import tests.http.MockResponse;
-import tests.http.MockWebServer;
-import tests.http.RecordedRequest;
public final class CookiesTest extends TestCase {
diff --git a/core/tests/coretests/src/android/net/http/DefaultHttpClientTest.java b/core/tests/coretests/src/android/net/http/DefaultHttpClientTest.java
index ad3ec3def37d..da772984849c 100644
--- a/core/tests/coretests/src/android/net/http/DefaultHttpClientTest.java
+++ b/core/tests/coretests/src/android/net/http/DefaultHttpClientTest.java
@@ -16,6 +16,12 @@
package android.net.http;
+import com.google.mockwebserver.MockResponse;
+import com.google.mockwebserver.MockWebServer;
+import com.google.mockwebserver.SocketPolicy;
+import static com.google.mockwebserver.SocketPolicy.DISCONNECT_AT_END;
+import static com.google.mockwebserver.SocketPolicy.SHUTDOWN_INPUT_AT_END;
+import static com.google.mockwebserver.SocketPolicy.SHUTDOWN_OUTPUT_AT_END;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.Reader;
@@ -24,12 +30,6 @@ import junit.framework.TestCase;
import org.apache.http.HttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.DefaultHttpClient;
-import tests.http.MockResponse;
-import tests.http.MockWebServer;
-import tests.http.SocketPolicy;
-import static tests.http.SocketPolicy.DISCONNECT_AT_END;
-import static tests.http.SocketPolicy.SHUTDOWN_INPUT_AT_END;
-import static tests.http.SocketPolicy.SHUTDOWN_OUTPUT_AT_END;
public final class DefaultHttpClientTest extends TestCase {
diff --git a/docs/html/guide/topics/graphics/renderscript.jd b/docs/html/guide/topics/graphics/renderscript.jd
index 60bffdb1a49a..180322f55435 100644
--- a/docs/html/guide/topics/graphics/renderscript.jd
+++ b/docs/html/guide/topics/graphics/renderscript.jd
@@ -630,7 +630,7 @@ int root(int launchID) {
<dt><code>ScriptC_helloworld</code></dt>
<dd>This class is generated by the Android build tools and is the reflected version of the
- <code>helloworld.rs</code> Renderscript. It provides a a high level entry point into the
+ <code>helloworld.rs</code> Renderscript. It provides a high level entry point into the
<code>helloworld.rs</code> native code by defining the corresponding methods that you can call
from the traditional framework APIs.</dd>
diff --git a/include/ui/Input.h b/include/ui/Input.h
index 3b5aba4df9a7..c9f694a8f0e9 100644
--- a/include/ui/Input.h
+++ b/include/ui/Input.h
@@ -655,11 +655,6 @@ private:
// Oldest sample to consider when calculating the velocity.
static const nsecs_t MAX_AGE = 200 * 1000000; // 200 ms
- // When the total duration of the window of samples being averaged is less
- // than the window size, the resulting velocity is scaled to reduce the impact
- // of overestimation in short traces.
- static const nsecs_t MIN_WINDOW = 100 * 1000000; // 100 ms
-
// The minimum duration between samples when estimating velocity.
static const nsecs_t MIN_DURATION = 10 * 1000000; // 10 ms
diff --git a/keystore/java/android/security/Credentials.java b/keystore/java/android/security/Credentials.java
index 6b69b8a3f581..fd6c22c2b945 100644
--- a/keystore/java/android/security/Credentials.java
+++ b/keystore/java/android/security/Credentials.java
@@ -20,8 +20,19 @@ import android.content.ActivityNotFoundException;
import android.content.Context;
import android.content.Intent;
import android.util.Log;
-
+import com.android.org.bouncycastle.openssl.PEMReader;
+import com.android.org.bouncycastle.openssl.PEMWriter;
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.io.OutputStreamWriter;
+import java.io.Reader;
+import java.io.Writer;
+import java.nio.charset.Charsets;
import java.security.KeyPair;
+import java.util.ArrayList;
+import java.util.List;
/**
* {@hide}
@@ -60,6 +71,40 @@ public class Credentials {
/** Data type for PKCS12. */
public static final String PKCS12 = "PKCS12";
+ /**
+ * Convert objects to a PEM format, which is used for
+ * CA_CERTIFICATE, USER_CERTIFICATE, and USER_PRIVATE_KEY
+ * entries.
+ */
+ public static byte[] convertToPem(Object... objects) throws IOException {
+ ByteArrayOutputStream bao = new ByteArrayOutputStream();
+ Writer writer = new OutputStreamWriter(bao, Charsets.US_ASCII);
+ PEMWriter pw = new PEMWriter(writer);
+ for (Object o : objects) {
+ pw.writeObject(o);
+ }
+ pw.close();
+ return bao.toByteArray();
+ }
+ /**
+ * Convert objects from PEM format, which is used for
+ * CA_CERTIFICATE, USER_CERTIFICATE, and USER_PRIVATE_KEY
+ * entries.
+ */
+ public static List<Object> convertFromPem(byte[] bytes) throws IOException {
+ ByteArrayInputStream bai = new ByteArrayInputStream(bytes);
+ Reader reader = new InputStreamReader(bai, Charsets.US_ASCII);
+ PEMReader pr = new PEMReader(reader);
+
+ List<Object> result = new ArrayList<Object>();
+ Object o;
+ while ((o = pr.readObject()) != null) {
+ result.add(o);
+ }
+ pr.close();
+ return result;
+ }
+
private static Credentials singleton;
public static Credentials getInstance() {
diff --git a/keystore/java/android/security/KeyChain.java b/keystore/java/android/security/KeyChain.java
index ec820cf77de9..ba784edeed8e 100644
--- a/keystore/java/android/security/KeyChain.java
+++ b/keystore/java/android/security/KeyChain.java
@@ -34,6 +34,7 @@ import java.io.ByteArrayInputStream;
import java.io.Closeable;
import java.io.IOException;
import java.security.KeyFactory;
+import java.security.KeyPair;
import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;
import java.security.cert.Certificate;
@@ -185,11 +186,9 @@ public final class KeyChain {
throw new IllegalArgumentException("bytes == null");
}
try {
- KeyFactory keyFactory = KeyFactory.getInstance("RSA");
- return keyFactory.generatePrivate(new PKCS8EncodedKeySpec(bytes));
- } catch (NoSuchAlgorithmException e) {
- throw new AssertionError(e);
- } catch (InvalidKeySpecException e) {
+ KeyPair keyPair = (KeyPair) Credentials.convertFromPem(bytes).get(0);
+ return keyPair.getPrivate();
+ } catch (IOException e) {
throw new AssertionError(e);
}
}
diff --git a/libs/ui/Input.cpp b/libs/ui/Input.cpp
index e95dbe4745d7..0af7f8043c35 100644
--- a/libs/ui/Input.cpp
+++ b/libs/ui/Input.cpp
@@ -700,7 +700,6 @@ bool MotionEvent::isTouchEvent(int32_t source, int32_t action) {
const uint32_t VelocityTracker::HISTORY_SIZE;
const nsecs_t VelocityTracker::MAX_AGE;
-const nsecs_t VelocityTracker::MIN_WINDOW;
const nsecs_t VelocityTracker::MIN_DURATION;
VelocityTracker::VelocityTracker() {
@@ -891,14 +890,6 @@ bool VelocityTracker::getVelocity(uint32_t id, float* outVx, float* outVy) const
// Make sure we used at least one sample.
if (samplesUsed != 0) {
- // Scale the velocity linearly if the window of samples is small.
- nsecs_t totalDuration = newestMovement.eventTime - oldestMovement.eventTime;
- if (totalDuration < MIN_WINDOW) {
- float scale = float(totalDuration) / float(MIN_WINDOW);
- accumVx *= scale;
- accumVy *= scale;
- }
-
*outVx = accumVx;
*outVy = accumVy;
return true;
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/MediaFrameworkTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/MediaFrameworkTest.java
index 79fd2cb741e0..e7f98de19d77 100644
--- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/MediaFrameworkTest.java
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/MediaFrameworkTest.java
@@ -123,63 +123,6 @@ public class MediaFrameworkTest extends Activity implements SurfaceHolder.Callba
intent.setDataAndType(path, mimetype);
startActivity(intent);
}
-
- @Override public boolean onKeyDown(int keyCode, KeyEvent event) {
- switch (keyCode) {
- case KeyEvent.KEYCODE_0:
- MediaPlayer mp = new MediaPlayer();
- try{
- mp.setDataSource(MediaNames.VIDEO_RTSP3GP);
- Log.v("emily","awb " + testfilepath);
- mp.setDisplay(mSurfaceView.getHolder());
- mp.prepare();
- mp.start();
- }catch (Exception e){}
- break;
-
- //start the music player intent with the test URL from PV
- case KeyEvent.KEYCODE_1:
- startPlayback(MediaNames.STREAM_MP3_1);
- break;
-
- case KeyEvent.KEYCODE_2:
- startPlayback(MediaNames.STREAM_MP3_2);
- break;
-
- case KeyEvent.KEYCODE_3:
- startPlayback(MediaNames.STREAM_MP3_3);
- break;
-
- case KeyEvent.KEYCODE_4:
- startPlayback(MediaNames.STREAM_MP3_4);
- break;
-
- case KeyEvent.KEYCODE_5:
- startPlayback(MediaNames.STREAM_MP3_5);
- break;
-
- case KeyEvent.KEYCODE_6:
- startPlayback(MediaNames.STREAM_MP3_6);
- break;
-
- case KeyEvent.KEYCODE_7:
- startPlayback(MediaNames.STREAM_MP3_7);
- break;
-
- case KeyEvent.KEYCODE_8:
- startPlayback(MediaNames.STREAM_MP3_8);
- break;
-
- case KeyEvent.KEYCODE_9:
- startPlayback(MediaNames.STREAM_MP3_9);
- break;
-
-
-
- }
- return super.onKeyDown(keyCode, event);
-
- }
public static boolean checkStreamingServer() throws Exception {
InetAddress address = InetAddress.getByAddress(MediaNames.STREAM_SERVER);
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/MediaNames.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/MediaNames.java
index ca6e99927042..d6e134679bfe 100755
--- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/MediaNames.java
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/MediaNames.java
@@ -50,19 +50,9 @@ public class MediaNames {
public static final long PAUSE_WAIT_TIME = 3000;
public static final long WAIT_TIME = 2000;
public static final long WAIT_SNAPSHOT_TIME = 5000;
-
- //Streaming Video
- public static final String VIDEO_HTTP3GP = "http://pvs.pv.com/jj/lipsync0.3gp";
- public static final String VIDEO_RTSP3GP = "rtsp://63.241.31.203/public/jj/md.3gp";
- public static final String VIDEO_RTSP3GP2 = "rtsp://pvs.pv.com/public/live_dvd1.3gp";
- public static final String VIDEO_RTSP3GP3 =
- "rtsp://ehug.rtsp-youtube.l.google.com/" +
- "Ci4LENy73wIaJQmeRVCJq4HuQBMYDSANFEIJbXYtZ29vZ2xlSARSB2RldGFpbHMM/0/0/0/video.3gp";
- //public static final String VIDEO_RTSP3GP = "rtsp://193.159.241.21/sp/alizee05.3gp";
-
+
//local video
public static final String VIDEO_MP4 = "/sdcard/media_api/video/MPEG4_320_AAC_64.mp4";
- public static final String VIDEO_LONG_3GP = "/sdcard/media_api/video/radiohead.3gp";
public static final String VIDEO_SHORT_3GP = "/sdcard/media_api/video/short.3gp";
public static final String VIDEO_LARGE_SIZE_3GP = "/sdcard/media_api/video/border_large.3gp";
public static final String VIDEO_H263_AAC = "/sdcard/media_api/video/H263_56_AAC_24.3gp";
@@ -73,205 +63,9 @@ public class MediaNames {
public static final String VIDEO_HIGHRES_H263 = "/sdcard/media_api/video/H263_500_AMRNB_12.3gp";
public static final String VIDEO_HIGHRES_MP4 = "/sdcard/media_api/video/H264_500_AAC_128.3gp";
- //ringtone
- public static final String ringtone = "/sdcard/media_api/ringtones/F1_NewVoicemail.mp3";
-
- //streaming mp3
- public static final String STREAM_MP3_1 =
- "http://wms.pv.com:7070/MediaDownloadContent/mp3/chadthi_jawani_128kbps.mp3";
- public static final String STREAM_MP3_2 =
- "http://wms.pv.com:7070/MediaDownloadContent/mp3/dualStereo.mp3";
- public static final String STREAM_MP3_3 =
- "http://wms.pv.com:7070/mediadownloadcontent/UserUploads/15%20Keep%20Holding%20On.mp3";
- public static final String STREAM_MP3_4 =
- "http://wms.pv.com:7070/mediadownloadcontent/UserUploads/1%20-%20Apologize.mp3";
- public static final String STREAM_MP3_5 =
- "http://wms.pv.com:7070/mediadownloadcontent/UserUploads/" +
- "03%20You're%20Gonna%20Miss%20This.mp3";
- public static final String STREAM_MP3_6 =
- "http://wms.pv.com:7070/mediadownloadcontent/UserUploads" +
- "/02%20Looney%20Tunes%20%C3%82%C2%B7%20Light%20Cavalry%20Overture%20(LP%20Version).mp3";
- public static final String STREAM_MP3_7 =
- "http://wms.pv.com:7070/mediadownloadcontent/UserUploads" +
- "/01%20Love%20Song%20(Album%20Version).mp3";
- public static final String STREAM_MP3_8 =
- "http://wms.pv.com:7070/MediaDownloadContent/UserUploads/1%20-%20Apologize.mp3";
- public static final String STREAM_MP3_9 =
- "http://wms.pv.com:7070/MediaDownloadContent/UserUploads" +
- "/1%20-%20Smile%20(Explicit%20Version).mp3";
- public static final String STREAM_MP3_10 =
- "http://wms.pv.com:7070/MediaDownloadContent/UserUploads/beefcake.mp3";
-
- //Sonivox
- public static String MIDIFILES[] = {
- "/sdcard/media_api/music/Leadsol.mxmf",
- "/sdcard/media_api/music/abba.imy", "/sdcard/media_api/music/ants.mid",
- "/sdcard/media_api/music/greensleeves.rtttl", "/sdcard/media_api/music/test.ota"};
-
- //Performance measurement
- public static String[] WAVFILES = {
- "/sdcard/media_api/music_perf/WAV/M1F1-AlawWE-AFsp.wav",
- "/sdcard/media_api/music_perf/WAV/M1F1-float64-AFsp.wav",
- "/sdcard/media_api/music_perf/WAV/song.wav",
- "/sdcard/media_api/music_perf/WAV/WAVEtest.wav",
- "/sdcard/media_api/music_perf/WAV/WAVEtest_out.wav",
- "/sdcard/media_api/music_perf/WAV/test_out.wav"};
-
- public static String[] AMRNBFILES = {
- "/sdcard/media_api/music_perf/AMR/AI_AMR-NB_5.9kbps_6.24kbps_8khz_mono_NMC.amr",
- "/sdcard/media_api/music_perf/AMR/AI_AMR-NB_5.15kbps_5.46kbps_8khz_mono_NMC.amr",
- "/sdcard/media_api/music_perf/AMR/AI_AMR-NB_7.4kbps_7.80kbps_8khz_mono_NMC.amr",
- "/sdcard/media_api/music_perf/AMR/AI_AMR-NB_7.95kbps_9.6kbps_8khz_mono_NMC.amr",
- "/sdcard/media_api/music_perf/AMR/AI_AMR-NB_10.2kbps_10.48kbps_8khz_mono_NMC.amr"};
-
- public static String[] AMRWBFILES = {
- "/sdcard/media_api/music_perf/AMRWB/NIN_AMR-WB_15.85kbps_16kbps.amr",
- "/sdcard/media_api/music_perf/AMRWB/NIN_AMR-WB_18.25kbps_18kbps.amr",
- "/sdcard/media_api/music_perf/AMRWB/NIN_AMR-WB_19.85kbps_20kbps.amr",
- "/sdcard/media_api/music_perf/AMRWB/NIN_AMR-WB_23.05kbps_23kbps.amr",
- "/sdcard/media_api/music_perf/AMRWB/NIN_AMR-WB_23.85kbps_24kbps.amr",
- "/sdcard/media_api/music_perf/AMRWB/PD_AMR-WB_19.85kbps_20kbps.amr",
- "/sdcard/media_api/music_perf/AMRWB/PD_AMR-WB_23.05kbps_23kbps.amr",
- "/sdcard/media_api/music_perf/AMRWB/PD_AMR-WB_23.85kbps_24kbps.amr",
- "/sdcard/media_api/music_perf/AMRWB/WC_AMR-WB_23.05kbps_23kbps.amr",
- "/sdcard/media_api/music_perf/AMRWB/WC_AMR-WB_23.85kbps_24kbps.amr", };
-
- public static String[] MP3FILES = {
- "/sdcard/media_api/music_perf/MP3/NIN_56kbps_32khz_stereo_VBR_MCA.MP3",
- "/sdcard/media_api/music_perf/MP3/NIN_80kbps_32khz_stereo_VBR_MCA.mp3",
- "/sdcard/media_api/music_perf/MP3/NIN_80kbps_44.1khz_stereo_VBR_MCA.mp3",
- "/sdcard/media_api/music_perf/MP3/NIN_80kbps_48khz_stereo_VBR_MCA.mp3",
- "/sdcard/media_api/music_perf/MP3/NIN_112kbps_32khz_stereo_VBR_MCA.mp3",
- "/sdcard/media_api/music_perf/MP3/NIN_112kbps_44.1khz_stereo_VBR_MCA.mp3",
- "/sdcard/media_api/music_perf/MP3/NIN_112kbps_48khz_stereo_VBR_MCA.mp3",
- "/sdcard/media_api/music_perf/MP3/NIN_192kbps_32khz_mono_CBR_MCA.mp3",
- "/sdcard/media_api/music_perf/MP3/NIN_192kbps_44.1khz_mono_CBR_MCA.mp3",
- "/sdcard/media_api/music_perf/MP3/NIN_192kbps_48khz_mono_CBR_MCA.mp3",
- "/sdcard/media_api/music_perf/MP3/NIN_256kbps_44.1khz_mono_CBR_MCA.mp3",
- "/sdcard/media_api/music_perf/MP3/NIN_256kbps_48khz_mono_CBR_MCA.mp3",
- "/sdcard/media_api/music_perf/MP3/PD_112kbps_32khz_stereo_VBR_MCA.mp3",
- "/sdcard/media_api/music_perf/MP3/PD_112kbps_44.1khz_stereo_VBR_MCA.mp3",
- "/sdcard/media_api/music_perf/MP3/PD_112kbps_48khz_stereo_VBR_MCA.mp3",
- "/sdcard/media_api/music_perf/MP3/PD_192kbps_32khz_mono_CBR_DPA.mp3",
- "/sdcard/media_api/music_perf/MP3/PD_256kbps_44.1khz_mono_CBR_DPA.mp3",
- "/sdcard/media_api/music_perf/MP3/PD_256kbps_48khz_mono_CBR_MCA.mp3",
- "/sdcard/media_api/music_perf/MP3/WC_256kbps_44.1khz_mono_CBR_DPA.mp3",
- "/sdcard/media_api/music_perf/MP3/WC_256kbps_48khz_mono_CBR_DPA.mp3",
- "/sdcard/media_api/music_perf/regular_album_photo/Apologize.mp3",
- "/sdcard/media_api/music_perf/regular_album_photo/Because_Of_You.mp3",
- "/sdcard/media_api/music_perf/regular_album_photo/Complicated.mp3",
- "/sdcard/media_api/music_perf/regular_album_photo/Glamorous.mp3",
- "/sdcard/media_api/music_perf/regular_album_photo/Im_With_You.mp3",
- "/sdcard/media_api/music_perf/regular_album_photo/Smile.mp3",
- "/sdcard/media_api/music_perf/regular_album_photo/Suddenly_I_See.mp3",
- "/sdcard/media_api/music_perf/regular_album_photo/When You Say Nothing At All.mp3",
- "/sdcard/media_api/music_perf/regular_album_photo/my_happy_ending.mp3"};
-
- public static String[] AACFILES = {
- "/sdcard/media_api/music_perf/AAC/AI_AAC_24kbps_12khz_Mono_1pCBR_SSE.mp4",
- "/sdcard/media_api/music_perf/AAC/AI_AAC_56kbps_22.05khz_Stereo_1pCBR_SSE.mp4",
- "/sdcard/media_api/music_perf/AAC/AI_AAC_56kbps_32khz_Stereo_CBR_SSE.mp4",
- "/sdcard/media_api/music_perf/AAC/AI_AAC_56kbps_44.1khz_Stereo_1pCBR_SSE.mp4",
- "/sdcard/media_api/music_perf/AAC/AI_AAC_80kbps_32khz_Stereo_1pCBR_SSE.mp4",
- "/sdcard/media_api/music_perf/AAC/AI_AAC_80kbps_32khz_Stereo_CBR_SSE.mp4",
- "/sdcard/media_api/music_perf/AAC/NIN_AAC_56kbps_22.05khz_Stereo_1pCBR_SSE.mp4",
- "/sdcard/media_api/music_perf/AAC/NIN_AAC_56kbps_32khz_Stereo_CBR_SSE.mp4",
- "/sdcard/media_api/music_perf/AAC/NIN_AAC_56kbps_44.1khz_Stereo_1pCBR_SSE.mp4",
- "/sdcard/media_api/music_perf/AAC/NIN_AAC_80kbps_32khz_Stereo_1pCBR_SSE.mp4",
- "/sdcard/media_api/music_perf/AAC/NIN_AAC_80kbps_32khz_Stereo_CBR_SSE.mp4",
- "/sdcard/media_api/music_perf/AAC/PD_AAC_56kbps_22.05khz_Stereo_1pCBR_SSE.mp4",
- "/sdcard/media_api/music_perf/AAC/PD_AAC_56kbps_32khz_Stereo_CBR_SSE.mp4",
- "/sdcard/media_api/music_perf/AAC/PD_AAC_56kbps_44.1khz_Stereo_1pCBR_SSE.mp4",
- "/sdcard/media_api/music_perf/AAC/PD_AAC_80kbps_32khz_Stereo_1pCBR_SSE.mp4",
- "/sdcard/media_api/music_perf/AAC/PD_AAC_80kbps_32khz_Stereo_CBR_SSE.mp4",
- "/sdcard/media_api/music_perf/AAC/PV_AAC_56kbps_22.05khz_Stereo_1pCBR_SSE.mp4",
- "/sdcard/media_api/music_perf/AAC/PV_AAC_56kbps_32khz_Stereo_CBR_SSE.mp4",
- "/sdcard/media_api/music_perf/AAC/PV_AAC_56kbps_44.1khz_Stereo_1pCBR_SSE.mp4",
- "/sdcard/media_api/music_perf/AAC/PV_AAC_80kbps_32khz_Stereo_1pCBR_SSE.mp4",
- "/sdcard/media_api/music_perf/AAC/PV_AAC_80kbps_32khz_Stereo_CBR_SSE.mp4",
- "/sdcard/media_api/music_perf/AAC/WC_AAC_56kbps_22.05khz_Stereo_1pCBR_SSE.mp4",
- "/sdcard/media_api/music_perf/AAC/WC_AAC_56kbps_32khz_Stereo_CBR_SSE.mp4",
- "/sdcard/media_api/music_perf/AAC/WC_AAC_56kbps_44.1khz_Stereo_1pCBR_SSE.mp4",
- "/sdcard/media_api/music_perf/AAC/WC_AAC_80kbps_32khz_Stereo_1pCBR_SSE.mp4",
- "/sdcard/media_api/music_perf/AAC/WC_AAC_80kbps_32khz_Stereo_CBR_SSE.mp4",
- };
-
- public static String[] VIDEOFILES = { "/sdcard/media_api/video_perf/AI_CTO_Mpeg4_32kbps_10fps_SQCIF_128x96+AAC_8kbps_8khz_mono_QTE.mp4",
- "/sdcard/media_api/video_perf/AI_CTO_Mpeg4_32kbps_12fps_SQCIF_128x96+AAC_8kbps_8khz_mono_QTE.mp4",
- "/sdcard/media_api/video_perf/AI_CTO_Mpeg4_32kbps_15fps_SQCIF_128x96+AAC_8kbps_8khz_mono_QTE.mp4",
- "/sdcard/media_api/video_perf/AI_CTO_Mpeg4_32kbps_5fps_SQCIF_128x96+AAC_8kbps_8khz_mono_QTE.mp4",
- "/sdcard/media_api/video_perf/AI_CTO_Mpeg4_32kbps_5fps_SQCIF_128x96+AAC_8kbps_8khz_mono_SSE.mp4",
- "/sdcard/media_api/video_perf/AI_CTO_Mpeg4_32kbps_7.5fps_SQCIF_128x96+AAC_8kbps_8khz_mono_QTE.mp4",
- "/sdcard/media_api/video_perf/AI_WMV_1024kbps_20fps_QCIF_176x144_noaudio_SSE.wmv",
- "/sdcard/media_api/video_perf/AI_WMV_1024kbps_25fps_QCIF_176x144_noaudio_SSE.wmv",
- "/sdcard/media_api/video_perf/Chicken.wmv",
- "/sdcard/media_api/video_perf/MP_qcif_15fps_100kbps_48kHz_192kbps_30secs.wmv",
- "/sdcard/media_api/video_perf/NIN_CTO_H264_123kbps_5fps_QCIF_176x144+AMR_12.2kbps_8khz_mono_QTE.3gp",
- "/sdcard/media_api/video_perf/NIN_CTO_H264_96kbps_10.2fps_QCIF_176x144+AMR_12.2kbps_8khz_mono_QTE.3gp",
- "/sdcard/media_api/video_perf/NIN_CTO_H264_96kbps_12fps_QCIF_176x144+AMR_12.2kbps_8khz_mono_QTE.3gp",
- "/sdcard/media_api/video_perf/NIN_CTO_H264_96kbps_15fps_QCIF_176x144+AMR_12.2kbps_8khz_mono_QTE.3gp",
- "/sdcard/media_api/video_perf/NIN_CTO_Mpeg4_123kbps_15fps_QCIF_176x144+AAC_32kbps_22khz_mono_SSE.3gp",
- "/sdcard/media_api/video_perf/NIN_CTO_Mpeg4_123kbps_7.5fps_QCIF_176x144+AAC_32kbps_22khz_stereo_SSE.3gp",
- "/sdcard/media_api/video_perf/NIN_CTO_Mpeg4_128kbps_10fps_QCIF_176x144+AAC+_32kbps_48khz_stereo_SSE.3gp",
- "/sdcard/media_api/video_perf/NIN_CTO_Mpeg4_128kbps_12fps_QCIF_176x144+AAC+_32kbps_48khz_stereo_SSE.3gp",
- "/sdcard/media_api/video_perf/NIN_CTO_Mpeg4_128kbps_15fps_QCIF_176x144+AAC+_32kbps_48khz_stereo_SSE.3gp",
- "/sdcard/media_api/video_perf/NIN_CTO_Mpeg4_128kbps_5fps_QCIF_176x144+AAC+_32kbps_48khz_stereo_SSE.3gp",
- "/sdcard/media_api/video_perf/NIN_CTO_Mpeg4_128kbps_7.5fps_QCIF_176x144+AAC+_32kbps_48khz_stereo_SSE.3gp",
- "/sdcard/media_api/video_perf/NIN_H263_128kbps_10fps_QCIF_174x144_noaudio_SSE.mp4",
- "/sdcard/media_api/video_perf/NIN_H263_128kbps_15fps_QCIF_174x144_noaudio_SSE.mp4",
- "/sdcard/media_api/video_perf/NIN_H263_48kbps_10fps_QCIF_174x144_noaudio_SSE.3gp",
- "/sdcard/media_api/video_perf/NIN_H263_48kbps_12fps_QCIF_174x144_noaudio_SSE.3gp",
- "/sdcard/media_api/video_perf/NIN_H264_123kbps_15fps_QCIF_176x144+AAC_32kbps_22khz_stereo_SSE.3gp",
- "/sdcard/media_api/video_perf/NIN_H264_123kbps_7.5fps_QCIF_176x144+AAC_32kbps_22khz_stereo_SSE.3gp",
- "/sdcard/media_api/video_perf/PV_H264_2000kbps_20fps_CIF_352x288+AAC_96kbps_48khz_stereo_SSE.mp4",
- "/sdcard/media_api/video_perf/PV_H264_2000kbps_25fps_CIF_352x288+AAC_96kbps_48khz_stereo_SSE.mp4",
- "/sdcard/media_api/video_perf/PV_H264_2000kbps_30fps_CIF_352x288+AAC_128kbps_48khz_stereo_SSE.mp4",
- "/sdcard/media_api/video_perf/Stevie-1.wmv",
- "/sdcard/media_api/video_perf/WC_H264_1600kbps_20fps_QCIF_176x144+AAC_96kbps_48khz_mono_SSE.mp4",
- "/sdcard/media_api/video_perf/WC_H264_1600kbps_25fps_QCIF_176x144+AAC_96kbps_48khz_mono_SSE.mp4",
- "/sdcard/media_api/video_perf/WC_H264_1600kbps_30fps_QCIF_176x144+AAC_96kbps_48khz_mono_SSE.mp4",
- "/sdcard/media_api/video_perf/bugs.wmv",
- "/sdcard/media_api/video_perf/niceday.wmv",
- "/sdcard/media_api/video_perf/eaglesatopnflpe.wmv",
-
- };
-
- //wma - only support up to wma 9
- public static String[] WMASUPPORTED = {
- "/sdcard/media_api/music_perf/WMASUPPORTED/AI_WMA9.2_32kbps_44.1khz_mono_CBR_DPA.wma",
- "/sdcard/media_api/music_perf/WMASUPPORTED/AI_WMA9.2_48kbps_44.1khz_mono_CBR_DPA.wma",
- "/sdcard/media_api/music_perf/WMASUPPORTED/NIN_WMA9.2_32kbps_44.1khz_mono_CBR_DPA.wma",
- "/sdcard/media_api/music_perf/WMASUPPORTED/NIN_WMA9.2_48kbps_44.1khz_mono_CBR_DPA.wma",
- "/sdcard/media_api/music_perf/WMASUPPORTED/PD_WMA9.2_32kbps_44.1khz_mono_CBR_DPA.wma",
- "/sdcard/media_api/music_perf/WMASUPPORTED/PD_WMA9.2_48kbps_44.1khz_mono_CBR_DPA.wma",
- "/sdcard/media_api/music_perf/WMASUPPORTED/PV_WMA9.2_32kbps_44.1khz_mono_CBR_DPA.wma",
- "/sdcard/media_api/music_perf/WMASUPPORTED/PV_WMA9.2_48kbps_44.1khz_mono_CBR_DPA.wma",
- "/sdcard/media_api/music_perf/WMASUPPORTED/WC_WMA9.2_32kbps_44.1khz_mono_CBR_DPA.wma",
- "/sdcard/media_api/music_perf/WMASUPPORTED/WC_WMA9.2_48kbps_44.1khz_mono_CBR_DPA.wma"
-
- };
-
- public static String[] WMAUNSUPPORTED = {
- "/sdcard/media_api/music_perf/WMAUNSUPPORTED/AI_WMA10_127kbps_48khz_stereo_CBR_DPA.wma",
- "/sdcard/media_api/music_perf/WMAUNSUPPORTED/AI_WMA10_128kbps_44.1khz_stereo_2pVBR_DPA.wma",
- "/sdcard/media_api/music_perf/WMAUNSUPPORTED/AI_WMA10_128kbps_48khz_stereo_2pVBR_DPA.wma",
- "/sdcard/media_api/music_perf/WMAUNSUPPORTED/AI_WMA10_128kbps_88khz_stereo_CBR_DPA.wma",
- "/sdcard/media_api/music_perf/WMAUNSUPPORTED/AI_WMA10_128kbps_96khz_stereo_CBR_DPA.wma",
- "/sdcard/media_api/music_perf/WMAUNSUPPORTED/AI_WMA10_192kbps_44.1khz_stereo_2pVBR_DPA.wma",
- "/sdcard/media_api/music_perf/WMAUNSUPPORTED/AI_WMA10_192kbps_88khz_stereo_CBR_DPA.wma",
- "/sdcard/media_api/music_perf/WMAUNSUPPORTED/AI_WMA10_192kbps_96khz_stereo_CBR_DPA.wma",
- "/sdcard/media_api/music_perf/WMAUNSUPPORTED/AI_WMA10_256kbps_44khz_stereo_CBR_DPA.wma",
- "/sdcard/media_api/music_perf/WMAUNSUPPORTED/AI_WMA10_256kbps_48khz_stereo_CBR_DPA.wma",
- "/sdcard/media_api/music_perf/WMAUNSUPPORTED/AI_WMA10_256kbps_88khz_stereo_CBR_DPA.wma",
- "/sdcard/media_api/music_perf/WMAUNSUPPORTED/AI_WMA10_256kbps_96khz_stereo_CBR_DPA.wma",
- "/sdcard/media_api/music_perf/WMAUNSUPPORTED/AI_WMA10_384kbps_44khz_stereo_CBR_DPA.wma",
- "/sdcard/media_api/music_perf/WMAUNSUPPORTED/AI_WMA10_384kbps_48khz_stereo_CBR_DPA.wma",
- "/sdcard/media_api/music_perf/WMAUNSUPPORTED/AI_WMA10_384kbps_88khz_stereo_CBR_DPA.wma"
- };
-
//Media Recorder
public static final String RECORDER_OUTPUT = "/sdcard/media_api/recorderOutput.amr";
-
+
//video thumbnail
public static final String THUMBNAIL_OUTPUT = "/sdcard/media_api/videoThumbnail.png";
public static final String GOLDEN_THUMBNAIL_OUTPUT = "/sdcard/media_api/goldenThumbnail.png";
@@ -318,7 +112,7 @@ public class MediaNames {
"/sdcard/media_api/metadata/test34.wmv",
"/sdcard/media_api/metadata/test_metadata.mp4",
};
-
+
public static final String[] METADATA_RETRIEVAL_TEST_FILES = {
// Raw AAC is not supported
// "/sdcard/media_api/test_raw.aac",
@@ -405,54 +199,8 @@ public class MediaNames {
null, null, null, null, null, null, "295", "1", null}
};
- public static final String META_DATA_OTHERS [][] = {
- {"/sdcard/media_api/metaDataTestMedias/3GP/cat.3gp", null, null, null,
- null, null, "20080309T002415.000Z", null,
- null, null, "63916", "2", null},
- {"/sdcard/media_api/metaDataTestMedias/AMR/AMR_NB.amr", null, null, null,
- null, null, null, null,
- null, null, "126540", "1", null},
- {"/sdcard/media_api/metaDataTestMedias/AMRWB/AMR_WB.amr", null, null, null,
- null, null, null, null,
- null, null, "231180", "1", null},
- {"/sdcard/media_api/metaDataTestMedias/M4A/Jaws Of Life_ver1.m4a", "1/8", "Suspended Animation",
- "John Petrucci", null, null, "20070510T125223.000Z",
- "12", "Jaws Of Life", "2005", "449329", "1", "m4a composer"},
- {"/sdcard/media_api/metaDataTestMedias/M4V/sample_iPod.m4v", null, null,
- null, null, null, "20051220T202015.000Z",
- null, null, null, "85500", "2", null},
- {"/sdcard/media_api/metaDataTestMedias/MIDI/MIDI.mid", null, "Suspended Animation",
- "John Petrucci", null, null, "20070510T125223.000Z",
- null, null, "2005", "231180", "1", null},
- {"/sdcard/media_api/metaDataTestMedias/MP4/kung_fu_panda_h264.mp4", "2/0", "mp4 album Kung Fu Panda",
- "mp4 artist Kung Fu Panda", null, null, "20080517T091451.000Z",
- "40", "Kung Fu Panda", "2008", "128521", "2", "mp4 composer"},
- {"/sdcard/media_api/metaDataTestMedias/OGG/Ring_Classic_02.ogg", null, "Suspended Animation",
- "John Petrucci", null, null, "20070510T125223.000Z",
- null, null, "2005", "231180", "1", null},
- {"/sdcard/media_api/metaDataTestMedias/OGG/When You Say Nothing At All.ogg",
- null, "Suspended Animation", "John Petrucci",
- null, null, "20070510T125223.000Z", null, null, "2005", "231180", "1", null},
- {"/sdcard/media_api/metaDataTestMedias/WAV/Im With You.wav", null, null,
- null, null, null, null,
- null, null, null, "224000", "1", null},
- {"/sdcard/media_api/metaDataTestMedias/WMA/WMA9.wma", "6", "Ten Songs in the Key of Betrayal",
- "Alien Crime Syndicate", "Alien Crime Syndicate",
- "wma 9 Composer", "20040521T175729.483Z",
- "Rock", "Run for the Money", "2004", "134479", "1", null},
- {"/sdcard/media_api/metaDataTestMedias/WMA/WMA10.wma", "09", "wma 10 Album",
- "wma 10 Album Artist", "wma 10 Artist", "wma 10 Composer", "20070705T063625.097Z",
- "Acid Jazz", "wma 10 Title", "2010", "126574", "1", null},
- {"/sdcard/media_api/metaDataTestMedias/WMV/bugs.wmv", "8", "wmv 9 Album",
- null, "wmv 9 Artist ", null, "20051122T155247.540Z",
- null, "Looney Tunes - Hare-Breadth Hurry", "2005", "193482", "2", null},
- {"/sdcard/media_api/metaDataTestMedias/WMV/clips_ver7.wmv", "50", "wmv 7 Album",
- null, "Hallau Shoots & Company", null, "20020226T170045.891Z",
- null, "CODEC Shootout", "1986", "43709", "2", null}
- };
-
//output recorded video
-
+
public static final String RECORDED_HVGA_H263 = "/sdcard/HVGA_H263.3gp";
public static final String RECORDED_QVGA_H263 = "/sdcard/QVGA_H263.3gp";
public static final String RECORDED_SQVGA_H263 = "/sdcard/SQVGA_H263.3gp";
@@ -474,22 +222,7 @@ public class MediaNames {
public static final long RECORDED_TIME = 5000;
public static final long VALID_VIDEO_DURATION = 2000;
-
- //Videos for the mediaplayer stress test
- public static String[] H263_STRESS = {
- "/sdcard/media_api/video_stress/h263/H263_CIF.3gp",
- "/sdcard/media_api/video_stress/h263/H263_QCIF.3gp",
- "/sdcard/media_api/video_stress/h263/H263_QVGA.3gp",
- "/sdcard/media_api/video_stress/h263/H263_SQVGA.3gp"
- };
-
- public static String[] MPEG4_STRESS = {
- "/sdcard/media_api/video_stress/h263/mpeg4_CIF.mp4",
- "/sdcard/media_api/video_stress/h263/mpeg4_QCIF.3gp",
- "/sdcard/media_api/video_stress/h263/mpeg4_QVGA.3gp",
- "/sdcard/media_api/video_stress/h263/mpeg4_SQVGA.mp4"
- };
-
+
//Streaming test files
public static final byte [] STREAM_SERVER = new byte[] {(byte)75,(byte)17,(byte)48,(byte)204};
public static final String STREAM_H264_480_360_1411k =
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/MediaMetadataTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/MediaMetadataTest.java
index 6ded74df6e4e..00e0a5244bce 100644
--- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/MediaMetadataTest.java
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/MediaMetadataTest.java
@@ -47,14 +47,8 @@ public class MediaMetadataTest extends AndroidTestCase {
CORRUPTED_ID3V2_TYER, CORRUPTED_ID3V2_TYER_2, CORRUPTED_ID3V2_TIT
}
- public static enum NON_MP3_TEST_FILE{
- THREE3GP, AMRNB, AMRWB, M4A1, M4V, MIDI,
- H264, OGG1, OGG2, WAV, WMA9, WMA10, WMV9, WMV7
- }
-
public static METADATA_EXPECTEDRESULT meta;
public static MP3_TEST_FILE mp3_test_file;
- public static NON_MP3_TEST_FILE non_mp3_test_file;
@MediumTest
public static void testID3V1V2Metadata() throws Exception {
@@ -116,88 +110,11 @@ public class MediaMetadataTest extends AndroidTestCase {
validateMetatData(mp3_test_file.CORRUPTED_ID3V2_TIT.ordinal(), MediaNames.META_DATA_MP3);
}
- @MediumTest
- public static void test3gp_Metadata() throws Exception {
- validateMetatData(non_mp3_test_file.THREE3GP.ordinal(), MediaNames.META_DATA_OTHERS);
- }
-
- @MediumTest
- public static void testAmr_Metadata() throws Exception {
- validateMetatData(non_mp3_test_file.AMRNB.ordinal(), MediaNames.META_DATA_OTHERS);
- }
-
- @MediumTest
- public static void testAmrWb_Metadata() throws Exception {
- validateMetatData(non_mp3_test_file.AMRWB.ordinal(), MediaNames.META_DATA_OTHERS);
- }
-
- @MediumTest
- public static void testM4A1_Metadata() throws Exception {
- validateMetatData(non_mp3_test_file.M4A1.ordinal(), MediaNames.META_DATA_OTHERS);
- }
-
- @MediumTest
- public static void testM4v_Metadata() throws Exception {
- validateMetatData(non_mp3_test_file.M4V.ordinal(), MediaNames.META_DATA_OTHERS);
- }
-
- @MediumTest
- public static void testH264_Metadata() throws Exception {
- validateMetatData(non_mp3_test_file.H264.ordinal(), MediaNames.META_DATA_OTHERS);
- }
- //bug# 1440489
- @Suppress
- @MediumTest
- public static void testOgg1_Metadata() throws Exception {
- validateMetatData(non_mp3_test_file.OGG1.ordinal(), MediaNames.META_DATA_OTHERS);
- }
-
- @Suppress
- @MediumTest
- public static void testOgg2_Metadata() throws Exception {
- validateMetatData(non_mp3_test_file.OGG2.ordinal(), MediaNames.META_DATA_OTHERS);
- }
-
- @Suppress
- @MediumTest
- public static void testMidi_Metadata() throws Exception {
- validateMetatData(non_mp3_test_file.MIDI.ordinal(), MediaNames.META_DATA_OTHERS);
- }
-
- @MediumTest
- public static void testWav_Metadata() throws Exception {
- validateMetatData(non_mp3_test_file.WAV.ordinal(), MediaNames.META_DATA_OTHERS);
- }
-
- @Suppress
- @MediumTest
- public static void testWma9_Metadata() throws Exception {
- validateMetatData(non_mp3_test_file.WMA9.ordinal(), MediaNames.META_DATA_OTHERS);
- }
-
- @Suppress
- @MediumTest
- public static void testWma10_Metadata() throws Exception {
- validateMetatData(non_mp3_test_file.WMA10.ordinal(), MediaNames.META_DATA_OTHERS);
- }
-
- @Suppress
- @MediumTest
- public static void testWmv9_Metadata() throws Exception {
- validateMetatData(non_mp3_test_file.WMV9.ordinal(), MediaNames.META_DATA_OTHERS);
- }
-
- @Suppress
- @MediumTest
- public static void testWmv10_Metadata() throws Exception {
- validateMetatData(non_mp3_test_file.WMV7.ordinal(), MediaNames.META_DATA_OTHERS);
- }
private static void validateMetatData(int fileIndex, String meta_data_file[][]) {
Log.v(TAG, "filePath = "+ meta_data_file[fileIndex][0]);
if ((meta_data_file[fileIndex][0].endsWith("wma") && !MediaProfileReader.getWMAEnable()) ||
(meta_data_file[fileIndex][0].endsWith("wmv") && !MediaProfileReader.getWMVEnable())) {
- Log.v(TAG, "Skip test since windows media is not supported");
return;
}
String value = null;
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/MediaPlayerApiTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/MediaPlayerApiTest.java
index d22025cadee2..3a9564d75a0a 100644
--- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/MediaPlayerApiTest.java
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/MediaPlayerApiTest.java
@@ -369,13 +369,7 @@ public class MediaPlayerApiTest extends ActivityInstrumentationTestCase<MediaFra
boolean isSeek = CodecTest.videoSeekTo(MediaNames.VIDEO_MP4);
assertTrue("Local MP4 SeekTo", isSeek);
}
-
- @LargeTest
- public void testVideoLong3gpSeekTo() throws Exception {
- boolean isSeek = CodecTest.videoSeekTo(MediaNames.VIDEO_LONG_3GP);
- assertTrue("Local 3gp SeekTo", isSeek);
- }
-
+
@LargeTest
public void testVideoH263AACSeekTo() throws Exception {
boolean isSeek = CodecTest.videoSeekTo(MediaNames.VIDEO_H263_AAC);
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/performance/MediaPlayerPerformance.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/performance/MediaPlayerPerformance.java
index 34affa7b1cb7..3b5b9a3b4e05 100644
--- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/performance/MediaPlayerPerformance.java
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/performance/MediaPlayerPerformance.java
@@ -100,109 +100,6 @@ public class MediaPlayerPerformance extends ActivityInstrumentationTestCase2<Med
MediaTestUtil.getNativeHeapDump(this.getName() + "_after");
}
- public void createDB() {
- mDB = SQLiteDatabase.openOrCreateDatabase("/sdcard/perf.db", null);
- mDB.execSQL("CREATE TABLE IF NOT EXISTS perfdata (_id INTEGER PRIMARY KEY," +
- "file TEXT," + "setdatatime LONG," + "preparetime LONG," +
- "playtime LONG" + ");");
- //clean the table before adding new data
- mDB.execSQL("DELETE FROM perfdata");
- }
-
- public void audioPlaybackStartupTime(String[] testFile) {
- long t1 = 0;
- long t2 = 0;
- long t3 = 0;
- long t4 = 0;
- long setDataSourceDuration = 0;
- long prepareDuration = 0;
- long startDuration = 0;
- long totalSetDataTime = 0;
- long totalPrepareTime = 0;
- long totalStartDuration = 0;
-
- int numberOfFiles = testFile.length;
- Log.v(TAG, "File length " + numberOfFiles);
- for (int k = 0; k < numberOfFiles; k++) {
- MediaPlayer mp = new MediaPlayer();
- try {
- t1 = SystemClock.uptimeMillis();
- FileInputStream fis = new FileInputStream(testFile[k]);
- FileDescriptor fd = fis.getFD();
- mp.setDataSource(fd);
- fis.close();
- t2 = SystemClock.uptimeMillis();
- mp.prepare();
- t3 = SystemClock.uptimeMillis();
- mp.start();
- t4 = SystemClock.uptimeMillis();
- } catch (Exception e) {
- Log.v(TAG, e.toString());
- }
- setDataSourceDuration = t2 - t1;
- prepareDuration = t3 - t2;
- startDuration = t4 - t3;
- totalSetDataTime = totalSetDataTime + setDataSourceDuration;
- totalPrepareTime = totalPrepareTime + prepareDuration;
- totalStartDuration = totalStartDuration + startDuration;
- mDB.execSQL("INSERT INTO perfdata (file, setdatatime, preparetime," +
- " playtime) VALUES (" + '"' + testFile[k] + '"' + ',' +
- setDataSourceDuration + ',' + prepareDuration +
- ',' + startDuration + ");");
- Log.v(TAG, "File name " + testFile[k]);
- mp.stop();
- mp.release();
- }
- Log.v(TAG, "setDataSource average " + totalSetDataTime / numberOfFiles);
- Log.v(TAG, "prepare average " + totalPrepareTime / numberOfFiles);
- Log.v(TAG, "start average " + totalStartDuration / numberOfFiles);
-
- }
-
- @Suppress
- public void testStartUpTime() throws Exception {
- createDB();
- audioPlaybackStartupTime(MediaNames.MP3FILES);
- audioPlaybackStartupTime(MediaNames.AACFILES);
-
- //close the database after all transactions
- if (mDB.isOpen()) {
- mDB.close();
- }
- }
-
- public void wmametadatautility(String[] testFile) {
- long t1 = 0;
- long t2 = 0;
- long sum = 0;
- long duration = 0;
- MediaMetadataRetriever retriever = new MediaMetadataRetriever();
- String value;
- for (int i = 0, n = testFile.length; i < n; ++i) {
- try {
- t1 = SystemClock.uptimeMillis();
- retriever.setDataSource(testFile[i]);
- value = retriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_ALBUM);
- value = retriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_ARTIST);
- value = retriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_COMPOSER);
- value = retriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_GENRE);
- value = retriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_TITLE);
- value = retriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_YEAR);
- value =
- retriever
- .extractMetadata(MediaMetadataRetriever.METADATA_KEY_CD_TRACK_NUMBER);
- t2 = SystemClock.uptimeMillis();
- duration = t2 - t1;
- Log.v(TAG, "Time taken = " + duration);
- sum = sum + duration;
- } catch (Exception e) {
- Log.v(TAG, e.getMessage());
- }
-
- }
- Log.v(TAG, "Average duration = " + sum / testFile.length);
- }
-
private void initializeMessageLooper() {
final ConditionVariable startDone = new ConditionVariable();
new Thread() {
@@ -421,13 +318,6 @@ public class MediaPlayerPerformance extends ActivityInstrumentationTestCase2<Med
return true;
}
- @Suppress
- public void testWmaParseTime() throws Exception {
- // createDB();
- wmametadatautility(MediaNames.WMASUPPORTED);
- }
-
-
// Test case 1: Capture the memory usage after every 20 h263 playback
@LargeTest
public void testH263VideoPlaybackMemoryUsage() throws Exception {
diff --git a/packages/BackupRestoreConfirmation/src/com/android/backupconfirm/BackupRestoreConfirmation.java b/packages/BackupRestoreConfirmation/src/com/android/backupconfirm/BackupRestoreConfirmation.java
index 52bfc2850681..ed413e693701 100644
--- a/packages/BackupRestoreConfirmation/src/com/android/backupconfirm/BackupRestoreConfirmation.java
+++ b/packages/BackupRestoreConfirmation/src/com/android/backupconfirm/BackupRestoreConfirmation.java
@@ -60,6 +60,7 @@ public class BackupRestoreConfirmation extends Activity {
IBackupManager mBackupManager;
FullObserver mObserver;
int mToken;
+ boolean mDidAcknowledge;
TextView mStatusView;
Button mAllowButton;
@@ -70,6 +71,7 @@ public class BackupRestoreConfirmation extends Activity {
Context mContext;
ObserverHandler(Context context) {
mContext = context;
+ mDidAcknowledge = false;
}
@Override
@@ -157,11 +159,7 @@ public class BackupRestoreConfirmation extends Activity {
mAllowButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
- try {
- mBackupManager.acknowledgeFullBackupOrRestore(mToken, true, mObserver);
- } catch (RemoteException e) {
- // TODO: bail gracefully if we can't contact the backup manager
- }
+ sendAcknowledgement(mToken, true, mObserver);
mAllowButton.setEnabled(false);
mDenyButton.setEnabled(false);
}
@@ -170,11 +168,7 @@ public class BackupRestoreConfirmation extends Activity {
mDenyButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
- try {
- mBackupManager.acknowledgeFullBackupOrRestore(mToken, false, mObserver);
- } catch (RemoteException e) {
- // TODO: bail gracefully if we can't contact the backup manager
- }
+ sendAcknowledgement(mToken, false, mObserver);
mAllowButton.setEnabled(false);
mDenyButton.setEnabled(false);
}
@@ -187,14 +181,21 @@ public class BackupRestoreConfirmation extends Activity {
// We explicitly equate departure from the UI with refusal. This includes the
// implicit configuration-changed stop/restart cycle.
- try {
- mBackupManager.acknowledgeFullBackupOrRestore(mToken, false, null);
- } catch (RemoteException e) {
- // if this fails we'll still time out with no acknowledgment
- }
+ sendAcknowledgement(mToken, false, null);
finish();
}
+ void sendAcknowledgement(int token, boolean allow, IFullBackupRestoreObserver observer) {
+ if (!mDidAcknowledge) {
+ mDidAcknowledge = true;
+ try {
+ mBackupManager.acknowledgeFullBackupOrRestore(mToken, true, mObserver);
+ } catch (RemoteException e) {
+ // TODO: bail gracefully if we can't contact the backup manager
+ }
+ }
+ }
+
/**
* The observer binder for showing backup/restore progress. This binder just bounces
* the notifications onto the main thread.
diff --git a/packages/SharedStorageBackup/Android.mk b/packages/SharedStorageBackup/Android.mk
new file mode 100644
index 000000000000..1d4f4da70d0d
--- /dev/null
+++ b/packages/SharedStorageBackup/Android.mk
@@ -0,0 +1,33 @@
+#
+# Copyright (C) 2011 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_MODULE_TAGS := optional
+
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
+
+LOCAL_PROGUARD_FLAG_FILES := proguard.flags
+
+LOCAL_PACKAGE_NAME := SharedStorageBackup
+LOCAL_CERTIFICATE := platform
+
+include $(BUILD_PACKAGE)
+
+########################
+include $(call all-makefiles-under,$(LOCAL_PATH))
+
diff --git a/packages/SharedStorageBackup/AndroidManifest.xml b/packages/SharedStorageBackup/AndroidManifest.xml
new file mode 100644
index 000000000000..258059c54fce
--- /dev/null
+++ b/packages/SharedStorageBackup/AndroidManifest.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+** Copyright 2011, 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.
+-->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.android.sharedstoragebackup" >
+
+ <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
+ <uses-permission android:name="android.permission.WRITE_MEDIA_STORAGE" />
+
+ <application android:allowClearUserData="false"
+ android:permission="android.permission.CONFIRM_FULL_BACKUP"
+ android:fullBackupAgent=".SharedStorageAgent"
+ android:allowBackup="false" >
+ </application>
+</manifest>
diff --git a/packages/SharedStorageBackup/proguard.flags b/packages/SharedStorageBackup/proguard.flags
new file mode 100644
index 000000000000..f43cb819b190
--- /dev/null
+++ b/packages/SharedStorageBackup/proguard.flags
@@ -0,0 +1 @@
+-keep class com.android.sharedstoragebackup.SharedStorageAgent
diff --git a/packages/SharedStorageBackup/src/com/android/sharedstoragebackup/SharedStorageAgent.java b/packages/SharedStorageBackup/src/com/android/sharedstoragebackup/SharedStorageAgent.java
new file mode 100644
index 000000000000..b02ca2e761ec
--- /dev/null
+++ b/packages/SharedStorageBackup/src/com/android/sharedstoragebackup/SharedStorageAgent.java
@@ -0,0 +1,93 @@
+package com.android.sharedstoragebackup;
+
+import android.app.backup.FullBackup;
+import android.app.backup.FullBackupAgent;
+import android.app.backup.BackupDataInput;
+import android.app.backup.BackupDataOutput;
+import android.content.Context;
+import android.os.Environment;
+import android.os.ParcelFileDescriptor;
+import android.os.storage.StorageManager;
+import android.os.storage.StorageVolume;
+import android.util.Slog;
+
+import java.io.File;
+import java.io.IOException;
+
+public class SharedStorageAgent extends FullBackupAgent {
+ static final String TAG = "SharedStorageAgent";
+ static final boolean DEBUG = true;
+
+ StorageVolume[] mVolumes;
+
+ @Override
+ public void onCreate() {
+ StorageManager mgr = (StorageManager) getSystemService(Context.STORAGE_SERVICE);
+ if (mgr != null) {
+ mVolumes = mgr.getVolumeList();
+ } else {
+ Slog.e(TAG, "Unable to access Storage Manager");
+ }
+ }
+
+ @Override
+ public void onBackup(ParcelFileDescriptor oldState, BackupDataOutput data,
+ ParcelFileDescriptor newState) throws IOException {
+ // If there are shared-storage volumes available, run the inherited directory-
+ // hierarchy backup process on them. By convention in the Storage Manager, the
+ // "primary" shared storage volume is first in the list.
+ if (mVolumes != null) {
+ for (int i = 0; i < mVolumes.length; i++) {
+ StorageVolume v = mVolumes[i];
+ // Express the contents of volume N this way in the tar stream:
+ // shared/N/path/to/file
+ // The restore will then extract to the given volume
+ String domain = FullBackup.SHARED_PREFIX + i;
+ processTree(null, domain, v.getPath(), null, data);
+ }
+ }
+ }
+
+ /**
+ * Incremental onRestore() implementation is not used.
+ */
+ @Override
+ public void onRestore(BackupDataInput data, int appVersionCode, ParcelFileDescriptor newState)
+ throws IOException {
+ }
+
+ /**
+ * Full restore of one file to shared storage
+ */
+ @Override
+ public void onRestoreFile(ParcelFileDescriptor data, long size,
+ int type, String domain, String relpath, long mode, long mtime)
+ throws IOException {
+ Slog.d(TAG, "Shared restore: [ " + domain + " : " + relpath + "]");
+
+ File outFile = null;
+
+ // The file path must be in the semantic form [number]/path/to/file...
+ int slash = relpath.indexOf('/');
+ if (slash > 0) {
+ try {
+ int i = Integer.parseInt(relpath.substring(0, slash));
+ if (i <= mVolumes.length) {
+ outFile = new File(mVolumes[i].getPath(), relpath.substring(slash + 1));
+ if (DEBUG) Slog.i(TAG, " => " + outFile.getAbsolutePath());
+ } else {
+ Slog.w(TAG, "Cannot restore data for unavailable volume " + i);
+ }
+ } catch (NumberFormatException e) {
+ if (DEBUG) Slog.w(TAG, "Bad volume number token: " + relpath.substring(0, slash));
+ }
+ } else {
+ if (DEBUG) Slog.i(TAG, "Can't find volume-number token");
+ }
+ if (outFile == null) {
+ Slog.e(TAG, "Skipping data with malformed path " + relpath);
+ }
+
+ FullBackup.restoreToFile(data, size, type, mode, mtime, outFile, false);
+ }
+}
diff --git a/packages/SystemUI/res/drawable-sw600dp-hdpi/ic_sysbar_zoom_default.png b/packages/SystemUI/res/drawable-sw600dp-hdpi/ic_sysbar_zoom_default.png
new file mode 100644
index 000000000000..e2584e3a2f9a
--- /dev/null
+++ b/packages/SystemUI/res/drawable-sw600dp-hdpi/ic_sysbar_zoom_default.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw600dp-hdpi/ic_sysbar_zoom_pressed.png b/packages/SystemUI/res/drawable-sw600dp-hdpi/ic_sysbar_zoom_pressed.png
new file mode 100644
index 000000000000..58b85102d9b3
--- /dev/null
+++ b/packages/SystemUI/res/drawable-sw600dp-hdpi/ic_sysbar_zoom_pressed.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw600dp-mdpi/ic_sysbar_zoom_default.png b/packages/SystemUI/res/drawable-sw600dp-mdpi/ic_sysbar_zoom_default.png
new file mode 100644
index 000000000000..2795c345f62e
--- /dev/null
+++ b/packages/SystemUI/res/drawable-sw600dp-mdpi/ic_sysbar_zoom_default.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw600dp-mdpi/ic_sysbar_zoom_pressed.png b/packages/SystemUI/res/drawable-sw600dp-mdpi/ic_sysbar_zoom_pressed.png
new file mode 100644
index 000000000000..bbed6a6467d6
--- /dev/null
+++ b/packages/SystemUI/res/drawable-sw600dp-mdpi/ic_sysbar_zoom_pressed.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable/ic_sysbar_zoom.xml b/packages/SystemUI/res/drawable/ic_sysbar_zoom.xml
new file mode 100644
index 000000000000..977e00205e6f
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_sysbar_zoom.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2011 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+ <item android:state_pressed="true" android:drawable="@drawable/ic_sysbar_zoom_pressed" />
+ <item android:drawable="@drawable/ic_sysbar_zoom_default" />
+</selector>
+
diff --git a/packages/SystemUI/res/layout-sw600dp/status_bar.xml b/packages/SystemUI/res/layout-sw600dp/status_bar.xml
index d9f3f2324499..707a8cb56f73 100644
--- a/packages/SystemUI/res/layout-sw600dp/status_bar.xml
+++ b/packages/SystemUI/res/layout-sw600dp/status_bar.xml
@@ -75,6 +75,13 @@
systemui:keyCode="82"
android:visibility="invisible"
/>
+ <com.android.systemui.statusbar.policy.CompatModeButton
+ android:id="@+id/compat_button"
+ android:layout_width="80dip"
+ android:layout_height="match_parent"
+ android:src="@drawable/ic_sysbar_zoom"
+ android:visibility="invisible"
+ />
</LinearLayout>
<!-- fake space bar zone -->
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/CompatModeButton.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/CompatModeButton.java
new file mode 100644
index 000000000000..9b44f7893cde
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/CompatModeButton.java
@@ -0,0 +1,63 @@
+/*
+ * 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.app.ActivityManager;
+import android.content.Context;
+import android.content.res.TypedArray;
+import android.os.RemoteException;
+import android.util.AttributeSet;
+import android.util.Slog;
+import android.view.View;
+import android.widget.ImageView;
+
+import com.android.systemui.R;
+
+public class CompatModeButton extends ImageView implements View.OnClickListener {
+ private static final String TAG = "StatusBar.CompatModeButton";
+
+ private ActivityManager mAM;
+
+ public CompatModeButton(Context context, AttributeSet attrs) {
+ this(context, attrs, 0);
+ }
+
+ public CompatModeButton(Context context, AttributeSet attrs, int defStyle) {
+ super(context, attrs);
+
+ setClickable(true);
+
+ mAM = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
+
+ setOnClickListener(this);
+
+ refresh();
+ }
+
+ @Override
+ public void onClick(View v) {
+ mAM.setFrontActivityScreenCompatMode(ActivityManager.COMPAT_MODE_TOGGLE);
+ }
+
+ public void refresh() {
+ setVisibility(
+ (mAM.getFrontActivityScreenCompatMode() == ActivityManager.COMPAT_MODE_NEVER)
+ ? View.GONE
+ : View.VISIBLE
+ );
+ }
+}
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 70a78df493e4..3175a99fb482 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkController.java
@@ -446,12 +446,14 @@ public class NetworkController extends BroadcastReceiver {
}
boolean isCdmaEri() {
- final int iconIndex = mServiceState.getCdmaEriIconIndex();
- if (iconIndex != EriInfo.ROAMING_INDICATOR_OFF) {
- final int iconMode = mServiceState.getCdmaEriIconMode();
- if (iconMode == EriInfo.ROAMING_ICON_MODE_NORMAL
- || iconMode == EriInfo.ROAMING_ICON_MODE_FLASH) {
- return true;
+ if (mServiceState != null) {
+ final int iconIndex = mServiceState.getCdmaEriIconIndex();
+ if (iconIndex != EriInfo.ROAMING_INDICATOR_OFF) {
+ final int iconMode = mServiceState.getCdmaEriIconMode();
+ if (iconMode == EriInfo.ROAMING_ICON_MODE_NORMAL
+ || iconMode == EriInfo.ROAMING_ICON_MODE_FLASH) {
+ return true;
+ }
}
}
return false;
@@ -854,7 +856,7 @@ public class NetworkController extends BroadcastReceiver {
pw.print(" mDataActivity=");
pw.println(mDataActivity);
pw.print(" mServiceState=");
- pw.println(mServiceState.toString());
+ pw.println(mServiceState);
pw.print(" mNetworkName=");
pw.println(mNetworkName);
pw.print(" mNetworkNameDefault=");
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletStatusBar.java
index 5b5801df8f46..ffb45ca5abcf 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletStatusBar.java
@@ -69,6 +69,7 @@ import com.android.systemui.R;
import com.android.systemui.statusbar.*;
import com.android.systemui.statusbar.policy.BatteryController;
import com.android.systemui.statusbar.policy.BluetoothController;
+import com.android.systemui.statusbar.policy.CompatModeButton;
import com.android.systemui.statusbar.policy.LocationController;
import com.android.systemui.statusbar.policy.NetworkController;
import com.android.systemui.statusbar.policy.Prefs;
@@ -963,6 +964,10 @@ public class TabletStatusBar extends StatusBar implements
// See above re: lights-out policy for legacy apps.
if (visible) setLightsOn(true);
+
+ // XXX: HACK: not sure if this is the best way to catch a new activity that might require a
+ // change in compatibility features, but it's a start.
+ ((CompatModeButton) mBarContents.findViewById(R.id.compat_button)).refresh();
}
public void setImeWindowStatus(IBinder token, int vis, int backDisposition) {
diff --git a/services/camera/libcameraservice/CameraHardwareInterface.h b/services/camera/libcameraservice/CameraHardwareInterface.h
index f9fa30e47ddb..7a18831f6fc4 100644
--- a/services/camera/libcameraservice/CameraHardwareInterface.h
+++ b/services/camera/libcameraservice/CameraHardwareInterface.h
@@ -438,18 +438,23 @@ private:
}
static void __data_cb(int32_t msg_type,
- const camera_memory_t *data,
+ const camera_memory_t *data, unsigned int index,
void *user)
{
LOGV("%s", __FUNCTION__);
CameraHardwareInterface *__this =
static_cast<CameraHardwareInterface *>(user);
sp<CameraHeapMemory> mem(static_cast<CameraHeapMemory *>(data->handle));
- __this->mDataCb(msg_type, mem, __this->mCbUser);
+ if (index >= mem->mNumBufs) {
+ LOGE("%s: invalid buffer index %d, max allowed is %d", __FUNCTION__,
+ index, mem->mNumBufs);
+ return;
+ }
+ __this->mDataCb(msg_type, mem->mBuffers[index], __this->mCbUser);
}
static void __data_cb_timestamp(nsecs_t timestamp, int32_t msg_type,
- const camera_memory_t *data,
+ const camera_memory_t *data, unsigned index,
void *user)
{
LOGV("%s", __FUNCTION__);
@@ -459,38 +464,85 @@ private:
// drop all references, it will be destroyed (as well as the enclosed
// MemoryHeapBase.
sp<CameraHeapMemory> mem(static_cast<CameraHeapMemory *>(data->handle));
- __this->mDataCbTimestamp(timestamp, msg_type, mem, __this->mCbUser);
+ if (index >= mem->mNumBufs) {
+ LOGE("%s: invalid buffer index %d, max allowed is %d", __FUNCTION__,
+ index, mem->mNumBufs);
+ return;
+ }
+ __this->mDataCbTimestamp(timestamp, msg_type, mem->mBuffers[index], __this->mCbUser);
}
// This is a utility class that combines a MemoryHeapBase and a MemoryBase
// in one. Since we tend to use them in a one-to-one relationship, this is
// handy.
- class CameraHeapMemory : public MemoryBase {
+ class CameraHeapMemory : public RefBase {
public:
- CameraHeapMemory(size_t size) :
- MemoryBase(new MemoryHeapBase(size), 0, size)
+ CameraHeapMemory(int fd, size_t buf_size, uint_t num_buffers = 1) :
+ mBufSize(buf_size),
+ mNumBufs(num_buffers)
+ {
+ mHeap = new MemoryHeapBase(fd, buf_size * num_buffers);
+ commonInitialization();
+ }
+
+ CameraHeapMemory(size_t buf_size, uint_t num_buffers = 1) :
+ mBufSize(buf_size),
+ mNumBufs(num_buffers)
{
- handle.data = getHeap()->base();
- handle.size = size;
+ mHeap = new MemoryHeapBase(buf_size * num_buffers);
+ commonInitialization();
+ }
+
+ void commonInitialization()
+ {
+ handle.data = mHeap->base();
+ handle.size = mBufSize * mNumBufs;
handle.handle = this;
+
+ mBuffers = new sp<MemoryBase>[mNumBufs];
+ for (uint_t i = 0; i < mNumBufs; i++)
+ mBuffers[i] = new MemoryBase(mHeap,
+ i * mBufSize,
+ mBufSize);
+
+ handle.release = __put_memory;
}
+ virtual ~CameraHeapMemory()
+ {
+ delete [] mBuffers;
+ }
+
+ size_t mBufSize;
+ uint_t mNumBufs;
+ sp<MemoryHeapBase> mHeap;
+ sp<MemoryBase> *mBuffers;
+
camera_memory_t handle;
};
- static camera_memory_t* __get_memory(size_t size,
- void *user __attribute__((unused)))
+ static camera_memory_t* __get_memory(int fd, size_t buf_size, uint_t num_bufs,
+ void *user __attribute__((unused)))
{
- // We allocate the object here, but we do not assign it to a strong
- // pointer yet. The HAL will pass it back to us via the data callback
- // or the data-timestamp callback, and from there on we will wrap it
- // within a strong pointer.
-
- CameraHeapMemory *mem = new CameraHeapMemory(size);
+ CameraHeapMemory *mem;
+ if (fd < 0)
+ mem = new CameraHeapMemory(buf_size, num_bufs);
+ else
+ mem = new CameraHeapMemory(fd, buf_size, num_bufs);
+ mem->incStrong(mem);
return &mem->handle;
}
+ static void __put_memory(camera_memory_t *data)
+ {
+ if (!data)
+ return;
+
+ CameraHeapMemory *mem = static_cast<CameraHeapMemory *>(data->handle);
+ mem->decStrong(mem);
+ }
+
static ANativeWindow *__to_anw(void *user)
{
CameraHardwareInterface *__this =
@@ -541,7 +593,7 @@ private:
static int __set_buffer_count(struct preview_stream_ops* w, int count)
{
ANativeWindow *a = anw(w);
- return native_window_set_buffer_count(a, count);
+ return native_window_set_buffer_count(a, count);
}
static int __set_buffers_geometry(struct preview_stream_ops* w,
diff --git a/services/input/InputReader.cpp b/services/input/InputReader.cpp
index c42e3abcd4f3..09b24a8ef1ed 100644
--- a/services/input/InputReader.cpp
+++ b/services/input/InputReader.cpp
@@ -200,23 +200,6 @@ static int32_t calculateEdgeFlagsUsingPointerBounds(
return edgeFlags;
}
-static void clampPositionUsingPointerBounds(
- const sp<PointerControllerInterface>& pointerController, float* x, float* y) {
- float minX, minY, maxX, maxY;
- if (pointerController->getBounds(&minX, &minY, &maxX, &maxY)) {
- if (*x < minX) {
- *x = minX;
- } else if (*x > maxX) {
- *x = maxX;
- }
- if (*y < minY) {
- *y = minY;
- } else if (*y > maxY) {
- *y = maxY;
- }
- }
-}
-
static float calculateCommonVector(float a, float b) {
if (a > 0 && b > 0) {
return a < b ? a : b;
@@ -787,8 +770,8 @@ void InputReader::dump(String8& dump) {
mConfig.pointerGestureTapSlop);
dump.appendFormat(INDENT3 "MultitouchSettleInterval: %0.1fms\n",
mConfig.pointerGestureMultitouchSettleInterval * 0.000001f);
- dump.appendFormat(INDENT3 "MultitouchMinSpeed: %0.1fpx/s\n",
- mConfig.pointerGestureMultitouchMinSpeed);
+ dump.appendFormat(INDENT3 "MultitouchMinDistance: %0.1fpx\n",
+ mConfig.pointerGestureMultitouchMinDistance);
dump.appendFormat(INDENT3 "SwipeTransitionAngleCosine: %0.1f\n",
mConfig.pointerGestureSwipeTransitionAngleCosine);
dump.appendFormat(INDENT3 "SwipeMaxWidthRatio: %0.1f\n",
@@ -3509,11 +3492,18 @@ void TouchInputMapper::dispatchPointerGestures(nsecs_t when, uint32_t policyFlag
cancelPreviousGesture = false;
}
- // Switch pointer presentation.
- mPointerController->setPresentation(
- mParameters.gestureMode == Parameters::GESTURE_MODE_SPOTS
- ? PointerControllerInterface::PRESENTATION_SPOT
- : PointerControllerInterface::PRESENTATION_POINTER);
+ // Update the pointer presentation and spots.
+ if (mParameters.gestureMode == Parameters::GESTURE_MODE_SPOTS) {
+ mPointerController->setPresentation(PointerControllerInterface::PRESENTATION_SPOT);
+ if (finishPreviousGesture || cancelPreviousGesture) {
+ mPointerController->clearSpots();
+ }
+ mPointerController->setSpots(mPointerGesture.currentGestureCoords,
+ mPointerGesture.currentGestureIdToIndex,
+ mPointerGesture.currentGestureIdBits);
+ } else {
+ mPointerController->setPresentation(PointerControllerInterface::PRESENTATION_POINTER);
+ }
// Show or hide the pointer if needed.
switch (mPointerGesture.currentGestureMode) {
@@ -3712,12 +3702,6 @@ bool TouchInputMapper::preparePointerGestures(nsecs_t when,
mPointerGesture.currentGestureIdBits.clear();
mPointerGesture.pointerVelocityControl.reset();
-
- if (mParameters.gestureMode == Parameters::GESTURE_MODE_SPOTS) {
- mPointerGesture.spotGesture = PointerControllerInterface::SPOT_GESTURE_NEUTRAL;
- mPointerGesture.spotIdBits.clear();
- moveSpotsLocked();
- }
return true;
}
}
@@ -3798,22 +3782,18 @@ bool TouchInputMapper::preparePointerGestures(nsecs_t when,
if (isQuietTime) {
// Case 1: Quiet time. (QUIET)
#if DEBUG_GESTURES
- LOGD("Gestures: QUIET for next %0.3fms",
- (mPointerGesture.quietTime + QUIET_INTERVAL - when) * 0.000001f);
+ LOGD("Gestures: QUIET for next %0.3fms", (mPointerGesture.quietTime
+ + mConfig->pointerGestureQuietInterval - when) * 0.000001f);
#endif
- *outFinishPreviousGesture = true;
+ if (mPointerGesture.lastGestureMode != PointerGesture::QUIET) {
+ *outFinishPreviousGesture = true;
+ }
mPointerGesture.activeGestureId = -1;
mPointerGesture.currentGestureMode = PointerGesture::QUIET;
mPointerGesture.currentGestureIdBits.clear();
mPointerGesture.pointerVelocityControl.reset();
-
- if (mParameters.gestureMode == Parameters::GESTURE_MODE_SPOTS) {
- mPointerGesture.spotGesture = PointerControllerInterface::SPOT_GESTURE_NEUTRAL;
- mPointerGesture.spotIdBits.clear();
- moveSpotsLocked();
- }
} else if (isPointerDown(mCurrentTouch.buttonState)) {
// Case 2: Button is pressed. (BUTTON_CLICK_OR_DRAG)
// The pointer follows the active touch point.
@@ -3899,32 +3879,11 @@ bool TouchInputMapper::preparePointerGestures(nsecs_t when,
mPointerGesture.currentGestureCoords[0].setAxisValue(AMOTION_EVENT_AXIS_X, x);
mPointerGesture.currentGestureCoords[0].setAxisValue(AMOTION_EVENT_AXIS_Y, y);
mPointerGesture.currentGestureCoords[0].setAxisValue(AMOTION_EVENT_AXIS_PRESSURE, 1.0f);
-
- if (mParameters.gestureMode == Parameters::GESTURE_MODE_SPOTS) {
- if (activeTouchId >= 0) {
- // Collapse all spots into one point at the pointer location.
- mPointerGesture.spotGesture = PointerControllerInterface::SPOT_GESTURE_BUTTON_DRAG;
- mPointerGesture.spotIdBits.clear();
- for (uint32_t i = 0; i < mCurrentTouch.pointerCount; i++) {
- uint32_t id = mCurrentTouch.pointers[i].id;
- mPointerGesture.spotIdBits.markBit(id);
- mPointerGesture.spotIdToIndex[id] = i;
- mPointerGesture.spotCoords[i] = mPointerGesture.currentGestureCoords[0];
- }
- } else {
- // No fingers. Generate a spot at the pointer location so the
- // anchor appears to be pressed.
- mPointerGesture.spotGesture = PointerControllerInterface::SPOT_GESTURE_BUTTON_CLICK;
- mPointerGesture.spotIdBits.clear();
- mPointerGesture.spotIdBits.markBit(0);
- mPointerGesture.spotIdToIndex[0] = 0;
- mPointerGesture.spotCoords[0] = mPointerGesture.currentGestureCoords[0];
- }
- moveSpotsLocked();
- }
} else if (mCurrentTouch.pointerCount == 0) {
// Case 3. No fingers down and button is not pressed. (NEUTRAL)
- *outFinishPreviousGesture = true;
+ if (mPointerGesture.lastGestureMode != PointerGesture::NEUTRAL) {
+ *outFinishPreviousGesture = true;
+ }
// Watch for taps coming out of HOVER or TAP_DRAG mode.
// Checking for taps after TAP_DRAG allows us to detect double-taps.
@@ -3965,15 +3924,6 @@ bool TouchInputMapper::preparePointerGestures(nsecs_t when,
mPointerGesture.currentGestureCoords[0].setAxisValue(
AMOTION_EVENT_AXIS_PRESSURE, 1.0f);
- if (mParameters.gestureMode == Parameters::GESTURE_MODE_SPOTS) {
- mPointerGesture.spotGesture = PointerControllerInterface::SPOT_GESTURE_TAP;
- mPointerGesture.spotIdBits.clear();
- mPointerGesture.spotIdBits.markBit(lastActiveTouchId);
- mPointerGesture.spotIdToIndex[lastActiveTouchId] = 0;
- mPointerGesture.spotCoords[0] = mPointerGesture.currentGestureCoords[0];
- moveSpotsLocked();
- }
-
tapped = true;
} else {
#if DEBUG_GESTURES
@@ -3999,12 +3949,6 @@ bool TouchInputMapper::preparePointerGestures(nsecs_t when,
mPointerGesture.activeGestureId = -1;
mPointerGesture.currentGestureMode = PointerGesture::NEUTRAL;
mPointerGesture.currentGestureIdBits.clear();
-
- if (mParameters.gestureMode == Parameters::GESTURE_MODE_SPOTS) {
- mPointerGesture.spotGesture = PointerControllerInterface::SPOT_GESTURE_NEUTRAL;
- mPointerGesture.spotIdBits.clear();
- moveSpotsLocked();
- }
}
} else if (mCurrentTouch.pointerCount == 1) {
// Case 4. Exactly one finger down, button is not pressed. (HOVER or TAP_DRAG)
@@ -4067,7 +4011,9 @@ bool TouchInputMapper::preparePointerGestures(nsecs_t when,
#if DEBUG_GESTURES
LOGD("Gestures: HOVER");
#endif
- *outFinishPreviousGesture = true;
+ if (mPointerGesture.lastGestureMode != PointerGesture::HOVER) {
+ *outFinishPreviousGesture = true;
+ }
mPointerGesture.activeGestureId = 0;
down = false;
}
@@ -4094,16 +4040,6 @@ bool TouchInputMapper::preparePointerGestures(nsecs_t when,
mPointerGesture.tapX = x;
mPointerGesture.tapY = y;
}
-
- if (mParameters.gestureMode == Parameters::GESTURE_MODE_SPOTS) {
- mPointerGesture.spotGesture = down ? PointerControllerInterface::SPOT_GESTURE_DRAG
- : PointerControllerInterface::SPOT_GESTURE_HOVER;
- mPointerGesture.spotIdBits.clear();
- mPointerGesture.spotIdBits.markBit(activeTouchId);
- mPointerGesture.spotIdToIndex[activeTouchId] = 0;
- mPointerGesture.spotCoords[0] = mPointerGesture.currentGestureCoords[0];
- moveSpotsLocked();
- }
} else {
// Case 5. At least two fingers down, button is not pressed. (PRESS, SWIPE or FREEFORM)
// We need to provide feedback for each finger that goes down so we cannot wait
@@ -4131,8 +4067,8 @@ bool TouchInputMapper::preparePointerGestures(nsecs_t when,
// Reset the gesture.
#if DEBUG_GESTURES
LOGD("Gestures: Resetting gesture since additional pointers went down for MULTITOUCH, "
- "settle time remaining %0.3fms",
- (mPointerGesture.firstTouchTime + MULTITOUCH_SETTLE_INTERVAL - when)
+ "settle time remaining %0.3fms", (mPointerGesture.firstTouchTime
+ + mConfig->pointerGestureMultitouchSettleInterval - when)
* 0.000001f);
#endif
*outCancelPreviousGesture = true;
@@ -4147,101 +4083,134 @@ bool TouchInputMapper::preparePointerGestures(nsecs_t when,
mPointerGesture.referenceIdBits.clear();
mPointerGesture.pointerVelocityControl.reset();
- if (settled && mParameters.gestureMode == Parameters::GESTURE_MODE_SPOTS
- && mLastTouch.idBits.hasBit(mPointerGesture.activeTouchId)) {
- // The spot is already visible and has settled, use it as the reference point
- // for the gesture. Other spots will be positioned relative to this one.
+ // Use the centroid and pointer location as the reference points for the gesture.
#if DEBUG_GESTURES
- LOGD("Gestures: Using active spot as reference for MULTITOUCH, "
- "settle time expired %0.3fms ago",
- (when - mPointerGesture.firstTouchTime - MULTITOUCH_SETTLE_INTERVAL)
- * 0.000001f);
+ LOGD("Gestures: Using centroid as reference for MULTITOUCH, "
+ "settle time remaining %0.3fms", (mPointerGesture.firstTouchTime
+ + mConfig->pointerGestureMultitouchSettleInterval - when)
+ * 0.000001f);
#endif
- const PointerData& d = mLastTouch.pointers[mLastTouch.idToIndex[
- mPointerGesture.activeTouchId]];
- mPointerGesture.referenceTouchX = d.x;
- mPointerGesture.referenceTouchY = d.y;
- const PointerCoords& c = mPointerGesture.spotCoords[mPointerGesture.spotIdToIndex[
- mPointerGesture.activeTouchId]];
- mPointerGesture.referenceGestureX = c.getAxisValue(AMOTION_EVENT_AXIS_X);
- mPointerGesture.referenceGestureY = c.getAxisValue(AMOTION_EVENT_AXIS_Y);
+ mCurrentTouch.getCentroid(&mPointerGesture.referenceTouchX,
+ &mPointerGesture.referenceTouchY);
+ mPointerController->getPosition(&mPointerGesture.referenceGestureX,
+ &mPointerGesture.referenceGestureY);
+ }
+
+ // Clear the reference deltas for fingers not yet included in the reference calculation.
+ for (BitSet32 idBits(mCurrentTouch.idBits.value & ~mPointerGesture.referenceIdBits.value);
+ !idBits.isEmpty(); ) {
+ uint32_t id = idBits.firstMarkedBit();
+ idBits.clearBit(id);
+
+ mPointerGesture.referenceDeltas[id].dx = 0;
+ mPointerGesture.referenceDeltas[id].dy = 0;
+ }
+ mPointerGesture.referenceIdBits = mCurrentTouch.idBits;
+
+ // Add delta for all fingers and calculate a common movement delta.
+ float commonDeltaX = 0, commonDeltaY = 0;
+ BitSet32 commonIdBits(mLastTouch.idBits.value & mCurrentTouch.idBits.value);
+ for (BitSet32 idBits(commonIdBits); !idBits.isEmpty(); ) {
+ bool first = (idBits == commonIdBits);
+ uint32_t id = idBits.firstMarkedBit();
+ idBits.clearBit(id);
+
+ const PointerData& cpd = mCurrentTouch.pointers[mCurrentTouch.idToIndex[id]];
+ const PointerData& lpd = mLastTouch.pointers[mLastTouch.idToIndex[id]];
+ PointerGesture::Delta& delta = mPointerGesture.referenceDeltas[id];
+ delta.dx += cpd.x - lpd.x;
+ delta.dy += cpd.y - lpd.y;
+
+ if (first) {
+ commonDeltaX = delta.dx;
+ commonDeltaY = delta.dy;
} else {
- // Use the centroid and pointer location as the reference points for the gesture.
-#if DEBUG_GESTURES
- LOGD("Gestures: Using centroid as reference for MULTITOUCH, "
- "settle time remaining %0.3fms",
- (mPointerGesture.firstTouchTime + MULTITOUCH_SETTLE_INTERVAL - when)
- * 0.000001f);
-#endif
- mCurrentTouch.getCentroid(&mPointerGesture.referenceTouchX,
- &mPointerGesture.referenceTouchY);
- mPointerController->getPosition(&mPointerGesture.referenceGestureX,
- &mPointerGesture.referenceGestureY);
+ commonDeltaX = calculateCommonVector(commonDeltaX, delta.dx);
+ commonDeltaY = calculateCommonVector(commonDeltaY, delta.dy);
}
}
+ // Consider transitions from PRESS to SWIPE or MULTITOUCH.
if (mPointerGesture.currentGestureMode == PointerGesture::PRESS) {
- float d;
- if (mCurrentTouch.pointerCount > 2) {
- // There are more than two pointers, switch to FREEFORM.
+ float dist[MAX_POINTER_ID + 1];
+ int32_t distOverThreshold = 0;
+ for (BitSet32 idBits(mPointerGesture.referenceIdBits); !idBits.isEmpty(); ) {
+ uint32_t id = idBits.firstMarkedBit();
+ idBits.clearBit(id);
+
+ PointerGesture::Delta& delta = mPointerGesture.referenceDeltas[id];
+ dist[id] = hypotf(delta.dx * mLocked.pointerGestureXZoomScale,
+ delta.dy * mLocked.pointerGestureYZoomScale);
+ if (dist[id] > mConfig->pointerGestureMultitouchMinDistance) {
+ distOverThreshold += 1;
+ }
+ }
+
+ // Only transition when at least two pointers have moved further than
+ // the minimum distance threshold.
+ if (distOverThreshold >= 2) {
+ float d;
+ if (mCurrentTouch.pointerCount > 2) {
+ // There are more than two pointers, switch to FREEFORM.
#if DEBUG_GESTURES
- LOGD("Gestures: PRESS transitioned to FREEFORM, number of pointers %d > 2",
- mCurrentTouch.pointerCount);
+ LOGD("Gestures: PRESS transitioned to FREEFORM, number of pointers %d > 2",
+ mCurrentTouch.pointerCount);
#endif
- *outCancelPreviousGesture = true;
- mPointerGesture.currentGestureMode = PointerGesture::FREEFORM;
- } else if (((d = distance(
- mCurrentTouch.pointers[0].x, mCurrentTouch.pointers[0].y,
- mCurrentTouch.pointers[1].x, mCurrentTouch.pointers[1].y))
- > mLocked.pointerGestureMaxSwipeWidth)) {
- // There are two pointers but they are too far apart, switch to FREEFORM.
+ *outCancelPreviousGesture = true;
+ mPointerGesture.currentGestureMode = PointerGesture::FREEFORM;
+ } else if (((d = distance(
+ mCurrentTouch.pointers[0].x, mCurrentTouch.pointers[0].y,
+ mCurrentTouch.pointers[1].x, mCurrentTouch.pointers[1].y))
+ > mLocked.pointerGestureMaxSwipeWidth)) {
+ // There are two pointers but they are too far apart for a SWIPE,
+ // switch to FREEFORM.
#if DEBUG_GESTURES
- LOGD("Gestures: PRESS transitioned to FREEFORM, distance %0.3f > %0.3f",
- d, mLocked.pointerGestureMaxSwipeWidth);
+ LOGD("Gestures: PRESS transitioned to FREEFORM, distance %0.3f > %0.3f",
+ d, mLocked.pointerGestureMaxSwipeWidth);
#endif
- *outCancelPreviousGesture = true;
- mPointerGesture.currentGestureMode = PointerGesture::FREEFORM;
- } else {
- // There are two pointers. Wait for both pointers to start moving
- // before deciding whether this is a SWIPE or FREEFORM gesture.
- uint32_t id1 = mCurrentTouch.pointers[0].id;
- uint32_t id2 = mCurrentTouch.pointers[1].id;
-
- float vx1, vy1, vx2, vy2;
- mPointerGesture.velocityTracker.getVelocity(id1, &vx1, &vy1);
- mPointerGesture.velocityTracker.getVelocity(id2, &vx2, &vy2);
-
- float speed1 = hypotf(vx1, vy1);
- float speed2 = hypotf(vx2, vy2);
- if (speed1 >= mConfig->pointerGestureMultitouchMinSpeed
- && speed2 >= mConfig->pointerGestureMultitouchMinSpeed) {
- // Calculate the dot product of the velocity vectors.
- // When the vectors are oriented in approximately the same direction,
- // the angle betweeen them is near zero and the cosine of the angle
- // approches 1.0. Recall that dot(v1, v2) = cos(angle) * mag(v1) * mag(v2).
- float dot = vx1 * vx2 + vy1 * vy2;
- float cosine = dot / (speed1 * speed2); // denominator always > 0
- if (cosine >= mConfig->pointerGestureSwipeTransitionAngleCosine) {
- // Pointers are moving in the same direction. Switch to SWIPE.
+ *outCancelPreviousGesture = true;
+ mPointerGesture.currentGestureMode = PointerGesture::FREEFORM;
+ } else {
+ // There are two pointers. Wait for both pointers to start moving
+ // before deciding whether this is a SWIPE or FREEFORM gesture.
+ uint32_t id1 = mCurrentTouch.pointers[0].id;
+ uint32_t id2 = mCurrentTouch.pointers[1].id;
+ float dist1 = dist[id1];
+ float dist2 = dist[id2];
+ if (dist1 >= mConfig->pointerGestureMultitouchMinDistance
+ && dist2 >= mConfig->pointerGestureMultitouchMinDistance) {
+ // Calculate the dot product of the displacement vectors.
+ // When the vectors are oriented in approximately the same direction,
+ // the angle betweeen them is near zero and the cosine of the angle
+ // approches 1.0. Recall that dot(v1, v2) = cos(angle) * mag(v1) * mag(v2).
+ PointerGesture::Delta& delta1 = mPointerGesture.referenceDeltas[id1];
+ PointerGesture::Delta& delta2 = mPointerGesture.referenceDeltas[id2];
+ float dot = delta1.dx * delta2.dx + delta1.dy * delta2.dy;
+ float cosine = dot / (dist1 * dist2); // denominator always > 0
+ if (cosine >= mConfig->pointerGestureSwipeTransitionAngleCosine) {
+ // Pointers are moving in the same direction. Switch to SWIPE.
#if DEBUG_GESTURES
- LOGD("Gestures: PRESS transitioned to SWIPE, "
- "speed1 %0.3f >= %0.3f, speed2 %0.3f >= %0.3f, "
- "cosine %0.3f >= %0.3f",
- speed1, MULTITOUCH_MIN_SPEED, speed2, MULTITOUCH_MIN_SPEED,
- cosine, SWIPE_TRANSITION_ANGLE_COSINE);
+ LOGD("Gestures: PRESS transitioned to SWIPE, "
+ "dist1 %0.3f >= %0.3f, dist2 %0.3f >= %0.3f, "
+ "cosine %0.3f >= %0.3f",
+ dist1, mConfig->pointerGestureMultitouchMinDistance,
+ dist2, mConfig->pointerGestureMultitouchMinDistance,
+ cosine, mConfig->pointerGestureSwipeTransitionAngleCosine);
#endif
- mPointerGesture.currentGestureMode = PointerGesture::SWIPE;
- } else {
- // Pointers are moving in different directions. Switch to FREEFORM.
+ mPointerGesture.currentGestureMode = PointerGesture::SWIPE;
+ } else {
+ // Pointers are moving in different directions. Switch to FREEFORM.
#if DEBUG_GESTURES
- LOGD("Gestures: PRESS transitioned to FREEFORM, "
- "speed1 %0.3f >= %0.3f, speed2 %0.3f >= %0.3f, "
- "cosine %0.3f < %0.3f",
- speed1, MULTITOUCH_MIN_SPEED, speed2, MULTITOUCH_MIN_SPEED,
- cosine, SWIPE_TRANSITION_ANGLE_COSINE);
+ LOGD("Gestures: PRESS transitioned to FREEFORM, "
+ "dist1 %0.3f >= %0.3f, dist2 %0.3f >= %0.3f, "
+ "cosine %0.3f < %0.3f",
+ dist1, mConfig->pointerGestureMultitouchMinDistance,
+ dist2, mConfig->pointerGestureMultitouchMinDistance,
+ cosine, mConfig->pointerGestureSwipeTransitionAngleCosine);
#endif
- *outCancelPreviousGesture = true;
- mPointerGesture.currentGestureMode = PointerGesture::FREEFORM;
+ *outCancelPreviousGesture = true;
+ mPointerGesture.currentGestureMode = PointerGesture::FREEFORM;
+ }
}
}
}
@@ -4258,67 +4227,28 @@ bool TouchInputMapper::preparePointerGestures(nsecs_t when,
}
}
- // Clear the reference deltas for fingers not yet included in the reference calculation.
- for (BitSet32 idBits(mCurrentTouch.idBits.value & ~mPointerGesture.referenceIdBits.value);
- !idBits.isEmpty(); ) {
- uint32_t id = idBits.firstMarkedBit();
- idBits.clearBit(id);
-
- mPointerGesture.referenceDeltas[id].dx = 0;
- mPointerGesture.referenceDeltas[id].dy = 0;
- }
- mPointerGesture.referenceIdBits = mCurrentTouch.idBits;
-
- // Move the reference points based on the overall group motion of the fingers.
- // The objective is to calculate a vector delta that is common to the movement
- // of all fingers.
- BitSet32 commonIdBits(mLastTouch.idBits.value & mCurrentTouch.idBits.value);
- if (!commonIdBits.isEmpty()) {
- float commonDeltaX = 0, commonDeltaY = 0;
- for (BitSet32 idBits(commonIdBits); !idBits.isEmpty(); ) {
- bool first = (idBits == commonIdBits);
+ // Move the reference points based on the overall group motion of the fingers
+ // except in PRESS mode while waiting for a transition to occur.
+ if (mPointerGesture.currentGestureMode != PointerGesture::PRESS
+ && (commonDeltaX || commonDeltaY)) {
+ for (BitSet32 idBits(mPointerGesture.referenceIdBits); !idBits.isEmpty(); ) {
uint32_t id = idBits.firstMarkedBit();
idBits.clearBit(id);
- const PointerData& cpd = mCurrentTouch.pointers[mCurrentTouch.idToIndex[id]];
- const PointerData& lpd = mLastTouch.pointers[mLastTouch.idToIndex[id]];
PointerGesture::Delta& delta = mPointerGesture.referenceDeltas[id];
- delta.dx += cpd.x - lpd.x;
- delta.dy += cpd.y - lpd.y;
-
- if (first) {
- commonDeltaX = delta.dx;
- commonDeltaY = delta.dy;
- } else {
- commonDeltaX = calculateCommonVector(commonDeltaX, delta.dx);
- commonDeltaY = calculateCommonVector(commonDeltaY, delta.dy);
- }
+ delta.dx = 0;
+ delta.dy = 0;
}
- if (commonDeltaX || commonDeltaY) {
- for (BitSet32 idBits(commonIdBits); !idBits.isEmpty(); ) {
- uint32_t id = idBits.firstMarkedBit();
- idBits.clearBit(id);
-
- PointerGesture::Delta& delta = mPointerGesture.referenceDeltas[id];
- delta.dx = 0;
- delta.dy = 0;
- }
-
- mPointerGesture.referenceTouchX += commonDeltaX;
- mPointerGesture.referenceTouchY += commonDeltaY;
+ mPointerGesture.referenceTouchX += commonDeltaX;
+ mPointerGesture.referenceTouchY += commonDeltaY;
- commonDeltaX *= mLocked.pointerGestureXMovementScale;
- commonDeltaY *= mLocked.pointerGestureYMovementScale;
- mPointerGesture.pointerVelocityControl.move(when, &commonDeltaX, &commonDeltaY);
+ commonDeltaX *= mLocked.pointerGestureXMovementScale;
+ commonDeltaY *= mLocked.pointerGestureYMovementScale;
+ mPointerGesture.pointerVelocityControl.move(when, &commonDeltaX, &commonDeltaY);
- mPointerGesture.referenceGestureX += commonDeltaX;
- mPointerGesture.referenceGestureY += commonDeltaY;
-
- clampPositionUsingPointerBounds(mPointerController,
- &mPointerGesture.referenceGestureX,
- &mPointerGesture.referenceGestureY);
- }
+ mPointerGesture.referenceGestureX += commonDeltaX;
+ mPointerGesture.referenceGestureY += commonDeltaY;
}
// Report gestures.
@@ -4344,10 +4274,6 @@ bool TouchInputMapper::preparePointerGestures(nsecs_t when,
mPointerGesture.currentGestureCoords[0].setAxisValue(AMOTION_EVENT_AXIS_Y,
mPointerGesture.referenceGestureY);
mPointerGesture.currentGestureCoords[0].setAxisValue(AMOTION_EVENT_AXIS_PRESSURE, 1.0f);
-
- if (mParameters.gestureMode == Parameters::GESTURE_MODE_SPOTS) {
- mPointerGesture.spotGesture = PointerControllerInterface::SPOT_GESTURE_PRESS;
- }
} else if (mPointerGesture.currentGestureMode == PointerGesture::SWIPE) {
// SWIPE mode.
#if DEBUG_GESTURES
@@ -4370,10 +4296,6 @@ bool TouchInputMapper::preparePointerGestures(nsecs_t when,
mPointerGesture.currentGestureCoords[0].setAxisValue(AMOTION_EVENT_AXIS_Y,
mPointerGesture.referenceGestureY);
mPointerGesture.currentGestureCoords[0].setAxisValue(AMOTION_EVENT_AXIS_PRESSURE, 1.0f);
-
- if (mParameters.gestureMode == Parameters::GESTURE_MODE_SPOTS) {
- mPointerGesture.spotGesture = PointerControllerInterface::SPOT_GESTURE_SWIPE;
- }
} else if (mPointerGesture.currentGestureMode == PointerGesture::FREEFORM) {
// FREEFORM mode.
#if DEBUG_GESTURES
@@ -4475,33 +4397,6 @@ bool TouchInputMapper::preparePointerGestures(nsecs_t when,
"activeGestureId=%d", mPointerGesture.activeGestureId);
#endif
}
-
- if (mParameters.gestureMode == Parameters::GESTURE_MODE_SPOTS) {
- mPointerGesture.spotGesture = PointerControllerInterface::SPOT_GESTURE_FREEFORM;
- }
- }
-
- // Update spot locations for PRESS, SWIPE and FREEFORM.
- // We use the same calculation as we do to calculate the gesture pointers
- // for FREEFORM so that the spots smoothly track gestures.
- if (mParameters.gestureMode == Parameters::GESTURE_MODE_SPOTS) {
- mPointerGesture.spotIdBits.clear();
- for (uint32_t i = 0; i < mCurrentTouch.pointerCount; i++) {
- uint32_t id = mCurrentTouch.pointers[i].id;
- mPointerGesture.spotIdBits.markBit(id);
- mPointerGesture.spotIdToIndex[id] = i;
-
- float x = (mCurrentTouch.pointers[i].x - mPointerGesture.referenceTouchX)
- * mLocked.pointerGestureXZoomScale + mPointerGesture.referenceGestureX;
- float y = (mCurrentTouch.pointers[i].y - mPointerGesture.referenceTouchY)
- * mLocked.pointerGestureYZoomScale + mPointerGesture.referenceGestureY;
-
- mPointerGesture.spotCoords[i].clear();
- mPointerGesture.spotCoords[i].setAxisValue(AMOTION_EVENT_AXIS_X, x);
- mPointerGesture.spotCoords[i].setAxisValue(AMOTION_EVENT_AXIS_Y, y);
- mPointerGesture.spotCoords[i].setAxisValue(AMOTION_EVENT_AXIS_PRESSURE, 1.0f);
- }
- moveSpotsLocked();
}
}
@@ -4544,11 +4439,6 @@ bool TouchInputMapper::preparePointerGestures(nsecs_t when,
return true;
}
-void TouchInputMapper::moveSpotsLocked() {
- mPointerController->setSpots(mPointerGesture.spotGesture,
- mPointerGesture.spotCoords, mPointerGesture.spotIdToIndex, mPointerGesture.spotIdBits);
-}
-
void TouchInputMapper::dispatchMotion(nsecs_t when, uint32_t policyFlags, uint32_t source,
int32_t action, int32_t flags, int32_t metaState, int32_t buttonState, int32_t edgeFlags,
const PointerProperties* properties, const PointerCoords* coords,
diff --git a/services/input/InputReader.h b/services/input/InputReader.h
index 1d4ad873c1dd..36cd89cfb576 100644
--- a/services/input/InputReader.h
+++ b/services/input/InputReader.h
@@ -101,8 +101,8 @@ struct InputReaderConfiguration {
nsecs_t pointerGestureMultitouchSettleInterval;
// The transition from PRESS to SWIPE or FREEFORM gesture mode is made when
- // both of the pointers are moving at least this fast.
- float pointerGestureMultitouchMinSpeed; // in pixels per second
+ // at least two pointers have moved at least this far from their starting place.
+ float pointerGestureMultitouchMinDistance; // in pixels
// The transition from PRESS to SWIPE gesture mode can only occur when the
// cosine of the angle between the two vectors is greater than or equal to than this value
@@ -134,7 +134,7 @@ struct InputReaderConfiguration {
filterTouchEvents(false),
filterJumpyTouchEvents(false),
virtualKeyQuietTime(0),
- pointerVelocityControlParameters(1.0f, 80.0f, 400.0f, 4.0f),
+ pointerVelocityControlParameters(1.0f, 500.0f, 3000.0f, 3.0f),
wheelVelocityControlParameters(1.0f, 15.0f, 50.0f, 4.0f),
pointerGestureQuietInterval(100 * 1000000LL), // 100 ms
pointerGestureDragMinSwitchSpeed(50), // 50 pixels per second
@@ -142,10 +142,10 @@ struct InputReaderConfiguration {
pointerGestureTapDragInterval(150 * 1000000LL), // 150 ms
pointerGestureTapSlop(10.0f), // 10 pixels
pointerGestureMultitouchSettleInterval(100 * 1000000LL), // 100 ms
- pointerGestureMultitouchMinSpeed(150.0f), // 150 pixels per second
+ pointerGestureMultitouchMinDistance(15), // 15 pixels
pointerGestureSwipeTransitionAngleCosine(0.5f), // cosine of 45degrees
- pointerGestureSwipeMaxWidthRatio(0.333f),
- pointerGestureMovementSpeedRatio(0.3f),
+ pointerGestureSwipeMaxWidthRatio(0.25f),
+ pointerGestureMovementSpeedRatio(0.8f),
pointerGestureZoomSpeedRatio(0.3f) { }
};
@@ -1140,12 +1140,6 @@ private:
PointerProperties lastGestureProperties[MAX_POINTERS];
PointerCoords lastGestureCoords[MAX_POINTERS];
- // Pointer coords and ids for the current spots.
- PointerControllerInterface::SpotGesture spotGesture;
- BitSet32 spotIdBits; // same set of ids as touch ids
- uint32_t spotIdToIndex[MAX_POINTER_ID + 1];
- PointerCoords spotCoords[MAX_POINTERS];
-
// Time the pointer gesture last went down.
nsecs_t downTime;
@@ -1192,8 +1186,6 @@ private:
currentGestureIdBits.clear();
lastGestureMode = NEUTRAL;
lastGestureIdBits.clear();
- spotGesture = PointerControllerInterface::SPOT_GESTURE_NEUTRAL;
- spotIdBits.clear();
downTime = 0;
velocityTracker.clear();
resetTap();
@@ -1219,7 +1211,6 @@ private:
void dispatchPointerGestures(nsecs_t when, uint32_t policyFlags, bool isTimeout);
bool preparePointerGestures(nsecs_t when,
bool* outCancelPreviousGesture, bool* outFinishPreviousGesture, bool isTimeout);
- void moveSpotsLocked();
// Dispatches a motion event.
// If the changedId is >= 0 and the action is POINTER_DOWN or POINTER_UP, the
diff --git a/services/input/PointerController.cpp b/services/input/PointerController.cpp
index c18ebcfccaae..12c7cba16cca 100644
--- a/services/input/PointerController.cpp
+++ b/services/input/PointerController.cpp
@@ -240,15 +240,15 @@ void PointerController::setPresentation(Presentation presentation) {
}
}
-void PointerController::setSpots(SpotGesture spotGesture,
- const PointerCoords* spotCoords, const uint32_t* spotIdToIndex, BitSet32 spotIdBits) {
+void PointerController::setSpots(const PointerCoords* spotCoords,
+ const uint32_t* spotIdToIndex, BitSet32 spotIdBits) {
#if DEBUG_POINTER_UPDATES
- LOGD("setSpots: spotGesture=%d", spotGesture);
+ LOGD("setSpots: idBits=%08x", spotIdBits.value);
for (BitSet32 idBits(spotIdBits); !idBits.isEmpty(); ) {
uint32_t id = idBits.firstMarkedBit();
idBits.clearBit(id);
const PointerCoords& c = spotCoords[spotIdToIndex[id]];
- LOGD(" spot %d: position=(%0.3f, %0.3f), pressure=%0.3f", id,
+ LOGD(" spot %d: position=(%0.3f, %0.3f), pressure=%0.3f", id,
c.getAxisValue(AMOTION_EVENT_AXIS_X),
c.getAxisValue(AMOTION_EVENT_AXIS_Y),
c.getAxisValue(AMOTION_EVENT_AXIS_PRESSURE));
diff --git a/services/input/PointerController.h b/services/input/PointerController.h
index 1c21db16d3a3..700ef7295fe7 100644
--- a/services/input/PointerController.h
+++ b/services/input/PointerController.h
@@ -90,38 +90,6 @@ public:
/* Sets the mode of the pointer controller. */
virtual void setPresentation(Presentation presentation) = 0;
- // Describes the current gesture.
- enum SpotGesture {
- // No gesture.
- // Do not display any spots.
- SPOT_GESTURE_NEUTRAL,
- // Tap at current location.
- // Briefly display one spot at the tapped location.
- SPOT_GESTURE_TAP,
- // Drag at current location.
- // Display spot at pressed location.
- SPOT_GESTURE_DRAG,
- // Button pressed but no finger is down.
- // Display spot at pressed location.
- SPOT_GESTURE_BUTTON_CLICK,
- // Button pressed and a finger is down.
- // Display spot at pressed location.
- SPOT_GESTURE_BUTTON_DRAG,
- // One finger down and hovering.
- // Display spot at the hovered location.
- SPOT_GESTURE_HOVER,
- // Two fingers down but not sure in which direction they are moving so we consider
- // it a press at the pointer location.
- // Display two spots near the pointer location.
- SPOT_GESTURE_PRESS,
- // Two fingers down and moving in same direction.
- // Display two spots near the pointer location.
- SPOT_GESTURE_SWIPE,
- // Two or more fingers down and moving in arbitrary directions.
- // Display two or more spots near the pointer location, one for each finger.
- SPOT_GESTURE_FREEFORM,
- };
-
/* Sets the spots for the current gesture.
* The spots are not subject to the inactivity timeout like the pointer
* itself it since they are expected to remain visible for so long as
@@ -131,8 +99,7 @@ public:
* For spotCoords, pressure != 0 indicates that the spot's location is being
* pressed (not hovering).
*/
- virtual void setSpots(SpotGesture spotGesture,
- const PointerCoords* spotCoords, const uint32_t* spotIdToIndex,
+ virtual void setSpots(const PointerCoords* spotCoords, const uint32_t* spotIdToIndex,
BitSet32 spotIdBits) = 0;
/* Removes all spots. */
@@ -198,8 +165,8 @@ public:
virtual void unfade(Transition transition);
virtual void setPresentation(Presentation presentation);
- virtual void setSpots(SpotGesture spotGesture,
- const PointerCoords* spotCoords, const uint32_t* spotIdToIndex, BitSet32 spotIdBits);
+ virtual void setSpots(const PointerCoords* spotCoords,
+ const uint32_t* spotIdToIndex, BitSet32 spotIdBits);
virtual void clearSpots();
void setDisplaySize(int32_t width, int32_t height);
diff --git a/services/input/tests/InputReader_test.cpp b/services/input/tests/InputReader_test.cpp
index 00b4222f68b8..d04c9e7db145 100644
--- a/services/input/tests/InputReader_test.cpp
+++ b/services/input/tests/InputReader_test.cpp
@@ -101,8 +101,8 @@ private:
virtual void setPresentation(Presentation presentation) {
}
- virtual void setSpots(SpotGesture spotGesture,
- const PointerCoords* spotCoords, const uint32_t* spotIdToIndex, BitSet32 spotIdBits) {
+ virtual void setSpots(const PointerCoords* spotCoords,
+ const uint32_t* spotIdToIndex, BitSet32 spotIdBits) {
}
virtual void clearSpots() {
diff --git a/services/java/com/android/server/BackupManagerService.java b/services/java/com/android/server/BackupManagerService.java
index 7c6d3c144346..c28732e8d2b4 100644
--- a/services/java/com/android/server/BackupManagerService.java
+++ b/services/java/com/android/server/BackupManagerService.java
@@ -134,6 +134,7 @@ class BackupManagerService extends IBackupManager.Stub {
// Timeout intervals for agent backup & restore operations
static final long TIMEOUT_BACKUP_INTERVAL = 30 * 1000;
static final long TIMEOUT_FULL_BACKUP_INTERVAL = 5 * 60 * 1000;
+ static final long TIMEOUT_SHARED_BACKUP_INTERVAL = 30 * 60 * 1000;
static final long TIMEOUT_RESTORE_INTERVAL = 60 * 1000;
// User confirmation timeout for a full backup/restore operation
@@ -1691,7 +1692,7 @@ class BackupManagerService extends IBackupManager.Stub {
public void run() {
final List<PackageInfo> packagesToBackup;
- Slog.i(TAG, "--- Performing full-dataset restore ---");
+ Slog.i(TAG, "--- Performing full-dataset backup ---");
sendStartBackup();
// doAllApps supersedes the package set if any
@@ -1720,64 +1721,23 @@ class BackupManagerService extends IBackupManager.Stub {
}
}
- // Now back up the app data via the agent mechanism
PackageInfo pkg = null;
try {
+ // Now back up the app data via the agent mechanism
int N = packagesToBackup.size();
for (int i = 0; i < N; i++) {
pkg = packagesToBackup.get(i);
+ backupOnePackage(pkg);
+ }
- Slog.d(TAG, "Binding to full backup agent : " + pkg.packageName);
-
- IBackupAgent agent = bindToAgentSynchronous(pkg.applicationInfo,
- IApplicationThread.BACKUP_MODE_FULL);
- if (agent != null) {
- try {
- ApplicationInfo app = pkg.applicationInfo;
- boolean sendApk = mIncludeApks
- && ((app.flags & ApplicationInfo.FLAG_FORWARD_LOCK) == 0)
- && ((app.flags & ApplicationInfo.FLAG_SYSTEM) == 0 ||
- (app.flags & ApplicationInfo.FLAG_UPDATED_SYSTEM_APP) != 0);
-
- sendOnBackupPackage(pkg.packageName);
-
- {
- BackupDataOutput output = new BackupDataOutput(
- mOutputFile.getFileDescriptor());
-
- if (DEBUG) Slog.d(TAG, "Writing manifest for " + pkg.packageName);
- writeAppManifest(pkg, mManifestFile, sendApk);
- FullBackup.backupToTar(pkg.packageName, null, null,
- mFilesDir.getAbsolutePath(),
- mManifestFile.getAbsolutePath(),
- output);
- }
-
- if (DEBUG) Slog.d(TAG, "Calling doBackup()");
- final int token = generateToken();
- prepareOperationTimeout(token, TIMEOUT_FULL_BACKUP_INTERVAL);
- agent.doBackup(null, mOutputFile, null, sendApk,
- token, mBackupManagerBinder);
- boolean success = waitUntilOperationComplete(token);
- if (!success) {
- Slog.d(TAG, "Full backup failed on package " + pkg.packageName);
- } else {
- if (DEBUG) Slog.d(TAG, "Full backup success: " + pkg.packageName);
- }
- } catch (IOException e) {
- Slog.e(TAG, "Error backing up " + pkg.packageName, e);
- }
- } else {
- Slog.w(TAG, "Unable to bind to full agent for " + pkg.packageName);
- }
- tearDown(pkg);
+ // Finally, shared storage if requested
+ if (mIncludeShared) {
+ backupSharedStorage();
}
} catch (RemoteException e) {
Slog.e(TAG, "App died during full backup");
} finally {
- if (pkg != null) {
- tearDown(pkg);
- }
+ tearDown(pkg);
try {
mOutputFile.close();
} catch (IOException e) {
@@ -1796,6 +1756,79 @@ class BackupManagerService extends IBackupManager.Stub {
}
}
+ private void backupOnePackage(PackageInfo pkg) throws RemoteException {
+ Slog.d(TAG, "Binding to full backup agent : " + pkg.packageName);
+
+ IBackupAgent agent = bindToAgentSynchronous(pkg.applicationInfo,
+ IApplicationThread.BACKUP_MODE_FULL);
+ if (agent != null) {
+ try {
+ ApplicationInfo app = pkg.applicationInfo;
+ boolean sendApk = mIncludeApks
+ && ((app.flags & ApplicationInfo.FLAG_FORWARD_LOCK) == 0)
+ && ((app.flags & ApplicationInfo.FLAG_SYSTEM) == 0 ||
+ (app.flags & ApplicationInfo.FLAG_UPDATED_SYSTEM_APP) != 0);
+
+ sendOnBackupPackage(pkg.packageName);
+
+ {
+ BackupDataOutput output = new BackupDataOutput(
+ mOutputFile.getFileDescriptor());
+
+ if (DEBUG) Slog.d(TAG, "Writing manifest for " + pkg.packageName);
+ writeAppManifest(pkg, mManifestFile, sendApk);
+ FullBackup.backupToTar(pkg.packageName, null, null,
+ mFilesDir.getAbsolutePath(),
+ mManifestFile.getAbsolutePath(),
+ output);
+ }
+
+ if (DEBUG) Slog.d(TAG, "Calling doBackup()");
+ final int token = generateToken();
+ prepareOperationTimeout(token, TIMEOUT_FULL_BACKUP_INTERVAL);
+ agent.doBackup(null, mOutputFile, null, sendApk,
+ token, mBackupManagerBinder);
+ if (!waitUntilOperationComplete(token)) {
+ Slog.e(TAG, "Full backup failed on package " + pkg.packageName);
+ } else {
+ if (DEBUG) Slog.d(TAG, "Full backup success: " + pkg.packageName);
+ }
+ } catch (IOException e) {
+ Slog.e(TAG, "Error backing up " + pkg.packageName, e);
+ }
+ } else {
+ Slog.w(TAG, "Unable to bind to full agent for " + pkg.packageName);
+ }
+ tearDown(pkg);
+ }
+
+ private void backupSharedStorage() throws RemoteException {
+ PackageInfo pkg = null;
+ try {
+ pkg = mPackageManager.getPackageInfo("com.android.sharedstoragebackup", 0);
+ IBackupAgent agent = bindToAgentSynchronous(pkg.applicationInfo,
+ IApplicationThread.BACKUP_MODE_FULL);
+ if (agent != null) {
+ sendOnBackupPackage("Shared storage");
+
+ final int token = generateToken();
+ prepareOperationTimeout(token, TIMEOUT_SHARED_BACKUP_INTERVAL);
+ agent.doBackup(null, mOutputFile, null, false, token, mBackupManagerBinder);
+ if (!waitUntilOperationComplete(token)) {
+ Slog.e(TAG, "Full backup failed on shared storage");
+ } else {
+ if (DEBUG) Slog.d(TAG, "Full shared storage backup success");
+ }
+ } else {
+ Slog.e(TAG, "Could not bind to shared storage backup agent");
+ }
+ } catch (NameNotFoundException e) {
+ Slog.e(TAG, "Shared storage backup package not found");
+ } finally {
+ tearDown(pkg);
+ }
+ }
+
private void writeAppManifest(PackageInfo pkg, File manifestFile, boolean withApk)
throws IOException {
// Manifest format. All data are strings ending in LF:
@@ -1836,23 +1869,24 @@ class BackupManagerService extends IBackupManager.Stub {
}
private void tearDown(PackageInfo pkg) {
- final ApplicationInfo app = pkg.applicationInfo;
- try {
- // unbind and tidy up even on timeout or failure, just in case
- mActivityManager.unbindBackupAgent(app);
-
- // The agent was running with a stub Application object, so shut it down.
- // !!! We hardcode the confirmation UI's package name here rather than use a
- // manifest flag! TODO something less direct.
- if (app.uid != Process.SYSTEM_UID
- && !pkg.packageName.equals("com.android.backupconfirm")) {
- if (DEBUG) Slog.d(TAG, "Backup complete, killing host process");
- mActivityManager.killApplicationProcess(app.processName, app.uid);
- } else {
- if (DEBUG) Slog.d(TAG, "Not killing after restore: " + app.processName);
+ if (pkg != null) {
+ final ApplicationInfo app = pkg.applicationInfo;
+ if (app != null) {
+ try {
+ // unbind and tidy up even on timeout or failure, just in case
+ mActivityManager.unbindBackupAgent(app);
+
+ // The agent was running with a stub Application object, so shut it down.
+ if (app.uid != Process.SYSTEM_UID) {
+ if (DEBUG) Slog.d(TAG, "Backup complete, killing host process");
+ mActivityManager.killApplicationProcess(app.processName, app.uid);
+ } else {
+ if (DEBUG) Slog.d(TAG, "Not killing after restore: " + app.processName);
+ }
+ } catch (RemoteException e) {
+ Slog.d(TAG, "Lost app trying to shut down");
+ }
}
- } catch (RemoteException e) {
- Slog.d(TAG, "Lost app trying to shut down");
}
}
@@ -1949,6 +1983,7 @@ class BackupManagerService extends IBackupManager.Stub {
// with a whitelist of packages known to be unclearable.
mClearedPackages.add("android");
mClearedPackages.add("com.android.providers.settings");
+
}
class RestoreFileRunnable implements Runnable {
@@ -1988,6 +2023,11 @@ class BackupManagerService extends IBackupManager.Stub {
Slog.i(TAG, "--- Performing full-dataset restore ---");
sendStartRestore();
+ // Are we able to restore shared-storage data?
+ if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {
+ mPackagePolicies.put("com.android.sharedstoragebackup", RestorePolicy.ACCEPT);
+ }
+
try {
byte[] buffer = new byte[32 * 1024];
FileInputStream instream = new FileInputStream(mInputFile.getFileDescriptor());
@@ -2707,7 +2747,9 @@ class BackupManagerService extends IBackupManager.Stub {
info.path, 0, FullBackup.SHARED_PREFIX.length())) {
// File in shared storage. !!! TODO: implement this.
info.path = info.path.substring(FullBackup.SHARED_PREFIX.length());
+ info.packageName = "com.android.sharedstoragebackup";
info.domain = FullBackup.SHARED_STORAGE_TOKEN;
+ if (DEBUG) Slog.i(TAG, "File in shared storage: " + info.path);
} else if (FullBackup.APPS_PREFIX.regionMatches(0,
info.path, 0, FullBackup.APPS_PREFIX.length())) {
// App content! Parse out the package name and domain
@@ -2817,6 +2859,7 @@ class BackupManagerService extends IBackupManager.Stub {
final int end = offset + maxChars;
for (int i = offset; i < end; i++) {
final byte b = data[i];
+ // Numeric fields in tar can terminate with either NUL or SPC
if (b == 0 || b == ' ') break;
if (b < '0' || b > ('0' + radix - 1)) {
throw new IOException("Invalid number in header");
@@ -2829,8 +2872,8 @@ class BackupManagerService extends IBackupManager.Stub {
String extractString(byte[] data, int offset, int maxChars) throws IOException {
final int end = offset + maxChars;
int eos = offset;
- // tar string fields can end with either NUL or SPC
- while (eos < end && data[eos] != 0 && data[eos] != ' ') eos++;
+ // tar string fields terminate early with a NUL
+ while (eos < end && data[eos] != 0) eos++;
return new String(data, offset, eos-offset, "US-ASCII");
}
diff --git a/services/java/com/android/server/ConnectivityService.java b/services/java/com/android/server/ConnectivityService.java
index dd76eb8c705c..e3d4c45cf62a 100644
--- a/services/java/com/android/server/ConnectivityService.java
+++ b/services/java/com/android/server/ConnectivityService.java
@@ -16,6 +16,7 @@
package com.android.server;
+import static android.Manifest.permission.READ_PHONE_STATE;
import static android.Manifest.permission.UPDATE_DEVICE_STATS;
import static android.net.ConnectivityManager.isNetworkTypeValid;
import static android.net.NetworkPolicyManager.RULE_ALLOW_ALL;
@@ -38,6 +39,7 @@ import android.net.MobileDataStateTracker;
import android.net.NetworkConfig;
import android.net.NetworkInfo;
import android.net.NetworkInfo.DetailedState;
+import android.net.NetworkState;
import android.net.NetworkStateTracker;
import android.net.NetworkUtils;
import android.net.Proxy;
@@ -65,6 +67,7 @@ import android.util.SparseIntArray;
import com.android.internal.telephony.Phone;
import com.android.server.connectivity.Tethering;
+import com.google.android.collect.Lists;
import java.io.FileDescriptor;
import java.io.IOException;
@@ -458,6 +461,12 @@ public class ConnectivityService extends IConnectivityManager.Stub {
mTethering.getTetherableBluetoothRegexs().length != 0) &&
mTethering.getUpstreamIfaceRegexs().length != 0);
+ try {
+ nmService.registerObserver(mTethering);
+ } catch (RemoteException e) {
+ loge("Error registering observer :" + e);
+ }
+
if (DBG) {
mInetLog = new ArrayList();
}
@@ -557,25 +566,32 @@ public class ConnectivityService extends IConnectivityManager.Stub {
*/
private boolean isNetworkBlocked(NetworkInfo info, int uid) {
synchronized (mUidRules) {
- return isNetworkBlockedLocked(info, uid);
+ // TODO: expand definition of "paid" network to cover tethered or
+ // paid hotspot use cases.
+ final boolean networkIsPaid = info.getType() != ConnectivityManager.TYPE_WIFI;
+ final int uidRules = mUidRules.get(uid, RULE_ALLOW_ALL);
+
+ if (networkIsPaid && (uidRules & RULE_REJECT_PAID) != 0) {
+ return true;
+ }
+
+ // no restrictive rules; network is visible
+ return false;
}
}
/**
- * Check if UID is blocked from using the given {@link NetworkInfo}.
+ * Return a filtered version of the given {@link NetworkInfo}, potentially
+ * marked {@link DetailedState#BLOCKED} based on
+ * {@link #isNetworkBlocked(NetworkInfo, int)}.
*/
- private boolean isNetworkBlockedLocked(NetworkInfo info, int uid) {
- // TODO: expand definition of "paid" network to cover tethered or paid
- // hotspot use cases.
- final boolean networkIsPaid = info.getType() != ConnectivityManager.TYPE_WIFI;
- final int uidRules = mUidRules.get(uid, RULE_ALLOW_ALL);
-
- if (networkIsPaid && (uidRules & RULE_REJECT_PAID) != 0) {
- return true;
+ private NetworkInfo filterNetworkInfo(NetworkInfo info, int uid) {
+ if (isNetworkBlocked(info, uid)) {
+ // network is blocked; clone and override state
+ info = new NetworkInfo(info);
+ info.setDetailedState(DetailedState.BLOCKED, null, null);
}
-
- // no restrictive rules; network is visible
- return false;
+ return info;
}
/**
@@ -610,12 +626,7 @@ public class ConnectivityService extends IConnectivityManager.Stub {
if (isNetworkTypeValid(networkType)) {
final NetworkStateTracker tracker = mNetTrackers[networkType];
if (tracker != null) {
- info = tracker.getNetworkInfo();
- if (isNetworkBlocked(info, uid)) {
- // network is blocked; clone and override state
- info = new NetworkInfo(info);
- info.setDetailedState(DetailedState.BLOCKED, null, null);
- }
+ info = filterNetworkInfo(tracker.getNetworkInfo(), uid);
}
}
return info;
@@ -625,22 +636,15 @@ public class ConnectivityService extends IConnectivityManager.Stub {
public NetworkInfo[] getAllNetworkInfo() {
enforceAccessPermission();
final int uid = Binder.getCallingUid();
- final NetworkInfo[] result = new NetworkInfo[mNetworksDefined];
- int i = 0;
+ final ArrayList<NetworkInfo> result = Lists.newArrayList();
synchronized (mUidRules) {
for (NetworkStateTracker tracker : mNetTrackers) {
if (tracker != null) {
- NetworkInfo info = tracker.getNetworkInfo();
- if (isNetworkBlockedLocked(info, uid)) {
- // network is blocked; clone and override state
- info = new NetworkInfo(info);
- info.setDetailedState(DetailedState.BLOCKED, null, null);
- }
- result[i++] = info;
+ result.add(filterNetworkInfo(tracker.getNetworkInfo(), uid));
}
}
}
- return result;
+ return result.toArray(new NetworkInfo[result.size()]);
}
/**
@@ -668,6 +672,23 @@ public class ConnectivityService extends IConnectivityManager.Stub {
return null;
}
+ @Override
+ public NetworkState[] getAllNetworkState() {
+ enforceAccessPermission();
+ final int uid = Binder.getCallingUid();
+ final ArrayList<NetworkState> result = Lists.newArrayList();
+ synchronized (mUidRules) {
+ for (NetworkStateTracker tracker : mNetTrackers) {
+ if (tracker != null) {
+ final NetworkInfo info = filterNetworkInfo(tracker.getNetworkInfo(), uid);
+ result.add(new NetworkState(
+ info, tracker.getLinkProperties(), tracker.getLinkCapabilities()));
+ }
+ }
+ }
+ return result.toArray(new NetworkState[result.size()]);
+ }
+
public boolean setRadios(boolean turnOn) {
boolean result = true;
enforceChangePermission();
diff --git a/services/java/com/android/server/MountService.java b/services/java/com/android/server/MountService.java
index f78dca96d243..c86f96237f44 100644
--- a/services/java/com/android/server/MountService.java
+++ b/services/java/com/android/server/MountService.java
@@ -1121,16 +1121,20 @@ class MountService extends IMountService.Stub implements INativeDaemonConnectorC
com.android.internal.R.styleable.Storage_emulated, false);
int mtpReserve = a.getInt(
com.android.internal.R.styleable.Storage_mtpReserve, 0);
+ boolean allowMassStorage = a.getBoolean(
+ com.android.internal.R.styleable.Storage_allowMassStorage, false);
Slog.d(TAG, "got storage path: " + path + " description: " + description +
" primary: " + primary + " removable: " + removable +
- " emulated: " + emulated + " mtpReserve: " + mtpReserve);
+ " emulated: " + emulated + " mtpReserve: " + mtpReserve +
+ " allowMassStorage: " + allowMassStorage);
if (path == null || description == null) {
Slog.e(TAG, "path or description is null in readStorageList");
} else {
String pathString = path.toString();
StorageVolume volume = new StorageVolume(pathString,
- description.toString(), removable, emulated, mtpReserve);
+ description.toString(), removable, emulated,
+ mtpReserve, allowMassStorage);
if (primary) {
if (mPrimaryVolume == null) {
mPrimaryVolume = volume;
diff --git a/services/java/com/android/server/SystemBackupAgent.java b/services/java/com/android/server/SystemBackupAgent.java
index 99c8af62d1d6..08c66996128e 100644
--- a/services/java/com/android/server/SystemBackupAgent.java
+++ b/services/java/com/android/server/SystemBackupAgent.java
@@ -138,7 +138,7 @@ public class SystemBackupAgent extends BackupAgentHelper {
if (outFile == null) {
Slog.w(TAG, "Skipping unrecognized system file: [ " + domain + " : " + path + " ]");
}
- FullBackup.restoreToFile(data, size, type, mode, mtime, outFile);
+ FullBackup.restoreToFile(data, size, type, mode, mtime, outFile, true);
if (restoredWallpaper) {
WallpaperManagerService wallpaper =
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index 596cbac4937f..fd03e5f8930a 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -305,6 +305,7 @@ class ServerThread extends Thread {
Slog.i(TAG, "Connectivity Service");
connectivity = new ConnectivityService(context, networkManagement, networkPolicy);
ServiceManager.addService(Context.CONNECTIVITY_SERVICE, connectivity);
+ networkStats.bindConnectivityManager(connectivity);
} catch (Throwable e) {
Slog.e(TAG, "Failure starting Connectivity Service", e);
}
diff --git a/services/java/com/android/server/WifiService.java b/services/java/com/android/server/WifiService.java
index 41ec63a53c90..4e2501b460e7 100644
--- a/services/java/com/android/server/WifiService.java
+++ b/services/java/com/android/server/WifiService.java
@@ -321,6 +321,13 @@ public class WifiService extends IWifiManager.Stub {
}
break;
}
+ case AsyncChannel.CMD_CHANNEL_DISCONNECTED: {
+ Slog.e(TAG, "WifiStateMachine channel lost, msg.arg1 =" + msg.arg1);
+ mWifiStateMachineChannel = null;
+ //Re-establish connection to state machine
+ mWsmChannel.connect(mContext, this, mWifiStateMachine.getHandler());
+ break;
+ }
default: {
Slog.d(TAG, "WifiStateMachineHandler.handleMessage ignoring msg=" + msg);
break;
@@ -593,7 +600,12 @@ public class WifiService extends IWifiManager.Stub {
*/
public WifiConfiguration getWifiApConfiguration() {
enforceAccessPermission();
- return mWifiStateMachine.syncGetWifiApConfiguration(mWifiStateMachineChannel);
+ if (mWifiStateMachineChannel != null) {
+ return mWifiStateMachine.syncGetWifiApConfiguration(mWifiStateMachineChannel);
+ } else {
+ Slog.e(TAG, "mWifiStateMachineChannel is not initialized");
+ return null;
+ }
}
/**
diff --git a/services/java/com/android/server/WifiWatchdogService.java b/services/java/com/android/server/WifiWatchdogService.java
index 6ef6963c8a69..6c7895e35b14 100644
--- a/services/java/com/android/server/WifiWatchdogService.java
+++ b/services/java/com/android/server/WifiWatchdogService.java
@@ -36,16 +36,21 @@ import android.provider.Settings;
import android.text.TextUtils;
import android.util.Slog;
+import java.io.BufferedInputStream;
+import java.io.InputStream;
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
+import java.net.HttpURLConnection;
import java.net.InetAddress;
import java.net.SocketException;
import java.net.SocketTimeoutException;
import java.net.UnknownHostException;
+import java.net.URL;
import java.util.Collection;
import java.util.List;
import java.util.Random;
+import java.util.Scanner;
/**
* {@link WifiWatchdogService} monitors the initial connection to a Wi-Fi
@@ -195,6 +200,34 @@ public class WifiWatchdogService {
return Settings.Secure.getInt(mContentResolver,
Settings.Secure.WIFI_WATCHDOG_PING_DELAY_MS, 250);
}
+
+ /**
+ * @see android.provider.Settings.Secure#WIFI_WATCHDOG_WALLED_GARDEN_TEST_ENABLED
+ */
+ private Boolean isWalledGardenTestEnabled() {
+ return Settings.Secure.getInt(mContentResolver,
+ Settings.Secure.WIFI_WATCHDOG_WALLED_GARDEN_TEST_ENABLED, 1) == 1;
+ }
+
+ /**
+ * @see android.provider.Settings.Secure#WIFI_WATCHDOG_WALLED_GARDEN_URL
+ */
+ private String getWalledGardenUrl() {
+ String url = Settings.Secure.getString(mContentResolver,
+ Settings.Secure.WIFI_WATCHDOG_WALLED_GARDEN_URL);
+ if (TextUtils.isEmpty(url)) return "http://www.google.com/";
+ return url;
+ }
+
+ /**
+ * @see android.provider.Settings.Secure#WIFI_WATCHDOG_WALLED_GARDEN_PATTERN
+ */
+ private String getWalledGardenPattern() {
+ String pattern = Settings.Secure.getString(mContentResolver,
+ Settings.Secure.WIFI_WATCHDOG_WALLED_GARDEN_PATTERN);
+ if (TextUtils.isEmpty(pattern)) return "<title>.*Google.*</title>";
+ return pattern;
+ }
/**
* @see android.provider.Settings.Secure#WIFI_WATCHDOG_ACCEPTABLE_PACKET_LOSS_PERCENTAGE
@@ -509,7 +542,7 @@ public class WifiWatchdogService {
// This access point does not require a watchdog, so queue idle on the main thread
mHandler.idle();
}
- mHandler.checkWalledGarden(ssid);
+ if (isWalledGardenTestEnabled()) mHandler.checkWalledGarden(ssid);
}
/**
@@ -1118,19 +1151,35 @@ public class WifiWatchdogService {
}
}
+ /**
+ * DNS based detection techniques do not work at all hotspots. The one sure way to check
+ * a walled garden is to see if a URL fetch on a known address fetches the data we
+ * expect
+ */
private boolean isWalledGardenConnection() {
- //One way to detect a walled garden is to see if multiple DNS queries
- //resolve to the same IP address
+ InputStream in = null;
+ HttpURLConnection urlConnection = null;
try {
- String host1 = "www.google.com";
- String host2 = "www.android.com";
- String address1 = InetAddress.getByName(host1).getHostAddress();
- String address2 = InetAddress.getByName(host2).getHostAddress();
- if (address1.equals(address2)) return true;
- } catch (UnknownHostException e) {
+ URL url = new URL(getWalledGardenUrl());
+ urlConnection = (HttpURLConnection) url.openConnection();
+ in = new BufferedInputStream(urlConnection.getInputStream());
+ Scanner scanner = new Scanner(in);
+ if (scanner.findInLine(getWalledGardenPattern()) != null) {
+ return false;
+ } else {
+ return true;
+ }
+ } catch (IOException e) {
return false;
+ } finally {
+ if (in != null) {
+ try {
+ in.close();
+ } catch (IOException e) {
+ }
+ }
+ if (urlConnection != null) urlConnection.disconnect();
}
- return false;
}
private void handleWalledGardenCheck(String ssid) {
diff --git a/services/java/com/android/server/accessibility/TouchExplorer.java b/services/java/com/android/server/accessibility/TouchExplorer.java
index 4c7f595de111..aab189a68cda 100644
--- a/services/java/com/android/server/accessibility/TouchExplorer.java
+++ b/services/java/com/android/server/accessibility/TouchExplorer.java
@@ -226,8 +226,9 @@ public class TouchExplorer implements Explorer {
// Send a hover for every finger down so the user gets feedback
// where she is currently touching.
mSendHoverDelayed.forceSendAndRemove();
- mSendHoverDelayed.post(event, MotionEvent.ACTION_HOVER_ENTER, 1, policyFlags,
- DELAY_SEND_HOVER_MOVE);
+ final int pointerIdBits = (1 << event.getActionIndex());
+ mSendHoverDelayed.post(event, MotionEvent.ACTION_HOVER_ENTER, pointerIdBits,
+ policyFlags, DELAY_SEND_HOVER_MOVE);
} break;
case MotionEvent.ACTION_POINTER_DOWN: {
switch (activePointerCount) {
@@ -350,11 +351,12 @@ public class TouchExplorer implements Explorer {
if (isDraggingGesture(event)) {
// Two pointers moving in the same direction within
// a given distance perform a drag.
- mCurrentState = STATE_DRAGGING;
+ mCurrentState = STATE_DRAGGING;
if (mTouchExploreGestureInProgress) {
sendAccessibilityEvent(TYPE_TOUCH_EXPLORATION_GESTURE_END);
mTouchExploreGestureInProgress = false;
}
+ mLastTouchExploreEvent = null;
mDraggingPointerId = pointerId;
sendMotionEvent(event, MotionEvent.ACTION_DOWN, pointerIdBits,
policyFlags);
@@ -365,6 +367,7 @@ public class TouchExplorer implements Explorer {
sendAccessibilityEvent(TYPE_TOUCH_EXPLORATION_GESTURE_END);
mTouchExploreGestureInProgress = false;
}
+ mLastTouchExploreEvent = null;
sendDownForAllActiveNotInjectedPointers(event, policyFlags);
}
} break;
@@ -382,6 +385,7 @@ public class TouchExplorer implements Explorer {
sendAccessibilityEvent(TYPE_TOUCH_EXPLORATION_GESTURE_END);
mTouchExploreGestureInProgress = false;
}
+ mLastTouchExploreEvent = null;
sendDownForAllActiveNotInjectedPointers(event, policyFlags);
}
}
@@ -728,7 +732,7 @@ public class TouchExplorer implements Explorer {
/**
* Sends an event.
*
- * @param event The event to send.
+ * @param prototype The prototype from which to create the injected events.
* @param action The action of the event.
* @param pointerIdBits The bits of the pointers to send.
* @param policyFlags The policy flags associated with the event.
@@ -979,7 +983,7 @@ public class TouchExplorer implements Explorer {
case MotionEvent.ACTION_DOWN: {
// New gesture so restart tracking injected down pointers.
mInjectedPointersDown = 0;
- handleReceivedPointerDown(0, event);
+ handleReceivedPointerDown(event.getActionIndex(), event);
} break;
case MotionEvent.ACTION_POINTER_DOWN: {
handleReceivedPointerDown(event.getActionIndex(), event);
@@ -988,7 +992,7 @@ public class TouchExplorer implements Explorer {
handleReceivedPointerMove(event);
} break;
case MotionEvent.ACTION_UP: {
- handleReceivedPointerUp(0, event);
+ handleReceivedPointerUp(event.getActionIndex(), event);
} break;
case MotionEvent.ACTION_POINTER_UP: {
handleReceivedPointerUp(event.getActionIndex(), event);
@@ -1008,13 +1012,13 @@ public class TouchExplorer implements Explorer {
final int action = event.getActionMasked();
switch (action) {
case MotionEvent.ACTION_DOWN: {
- handleInjectedPointerDown(0, event);
+ handleInjectedPointerDown(event.getActionIndex(), event);
} break;
case MotionEvent.ACTION_POINTER_DOWN: {
handleInjectedPointerDown(event.getActionIndex(), event);
} break;
case MotionEvent.ACTION_UP: {
- handleInjectedPointerUp(0, event);
+ handleInjectedPointerUp(event.getActionIndex(), event);
} break;
case MotionEvent.ACTION_POINTER_UP: {
handleInjectedPointerUp(event.getActionIndex(), event);
diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java
index c2a8a1db01ab..da9f1d6844b5 100644
--- a/services/java/com/android/server/am/ActivityManagerService.java
+++ b/services/java/com/android/server/am/ActivityManagerService.java
@@ -92,7 +92,6 @@ import android.os.FileObserver;
import android.os.FileUtils;
import android.os.Handler;
import android.os.IBinder;
-import android.os.IInterface;
import android.os.IPermissionController;
import android.os.Looper;
import android.os.Message;
diff --git a/services/java/com/android/server/connectivity/Tethering.java b/services/java/com/android/server/connectivity/Tethering.java
index 7ea05916c2fd..5fa26ef5f03e 100644
--- a/services/java/com/android/server/connectivity/Tethering.java
+++ b/services/java/com/android/server/connectivity/Tethering.java
@@ -129,13 +129,6 @@ public class Tethering extends INetworkManagementEventObserver.Stub {
mNMService = nmService;
mLooper = looper;
- // register for notifications from NetworkManagement Service
- try {
- mNMService.registerObserver(this);
- } catch (RemoteException e) {
- Log.e(TAG, "Error registering observer :" + e);
- }
-
mIfaces = new HashMap<String, TetherInterfaceSM>();
// make our own thread so we don't anr the system
diff --git a/services/java/com/android/server/net/InterfaceIdentity.java b/services/java/com/android/server/net/InterfaceIdentity.java
new file mode 100644
index 000000000000..ff86581effc9
--- /dev/null
+++ b/services/java/com/android/server/net/InterfaceIdentity.java
@@ -0,0 +1,73 @@
+/*
+ * Copyright (C) 2011 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.net;
+
+import java.io.DataInputStream;
+import java.io.DataOutputStream;
+import java.io.IOException;
+import java.net.ProtocolException;
+import java.util.HashSet;
+
+/**
+ * Identity of a {@code iface}, defined by the set of {@link NetworkIdentity}
+ * active on that interface.
+ *
+ * @hide
+ */
+public class InterfaceIdentity extends HashSet<NetworkIdentity> {
+ private static final int VERSION_CURRENT = 1;
+
+ public InterfaceIdentity() {
+ }
+
+ public InterfaceIdentity(DataInputStream in) throws IOException {
+ final int version = in.readInt();
+ switch (version) {
+ case VERSION_CURRENT: {
+ final int size = in.readInt();
+ for (int i = 0; i < size; i++) {
+ add(new NetworkIdentity(in));
+ }
+ break;
+ }
+ default: {
+ throw new ProtocolException("unexpected version: " + version);
+ }
+ }
+ }
+
+ public void writeToStream(DataOutputStream out) throws IOException {
+ out.writeInt(VERSION_CURRENT);
+ out.writeInt(size());
+ for (NetworkIdentity ident : this) {
+ ident.writeToStream(out);
+ }
+ }
+
+ /**
+ * Test if any {@link NetworkIdentity} on this interface matches the given
+ * template and IMEI.
+ */
+ public boolean matchesTemplate(int networkTemplate, String subscriberId) {
+ for (NetworkIdentity ident : this) {
+ if (ident.matchesTemplate(networkTemplate, subscriberId)) {
+ return true;
+ }
+ }
+ return false;
+ }
+}
diff --git a/services/java/com/android/server/net/NetworkIdentity.java b/services/java/com/android/server/net/NetworkIdentity.java
new file mode 100644
index 000000000000..79feb95f3463
--- /dev/null
+++ b/services/java/com/android/server/net/NetworkIdentity.java
@@ -0,0 +1,208 @@
+/*
+ * Copyright (C) 2011 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.net;
+
+import static android.net.ConnectivityManager.TYPE_WIFI;
+import static android.net.ConnectivityManager.TYPE_WIMAX;
+import static android.net.ConnectivityManager.isNetworkTypeMobile;
+import static android.net.TrafficStats.TEMPLATE_MOBILE_3G_LOWER;
+import static android.net.TrafficStats.TEMPLATE_MOBILE_4G;
+import static android.net.TrafficStats.TEMPLATE_MOBILE_ALL;
+import static android.net.TrafficStats.TEMPLATE_WIFI;
+import static android.telephony.TelephonyManager.NETWORK_CLASS_2_G;
+import static android.telephony.TelephonyManager.NETWORK_CLASS_3_G;
+import static android.telephony.TelephonyManager.NETWORK_CLASS_4_G;
+import static android.telephony.TelephonyManager.getNetworkClass;
+
+import android.content.Context;
+import android.net.ConnectivityManager;
+import android.net.NetworkInfo;
+import android.net.NetworkState;
+import android.telephony.TelephonyManager;
+
+import com.android.internal.util.Objects;
+
+import java.io.DataInputStream;
+import java.io.DataOutputStream;
+import java.io.IOException;
+import java.net.ProtocolException;
+
+/**
+ * Identity of a {@link NetworkInfo}, defined by network type and billing
+ * relationship (such as IMSI).
+ *
+ * @hide
+ */
+public class NetworkIdentity {
+ private static final int VERSION_CURRENT = 1;
+
+ public final int type;
+ public final int subType;
+ public final String subscriberId;
+
+ public NetworkIdentity(int type, int subType, String subscriberId) {
+ this.type = type;
+ this.subType = subType;
+ this.subscriberId = subscriberId;
+ }
+
+ public NetworkIdentity(DataInputStream in) throws IOException {
+ final int version = in.readInt();
+ switch (version) {
+ case VERSION_CURRENT: {
+ type = in.readInt();
+ subType = in.readInt();
+ subscriberId = in.readUTF();
+ break;
+ }
+ default: {
+ throw new ProtocolException("unexpected version: " + version);
+ }
+ }
+ }
+
+ public void writeToStream(DataOutputStream out) throws IOException {
+ out.writeInt(VERSION_CURRENT);
+ out.writeInt(type);
+ out.writeInt(subType);
+ out.writeUTF(subscriberId);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hashCode(type, subType, subscriberId);
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (obj instanceof NetworkIdentity) {
+ final NetworkIdentity ident = (NetworkIdentity) obj;
+ return type == ident.type && subType == ident.subType
+ && Objects.equal(subscriberId, ident.subscriberId);
+ }
+ return false;
+ }
+
+ @Override
+ public String toString() {
+ final String typeName = ConnectivityManager.getNetworkTypeName(type);
+ final String subTypeName;
+ if (ConnectivityManager.isNetworkTypeMobile(type)) {
+ subTypeName = TelephonyManager.getNetworkTypeName(subType);
+ } else {
+ subTypeName = Integer.toString(subType);
+ }
+
+ return "[type=" + typeName + ", subType=" + subTypeName + ", subId=" + subscriberId + "]";
+ }
+
+ /**
+ * Test if this network matches the given template and IMEI.
+ */
+ public boolean matchesTemplate(int networkTemplate, String subscriberId) {
+ switch (networkTemplate) {
+ case TEMPLATE_MOBILE_ALL:
+ return matchesMobile(subscriberId);
+ case TEMPLATE_MOBILE_3G_LOWER:
+ return matchesMobile3gLower(subscriberId);
+ case TEMPLATE_MOBILE_4G:
+ return matchesMobile4g(subscriberId);
+ case TEMPLATE_WIFI:
+ return matchesWifi();
+ default:
+ throw new IllegalArgumentException("unknown network template");
+ }
+ }
+
+ /**
+ * Check if mobile network with matching IMEI. Also matches
+ * {@link #TYPE_WIMAX}.
+ */
+ private boolean matchesMobile(String subscriberId) {
+ if (isNetworkTypeMobile(type) && Objects.equal(this.subscriberId, subscriberId)) {
+ return true;
+ } else if (type == TYPE_WIMAX) {
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * Check if mobile network classified 3G or lower with matching IMEI.
+ */
+ private boolean matchesMobile3gLower(String subscriberId) {
+ if (isNetworkTypeMobile(type)
+ && Objects.equal(this.subscriberId, subscriberId)) {
+ switch (getNetworkClass(subType)) {
+ case NETWORK_CLASS_2_G:
+ case NETWORK_CLASS_3_G:
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Check if mobile network classified 4G with matching IMEI. Also matches
+ * {@link #TYPE_WIMAX}.
+ */
+ private boolean matchesMobile4g(String subscriberId) {
+ if (isNetworkTypeMobile(type)
+ && Objects.equal(this.subscriberId, subscriberId)) {
+ switch (getNetworkClass(subType)) {
+ case NETWORK_CLASS_4_G:
+ return true;
+ }
+ } else if (type == TYPE_WIMAX) {
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * Check if matches Wi-Fi network template.
+ */
+ private boolean matchesWifi() {
+ if (type == TYPE_WIFI) {
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * Build a {@link NetworkIdentity} from the given {@link NetworkState},
+ * assuming that any mobile networks are using the current IMSI.
+ */
+ public static NetworkIdentity buildNetworkIdentity(Context context, NetworkState state) {
+ final int type = state.networkInfo.getType();
+ final int subType = state.networkInfo.getSubtype();
+
+ // TODO: consider moving subscriberId over to LinkCapabilities, so it
+ // comes from an authoritative source.
+
+ final String subscriberId;
+ if (isNetworkTypeMobile(type)) {
+ final TelephonyManager telephony = (TelephonyManager) context.getSystemService(
+ Context.TELEPHONY_SERVICE);
+ subscriberId = telephony.getSubscriberId();
+ } else {
+ subscriberId = null;
+ }
+ return new NetworkIdentity(type, subType, subscriberId);
+ }
+
+}
diff --git a/services/java/com/android/server/net/NetworkPolicyManagerService.java b/services/java/com/android/server/net/NetworkPolicyManagerService.java
index 17c7161d06d6..1a90a92449d3 100644
--- a/services/java/com/android/server/net/NetworkPolicyManagerService.java
+++ b/services/java/com/android/server/net/NetworkPolicyManagerService.java
@@ -89,6 +89,8 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
// TODO: keep record of billing cycle details, and limit rules
// TODO: keep map of interfaces-to-billing-relationship
+ // TODO: dispatch callbacks through handler when locked
+
public NetworkPolicyManagerService(Context context, IActivityManager activityManager,
IPowerManager powerManager, INetworkStatsService networkStats) {
mContext = checkNotNull(context, "missing context");
diff --git a/services/java/com/android/server/net/NetworkStatsService.java b/services/java/com/android/server/net/NetworkStatsService.java
index d9c1f25b7293..3892de81319b 100644
--- a/services/java/com/android/server/net/NetworkStatsService.java
+++ b/services/java/com/android/server/net/NetworkStatsService.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2008 The Android Open Source Project
+ * Copyright (C) 2011 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.
@@ -16,12 +16,23 @@
package com.android.server.net;
+import static android.Manifest.permission.CONNECTIVITY_INTERNAL;
import static android.Manifest.permission.DUMP;
import static android.Manifest.permission.SHUTDOWN;
import static android.Manifest.permission.UPDATE_DEVICE_STATS;
-import static android.net.ConnectivityManager.TYPE_MOBILE;
-import static android.net.ConnectivityManager.TYPE_WIFI;
+import static android.net.ConnectivityManager.CONNECTIVITY_ACTION;
+import static android.net.NetworkStats.IFACE_ALL;
import static android.net.NetworkStats.UID_ALL;
+import static android.provider.Settings.Secure.NETSTATS_DETAIL_BUCKET_DURATION;
+import static android.provider.Settings.Secure.NETSTATS_DETAIL_MAX_HISTORY;
+import static android.provider.Settings.Secure.NETSTATS_PERSIST_THRESHOLD;
+import static android.provider.Settings.Secure.NETSTATS_POLL_INTERVAL;
+import static android.provider.Settings.Secure.NETSTATS_SUMMARY_BUCKET_DURATION;
+import static android.provider.Settings.Secure.NETSTATS_SUMMARY_MAX_HISTORY;
+import static android.text.format.DateUtils.DAY_IN_MILLIS;
+import static android.text.format.DateUtils.HOUR_IN_MILLIS;
+import static android.text.format.DateUtils.MINUTE_IN_MILLIS;
+import static com.android.internal.util.Preconditions.checkNotNull;
import android.app.AlarmManager;
import android.app.IAlarmManager;
@@ -30,29 +41,33 @@ import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
+import android.content.pm.ApplicationInfo;
+import android.net.IConnectivityManager;
import android.net.INetworkStatsService;
-import android.net.LinkProperties;
+import android.net.NetworkInfo;
+import android.net.NetworkState;
import android.net.NetworkStats;
import android.net.NetworkStatsHistory;
-import android.net.wifi.WifiManager;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.INetworkManagementService;
import android.os.RemoteException;
import android.os.SystemClock;
+import android.provider.Settings;
import android.telephony.TelephonyManager;
-import android.text.format.DateUtils;
import android.util.NtpTrustedTime;
import android.util.Slog;
+import android.util.SparseArray;
import android.util.TrustedTime;
-import com.android.internal.telephony.Phone;
-import com.android.internal.telephony.TelephonyIntents;
+import com.google.android.collect.Lists;
import com.google.android.collect.Maps;
import java.io.FileDescriptor;
import java.io.PrintWriter;
+import java.util.ArrayList;
import java.util.HashMap;
+import java.util.HashSet;
/**
* Collect and persist detailed network statistics, and provide this data to
@@ -67,39 +82,49 @@ public class NetworkStatsService extends INetworkStatsService.Stub {
private final IAlarmManager mAlarmManager;
private final TrustedTime mTime;
+ private IConnectivityManager mConnManager;
+
private static final String ACTION_NETWORK_STATS_POLL =
"com.android.server.action.NETWORK_STATS_POLL";
private PendingIntent mPollIntent;
- // TODO: move tweakable params to Settings.Secure
// TODO: listen for kernel push events through netd instead of polling
private static final long KB_IN_BYTES = 1024;
+ private static final long MB_IN_BYTES = 1024 * KB_IN_BYTES;
+ private static final long GB_IN_BYTES = 1024 * MB_IN_BYTES;
- private static final long POLL_INTERVAL = AlarmManager.INTERVAL_FIFTEEN_MINUTES;
- private static final long SUMMARY_BUCKET_DURATION = 6 * DateUtils.HOUR_IN_MILLIS;
- private static final long SUMMARY_MAX_HISTORY = 90 * DateUtils.DAY_IN_MILLIS;
-
- // TODO: remove these high-frequency testing values
-// private static final long POLL_INTERVAL = 5 * DateUtils.SECOND_IN_MILLIS;
-// private static final long SUMMARY_BUCKET_DURATION = 10 * DateUtils.SECOND_IN_MILLIS;
-// private static final long SUMMARY_MAX_HISTORY = 2 * DateUtils.MINUTE_IN_MILLIS;
+ private LongSecureSetting mPollInterval = new LongSecureSetting(
+ NETSTATS_POLL_INTERVAL, 15 * MINUTE_IN_MILLIS);
+ private LongSecureSetting mPersistThreshold = new LongSecureSetting(
+ NETSTATS_PERSIST_THRESHOLD, 64 * KB_IN_BYTES);
- /** Minimum delta required to persist to disk. */
- private static final long SUMMARY_PERSIST_THRESHOLD = 64 * KB_IN_BYTES;
+ private LongSecureSetting mSummaryBucketDuration = new LongSecureSetting(
+ NETSTATS_SUMMARY_BUCKET_DURATION, 6 * HOUR_IN_MILLIS);
+ private LongSecureSetting mSummaryMaxHistory = new LongSecureSetting(
+ NETSTATS_SUMMARY_MAX_HISTORY, 90 * DAY_IN_MILLIS);
+ private LongSecureSetting mDetailBucketDuration = new LongSecureSetting(
+ NETSTATS_DETAIL_BUCKET_DURATION, 6 * HOUR_IN_MILLIS);
+ private LongSecureSetting mDetailMaxHistory = new LongSecureSetting(
+ NETSTATS_DETAIL_MAX_HISTORY, 90 * DAY_IN_MILLIS);
- private static final long TIME_CACHE_MAX_AGE = DateUtils.DAY_IN_MILLIS;
+ private static final long TIME_CACHE_MAX_AGE = DAY_IN_MILLIS;
private final Object mStatsLock = new Object();
/** Set of active ifaces during this boot. */
- private HashMap<String, InterfaceInfo> mActiveIface = Maps.newHashMap();
+ private HashMap<String, InterfaceIdentity> mActiveIface = Maps.newHashMap();
+
/** Set of historical stats for known ifaces. */
- private HashMap<InterfaceInfo, NetworkStatsHistory> mIfaceStats = Maps.newHashMap();
+ private HashMap<InterfaceIdentity, NetworkStatsHistory> mSummaryStats = Maps.newHashMap();
+ /** Set of historical stats for known UIDs. */
+ private SparseArray<NetworkStatsHistory> mDetailStats = new SparseArray<NetworkStatsHistory>();
- private NetworkStats mLastPollStats;
- private NetworkStats mLastPersistStats;
+ private NetworkStats mLastSummaryPoll;
+ private NetworkStats mLastSummaryPersist;
+
+ private NetworkStats mLastDetailPoll;
private final HandlerThread mHandlerThread;
private final Handler mHandler;
@@ -132,13 +157,9 @@ public class NetworkStatsService extends INetworkStatsService.Stub {
readStatsLocked();
// watch other system services that claim interfaces
- // TODO: protect incoming broadcast with permissions check.
- // TODO: consider migrating this to ConnectivityService, but it might
- // cause a circular dependency.
- final IntentFilter interfaceFilter = new IntentFilter();
- interfaceFilter.addAction(TelephonyIntents.ACTION_ANY_DATA_CONNECTION_STATE_CHANGED);
- interfaceFilter.addAction(WifiManager.NETWORK_STATE_CHANGED_ACTION);
- mContext.registerReceiver(mInterfaceReceiver, interfaceFilter);
+ final IntentFilter ifaceFilter = new IntentFilter();
+ ifaceFilter.addAction(CONNECTIVITY_ACTION);
+ mContext.registerReceiver(mIfaceReceiver, ifaceFilter, CONNECTIVITY_INTERNAL, mHandler);
// listen for periodic polling events
final IntentFilter pollFilter = new IntentFilter(ACTION_NETWORK_STATS_POLL);
@@ -155,9 +176,13 @@ public class NetworkStatsService extends INetworkStatsService.Stub {
}
}
+ public void bindConnectivityManager(IConnectivityManager connManager) {
+ mConnManager = checkNotNull(connManager, "missing IConnectivityManager");
+ }
+
/**
* Clear any existing {@link #ACTION_NETWORK_STATS_POLL} alarms, and
- * reschedule based on current {@link #POLL_INTERVAL} value.
+ * reschedule based on current {@link #mPollInterval} value.
*/
private void registerPollAlarmLocked() throws RemoteException {
if (mPollIntent != null) {
@@ -169,49 +194,72 @@ public class NetworkStatsService extends INetworkStatsService.Stub {
final long currentRealtime = SystemClock.elapsedRealtime();
mAlarmManager.setInexactRepeating(
- AlarmManager.ELAPSED_REALTIME, currentRealtime, POLL_INTERVAL, mPollIntent);
+ AlarmManager.ELAPSED_REALTIME, currentRealtime, mPollInterval.get(), mPollIntent);
}
@Override
- public NetworkStatsHistory[] getNetworkStatsSummary(int networkType) {
- // TODO: return history for requested types
- return null;
+ public NetworkStatsHistory getHistoryForNetwork(int networkTemplate) {
+ // TODO: create relaxed permission for reading stats
+ mContext.enforceCallingOrSelfPermission(UPDATE_DEVICE_STATS, TAG);
+
+ synchronized (mStatsLock) {
+ // combine all interfaces that match template
+ final String subscriberId = getActiveSubscriberId();
+ final NetworkStatsHistory combined = new NetworkStatsHistory(
+ mSummaryBucketDuration.get());
+ for (InterfaceIdentity ident : mSummaryStats.keySet()) {
+ final NetworkStatsHistory history = mSummaryStats.get(ident);
+ if (ident.matchesTemplate(networkTemplate, subscriberId)) {
+ combined.recordEntireHistory(history);
+ }
+ }
+ return combined;
+ }
}
@Override
- public NetworkStatsHistory getNetworkStatsUid(int uid) {
+ public NetworkStatsHistory getHistoryForUid(int uid, int networkTemplate) {
+ // TODO: create relaxed permission for reading stats
+ mContext.enforceCallingOrSelfPermission(UPDATE_DEVICE_STATS, TAG);
+
// TODO: return history for requested uid
return null;
}
+ @Override
+ public NetworkStats getSummaryPerUid(long start, long end, int networkTemplate) {
+ // TODO: create relaxed permission for reading stats
+ mContext.enforceCallingOrSelfPermission(UPDATE_DEVICE_STATS, TAG);
+
+ // TODO: apply networktemplate once granular uid stats are stored.
+
+ synchronized (mStatsLock) {
+ final int size = mDetailStats.size();
+ final NetworkStats.Builder stats = new NetworkStats.Builder(end - start, size);
+
+ final long[] total = new long[2];
+ for (int i = 0; i < size; i++) {
+ final int uid = mDetailStats.keyAt(i);
+ final NetworkStatsHistory history = mDetailStats.valueAt(i);
+ history.getTotalData(start, end, total);
+ stats.addEntry(IFACE_ALL, uid, total[0], total[1]);
+ }
+ return stats.build();
+ }
+ }
+
/**
- * Receiver that watches for other system components that claim network
+ * Receiver that watches for {@link IConnectivityManager} to claim network
* interfaces. Used to associate {@link TelephonyManager#getSubscriberId()}
* with mobile interfaces.
*/
- private BroadcastReceiver mInterfaceReceiver = new BroadcastReceiver() {
+ private BroadcastReceiver mIfaceReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
- final String action = intent.getAction();
- if (TelephonyIntents.ACTION_ANY_DATA_CONNECTION_STATE_CHANGED.equals(action)) {
- final LinkProperties prop = intent.getParcelableExtra(
- Phone.DATA_LINK_PROPERTIES_KEY);
- final String iface = prop != null ? prop.getInterfaceName() : null;
- if (iface != null) {
- final TelephonyManager teleManager = (TelephonyManager) context
- .getSystemService(Context.TELEPHONY_SERVICE);
- final InterfaceInfo info = new InterfaceInfo(
- iface, TYPE_MOBILE, teleManager.getSubscriberId());
- reportActiveInterface(info);
- }
- } else if (WifiManager.NETWORK_STATE_CHANGED_ACTION.equals(action)) {
- final LinkProperties prop = intent.getParcelableExtra(
- WifiManager.EXTRA_LINK_PROPERTIES);
- final String iface = prop != null ? prop.getInterfaceName() : null;
- if (iface != null) {
- final InterfaceInfo info = new InterfaceInfo(iface, TYPE_WIFI, null);
- reportActiveInterface(info);
- }
+ // on background handler thread, and verified CONNECTIVITY_INTERNAL
+ // permission above.
+ synchronized (mStatsLock) {
+ updateIfacesLocked();
}
}
};
@@ -219,8 +267,8 @@ public class NetworkStatsService extends INetworkStatsService.Stub {
private BroadcastReceiver mPollReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
- // already running on background handler, network/io is safe, and
- // caller verified to have UPDATE_DEVICE_STATS permission above.
+ // on background handler thread, and verified UPDATE_DEVICE_STATS
+ // permission above.
synchronized (mStatsLock) {
// TODO: acquire wakelock while performing poll
performPollLocked();
@@ -231,13 +279,49 @@ public class NetworkStatsService extends INetworkStatsService.Stub {
private BroadcastReceiver mShutdownReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
- // persist stats during clean shutdown
+ // verified SHUTDOWN permission above.
synchronized (mStatsLock) {
writeStatsLocked();
}
}
};
+ /**
+ * Inspect all current {@link NetworkState} to derive mapping from {@code
+ * iface} to {@link NetworkStatsHistory}. When multiple {@link NetworkInfo}
+ * are active on a single {@code iface}, they are combined under a single
+ * {@link InterfaceIdentity}.
+ */
+ private void updateIfacesLocked() {
+ if (LOGD) Slog.v(TAG, "updateIfacesLocked()");
+
+ // take one last stats snapshot before updating iface mapping. this
+ // isn't perfect, since the kernel may already be counting traffic from
+ // the updated network.
+ // TODO: verify that we only poll summary stats, not uid details
+ performPollLocked();
+
+ final NetworkState[] states;
+ try {
+ states = mConnManager.getAllNetworkState();
+ } catch (RemoteException e) {
+ Slog.w(TAG, "problem reading network state");
+ return;
+ }
+
+ // rebuild active interfaces based on connected networks
+ mActiveIface.clear();
+
+ for (NetworkState state : states) {
+ if (state.networkInfo.isConnected()) {
+ // collect networks under their parent interfaces
+ final String iface = state.linkProperties.getInterfaceName();
+ final InterfaceIdentity ident = findOrCreateInterfaceLocked(iface);
+ ident.add(NetworkIdentity.buildNetworkIdentity(mContext, state));
+ }
+ }
+ }
+
private void performPollLocked() {
if (LOGD) Slog.v(TAG, "performPollLocked()");
@@ -250,58 +334,110 @@ public class NetworkStatsService extends INetworkStatsService.Stub {
final long currentTime = mTime.hasCache() ? mTime.currentTimeMillis()
: System.currentTimeMillis();
- final NetworkStats current;
+ final NetworkStats summary;
+ final NetworkStats detail;
try {
- current = mNetworkManager.getNetworkStatsSummary();
+ summary = mNetworkManager.getNetworkStatsSummary();
+ detail = mNetworkManager.getNetworkStatsDetail();
} catch (RemoteException e) {
Slog.w(TAG, "problem reading network stats");
return;
}
- // update historical usage with delta since last poll
- final NetworkStats pollDelta = computeStatsDelta(mLastPollStats, current);
- final long timeStart = currentTime - pollDelta.elapsedRealtime;
- for (String iface : pollDelta.getKnownIfaces()) {
- final InterfaceInfo info = mActiveIface.get(iface);
- if (info == null) {
- if (LOGD) Slog.w(TAG, "unknown interface " + iface + ", ignoring stats");
+ performSummaryPollLocked(summary, currentTime);
+ performDetailPollLocked(detail, currentTime);
+
+ // decide if enough has changed to trigger persist
+ final NetworkStats persistDelta = computeStatsDelta(mLastSummaryPersist, summary);
+ final long persistThreshold = mPersistThreshold.get();
+ for (String iface : persistDelta.getUniqueIfaces()) {
+ final int index = persistDelta.findIndex(iface, UID_ALL);
+ if (persistDelta.rx[index] > persistThreshold
+ || persistDelta.tx[index] > persistThreshold) {
+ writeStatsLocked();
+ mLastSummaryPersist = summary;
+ break;
+ }
+ }
+ }
+
+ /**
+ * Update {@link #mSummaryStats} historical usage.
+ */
+ private void performSummaryPollLocked(NetworkStats summary, long currentTime) {
+ final ArrayList<String> unknownIface = Lists.newArrayList();
+
+ final NetworkStats delta = computeStatsDelta(mLastSummaryPoll, summary);
+ final long timeStart = currentTime - delta.elapsedRealtime;
+ final long maxHistory = mSummaryMaxHistory.get();
+ for (String iface : delta.getUniqueIfaces()) {
+ final InterfaceIdentity ident = mActiveIface.get(iface);
+ if (ident == null) {
+ unknownIface.add(iface);
continue;
}
- final int index = pollDelta.findIndex(iface, UID_ALL);
- final long rx = pollDelta.rx[index];
- final long tx = pollDelta.tx[index];
+ final int index = delta.findIndex(iface, UID_ALL);
+ final long rx = delta.rx[index];
+ final long tx = delta.tx[index];
- final NetworkStatsHistory history = findOrCreateHistoryLocked(info);
+ final NetworkStatsHistory history = findOrCreateSummaryLocked(ident);
history.recordData(timeStart, currentTime, rx, tx);
- history.removeBucketsBefore(currentTime - SUMMARY_MAX_HISTORY);
+ history.removeBucketsBefore(currentTime - maxHistory);
}
+ mLastSummaryPoll = summary;
- mLastPollStats = current;
+ if (LOGD && unknownIface.size() > 0) {
+ Slog.w(TAG, "unknown interfaces " + unknownIface.toString() + ", ignoring those stats");
+ }
+ }
- // decide if enough has changed to trigger persist
- final NetworkStats persistDelta = computeStatsDelta(mLastPersistStats, current);
- for (String iface : persistDelta.getKnownIfaces()) {
- final int index = persistDelta.findIndex(iface, UID_ALL);
- if (persistDelta.rx[index] > SUMMARY_PERSIST_THRESHOLD
- || persistDelta.tx[index] > SUMMARY_PERSIST_THRESHOLD) {
- writeStatsLocked();
- mLastPersistStats = current;
- break;
- }
+ /**
+ * Update {@link #mDetailStats} historical usage.
+ */
+ private void performDetailPollLocked(NetworkStats detail, long currentTime) {
+ final NetworkStats delta = computeStatsDelta(mLastDetailPoll, detail);
+ final long timeStart = currentTime - delta.elapsedRealtime;
+ final long maxHistory = mDetailMaxHistory.get();
+ for (int uid : delta.getUniqueUids()) {
+ final int index = delta.findIndex(IFACE_ALL, uid);
+ final long rx = delta.rx[index];
+ final long tx = delta.tx[index];
+
+ final NetworkStatsHistory history = findOrCreateDetailLocked(uid);
+ history.recordData(timeStart, currentTime, rx, tx);
+ history.removeBucketsBefore(currentTime - maxHistory);
}
+ mLastDetailPoll = detail;
}
- private NetworkStatsHistory findOrCreateHistoryLocked(InterfaceInfo info) {
- NetworkStatsHistory stats = mIfaceStats.get(info);
+ private NetworkStatsHistory findOrCreateSummaryLocked(InterfaceIdentity ident) {
+ NetworkStatsHistory stats = mSummaryStats.get(ident);
if (stats == null) {
- stats = new NetworkStatsHistory(
- info.networkType, info.identity, UID_ALL, SUMMARY_BUCKET_DURATION);
- mIfaceStats.put(info, stats);
+ stats = new NetworkStatsHistory(mSummaryBucketDuration.get());
+ mSummaryStats.put(ident, stats);
}
return stats;
}
+ private NetworkStatsHistory findOrCreateDetailLocked(int uid) {
+ NetworkStatsHistory stats = mDetailStats.get(uid);
+ if (stats == null) {
+ stats = new NetworkStatsHistory(mDetailBucketDuration.get());
+ mDetailStats.put(uid, stats);
+ }
+ return stats;
+ }
+
+ private InterfaceIdentity findOrCreateInterfaceLocked(String iface) {
+ InterfaceIdentity ident = mActiveIface.get(iface);
+ if (ident == null) {
+ ident = new InterfaceIdentity();
+ mActiveIface.put(iface, ident);
+ }
+ return ident;
+ }
+
private void readStatsLocked() {
if (LOGD) Slog.v(TAG, "readStatsLocked()");
// TODO: read historical stats from disk using AtomicFile
@@ -310,70 +446,96 @@ public class NetworkStatsService extends INetworkStatsService.Stub {
private void writeStatsLocked() {
if (LOGD) Slog.v(TAG, "writeStatsLocked()");
// TODO: persist historical stats to disk using AtomicFile
+ // TODO: consider duplicating stats and releasing lock while writing
}
@Override
protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
mContext.enforceCallingOrSelfPermission(DUMP, TAG);
- pw.println("Active interfaces:");
- for (InterfaceInfo info : mActiveIface.values()) {
- info.dump(" ", pw);
+ final HashSet<String> argSet = new HashSet<String>();
+ for (String arg : args) {
+ argSet.add(arg);
}
- pw.println("Known historical stats:");
- for (NetworkStatsHistory stats : mIfaceStats.values()) {
- stats.dump(" ", pw);
+ synchronized (mStatsLock) {
+ // TODO: remove this testing code, since it corrupts stats
+ if (argSet.contains("generate")) {
+ generateRandomLocked();
+ pw.println("Generated stub stats");
+ return;
+ }
+
+ pw.println("Active interfaces:");
+ for (String iface : mActiveIface.keySet()) {
+ final InterfaceIdentity ident = mActiveIface.get(iface);
+ pw.print(" iface="); pw.print(iface);
+ pw.print(" ident="); pw.println(ident.toString());
+ }
+
+ pw.println("Known historical stats:");
+ for (InterfaceIdentity ident : mSummaryStats.keySet()) {
+ final NetworkStatsHistory stats = mSummaryStats.get(ident);
+ pw.print(" ident="); pw.println(ident.toString());
+ stats.dump(" ", pw);
+ }
+
+ if (argSet.contains("detail")) {
+ pw.println("Known detail stats:");
+ for (int i = 0; i < mDetailStats.size(); i++) {
+ final int uid = mDetailStats.keyAt(i);
+ final NetworkStatsHistory stats = mDetailStats.valueAt(i);
+ pw.print(" UID="); pw.println(uid);
+ stats.dump(" ", pw);
+ }
+ }
}
}
/**
- * Details for a well-known network interface, including its name, network
- * type, and billing relationship identity (such as IMSI).
+ * @deprecated only for temporary testing
*/
- private static class InterfaceInfo {
- public final String iface;
- public final int networkType;
- public final String identity;
-
- public InterfaceInfo(String iface, int networkType, String identity) {
- this.iface = iface;
- this.networkType = networkType;
- this.identity = identity;
+ @Deprecated
+ private void generateRandomLocked() {
+ long end = System.currentTimeMillis();
+ long start = end - mSummaryMaxHistory.get();
+ long rx = 3 * GB_IN_BYTES;
+ long tx = 2 * GB_IN_BYTES;
+
+ mSummaryStats.clear();
+ for (InterfaceIdentity ident : mActiveIface.values()) {
+ final NetworkStatsHistory stats = findOrCreateSummaryLocked(ident);
+ stats.generateRandom(start, end, rx, tx);
}
- @Override
- public int hashCode() {
- final int prime = 31;
- int result = 1;
- result = prime * result + ((identity == null) ? 0 : identity.hashCode());
- result = prime * result + ((iface == null) ? 0 : iface.hashCode());
- result = prime * result + networkType;
- return result;
- }
+ end = System.currentTimeMillis();
+ start = end - mDetailMaxHistory.get();
+ rx = 500 * MB_IN_BYTES;
+ tx = 100 * MB_IN_BYTES;
- @Override
- public boolean equals(Object obj) {
- if (obj instanceof InterfaceInfo) {
- final InterfaceInfo info = (InterfaceInfo) obj;
- return equal(iface, info.iface) && networkType == info.networkType
- && equal(identity, info.identity);
- }
- return false;
+ mDetailStats.clear();
+ for (ApplicationInfo info : mContext.getPackageManager().getInstalledApplications(0)) {
+ final int uid = info.uid;
+ final NetworkStatsHistory stats = findOrCreateDetailLocked(uid);
+ stats.generateRandom(start, end, rx, tx);
}
+ }
+
+ private class LongSecureSetting {
+ private String mKey;
+ private long mDefaultValue;
- public void dump(String prefix, PrintWriter pw) {
- pw.print(prefix);
- pw.print("InterfaceInfo: iface="); pw.print(iface);
- pw.print(" networkType="); pw.print(networkType);
- pw.print(" identity="); pw.println(identity);
+ public LongSecureSetting(String key, long defaultValue) {
+ mKey = key;
+ mDefaultValue = defaultValue;
}
- }
- private void reportActiveInterface(InterfaceInfo info) {
- synchronized (mStatsLock) {
- // TODO: when interface redefined, port over historical stats
- mActiveIface.put(info.iface, info);
+ public long get() {
+ if (mContext != null) {
+ return Settings.Secure.getLong(mContext.getContentResolver(), mKey, mDefaultValue);
+ } else {
+ return mDefaultValue;
+ }
}
}
@@ -389,15 +551,10 @@ public class NetworkStatsService extends INetworkStatsService.Stub {
}
}
- private static boolean equal(Object a, Object b) {
- return a == b || (a != null && a.equals(b));
- }
-
- private static <T> T checkNotNull(T value, String message) {
- if (value == null) {
- throw new NullPointerException(message);
- }
- return value;
+ private String getActiveSubscriberId() {
+ final TelephonyManager telephony = (TelephonyManager) mContext.getSystemService(
+ Context.TELEPHONY_SERVICE);
+ return telephony.getSubscriberId();
}
}
diff --git a/services/java/com/android/server/wm/InputManager.java b/services/java/com/android/server/wm/InputManager.java
index 3095c37799d8..ee69311b0950 100644
--- a/services/java/com/android/server/wm/InputManager.java
+++ b/services/java/com/android/server/wm/InputManager.java
@@ -617,8 +617,13 @@ public class InputManager {
}
@SuppressWarnings("unused")
- public int getTapTimeout() {
- return ViewConfiguration.getTapTimeout();
+ public int getHoverTapTimeout() {
+ return ViewConfiguration.getHoverTapTimeout();
+ }
+
+ @SuppressWarnings("unused")
+ public int getHoverTapSlop() {
+ return ViewConfiguration.getHoverTapSlop();
}
@SuppressWarnings("unused")
@@ -632,11 +637,6 @@ public class InputManager {
}
@SuppressWarnings("unused")
- public int getTouchSlop() {
- return ViewConfiguration.get(mContext).getScaledTouchSlop();
- }
-
- @SuppressWarnings("unused")
public int getMaxEventsPerSecond() {
int result = 0;
try {
diff --git a/services/java/com/android/server/wm/WindowManagerService.java b/services/java/com/android/server/wm/WindowManagerService.java
index d95d4c543939..819c16eb08a8 100644
--- a/services/java/com/android/server/wm/WindowManagerService.java
+++ b/services/java/com/android/server/wm/WindowManagerService.java
@@ -153,6 +153,7 @@ public class WindowManagerService extends IWindowManager.Stub
static final boolean DEBUG_WINDOW_MOVEMENT = false;
static final boolean DEBUG_TOKEN_MOVEMENT = false;
static final boolean DEBUG_ORIENTATION = false;
+ static final boolean DEBUG_APP_ORIENTATION = false;
static final boolean DEBUG_CONFIGURATION = false;
static final boolean DEBUG_APP_TRANSITIONS = false;
static final boolean DEBUG_STARTING_WINDOW = false;
@@ -427,6 +428,7 @@ public class WindowManagerService extends IWindowManager.Stub
boolean mWindowsFreezingScreen = false;
long mFreezeGcPending = 0;
int mAppsFreezingScreen = 0;
+ int mLastWindowForcedOrientation = ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
int mLayoutSeq = 0;
@@ -3187,6 +3189,15 @@ public class WindowManagerService extends IWindowManager.Stub
}
public int getOrientationFromWindowsLocked() {
+ if (mDisplayFrozen || mOpeningApps.size() > 0 || mClosingApps.size() > 0) {
+ // If the display is frozen, some activities may be in the middle
+ // of restarting, and thus have removed their old window. If the
+ // window has the flag to hide the lock screen, then the lock screen
+ // can re-appear and inflict its own orientation on us. Keep the
+ // orientation stable until this all settles down.
+ return mLastWindowForcedOrientation;
+ }
+
int pos = mWindows.size() - 1;
while (pos >= 0) {
WindowState wtoken = mWindows.get(pos);
@@ -3194,7 +3205,7 @@ public class WindowManagerService extends IWindowManager.Stub
if (wtoken.mAppToken != null) {
// We hit an application window. so the orientation will be determined by the
// app window. No point in continuing further.
- return ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
+ return (mLastWindowForcedOrientation=ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED);
}
if (!wtoken.isVisibleLw() || !wtoken.mPolicyVisibilityAfterAnim) {
continue;
@@ -3204,10 +3215,10 @@ public class WindowManagerService extends IWindowManager.Stub
(req == ActivityInfo.SCREEN_ORIENTATION_BEHIND)){
continue;
} else {
- return req;
+ return (mLastWindowForcedOrientation=req);
}
}
- return ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
+ return (mLastWindowForcedOrientation=ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED);
}
public int getOrientationFromAppTokensLocked() {
@@ -3220,16 +3231,23 @@ public class WindowManagerService extends IWindowManager.Stub
while (pos >= 0) {
AppWindowToken wtoken = mAppTokens.get(pos);
pos--;
+
+ if (DEBUG_APP_ORIENTATION) Slog.v(TAG, "Checking app orientation: " + wtoken);
+
// if we're about to tear down this window and not seek for
// the behind activity, don't use it for orientation
if (!findingBehind
&& (!wtoken.hidden && wtoken.hiddenRequested)) {
+ if (DEBUG_ORIENTATION) Slog.v(TAG, "Skipping " + wtoken
+ + " -- going to hide");
continue;
}
if (!haveGroup) {
// We ignore any hidden applications on the top.
if (wtoken.hiddenRequested || wtoken.willBeHidden) {
+ if (DEBUG_ORIENTATION) Slog.v(TAG, "Skipping " + wtoken
+ + " -- hidden on top");
continue;
}
haveGroup = true;
@@ -3243,6 +3261,8 @@ public class WindowManagerService extends IWindowManager.Stub
// user's orientation.
if (lastOrientation != ActivityInfo.SCREEN_ORIENTATION_BEHIND
&& lastFullscreen) {
+ if (DEBUG_ORIENTATION) Slog.v(TAG, "Done at " + wtoken
+ + " -- end of group, return " + lastOrientation);
return lastOrientation;
}
}
@@ -3253,16 +3273,21 @@ public class WindowManagerService extends IWindowManager.Stub
lastFullscreen = wtoken.appFullscreen;
if (lastFullscreen
&& or != ActivityInfo.SCREEN_ORIENTATION_BEHIND) {
+ if (DEBUG_ORIENTATION) Slog.v(TAG, "Done at " + wtoken
+ + " -- full screen, return " + or);
return or;
}
// If this application has requested an explicit orientation,
// then use it.
if (or != ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED
&& or != ActivityInfo.SCREEN_ORIENTATION_BEHIND) {
+ if (DEBUG_ORIENTATION) Slog.v(TAG, "Done at " + wtoken
+ + " -- explicitly set, return " + or);
return or;
}
findingBehind |= (or == ActivityInfo.SCREEN_ORIENTATION_BEHIND);
}
+ if (DEBUG_ORIENTATION) Slog.v(TAG, "No app is requesting an orientation");
return ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
}
@@ -3335,15 +3360,6 @@ public class WindowManagerService extends IWindowManager.Stub
* android.os.IBinder)
*/
boolean updateOrientationFromAppTokensLocked(boolean inTransaction) {
- if (mDisplayFrozen || mOpeningApps.size() > 0 || mClosingApps.size() > 0) {
- // If the display is frozen, some activities may be in the middle
- // of restarting, and thus have removed their old window. If the
- // window has the flag to hide the lock screen, then the lock screen
- // can re-appear and inflict its own orientation on us. Keep the
- // orientation stable until this all settles down.
- return false;
- }
-
boolean changed = false;
long ident = Binder.clearCallingIdentity();
try {
@@ -8939,9 +8955,10 @@ public class WindowManagerService extends IWindowManager.Stub
pw.print(" mAppsFreezingScreen="); pw.print(mAppsFreezingScreen);
pw.print(" mWaitingForConfig="); pw.println(mWaitingForConfig);
pw.print(" mRotation="); pw.print(mRotation);
- pw.print(" mForcedAppOrientation="); pw.print(mForcedAppOrientation);
pw.print(" mRequestedRotation="); pw.print(mRequestedRotation);
pw.print(" mAltOrientation="); pw.println(mAltOrientation);
+ pw.print(" mLastWindowForcedOrientation"); pw.print(mLastWindowForcedOrientation);
+ pw.print(" mForcedAppOrientation="); pw.println(mForcedAppOrientation);
pw.print(" mDeferredRotation="); pw.print(mDeferredRotation);
pw.print(", mDeferredRotationAnimFlags="); pw.println(mDeferredRotationAnimFlags);
pw.print(" mAnimationPending="); pw.print(mAnimationPending);
diff --git a/services/jni/com_android_server_InputManager.cpp b/services/jni/com_android_server_InputManager.cpp
index 881882f104c2..7c5084fda650 100644
--- a/services/jni/com_android_server_InputManager.cpp
+++ b/services/jni/com_android_server_InputManager.cpp
@@ -56,7 +56,7 @@ namespace android {
// The exponent used to calculate the pointer speed scaling factor.
// The scaling factor is calculated as 2 ^ (speed * exponent),
// where the speed ranges from -7 to + 7 and is supplied by the user.
-static const float POINTER_SPEED_EXPONENT = 1.0f / 3;
+static const float POINTER_SPEED_EXPONENT = 1.0f / 4;
static struct {
jmethodID notifyConfigurationChanged;
@@ -76,10 +76,10 @@ static struct {
jmethodID getKeyRepeatTimeout;
jmethodID getKeyRepeatDelay;
jmethodID getMaxEventsPerSecond;
- jmethodID getTapTimeout;
+ jmethodID getHoverTapTimeout;
+ jmethodID getHoverTapSlop;
jmethodID getDoubleTapTimeout;
jmethodID getLongPressTimeout;
- jmethodID getTouchSlop;
jmethodID getPointerLayer;
jmethodID getPointerIcon;
} gCallbacksClassInfo;
@@ -410,32 +410,32 @@ void NativeInputManager::getReaderConfiguration(InputReaderConfiguration* outCon
env->DeleteLocalRef(excludedDeviceNames);
}
- jint tapTimeout = env->CallIntMethod(mCallbacksObj,
- gCallbacksClassInfo.getTapTimeout);
- if (!checkAndClearExceptionFromCallback(env, "getTapTimeout")) {
+ jint hoverTapTimeout = env->CallIntMethod(mCallbacksObj,
+ gCallbacksClassInfo.getHoverTapTimeout);
+ if (!checkAndClearExceptionFromCallback(env, "getHoverTapTimeout")) {
jint doubleTapTimeout = env->CallIntMethod(mCallbacksObj,
gCallbacksClassInfo.getDoubleTapTimeout);
if (!checkAndClearExceptionFromCallback(env, "getDoubleTapTimeout")) {
jint longPressTimeout = env->CallIntMethod(mCallbacksObj,
gCallbacksClassInfo.getLongPressTimeout);
if (!checkAndClearExceptionFromCallback(env, "getLongPressTimeout")) {
- outConfig->pointerGestureTapInterval = milliseconds_to_nanoseconds(tapTimeout);
+ outConfig->pointerGestureTapInterval = milliseconds_to_nanoseconds(hoverTapTimeout);
// We must ensure that the tap-drag interval is significantly shorter than
// the long-press timeout because the tap is held down for the entire duration
// of the double-tap timeout.
jint tapDragInterval = max(min(longPressTimeout - 100,
- doubleTapTimeout), tapTimeout);
+ doubleTapTimeout), hoverTapTimeout);
outConfig->pointerGestureTapDragInterval =
milliseconds_to_nanoseconds(tapDragInterval);
}
}
}
- jint touchSlop = env->CallIntMethod(mCallbacksObj,
- gCallbacksClassInfo.getTouchSlop);
- if (!checkAndClearExceptionFromCallback(env, "getTouchSlop")) {
- outConfig->pointerGestureTapSlop = touchSlop;
+ jint hoverTapSlop = env->CallIntMethod(mCallbacksObj,
+ gCallbacksClassInfo.getHoverTapSlop);
+ if (!checkAndClearExceptionFromCallback(env, "getHoverTapSlop")) {
+ outConfig->pointerGestureTapSlop = hoverTapSlop;
}
{ // acquire lock
@@ -1394,8 +1394,11 @@ int register_android_server_InputManager(JNIEnv* env) {
GET_METHOD_ID(gCallbacksClassInfo.getKeyRepeatDelay, clazz,
"getKeyRepeatDelay", "()I");
- GET_METHOD_ID(gCallbacksClassInfo.getTapTimeout, clazz,
- "getTapTimeout", "()I");
+ GET_METHOD_ID(gCallbacksClassInfo.getHoverTapTimeout, clazz,
+ "getHoverTapTimeout", "()I");
+
+ GET_METHOD_ID(gCallbacksClassInfo.getHoverTapSlop, clazz,
+ "getHoverTapSlop", "()I");
GET_METHOD_ID(gCallbacksClassInfo.getDoubleTapTimeout, clazz,
"getDoubleTapTimeout", "()I");
@@ -1403,9 +1406,6 @@ int register_android_server_InputManager(JNIEnv* env) {
GET_METHOD_ID(gCallbacksClassInfo.getLongPressTimeout, clazz,
"getLongPressTimeout", "()I");
- GET_METHOD_ID(gCallbacksClassInfo.getTouchSlop, clazz,
- "getTouchSlop", "()I");
-
GET_METHOD_ID(gCallbacksClassInfo.getMaxEventsPerSecond, clazz,
"getMaxEventsPerSecond", "()I");
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index 8732e2199890..7272b0838d08 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -469,6 +469,46 @@ public class TelephonyManager {
}
}
+ /** Unknown network class. {@hide} */
+ public static final int NETWORK_CLASS_UNKNOWN = 0;
+ /** Class of broadly defined "2G" networks. {@hide} */
+ public static final int NETWORK_CLASS_2_G = 1;
+ /** Class of broadly defined "3G" networks. {@hide} */
+ public static final int NETWORK_CLASS_3_G = 2;
+ /** Class of broadly defined "4G" networks. {@hide} */
+ public static final int NETWORK_CLASS_4_G = 3;
+
+ /**
+ * Return general class of network type, such as "3G" or "4G". In cases
+ * where classification is contentious, this method is conservative.
+ *
+ * @hide
+ */
+ public static int getNetworkClass(int networkType) {
+ switch (networkType) {
+ case NETWORK_TYPE_GPRS:
+ case NETWORK_TYPE_EDGE:
+ case NETWORK_TYPE_CDMA:
+ case NETWORK_TYPE_1xRTT:
+ case NETWORK_TYPE_IDEN:
+ return NETWORK_CLASS_2_G;
+ case NETWORK_TYPE_UMTS:
+ case NETWORK_TYPE_EVDO_0:
+ case NETWORK_TYPE_EVDO_A:
+ case NETWORK_TYPE_HSDPA:
+ case NETWORK_TYPE_HSUPA:
+ case NETWORK_TYPE_HSPA:
+ case NETWORK_TYPE_EVDO_B:
+ case NETWORK_TYPE_EHRPD:
+ case NETWORK_TYPE_HSPAP:
+ return NETWORK_CLASS_3_G;
+ case NETWORK_TYPE_LTE:
+ return NETWORK_CLASS_4_G;
+ default:
+ return NETWORK_CLASS_UNKNOWN;
+ }
+ }
+
/**
* Returns a string representation of the radio technology (network type)
* currently in use on the device.
@@ -477,7 +517,12 @@ public class TelephonyManager {
* @hide pending API council review
*/
public String getNetworkTypeName() {
- switch (getNetworkType()) {
+ return getNetworkTypeName(getNetworkType());
+ }
+
+ /** {@hide} */
+ public static String getNetworkTypeName(int type) {
+ switch (type) {
case NETWORK_TYPE_GPRS:
return "GPRS";
case NETWORK_TYPE_EDGE:
diff --git a/telephony/java/com/android/internal/telephony/BaseCommands.java b/telephony/java/com/android/internal/telephony/BaseCommands.java
index 0c4581b578b4..8427d1439895 100644
--- a/telephony/java/com/android/internal/telephony/BaseCommands.java
+++ b/telephony/java/com/android/internal/telephony/BaseCommands.java
@@ -96,8 +96,10 @@ public abstract class BaseCommands implements CommandsInterface {
protected Registrant mRestrictedStateRegistrant;
protected Registrant mGsmBroadcastSmsRegistrant;
- // Network Mode received from PhoneFactory
- protected int mNetworkMode;
+ // Preferred network type received from PhoneFactory.
+ // This is used when establishing a connection to the
+ // vendor ril so it starts up in the correct mode.
+ protected int mPreferredNetworkType;
// CDMA subscription received from PhoneFactory
protected int mCdmaSubscription;
// Type of Phone, GSM or CDMA. Set by CDMAPhone or GSMPhone.
diff --git a/telephony/java/com/android/internal/telephony/RIL.java b/telephony/java/com/android/internal/telephony/RIL.java
index 2c04b30f1cf0..572bbaa9d4c6 100644
--- a/telephony/java/com/android/internal/telephony/RIL.java
+++ b/telephony/java/com/android/internal/telephony/RIL.java
@@ -611,14 +611,14 @@ public final class RIL extends BaseCommands implements CommandsInterface {
//***** Constructors
- public RIL(Context context, int networkMode, int cdmaSubscription) {
+ public RIL(Context context, int preferredNetworkType, int cdmaSubscription) {
super(context);
if (RILJ_LOGD) {
- riljLog("RIL(context, networkMode=" + networkMode +
+ riljLog("RIL(context, preferredNetworkType=" + preferredNetworkType +
" cdmaSubscription=" + cdmaSubscription + ")");
}
mCdmaSubscription = cdmaSubscription;
- mNetworkMode = networkMode;
+ mPreferredNetworkType = preferredNetworkType;
mPhoneType = RILConstants.NO_PHONE;
PowerManager pm = (PowerManager)context.getSystemService(Context.POWER_SERVICE);
@@ -1813,6 +1813,8 @@ public final class RIL extends BaseCommands implements CommandsInterface {
rr.mp.writeInt(1);
rr.mp.writeInt(networkType);
+ mPreferredNetworkType = networkType;
+
if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest)
+ " : " + networkType);
@@ -2222,7 +2224,7 @@ public final class RIL extends BaseCommands implements CommandsInterface {
case RIL_REQUEST_STK_HANDLE_CALL_SETUP_REQUESTED_FROM_SIM: ret = responseInts(p); break;
case RIL_REQUEST_EXPLICIT_CALL_TRANSFER: ret = responseVoid(p); break;
case RIL_REQUEST_SET_PREFERRED_NETWORK_TYPE: ret = responseVoid(p); break;
- case RIL_REQUEST_GET_PREFERRED_NETWORK_TYPE: ret = responseInts(p); break;
+ case RIL_REQUEST_GET_PREFERRED_NETWORK_TYPE: ret = responseGetPreferredNetworkType(p); break;
case RIL_REQUEST_GET_NEIGHBORING_CELL_IDS: ret = responseCellList(p); break;
case RIL_REQUEST_SET_LOCATION_UPDATES: ret = responseVoid(p); break;
case RIL_REQUEST_CDMA_SET_SUBSCRIPTION_SOURCE: ret = responseVoid(p); break;
@@ -2737,7 +2739,7 @@ public final class RIL extends BaseCommands implements CommandsInterface {
// Initial conditions
setRadioPower(false, null);
- setPreferredNetworkType(mNetworkMode, null);
+ setPreferredNetworkType(mPreferredNetworkType, null);
setCdmaSubscriptionSource(mCdmaSubscription, null);
notifyRegistrantsRilConnectionChanged(((int[])ret)[0]);
break;
@@ -3161,6 +3163,18 @@ public final class RIL extends BaseCommands implements CommandsInterface {
return response;
}
+ private Object responseGetPreferredNetworkType(Parcel p) {
+ int [] response = (int[]) responseInts(p);
+
+ if (response.length >= 1) {
+ // Since this is the response for getPreferredNetworkType
+ // we'll assume that it should be the value we want the
+ // vendor ril to take if we reestablish a connection to it.
+ mPreferredNetworkType = response[0];
+ }
+ return response;
+ }
+
private Object responseGmsBroadcastConfig(Parcel p) {
int num;
ArrayList<SmsBroadcastConfigInfo> response;
diff --git a/tests/BiDiTests/res/layout/frame_layout_ltr.xml b/tests/BiDiTests/res/layout/frame_layout_ltr.xml
index bd324e3c0cad..61fd06e08532 100644
--- a/tests/BiDiTests/res/layout/frame_layout_ltr.xml
+++ b/tests/BiDiTests/res/layout/frame_layout_ltr.xml
@@ -18,7 +18,7 @@
android:id="@+id/frame_layout_ltr"
android:layout_width="match_parent"
android:layout_height="match_parent"
- android:horizontalDirection="ltr"
+ android:layoutDirection="ltr"
android:background="#FF000000">
<FrameLayout
@@ -52,28 +52,28 @@
<FrameLayout
android:layout_width="100dp"
android:layout_height="100dp"
- android:layout_gravity="top|before"
+ android:layout_gravity="top|start"
android:background="#FFFFFFFF">
</FrameLayout>
<FrameLayout
android:layout_width="100dp"
android:layout_height="100dp"
- android:layout_gravity="top|after"
+ android:layout_gravity="top|end"
android:background="#FFFFFF00">
</FrameLayout>
<FrameLayout
android:layout_width="100dp"
android:layout_height="100dp"
- android:layout_gravity="bottom|before"
+ android:layout_gravity="bottom|start"
android:background="#FFFFFFFF">
</FrameLayout>
<FrameLayout
android:layout_width="100dp"
android:layout_height="100dp"
- android:layout_gravity="bottom|after"
+ android:layout_gravity="bottom|end"
android:background="#FFFFFF00">
</FrameLayout>
diff --git a/tests/BiDiTests/res/layout/frame_layout_rtl.xml b/tests/BiDiTests/res/layout/frame_layout_rtl.xml
index 814f5e137b3f..598b41a233a2 100644
--- a/tests/BiDiTests/res/layout/frame_layout_rtl.xml
+++ b/tests/BiDiTests/res/layout/frame_layout_rtl.xml
@@ -18,7 +18,7 @@
android:id="@+id/frame_layout_ltr"
android:layout_width="match_parent"
android:layout_height="match_parent"
- android:horizontalDirection="rtl"
+ android:layoutDirection="rtl"
android:background="#FF000000">
<FrameLayout
@@ -52,28 +52,28 @@
<FrameLayout
android:layout_width="100dp"
android:layout_height="100dp"
- android:layout_gravity="top|before"
+ android:layout_gravity="top|start"
android:background="#FFFFFFFF">
</FrameLayout>
<FrameLayout
android:layout_width="100dp"
android:layout_height="100dp"
- android:layout_gravity="top|after"
+ android:layout_gravity="top|end"
android:background="#FFFFFF00">
</FrameLayout>
<FrameLayout
android:layout_width="100dp"
android:layout_height="100dp"
- android:layout_gravity="bottom|before"
+ android:layout_gravity="bottom|start"
android:background="#FFFFFFFF">
</FrameLayout>
<FrameLayout
android:layout_width="100dp"
android:layout_height="100dp"
- android:layout_gravity="bottom|after"
+ android:layout_gravity="bottom|end"
android:background="#FFFFFF00">
</FrameLayout>
diff --git a/tests/BiDiTests/res/layout/linear_layout_ltr.xml b/tests/BiDiTests/res/layout/linear_layout_ltr.xml
index c5a8d47d6e62..d4386f2d0102 100644
--- a/tests/BiDiTests/res/layout/linear_layout_ltr.xml
+++ b/tests/BiDiTests/res/layout/linear_layout_ltr.xml
@@ -19,7 +19,7 @@
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent"
- android:horizontalDirection="ltr">
+ android:layoutDirection="ltr">
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="horizontal"
@@ -51,7 +51,7 @@
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:horizontalDirection="inherit">
+ android:layoutDirection="inherit">
<Button android:layout_height="wrap_content"
android:layout_width="wrap_content"
@@ -78,7 +78,7 @@
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:horizontalDirection="ltr">
+ android:layoutDirection="ltr">
<Button android:layout_height="wrap_content"
android:layout_width="wrap_content"
@@ -105,7 +105,7 @@
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:horizontalDirection="rtl">
+ android:layoutDirection="rtl">
<Button android:layout_height="wrap_content"
android:layout_width="wrap_content"
@@ -132,7 +132,7 @@
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:horizontalDirection="inherit">
+ android:layoutDirection="inherit">
<Button android:layout_height="wrap_content"
android:layout_width="wrap_content"
@@ -159,7 +159,7 @@
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:horizontalDirection="ltr">
+ android:layoutDirection="ltr">
<Button android:layout_height="wrap_content"
android:layout_width="wrap_content"
@@ -186,7 +186,7 @@
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:horizontalDirection="rtl">
+ android:layoutDirection="rtl">
<Button android:layout_height="wrap_content"
android:layout_width="wrap_content"
diff --git a/tests/BiDiTests/res/layout/linear_layout_rtl.xml b/tests/BiDiTests/res/layout/linear_layout_rtl.xml
index 1494fec54ac9..9d0726386c3d 100644
--- a/tests/BiDiTests/res/layout/linear_layout_rtl.xml
+++ b/tests/BiDiTests/res/layout/linear_layout_rtl.xml
@@ -19,7 +19,7 @@
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent"
- android:horizontalDirection="rtl">
+ android:layoutDirection="rtl">
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="horizontal"
@@ -51,7 +51,7 @@
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:horizontalDirection="inherit">
+ android:layoutDirection="inherit">
<Button android:layout_height="wrap_content"
android:layout_width="wrap_content"
@@ -78,7 +78,7 @@
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:horizontalDirection="ltr">
+ android:layoutDirection="ltr">
<Button android:layout_height="wrap_content"
android:layout_width="wrap_content"
@@ -105,7 +105,7 @@
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:horizontalDirection="rtl">
+ android:layoutDirection="rtl">
<Button android:layout_height="wrap_content"
android:layout_width="wrap_content"
@@ -132,7 +132,7 @@
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:horizontalDirection="inherit">
+ android:layoutDirection="inherit">
<Button android:layout_height="wrap_content"
android:layout_width="wrap_content"
@@ -159,7 +159,7 @@
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:horizontalDirection="ltr">
+ android:layoutDirection="ltr">
<Button android:layout_height="wrap_content"
android:layout_width="wrap_content"
@@ -186,7 +186,7 @@
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:horizontalDirection="rtl">
+ android:layoutDirection="rtl">
<Button android:layout_height="wrap_content"
android:layout_width="wrap_content"
diff --git a/tests/BiDiTests/res/layout/relative_layout_ltr.xml b/tests/BiDiTests/res/layout/relative_layout_ltr.xml
index 53ae7c34ba28..d789707dfe62 100644
--- a/tests/BiDiTests/res/layout/relative_layout_ltr.xml
+++ b/tests/BiDiTests/res/layout/relative_layout_ltr.xml
@@ -18,7 +18,7 @@
android:id="@+id/frame_layout_ltr"
android:layout_width="match_parent"
android:layout_height="match_parent"
- android:horizontalDirection="ltr"
+ android:layoutDirection="ltr"
android:background="#FF000000">
<RelativeLayout
@@ -52,28 +52,28 @@
<RelativeLayout
android:layout_width="100dp"
android:layout_height="100dp"
- android:layout_gravity="top|before"
+ android:layout_gravity="top|start"
android:background="#FFFFFFFF">
</RelativeLayout>
<RelativeLayout
android:layout_width="100dp"
android:layout_height="100dp"
- android:layout_gravity="top|after"
+ android:layout_gravity="top|end"
android:background="#FFFFFF00">
</RelativeLayout>
<RelativeLayout
android:layout_width="100dp"
android:layout_height="100dp"
- android:layout_gravity="bottom|before"
+ android:layout_gravity="bottom|start"
android:background="#FFFFFFFF">
</RelativeLayout>
<RelativeLayout
android:layout_width="100dp"
android:layout_height="100dp"
- android:layout_gravity="bottom|after"
+ android:layout_gravity="bottom|end"
android:background="#FFFFFF00">
</RelativeLayout>
diff --git a/tests/BiDiTests/res/layout/relative_layout_ltr_2.xml b/tests/BiDiTests/res/layout/relative_layout_ltr_2.xml
index 93d1b4ba1676..a13ef8bfc0ad 100644
--- a/tests/BiDiTests/res/layout/relative_layout_ltr_2.xml
+++ b/tests/BiDiTests/res/layout/relative_layout_ltr_2.xml
@@ -19,7 +19,7 @@
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent"
- android:horizontalDirection="ltr">
+ android:layoutDirection="ltr">
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
@@ -58,7 +58,7 @@
android:layout_height="wrap_content"
android:background="#FF000000"
android:padding="10px"
- android:horizontalDirection="ltr">
+ android:layoutDirection="ltr">
<TextView android:id="@+id/label_2"
android:layout_width="fill_parent"
@@ -91,7 +91,7 @@
android:layout_height="wrap_content"
android:background="#FF000000"
android:padding="10px"
- android:horizontalDirection="inherit">
+ android:layoutDirection="inherit">
<TextView android:id="@+id/label_3"
android:layout_width="fill_parent"
@@ -124,7 +124,7 @@
android:layout_height="wrap_content"
android:background="#FF000000"
android:padding="10px"
- android:horizontalDirection="rtl">
+ android:layoutDirection="rtl">
<TextView android:id="@+id/label_4"
android:layout_width="fill_parent"
diff --git a/tests/BiDiTests/res/layout/relative_layout_rtl.xml b/tests/BiDiTests/res/layout/relative_layout_rtl.xml
index 4b87752a92b1..580892474206 100644
--- a/tests/BiDiTests/res/layout/relative_layout_rtl.xml
+++ b/tests/BiDiTests/res/layout/relative_layout_rtl.xml
@@ -18,7 +18,7 @@
android:id="@+id/frame_layout_rtl"
android:layout_width="match_parent"
android:layout_height="match_parent"
- android:horizontalDirection="rtl"
+ android:layoutDirection="rtl"
android:background="#FF000000">
<RelativeLayout
@@ -52,28 +52,28 @@
<RelativeLayout
android:layout_width="100dp"
android:layout_height="100dp"
- android:layout_gravity="top|before"
+ android:layout_gravity="top|start"
android:background="#FFFFFFFF">
</RelativeLayout>
<RelativeLayout
android:layout_width="100dp"
android:layout_height="100dp"
- android:layout_gravity="top|after"
+ android:layout_gravity="top|end"
android:background="#FFFFFF00">
</RelativeLayout>
<RelativeLayout
android:layout_width="100dp"
android:layout_height="100dp"
- android:layout_gravity="bottom|before"
+ android:layout_gravity="bottom|start"
android:background="#FFFFFFFF">
</RelativeLayout>
<RelativeLayout
android:layout_width="100dp"
android:layout_height="100dp"
- android:layout_gravity="bottom|after"
+ android:layout_gravity="bottom|end"
android:background="#FFFFFF00">
</RelativeLayout>
diff --git a/tests/BiDiTests/res/layout/relative_layout_rtl_2.xml b/tests/BiDiTests/res/layout/relative_layout_rtl_2.xml
index 8418e72f58ab..1a6b3d54a04d 100644
--- a/tests/BiDiTests/res/layout/relative_layout_rtl_2.xml
+++ b/tests/BiDiTests/res/layout/relative_layout_rtl_2.xml
@@ -19,7 +19,7 @@
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent"
- android:horizontalDirection="rtl">
+ android:layoutDirection="rtl">
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
@@ -58,7 +58,7 @@
android:layout_height="wrap_content"
android:background="#FF000000"
android:padding="10px"
- android:horizontalDirection="ltr">
+ android:layoutDirection="ltr">
<TextView android:id="@+id/label_2"
android:layout_width="fill_parent"
@@ -91,7 +91,7 @@
android:layout_height="wrap_content"
android:background="#FF000000"
android:padding="10px"
- android:horizontalDirection="inherit">
+ android:layoutDirection="inherit">
<TextView android:id="@+id/label_3"
android:layout_width="fill_parent"
@@ -124,7 +124,7 @@
android:layout_height="wrap_content"
android:background="#FF000000"
android:padding="10px"
- android:horizontalDirection="rtl">
+ android:layoutDirection="rtl">
<TextView android:id="@+id/label_4"
android:layout_width="fill_parent"
diff --git a/tests/BiDiTests/res/layout/table_layout_ltr.xml b/tests/BiDiTests/res/layout/table_layout_ltr.xml
index f44de8ed9880..8e1891e7014c 100644
--- a/tests/BiDiTests/res/layout/table_layout_ltr.xml
+++ b/tests/BiDiTests/res/layout/table_layout_ltr.xml
@@ -19,7 +19,7 @@
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent"
- android:horizontalDirection="ltr">
+ android:layoutDirection="ltr">
<TableLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
@@ -72,7 +72,7 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:stretchColumns="1,2"
- android:horizontalDirection="inherit">
+ android:layoutDirection="inherit">
<TableRow>
<Button android:layout_height="wrap_content"
@@ -120,7 +120,7 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:stretchColumns="1,2"
- android:horizontalDirection="ltr">
+ android:layoutDirection="ltr">
<TableRow>
<Button android:layout_height="wrap_content"
@@ -168,7 +168,7 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:stretchColumns="1,2"
- android:horizontalDirection="rtl">
+ android:layoutDirection="rtl">
<TableRow>
<Button android:layout_height="wrap_content"
diff --git a/tests/BiDiTests/res/layout/table_layout_rtl.xml b/tests/BiDiTests/res/layout/table_layout_rtl.xml
index 84270baa8b97..bd664e4900db 100644
--- a/tests/BiDiTests/res/layout/table_layout_rtl.xml
+++ b/tests/BiDiTests/res/layout/table_layout_rtl.xml
@@ -19,7 +19,7 @@
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent"
- android:horizontalDirection="rtl">
+ android:layoutDirection="rtl">
<TableLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
@@ -72,7 +72,7 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:stretchColumns="1,2"
- android:horizontalDirection="inherit">
+ android:layoutDirection="inherit">
<TableRow>
<Button android:layout_height="wrap_content"
@@ -120,7 +120,7 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:stretchColumns="1,2"
- android:horizontalDirection="ltr">
+ android:layoutDirection="ltr">
<TableRow>
<Button android:layout_height="wrap_content"
@@ -168,7 +168,7 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:stretchColumns="1,2"
- android:horizontalDirection="rtl">
+ android:layoutDirection="rtl">
<TableRow>
<Button android:layout_height="wrap_content"
diff --git a/tools/layoutlib/bridge/src/android/graphics/Canvas_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/Canvas_Delegate.java
index 922cd4c977fb..8e3ed9327736 100644
--- a/tools/layoutlib/bridge/src/android/graphics/Canvas_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/graphics/Canvas_Delegate.java
@@ -425,7 +425,7 @@ public final class Canvas_Delegate {
AffineTransform matrixTx = matrixDelegate.getAffineTransform();
// combine them so that the given matrix is applied after.
- currentTx.preConcatenate(matrixTx);
+ currentTx.concatenate(matrixTx);
// give it to the graphics2D as a new matrix replacing all previous transform
snapshot.setTransform(currentTx);
@@ -717,7 +717,7 @@ public final class Canvas_Delegate {
/*package*/ static void native_drawCircle(int nativeCanvas,
float cx, float cy, float radius, int paint) {
native_drawOval(nativeCanvas,
- new RectF(cx - radius, cy - radius, radius*2, radius*2),
+ new RectF(cx - radius, cy - radius, radius, radius),
paint);
}
diff --git a/tools/layoutlib/bridge/src/android/os/HandlerThread_Delegate.java b/tools/layoutlib/bridge/src/android/os/HandlerThread_Delegate.java
new file mode 100644
index 000000000000..afbe97c06ebb
--- /dev/null
+++ b/tools/layoutlib/bridge/src/android/os/HandlerThread_Delegate.java
@@ -0,0 +1,80 @@
+/*
+ * Copyright (C) 2011 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.os;
+
+import com.android.layoutlib.bridge.android.BridgeContext;
+import com.android.layoutlib.bridge.impl.RenderAction;
+import com.android.tools.layoutlib.annotations.LayoutlibDelegate;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Delegate overriding selected methods of android.os.HandlerThread
+ *
+ * Through the layoutlib_create tool, selected methods of Handler have been replaced
+ * by calls to methods of the same name in this delegate class.
+ *
+ *
+ */
+public class HandlerThread_Delegate {
+
+ private static Map<BridgeContext, List<HandlerThread>> sThreads =
+ new HashMap<BridgeContext, List<HandlerThread>>();
+
+ public static void cleanUp(BridgeContext context) {
+ List<HandlerThread> list = sThreads.get(context);
+ if (list != null) {
+ for (HandlerThread thread : list) {
+ thread.quit();
+ }
+
+ list.clear();
+ sThreads.remove(context);
+ }
+ }
+
+ // -------- Delegate methods
+
+ @LayoutlibDelegate
+ /*package*/ static void run(HandlerThread theThread) {
+ // record the thread so that it can be quit() on clean up.
+ BridgeContext context = RenderAction.getCurrentContext();
+ List<HandlerThread> list = sThreads.get(context);
+ if (list == null) {
+ list = new ArrayList<HandlerThread>();
+ sThreads.put(context, list);
+ }
+
+ list.add(theThread);
+
+ // ---- START DEFAULT IMPLEMENTATION.
+
+ theThread.mTid = Process.myTid();
+ Looper.prepare();
+ synchronized (theThread) {
+ theThread.mLooper = Looper.myLooper();
+ theThread.notifyAll();
+ }
+ Process.setThreadPriority(theThread.mPriority);
+ theThread.onLooperPrepared();
+ Looper.loop();
+ theThread.mTid = -1;
+ }
+}
diff --git a/tools/layoutlib/bridge/src/android/view/LayoutInflater_Delegate.java b/tools/layoutlib/bridge/src/android/view/LayoutInflater_Delegate.java
index 0f3cf571cf8d..3ef328802ec4 100644
--- a/tools/layoutlib/bridge/src/android/view/LayoutInflater_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/view/LayoutInflater_Delegate.java
@@ -22,7 +22,10 @@ import com.android.tools.layoutlib.annotations.LayoutlibDelegate;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
+import android.content.res.TypedArray;
+import android.content.res.XmlResourceParser;
import android.util.AttributeSet;
+import android.util.Xml;
import java.io.IOException;
@@ -35,6 +38,8 @@ import java.io.IOException;
*/
public class LayoutInflater_Delegate {
+ public static boolean sIsInInclude = false;
+
/**
* Recursive method used to descend down the xml hierarchy and instantiate
* views, instantiate their children, and then call onFinishInflate().
@@ -94,4 +99,128 @@ public class LayoutInflater_Delegate {
}
}
}
+
+ @LayoutlibDelegate
+ public static void parseInclude(
+ LayoutInflater thisInflater,
+ XmlPullParser parser, View parent, AttributeSet attrs)
+ throws XmlPullParserException, IOException {
+
+ int type;
+
+ if (parent instanceof ViewGroup) {
+ final int layout = attrs.getAttributeResourceValue(null, "layout", 0);
+ if (layout == 0) {
+ final String value = attrs.getAttributeValue(null, "layout");
+ if (value == null) {
+ throw new InflateException("You must specifiy a layout in the"
+ + " include tag: <include layout=\"@layout/layoutID\" />");
+ } else {
+ throw new InflateException("You must specifiy a valid layout "
+ + "reference. The layout ID " + value + " is not valid.");
+ }
+ } else {
+ final XmlResourceParser childParser =
+ thisInflater.getContext().getResources().getLayout(layout);
+
+ try {
+ final AttributeSet childAttrs = Xml.asAttributeSet(childParser);
+
+ while ((type = childParser.next()) != XmlPullParser.START_TAG &&
+ type != XmlPullParser.END_DOCUMENT) {
+ // Empty.
+ }
+
+ if (type != XmlPullParser.START_TAG) {
+ throw new InflateException(childParser.getPositionDescription() +
+ ": No start tag found!");
+ }
+
+ final String childName = childParser.getName();
+
+ if (LayoutInflater.TAG_MERGE.equals(childName)) {
+ // Inflate all children.
+ thisInflater.rInflate(childParser, parent, childAttrs, false);
+ } else {
+ final View view = thisInflater.createViewFromTag(parent, childName, childAttrs);
+ final ViewGroup group = (ViewGroup) parent;
+
+ // We try to load the layout params set in the <include /> tag. If
+ // they don't exist, we will rely on the layout params set in the
+ // included XML file.
+ // During a layoutparams generation, a runtime exception is thrown
+ // if either layout_width or layout_height is missing. We catch
+ // this exception and set localParams accordingly: true means we
+ // successfully loaded layout params from the <include /> tag,
+ // false means we need to rely on the included layout params.
+ ViewGroup.LayoutParams params = null;
+ try {
+ // ---- START CHANGES
+ sIsInInclude = true;
+ // ---- END CHANGES
+
+ params = group.generateLayoutParams(attrs);
+
+ } catch (RuntimeException e) {
+ // ---- START CHANGES
+ sIsInInclude = false;
+ // ---- END CHANGES
+
+ params = group.generateLayoutParams(childAttrs);
+ } finally {
+ // ---- START CHANGES
+ sIsInInclude = false;
+ // ---- END CHANGES
+
+ if (params != null) {
+ view.setLayoutParams(params);
+ }
+ }
+
+ // Inflate all children.
+ thisInflater.rInflate(childParser, view, childAttrs, true);
+
+ // Attempt to override the included layout's android:id with the
+ // one set on the <include /> tag itself.
+ TypedArray a = thisInflater.mContext.obtainStyledAttributes(attrs,
+ com.android.internal.R.styleable.View, 0, 0);
+ int id = a.getResourceId(com.android.internal.R.styleable.View_id, View.NO_ID);
+ // While we're at it, let's try to override android:visibility.
+ int visibility = a.getInt(com.android.internal.R.styleable.View_visibility, -1);
+ a.recycle();
+
+ if (id != View.NO_ID) {
+ view.setId(id);
+ }
+
+ switch (visibility) {
+ case 0:
+ view.setVisibility(View.VISIBLE);
+ break;
+ case 1:
+ view.setVisibility(View.INVISIBLE);
+ break;
+ case 2:
+ view.setVisibility(View.GONE);
+ break;
+ }
+
+ group.addView(view);
+ }
+ } finally {
+ childParser.close();
+ }
+ }
+ } else {
+ throw new InflateException("<include /> can only be used inside of a ViewGroup");
+ }
+
+ final int currentDepth = parser.getDepth();
+ while (((type = parser.next()) != XmlPullParser.END_TAG ||
+ parser.getDepth() > currentDepth) && type != XmlPullParser.END_DOCUMENT) {
+ // Empty
+ }
+ }
+
+
}
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/Bridge.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/Bridge.java
index 144ec428a752..3ba32573aec8 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/Bridge.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/Bridge.java
@@ -196,7 +196,7 @@ public final class Bridge extends com.android.ide.common.rendering.api.Bridge {
Capability.UNBOUND_RENDERING,
Capability.CUSTOM_BACKGROUND_COLOR,
Capability.RENDER,
- //Capability.LAYOUT_ONLY, // disable to run on ADT 10.0 which doesn't include this.
+ Capability.LAYOUT_ONLY,
Capability.EMBEDDED_LAYOUT,
Capability.VIEW_MANIPULATION,
Capability.PLAY_ANIMATION,
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java
index e5360289f977..4fa924d0da57 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java
@@ -71,7 +71,6 @@ import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
-import java.io.FileReader;
import java.io.IOException;
import java.io.InputStream;
import java.util.HashMap;
@@ -342,7 +341,7 @@ public final class BridgeContext extends Activity {
try {
KXmlParser parser = new KXmlParser();
parser.setFeature(XmlPullParser.FEATURE_PROCESS_NAMESPACES, true);
- parser.setInput(new FileReader(xml));
+ parser.setInput(new FileInputStream(xml), "UTF-8"); //$NON-NLS-1$);
// set the resource ref to have correct view cookies
mBridgeInflater.setResourceReference(resource);
@@ -514,14 +513,13 @@ public final class BridgeContext extends Activity {
BridgeTypedArray ta = ((BridgeResources) mSystemResources).newTypeArray(attrs.length,
isPlatformFile);
- // resolve the defStyleAttr value into a IStyleResourceValue
- StyleResourceValue defStyleValues = null;
-
// look for a custom style.
String customStyle = null;
if (set != null) {
customStyle = set.getAttributeValue(null /* namespace*/, "style");
}
+
+ StyleResourceValue customStyleValues = null;
if (customStyle != null) {
ResourceValue item = mRenderResources.findResValue(customStyle,
false /*forceFrameworkOnly*/);
@@ -530,75 +528,76 @@ public final class BridgeContext extends Activity {
item = mRenderResources.resolveResValue(item);
if (item instanceof StyleResourceValue) {
- defStyleValues = (StyleResourceValue)item;
+ customStyleValues = (StyleResourceValue)item;
}
}
- if (defStyleValues == null) {
- if (defStyleAttr != 0) {
- // get the name from the int.
- String defStyleName = searchAttr(defStyleAttr);
+ // resolve the defStyleAttr value into a IStyleResourceValue
+ StyleResourceValue defStyleValues = null;
- if (defaultPropMap != null) {
- defaultPropMap.put("style", defStyleName);
- }
+ if (defStyleAttr != 0) {
+ // get the name from the int.
+ String defStyleName = searchAttr(defStyleAttr);
- // look for the style in the current theme, and its parent:
- ResourceValue item = mRenderResources.findItemInTheme(defStyleName);
+ if (defaultPropMap != null) {
+ defaultPropMap.put("style", defStyleName);
+ }
- if (item != null) {
- // item is a reference to a style entry. Search for it.
- item = mRenderResources.findResValue(item.getValue(),
- false /*forceFrameworkOnly*/);
+ // look for the style in the current theme, and its parent:
+ ResourceValue item = mRenderResources.findItemInTheme(defStyleName);
- if (item instanceof StyleResourceValue) {
- defStyleValues = (StyleResourceValue)item;
- }
- } else {
- Bridge.getLog().error(null,
- String.format(
- "Failed to find style '%s' in current theme", defStyleName),
- null /*data*/);
- }
- } else if (defStyleRes != 0) {
- Pair<ResourceType, String> value = Bridge.resolveResourceId(defStyleRes);
- if (value == null) {
- value = mProjectCallback.resolveResourceId(defStyleRes);
+ if (item != null) {
+ // item is a reference to a style entry. Search for it.
+ item = mRenderResources.findResValue(item.getValue(),
+ false /*forceFrameworkOnly*/);
+
+ if (item instanceof StyleResourceValue) {
+ defStyleValues = (StyleResourceValue)item;
}
+ } else {
+ Bridge.getLog().error(null,
+ String.format(
+ "Failed to find style '%s' in current theme", defStyleName),
+ null /*data*/);
+ }
+ } else if (defStyleRes != 0) {
+ Pair<ResourceType, String> value = Bridge.resolveResourceId(defStyleRes);
+ if (value == null) {
+ value = mProjectCallback.resolveResourceId(defStyleRes);
+ }
- if (value != null) {
- if (value.getFirst() == ResourceType.STYLE) {
- // look for the style in the current theme, and its parent:
- ResourceValue item = mRenderResources.findItemInTheme(value.getSecond());
- if (item != null) {
- if (item instanceof StyleResourceValue) {
- if (defaultPropMap != null) {
- defaultPropMap.put("style", item.getName());
- }
-
- defStyleValues = (StyleResourceValue)item;
+ if (value != null) {
+ if (value.getFirst() == ResourceType.STYLE) {
+ // look for the style in the current theme, and its parent:
+ ResourceValue item = mRenderResources.findItemInTheme(value.getSecond());
+ if (item != null) {
+ if (item instanceof StyleResourceValue) {
+ if (defaultPropMap != null) {
+ defaultPropMap.put("style", item.getName());
}
- } else {
- Bridge.getLog().error(null,
- String.format(
- "Style with id 0x%x (resolved to '%s') does not exist.",
- defStyleRes, value.getSecond()),
- null /*data*/);
+
+ defStyleValues = (StyleResourceValue)item;
}
} else {
Bridge.getLog().error(null,
String.format(
- "Resouce id 0x%x is not of type STYLE (instead %s)",
- defStyleRes, value.getFirst().toString()),
+ "Style with id 0x%x (resolved to '%s') does not exist.",
+ defStyleRes, value.getSecond()),
null /*data*/);
}
} else {
Bridge.getLog().error(null,
String.format(
- "Failed to find style with id 0x%x in current theme",
- defStyleRes),
+ "Resouce id 0x%x is not of type STYLE (instead %s)",
+ defStyleRes, value.getFirst().toString()),
null /*data*/);
}
+ } else {
+ Bridge.getLog().error(null,
+ String.format(
+ "Failed to find style with id 0x%x in current theme",
+ defStyleRes),
+ null /*data*/);
}
}
@@ -623,8 +622,13 @@ public final class BridgeContext extends Activity {
if (value == null) {
ResourceValue resValue = null;
- // look for the value in the defStyle first (and its parent if needed)
- if (defStyleValues != null) {
+ // look for the value in the custom style first (and its parent if needed)
+ if (customStyleValues != null) {
+ resValue = mRenderResources.findItemInStyle(customStyleValues, name);
+ }
+
+ // then look for the value in the default Style (and its parent if needed)
+ if (resValue == null && defStyleValues != null) {
resValue = mRenderResources.findItemInStyle(defStyleValues, name);
}
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeInflater.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeInflater.java
index d6bbebd807d0..7c90a312c6ad 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeInflater.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeInflater.java
@@ -36,7 +36,7 @@ import android.view.View;
import android.view.ViewGroup;
import java.io.File;
-import java.io.FileReader;
+import java.io.FileInputStream;
/**
* Custom implementation of {@link LayoutInflater} to handle custom views.
@@ -177,7 +177,7 @@ public final class BridgeInflater extends LayoutInflater {
try {
KXmlParser parser = new KXmlParser();
parser.setFeature(XmlPullParser.FEATURE_PROCESS_NAMESPACES, true);
- parser.setInput(new FileReader(f));
+ parser.setInput(new FileInputStream(f), "UTF-8"); //$NON-NLS-1$
BridgeXmlBlockParser bridgeParser = new BridgeXmlBlockParser(
parser, bridgeContext, false);
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeResources.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeResources.java
index 273e493fa376..345f053582d7 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeResources.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeResources.java
@@ -46,7 +46,6 @@ import android.view.ViewGroup.LayoutParams;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
-import java.io.FileReader;
import java.io.InputStream;
/**
@@ -244,7 +243,7 @@ public final class BridgeResources extends Resources {
// give that to our XmlBlockParser
parser = new KXmlParser();
parser.setFeature(XmlPullParser.FEATURE_PROCESS_NAMESPACES, true);
- parser.setInput(new FileReader(xml));
+ parser.setInput(new FileInputStream(xml), "UTF-8"); //$NON-NLS-1$);
}
}
@@ -282,7 +281,7 @@ public final class BridgeResources extends Resources {
// give that to our XmlBlockParser
parser = new KXmlParser();
parser.setFeature(XmlPullParser.FEATURE_PROCESS_NAMESPACES, true);
- parser.setInput(new FileReader(xml));
+ parser.setInput(new FileInputStream(xml), "UTF-8"); //$NON-NLS-1$);
return new BridgeXmlBlockParser(parser, mContext, mPlatformResourceFlag[0]);
}
@@ -501,7 +500,7 @@ public final class BridgeResources extends Resources {
try {
KXmlParser parser = new KXmlParser();
parser.setFeature(XmlPullParser.FEATURE_PROCESS_NAMESPACES, true);
- parser.setInput(new FileReader(f));
+ parser.setInput(new FileInputStream(f), "UTF-8"); //$NON-NLS-1$);
return new BridgeXmlBlockParser(parser, mContext, mPlatformResourceFlag[0]);
} catch (XmlPullParserException e) {
@@ -536,7 +535,7 @@ public final class BridgeResources extends Resources {
try {
KXmlParser parser = new KXmlParser();
parser.setFeature(XmlPullParser.FEATURE_PROCESS_NAMESPACES, true);
- parser.setInput(new FileReader(f));
+ parser.setInput(new FileInputStream(f), "UTF-8"); //$NON-NLS-1$);
return new BridgeXmlBlockParser(parser, mContext, mPlatformResourceFlag[0]);
} catch (XmlPullParserException e) {
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeTypedArray.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeTypedArray.java
index b9f769f2af06..d4600a14f42e 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeTypedArray.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeTypedArray.java
@@ -36,10 +36,11 @@ import android.content.res.TypedArray;
import android.graphics.drawable.Drawable;
import android.util.DisplayMetrics;
import android.util.TypedValue;
+import android.view.LayoutInflater_Delegate;
import android.view.ViewGroup.LayoutParams;
import java.io.File;
-import java.io.FileReader;
+import java.io.FileInputStream;
import java.util.Arrays;
import java.util.Map;
@@ -315,7 +316,7 @@ public final class BridgeTypedArray extends TypedArray {
try {
KXmlParser parser = new KXmlParser();
parser.setFeature(XmlPullParser.FEATURE_PROCESS_NAMESPACES, true);
- parser.setInput(new FileReader(f));
+ parser.setInput(new FileInputStream(f), "UTF-8"); //$NON-NLS-1$);
BridgeXmlBlockParser blockParser = new BridgeXmlBlockParser(
parser, mContext, resValue.isFramework());
@@ -471,40 +472,23 @@ public final class BridgeTypedArray extends TypedArray {
*/
@Override
public int getDimensionPixelSize(int index, int defValue) {
- if (mResourceData[index] == null) {
- return defValue;
- }
+ try {
+ return getDimension(index);
+ } catch (RuntimeException e) {
+ if (mResourceData[index] != null) {
+ String s = mResourceData[index].getValue();
- String s = mResourceData[index].getValue();
+ if (s != null) {
+ // looks like we were unable to resolve the dimension value
+ Bridge.getLog().warning(LayoutLog.TAG_RESOURCES_FORMAT,
+ String.format(
+ "\"%1$s\" in attribute \"%2$s\" is not a valid format.",
+ s, mNames[index]), null /*data*/);
+ }
+ }
- if (s == null) {
- return defValue;
- } else if (s.equals(BridgeConstants.MATCH_PARENT) ||
- s.equals(BridgeConstants.FILL_PARENT)) {
- return LayoutParams.MATCH_PARENT;
- } else if (s.equals(BridgeConstants.WRAP_CONTENT)) {
- return LayoutParams.WRAP_CONTENT;
- } else if (RenderResources.REFERENCE_NULL.equals(s)) {
return defValue;
}
-
- if (ResourceHelper.stringToFloat(s, mValue)) {
- float f = mValue.getDimension(mBridgeResources.mMetrics);
-
- final int res = (int)(f+0.5f);
- if (res != 0) return res;
- if (f == 0) return 0;
- if (f > 0) return 1;
- return defValue; // this is basically unreachable.
- }
-
- // looks like we were unable to resolve the dimension value
- Bridge.getLog().warning(LayoutLog.TAG_RESOURCES_FORMAT,
- String.format(
- "\"%1$s\" in attribute \"%2$s\" is not a valid format.",
- s, mNames[index]), null /*data*/);
-
- return defValue;
}
/**
@@ -521,7 +505,20 @@ public final class BridgeTypedArray extends TypedArray {
*/
@Override
public int getLayoutDimension(int index, String name) {
- return getDimensionPixelSize(index, 0);
+ try {
+ // this will throw an exception
+ return getDimension(index);
+ } catch (RuntimeException e) {
+
+ if (LayoutInflater_Delegate.sIsInInclude) {
+ throw new RuntimeException();
+ }
+
+ Bridge.getLog().warning(LayoutLog.TAG_RESOURCES_FORMAT,
+ "You must supply a " + name + " attribute.", null);
+
+ return 0;
+ }
}
@Override
@@ -529,6 +526,36 @@ public final class BridgeTypedArray extends TypedArray {
return getDimensionPixelSize(index, defValue);
}
+ private int getDimension(int index) {
+ if (mResourceData[index] == null) {
+ throw new RuntimeException();
+ }
+
+ String s = mResourceData[index].getValue();
+
+ if (s == null) {
+ throw new RuntimeException();
+ } else if (s.equals(BridgeConstants.MATCH_PARENT) ||
+ s.equals(BridgeConstants.FILL_PARENT)) {
+ return LayoutParams.MATCH_PARENT;
+ } else if (s.equals(BridgeConstants.WRAP_CONTENT)) {
+ return LayoutParams.WRAP_CONTENT;
+ } else if (RenderResources.REFERENCE_NULL.equals(s)) {
+ throw new RuntimeException();
+ }
+
+ if (ResourceHelper.stringToFloat(s, mValue)) {
+ float f = mValue.getDimension(mBridgeResources.mMetrics);
+
+ final int res = (int)(f+0.5f);
+ if (res != 0) return res;
+ if (f == 0) return 0;
+ if (f > 0) return 1;
+ }
+
+ throw new RuntimeException();
+ }
+
/**
* Retrieve a fractional unit attribute at <var>index</var>.
*
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/CustomBar.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/CustomBar.java
index 0c4b0d3bbda7..060e6ee077bb 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/CustomBar.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/CustomBar.java
@@ -73,7 +73,7 @@ abstract class CustomBar extends LinearLayout {
parser.setFeature(XmlPullParser.FEATURE_PROCESS_NAMESPACES, true);
parser.setInput(
getClass().getResourceAsStream(layoutPath),
- "UTF8");
+ "UTF8"); //$NON-NLS-1$
BridgeXmlBlockParser bridgeParser = new BridgeXmlBlockParser(
parser, (BridgeContext) context, false /*platformFile*/);
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/RenderAction.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/RenderAction.java
index 8e80c2117115..6194f5d757cb 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/RenderAction.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/RenderAction.java
@@ -29,6 +29,7 @@ import com.android.layoutlib.bridge.Bridge;
import com.android.layoutlib.bridge.android.BridgeContext;
import com.android.resources.ResourceType;
+import android.os.HandlerThread_Delegate;
import android.util.DisplayMetrics;
import java.util.concurrent.TimeUnit;
@@ -228,6 +229,10 @@ public abstract class RenderAction<T extends RenderParams> extends FrameworkReso
private void tearDown() {
// Make sure to remove static references, otherwise we could not unload the lib
mContext.disposeResources();
+
+ // quit HandlerThread created during this session.
+ HandlerThread_Delegate.cleanUp(sCurrentContext);
+
sCurrentContext = null;
Bridge.setLog(null);
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/ResourceHelper.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/ResourceHelper.java
index 96ab30f1c2ff..e5efa4e55424 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/ResourceHelper.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/ResourceHelper.java
@@ -44,7 +44,6 @@ import android.util.TypedValue;
import java.io.File;
import java.io.FileInputStream;
-import java.io.FileReader;
import java.io.IOException;
import java.io.InputStream;
import java.net.MalformedURLException;
@@ -124,7 +123,7 @@ public final class ResourceHelper {
// providing an XmlPullParser
KXmlParser parser = new KXmlParser();
parser.setFeature(XmlPullParser.FEATURE_PROCESS_NAMESPACES, true);
- parser.setInput(new FileReader(f));
+ parser.setInput(new FileInputStream(f), "UTF-8"); //$NON-NLS-1$);
BridgeXmlBlockParser blockParser = new BridgeXmlBlockParser(
parser, context, resValue.isFramework());
@@ -206,7 +205,7 @@ public final class ResourceHelper {
// let the framework inflate the Drawable from the XML file.
KXmlParser parser = new KXmlParser();
parser.setFeature(XmlPullParser.FEATURE_PROCESS_NAMESPACES, true);
- parser.setInput(new FileReader(f));
+ parser.setInput(new FileInputStream(f), "UTF-8"); //$NON-NLS-1$);
BridgeXmlBlockParser blockParser = new BridgeXmlBlockParser(
parser, context, value.isFramework());
diff --git a/tools/layoutlib/bridge/tests/src/com/android/layoutlib/bridge/android/BridgeXmlBlockParserTest.java b/tools/layoutlib/bridge/tests/src/com/android/layoutlib/bridge/android/BridgeXmlBlockParserTest.java
index 3252fb497714..70d5446265e5 100644
--- a/tools/layoutlib/bridge/tests/src/com/android/layoutlib/bridge/android/BridgeXmlBlockParserTest.java
+++ b/tools/layoutlib/bridge/tests/src/com/android/layoutlib/bridge/android/BridgeXmlBlockParserTest.java
@@ -44,7 +44,7 @@ public class BridgeXmlBlockParserTest extends TestCase {
InputStream input = this.getClass().getClassLoader().getResourceAsStream(
"com/android/layoutlib/testdata/layout1.xml");
- parser.setInput(input, null /*encoding*/);
+ parser.setInput(input, "UTF-8"); //$NON-NLS-1$
assertEquals(XmlPullParser.START_DOCUMENT, parser.next());
diff --git a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/CreateInfo.java b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/CreateInfo.java
index eff6bbc893b1..5c60318686bb 100644
--- a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/CreateInfo.java
+++ b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/CreateInfo.java
@@ -99,8 +99,10 @@ public final class CreateInfo implements ICreateInfo {
"android.content.res.Resources$Theme#resolveAttribute",
"android.graphics.BitmapFactory#finishDecode",
"android.os.Handler#sendMessageAtTime",
+ "android.os.HandlerThread#run",
"android.os.Build#getString",
"android.view.LayoutInflater#rInflate",
+ "android.view.LayoutInflater#parseInclude",
"android.view.View#isInEditMode",
"com.android.internal.util.XmlUtils#convertValueToInt",
// TODO: comment out once DelegateClass is working