summaryrefslogtreecommitdiffstats
path: root/core
diff options
context:
space:
mode:
Diffstat (limited to 'core')
-rw-r--r--core/java/android/accounts/AccountManagerService.java797
-rwxr-xr-xcore/java/android/animation/ValueAnimator.java17
-rw-r--r--core/java/android/animation/package.html2
-rw-r--r--core/java/android/app/Activity.java32
-rw-r--r--core/java/android/app/ActivityManager.java31
-rw-r--r--core/java/android/app/ContextImpl.java4
-rw-r--r--core/java/android/app/Dialog.java23
-rw-r--r--core/java/android/app/DialogFragment.java71
-rw-r--r--core/java/android/app/DownloadManager.java4
-rw-r--r--core/java/android/app/FragmentManager.java7
-rw-r--r--core/java/android/app/KeyguardManager.java34
-rw-r--r--core/java/android/app/ListActivity.java6
-rw-r--r--core/java/android/app/Notification.java1
-rw-r--r--core/java/android/app/NotificationManager.java16
-rw-r--r--core/java/android/app/SearchManager.java6
-rw-r--r--core/java/android/app/backup/WallpaperBackupHelper.java9
-rw-r--r--core/java/android/appwidget/AppWidgetHost.java21
-rw-r--r--core/java/android/appwidget/AppWidgetProviderInfo.java33
-rw-r--r--core/java/android/bluetooth/BluetoothAdapter.java6
-rw-r--r--core/java/android/bluetooth/BluetoothDeviceProfileState.java19
-rw-r--r--core/java/android/bluetooth/BluetoothInputDevice.java320
-rw-r--r--core/java/android/bluetooth/BluetoothPan.java276
-rw-r--r--core/java/android/bluetooth/BluetoothProfile.java13
-rw-r--r--core/java/android/bluetooth/BluetoothProfileState.java10
-rw-r--r--core/java/android/bluetooth/BluetoothTetheringDataTracker.java21
-rw-r--r--core/java/android/bluetooth/IBluetooth.aidl6
-rw-r--r--core/java/android/content/Context.java4
-rw-r--r--core/java/android/content/Intent.java42
-rw-r--r--core/java/android/content/IntentFilter.java2
-rw-r--r--core/java/android/content/pm/ApplicationInfo.java6
-rw-r--r--core/java/android/content/pm/IPackageDeleteObserver.aidl2
-rw-r--r--core/java/android/content/pm/IPackageManager.aidl6
-rw-r--r--core/java/android/content/pm/PackageManager.java48
-rw-r--r--core/java/android/content/pm/PackageParser.java13
-rwxr-xr-xcore/java/android/content/res/Resources.java2
-rw-r--r--core/java/android/database/AbstractWindowedCursor.java3
-rw-r--r--core/java/android/database/CursorWindow.java14
-rw-r--r--core/java/android/database/sqlite/SQLiteDatabase.java5
-rw-r--r--core/java/android/hardware/Camera.java107
-rw-r--r--core/java/android/hardware/IUsbManager.aidl31
-rw-r--r--core/java/android/hardware/SensorEvent.java18
-rw-r--r--core/java/android/hardware/usb/IUsbManager.aidl64
-rw-r--r--core/java/android/hardware/usb/UsbAccessory.aidl (renamed from core/java/android/hardware/UsbAccessory.aidl)2
-rw-r--r--core/java/android/hardware/usb/UsbAccessory.java (renamed from core/java/android/hardware/UsbAccessory.java)33
-rw-r--r--core/java/android/hardware/usb/UsbConstants.java (renamed from core/java/android/hardware/UsbConstants.java)2
-rw-r--r--core/java/android/hardware/usb/UsbDevice.aidl (renamed from core/java/android/hardware/UsbDevice.aidl)2
-rw-r--r--core/java/android/hardware/usb/UsbDevice.java (renamed from core/java/android/hardware/UsbDevice.java)25
-rw-r--r--core/java/android/hardware/usb/UsbEndpoint.aidl (renamed from core/java/android/hardware/UsbEndpoint.aidl)2
-rw-r--r--core/java/android/hardware/usb/UsbEndpoint.java (renamed from core/java/android/hardware/UsbEndpoint.java)20
-rw-r--r--core/java/android/hardware/usb/UsbInterface.aidl (renamed from core/java/android/hardware/UsbInterface.aidl)2
-rw-r--r--core/java/android/hardware/usb/UsbInterface.java (renamed from core/java/android/hardware/UsbInterface.java)14
-rw-r--r--core/java/android/hardware/usb/UsbManager.java (renamed from core/java/android/hardware/UsbManager.java)100
-rw-r--r--core/java/android/hardware/usb/UsbRequest.java (renamed from core/java/android/hardware/UsbRequest.java)12
-rw-r--r--core/java/android/net/ConnectivityManager.java28
-rw-r--r--core/java/android/net/MobileDataStateTracker.java9
-rw-r--r--core/java/android/nfc/tech/Ndef.java9
-rw-r--r--core/java/android/os/Binder.java1
-rw-r--r--core/java/android/os/Parcel.java10
-rw-r--r--core/java/android/os/ParcelFileDescriptor.java34
-rw-r--r--core/java/android/pim/ICalendar.java17
-rw-r--r--core/java/android/provider/Applications.java39
-rw-r--r--core/java/android/provider/Browser.java9
-rw-r--r--core/java/android/provider/ContactsContract.java5
-rw-r--r--core/java/android/provider/Settings.java1
-rw-r--r--core/java/android/provider/Telephony.java8
-rw-r--r--core/java/android/server/BluetoothA2dpService.java57
-rw-r--r--core/java/android/server/BluetoothAdapterProperties.java106
-rw-r--r--core/java/android/server/BluetoothBondState.java368
-rw-r--r--core/java/android/server/BluetoothDeviceProperties.java128
-rw-r--r--core/java/android/server/BluetoothEventLoop.java262
-rw-r--r--core/java/android/server/BluetoothInputProfileHandler.java20
-rw-r--r--core/java/android/server/BluetoothPanProfileHandler.java38
-rw-r--r--core/java/android/server/BluetoothService.java1027
-rw-r--r--core/java/android/service/wallpaper/WallpaperService.java17
-rw-r--r--core/java/android/text/Layout.java21
-rw-r--r--core/java/android/text/StaticLayout.java70
-rw-r--r--core/java/android/text/format/DateUtils.java26
-rw-r--r--core/java/android/text/method/BaseKeyListener.java67
-rw-r--r--core/java/android/text/method/BaseMovementMethod.java306
-rw-r--r--core/java/android/text/method/MovementMethod.java1
-rw-r--r--core/java/android/text/method/ScrollingMovementMethod.java155
-rw-r--r--core/java/android/util/AttributeSet.java70
-rw-r--r--core/java/android/util/Config.java5
-rw-r--r--core/java/android/util/DebugUtils.java4
-rw-r--r--core/java/android/util/EventLog.java2
-rw-r--r--core/java/android/util/LruCache.java164
-rw-r--r--core/java/android/util/StateSet.java15
-rw-r--r--core/java/android/util/TimeUtils.java31
-rw-r--r--core/java/android/util/Xml.java9
-rw-r--r--core/java/android/view/Display.java10
-rw-r--r--core/java/android/view/IWindowManager.aidl2
-rw-r--r--core/java/android/view/MotionEvent.java60
-rw-r--r--core/java/android/view/ScaleGestureDetector.java267
-rw-r--r--core/java/android/view/View.java320
-rw-r--r--core/java/android/view/ViewGroup.java88
-rw-r--r--core/java/android/view/ViewPropertyAnimator.java775
-rw-r--r--core/java/android/view/ViewRoot.java155
-rw-r--r--core/java/android/view/WindowManagerImpl.java14
-rw-r--r--core/java/android/view/WindowManagerPolicy.java18
-rw-r--r--core/java/android/view/inputmethod/InputMethodManager.java3
-rw-r--r--core/java/android/webkit/CookieManager.java89
-rw-r--r--core/java/android/webkit/HTML5Audio.java3
-rw-r--r--core/java/android/webkit/HTML5VideoViewProxy.java10
-rw-r--r--core/java/android/webkit/L10nUtils.java73
-rw-r--r--core/java/android/webkit/Plugin.java25
-rw-r--r--core/java/android/webkit/PluginData.java6
-rw-r--r--core/java/android/webkit/PluginList.java7
-rw-r--r--core/java/android/webkit/SelectActionModeCallback.java1
-rw-r--r--core/java/android/webkit/UrlInterceptHandler.java3
-rw-r--r--core/java/android/webkit/UrlInterceptRegistry.java7
-rw-r--r--core/java/android/webkit/WebTextView.java2
-rw-r--r--core/java/android/webkit/WebView.java191
-rw-r--r--core/java/android/webkit/WebViewCore.java58
-rw-r--r--core/java/android/webkit/ZoomManager.java23
-rw-r--r--core/java/android/widget/AbsListView.java118
-rw-r--r--core/java/android/widget/DatePicker.java12
-rw-r--r--core/java/android/widget/EdgeGlow.java1
-rw-r--r--core/java/android/widget/ExpandableListView.java3
-rw-r--r--core/java/android/widget/GridView.java34
-rw-r--r--core/java/android/widget/HorizontalScrollView.java95
-rw-r--r--core/java/android/widget/ListAdapter.java13
-rw-r--r--core/java/android/widget/NumberPicker.java2
-rw-r--r--core/java/android/widget/PopupWindow.java14
-rw-r--r--core/java/android/widget/ProgressBar.java2
-rw-r--r--core/java/android/widget/RemoteViewsAdapter.java3
-rw-r--r--core/java/android/widget/RemoteViewsService.java24
-rw-r--r--core/java/android/widget/ScrollView.java86
-rw-r--r--core/java/android/widget/StackView.java36
-rw-r--r--core/java/android/widget/TabHost.java8
-rw-r--r--core/java/android/widget/TabWidget.java11
-rw-r--r--core/java/android/widget/TextView.java526
-rw-r--r--core/java/com/android/internal/app/ResolverActivity.java21
-rw-r--r--core/java/com/android/internal/widget/IRemoteViewsFactory.aidl2
-rw-r--r--core/java/com/android/internal/widget/PointerLocationView.java123
-rw-r--r--core/jni/Android.mk1
-rw-r--r--core/jni/android/graphics/Bitmap.cpp12
-rw-r--r--core/jni/android/graphics/Camera.cpp14
-rw-r--r--core/jni/android/graphics/Canvas.cpp2
-rw-r--r--core/jni/android/graphics/ColorFilter.cpp2
-rw-r--r--core/jni/android/graphics/DrawFilter.cpp2
-rw-r--r--core/jni/android/graphics/MaskFilter.cpp2
-rw-r--r--core/jni/android/graphics/PathEffect.cpp2
-rw-r--r--core/jni/android/graphics/Rasterizer.cpp2
-rw-r--r--core/jni/android/graphics/Shader.cpp2
-rw-r--r--core/jni/android/graphics/TextLayout.cpp55
-rw-r--r--core/jni/android/graphics/TextLayout.h12
-rw-r--r--core/jni/android/graphics/Xfermode.cpp2
-rw-r--r--core/jni/android_app_NativeActivity.cpp6
-rwxr-xr-xcore/jni/android_bluetooth_BluetoothAudioGateway.cpp64
-rw-r--r--core/jni/android_bluetooth_BluetoothSocket.cpp20
-rw-r--r--core/jni/android_bluetooth_HeadsetBase.cpp14
-rw-r--r--core/jni/android_database_CursorWindow.cpp5
-rw-r--r--core/jni/android_hardware_Camera.cpp240
-rw-r--r--core/jni/android_hardware_UsbDevice.cpp8
-rw-r--r--core/jni/android_hardware_UsbEndpoint.cpp124
-rw-r--r--core/jni/android_hardware_UsbRequest.cpp8
-rw-r--r--core/jni/android_net_wifi_Wifi.cpp13
-rw-r--r--core/jni/android_os_ParcelFileDescriptor.cpp15
-rw-r--r--core/jni/android_server_BluetoothA2dpService.cpp20
-rw-r--r--core/jni/android_server_BluetoothEventLoop.cpp22
-rw-r--r--core/jni/android_server_BluetoothService.cpp94
-rw-r--r--core/jni/android_util_Binder.cpp201
-rw-r--r--core/jni/android_view_Display.cpp50
-rw-r--r--core/jni/android_view_InputChannel.cpp18
-rw-r--r--core/jni/android_view_Surface.cpp4
-rw-r--r--core/jni/com_google_android_gles_jni_EGLImpl.cpp6
-rw-r--r--core/res/AndroidManifest.xml32
-rw-r--r--core/res/res/drawable-hdpi/btn_check_off_holo.pngbin0 -> 422 bytes
-rw-r--r--core/res/res/drawable-hdpi/btn_check_on_holo.pngbin0 -> 2131 bytes
-rw-r--r--core/res/res/drawable-hdpi/btn_radio_off_holo.pngbin0 -> 989 bytes
-rw-r--r--core/res/res/drawable-hdpi/btn_radio_on_holo.pngbin0 -> 2221 bytes
-rw-r--r--core/res/res/drawable-mdpi/btn_check_off_holo.pngbin0 -> 387 bytes
-rw-r--r--core/res/res/drawable-mdpi/btn_check_on_holo.pngbin0 -> 1356 bytes
-rw-r--r--core/res/res/drawable-mdpi/btn_radio_off_holo.pngbin0 -> 724 bytes
-rw-r--r--core/res/res/drawable-mdpi/btn_radio_on_holo.pngbin0 -> 1350 bytes
-rw-r--r--core/res/res/layout/webview_select_singlechoice.xml30
-rw-r--r--core/res/res/values-ar/strings.xml4
-rw-r--r--core/res/res/values-bg/strings.xml4
-rw-r--r--core/res/res/values-ca/strings.xml6
-rw-r--r--core/res/res/values-cs/strings.xml4
-rw-r--r--core/res/res/values-da/strings.xml4
-rw-r--r--core/res/res/values-de/strings.xml8
-rw-r--r--core/res/res/values-el/strings.xml4
-rw-r--r--core/res/res/values-en-rGB/strings.xml4
-rw-r--r--core/res/res/values-es-rUS/strings.xml4
-rw-r--r--core/res/res/values-es/strings.xml82
-rw-r--r--core/res/res/values-fa/strings.xml4
-rw-r--r--core/res/res/values-fi/strings.xml4
-rw-r--r--core/res/res/values-fr/strings.xml4
-rw-r--r--core/res/res/values-hr/strings.xml4
-rw-r--r--core/res/res/values-hu/strings.xml4
-rw-r--r--core/res/res/values-in/strings.xml8
-rw-r--r--core/res/res/values-it/strings.xml6
-rw-r--r--core/res/res/values-iw/strings.xml22
-rw-r--r--core/res/res/values-ja/strings.xml4
-rw-r--r--core/res/res/values-ko/strings.xml4
-rw-r--r--core/res/res/values-lt/strings.xml4
-rw-r--r--core/res/res/values-lv/strings.xml4
-rw-r--r--core/res/res/values-nb/strings.xml4
-rw-r--r--core/res/res/values-nl/strings.xml314
-rw-r--r--core/res/res/values-pl/strings.xml4
-rw-r--r--core/res/res/values-pt-rPT/strings.xml4
-rw-r--r--core/res/res/values-pt/strings.xml4
-rw-r--r--core/res/res/values-rm/strings.xml4
-rw-r--r--core/res/res/values-ro/strings.xml4
-rw-r--r--core/res/res/values-ru/strings.xml4
-rw-r--r--core/res/res/values-sk/strings.xml4
-rw-r--r--core/res/res/values-sl/strings.xml4
-rw-r--r--core/res/res/values-sr/strings.xml4
-rw-r--r--core/res/res/values-sv/strings.xml38
-rw-r--r--core/res/res/values-th/strings.xml4
-rw-r--r--core/res/res/values-tl/strings.xml4
-rw-r--r--core/res/res/values-tr/strings.xml4
-rw-r--r--core/res/res/values-uk/strings.xml4
-rw-r--r--core/res/res/values-vi/strings.xml4
-rw-r--r--core/res/res/values-zh-rCN/strings.xml4
-rw-r--r--core/res/res/values-zh-rTW/strings.xml4
-rwxr-xr-xcore/res/res/values/attrs.xml89
-rw-r--r--core/res/res/values/config.xml21
-rw-r--r--core/res/res/values/public.xml9
-rwxr-xr-xcore/res/res/values/strings.xml115
-rw-r--r--core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/ConnectivityManagerTestActivity.java42
-rw-r--r--core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/functional/WifiConnectionTest.java24
-rw-r--r--core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/stress/WifiApStress.java9
-rw-r--r--core/tests/coretests/AndroidManifest.xml1
-rw-r--r--core/tests/coretests/src/android/accounts/AccountManagerServiceTest.java2
-rw-r--r--core/tests/coretests/src/android/bluetooth/BluetoothStressTest.java34
-rw-r--r--core/tests/coretests/src/android/bluetooth/BluetoothTestRunner.java11
-rw-r--r--core/tests/coretests/src/android/bluetooth/BluetoothTestUtils.java399
-rwxr-xr-xcore/tests/coretests/src/android/content/pm/PackageManagerTests.java4
-rw-r--r--core/tests/coretests/src/android/util/LruCacheTest.java141
231 files changed, 7597 insertions, 3873 deletions
diff --git a/core/java/android/accounts/AccountManagerService.java b/core/java/android/accounts/AccountManagerService.java
index 2e70a56..894e196 100644
--- a/core/java/android/accounts/AccountManagerService.java
+++ b/core/java/android/accounts/AccountManagerService.java
@@ -52,7 +52,6 @@ import android.os.Message;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.SystemClock;
-import android.os.SystemProperties;
import android.telephony.TelephonyManager;
import android.text.TextUtils;
import android.util.Log;
@@ -81,8 +80,6 @@ import java.util.concurrent.atomic.AtomicReference;
public class AccountManagerService
extends IAccountManager.Stub
implements RegisteredServicesCacheListener<AuthenticatorDescription> {
- private static final String GOOGLE_ACCOUNT_TYPE = "com.google";
-
private static final String TAG = "AccountManagerService";
private static final int TIMEOUT_DELAY_MS = 1000 * 60;
@@ -101,7 +98,6 @@ public class AccountManagerService
private final IAccountAuthenticatorCache mAuthenticatorCache;
private final DatabaseHelper mOpenHelper;
- private final SimWatcher mSimWatcher;
private static final String TABLE_ACCOUNTS = "accounts";
private static final String ACCOUNTS_ID = "_id";
@@ -199,7 +195,9 @@ public class AccountManagerService
mContext = context;
mPackageManager = packageManager;
- mOpenHelper = new DatabaseHelper(mContext);
+ synchronized (mCacheLock) {
+ mOpenHelper = new DatabaseHelper(mContext);
+ }
mMessageThread = new HandlerThread("AccountManagerService");
mMessageThread.start();
@@ -208,20 +206,54 @@ public class AccountManagerService
mAuthenticatorCache = authenticatorCache;
mAuthenticatorCache.setListener(this, null /* Handler */);
- mSimWatcher = new SimWatcher(mContext);
sThis.set(this);
+ IntentFilter intentFilter = new IntentFilter();
+ intentFilter.addAction(Intent.ACTION_PACKAGE_REMOVED);
+ intentFilter.addDataScheme("package");
+ mContext.registerReceiver(new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context1, Intent intent) {
+ purgeOldGrants();
+ }
+ }, intentFilter);
+ purgeOldGrants();
+
validateAccountsAndPopulateCache();
}
+ private void purgeOldGrants() {
+ synchronized (mCacheLock) {
+ final SQLiteDatabase db = mOpenHelper.getWritableDatabase();
+ final Cursor cursor = db.query(TABLE_GRANTS,
+ new String[]{GRANTS_GRANTEE_UID},
+ null, null, GRANTS_GRANTEE_UID, null, null);
+ try {
+ while (cursor.moveToNext()) {
+ final int uid = cursor.getInt(0);
+ final boolean packageExists = mPackageManager.getPackagesForUid(uid) != null;
+ if (packageExists) {
+ continue;
+ }
+ Log.d(TAG, "deleting grants for UID " + uid
+ + " because its package is no longer installed");
+ db.delete(TABLE_GRANTS, GRANTS_GRANTEE_UID + "=?",
+ new String[]{Integer.toString(uid)});
+ }
+ } finally {
+ cursor.close();
+ }
+ }
+ }
+
private void validateAccountsAndPopulateCache() {
- boolean accountDeleted = false;
- SQLiteDatabase db = mOpenHelper.getWritableDatabase();
- Cursor cursor = db.query(TABLE_ACCOUNTS,
- new String[]{ACCOUNTS_ID, ACCOUNTS_TYPE, ACCOUNTS_NAME},
- null, null, null, null, null);
- try {
- synchronized (mCacheLock) {
+ synchronized (mCacheLock) {
+ final SQLiteDatabase db = mOpenHelper.getWritableDatabase();
+ boolean accountDeleted = false;
+ Cursor cursor = db.query(TABLE_ACCOUNTS,
+ new String[]{ACCOUNTS_ID, ACCOUNTS_TYPE, ACCOUNTS_NAME},
+ null, null, null, null, null);
+ try {
mAccountCache.clear();
final HashMap<String, ArrayList<String>> accountNamesByType =
new HashMap<String, ArrayList<String>>();
@@ -247,7 +279,8 @@ public class AccountManagerService
accountNames.add(accountName);
}
}
- for (HashMap.Entry<String, ArrayList<String>> cur : accountNamesByType.entrySet()) {
+ for (HashMap.Entry<String, ArrayList<String>> cur
+ : accountNamesByType.entrySet()) {
final String accountType = cur.getKey();
final ArrayList<String> accountNames = cur.getValue();
final Account[] accountsForType = new Account[accountNames.size()];
@@ -258,11 +291,11 @@ public class AccountManagerService
}
mAccountCache.put(accountType, accountsForType);
}
- }
- } finally {
- cursor.close();
- if (accountDeleted) {
- sendAccountsChangedBroadcast();
+ } finally {
+ cursor.close();
+ if (accountDeleted) {
+ sendAccountsChangedBroadcast();
+ }
}
}
}
@@ -282,28 +315,30 @@ public class AccountManagerService
long identityToken = clearCallingIdentity();
try {
- return readPasswordFromDatabase(account);
+ return readPasswordInternal(account);
} finally {
restoreCallingIdentity(identityToken);
}
}
- private String readPasswordFromDatabase(Account account) {
+ private String readPasswordInternal(Account account) {
if (account == null) {
return null;
}
- SQLiteDatabase db = mOpenHelper.getReadableDatabase();
- Cursor cursor = db.query(TABLE_ACCOUNTS, new String[]{ACCOUNTS_PASSWORD},
- ACCOUNTS_NAME + "=? AND " + ACCOUNTS_TYPE+ "=?",
- new String[]{account.name, account.type}, null, null, null);
- try {
- if (cursor.moveToNext()) {
- return cursor.getString(0);
+ synchronized (mCacheLock) {
+ final SQLiteDatabase db = mOpenHelper.getReadableDatabase();
+ Cursor cursor = db.query(TABLE_ACCOUNTS, new String[]{ACCOUNTS_PASSWORD},
+ ACCOUNTS_NAME + "=? AND " + ACCOUNTS_TYPE+ "=?",
+ new String[]{account.name, account.type}, null, null, null);
+ try {
+ if (cursor.moveToNext()) {
+ return cursor.getString(0);
+ }
+ return null;
+ } finally {
+ cursor.close();
}
- return null;
- } finally {
- cursor.close();
}
}
@@ -319,7 +354,7 @@ public class AccountManagerService
checkAuthenticateAccountsPermission(account);
long identityToken = clearCallingIdentity();
try {
- return readUserDataFromCache(account, key);
+ return readUserDataInternal(account, key);
} finally {
restoreCallingIdentity(identityToken);
}
@@ -361,58 +396,60 @@ public class AccountManagerService
// fails if the account already exists
long identityToken = clearCallingIdentity();
try {
- return insertAccountIntoDatabase(account, password, extras);
+ return addAccountInternal(account, password, extras);
} finally {
restoreCallingIdentity(identityToken);
}
}
- private boolean insertAccountIntoDatabase(Account account, String password, Bundle extras) {
- SQLiteDatabase db = mOpenHelper.getWritableDatabase();
+ private boolean addAccountInternal(Account account, String password, Bundle extras) {
if (account == null) {
return false;
}
- db.beginTransaction();
- try {
- long numMatches = DatabaseUtils.longForQuery(db,
- "select count(*) from " + TABLE_ACCOUNTS
- + " WHERE " + ACCOUNTS_NAME + "=? AND " + ACCOUNTS_TYPE+ "=?",
- new String[]{account.name, account.type});
- if (numMatches > 0) {
- Log.w(TAG, "insertAccountIntoDatabase: " + account
- + ", skipping since the account already exists");
- return false;
- }
- ContentValues values = new ContentValues();
- values.put(ACCOUNTS_NAME, account.name);
- values.put(ACCOUNTS_TYPE, account.type);
- values.put(ACCOUNTS_PASSWORD, password);
- long accountId = db.insert(TABLE_ACCOUNTS, ACCOUNTS_NAME, values);
- if (accountId < 0) {
- Log.w(TAG, "insertAccountIntoDatabase: " + account
- + ", skipping the DB insert failed");
- return false;
- }
- if (extras != null) {
- for (String key : extras.keySet()) {
- final String value = extras.getString(key);
- if (insertExtra(db, accountId, key, value) < 0) {
- Log.w(TAG, "insertAccountIntoDatabase: " + account
- + ", skipping since insertExtra failed for key " + key);
- return false;
+ synchronized (mCacheLock) {
+ final SQLiteDatabase db = mOpenHelper.getWritableDatabase();
+ db.beginTransaction();
+ try {
+ long numMatches = DatabaseUtils.longForQuery(db,
+ "select count(*) from " + TABLE_ACCOUNTS
+ + " WHERE " + ACCOUNTS_NAME + "=? AND " + ACCOUNTS_TYPE+ "=?",
+ new String[]{account.name, account.type});
+ if (numMatches > 0) {
+ Log.w(TAG, "insertAccountIntoDatabase: " + account
+ + ", skipping since the account already exists");
+ return false;
+ }
+ ContentValues values = new ContentValues();
+ values.put(ACCOUNTS_NAME, account.name);
+ values.put(ACCOUNTS_TYPE, account.type);
+ values.put(ACCOUNTS_PASSWORD, password);
+ long accountId = db.insert(TABLE_ACCOUNTS, ACCOUNTS_NAME, values);
+ if (accountId < 0) {
+ Log.w(TAG, "insertAccountIntoDatabase: " + account
+ + ", skipping the DB insert failed");
+ return false;
+ }
+ if (extras != null) {
+ for (String key : extras.keySet()) {
+ final String value = extras.getString(key);
+ if (insertExtraLocked(db, accountId, key, value) < 0) {
+ Log.w(TAG, "insertAccountIntoDatabase: " + account
+ + ", skipping since insertExtra failed for key " + key);
+ return false;
+ }
}
}
+ db.setTransactionSuccessful();
+ insertAccountIntoCacheLocked(account);
+ } finally {
+ db.endTransaction();
}
- db.setTransactionSuccessful();
- insertAccountIntoCache(account);
- } finally {
- db.endTransaction();
+ sendAccountsChangedBroadcast();
+ return true;
}
- sendAccountsChangedBroadcast();
- return true;
}
- private long insertExtra(SQLiteDatabase db, long accountId, String key, String value) {
+ private long insertExtraLocked(SQLiteDatabase db, long accountId, String key, String value) {
ContentValues values = new ContentValues();
values.put(EXTRAS_KEY, key);
values.put(EXTRAS_ACCOUNTS_ID, accountId);
@@ -545,7 +582,7 @@ public class AccountManagerService
&& !result.containsKey(AccountManager.KEY_INTENT)) {
final boolean removalAllowed = result.getBoolean(AccountManager.KEY_BOOLEAN_RESULT);
if (removalAllowed) {
- removeAccount(mAccount);
+ removeAccountInternal(mAccount);
}
IAccountManagerResponse response = getResponseAndClose();
if (response != null) {
@@ -566,12 +603,14 @@ public class AccountManagerService
}
}
- protected void removeAccount(Account account) {
- final SQLiteDatabase db = mOpenHelper.getWritableDatabase();
- db.delete(TABLE_ACCOUNTS, ACCOUNTS_NAME + "=? AND " + ACCOUNTS_TYPE+ "=?",
- new String[]{account.name, account.type});
- removeAccountFromCache(account);
- sendAccountsChangedBroadcast();
+ protected void removeAccountInternal(Account account) {
+ synchronized (mCacheLock) {
+ final SQLiteDatabase db = mOpenHelper.getWritableDatabase();
+ db.delete(TABLE_ACCOUNTS, ACCOUNTS_NAME + "=? AND " + ACCOUNTS_TYPE+ "=?",
+ new String[]{account.name, account.type});
+ removeAccountFromCacheLocked(account);
+ sendAccountsChangedBroadcast();
+ }
}
public void invalidateAuthToken(String accountType, String authToken) {
@@ -585,20 +624,22 @@ public class AccountManagerService
checkManageAccountsOrUseCredentialsPermissions();
long identityToken = clearCallingIdentity();
try {
- SQLiteDatabase db = mOpenHelper.getWritableDatabase();
- db.beginTransaction();
- try {
- invalidateAuthToken(db, accountType, authToken);
- db.setTransactionSuccessful();
- } finally {
- db.endTransaction();
+ synchronized (mCacheLock) {
+ final SQLiteDatabase db = mOpenHelper.getWritableDatabase();
+ db.beginTransaction();
+ try {
+ invalidateAuthTokenLocked(db, accountType, authToken);
+ db.setTransactionSuccessful();
+ } finally {
+ db.endTransaction();
+ }
}
} finally {
restoreCallingIdentity(identityToken);
}
}
- private void invalidateAuthToken(SQLiteDatabase db, String accountType, String authToken) {
+ private void invalidateAuthTokenLocked(SQLiteDatabase db, String accountType, String authToken) {
if (authToken == null || accountType == null) {
return;
}
@@ -619,7 +660,8 @@ public class AccountManagerService
String accountName = cursor.getString(1);
String authTokenType = cursor.getString(2);
db.delete(TABLE_AUTHTOKENS, AUTHTOKENS_ID + "=" + authTokenId, null);
- writeAuthTokenIntoCache(new Account(accountName, accountType), authTokenType, null);
+ writeAuthTokenIntoCacheLocked(db, new Account(accountName, accountType),
+ authTokenType, null);
}
} finally {
cursor.close();
@@ -631,28 +673,30 @@ public class AccountManagerService
return false;
}
cancelNotification(getSigninRequiredNotificationId(account));
- SQLiteDatabase db = mOpenHelper.getWritableDatabase();
- db.beginTransaction();
- try {
- long accountId = getAccountId(db, account);
- if (accountId < 0) {
+ synchronized (mCacheLock) {
+ final SQLiteDatabase db = mOpenHelper.getWritableDatabase();
+ db.beginTransaction();
+ try {
+ long accountId = getAccountIdLocked(db, account);
+ if (accountId < 0) {
+ return false;
+ }
+ db.delete(TABLE_AUTHTOKENS,
+ AUTHTOKENS_ACCOUNTS_ID + "=" + accountId + " AND " + AUTHTOKENS_TYPE + "=?",
+ new String[]{type});
+ ContentValues values = new ContentValues();
+ values.put(AUTHTOKENS_ACCOUNTS_ID, accountId);
+ values.put(AUTHTOKENS_TYPE, type);
+ values.put(AUTHTOKENS_AUTHTOKEN, authToken);
+ if (db.insert(TABLE_AUTHTOKENS, AUTHTOKENS_AUTHTOKEN, values) >= 0) {
+ db.setTransactionSuccessful();
+ writeAuthTokenIntoCacheLocked(db, account, type, authToken);
+ return true;
+ }
return false;
+ } finally {
+ db.endTransaction();
}
- db.delete(TABLE_AUTHTOKENS,
- AUTHTOKENS_ACCOUNTS_ID + "=" + accountId + " AND " + AUTHTOKENS_TYPE + "=?",
- new String[]{type});
- ContentValues values = new ContentValues();
- values.put(AUTHTOKENS_ACCOUNTS_ID, accountId);
- values.put(AUTHTOKENS_TYPE, type);
- values.put(AUTHTOKENS_AUTHTOKEN, authToken);
- if (db.insert(TABLE_AUTHTOKENS, AUTHTOKENS_AUTHTOKEN, values) >= 0) {
- db.setTransactionSuccessful();
- writeAuthTokenIntoCache(account, type, authToken);
- return true;
- }
- return false;
- } finally {
- db.endTransaction();
}
}
@@ -668,7 +712,7 @@ public class AccountManagerService
checkAuthenticateAccountsPermission(account);
long identityToken = clearCallingIdentity();
try {
- return readAuthTokenFromCache(account, authTokenType);
+ return readAuthTokenInternal(account, authTokenType);
} finally {
restoreCallingIdentity(identityToken);
}
@@ -702,35 +746,35 @@ public class AccountManagerService
checkAuthenticateAccountsPermission(account);
long identityToken = clearCallingIdentity();
try {
- setPasswordInDB(account, password);
+ setPasswordInternal(account, password);
} finally {
restoreCallingIdentity(identityToken);
}
}
- private void setPasswordInDB(Account account, String password) {
+ private void setPasswordInternal(Account account, String password) {
if (account == null) {
return;
}
- SQLiteDatabase db = mOpenHelper.getWritableDatabase();
- db.beginTransaction();
- try {
- final ContentValues values = new ContentValues();
- values.put(ACCOUNTS_PASSWORD, password);
- final long accountId = getAccountId(db, account);
- if (accountId >= 0) {
- final String[] argsAccountId = {String.valueOf(accountId)};
- db.update(TABLE_ACCOUNTS, values, ACCOUNTS_ID + "=?", argsAccountId);
- db.delete(TABLE_AUTHTOKENS, AUTHTOKENS_ACCOUNTS_ID + "=?", argsAccountId);
- synchronized (mCacheLock) {
+ synchronized (mCacheLock) {
+ final SQLiteDatabase db = mOpenHelper.getWritableDatabase();
+ db.beginTransaction();
+ try {
+ final ContentValues values = new ContentValues();
+ values.put(ACCOUNTS_PASSWORD, password);
+ final long accountId = getAccountIdLocked(db, account);
+ if (accountId >= 0) {
+ final String[] argsAccountId = {String.valueOf(accountId)};
+ db.update(TABLE_ACCOUNTS, values, ACCOUNTS_ID + "=?", argsAccountId);
+ db.delete(TABLE_AUTHTOKENS, AUTHTOKENS_ACCOUNTS_ID + "=?", argsAccountId);
mAuthTokenCache.remove(account);
+ db.setTransactionSuccessful();
}
- db.setTransactionSuccessful();
+ } finally {
+ db.endTransaction();
}
- } finally {
- db.endTransaction();
+ sendAccountsChangedBroadcast();
}
- sendAccountsChangedBroadcast();
}
private void sendAccountsChangedBroadcast() {
@@ -749,7 +793,7 @@ public class AccountManagerService
checkManageAccountsPermission();
long identityToken = clearCallingIdentity();
try {
- setPasswordInDB(account, null);
+ setPasswordInternal(account, null);
} finally {
restoreCallingIdentity(identityToken);
}
@@ -767,41 +811,43 @@ public class AccountManagerService
checkAuthenticateAccountsPermission(account);
long identityToken = clearCallingIdentity();
try {
- writeUserdataIntoDatabase(account, key, value);
+ setUserdataInternal(account, key, value);
} finally {
restoreCallingIdentity(identityToken);
}
}
- private void writeUserdataIntoDatabase(Account account, String key, String value) {
+ private void setUserdataInternal(Account account, String key, String value) {
if (account == null || key == null) {
return;
}
- SQLiteDatabase db = mOpenHelper.getWritableDatabase();
- db.beginTransaction();
- try {
- long accountId = getAccountId(db, account);
- if (accountId < 0) {
- return;
- }
- long extrasId = getExtrasId(db, accountId, key);
- if (extrasId < 0 ) {
- extrasId = insertExtra(db, accountId, key, value);
- if (extrasId < 0) {
- return;
- }
- } else {
- ContentValues values = new ContentValues();
- values.put(EXTRAS_VALUE, value);
- if (1 != db.update(TABLE_EXTRAS, values, EXTRAS_ID + "=" + extrasId, null)) {
+ synchronized (mCacheLock) {
+ final SQLiteDatabase db = mOpenHelper.getWritableDatabase();
+ db.beginTransaction();
+ try {
+ long accountId = getAccountIdLocked(db, account);
+ if (accountId < 0) {
return;
}
+ long extrasId = getExtrasIdLocked(db, accountId, key);
+ if (extrasId < 0 ) {
+ extrasId = insertExtraLocked(db, accountId, key, value);
+ if (extrasId < 0) {
+ return;
+ }
+ } else {
+ ContentValues values = new ContentValues();
+ values.put(EXTRAS_VALUE, value);
+ if (1 != db.update(TABLE_EXTRAS, values, EXTRAS_ID + "=" + extrasId, null)) {
+ return;
+ }
+ }
+ writeUserDataIntoCacheLocked(db, account, key, value);
+ db.setTransactionSuccessful();
+ } finally {
+ db.endTransaction();
}
- db.setTransactionSuccessful();
- writeUserDataIntoCache(account, key, value);
- } finally {
- db.endTransaction();
}
}
@@ -907,7 +953,7 @@ public class AccountManagerService
// if the caller has permission, do the peek. otherwise go the more expensive
// route of starting a Session
if (!customTokens && permissionGranted) {
- String authToken = readAuthTokenFromCache(account, authTokenType);
+ String authToken = readAuthTokenInternal(account, authTokenType);
if (authToken != null) {
Bundle result = new Bundle();
result.putString(AccountManager.KEY_AUTHTOKEN, authToken);
@@ -1213,7 +1259,9 @@ public class AccountManagerService
}
public void run() throws RemoteException {
- mAccountsOfType = getAccountsByTypeFromCache(mAccountType);
+ synchronized (mCacheLock) {
+ mAccountsOfType = getAccountsFromCacheLocked(mAccountType);
+ }
// check whether each account matches the requested features
mAccountsWithFeatures = new ArrayList<Account>(mAccountsOfType.length);
mCurrentAccount = 0;
@@ -1299,7 +1347,9 @@ public class AccountManagerService
checkReadAccountsPermission();
long identityToken = clearCallingIdentity();
try {
- return getAccountsByTypeFromCache(type);
+ synchronized (mCacheLock) {
+ return getAccountsFromCacheLocked(type);
+ }
} finally {
restoreCallingIdentity(identityToken);
}
@@ -1320,7 +1370,10 @@ public class AccountManagerService
long identityToken = clearCallingIdentity();
try {
if (features == null || features.length == 0) {
- Account[] accounts = getAccountsByTypeFromCache(type);
+ Account[] accounts;
+ synchronized (mCacheLock) {
+ accounts = getAccountsFromCacheLocked(type);
+ }
Bundle result = new Bundle();
result.putParcelableArray(AccountManager.KEY_ACCOUNTS, accounts);
onResult(response, result);
@@ -1332,7 +1385,7 @@ public class AccountManagerService
}
}
- private long getAccountId(SQLiteDatabase db, Account account) {
+ private long getAccountIdLocked(SQLiteDatabase db, Account account) {
Cursor cursor = db.query(TABLE_ACCOUNTS, new String[]{ACCOUNTS_ID},
"name=? AND type=?", new String[]{account.name, account.type}, null, null, null);
try {
@@ -1345,7 +1398,7 @@ public class AccountManagerService
}
}
- private long getExtrasId(SQLiteDatabase db, long accountId, String key) {
+ private long getExtrasIdLocked(SQLiteDatabase db, long accountId, String key) {
Cursor cursor = db.query(TABLE_EXTRAS, new String[]{EXTRAS_ID},
EXTRAS_ACCOUNTS_ID + "=" + accountId + " AND " + EXTRAS_KEY + "=?",
new String[]{key}, null, null, null);
@@ -1635,6 +1688,11 @@ public class AccountManagerService
super(context, AccountManagerService.getDatabaseName(), null, DATABASE_VERSION);
}
+ /**
+ * This call needs to be made while the mCacheLock is held. The way to
+ * ensure this is to get the lock any time a method is called ont the DatabaseHelper
+ * @param db The database.
+ */
@Override
public void onCreate(SQLiteDatabase db) {
db.execSQL("CREATE TABLE " + TABLE_ACCOUNTS + " ( "
@@ -1723,113 +1781,24 @@ public class AccountManagerService
ContentValues values = new ContentValues();
values.put(META_KEY, key);
values.put(META_VALUE, value);
- mOpenHelper.getWritableDatabase().replace(TABLE_META, META_KEY, values);
- }
-
- private String getMetaValue(String key) {
- Cursor c = mOpenHelper.getReadableDatabase().query(TABLE_META,
- new String[]{META_VALUE}, META_KEY + "=?", new String[]{key}, null, null, null);
- try {
- if (c.moveToNext()) {
- return c.getString(0);
- }
- return null;
- } finally {
- c.close();
+ synchronized (mCacheLock) {
+ mOpenHelper.getWritableDatabase().replace(TABLE_META, META_KEY, values);
}
}
- private class SimWatcher extends BroadcastReceiver {
- public SimWatcher(Context context) {
- // Re-scan the SIM card when the SIM state changes, and also if
- // the disk recovers from a full state (we may have failed to handle
- // things properly while the disk was full).
- final IntentFilter filter = new IntentFilter();
- filter.addAction(TelephonyIntents.ACTION_SIM_STATE_CHANGED);
- filter.addAction(Intent.ACTION_DEVICE_STORAGE_OK);
- context.registerReceiver(this, filter);
- }
-
- /**
- * Compare the IMSI to the one stored in the login service's
- * database. If they differ, erase all passwords and
- * authtokens (and store the new IMSI).
- */
- @Override
- public void onReceive(Context context, Intent intent) {
- // Check IMSI on every update; nothing happens if the IMSI
- // is missing or unchanged.
- TelephonyManager telephonyManager =
- (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE);
- if (telephonyManager == null) {
- Log.w(TAG, "failed to get TelephonyManager");
- return;
- }
- String imsi = telephonyManager.getSubscriberId();
-
- // If the subscriber ID is an empty string, don't do anything.
- if (TextUtils.isEmpty(imsi)) return;
-
- // If the current IMSI matches what's stored, don't do anything.
- String storedImsi = getMetaValue("imsi");
- if (Log.isLoggable(TAG, Log.VERBOSE)) {
- Log.v(TAG, "current IMSI=" + imsi + "; stored IMSI=" + storedImsi);
- }
- if (imsi.equals(storedImsi)) return;
-
- // If a CDMA phone is unprovisioned, getSubscriberId()
- // will return a different value, but we *don't* erase the
- // passwords. We only erase them if it has a different
- // subscriber ID once it's provisioned.
- if (telephonyManager.getCurrentPhoneType() == TelephonyManager.PHONE_TYPE_CDMA) {
- IBinder service = ServiceManager.checkService(Context.TELEPHONY_SERVICE);
- if (service == null) {
- Log.w(TAG, "call to checkService(TELEPHONY_SERVICE) failed");
- return;
- }
- ITelephony telephony = ITelephony.Stub.asInterface(service);
- if (telephony == null) {
- Log.w(TAG, "failed to get ITelephony interface");
- return;
- }
- boolean needsProvisioning;
- try {
- needsProvisioning = telephony.needsOtaServiceProvisioning();
- } catch (RemoteException e) {
- Log.w(TAG, "exception while checking provisioning", e);
- // default to NOT wiping out the passwords
- needsProvisioning = true;
- }
- if (needsProvisioning) {
- // if the phone needs re-provisioning, don't do anything.
- if (Log.isLoggable(TAG, Log.VERBOSE)) {
- Log.v(TAG, "current IMSI=" + imsi + " (needs provisioning); stored IMSI=" +
- storedImsi);
- }
- return;
- }
- }
-
- if (!imsi.equals(storedImsi) && !TextUtils.isEmpty(storedImsi)) {
- Log.w(TAG, "wiping all passwords and authtokens because IMSI changed ("
- + "stored=" + storedImsi + ", current=" + imsi + ")");
- SQLiteDatabase db = mOpenHelper.getWritableDatabase();
- db.beginTransaction();
- try {
- db.execSQL("DELETE from " + TABLE_AUTHTOKENS);
- db.execSQL("UPDATE " + TABLE_ACCOUNTS + " SET " + ACCOUNTS_PASSWORD + " = ''");
-
- synchronized (mCacheLock) {
- mAuthTokenCache = new HashMap<Account, HashMap<String, String>>();
- }
-
- db.setTransactionSuccessful();
- } finally {
- db.endTransaction();
+ private String getMetaValue(String key) {
+ synchronized (mCacheLock) {
+ final SQLiteDatabase db = mOpenHelper.getReadableDatabase();
+ Cursor c = db.query(TABLE_META,
+ new String[]{META_VALUE}, META_KEY + "=?", new String[]{key}, null, null, null);
+ try {
+ if (c.moveToNext()) {
+ return c.getString(0);
}
- sendAccountsChangedBroadcast();
+ return null;
+ } finally {
+ c.close();
}
- setMetaValue("imsi", imsi);
}
}
@@ -1855,42 +1824,44 @@ public class AccountManagerService
}
protected void dump(FileDescriptor fd, PrintWriter fout, String[] args) {
- final boolean isCheckinRequest = scanArgs(args, "--checkin") || scanArgs(args, "-c");
+ synchronized (mCacheLock) {
+ final SQLiteDatabase db = mOpenHelper.getReadableDatabase();
- if (isCheckinRequest) {
- // This is a checkin request. *Only* upload the account types and the count of each.
- SQLiteDatabase db = mOpenHelper.getReadableDatabase();
+ final boolean isCheckinRequest = scanArgs(args, "--checkin") || scanArgs(args, "-c");
- Cursor cursor = db.query(TABLE_ACCOUNTS, ACCOUNT_TYPE_COUNT_PROJECTION,
- null, null, ACCOUNTS_TYPE, null, null);
- try {
- while (cursor.moveToNext()) {
- // print type,count
- fout.println(cursor.getString(0) + "," + cursor.getString(1));
+ if (isCheckinRequest) {
+ // This is a checkin request. *Only* upload the account types and the count of each.
+ Cursor cursor = db.query(TABLE_ACCOUNTS, ACCOUNT_TYPE_COUNT_PROJECTION,
+ null, null, ACCOUNTS_TYPE, null, null);
+ try {
+ while (cursor.moveToNext()) {
+ // print type,count
+ fout.println(cursor.getString(0) + "," + cursor.getString(1));
+ }
+ } finally {
+ if (cursor != null) {
+ cursor.close();
+ }
}
- } finally {
- if (cursor != null) {
- cursor.close();
+ } else {
+ Account[] accounts = getAccountsFromCacheLocked(null /* type */);
+ fout.println("Accounts: " + accounts.length);
+ for (Account account : accounts) {
+ fout.println(" " + account);
}
- }
- } else {
- Account[] accounts = getAccountsByTypeFromCache(null /* type */);
- fout.println("Accounts: " + accounts.length);
- for (Account account : accounts) {
- fout.println(" " + account);
- }
- fout.println();
- synchronized (mSessions) {
- final long now = SystemClock.elapsedRealtime();
- fout.println("Active Sessions: " + mSessions.size());
- for (Session session : mSessions.values()) {
- fout.println(" " + session.toDebugString(now));
+ fout.println();
+ synchronized (mSessions) {
+ final long now = SystemClock.elapsedRealtime();
+ fout.println("Active Sessions: " + mSessions.size());
+ for (Session session : mSessions.values()) {
+ fout.println(" " + session.toDebugString(now));
+ }
}
- }
- fout.println();
- mAuthenticatorCache.dump(fd, fout, args);
+ fout.println();
+ mAuthenticatorCache.dump(fd, fout, args);
+ }
}
}
@@ -2003,20 +1974,22 @@ public class AccountManagerService
if (Binder.getCallingUid() == android.os.Process.SYSTEM_UID) {
return true;
}
- SQLiteDatabase db = mOpenHelper.getReadableDatabase();
- String[] args = {String.valueOf(Binder.getCallingUid()), authTokenType,
- account.name, account.type};
- final boolean permissionGranted =
- DatabaseUtils.longForQuery(db, COUNT_OF_MATCHING_GRANTS, args) != 0;
- if (!permissionGranted && ActivityManager.isRunningInTestHarness()) {
- // TODO: Skip this check when running automated tests. Replace this
- // with a more general solution.
- Log.d(TAG, "no credentials permission for usage of " + account + ", "
- + authTokenType + " by uid " + Binder.getCallingUid()
- + " but ignoring since device is in test harness.");
- return true;
+ synchronized (mCacheLock) {
+ final SQLiteDatabase db = mOpenHelper.getReadableDatabase();
+ String[] args = {String.valueOf(Binder.getCallingUid()), authTokenType,
+ account.name, account.type};
+ final boolean permissionGranted =
+ DatabaseUtils.longForQuery(db, COUNT_OF_MATCHING_GRANTS, args) != 0;
+ if (!permissionGranted && ActivityManager.isRunningInTestHarness()) {
+ // TODO: Skip this check when running automated tests. Replace this
+ // with a more general solution.
+ Log.d(TAG, "no credentials permission for usage of " + account + ", "
+ + authTokenType + " by uid " + Binder.getCallingUid()
+ + " but ignoring since device is in test harness.");
+ return true;
+ }
+ return permissionGranted;
}
- return permissionGranted;
}
private void checkCallingUidAgainstAuthenticator(Account account) {
@@ -2061,22 +2034,24 @@ public class AccountManagerService
Log.e(TAG, "grantAppPermission: called with invalid arguments", new Exception());
return;
}
- SQLiteDatabase db = mOpenHelper.getWritableDatabase();
- db.beginTransaction();
- try {
- long accountId = getAccountId(db, account);
- if (accountId >= 0) {
- ContentValues values = new ContentValues();
- values.put(GRANTS_ACCOUNTS_ID, accountId);
- values.put(GRANTS_AUTH_TOKEN_TYPE, authTokenType);
- values.put(GRANTS_GRANTEE_UID, uid);
- db.insert(TABLE_GRANTS, GRANTS_ACCOUNTS_ID, values);
- db.setTransactionSuccessful();
+ synchronized (mCacheLock) {
+ final SQLiteDatabase db = mOpenHelper.getWritableDatabase();
+ db.beginTransaction();
+ try {
+ long accountId = getAccountIdLocked(db, account);
+ if (accountId >= 0) {
+ ContentValues values = new ContentValues();
+ values.put(GRANTS_ACCOUNTS_ID, accountId);
+ values.put(GRANTS_AUTH_TOKEN_TYPE, authTokenType);
+ values.put(GRANTS_GRANTEE_UID, uid);
+ db.insert(TABLE_GRANTS, GRANTS_ACCOUNTS_ID, values);
+ db.setTransactionSuccessful();
+ }
+ } finally {
+ db.endTransaction();
}
- } finally {
- db.endTransaction();
+ cancelNotification(getCredentialPermissionNotificationId(account, authTokenType, uid));
}
- cancelNotification(getCredentialPermissionNotificationId(account, authTokenType, uid));
}
/**
@@ -2092,153 +2067,149 @@ public class AccountManagerService
Log.e(TAG, "revokeAppPermission: called with invalid arguments", new Exception());
return;
}
- SQLiteDatabase db = mOpenHelper.getWritableDatabase();
- db.beginTransaction();
- try {
- long accountId = getAccountId(db, account);
- if (accountId >= 0) {
- db.delete(TABLE_GRANTS,
- GRANTS_ACCOUNTS_ID + "=? AND " + GRANTS_AUTH_TOKEN_TYPE + "=? AND "
- + GRANTS_GRANTEE_UID + "=?",
- new String[]{String.valueOf(accountId), authTokenType,
- String.valueOf(uid)});
- db.setTransactionSuccessful();
+ synchronized (mCacheLock) {
+ final SQLiteDatabase db = mOpenHelper.getWritableDatabase();
+ db.beginTransaction();
+ try {
+ long accountId = getAccountIdLocked(db, account);
+ if (accountId >= 0) {
+ db.delete(TABLE_GRANTS,
+ GRANTS_ACCOUNTS_ID + "=? AND " + GRANTS_AUTH_TOKEN_TYPE + "=? AND "
+ + GRANTS_GRANTEE_UID + "=?",
+ new String[]{String.valueOf(accountId), authTokenType,
+ String.valueOf(uid)});
+ db.setTransactionSuccessful();
+ }
+ } finally {
+ db.endTransaction();
}
- } finally {
- db.endTransaction();
+ cancelNotification(getCredentialPermissionNotificationId(account, authTokenType, uid));
}
- cancelNotification(getCredentialPermissionNotificationId(account, authTokenType, uid));
}
static final private String stringArrayToString(String[] value) {
return value != null ? ("[" + TextUtils.join(",", value) + "]") : null;
}
- private void removeAccountFromCache(Account account) {
- synchronized (mCacheLock) {
- final Account[] oldAccountsForType = mAccountCache.get(account.type);
- if (oldAccountsForType != null) {
- ArrayList<Account> newAccountsList = new ArrayList<Account>();
- for (Account curAccount : oldAccountsForType) {
- if (!curAccount.equals(account)) {
- newAccountsList.add(curAccount);
- }
- }
- if (newAccountsList.isEmpty()) {
- mAccountCache.remove(account.type);
- } else {
- Account[] newAccountsForType = new Account[newAccountsList.size()];
- newAccountsForType = newAccountsList.toArray(newAccountsForType);
- mAccountCache.put(account.type, newAccountsForType);
+ private void removeAccountFromCacheLocked(Account account) {
+ final Account[] oldAccountsForType = mAccountCache.get(account.type);
+ if (oldAccountsForType != null) {
+ ArrayList<Account> newAccountsList = new ArrayList<Account>();
+ for (Account curAccount : oldAccountsForType) {
+ if (!curAccount.equals(account)) {
+ newAccountsList.add(curAccount);
}
}
- mUserDataCache.remove(account);
- mAuthTokenCache.remove(account);
+ if (newAccountsList.isEmpty()) {
+ mAccountCache.remove(account.type);
+ } else {
+ Account[] newAccountsForType = new Account[newAccountsList.size()];
+ newAccountsForType = newAccountsList.toArray(newAccountsForType);
+ mAccountCache.put(account.type, newAccountsForType);
+ }
}
+ mUserDataCache.remove(account);
+ mAuthTokenCache.remove(account);
}
/**
* This assumes that the caller has already checked that the account is not already present.
*/
- private void insertAccountIntoCache(Account account) {
- synchronized (mCacheLock) {
- Account[] accountsForType = mAccountCache.get(account.type);
- int oldLength = (accountsForType != null) ? accountsForType.length : 0;
- Account[] newAccountsForType = new Account[oldLength + 1];
- if (accountsForType != null) {
- System.arraycopy(accountsForType, 0, newAccountsForType, 0, oldLength);
- }
- newAccountsForType[oldLength] = account;
- mAccountCache.put(account.type, newAccountsForType);
- }
- }
-
- protected Account[] getAccountsByTypeFromCache(String accountType) {
- synchronized (mCacheLock) {
- if (accountType != null) {
- final Account[] accounts = mAccountCache.get(accountType);
- if (accounts == null) {
- return EMPTY_ACCOUNT_ARRAY;
- } else {
- return Arrays.copyOf(accounts, accounts.length);
- }
+ private void insertAccountIntoCacheLocked(Account account) {
+ Account[] accountsForType = mAccountCache.get(account.type);
+ int oldLength = (accountsForType != null) ? accountsForType.length : 0;
+ Account[] newAccountsForType = new Account[oldLength + 1];
+ if (accountsForType != null) {
+ System.arraycopy(accountsForType, 0, newAccountsForType, 0, oldLength);
+ }
+ newAccountsForType[oldLength] = account;
+ mAccountCache.put(account.type, newAccountsForType);
+ }
+
+ protected Account[] getAccountsFromCacheLocked(String accountType) {
+ if (accountType != null) {
+ final Account[] accounts = mAccountCache.get(accountType);
+ if (accounts == null) {
+ return EMPTY_ACCOUNT_ARRAY;
} else {
- int totalLength = 0;
- for (Account[] accounts : mAccountCache.values()) {
- totalLength += accounts.length;
- }
- if (totalLength == 0) {
- return EMPTY_ACCOUNT_ARRAY;
- }
- Account[] accounts = new Account[totalLength];
- totalLength = 0;
- for (Account[] accountsOfType : mAccountCache.values()) {
- System.arraycopy(accountsOfType, 0, accounts, totalLength,
- accountsOfType.length);
- totalLength += accountsOfType.length;
- }
- return accounts;
+ return Arrays.copyOf(accounts, accounts.length);
}
+ } else {
+ int totalLength = 0;
+ for (Account[] accounts : mAccountCache.values()) {
+ totalLength += accounts.length;
+ }
+ if (totalLength == 0) {
+ return EMPTY_ACCOUNT_ARRAY;
+ }
+ Account[] accounts = new Account[totalLength];
+ totalLength = 0;
+ for (Account[] accountsOfType : mAccountCache.values()) {
+ System.arraycopy(accountsOfType, 0, accounts, totalLength,
+ accountsOfType.length);
+ totalLength += accountsOfType.length;
+ }
+ return accounts;
}
}
- protected void writeUserDataIntoCache(Account account, String key, String value) {
- synchronized (mCacheLock) {
- HashMap<String, String> userDataForAccount = mUserDataCache.get(account);
- if (userDataForAccount == null) {
- userDataForAccount = readUserDataForAccountFromDatabase(account);
- mUserDataCache.put(account, userDataForAccount);
- }
- if (value == null) {
- userDataForAccount.remove(key);
- } else {
- userDataForAccount.put(key, value);
- }
+ protected void writeUserDataIntoCacheLocked(final SQLiteDatabase db, Account account,
+ String key, String value) {
+ HashMap<String, String> userDataForAccount = mUserDataCache.get(account);
+ if (userDataForAccount == null) {
+ userDataForAccount = readUserDataForAccountFromDatabaseLocked(db, account);
+ mUserDataCache.put(account, userDataForAccount);
+ }
+ if (value == null) {
+ userDataForAccount.remove(key);
+ } else {
+ userDataForAccount.put(key, value);
}
}
- protected void writeAuthTokenIntoCache(Account account, String key, String value) {
- synchronized (mCacheLock) {
- HashMap<String, String> authTokensForAccount = mAuthTokenCache.get(account);
- if (authTokensForAccount == null) {
- authTokensForAccount = readAuthTokensForAccountFromDatabase(account);
- mAuthTokenCache.put(account, authTokensForAccount);
- }
- if (value == null) {
- authTokensForAccount.remove(key);
- } else {
- authTokensForAccount.put(key, value);
- }
+ protected void writeAuthTokenIntoCacheLocked(final SQLiteDatabase db, Account account,
+ String key, String value) {
+ HashMap<String, String> authTokensForAccount = mAuthTokenCache.get(account);
+ if (authTokensForAccount == null) {
+ authTokensForAccount = readAuthTokensForAccountFromDatabaseLocked(db, account);
+ mAuthTokenCache.put(account, authTokensForAccount);
+ }
+ if (value == null) {
+ authTokensForAccount.remove(key);
+ } else {
+ authTokensForAccount.put(key, value);
}
}
- protected String readAuthTokenFromCache(Account account, String authTokenType) {
+ protected String readAuthTokenInternal(Account account, String authTokenType) {
synchronized (mCacheLock) {
HashMap<String, String> authTokensForAccount = mAuthTokenCache.get(account);
if (authTokensForAccount == null) {
// need to populate the cache for this account
- authTokensForAccount = readAuthTokensForAccountFromDatabase(account);
+ final SQLiteDatabase db = mOpenHelper.getReadableDatabase();
+ authTokensForAccount = readAuthTokensForAccountFromDatabaseLocked(db, account);
mAuthTokenCache.put(account, authTokensForAccount);
}
return authTokensForAccount.get(authTokenType);
}
}
- protected String readUserDataFromCache(Account account, String key) {
+ protected String readUserDataInternal(Account account, String key) {
synchronized (mCacheLock) {
HashMap<String, String> userDataForAccount = mUserDataCache.get(account);
if (userDataForAccount == null) {
// need to populate the cache for this account
- userDataForAccount = readUserDataForAccountFromDatabase(account);
+ final SQLiteDatabase db = mOpenHelper.getReadableDatabase();
+ userDataForAccount = readUserDataForAccountFromDatabaseLocked(db, account);
mUserDataCache.put(account, userDataForAccount);
}
return userDataForAccount.get(key);
}
}
- protected HashMap<String, String> readUserDataForAccountFromDatabase(Account account) {
+ protected HashMap<String, String> readUserDataForAccountFromDatabaseLocked(
+ final SQLiteDatabase db, Account account) {
HashMap<String, String> userDataForAccount = new HashMap<String, String>();
- SQLiteDatabase db = mOpenHelper.getReadableDatabase();
Cursor cursor = db.query(TABLE_EXTRAS,
COLUMNS_EXTRAS_KEY_AND_VALUE,
SELECTION_USERDATA_BY_ACCOUNT,
@@ -2256,9 +2227,9 @@ public class AccountManagerService
return userDataForAccount;
}
- protected HashMap<String, String> readAuthTokensForAccountFromDatabase(Account account) {
+ protected HashMap<String, String> readAuthTokensForAccountFromDatabaseLocked(
+ final SQLiteDatabase db, Account account) {
HashMap<String, String> authTokensForAccount = new HashMap<String, String>();
- SQLiteDatabase db = mOpenHelper.getReadableDatabase();
Cursor cursor = db.query(TABLE_AUTHTOKENS,
COLUMNS_AUTHTOKENS_TYPE_AND_AUTHTOKEN,
SELECTION_AUTHTOKENS_BY_ACCOUNT,
diff --git a/core/java/android/animation/ValueAnimator.java b/core/java/android/animation/ValueAnimator.java
index 2e44d6d..f562851 100755
--- a/core/java/android/animation/ValueAnimator.java
+++ b/core/java/android/animation/ValueAnimator.java
@@ -160,6 +160,11 @@ public class ValueAnimator extends Animator {
private int mCurrentIteration = 0;
/**
+ * Tracks current elapsed/eased fraction, for querying in getAnimatedFraction().
+ */
+ private float mCurrentFraction = 0f;
+
+ /**
* Tracks whether a startDelay'd animation has begun playing through the startDelay.
*/
private boolean mStartedDelay = false;
@@ -902,6 +907,7 @@ public class ValueAnimator extends Animator {
if (mStartDelay == 0) {
// This sets the initial value of the animation, prior to actually starting it running
setCurrentPlayTime(getCurrentPlayTime());
+ mPlayingState = STOPPED;
if (mListeners != null) {
ArrayList<AnimatorListener> tmpListeners =
@@ -1110,6 +1116,16 @@ public class ValueAnimator extends Animator {
}
/**
+ * Returns the current animation fraction, which is the elapsed/interpolated fraction used in
+ * the most recent frame update on the animation.
+ *
+ * @return Elapsed/interpolated fraction of the animation.
+ */
+ public float getAnimatedFraction() {
+ return mCurrentFraction;
+ }
+
+ /**
* This method is called with the elapsed fraction of the animation during every
* animation frame. This function turns the elapsed fraction into an interpolated fraction
* and then into an animated value (from the evaluator. The function is called mostly during
@@ -1123,6 +1139,7 @@ public class ValueAnimator extends Animator {
*/
void animateValue(float fraction) {
fraction = mInterpolator.getInterpolation(fraction);
+ mCurrentFraction = fraction;
int numValues = mValues.length;
for (int i = 0; i < numValues; ++i) {
mValues[i].calculateValue(fraction);
diff --git a/core/java/android/animation/package.html b/core/java/android/animation/package.html
index ff43260..92eeb20 100644
--- a/core/java/android/animation/package.html
+++ b/core/java/android/animation/package.html
@@ -15,7 +15,7 @@ behaviors.</p>
<p>
For a guide on how to use the property animation system, see the
-<a href="{@docRoot}guide/topics/media/index.html">Animation</a> developer guide.
+<a href="{@docRoot}guide/topics/graphics/animation.html">Animation</a> developer guide.
</p>
</body>
</html>
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java
index 67e4806..3a82c78 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -66,6 +66,7 @@ import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.MotionEvent;
import android.view.View;
+import android.view.WindowManagerImpl;
import android.view.View.OnCreateContextMenuListener;
import android.view.ViewGroup;
import android.view.ViewGroup.LayoutParams;
@@ -2122,24 +2123,21 @@ public class Activity extends ContextThemeWrapper
* Called when a generic motion event was not handled by any of the
* views inside of the activity.
* <p>
- * Generic motion events are dispatched to the focused view to describe
- * the motions of input devices such as joysticks. The
+ * Generic motion events describe joystick movements, mouse hovers, track pad
+ * touches, scroll wheel movements and other input events. The
* {@link MotionEvent#getSource() source} of the motion event specifies
* the class of input that was received. Implementations of this method
* must examine the bits in the source before processing the event.
* The following code example shows how this is done.
+ * </p><p>
+ * Generic motion events with source class
+ * {@link android.view.InputDevice#SOURCE_CLASS_POINTER}
+ * are delivered to the view under the pointer. All other generic motion events are
+ * delivered to the focused view.
+ * </p><p>
+ * See {@link View#onGenericMotionEvent(MotionEvent)} for an example of how to
+ * handle this event.
* </p>
- * <code>
- * public boolean onGenericMotionEvent(MotionEvent event) {
- * if ((event.getSource() &amp; InputDevice.SOURCE_CLASS_JOYSTICK) != 0) {
- * float x = event.getX();
- * float y = event.getY();
- * // process the joystick motion
- * return true;
- * }
- * return super.onGenericMotionEvent(event);
- * }
- * </code>
*
* @param event The generic motion event being processed.
*
@@ -2420,6 +2418,7 @@ public class Activity extends ContextThemeWrapper
*/
public boolean onMenuOpened(int featureId, Menu menu) {
if (featureId == Window.FEATURE_ACTION_BAR) {
+ initActionBar();
if (mActionBar != null) {
mActionBar.dispatchMenuVisibilityChanged(true);
} else {
@@ -4404,6 +4403,9 @@ public class Activity extends ContextThemeWrapper
if (mStopped) {
mStopped = false;
mCalled = false;
+ if (mToken != null && mParent == null) {
+ WindowManagerImpl.getDefault().setStoppedState(mToken, false);
+ }
mInstrumentation.callActivityOnRestart(this);
if (!mCalled) {
throw new SuperNotCalledException(
@@ -4480,6 +4482,10 @@ public class Activity extends ContextThemeWrapper
mWindow.closeAllPanels();
}
+ if (mToken != null && mParent == null) {
+ WindowManagerImpl.getDefault().setStoppedState(mToken, true);
+ }
+
mFragments.dispatchStop();
mCalled = false;
diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java
index a660076..77dc084 100644
--- a/core/java/android/app/ActivityManager.java
+++ b/core/java/android/app/ActivityManager.java
@@ -30,11 +30,17 @@ import android.os.RemoteException;
import android.os.Handler;
import android.os.Parcel;
import android.os.Parcelable;
+import android.os.ServiceManager;
import android.os.SystemProperties;
import android.text.TextUtils;
import android.util.DisplayMetrics;
+import android.util.Log;
+import com.android.internal.app.IUsageStats;
+import com.android.internal.os.PkgUsageStats;
+import java.util.HashMap;
import java.util.List;
+import java.util.Map;
/**
* Interact with the overall activities running in the system.
@@ -1233,4 +1239,29 @@ public class ActivityManager {
public static boolean isRunningInTestHarness() {
return SystemProperties.getBoolean("ro.test_harness", false);
}
+
+ /**
+ * Returns the launch count of each installed package.
+ *
+ * @hide
+ */
+ public Map<String, Integer> getAllPackageLaunchCounts() {
+ try {
+ IUsageStats usageStatsService = IUsageStats.Stub.asInterface(
+ ServiceManager.getService("usagestats"));
+ if (usageStatsService == null) {
+ return new HashMap<String, Integer>();
+ }
+
+ Map<String, Integer> launchCounts = new HashMap<String, Integer>();
+ for (PkgUsageStats pkgUsageStats : usageStatsService.getAllPkgUsageStats()) {
+ launchCounts.put(pkgUsageStats.packageName, pkgUsageStats.launchCount);
+ }
+
+ return launchCounts;
+ } catch (RemoteException e) {
+ Log.w(TAG, "Could not query launch counts", e);
+ return new HashMap<String, Integer>();
+ }
+ }
}
diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java
index 8737e93..539e946 100644
--- a/core/java/android/app/ContextImpl.java
+++ b/core/java/android/app/ContextImpl.java
@@ -41,9 +41,9 @@ import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteDatabase.CursorFactory;
import android.graphics.Bitmap;
import android.graphics.drawable.Drawable;
-import android.hardware.IUsbManager;
import android.hardware.SensorManager;
-import android.hardware.UsbManager;
+import android.hardware.usb.IUsbManager;
+import android.hardware.usb.UsbManager;
import android.location.CountryDetector;
import android.location.ICountryDetector;
import android.location.ILocationManager;
diff --git a/core/java/android/app/Dialog.java b/core/java/android/app/Dialog.java
index cc4fefc..087753b 100644
--- a/core/java/android/app/Dialog.java
+++ b/core/java/android/app/Dialog.java
@@ -627,24 +627,21 @@ public class Dialog implements DialogInterface, Window.Callback,
* Called when a generic motion event was not handled by any of the
* views inside of the dialog.
* <p>
- * Generic motion events are dispatched to the focused view to describe
- * the motions of input devices such as joysticks. The
+ * Generic motion events describe joystick movements, mouse hovers, track pad
+ * touches, scroll wheel movements and other input events. The
* {@link MotionEvent#getSource() source} of the motion event specifies
* the class of input that was received. Implementations of this method
* must examine the bits in the source before processing the event.
* The following code example shows how this is done.
+ * </p><p>
+ * Generic motion events with source class
+ * {@link android.view.InputDevice#SOURCE_CLASS_POINTER}
+ * are delivered to the view under the pointer. All other generic motion events are
+ * delivered to the focused view.
+ * </p><p>
+ * See {@link View#onGenericMotionEvent(MotionEvent)} for an example of how to
+ * handle this event.
* </p>
- * <code>
- * public boolean onGenericMotionEvent(MotionEvent event) {
- * if ((event.getSource() &amp; InputDevice.SOURCE_CLASS_JOYSTICK) != 0) {
- * float x = event.getX();
- * float y = event.getY();
- * // process the joystick motion
- * return true;
- * }
- * return super.onGenericMotionEvent(event);
- * }
- * </code>
*
* @param event The generic motion event being processed.
*
diff --git a/core/java/android/app/DialogFragment.java b/core/java/android/app/DialogFragment.java
index 50953d7..dee1ef3 100644
--- a/core/java/android/app/DialogFragment.java
+++ b/core/java/android/app/DialogFragment.java
@@ -25,6 +25,9 @@ import android.view.ViewGroup;
import android.view.Window;
import android.view.WindowManager;
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
+
/**
* A fragment that displays a dialog window, floating on top of its
* activity's window. This fragment contains a Dialog object, which it
@@ -177,8 +180,9 @@ public class DialogFragment extends Fragment
int mBackStackId = -1;
Dialog mDialog;
- boolean mDestroyed;
- boolean mRemoved;
+ boolean mViewDestroyed;
+ boolean mDismissed;
+ boolean mShownByMe;
public DialogFragment() {
}
@@ -219,6 +223,8 @@ public class DialogFragment extends Fragment
* {@link FragmentTransaction#add(Fragment, String) FragmentTransaction.add}.
*/
public void show(FragmentManager manager, String tag) {
+ mDismissed = false;
+ mShownByMe = true;
FragmentTransaction ft = manager.beginTransaction();
ft.add(this, tag);
ft.commit();
@@ -234,8 +240,10 @@ public class DialogFragment extends Fragment
* {@link FragmentTransaction#commit() FragmentTransaction.commit()}.
*/
public int show(FragmentTransaction transaction, String tag) {
+ mDismissed = false;
+ mShownByMe = true;
transaction.add(this, tag);
- mRemoved = false;
+ mViewDestroyed = false;
mBackStackId = transaction.commit();
return mBackStackId;
}
@@ -251,11 +259,16 @@ public class DialogFragment extends Fragment
}
void dismissInternal(boolean allowStateLoss) {
+ if (mDismissed) {
+ return;
+ }
+ mDismissed = true;
+ mShownByMe = false;
if (mDialog != null) {
mDialog.dismiss();
mDialog = null;
}
- mRemoved = true;
+ mViewDestroyed = true;
if (mBackStackId >= 0) {
getFragmentManager().popBackStack(mBackStackId,
FragmentManager.POP_BACK_STACK_INCLUSIVE);
@@ -329,6 +342,27 @@ public class DialogFragment extends Fragment
}
@Override
+ public void onAttach(Activity activity) {
+ super.onAttach(activity);
+ if (!mShownByMe) {
+ // If not explicitly shown through our API, take this as an
+ // indication that the dialog is no longer dismissed.
+ mDismissed = false;
+ }
+ }
+
+ @Override
+ public void onDetach() {
+ super.onDetach();
+ if (!mShownByMe && !mDismissed) {
+ // The fragment was not shown by a direct call here, it is not
+ // dismissed, and now it is being detached... well, okay, thou
+ // art now dismissed. Have fun.
+ mDismissed = true;
+ }
+ }
+
+ @Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
@@ -352,7 +386,6 @@ public class DialogFragment extends Fragment
}
mDialog = onCreateDialog(savedInstanceState);
- mDestroyed = false;
switch (mStyle) {
case STYLE_NO_INPUT:
mDialog.getWindow().addFlags(
@@ -363,7 +396,11 @@ public class DialogFragment extends Fragment
case STYLE_NO_TITLE:
mDialog.requestWindowFeature(Window.FEATURE_NO_TITLE);
}
- return (LayoutInflater)mDialog.getContext().getSystemService(
+ if (mDialog != null) {
+ return (LayoutInflater)mDialog.getContext().getSystemService(
+ Context.LAYOUT_INFLATER_SERVICE);
+ }
+ return (LayoutInflater)mActivity.getSystemService(
Context.LAYOUT_INFLATER_SERVICE);
}
@@ -397,7 +434,7 @@ public class DialogFragment extends Fragment
}
public void onDismiss(DialogInterface dialog) {
- if (!mRemoved) {
+ if (!mViewDestroyed) {
// Note: we need to use allowStateLoss, because the dialog
// dispatches this asynchronously so we can receive the call
// after the activity is paused. Worst case, when the user comes
@@ -439,7 +476,7 @@ public class DialogFragment extends Fragment
public void onStart() {
super.onStart();
if (mDialog != null) {
- mRemoved = false;
+ mViewDestroyed = false;
mDialog.show();
}
}
@@ -484,14 +521,28 @@ public class DialogFragment extends Fragment
@Override
public void onDestroyView() {
super.onDestroyView();
- mDestroyed = true;
if (mDialog != null) {
// Set removed here because this dismissal is just to hide
// the dialog -- we don't want this to cause the fragment to
// actually be removed.
- mRemoved = true;
+ mViewDestroyed = true;
mDialog.dismiss();
mDialog = null;
}
}
+
+ @Override
+ public void dump(String prefix, FileDescriptor fd, PrintWriter writer, String[] args) {
+ super.dump(prefix, fd, writer, args);
+ writer.print(prefix); writer.println("DialogFragment:");
+ writer.print(prefix); writer.print(" mStyle="); writer.print(mStyle);
+ writer.print(" mTheme=0x"); writer.println(Integer.toHexString(mTheme));
+ writer.print(prefix); writer.print(" mCancelable="); writer.print(mCancelable);
+ writer.print(" mShowsDialog="); writer.print(mShowsDialog);
+ writer.print(" mBackStackId="); writer.println(mBackStackId);
+ writer.print(prefix); writer.print(" mDialog="); writer.println(mDialog);
+ writer.print(prefix); writer.print(" mViewDestroyed="); writer.print(mViewDestroyed);
+ writer.print(" mDismissed="); writer.print(mDismissed);
+ writer.print(" mShownByMe="); writer.println(mShownByMe);
+ }
}
diff --git a/core/java/android/app/DownloadManager.java b/core/java/android/app/DownloadManager.java
index 178567f..d04fa57 100644
--- a/core/java/android/app/DownloadManager.java
+++ b/core/java/android/app/DownloadManager.java
@@ -907,8 +907,8 @@ public class DownloadManager {
/**
* Cancel downloads and remove them from the download manager. Each download will be stopped if
- * it was running, and it will no longer be accessible through the download manager. If a file
- * was already downloaded to external storage, it will not be deleted.
+ * it was running, and it will no longer be accessible through the download manager.
+ * If there is a downloaded file, partial or complete, it is deleted.
*
* @param ids the IDs of the downloads to remove
* @return the number of downloads actually removed
diff --git a/core/java/android/app/FragmentManager.java b/core/java/android/app/FragmentManager.java
index 52b3108..d8d0a5b 100644
--- a/core/java/android/app/FragmentManager.java
+++ b/core/java/android/app/FragmentManager.java
@@ -167,10 +167,9 @@ public abstract class FragmentManager {
public static final int POP_BACK_STACK_INCLUSIVE = 1<<0;
/**
- * Pop the top state off the back stack. Returns true if there was one
- * to pop, else false. This function is asynchronous -- it enqueues the
- * request to pop, but the action will not be performed until the application
- * returns to its event loop.
+ * Pop the top state off the back stack. This function is asynchronous -- it
+ * enqueues the request to pop, but the action will not be performed until the
+ * application returns to its event loop.
*/
public abstract void popBackStack();
diff --git a/core/java/android/app/KeyguardManager.java b/core/java/android/app/KeyguardManager.java
index e3d8e20..a601fbf 100644
--- a/core/java/android/app/KeyguardManager.java
+++ b/core/java/android/app/KeyguardManager.java
@@ -117,6 +117,40 @@ public class KeyguardManager {
}
/**
+ * isKeyguardLocked
+ *
+ * Return whether the keyguard is currently locked.
+ *
+ * @return true if in keyguard is locked.
+ *
+ * @hide
+ */
+ public boolean isKeyguardLocked() {
+ try {
+ return mWM.isKeyguardLocked();
+ } catch (RemoteException ex) {
+ return false;
+ }
+ }
+
+ /**
+ * isKeyguardSecure
+ *
+ * Return whether the keyguard requires a password to unlock.
+ *
+ * @return true if in keyguard is secure.
+ *
+ * @hide
+ */
+ public boolean isKeyguardSecure() {
+ try {
+ return mWM.isKeyguardSecure();
+ } catch (RemoteException ex) {
+ return false;
+ }
+ }
+
+ /**
* If keyguard screen is showing or in restricted key input mode (i.e. in
* keyguard password emergency screen). When in such mode, certain keys,
* such as the Home key and the right soft keys, don't work.
diff --git a/core/java/android/app/ListActivity.java b/core/java/android/app/ListActivity.java
index d49968f..2162521 100644
--- a/core/java/android/app/ListActivity.java
+++ b/core/java/android/app/ListActivity.java
@@ -43,7 +43,7 @@ import android.widget.ListView;
* <p>
* Optionally, your custom view can contain another view object of any type to
* display when the list view is empty. This "empty list" notifier must have an
- * id "android:empty". Note that when an empty view is present, the list view
+ * id "android:id/empty". Note that when an empty view is present, the list view
* will be hidden when there is no data to display.
* <p>
* The following code demonstrates an (ugly) custom screen layout. It has a list
@@ -59,14 +59,14 @@ import android.widget.ListView;
* android:paddingLeft=&quot;8dp&quot;
* android:paddingRight=&quot;8dp&quot;&gt;
*
- * &lt;ListView android:id=&quot;@id/android:list&quot;
+ * &lt;ListView android:id=&quot;@android:id/list&quot;
* android:layout_width=&quot;match_parent&quot;
* android:layout_height=&quot;match_parent&quot;
* android:background=&quot;#00FF00&quot;
* android:layout_weight=&quot;1&quot;
* android:drawSelectorOnTop=&quot;false&quot;/&gt;
*
- * &lt;TextView android:id=&quot;@id/android:empty&quot;
+ * &lt;TextView android:id=&quot;@android:id/empty&quot;
* android:layout_width=&quot;match_parent&quot;
* android:layout_height=&quot;match_parent&quot;
* android:background=&quot;#FF0000&quot;
diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java
index 4370ebf..ccd65de 100644
--- a/core/java/android/app/Notification.java
+++ b/core/java/android/app/Notification.java
@@ -82,6 +82,7 @@ public class Notification implements Parcelable
/**
* The resource id of a drawable to use as the icon in the status bar.
+ * This is required; notifications with an invalid icon resource will not be shown.
*/
public int icon;
diff --git a/core/java/android/app/NotificationManager.java b/core/java/android/app/NotificationManager.java
index e3242c1..6541c54 100644
--- a/core/java/android/app/NotificationManager.java
+++ b/core/java/android/app/NotificationManager.java
@@ -83,12 +83,14 @@ public class NotificationManager
}
/**
- * Persistent notification on the status bar,
+ * Post a notification to be shown in the status bar. If a notification with
+ * the same id has already been posted by your application and has not yet been canceled, it
+ * will be replaced by the updated information.
*
* @param id An identifier for this notification unique within your
* application.
- * @param notification A {@link Notification} object describing how to
- * notify the user, other than the view you're providing. Must not be null.
+ * @param notification A {@link Notification} object describing what to show the user. Must not
+ * be null.
*/
public void notify(int id, Notification notification)
{
@@ -96,13 +98,15 @@ public class NotificationManager
}
/**
- * Persistent notification on the status bar,
+ * Post a notification to be shown in the status bar. If a notification with
+ * the same tag and id has already been posted by your application and has not yet been
+ * canceled, it will be replaced by the updated information.
*
* @param tag A string identifier for this notification. May be {@code null}.
* @param id An identifier for this notification. The pair (tag, id) must be unique
* within your application.
- * @param notification A {@link Notification} object describing how to
- * notify the user, other than the view you're providing. Must not be null.
+ * @param notification A {@link Notification} object describing what to
+ * show the user. Must not be null.
*/
public void notify(String tag, int id, Notification notification)
{
diff --git a/core/java/android/app/SearchManager.java b/core/java/android/app/SearchManager.java
index 6715012..aab087f 100644
--- a/core/java/android/app/SearchManager.java
+++ b/core/java/android/app/SearchManager.java
@@ -138,6 +138,12 @@ public class SearchManager
public final static String EXTRA_SELECT_QUERY = "select_query";
/**
+ * Boolean extra data key for {@link Intent#ACTION_WEB_SEARCH} intents. If {@code true},
+ * this search should open a new browser window, rather than using an existing one.
+ */
+ public final static String EXTRA_NEW_SEARCH = "new_search";
+
+ /**
* Boolean extra data key for a suggestion provider to return in {@link Cursor#getExtras} to
* indicate that the search is not complete yet. This can be used by the search UI
* to indicate that a search is in progress. The suggestion provider can return partial results
diff --git a/core/java/android/app/backup/WallpaperBackupHelper.java b/core/java/android/app/backup/WallpaperBackupHelper.java
index d70b3d3..6539711 100644
--- a/core/java/android/app/backup/WallpaperBackupHelper.java
+++ b/core/java/android/app/backup/WallpaperBackupHelper.java
@@ -21,6 +21,8 @@ import android.content.Context;
import android.graphics.BitmapFactory;
import android.os.ParcelFileDescriptor;
import android.util.Slog;
+import android.view.Display;
+import android.view.WindowManager;
import java.io.File;
@@ -65,6 +67,13 @@ public class WallpaperBackupHelper extends FileBackupHelperBase implements Backu
mDesiredMinWidth = (double) wpm.getDesiredMinimumWidth();
mDesiredMinHeight = (double) wpm.getDesiredMinimumHeight();
+ if (mDesiredMinWidth <= 0 || mDesiredMinHeight <= 0) {
+ WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
+ Display d = wm.getDefaultDisplay();
+ mDesiredMinWidth = d.getWidth();
+ mDesiredMinHeight = d.getHeight();
+ }
+
if (DEBUG) {
Slog.d(TAG, "dmW=" + mDesiredMinWidth + " dmH=" + mDesiredMinHeight);
}
diff --git a/core/java/android/appwidget/AppWidgetHost.java b/core/java/android/appwidget/AppWidgetHost.java
index 9835484..8204a4f 100644
--- a/core/java/android/appwidget/AppWidgetHost.java
+++ b/core/java/android/appwidget/AppWidgetHost.java
@@ -16,6 +16,9 @@
package android.appwidget;
+import java.util.ArrayList;
+import java.util.HashMap;
+
import android.content.Context;
import android.os.Handler;
import android.os.IBinder;
@@ -23,11 +26,10 @@ import android.os.Looper;
import android.os.Message;
import android.os.RemoteException;
import android.os.ServiceManager;
+import android.util.DisplayMetrics;
+import android.util.TypedValue;
import android.widget.RemoteViews;
-import java.util.ArrayList;
-import java.util.HashMap;
-
import com.android.internal.appwidget.IAppWidgetHost;
import com.android.internal.appwidget.IAppWidgetService;
@@ -43,6 +45,7 @@ public class AppWidgetHost {
final static Object sServiceLock = new Object();
static IAppWidgetService sService;
+ private DisplayMetrics mDisplayMetrics;
Context mContext;
String mPackageName;
@@ -103,6 +106,7 @@ public class AppWidgetHost {
mContext = context;
mHostId = hostId;
mHandler = new UpdateHandler(context.getMainLooper());
+ mDisplayMetrics = context.getResources().getDisplayMetrics();
synchronized (sServiceLock) {
if (sService == null) {
IBinder b = ServiceManager.getService(Context.APPWIDGET_SERVICE);
@@ -243,12 +247,21 @@ public class AppWidgetHost {
AppWidgetProviderInfo appWidget) {
return new AppWidgetHostView(context);
}
-
+
/**
* Called when the AppWidget provider for a AppWidget has been upgraded to a new apk.
*/
protected void onProviderChanged(int appWidgetId, AppWidgetProviderInfo appWidget) {
AppWidgetHostView v;
+
+ // Convert complex to dp -- we are getting the AppWidgetProviderInfo from the
+ // AppWidgetService, which doesn't have our context, hence we need to do the
+ // conversion here.
+ appWidget.minWidth =
+ TypedValue.complexToDimensionPixelSize(appWidget.minWidth, mDisplayMetrics);
+ appWidget.minHeight =
+ TypedValue.complexToDimensionPixelSize(appWidget.minHeight, mDisplayMetrics);
+
synchronized (mViews) {
v = mViews.get(appWidgetId);
}
diff --git a/core/java/android/appwidget/AppWidgetProviderInfo.java b/core/java/android/appwidget/AppWidgetProviderInfo.java
index fe33782..b46802e 100644
--- a/core/java/android/appwidget/AppWidgetProviderInfo.java
+++ b/core/java/android/appwidget/AppWidgetProviderInfo.java
@@ -25,6 +25,24 @@ import android.content.ComponentName;
* correspond to the fields in the <code>&lt;appwidget-provider&gt;</code> xml tag.
*/
public class AppWidgetProviderInfo implements Parcelable {
+
+ /**
+ * Widget is not resizable.
+ */
+ public static final int RESIZE_NONE = 0;
+ /**
+ * Widget is resizable in the horizontal axis only.
+ */
+ public static final int RESIZE_HORIZONTAL = 1;
+ /**
+ * Widget is resizable in the vertical axis only.
+ */
+ public static final int RESIZE_VERTICAL = 2;
+ /**
+ * Widget is resizable in both the horizontal and vertical axes.
+ */
+ public static final int RESIZE_BOTH = RESIZE_HORIZONTAL | RESIZE_VERTICAL;
+
/**
* Identity of this AppWidget component. This component should be a {@link
* android.content.BroadcastReceiver}, and it will be sent the AppWidget intents
@@ -112,6 +130,9 @@ public class AppWidgetProviderInfo implements Parcelable {
/**
* The view id of the AppWidget subview which should be auto-advanced by the widget's host.
+ *
+ * <p>This field corresponds to the <code>android:autoAdvanceViewId</code> attribute in
+ * the AppWidget meta-data file.
*/
public int autoAdvanceViewId;
@@ -124,6 +145,16 @@ public class AppWidgetProviderInfo implements Parcelable {
*/
public int previewImage;
+ /**
+ * The rules by which a widget can be resized. See {@link #RESIZE_NONE},
+ * {@link #RESIZE_NONE}, {@link #RESIZE_HORIZONTAL},
+ * {@link #RESIZE_VERTICAL}, {@link #RESIZE_BOTH}.
+ *
+ * <p>This field corresponds to the <code>android:resizeMode</code> attribute in
+ * the AppWidget meta-data file.
+ */
+ public int resizeMode;
+
public AppWidgetProviderInfo() {
}
@@ -145,6 +176,7 @@ public class AppWidgetProviderInfo implements Parcelable {
this.icon = in.readInt();
this.previewImage = in.readInt();
this.autoAdvanceViewId = in.readInt();
+ this.resizeMode = in.readInt();
}
public void writeToParcel(android.os.Parcel out, int flags) {
@@ -168,6 +200,7 @@ public class AppWidgetProviderInfo implements Parcelable {
out.writeInt(this.icon);
out.writeInt(this.previewImage);
out.writeInt(this.autoAdvanceViewId);
+ out.writeInt(this.resizeMode);
}
public int describeContents() {
diff --git a/core/java/android/bluetooth/BluetoothAdapter.java b/core/java/android/bluetooth/BluetoothAdapter.java
index 4656e15..e1c9044 100644
--- a/core/java/android/bluetooth/BluetoothAdapter.java
+++ b/core/java/android/bluetooth/BluetoothAdapter.java
@@ -1049,6 +1049,12 @@ public final class BluetoothAdapter {
} else if (profile == BluetoothProfile.A2DP) {
BluetoothA2dp a2dp = new BluetoothA2dp(context, listener);
return true;
+ } else if (profile == BluetoothProfile.INPUT_DEVICE) {
+ BluetoothInputDevice iDev = new BluetoothInputDevice(context, listener);
+ return true;
+ } else if (profile == BluetoothProfile.PAN) {
+ BluetoothPan pan = new BluetoothPan(context, listener);
+ return true;
} else {
return false;
}
diff --git a/core/java/android/bluetooth/BluetoothDeviceProfileState.java b/core/java/android/bluetooth/BluetoothDeviceProfileState.java
index 6ec347f..9855709 100644
--- a/core/java/android/bluetooth/BluetoothDeviceProfileState.java
+++ b/core/java/android/bluetooth/BluetoothDeviceProfileState.java
@@ -82,7 +82,6 @@ public final class BluetoothDeviceProfileState extends HierarchicalStateMachine
public static final int TRANSITION_TO_STABLE = 102;
public static final int CONNECT_OTHER_PROFILES = 103;
- private static final int AUTO_CONNECT_DELAY = 6000; // 6 secs
private static final int CONNECT_OTHER_PROFILES_DELAY = 4000; // 4 secs
private BondedDevice mBondedDevice = new BondedDevice();
@@ -136,17 +135,17 @@ public final class BluetoothDeviceProfileState extends HierarchicalStateMachine
newState == BluetoothProfile.STATE_DISCONNECTED) {
sendMessage(TRANSITION_TO_STABLE);
}
- } else if (action.equals(BluetoothInputDevice.ACTION_INPUT_DEVICE_STATE_CHANGED)) {
- int newState = intent.getIntExtra(BluetoothInputDevice.EXTRA_INPUT_DEVICE_STATE, 0);
+ } else if (action.equals(BluetoothInputDevice.ACTION_CONNECTION_STATE_CHANGED)) {
+ int newState = intent.getIntExtra(BluetoothProfile.EXTRA_STATE, 0);
int oldState =
- intent.getIntExtra(BluetoothInputDevice.EXTRA_PREVIOUS_INPUT_DEVICE_STATE, 0);
+ intent.getIntExtra(BluetoothProfile.EXTRA_PREVIOUS_STATE, 0);
- if (oldState == BluetoothInputDevice.STATE_CONNECTED &&
- newState == BluetoothInputDevice.STATE_DISCONNECTED) {
+ if (oldState == BluetoothProfile.STATE_CONNECTED &&
+ newState == BluetoothProfile.STATE_DISCONNECTED) {
sendMessage(DISCONNECT_HID_INCOMING);
}
- if (newState == BluetoothInputDevice.STATE_CONNECTED ||
- newState == BluetoothInputDevice.STATE_DISCONNECTED) {
+ if (newState == BluetoothProfile.STATE_CONNECTED ||
+ newState == BluetoothProfile.STATE_DISCONNECTED) {
sendMessage(TRANSITION_TO_STABLE);
}
} else if (action.equals(BluetoothDevice.ACTION_ACL_DISCONNECTED)) {
@@ -194,7 +193,7 @@ public final class BluetoothDeviceProfileState extends HierarchicalStateMachine
filter.addAction(BluetoothDevice.ACTION_ACL_CONNECTED);
filter.addAction(BluetoothHeadset.ACTION_CONNECTION_STATE_CHANGED);
filter.addAction(BluetoothA2dp.ACTION_CONNECTION_STATE_CHANGED);
- filter.addAction(BluetoothInputDevice.ACTION_INPUT_DEVICE_STATE_CHANGED);
+ filter.addAction(BluetoothInputDevice.ACTION_CONNECTION_STATE_CHANGED);
filter.addAction(BluetoothDevice.ACTION_ACL_DISCONNECTED);
mContext.registerReceiver(mBroadcastReceiver, filter);
@@ -286,7 +285,7 @@ public final class BluetoothDeviceProfileState extends HierarchicalStateMachine
sendMessage(DISCONNECT_A2DP_OUTGOING);
deferMessage(message);
break;
- } else if (mService.getInputDeviceState(mDevice) !=
+ } else if (mService.getInputDeviceConnectionState(mDevice) !=
BluetoothInputDevice.STATE_DISCONNECTED) {
sendMessage(DISCONNECT_HID_OUTGOING);
deferMessage(message);
diff --git a/core/java/android/bluetooth/BluetoothInputDevice.java b/core/java/android/bluetooth/BluetoothInputDevice.java
index a70de59..df212a8 100644
--- a/core/java/android/bluetooth/BluetoothInputDevice.java
+++ b/core/java/android/bluetooth/BluetoothInputDevice.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2010 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.
@@ -27,91 +27,88 @@ import android.util.Log;
import java.util.ArrayList;
import java.util.List;
+
/**
- * Public API for controlling the Bluetooth HID (Input Device) Profile
- *
- * BluetoothInputDevice is a proxy object used to make calls to Bluetooth Service
- * which handles the HID profile.
+ * This class provides the public APIs to control the Bluetooth Input
+ * Device Profile.
*
- * Creating a BluetoothInputDevice object will initiate a binding with the
- * Bluetooth service. Users of this object should call close() when they
- * are finished, so that this proxy object can unbind from the service.
+ *<p>BluetoothInputDevice is a proxy object for controlling the Bluetooth
+ * Service via IPC. Use {@link BluetoothAdapter#getProfileProxy} to get
+ * the BluetoothInputDevice proxy object.
*
- * Currently the Bluetooth service runs in the system server and this
- * proxy object will be immediately bound to the service on construction.
- *
- * @hide
+ *<p>Each method is protected with its appropriate permission.
+ *@hide
*/
-public final class BluetoothInputDevice {
+public final class BluetoothInputDevice implements BluetoothProfile {
private static final String TAG = "BluetoothInputDevice";
private static final boolean DBG = false;
- /** int extra for ACTION_INPUT_DEVICE_STATE_CHANGED */
- public static final String EXTRA_INPUT_DEVICE_STATE =
- "android.bluetooth.inputdevice.extra.INPUT_DEVICE_STATE";
- /** int extra for ACTION_INPUT_DEVICE_STATE_CHANGED */
- public static final String EXTRA_PREVIOUS_INPUT_DEVICE_STATE =
- "android.bluetooth.inputdevice.extra.PREVIOUS_INPUT_DEVICE_STATE";
-
- /** Indicates the state of an input device has changed.
- * This intent will always contain EXTRA_INPUT_DEVICE_STATE,
- * EXTRA_PREVIOUS_INPUT_DEVICE_STATE and BluetoothDevice.EXTRA_DEVICE
- * extras.
- */
- @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
- public static final String ACTION_INPUT_DEVICE_STATE_CHANGED =
- "android.bluetooth.inputdevice.action.INPUT_DEVICE_STATE_CHANGED";
-
- public static final int STATE_DISCONNECTED = 0;
- public static final int STATE_CONNECTING = 1;
- public static final int STATE_CONNECTED = 2;
- public static final int STATE_DISCONNECTING = 3;
-
- /**
- * Auto connection, incoming and outgoing connection are allowed at this
- * priority level.
- */
- public static final int PRIORITY_AUTO_CONNECT = 1000;
- /**
- * Incoming and outgoing connection are allowed at this priority level
- */
- public static final int PRIORITY_ON = 100;
- /**
- * Connections to the device are not allowed at this priority level.
- */
- public static final int PRIORITY_OFF = 0;
/**
- * Default priority level when the device is unpaired.
+ * Intent used to broadcast the change in connection state of the Input
+ * Device profile.
+ *
+ * <p>This intent will have 3 extras:
+ * <ul>
+ * <li> {@link #EXTRA_STATE} - The current state of the profile. </li>
+ * <li> {@link #EXTRA_PREVIOUS_STATE}- The previous state of the profile.</li>
+ * <li> {@link BluetoothDevice#EXTRA_DEVICE} - The remote device. </li>
+ * </ul>
+ *
+ * <p>{@link #EXTRA_STATE} or {@link #EXTRA_PREVIOUS_STATE} can be any of
+ * {@link #STATE_DISCONNECTED}, {@link #STATE_CONNECTING},
+ * {@link #STATE_CONNECTED}, {@link #STATE_DISCONNECTING}.
+ *
+ * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission to
+ * receive.
*/
- public static final int PRIORITY_UNDEFINED = -1;
+ @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
+ public static final String ACTION_CONNECTION_STATE_CHANGED =
+ "android.bluetooth.input.profile.action.CONNECTION_STATE_CHANGED";
/**
* Return codes for the connect and disconnect Bluez / Dbus calls.
+ * @hide
*/
public static final int INPUT_DISCONNECT_FAILED_NOT_CONNECTED = 5000;
+ /**
+ * @hide
+ */
public static final int INPUT_CONNECT_FAILED_ALREADY_CONNECTED = 5001;
+ /**
+ * @hide
+ */
public static final int INPUT_CONNECT_FAILED_ATTEMPT_FAILED = 5002;
+ /**
+ * @hide
+ */
public static final int INPUT_OPERATION_GENERIC_FAILURE = 5003;
+ /**
+ * @hide
+ */
public static final int INPUT_OPERATION_SUCCESS = 5004;
- private final IBluetooth mService;
- private final Context mContext;
+ private ServiceListener mServiceListener;
+ private BluetoothAdapter mAdapter;
+ private IBluetooth mService;
/**
* Create a BluetoothInputDevice proxy object for interacting with the local
- * Bluetooth Service which handle the HID profile.
- * @param c Context
+ * Bluetooth Service which handles the InputDevice profile
+ *
*/
- public BluetoothInputDevice(Context c) {
- mContext = c;
-
+ /*package*/ BluetoothInputDevice(Context mContext, ServiceListener l) {
IBinder b = ServiceManager.getService(BluetoothAdapter.BLUETOOTH_SERVICE);
+ mServiceListener = l;
+ mAdapter = BluetoothAdapter.getDefaultAdapter();
if (b != null) {
mService = IBluetooth.Stub.asInterface(b);
+ if (mServiceListener != null) {
+ mServiceListener.onServiceConnected(BluetoothProfile.INPUT_DEVICE, this);
+ }
} else {
Log.w(TAG, "Bluetooth Service not available!");
@@ -121,130 +118,151 @@ public final class BluetoothInputDevice {
}
}
- /** Initiate a connection to an Input device.
- *
- * This function returns false on error and true if the connection
- * attempt is being made.
- *
- * Listen for INPUT_DEVICE_STATE_CHANGED_ACTION to find out when the
- * connection is completed.
- * @param device Remote BT device.
- * @return false on immediate error, true otherwise
- * @hide
+ /**
+ * {@inheritDoc}
+ * @hide
*/
- public boolean connectInputDevice(BluetoothDevice device) {
- if (DBG) log("connectInputDevice(" + device + ")");
- try {
- return mService.connectInputDevice(device);
- } catch (RemoteException e) {
- Log.e(TAG, "", e);
- return false;
+ public boolean connect(BluetoothDevice device) {
+ if (DBG) log("connect(" + device + ")");
+ if (mService != null && isEnabled() &&
+ isValidDevice(device)) {
+ try {
+ return mService.connectInputDevice(device);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
+ return false;
+ }
}
+ if (mService == null) Log.w(TAG, "Proxy not attached to service");
+ return false;
}
- /** Initiate disconnect from an Input Device.
- * This function return false on error and true if the disconnection
- * attempt is being made.
- *
- * Listen for INPUT_DEVICE_STATE_CHANGED_ACTION to find out when
- * disconnect is completed.
- *
- * @param device Remote BT device.
- * @return false on immediate error, true otherwise
- * @hide
+ /**
+ * {@inheritDoc}
+ * @hide
*/
- public boolean disconnectInputDevice(BluetoothDevice device) {
- if (DBG) log("disconnectInputDevice(" + device + ")");
- try {
- return mService.disconnectInputDevice(device);
- } catch (RemoteException e) {
- Log.e(TAG, "", e);
- return false;
+ public boolean disconnect(BluetoothDevice device) {
+ if (DBG) log("disconnect(" + device + ")");
+ if (mService != null && isEnabled() &&
+ isValidDevice(device)) {
+ try {
+ return mService.disconnectInputDevice(device);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
+ return false;
+ }
}
+ if (mService == null) Log.w(TAG, "Proxy not attached to service");
+ return false;
}
- /** Check if a specified InputDevice is connected.
- *
- * @param device Remote BT device.
- * @return True if connected , false otherwise and on error.
- * @hide
+ /**
+ * {@inheritDoc}
*/
- public boolean isInputDeviceConnected(BluetoothDevice device) {
- if (DBG) log("isInputDeviceConnected(" + device + ")");
- int state = getInputDeviceState(device);
- if (state == STATE_CONNECTED) return true;
- return false;
+ public List<BluetoothDevice> getConnectedDevices() {
+ if (DBG) log("getConnectedDevices()");
+ if (mService != null && isEnabled()) {
+ try {
+ return mService.getConnectedInputDevices();
+ } catch (RemoteException e) {
+ Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
+ return new ArrayList<BluetoothDevice>();
+ }
+ }
+ if (mService == null) Log.w(TAG, "Proxy not attached to service");
+ return new ArrayList<BluetoothDevice>();
}
- /** Check if any Input Device is connected.
- *
- * @return List of devices, empty List on error.
- * @hide
+ /**
+ * {@inheritDoc}
*/
- public List<BluetoothDevice> getConnectedInputDevices() {
- if (DBG) log("getConnectedInputDevices()");
- try {
- return mService.getConnectedInputDevices();
- } catch (RemoteException e) {
- Log.e(TAG, "", e);
- return new ArrayList<BluetoothDevice>();
+ public List<BluetoothDevice> getDevicesMatchingConnectionStates(int[] states) {
+ if (DBG) log("getDevicesMatchingStates()");
+ if (mService != null && isEnabled()) {
+ try {
+ return mService.getInputDevicesMatchingConnectionStates(states);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
+ return new ArrayList<BluetoothDevice>();
+ }
}
+ if (mService == null) Log.w(TAG, "Proxy not attached to service");
+ return new ArrayList<BluetoothDevice>();
}
- /** Get the state of an Input Device.
- *
- * @param device Remote BT device.
- * @return The current state of the Input Device
- * @hide
+ /**
+ * {@inheritDoc}
*/
- public int getInputDeviceState(BluetoothDevice device) {
- if (DBG) log("getInputDeviceState(" + device + ")");
- try {
- return mService.getInputDeviceState(device);
- } catch (RemoteException e) {
- Log.e(TAG, "", e);
- return STATE_DISCONNECTED;
+ public int getConnectionState(BluetoothDevice device) {
+ if (DBG) log("getState(" + device + ")");
+ if (mService != null && isEnabled()
+ && isValidDevice(device)) {
+ try {
+ return mService.getInputDeviceConnectionState(device);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
+ return BluetoothProfile.STATE_DISCONNECTED;
+ }
}
+ if (mService == null) Log.w(TAG, "Proxy not attached to service");
+ return BluetoothProfile.STATE_DISCONNECTED;
}
/**
- * Set priority of an input device.
- *
- * Priority is a non-negative integer. Priority can take the following
- * values:
- * {@link PRIORITY_ON}, {@link PRIORITY_OFF}, {@link PRIORITY_AUTO_CONNECT}
- *
- * @param device Paired device.
- * @param priority Integer priority
- * @return true if priority is set, false on error
+ * {@inheritDoc}
+ * @hide
*/
- public boolean setInputDevicePriority(BluetoothDevice device, int priority) {
- if (DBG) log("setInputDevicePriority(" + device + ", " + priority + ")");
- try {
- return mService.setInputDevicePriority(device, priority);
- } catch (RemoteException e) {
- Log.e(TAG, "", e);
- return false;
+ public boolean setPriority(BluetoothDevice device, int priority) {
+ if (DBG) log("setPriority(" + device + ", " + priority + ")");
+ if (mService != null && isEnabled()
+ && isValidDevice(device)) {
+ if (priority != BluetoothProfile.PRIORITY_OFF &&
+ priority != BluetoothProfile.PRIORITY_ON) {
+ return false;
+ }
+ try {
+ return mService.setInputDevicePriority(device, priority);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
+ return false;
+ }
}
+ if (mService == null) Log.w(TAG, "Proxy not attached to service");
+ return false;
}
/**
- * Get the priority associated with an Input Device.
- *
- * @param device Input Device
- * @return non-negative priority, or negative error code on error.
+ * {@inheritDoc}
+ * @hide
*/
- public int getInputDevicePriority(BluetoothDevice device) {
- if (DBG) log("getInputDevicePriority(" + device + ")");
- try {
- return mService.getInputDevicePriority(device);
- } catch (RemoteException e) {
- Log.e(TAG, "", e);
- return PRIORITY_OFF;
+ public int getPriority(BluetoothDevice device) {
+ if (DBG) log("getPriority(" + device + ")");
+ if (mService != null && isEnabled()
+ && isValidDevice(device)) {
+ try {
+ return mService.getInputDevicePriority(device);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
+ return BluetoothProfile.PRIORITY_OFF;
+ }
}
+ if (mService == null) Log.w(TAG, "Proxy not attached to service");
+ return BluetoothProfile.PRIORITY_OFF;
+ }
+
+ private boolean isEnabled() {
+ if (mAdapter.getState() == BluetoothAdapter.STATE_ON) return true;
+ return false;
+ }
+
+ private boolean isValidDevice(BluetoothDevice device) {
+ if (device == null) return false;
+
+ if (BluetoothAdapter.checkBluetoothAddress(device.getAddress())) return true;
+ return false;
}
private static void log(String msg) {
- Log.d(TAG, msg);
+ Log.d(TAG, msg);
}
}
diff --git a/core/java/android/bluetooth/BluetoothPan.java b/core/java/android/bluetooth/BluetoothPan.java
index 1f07349..9ffed26 100644
--- a/core/java/android/bluetooth/BluetoothPan.java
+++ b/core/java/android/bluetooth/BluetoothPan.java
@@ -27,187 +27,261 @@ import android.util.Log;
import java.util.ArrayList;
import java.util.List;
+
/**
- * @hide
+ * This class provides the APIs to control the Bluetooth Pan
+ * Profile.
+ *
+ *<p>BluetoothPan is a proxy object for controlling the Bluetooth
+ * Service via IPC. Use {@link BluetoothAdapter#getProfileProxy} to get
+ * the BluetoothPan proxy object.
+ *
+ *<p>Each method is protected with its appropriate permission.
+ *@hide
*/
-public final class BluetoothPan {
+public final class BluetoothPan implements BluetoothProfile {
private static final String TAG = "BluetoothPan";
private static final boolean DBG = false;
- //TODO: This needs to inherit from BluetoothProfile like other profiles.
-
- /** int extra for ACTION_PAN_STATE_CHANGED */
- public static final String EXTRA_PAN_STATE = "android.bluetooth.pan.extra.STATE";
-
- /** int extra for ACTION_PAN_STATE_CHANGED */
- public static final String EXTRA_PREVIOUS_PAN_STATE =
- "android.bluetooth.pan.extra.PREVIOUS_STATE";
+ /**
+ * Intent used to broadcast the change in connection state of the Pan
+ * profile.
+ *
+ * <p>This intent will have 4 extras:
+ * <ul>
+ * <li> {@link #EXTRA_STATE} - The current state of the profile. </li>
+ * <li> {@link #EXTRA_PREVIOUS_STATE}- The previous state of the profile.</li>
+ * <li> {@link BluetoothDevice#EXTRA_DEVICE} - The remote device. </li>
+ * <li> {@link #EXTRA_LOCAL_ROLE} - Which local role the remote device is
+ * bound to. </li>
+ * </ul>
+ *
+ * <p>{@link #EXTRA_STATE} or {@link #EXTRA_PREVIOUS_STATE} can be any of
+ * {@link #STATE_DISCONNECTED}, {@link #STATE_CONNECTING},
+ * {@link #STATE_CONNECTED}, {@link #STATE_DISCONNECTING}.
+ *
+ * <p> {@link #EXTRA_LOCAL_ROLE} can be one of {@link #LOCAL_NAP_ROLE} or
+ * {@link #LOCAL_PANU_ROLE}
+ * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission to
+ * receive.
+ */
+ @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
+ public static final String ACTION_CONNECTION_STATE_CHANGED =
+ "android.bluetooth.pan.profile.action.CONNECTION_STATE_CHANGED";
- /** int extra for ACTION_PAN_STATE_CHANGED */
+ /**
+ * Extra for {@link #ACTION_CONNECTION_STATE_CHANGED} intent
+ * The local role of the PAN profile that the remote device is bound to.
+ * It can be one of {@link #LOCAL_NAP_ROLE} or {@link #LOCAL_PANU_ROLE}.
+ */
public static final String EXTRA_LOCAL_ROLE = "android.bluetooth.pan.extra.LOCAL_ROLE";
+ /**
+ * The local device is acting as a Network Access Point.
+ */
public static final int LOCAL_NAP_ROLE = 1;
- public static final int LOCAL_PANU_ROLE = 2;
/**
- * Indicates the state of an PAN device has changed.
- * This intent will always contain EXTRA_DEVICE_STATE,
- * EXTRA_PREVIOUS_DEVICE_STATE, BluetoothDevice.EXTRA_DEVICE
- * and EXTRA_LOCAL_ROLE.
- * extras.
+ * The local device is acting as a PAN User.
*/
- @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
- public static final String ACTION_PAN_STATE_CHANGED =
- "android.bluetooth.pan.action.STATE_CHANGED";
-
- public static final String NAP_ROLE = "nap";
- public static final String NAP_BRIDGE = "pan1";
-
- public static final int MAX_CONNECTIONS = 7;
-
- public static final int STATE_DISCONNECTED = 0;
- public static final int STATE_CONNECTING = 1;
- public static final int STATE_CONNECTED = 2;
- public static final int STATE_DISCONNECTING = 3;
+ public static final int LOCAL_PANU_ROLE = 2;
/**
* Return codes for the connect and disconnect Bluez / Dbus calls.
+ * @hide
*/
public static final int PAN_DISCONNECT_FAILED_NOT_CONNECTED = 1000;
+ /**
+ * @hide
+ */
public static final int PAN_CONNECT_FAILED_ALREADY_CONNECTED = 1001;
+ /**
+ * @hide
+ */
public static final int PAN_CONNECT_FAILED_ATTEMPT_FAILED = 1002;
+ /**
+ * @hide
+ */
public static final int PAN_OPERATION_GENERIC_FAILURE = 1003;
+ /**
+ * @hide
+ */
public static final int PAN_OPERATION_SUCCESS = 1004;
- private final IBluetooth mService;
- private final Context mContext;
+ private ServiceListener mServiceListener;
+ private BluetoothAdapter mAdapter;
+ private IBluetooth mService;
/**
* Create a BluetoothPan proxy object for interacting with the local
- * Bluetooth Pan service.
- * @param c Context
+ * Bluetooth Service which handles the Pan profile
+ *
*/
- public BluetoothPan(Context c) {
- mContext = c;
-
+ /*package*/ BluetoothPan(Context mContext, ServiceListener l) {
IBinder b = ServiceManager.getService(BluetoothAdapter.BLUETOOTH_SERVICE);
+ mServiceListener = l;
+ mAdapter = BluetoothAdapter.getDefaultAdapter();
if (b != null) {
mService = IBluetooth.Stub.asInterface(b);
+ if (mServiceListener != null) {
+ mServiceListener.onServiceConnected(BluetoothProfile.PAN, this);
+ }
} else {
Log.w(TAG, "Bluetooth Service not available!");
// Instead of throwing an exception which prevents people from going
- // into Wireless settings in the emulator. Let it crash later
- // when it is actually used.
+ // into Wireless settings in the emulator. Let it crash later when it is actually used.
mService = null;
}
}
/**
- * Initiate a PAN connection.
- *
- * This function returns false on error and true if the connection
- * attempt is being made.
- *
- * Listen for {@link #ACTION_PAN_STATE_CHANGED} to find out when the
- * connection is completed.
- *
- * @param device Remote BT device.
- * @return false on immediate error, true otherwise
+ * {@inheritDoc}
* @hide
*/
public boolean connect(BluetoothDevice device) {
if (DBG) log("connect(" + device + ")");
- try {
- return mService.connectPanDevice(device);
- } catch (RemoteException e) {
- Log.e(TAG, "", e);
- return false;
+ if (mService != null && isEnabled() &&
+ isValidDevice(device)) {
+ try {
+ return mService.connectPanDevice(device);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
+ return false;
+ }
}
+ if (mService == null) Log.w(TAG, "Proxy not attached to service");
+ return false;
}
/**
- * Initiate disconnect from PAN.
- *
- * This function return false on error and true if the disconnection
- * attempt is being made.
- *
- * Listen for {@link #ACTION_PAN_STATE_CHANGED} to find out when
- * disconnect is completed.
- *
- * @param device Remote BT device.
- * @return false on immediate error, true otherwise
+ * {@inheritDoc}
* @hide
*/
public boolean disconnect(BluetoothDevice device) {
if (DBG) log("disconnect(" + device + ")");
- try {
- return mService.disconnectPanDevice(device);
- } catch (RemoteException e) {
- Log.e(TAG, "", e);
- return false;
+ if (mService != null && isEnabled() &&
+ isValidDevice(device)) {
+ try {
+ return mService.disconnectPanDevice(device);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
+ return false;
+ }
}
+ if (mService == null) Log.w(TAG, "Proxy not attached to service");
+ return false;
}
/**
- * Get the state of a PAN Device.
- *
- * This function returns an int representing the state of the PAN connection
- *
- * @param device Remote BT device.
- * @return The current state of the PAN Device
- * @hide
+ * {@inheritDoc}
*/
- public int getPanDeviceState(BluetoothDevice device) {
- if (DBG) log("getPanDeviceState(" + device + ")");
- try {
- return mService.getPanDeviceState(device);
- } catch (RemoteException e) {
- Log.e(TAG, "", e);
- return STATE_DISCONNECTED;
+ public List<BluetoothDevice> getConnectedDevices() {
+ if (DBG) log("getConnectedDevices()");
+ if (mService != null && isEnabled()) {
+ try {
+ return mService.getConnectedPanDevices();
+ } catch (RemoteException e) {
+ Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
+ return new ArrayList<BluetoothDevice>();
+ }
}
+ if (mService == null) Log.w(TAG, "Proxy not attached to service");
+ return new ArrayList<BluetoothDevice>();
}
/**
- * Returns a set of all the connected PAN Devices
- *
- * Does not include devices that are currently connecting or disconnecting
- *
- * @return List of PAN devices or empty on Error
+ * {@inheritDoc}
+ */
+ public List<BluetoothDevice> getDevicesMatchingConnectionStates(int[] states) {
+ if (DBG) log("getDevicesMatchingStates()");
+ if (mService != null && isEnabled()) {
+ try {
+ return mService.getPanDevicesMatchingConnectionStates(states);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
+ return new ArrayList<BluetoothDevice>();
+ }
+ }
+ if (mService == null) Log.w(TAG, "Proxy not attached to service");
+ return new ArrayList<BluetoothDevice>();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public int getConnectionState(BluetoothDevice device) {
+ if (DBG) log("getState(" + device + ")");
+ if (mService != null && isEnabled()
+ && isValidDevice(device)) {
+ try {
+ return mService.getPanDeviceConnectionState(device);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
+ return BluetoothProfile.STATE_DISCONNECTED;
+ }
+ }
+ if (mService == null) Log.w(TAG, "Proxy not attached to service");
+ return BluetoothProfile.STATE_DISCONNECTED;
+ }
+
+ /**
+ * {@inheritDoc}
* @hide
*/
- public List<BluetoothDevice> getConnectedDevices() {
- if (DBG) log("getConnectedDevices");
- try {
- return mService.getConnectedPanDevices();
- } catch (RemoteException e) {
- Log.e(TAG, "", e);
- return new ArrayList<BluetoothDevice>();
- }
+ public boolean setPriority(BluetoothDevice device, int priority) {
+ // Priorities are not supported for PAN devices - since we don't
+ // auto connect.
+ return false;
}
- private static void log(String msg) {
- Log.d(TAG, msg);
+ /**
+ * {@inheritDoc}
+ * @hide
+ */
+ public int getPriority(BluetoothDevice device) {
+ if (DBG) log("getPriority(" + device + ")");
+ // Priorities are not supported for PAN devices - since we don't
+ // auto connect.
+ return BluetoothProfile.PRIORITY_ON;
}
public void setBluetoothTethering(boolean value) {
+ if (DBG) log("setBluetoothTethering(" + value + ")");
try {
mService.setBluetoothTethering(value);
} catch (RemoteException e) {
- Log.e(TAG, "", e);
+ Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
}
}
public boolean isTetheringOn() {
+ if (DBG) log("isTetheringOn()");
try {
return mService.isTetheringOn();
} catch (RemoteException e) {
- Log.e(TAG, "", e);
+ Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
return false;
}
}
-}
+
+ private boolean isEnabled() {
+ if (mAdapter.getState() == BluetoothAdapter.STATE_ON) return true;
+ return false;
+ }
+
+ private boolean isValidDevice(BluetoothDevice device) {
+ if (device == null) return false;
+
+ if (BluetoothAdapter.checkBluetoothAddress(device.getAddress())) return true;
+ return false;
+ }
+
+ private static void log(String msg) {
+ Log.d(TAG, msg);
+ }
+} \ No newline at end of file
diff --git a/core/java/android/bluetooth/BluetoothProfile.java b/core/java/android/bluetooth/BluetoothProfile.java
index ef80195..1ad66f7 100644
--- a/core/java/android/bluetooth/BluetoothProfile.java
+++ b/core/java/android/bluetooth/BluetoothProfile.java
@@ -58,12 +58,25 @@ public interface BluetoothProfile {
* Headset and Handsfree profile
*/
public static final int HEADSET = 1;
+
/**
* A2DP profile.
*/
public static final int A2DP = 2;
/**
+ * Input Device Profile
+ * @hide
+ */
+ public static final int INPUT_DEVICE = 3;
+
+ /**
+ * PAN Profile
+ * @hide
+ */
+ public static final int PAN = 4;
+
+ /**
* Default priority for devices that we try to auto-connect to and
* and allow incoming connections for the profile
* @hide
diff --git a/core/java/android/bluetooth/BluetoothProfileState.java b/core/java/android/bluetooth/BluetoothProfileState.java
index 3f36926..18060a0 100644
--- a/core/java/android/bluetooth/BluetoothProfileState.java
+++ b/core/java/android/bluetooth/BluetoothProfileState.java
@@ -72,10 +72,10 @@ public class BluetoothProfileState extends HierarchicalStateMachine {
newState == BluetoothProfile.STATE_DISCONNECTED)) {
sendMessage(TRANSITION_TO_STABLE);
}
- } else if (action.equals(BluetoothInputDevice.ACTION_INPUT_DEVICE_STATE_CHANGED)) {
- int newState = intent.getIntExtra(BluetoothInputDevice.EXTRA_INPUT_DEVICE_STATE, 0);
- if (mProfile == HID && (newState == BluetoothInputDevice.STATE_CONNECTED ||
- newState == BluetoothInputDevice.STATE_DISCONNECTED)) {
+ } else if (action.equals(BluetoothInputDevice.ACTION_CONNECTION_STATE_CHANGED)) {
+ int newState = intent.getIntExtra(BluetoothProfile.EXTRA_STATE, 0);
+ if (mProfile == HID && (newState == BluetoothProfile.STATE_CONNECTED ||
+ newState == BluetoothProfile.STATE_DISCONNECTED)) {
sendMessage(TRANSITION_TO_STABLE);
}
} else if (action.equals(BluetoothDevice.ACTION_ACL_DISCONNECTED)) {
@@ -96,7 +96,7 @@ public class BluetoothProfileState extends HierarchicalStateMachine {
IntentFilter filter = new IntentFilter();
filter.addAction(BluetoothA2dp.ACTION_CONNECTION_STATE_CHANGED);
filter.addAction(BluetoothHeadset.ACTION_CONNECTION_STATE_CHANGED);
- filter.addAction(BluetoothInputDevice.ACTION_INPUT_DEVICE_STATE_CHANGED);
+ filter.addAction(BluetoothInputDevice.ACTION_CONNECTION_STATE_CHANGED);
filter.addAction(BluetoothDevice.ACTION_ACL_DISCONNECTED);
context.registerReceiver(mBroadcastReceiver, filter);
}
diff --git a/core/java/android/bluetooth/BluetoothTetheringDataTracker.java b/core/java/android/bluetooth/BluetoothTetheringDataTracker.java
index aa1adcb..c08f14f 100644
--- a/core/java/android/bluetooth/BluetoothTetheringDataTracker.java
+++ b/core/java/android/bluetooth/BluetoothTetheringDataTracker.java
@@ -96,17 +96,32 @@ public class BluetoothTetheringDataTracker implements NetworkStateTracker {
public void startMonitoring(Context context, Handler target) {
mContext = context;
mCsHandler = target;
- mBluetoothPan = new BluetoothPan(mContext);
+ BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
+ if (adapter != null) {
+ adapter.getProfileProxy(mContext, mProfileServiceListener, BluetoothProfile.PAN);
+ }
}
+ private BluetoothProfile.ServiceListener mProfileServiceListener =
+ new BluetoothProfile.ServiceListener() {
+ public void onServiceConnected(int profile, BluetoothProfile proxy) {
+ mBluetoothPan = (BluetoothPan) proxy;
+ }
+ public void onServiceDisconnected(int profile) {
+ mBluetoothPan = null;
+ }
+ };
+
/**
* Disable connectivity to a network
* TODO: do away with return value after making MobileDataStateTracker async
*/
public boolean teardown() {
mTeardownRequested.set(true);
- for (BluetoothDevice device: mBluetoothPan.getConnectedDevices()) {
- mBluetoothPan.disconnect(device);
+ if (mBluetoothPan != null) {
+ for (BluetoothDevice device: mBluetoothPan.getConnectedDevices()) {
+ mBluetoothPan.disconnect(device);
+ }
}
return true;
}
diff --git a/core/java/android/bluetooth/IBluetooth.aidl b/core/java/android/bluetooth/IBluetooth.aidl
index f3e73cf..d25f5d0 100644
--- a/core/java/android/bluetooth/IBluetooth.aidl
+++ b/core/java/android/bluetooth/IBluetooth.aidl
@@ -85,14 +85,16 @@ interface IBluetooth
boolean connectInputDevice(in BluetoothDevice device);
boolean disconnectInputDevice(in BluetoothDevice device);
List<BluetoothDevice> getConnectedInputDevices();
- int getInputDeviceState(in BluetoothDevice device);
+ List<BluetoothDevice> getInputDevicesMatchingConnectionStates(in int[] states);
+ int getInputDeviceConnectionState(in BluetoothDevice device);
boolean setInputDevicePriority(in BluetoothDevice device, int priority);
int getInputDevicePriority(in BluetoothDevice device);
boolean isTetheringOn();
void setBluetoothTethering(boolean value);
- int getPanDeviceState(in BluetoothDevice device);
+ int getPanDeviceConnectionState(in BluetoothDevice device);
List<BluetoothDevice> getConnectedPanDevices();
+ List<BluetoothDevice> getPanDevicesMatchingConnectionStates(in int[] states);
boolean connectPanDevice(in BluetoothDevice device);
boolean disconnectPanDevice(in BluetoothDevice device);
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index 051ae9e..4c7d87f 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -1664,11 +1664,11 @@ public abstract class Context {
/**
* Use with {@link #getSystemService} to retrieve a {@link
- * android.hardware.UsbManager} for access to USB devices (as a USB host)
+ * android.hardware.usb.UsbManager} for access to USB devices (as a USB host)
* and for controlling this device's behavior as a USB device.
*
* @see #getSystemService
- * @see android.harware.UsbManager
+ * @see android.harware.usb.UsbManager
*/
public static final String USB_SERVICE = "usb";
diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java
index ce7f096..7bdd1b9 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -1312,6 +1312,17 @@ public class Intent implements Parcelable, Cloneable {
@SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
public static final String ACTION_PACKAGE_REPLACED = "android.intent.action.PACKAGE_REPLACED";
/**
+ * Broadcast Action: A new version of your application has been installed
+ * over an existing one. This is only sent to the application that was
+ * replaced. It does not contain any additional data; to receive it, just
+ * use an intent filter for this action.
+ *
+ * <p class="note">This is a protected intent that can only be sent
+ * by the system.
+ */
+ @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
+ public static final String ACTION_MY_PACKAGE_REPLACED = "android.intent.action.MY_PACKAGE_REPLACED";
+ /**
* Broadcast Action: An existing application package has been removed from
* the device. The data contains the name of the package. The package
* that is being installed does <em>not</em> receive this Intent.
@@ -1403,6 +1414,17 @@ public class Intent implements Parcelable, Cloneable {
public static final String ACTION_UID_REMOVED = "android.intent.action.UID_REMOVED";
/**
+ * Broadcast Action: Sent to the installer package of an application
+ * when that application is first launched (that is the first time it
+ * is moved out of the stopped state). The data contains the name of the package.
+ *
+ * <p class="note">This is a protected intent that can only be sent
+ * by the system.
+ */
+ @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
+ public static final String ACTION_PACKAGE_FIRST_LAUNCH = "android.intent.action.PACKAGE_FIRST_LAUNCH";
+
+ /**
* Broadcast Action: Resources for a set of packages (which were
* previously unavailable) are currently
* available since the media on which they exist is available.
@@ -2442,6 +2464,20 @@ public class Intent implements Parcelable, Cloneable {
* been found to create the final resolved list.
*/
public static final int FLAG_DEBUG_LOG_RESOLUTION = 0x00000008;
+ /**
+ * If set, this intent will not match any components in packages that
+ * are currently stopped. If this is not set, then the default behavior
+ * is to include such applications in the result.
+ */
+ public static final int FLAG_EXCLUDE_STOPPED_PACKAGES = 0x00000010;
+ /**
+ * If set, this intent will always match any components in packages that
+ * are currently stopped. This is the default behavior when
+ * {@link #FLAG_EXCLUDE_STOPPED_PACKAGES} is not set. If both of these
+ * flags are set, this one wins (it allows overriding of exclude for
+ * places where the framework may automatically set the exclude flag).
+ */
+ public static final int FLAG_INCLUDE_STOPPED_PACKAGES = 0x00000020;
/**
* If set, the new activity is not kept in the history stack. As soon as
@@ -3915,6 +3951,12 @@ public class Intent implements Parcelable, Cloneable {
return mFlags;
}
+ /** @hide */
+ public boolean isExcludingStopped() {
+ return (mFlags&(FLAG_EXCLUDE_STOPPED_PACKAGES|FLAG_INCLUDE_STOPPED_PACKAGES))
+ == FLAG_EXCLUDE_STOPPED_PACKAGES;
+ }
+
/**
* Retrieve the application package name this Intent is limited to. When
* resolving an Intent, if non-null this limits the resolution to only
diff --git a/core/java/android/content/IntentFilter.java b/core/java/android/content/IntentFilter.java
index 61d7424..06c1ecb 100644
--- a/core/java/android/content/IntentFilter.java
+++ b/core/java/android/content/IntentFilter.java
@@ -1094,7 +1094,7 @@ public class IntentFilter implements Parcelable {
*/
public final int match(String action, String type, String scheme,
Uri data, Set<String> categories, String logTag) {
- if (!matchAction(action)) {
+ if (action != null && !matchAction(action)) {
if (Config.LOGV) Log.v(
logTag, "No matching action " + action + " for " + this);
return NO_MATCH_ACTION;
diff --git a/core/java/android/content/pm/ApplicationInfo.java b/core/java/android/content/pm/ApplicationInfo.java
index 2d95781..92b2c3b 100644
--- a/core/java/android/content/pm/ApplicationInfo.java
+++ b/core/java/android/content/pm/ApplicationInfo.java
@@ -278,6 +278,12 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable {
public static final int FLAG_LARGE_HEAP = 1<<20;
/**
+ * Value for {@link #flags}: true if this application's package is in
+ * the stopped state.
+ */
+ public static final int FLAG_STOPPED = 1<<21;
+
+ /**
* Value for {@link #flags}: Set to true if the application has been
* installed using the forward lock option.
*
diff --git a/core/java/android/content/pm/IPackageDeleteObserver.aidl b/core/java/android/content/pm/IPackageDeleteObserver.aidl
index bc16b3e..2e2d16e 100644
--- a/core/java/android/content/pm/IPackageDeleteObserver.aidl
+++ b/core/java/android/content/pm/IPackageDeleteObserver.aidl
@@ -23,6 +23,6 @@ package android.content.pm;
* {@hide}
*/
oneway interface IPackageDeleteObserver {
- void packageDeleted(in boolean succeeded);
+ void packageDeleted(in String packageName, in int returnCode);
}
diff --git a/core/java/android/content/pm/IPackageManager.aidl b/core/java/android/content/pm/IPackageManager.aidl
index 034525e..fbf8f92 100644
--- a/core/java/android/content/pm/IPackageManager.aidl
+++ b/core/java/android/content/pm/IPackageManager.aidl
@@ -210,6 +210,12 @@ interface IPackageManager {
int getApplicationEnabledSetting(in String packageName);
/**
+ * Set whether the given package should be considered stopped, making
+ * it not visible to implicit intents that filter out stopped packages.
+ */
+ void setPackageStoppedState(String packageName, boolean stopped);
+
+ /**
* Free storage by deleting LRU sorted list of cache files across
* all applications. If the currently available free storage
* on the device is greater than or equal to the requested
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index a589216..fc07478 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -552,9 +552,38 @@ public abstract class PackageManager {
public static final int DONT_DELETE_DATA = 0x00000001;
/**
+ * Return code for when package deletion succeeds. This is passed to the
+ * {@link IPackageDeleteObserver} by {@link #deletePackage()} if the system
+ * succeeded in deleting the package.
+ *
+ * @hide
+ */
+ public static final int DELETE_SUCCEEDED = 1;
+
+ /**
+ * Deletion failed return code: this is passed to the
+ * {@link IPackageDeleteObserver} by {@link #deletePackage()} if the system
+ * failed to delete the package for an unspecified reason.
+ *
+ * @hide
+ */
+ public static final int DELETE_FAILED_INTERNAL_ERROR = -1;
+
+ /**
+ * Deletion failed return code: this is passed to the
+ * {@link IPackageDeleteObserver} by {@link #deletePackage()} if the system
+ * failed to delete the package because it is the active DevicePolicy
+ * manager.
+ *
+ * @hide
+ */
+ public static final int DELETE_FAILED_DEVICE_POLICY_MANAGER = -2;
+
+ /**
* Return code that is passed to the {@link IPackageMoveObserver} by
- * {@link #movePackage(android.net.Uri, IPackageMoveObserver)}
- * when the package has been successfully moved by the system.
+ * {@link #movePackage(android.net.Uri, IPackageMoveObserver)} when the
+ * package has been successfully moved by the system.
+ *
* @hide
*/
public static final int MOVE_SUCCEEDED = 1;
@@ -785,6 +814,21 @@ public abstract class PackageManager {
/**
* Feature for {@link #getSystemAvailableFeatures} and
+ * {@link #hasSystemFeature}: The device supports connecting to USB devices
+ * as the USB host.
+ */
+ @SdkConstant(SdkConstantType.FEATURE)
+ public static final String FEATURE_USB_HOST = "android.hardware.usb.host";
+
+ /**
+ * Feature for {@link #getSystemAvailableFeatures} and
+ * {@link #hasSystemFeature}: The device supports connecting to USB accessories.
+ */
+ @SdkConstant(SdkConstantType.FEATURE)
+ public static final String FEATURE_USB_ACCESSORY = "android.hardware.usb.accessory";
+
+ /**
+ * Feature for {@link #getSystemAvailableFeatures} and
* {@link #hasSystemFeature}: The SIP API is enabled on the device.
*/
@SdkConstant(SdkConstantType.FEATURE)
diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java
index 7676258..7ebfda4 100644
--- a/core/java/android/content/pm/PackageParser.java
+++ b/core/java/android/content/pm/PackageParser.java
@@ -2817,6 +2817,9 @@ public class PackageParser {
// User set enabled state.
public int mSetEnabled = PackageManager.COMPONENT_ENABLED_STATE_DEFAULT;
+ // Whether the package has been stopped.
+ public boolean mSetStopped = false;
+
// Additional data supplied by callers.
public Object mExtras;
@@ -3071,6 +3074,11 @@ public class PackageParser {
if (!sCompatibilityModeEnabled) {
p.applicationInfo.disableCompatibilityMode();
}
+ if (p.mSetStopped) {
+ p.applicationInfo.flags |= ApplicationInfo.FLAG_STOPPED;
+ } else {
+ p.applicationInfo.flags &= ~ApplicationInfo.FLAG_STOPPED;
+ }
return p.applicationInfo;
}
@@ -3085,6 +3093,11 @@ public class PackageParser {
if (!sCompatibilityModeEnabled) {
ai.disableCompatibilityMode();
}
+ if (p.mSetStopped) {
+ p.applicationInfo.flags |= ApplicationInfo.FLAG_STOPPED;
+ } else {
+ p.applicationInfo.flags &= ~ApplicationInfo.FLAG_STOPPED;
+ }
if (p.mSetEnabled == PackageManager.COMPONENT_ENABLED_STATE_ENABLED) {
ai.enabled = true;
} else if (p.mSetEnabled == PackageManager.COMPONENT_ENABLED_STATE_DISABLED) {
diff --git a/core/java/android/content/res/Resources.java b/core/java/android/content/res/Resources.java
index 85f64d0..81eb09c 100755
--- a/core/java/android/content/res/Resources.java
+++ b/core/java/android/content/res/Resources.java
@@ -115,7 +115,7 @@ public class Resources {
private CompatibilityInfo mCompatibilityInfo;
private Display mDefaultDisplay;
- private static final LongSparseArray<Object> EMPTY_ARRAY = new LongSparseArray<Object>() {
+ private static final LongSparseArray<Object> EMPTY_ARRAY = new LongSparseArray<Object>(0) {
@Override
public void put(long k, Object o) {
throw new UnsupportedOperationException();
diff --git a/core/java/android/database/AbstractWindowedCursor.java b/core/java/android/database/AbstractWindowedCursor.java
index 8addaa8..3d95769 100644
--- a/core/java/android/database/AbstractWindowedCursor.java
+++ b/core/java/android/database/AbstractWindowedCursor.java
@@ -117,7 +117,8 @@ public abstract class AbstractWindowedCursor extends AbstractCursor {
super.checkPosition();
if (mWindow == null) {
- throw new StaleDataException("Attempting to access a closed cursor");
+ throw new StaleDataException("Attempting to access a closed CursorWindow." +
+ "Most probable cause: cursor is deactivated prior to calling this method.");
}
}
diff --git a/core/java/android/database/CursorWindow.java b/core/java/android/database/CursorWindow.java
index bd78063..f7cbf7a 100644
--- a/core/java/android/database/CursorWindow.java
+++ b/core/java/android/database/CursorWindow.java
@@ -17,14 +17,12 @@
package android.database;
import android.content.res.Resources;
-import android.database.sqlite.DatabaseObjectNotClosedException;
import android.database.sqlite.SQLiteClosable;
import android.os.Binder;
import android.os.IBinder;
import android.os.Parcel;
import android.os.Parcelable;
import android.os.Process;
-import android.os.StrictMode;
import android.util.Log;
import android.util.SparseIntArray;
@@ -47,7 +45,6 @@ public class CursorWindow extends SQLiteClosable implements Parcelable {
private int nWindow;
private int mStartPos;
- private final Throwable mStackTrace;
/**
* Creates a new empty window.
@@ -59,7 +56,6 @@ public class CursorWindow extends SQLiteClosable implements Parcelable {
int rslt = native_init(sCursorWindowSize, localWindow);
printDebugMsgIfError(rslt);
recordNewWindow(Binder.getCallingPid(), nWindow);
- mStackTrace = new DatabaseObjectNotClosedException().fillInStackTrace();
}
private void printDebugMsgIfError(int rslt) {
@@ -568,12 +564,9 @@ public class CursorWindow extends SQLiteClosable implements Parcelable {
if (nWindow == 0) {
return;
}
- if (StrictMode.vmSqliteObjectLeaksEnabled()) {
- StrictMode.onSqliteObjectLeaked(
- "Releasing cursor in a finalizer. Please ensure " +
- "that you explicitly call close() on your cursor: ",
- mStackTrace);
- }
+ // due to bugs 3329504, 3502276, cursorwindow sometimes is closed in fialize()
+ // don't print any warning saying "don't release cursor in finzlize"
+ // because it is a bug in framework code - NOT an app bug.
recordClosingOfWindow(nWindow);
close_native();
}
@@ -606,7 +599,6 @@ public class CursorWindow extends SQLiteClosable implements Parcelable {
IBinder nativeBinder = source.readStrongBinder();
mStartPos = source.readInt();
int rslt = native_init(nativeBinder);
- mStackTrace = new DatabaseObjectNotClosedException().fillInStackTrace();
printDebugMsgIfError(rslt);
}
diff --git a/core/java/android/database/sqlite/SQLiteDatabase.java b/core/java/android/database/sqlite/SQLiteDatabase.java
index 2e43eef..90a5b5d 100644
--- a/core/java/android/database/sqlite/SQLiteDatabase.java
+++ b/core/java/android/database/sqlite/SQLiteDatabase.java
@@ -2218,9 +2218,10 @@ public class SQLiteDatabase extends SQLiteClosable {
}
mCompiledQueries = new LruCache<String, SQLiteCompiledSql>(cacheSize) {
@Override
- protected void entryEvicted(String key, SQLiteCompiledSql value) {
+ protected void entryRemoved(boolean evicted, String key, SQLiteCompiledSql oldValue,
+ SQLiteCompiledSql newValue) {
verifyLockOwner();
- value.releaseIfNotInUse();
+ oldValue.releaseIfNotInUse();
}
};
if (oldCompiledQueries != null) {
diff --git a/core/java/android/hardware/Camera.java b/core/java/android/hardware/Camera.java
index c2f3ae7..97f0e1b 100644
--- a/core/java/android/hardware/Camera.java
+++ b/core/java/android/hardware/Camera.java
@@ -508,23 +508,86 @@ public class Camera {
* finish processing the data in them.
*
* <p>The size of the buffer is determined by multiplying the preview
- * image width, height, and bytes per pixel. The width and height can be
- * read from {@link Camera.Parameters#getPreviewSize()}. Bytes per pixel
+ * image width, height, and bytes per pixel. The width and height can be
+ * read from {@link Camera.Parameters#getPreviewSize()}. Bytes per pixel
* can be computed from
* {@link android.graphics.ImageFormat#getBitsPerPixel(int)} / 8,
* using the image format from {@link Camera.Parameters#getPreviewFormat()}.
*
* <p>This method is only necessary when
- * {@link #setPreviewCallbackWithBuffer(PreviewCallback)} is used. When
+ * {@link #setPreviewCallbackWithBuffer(PreviewCallback)} is used. When
* {@link #setPreviewCallback(PreviewCallback)} or
* {@link #setOneShotPreviewCallback(PreviewCallback)} are used, buffers
- * are automatically allocated.
+ * are automatically allocated. When a supplied buffer is too small to
+ * hold the preview frame data, preview callback will return null and
+ * the buffer will be removed from the buffer queue.
*
* @param callbackBuffer the buffer to add to the queue.
* The size should be width * height * bits_per_pixel / 8.
* @see #setPreviewCallbackWithBuffer(PreviewCallback)
*/
- public native final void addCallbackBuffer(byte[] callbackBuffer);
+ public final void addCallbackBuffer(byte[] callbackBuffer)
+ {
+ _addCallbackBuffer(callbackBuffer, CAMERA_MSG_PREVIEW_FRAME);
+ }
+
+ /**
+ * Adds a pre-allocated buffer to the raw image callback buffer queue.
+ * Applications can add one or more buffers to the queue. When a raw image
+ * frame arrives and there is still at least one available buffer, the
+ * buffer will be used to hold the raw image data and removed from the
+ * queue. Then raw image callback is invoked with the buffer. If a raw
+ * image frame arrives but there is no buffer left, the frame is
+ * discarded. Applications should add buffers back when they finish
+ * processing the data in them by calling this method again in order
+ * to avoid running out of raw image callback buffers.
+ *
+ * <p>The size of the buffer is determined by multiplying the raw image
+ * width, height, and bytes per pixel. The width and height can be
+ * read from {@link Camera.Parameters#getPictureSize()}. Bytes per pixel
+ * can be computed from
+ * {@link android.graphics.ImageFormat#getBitsPerPixel(int)} / 8,
+ * using the image format from {@link Camera.Parameters#getPreviewFormat()}.
+ *
+ * <p>This method is only necessary when the PictureCallbck for raw image
+ * is used while calling {@link #takePicture(Camera.ShutterCallback,
+ * Camera.PictureCallback, Camera.PictureCallback, Camera.PictureCallback)}.
+ *
+ * Please note that by calling this method, the mode for application-managed
+ * callback buffers is triggered. If this method has never been called,
+ * null will be returned by the raw image callback since there is
+ * no image callback buffer available. Furthermore, When a supplied buffer
+ * is too small to hold the raw image data, raw image callback will return
+ * null and the buffer will be removed from the buffer queue.
+ *
+ * @param callbackBuffer the buffer to add to the raw image callback buffer
+ * queue. The size should be width * height * (bits per pixel) / 8. An
+ * null callbackBuffer will be ignored and won't be added to the queue.
+ *
+ * @see #takePicture(Camera.ShutterCallback,
+ * Camera.PictureCallback, Camera.PictureCallback, Camera.PictureCallback)}.
+ *
+ * {@hide}
+ */
+ public final void addRawImageCallbackBuffer(byte[] callbackBuffer)
+ {
+ addCallbackBuffer(callbackBuffer, CAMERA_MSG_RAW_IMAGE);
+ }
+
+ private final void addCallbackBuffer(byte[] callbackBuffer, int msgType)
+ {
+ // CAMERA_MSG_VIDEO_FRAME may be allowed in the future.
+ if (msgType != CAMERA_MSG_PREVIEW_FRAME &&
+ msgType != CAMERA_MSG_RAW_IMAGE) {
+ throw new IllegalArgumentException(
+ "Unsupported message type: " + msgType);
+ }
+
+ _addCallbackBuffer(callbackBuffer, msgType);
+ }
+
+ private native final void _addCallbackBuffer(
+ byte[] callbackBuffer, int msgType);
private class EventHandler extends Handler
{
@@ -735,7 +798,7 @@ public class Camera {
PictureCallback jpeg) {
takePicture(shutter, raw, null, jpeg);
}
- private native final void native_takePicture();
+ private native final void native_takePicture(int msgType);
/**
* Triggers an asynchronous image capture. The camera service will initiate
@@ -743,7 +806,8 @@ public class Camera {
* The shutter callback occurs after the image is captured. This can be used
* to trigger a sound to let the user know that image has been captured. The
* raw callback occurs when the raw image data is available (NOTE: the data
- * may be null if the hardware does not have enough memory to make a copy).
+ * will be null if there is no raw image callback buffer available or the
+ * raw image callback buffer is not large enough to hold the raw image).
* The postview callback occurs when a scaled, fully processed postview
* image is available (NOTE: not all hardware supports this). The jpeg
* callback occurs when the compressed image is available. If the
@@ -762,6 +826,8 @@ public class Camera {
* @param raw the callback for raw (uncompressed) image data, or null
* @param postview callback with postview image data, may be null
* @param jpeg the callback for JPEG image data, or null
+ *
+ * @see #addRawImageCallbackBuffer(byte[])
*/
public final void takePicture(ShutterCallback shutter, PictureCallback raw,
PictureCallback postview, PictureCallback jpeg) {
@@ -769,7 +835,23 @@ public class Camera {
mRawImageCallback = raw;
mPostviewCallback = postview;
mJpegCallback = jpeg;
- native_takePicture();
+
+ // If callback is not set, do not send me callbacks.
+ int msgType = 0;
+ if (mShutterCallback != null) {
+ msgType |= CAMERA_MSG_SHUTTER;
+ }
+ if (mRawImageCallback != null) {
+ msgType |= CAMERA_MSG_RAW_IMAGE;
+ }
+ if (mPostviewCallback != null) {
+ msgType |= CAMERA_MSG_POSTVIEW_FRAME;
+ }
+ if (mJpegCallback != null) {
+ msgType |= CAMERA_MSG_COMPRESSED_IMAGE;
+ }
+
+ native_takePicture(msgType);
}
/**
@@ -1280,6 +1362,7 @@ public class Camera {
private static final String PIXEL_FORMAT_YUV422SP = "yuv422sp";
private static final String PIXEL_FORMAT_YUV420SP = "yuv420sp";
private static final String PIXEL_FORMAT_YUV422I = "yuv422i-yuyv";
+ private static final String PIXEL_FORMAT_YUV420P = "yuv420p";
private static final String PIXEL_FORMAT_RGB565 = "rgb565";
private static final String PIXEL_FORMAT_JPEG = "jpeg";
@@ -1693,7 +1776,9 @@ public class Camera {
}
/**
- * Gets the supported preview formats.
+ * Gets the supported preview formats. {@link android.graphics.ImageFormat#NV21}
+ * is always supported. {@link android.graphics.ImageFormat#YV12}
+ * is always supported since API level 12.
*
* @return a list of supported preview formats. This method will always
* return a list with at least one element.
@@ -1800,6 +1885,7 @@ public class Camera {
case ImageFormat.NV16: return PIXEL_FORMAT_YUV422SP;
case ImageFormat.NV21: return PIXEL_FORMAT_YUV420SP;
case ImageFormat.YUY2: return PIXEL_FORMAT_YUV422I;
+ case ImageFormat.YV12: return PIXEL_FORMAT_YUV420P;
case ImageFormat.RGB_565: return PIXEL_FORMAT_RGB565;
case ImageFormat.JPEG: return PIXEL_FORMAT_JPEG;
default: return null;
@@ -1819,6 +1905,9 @@ public class Camera {
if (format.equals(PIXEL_FORMAT_YUV422I))
return ImageFormat.YUY2;
+ if (format.equals(PIXEL_FORMAT_YUV420P))
+ return ImageFormat.YV12;
+
if (format.equals(PIXEL_FORMAT_RGB565))
return ImageFormat.RGB_565;
diff --git a/core/java/android/hardware/IUsbManager.aidl b/core/java/android/hardware/IUsbManager.aidl
deleted file mode 100644
index 6c99ab3..0000000
--- a/core/java/android/hardware/IUsbManager.aidl
+++ /dev/null
@@ -1,31 +0,0 @@
-/*
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.hardware;
-
-import android.hardware.UsbAccessory;
-import android.os.Bundle;
-import android.os.ParcelFileDescriptor;
-
-/** @hide */
-interface IUsbManager
-{
- /* Returns a list of all currently attached USB devices */
- void getDeviceList(out Bundle devices);
- ParcelFileDescriptor openDevice(String deviceName);
- UsbAccessory getCurrentAccessory();
- ParcelFileDescriptor openAccessory();
-}
diff --git a/core/java/android/hardware/SensorEvent.java b/core/java/android/hardware/SensorEvent.java
index 8c55bf3..78d7991 100644
--- a/core/java/android/hardware/SensorEvent.java
+++ b/core/java/android/hardware/SensorEvent.java
@@ -122,13 +122,13 @@ public class SensorEvent {
*
* final float alpha = 0.8;
*
- * gravity[0] = alpha * gravity[0] + (1 - alpha) * event.data[0];
- * gravity[1] = alpha * gravity[1] + (1 - alpha) * event.data[1];
- * gravity[2] = alpha * gravity[2] + (1 - alpha) * event.data[2];
+ * gravity[0] = alpha * gravity[0] + (1 - alpha) * event.values[0];
+ * gravity[1] = alpha * gravity[1] + (1 - alpha) * event.values[1];
+ * gravity[2] = alpha * gravity[2] + (1 - alpha) * event.values[2];
*
- * linear_acceleration[0] = event.data[0] - gravity[0];
- * linear_acceleration[1] = event.data[1] - gravity[1];
- * linear_acceleration[2] = event.data[2] - gravity[2];
+ * linear_acceleration[0] = event.values[0] - gravity[0];
+ * linear_acceleration[1] = event.values[1] - gravity[1];
+ * linear_acceleration[2] = event.values[2] - gravity[2];
* }
* </pre>
*
@@ -186,9 +186,9 @@ public class SensorEvent {
* {
* if (timestamp != 0) {
* final float dT = (event.timestamp - timestamp) * NS2S;
- * angle[0] += event.data[0] * dT;
- * angle[1] += event.data[1] * dT;
- * angle[2] += event.data[2] * dT;
+ * angle[0] += event.values[0] * dT;
+ * angle[1] += event.values[1] * dT;
+ * angle[2] += event.values[2] * dT;
* }
* timestamp = event.timestamp;
* }
diff --git a/core/java/android/hardware/usb/IUsbManager.aidl b/core/java/android/hardware/usb/IUsbManager.aidl
new file mode 100644
index 0000000..be65bdb
--- /dev/null
+++ b/core/java/android/hardware/usb/IUsbManager.aidl
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.usb;
+
+import android.hardware.usb.UsbAccessory;
+import android.hardware.usb.UsbDevice;
+import android.os.Bundle;
+import android.os.ParcelFileDescriptor;
+
+/** @hide */
+interface IUsbManager
+{
+ /* Returns a list of all currently attached USB devices */
+ void getDeviceList(out Bundle devices);
+
+ /* Returns a file descriptor for communicating with the USB device.
+ * The native fd can be passed to usb_device_new() in libusbhost.
+ */
+ ParcelFileDescriptor openDevice(String deviceName);
+
+ /* Returns the currently attached USB accessory */
+ UsbAccessory getCurrentAccessory();
+
+ /* Returns a file descriptor for communicating with the USB accessory.
+ * This file descriptor can be used with standard Java file operations.
+ */
+ ParcelFileDescriptor openAccessory(in UsbAccessory accessory);
+
+ /* Sets the default package for a USB device
+ * (or clears it if the package name is null)
+ */
+ oneway void setDevicePackage(in UsbDevice device, String packageName);
+
+ /* Sets the default package for a USB device
+ * (or clears it if the package name is null)
+ */
+ void setAccessoryPackage(in UsbAccessory accessory, String packageName);
+
+ /* Grants permission for the given UID to access the device */
+ void grantDevicePermission(in UsbDevice device, int uid);
+
+ /* Grants permission for the given UID to access the accessory */
+ void grantAccessoryPermission(in UsbAccessory accessory, int uid);
+
+ /* Returns true if the USB manager has default preferences or permissions for the package */
+ boolean hasDefaults(String packageName, int uid);
+
+ /* Clears default preferences and permissions for the package */
+ oneway void clearDefaults(String packageName, int uid);
+}
diff --git a/core/java/android/hardware/UsbAccessory.aidl b/core/java/android/hardware/usb/UsbAccessory.aidl
index 97a777b..1c15f1c 100644
--- a/core/java/android/hardware/UsbAccessory.aidl
+++ b/core/java/android/hardware/usb/UsbAccessory.aidl
@@ -14,6 +14,6 @@
* limitations under the License.
*/
-package android.hardware;
+package android.hardware.usb;
parcelable UsbAccessory;
diff --git a/core/java/android/hardware/UsbAccessory.java b/core/java/android/hardware/usb/UsbAccessory.java
index 71672fa..6cd9178 100644
--- a/core/java/android/hardware/UsbAccessory.java
+++ b/core/java/android/hardware/usb/UsbAccessory.java
@@ -14,28 +14,24 @@
* limitations under the License.
*/
-package android.hardware;
+package android.hardware.usb;
import android.os.Bundle;
import android.os.Parcel;
import android.os.Parcelable;
-import android.os.ParcelFileDescriptor;
import android.util.Log;
/**
* A class representing a USB accessory.
*/
-public final class UsbAccessory implements Parcelable {
+public class UsbAccessory implements Parcelable {
private static final String TAG = "UsbAccessory";
- private String mManufacturer;
- private String mModel;
- private String mType;
- private String mVersion;
-
- private UsbAccessory() {
- }
+ private final String mManufacturer;
+ private final String mModel;
+ private final String mType;
+ private final String mVersion;
/**
* UsbAccessory should only be instantiated by UsbService implementation
@@ -95,6 +91,23 @@ public final class UsbAccessory implements Parcelable {
return mVersion;
}
+ private static boolean compare(String s1, String s2) {
+ if (s1 == null) return (s2 == null);
+ return s1.equals(s2);
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (obj instanceof UsbAccessory) {
+ UsbAccessory accessory = (UsbAccessory)obj;
+ return (compare(mManufacturer, accessory.getManufacturer()) &&
+ compare(mModel, accessory.getModel()) &&
+ compare(mType, accessory.getType()) &&
+ compare(mVersion, accessory.getVersion()));
+ }
+ return false;
+ }
+
@Override
public String toString() {
return "UsbAccessory[mManufacturer=" + mManufacturer +
diff --git a/core/java/android/hardware/UsbConstants.java b/core/java/android/hardware/usb/UsbConstants.java
index 4c8c4d4..6626c9f 100644
--- a/core/java/android/hardware/UsbConstants.java
+++ b/core/java/android/hardware/usb/UsbConstants.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package android.hardware;
+package android.hardware.usb;
/**
* Contains constants for the USB protocol.
diff --git a/core/java/android/hardware/UsbDevice.aidl b/core/java/android/hardware/usb/UsbDevice.aidl
index 6dfd43f..6030ad1 100644
--- a/core/java/android/hardware/UsbDevice.aidl
+++ b/core/java/android/hardware/usb/UsbDevice.aidl
@@ -14,6 +14,6 @@
* limitations under the License.
*/
-package android.hardware;
+package android.hardware.usb;
parcelable UsbDevice;
diff --git a/core/java/android/hardware/UsbDevice.java b/core/java/android/hardware/usb/UsbDevice.java
index ca7dae3..37bd82b 100644
--- a/core/java/android/hardware/UsbDevice.java
+++ b/core/java/android/hardware/usb/UsbDevice.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package android.hardware;
+package android.hardware.usb;
import android.os.Bundle;
import android.os.Parcel;
@@ -106,7 +106,7 @@ public final class UsbDevice implements Parcelable {
/**
* Returns the devices's class field.
* Some useful constants for USB device classes can be found in
- * {@link android.hardware.UsbConstants}
+ * {@link android.hardware.usb.UsbConstants}
*
* @return the devices's class
*/
@@ -133,7 +133,7 @@ public final class UsbDevice implements Parcelable {
}
/**
- * Returns the number of {@link android.hardware.UsbInterface}s this device contains.
+ * Returns the number of {@link android.hardware.usb.UsbInterface}s this device contains.
*
* @return the number of interfaces
*/
@@ -142,7 +142,7 @@ public final class UsbDevice implements Parcelable {
}
/**
- * Returns the {@link android.hardware.UsbInterface} at the given index.
+ * Returns the {@link android.hardware.usb.UsbInterface} at the given index.
*
* @return the interface
*/
@@ -171,9 +171,9 @@ public final class UsbDevice implements Parcelable {
}
/**
- * Claims exclusive access to a {@link android.hardware.UsbInterface}.
+ * Claims exclusive access to a {@link android.hardware.usb.UsbInterface}.
* This must be done before sending or receiving data on any
- * {@link android.hardware.UsbEndpoint}s belonging to the interface
+ * {@link android.hardware.usb.UsbEndpoint}s belonging to the interface
* @param intf the interface to claim
* @param force true to disconnect kernel driver if necessary
* @return true if the interface was successfully claimed
@@ -183,7 +183,7 @@ public final class UsbDevice implements Parcelable {
}
/**
- * Releases exclusive access to a {@link android.hardware.UsbInterface}.
+ * Releases exclusive access to a {@link android.hardware.usb.UsbInterface}.
*
* @return true if the interface was successfully released
*/
@@ -231,11 +231,12 @@ public final class UsbDevice implements Parcelable {
}
/**
- * Waits for the result of a {@link android.hardware.UsbRequest#queue} operation
- * Note that this may return requests queued on multiple {@link android.hardware.UsbEndpoint}s.
- * When multiple endpoints are in use, {@link android.hardware.UsbRequest#getEndpoint} and
- * {@link android.hardware.UsbRequest#getClientData} can be useful in determining how to process
- * the result of this function.
+ * Waits for the result of a {@link android.hardware.usb.UsbRequest#queue} operation
+ * Note that this may return requests queued on multiple
+ * {@link android.hardware.usb.UsbEndpoint}s.
+ * When multiple endpoints are in use, {@link android.hardware.usb.UsbRequest#getEndpoint} and
+ * {@link android.hardware.usb.UsbRequest#getClientData} can be useful in determining
+ * how to process the result of this function.
*
* @return a completed USB request, or null if an error occurred
*/
diff --git a/core/java/android/hardware/UsbEndpoint.aidl b/core/java/android/hardware/usb/UsbEndpoint.aidl
index 51fc67b..a75cd7e 100644
--- a/core/java/android/hardware/UsbEndpoint.aidl
+++ b/core/java/android/hardware/usb/UsbEndpoint.aidl
@@ -14,6 +14,6 @@
* limitations under the License.
*/
-package android.hardware;
+package android.hardware.usb;
parcelable UsbEndpoint;
diff --git a/core/java/android/hardware/UsbEndpoint.java b/core/java/android/hardware/usb/UsbEndpoint.java
index 8d4099d..a48d88f 100644
--- a/core/java/android/hardware/UsbEndpoint.java
+++ b/core/java/android/hardware/usb/UsbEndpoint.java
@@ -14,14 +14,14 @@
* limitations under the License.
*/
-package android.hardware;
+package android.hardware.usb;
import android.os.Bundle;
import android.os.Parcel;
import android.os.Parcelable;
/**
- * A class representing an endpoint on a {@link android.hardware.UsbInterface}.
+ * A class representing an endpoint on a {@link android.hardware.usb.UsbInterface}.
*/
public final class UsbEndpoint implements Parcelable {
@@ -65,9 +65,9 @@ public final class UsbEndpoint implements Parcelable {
/**
* Returns the endpoint's direction.
- * Returns {@link android.hardware.UsbConstants#USB_DIR_OUT}
+ * Returns {@link android.hardware.usb.UsbConstants#USB_DIR_OUT}
* if the direction is host to device, and
- * {@link android.hardware.UsbConstants#USB_DIR_IN} if the
+ * {@link android.hardware.usb.UsbConstants#USB_DIR_IN} if the
* direction is device to host.
*
* @return the endpoint's direction
@@ -89,10 +89,10 @@ public final class UsbEndpoint implements Parcelable {
* Returns the endpoint's type.
* Possible results are:
* <ul>
- * <li>{@link android.hardware.UsbConstants#USB_ENDPOINT_XFER_CONTROL} (endpoint zero)
- * <li>{@link android.hardware.UsbConstants#USB_ENDPOINT_XFER_ISOC} (isochronous endpoint)
- * <li>{@link android.hardware.UsbConstants#USB_ENDPOINT_XFER_BULK} (bulk endpoint)
- * <li>{@link android.hardware.UsbConstants#USB_ENDPOINT_XFER_INT} (interrupt endpoint)
+ * <li>{@link android.hardware.usb.UsbConstants#USB_ENDPOINT_XFER_CONTROL} (endpoint zero)
+ * <li>{@link android.hardware.usb.UsbConstants#USB_ENDPOINT_XFER_ISOC} (isochronous endpoint)
+ * <li>{@link android.hardware.usb.UsbConstants#USB_ENDPOINT_XFER_BULK} (bulk endpoint)
+ * <li>{@link android.hardware.usb.UsbConstants#USB_ENDPOINT_XFER_INT} (interrupt endpoint)
* </ul>
*
* @return the endpoint's type
@@ -120,7 +120,7 @@ public final class UsbEndpoint implements Parcelable {
}
/**
- * Returns the {@link android.hardware.UsbInterface} this endpoint belongs to.
+ * Returns the {@link android.hardware.usb.UsbInterface} this endpoint belongs to.
*
* @return the endpoint's interface
*/
@@ -129,7 +129,7 @@ public final class UsbEndpoint implements Parcelable {
}
/**
- * Returns the {@link android.hardware.UsbDevice} this endpoint belongs to.
+ * Returns the {@link android.hardware.usb.UsbDevice} this endpoint belongs to.
*
* @return the endpoint's device
*/
diff --git a/core/java/android/hardware/UsbInterface.aidl b/core/java/android/hardware/usb/UsbInterface.aidl
index a715ccd..32b8c64 100644
--- a/core/java/android/hardware/UsbInterface.aidl
+++ b/core/java/android/hardware/usb/UsbInterface.aidl
@@ -14,6 +14,6 @@
* limitations under the License.
*/
-package android.hardware;
+package android.hardware.usb;
parcelable UsbInterface;
diff --git a/core/java/android/hardware/UsbInterface.java b/core/java/android/hardware/usb/UsbInterface.java
index deef81f..b3b0e81 100644
--- a/core/java/android/hardware/UsbInterface.java
+++ b/core/java/android/hardware/usb/UsbInterface.java
@@ -14,16 +14,16 @@
* limitations under the License.
*/
-package android.hardware;
+package android.hardware.usb;
import android.os.Bundle;
import android.os.Parcel;
import android.os.Parcelable;
/**
- * A class representing an interface on a {@link android.hardware.UsbDevice}.
+ * A class representing an interface on a {@link android.hardware.usb.UsbDevice}.
*/
-public final class UsbInterface implements Parcelable {
+public class UsbInterface implements Parcelable {
private int mId;
private int mClass;
@@ -60,7 +60,7 @@ public final class UsbInterface implements Parcelable {
/**
* Returns the interface's class field.
* Some useful constants for USB classes can be found in
- * {@link android.hardware.UsbConstants}
+ * {@link android.hardware.usb.UsbConstants}
*
* @return the interface's class
*/
@@ -87,7 +87,7 @@ public final class UsbInterface implements Parcelable {
}
/**
- * Returns the number of {@link android.hardware.UsbEndpoint}s this interface contains.
+ * Returns the number of {@link android.hardware.usb.UsbEndpoint}s this interface contains.
*
* @return the number of endpoints
*/
@@ -96,7 +96,7 @@ public final class UsbInterface implements Parcelable {
}
/**
- * Returns the {@link android.hardware.UsbEndpoint} at the given index.
+ * Returns the {@link android.hardware.usb.UsbEndpoint} at the given index.
*
* @return the endpoint
*/
@@ -105,7 +105,7 @@ public final class UsbInterface implements Parcelable {
}
/**
- * Returns the {@link android.hardware.UsbDevice} this interface belongs to.
+ * Returns the {@link android.hardware.usb.UsbDevice} this interface belongs to.
*
* @return the interface's device
*/
diff --git a/core/java/android/hardware/UsbManager.java b/core/java/android/hardware/usb/UsbManager.java
index 0f616ff..6683179 100644
--- a/core/java/android/hardware/UsbManager.java
+++ b/core/java/android/hardware/usb/UsbManager.java
@@ -15,7 +15,7 @@
*/
-package android.hardware;
+package android.hardware.usb;
import android.os.Bundle;
import android.os.ParcelFileDescriptor;
@@ -55,64 +55,55 @@ public class UsbManager {
* </ul>
*/
public static final String ACTION_USB_STATE =
- "android.hardware.action.USB_STATE";
+ "android.hardware.usb.action.USB_STATE";
/**
* Broadcast Action: A broadcast for USB device attached event.
*
* This intent is sent when a USB device is attached to the USB bus when in host mode.
* <ul>
- * <li> {@link #EXTRA_DEVICE_NAME} containing the device's name (String)
- * <li> {@link #EXTRA_VENDOR_ID} containing the device's vendor ID (Integer)
- * <li> {@link #EXTRA_PRODUCT_ID} containing the device's product ID (Integer)
- * <li> {@link #EXTRA_DEVICE_CLASS} } containing the device class (Integer)
- * <li> {@link #EXTRA_DEVICE_SUBCLASS} containing the device subclass (Integer)
- * <li> {@link #EXTRA_DEVICE_PROTOCOL} containing the device protocol (Integer)
- * <li> {@link #EXTRA_DEVICE} containing the {@link android.hardware.UsbDevice}
+ * <li> {@link #EXTRA_DEVICE} containing the {@link android.hardware.usb.UsbDevice}
* for the attached device
* </ul>
*/
public static final String ACTION_USB_DEVICE_ATTACHED =
- "android.hardware.action.USB_DEVICE_ATTACHED";
+ "android.hardware.usb.action.USB_DEVICE_ATTACHED";
/**
* Broadcast Action: A broadcast for USB device detached event.
*
* This intent is sent when a USB device is detached from the USB bus when in host mode.
* <ul>
- * <li> {@link #EXTRA_DEVICE_NAME} containing the device's name (String)
+ * <li> {@link #EXTRA_DEVICE} containing the {@link android.hardware.usb.UsbDevice}
+ * for the detached device
* </ul>
*/
public static final String ACTION_USB_DEVICE_DETACHED =
- "android.hardware.action.USB_DEVICE_DETACHED";
+ "android.hardware.usb.action.USB_DEVICE_DETACHED";
/**
* Broadcast Action: A broadcast for USB accessory attached event.
*
* This intent is sent when a USB accessory is attached.
* <ul>
- * <li> {@link #EXTRA_ACCESSORY_MANUFACTURER} containing the accessory's manufacturer (String)
- * <li> {@link #EXTRA_ACCESSORY_PRODUCT} containing the accessory's product name (String)
- * <li> {@link #EXTRA_ACCESSORY_TYPE} containing the accessory's type (String)
- * <li> {@link #EXTRA_ACCESSORY_VERSION} containing the accessory's version (String)
- * <li> {@link #EXTRA_ACCESSORY} containing the {@link android.hardware.UsbAccessory}
+ * <li> {@link #EXTRA_ACCESSORY} containing the {@link android.hardware.usb.UsbAccessory}
* for the attached accessory
* </ul>
*/
public static final String ACTION_USB_ACCESSORY_ATTACHED =
- "android.hardware.action.USB_ACCESSORY_ATTACHED";
+ "android.hardware.usb.action.USB_ACCESSORY_ATTACHED";
/**
* Broadcast Action: A broadcast for USB accessory detached event.
*
* This intent is sent when a USB accessory is detached.
* <ul>
- * <li> {@link #EXTRA_ACCESSORY} containing the {@link android.hardware.UsbAccessory}
+ * <li> {@link #EXTRA_ACCESSORY} containing the {@link android.hardware.usb.UsbAccessory}
* for the attached accessory that was detached
* </ul>
*/
public static final String ACTION_USB_ACCESSORY_DETACHED =
- "android.hardware.action.USB_ACCESSORY_DETACHED";
+ "android.hardware.usb.action.USB_ACCESSORY_DETACHED";
/**
* Boolean extra indicating whether USB is connected or disconnected.
@@ -173,77 +164,18 @@ public class UsbManager {
/**
* Name of extra for {@link #ACTION_USB_DEVICE_ATTACHED} and
* {@link #ACTION_USB_DEVICE_DETACHED} broadcasts
- * containing the device's ID (String).
- */
- public static final String EXTRA_DEVICE_NAME = "device_name";
-
- /**
- * Name of extra for {@link #ACTION_USB_DEVICE_ATTACHED} broadcast
- * containing the device's vendor ID (int).
- */
- public static final String EXTRA_VENDOR_ID = "vendor_id";
-
- /**
- * Name of extra for {@link #ACTION_USB_DEVICE_ATTACHED} broadcast
- * containing the device's product ID (int).
- */
- public static final String EXTRA_PRODUCT_ID = "product_id";
-
- /**
- * Name of extra for {@link #ACTION_USB_DEVICE_ATTACHED} broadcast
- * containing the device's class (int).
- */
- public static final String EXTRA_DEVICE_CLASS = "device_class";
-
- /**
- * Name of extra for {@link #ACTION_USB_DEVICE_ATTACHED} broadcast
- * containing the device's class (int).
- */
- public static final String EXTRA_DEVICE_SUBCLASS = "device_subclass";
-
- /**
- * Name of extra for {@link #ACTION_USB_DEVICE_ATTACHED} broadcast
- * containing the device's class (int).
- */
- public static final String EXTRA_DEVICE_PROTOCOL = "device_protocol";
-
- /**
- * Name of extra for {@link #ACTION_USB_DEVICE_ATTACHED} broadcast
* containing the UsbDevice object for the device.
*/
public static final String EXTRA_DEVICE = "device";
/**
- * Name of extra for {@link #ACTION_USB_ACCESSORY_ATTACHED} broadcast
+ * Name of extra for {@link #ACTION_USB_ACCESSORY_ATTACHED} and
+ * {@link #ACTION_USB_ACCESSORY_DETACHED} broadcasts
* containing the UsbAccessory object for the accessory.
*/
public static final String EXTRA_ACCESSORY = "accessory";
- /**
- * Name of extra for {@link #ACTION_USB_ACCESSORY_ATTACHED} broadcast
- * containing the accessory's manufacturer name.
- */
- public static final String EXTRA_ACCESSORY_MANUFACTURER = "accessory-manufacturer";
-
- /**
- * Name of extra for {@link #ACTION_USB_ACCESSORY_ATTACHED} broadcast
- * containing the accessory's product name.
- */
- public static final String EXTRA_ACCESSORY_PRODUCT = "accessory-product";
-
- /**
- * Name of extra for {@link #ACTION_USB_ACCESSORY_ATTACHED} broadcast
- * containing the accessory's type.
- */
- public static final String EXTRA_ACCESSORY_TYPE = "accessory-type";
-
- /**
- * Name of extra for {@link #ACTION_USB_ACCESSORY_ATTACHED} broadcast
- * containing the accessory's version.
- */
- public static final String EXTRA_ACCESSORY_VERSION = "accessory-version";
-
private IUsbManager mService;
/**
@@ -278,7 +210,7 @@ public class UsbManager {
/**
* Opens the device so it can be used to send and receive
- * data using {@link android.hardware.UsbRequest}.
+ * data using {@link android.hardware.usb.UsbRequest}.
*
* @param device the device to open
* @return true if we successfully opened the device
@@ -313,7 +245,7 @@ public class UsbManager {
return new UsbAccessory[] { accessory };
}
} catch (RemoteException e) {
- Log.e(TAG, "RemoteException in openAccessory" , e);
+ Log.e(TAG, "RemoteException in getAccessoryList" , e);
return null;
}
}
@@ -326,7 +258,7 @@ public class UsbManager {
*/
public ParcelFileDescriptor openAccessory(UsbAccessory accessory) {
try {
- return mService.openAccessory();
+ return mService.openAccessory(accessory);
} catch (RemoteException e) {
Log.e(TAG, "RemoteException in openAccessory" , e);
return null;
diff --git a/core/java/android/hardware/UsbRequest.java b/core/java/android/hardware/usb/UsbRequest.java
index ae3a289..80085c1 100644
--- a/core/java/android/hardware/UsbRequest.java
+++ b/core/java/android/hardware/usb/UsbRequest.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package android.hardware;
+package android.hardware.usb;
import android.util.Log;
@@ -23,9 +23,9 @@ import java.nio.ByteBuffer;
/**
* A class representing USB request packet.
* This can be used for both reading and writing data to or from a
- * {@link android.hardware.UsbDevice}.
+ * {@link android.hardware.usb.UsbDevice}.
* UsbRequests are sent asynchronously via {@link #queue} and the results
- * are read by {@link android.hardware.UsbDevice#requestWait}.
+ * are read by {@link android.hardware.usb.UsbDevice#requestWait}.
*/
public class UsbRequest {
@@ -94,7 +94,7 @@ public class UsbRequest {
* This can be used in conjunction with {@link #setClientData}
* to associate another object with this request, which can be useful for
* maintaining state between calls to {@link #queue} and
- * {@link android.hardware.UsbDevice#requestWait}
+ * {@link android.hardware.usb.UsbDevice#requestWait}
*
* @return the client data for the request
*/
@@ -107,7 +107,7 @@ public class UsbRequest {
* This can be used in conjunction with {@link #getClientData}
* to associate another object with this request, which can be useful for
* maintaining state between calls to {@link #queue} and
- * {@link android.hardware.UsbDevice#requestWait}
+ * {@link android.hardware.usb.UsbDevice#requestWait}
*
* @param data the client data for the request
*/
@@ -121,7 +121,7 @@ public class UsbRequest {
* For IN endpoints, the endpoint will attempt to read the given number of bytes
* into the specified buffer.
* If the queueing operation is successful, we return true and the result will be
- * returned via {@link android.hardware.UsbDevice#requestWait}
+ * returned via {@link android.hardware.usb.UsbDevice#requestWait}
*
* @param buffer the buffer containing the bytes to write, or location to store
* the results of a read
diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java
index cab8ed2..26f375d 100644
--- a/core/java/android/net/ConnectivityManager.java
+++ b/core/java/android/net/ConnectivityManager.java
@@ -221,12 +221,32 @@ public class ConnectivityManager
/** {@hide} */
public static final int TYPE_DUMMY = 8;
+
/** {@hide} */
public static final int TYPE_ETHERNET = 9;
- /** {@hide} TODO: Need to adjust this for WiMAX. */
- public static final int MAX_RADIO_TYPE = TYPE_DUMMY;
- /** {@hide} TODO: Need to adjust this for WiMAX. */
- public static final int MAX_NETWORK_TYPE = TYPE_DUMMY;
+ /**
+ * Over the air Adminstration.
+ * {@hide}
+ */
+ public static final int TYPE_MOBILE_FOTA = 10;
+
+ /**
+ * IP Multimedia Subsystem
+ * {@hide}
+ */
+ public static final int TYPE_MOBILE_IMS = 11;
+
+ /**
+ * Carrier Branded Services
+ * {@hide}
+ */
+ public static final int TYPE_MOBILE_CBS = 12;
+
+ /** {@hide} */
+ public static final int MAX_RADIO_TYPE = TYPE_MOBILE_CBS;
+
+ /** {@hide} */
+ public static final int MAX_NETWORK_TYPE = TYPE_MOBILE_CBS;
public static final int DEFAULT_NETWORK_PREFERENCE = TYPE_WIFI;
diff --git a/core/java/android/net/MobileDataStateTracker.java b/core/java/android/net/MobileDataStateTracker.java
index e04964e..5b4da66 100644
--- a/core/java/android/net/MobileDataStateTracker.java
+++ b/core/java/android/net/MobileDataStateTracker.java
@@ -437,7 +437,8 @@ public class MobileDataStateTracker implements NetworkStateTracker {
retValue = true;
break;
case Phone.APN_REQUEST_STARTED:
- // no need to do anything - we're already due some status update intents
+ // set IDLE here , avoid the following second FAILED not sent out
+ mNetworkInfo.setDetailedState(DetailedState.IDLE, null, null);
retValue = true;
break;
case Phone.APN_REQUEST_FAILED:
@@ -546,6 +547,12 @@ public class MobileDataStateTracker implements NetworkStateTracker {
return Phone.APN_TYPE_DUN;
case ConnectivityManager.TYPE_MOBILE_HIPRI:
return Phone.APN_TYPE_HIPRI;
+ case ConnectivityManager.TYPE_MOBILE_FOTA:
+ return Phone.APN_TYPE_FOTA;
+ case ConnectivityManager.TYPE_MOBILE_IMS:
+ return Phone.APN_TYPE_IMS;
+ case ConnectivityManager.TYPE_MOBILE_CBS:
+ return Phone.APN_TYPE_CBS;
default:
sloge("Error mapping networkType " + netType + " to apnType.");
return null;
diff --git a/core/java/android/nfc/tech/Ndef.java b/core/java/android/nfc/tech/Ndef.java
index 6727d6a..e4daa57 100644
--- a/core/java/android/nfc/tech/Ndef.java
+++ b/core/java/android/nfc/tech/Ndef.java
@@ -103,6 +103,8 @@ public final class Ndef extends BasicTagTechnology {
public static final int TYPE_4 = 4;
/** @hide */
public static final int TYPE_MIFARE_CLASSIC = 101;
+ /** @hide */
+ public static final int TYPE_ICODE_SLI = 102;
/** @hide */
public static final String UNKNOWN = "android.ndef.unknown";
@@ -117,6 +119,11 @@ public final class Ndef extends BasicTagTechnology {
public static final String NFC_FORUM_TYPE_4 = "org.nfcforum.ndef.type4";
/** NDEF on MIFARE Classic */
public static final String MIFARE_CLASSIC = "com.nxp.ndef.mifareclassic";
+ /**
+ * NDEF on iCODE SLI
+ * @hide
+ */
+ public static final String ICODE_SLI = "com.nxp.ndef.icodesli";
private final int mMaxNdefSize;
private final int mCardState;
@@ -200,6 +207,8 @@ public final class Ndef extends BasicTagTechnology {
return NFC_FORUM_TYPE_4;
case TYPE_MIFARE_CLASSIC:
return MIFARE_CLASSIC;
+ case TYPE_ICODE_SLI:
+ return ICODE_SLI;
default:
return UNKNOWN;
}
diff --git a/core/java/android/os/Binder.java b/core/java/android/os/Binder.java
index a402c91..7dc36f9 100644
--- a/core/java/android/os/Binder.java
+++ b/core/java/android/os/Binder.java
@@ -392,4 +392,5 @@ final class BinderProxy implements IBinder {
final private WeakReference mSelf;
private int mObject;
+ private int mOrgue;
}
diff --git a/core/java/android/os/Parcel.java b/core/java/android/os/Parcel.java
index 31f8719..eca3484 100644
--- a/core/java/android/os/Parcel.java
+++ b/core/java/android/os/Parcel.java
@@ -31,6 +31,7 @@ import java.io.ObjectOutputStream;
import java.io.Serializable;
import java.lang.reflect.Field;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@@ -356,7 +357,7 @@ public final class Parcel {
public final native void enforceInterface(String interfaceName);
/**
- * Write a byte array into the parcel at the current {#link #dataPosition},
+ * Write a byte array into the parcel at the current {@link #dataPosition},
* growing {@link #dataCapacity} if needed.
* @param b Bytes to place into the parcel.
*/
@@ -365,7 +366,7 @@ public final class Parcel {
}
/**
- * Write an byte array into the parcel at the current {#link #dataPosition},
+ * Write an byte array into the parcel at the current {@link #dataPosition},
* growing {@link #dataCapacity} if needed.
* @param b Bytes to place into the parcel.
* @param offset Index of first byte to be written.
@@ -376,9 +377,7 @@ public final class Parcel {
writeInt(-1);
return;
}
- if (b.length < offset + len || len < 0 || offset < 0) {
- throw new ArrayIndexOutOfBoundsException();
- }
+ Arrays.checkOffsetAndCount(b.length, offset, len);
writeNative(b, offset, len);
}
@@ -1386,6 +1385,7 @@ public final class Parcel {
int mode) throws FileNotFoundException;
/*package*/ static native void closeFileDescriptor(FileDescriptor desc)
throws IOException;
+ /*package*/ static native void clearFileDescriptor(FileDescriptor desc);
/**
* Read a byte value from the parcel at the current dataPosition().
diff --git a/core/java/android/os/ParcelFileDescriptor.java b/core/java/android/os/ParcelFileDescriptor.java
index 3a5d26b..5bd129f 100644
--- a/core/java/android/os/ParcelFileDescriptor.java
+++ b/core/java/android/os/ParcelFileDescriptor.java
@@ -197,6 +197,40 @@ public class ParcelFileDescriptor implements Parcelable {
public native long seekTo(long pos);
/**
+ * Return the native fd int for this ParcelFileDescriptor. The
+ * ParcelFileDescriptor still owns the fd, and it still must be closed
+ * through this API.
+ */
+ public int getFd() {
+ if (mClosed) {
+ throw new IllegalStateException("Already closed");
+ }
+ return getFdNative();
+ }
+
+ private native int getFdNative();
+
+ /**
+ * Return the native fd int for this ParcelFileDescriptor and detach it
+ * from the object here. You are now responsible for closing the fd in
+ * native code.
+ */
+ public int detachFd() {
+ if (mClosed) {
+ throw new IllegalStateException("Already closed");
+ }
+ if (mParcelDescriptor != null) {
+ int fd = mParcelDescriptor.detachFd();
+ mClosed = true;
+ return fd;
+ }
+ int fd = getFd();
+ mClosed = true;
+ Parcel.clearFileDescriptor(mFileDescriptor);
+ return fd;
+ }
+
+ /**
* Close the ParcelFileDescriptor. This implementation closes the underlying
* OS resources allocated to represent this stream.
*
diff --git a/core/java/android/pim/ICalendar.java b/core/java/android/pim/ICalendar.java
index cc0f45e..9c4eaf4 100644
--- a/core/java/android/pim/ICalendar.java
+++ b/core/java/android/pim/ICalendar.java
@@ -578,6 +578,23 @@ public class ICalendar {
+ text);
}
parameter.name = text.substring(startIndex + 1, equalIndex);
+ } else if (c == '"') {
+ if (parameter == null) {
+ throw new FormatException("Expected parameter before '\"' in " + text);
+ }
+ if (equalIndex == -1) {
+ throw new FormatException("Expected '=' within parameter in " + text);
+ }
+ if (state.index > equalIndex + 1) {
+ throw new FormatException("Parameter value cannot contain a '\"' in " + text);
+ }
+ final int endQuote = text.indexOf('"', state.index + 1);
+ if (endQuote < 0) {
+ throw new FormatException("Expected closing '\"' in " + text);
+ }
+ parameter.value = text.substring(state.index + 1, endQuote);
+ state.index = endQuote + 1;
+ return parameter;
}
++state.index;
}
diff --git a/core/java/android/provider/Applications.java b/core/java/android/provider/Applications.java
index 3686d17..7aabc50 100644
--- a/core/java/android/provider/Applications.java
+++ b/core/java/android/provider/Applications.java
@@ -18,7 +18,6 @@ package android.provider;
import android.content.ComponentName;
import android.content.ContentResolver;
-import android.content.ContentValues;
import android.database.Cursor;
import android.net.Uri;
@@ -27,12 +26,10 @@ import java.util.List;
/**
* The Applications provider gives information about installed applications.
*
- * @hide Only used by ApplicationsProvider and Launchers so far.
+ * @hide Only used by ApplicationsProvider so far.
*/
public class Applications {
- private static final String TAG = "ApplicationsProvider";
-
/**
* The content authority for this provider.
*/
@@ -68,26 +65,6 @@ public class Applications {
ContentResolver.CURSOR_DIR_BASE_TYPE + "/" + APPLICATION_SUB_TYPE;
/**
- * The path that should be used when an application is launched. The aim is
- * to help ApplicationsProvider keep track of which applications the user
- * uses the most, and improve app ranking based on this.
- */
- public static final String INCREASE_LAUNCH_COUNT_PATH = "increase_launch_count";
-
- public static final Uri INCREASE_LAUNCH_COUNT_URI = CONTENT_URI.buildUpon()
- .appendPath(INCREASE_LAUNCH_COUNT_PATH).build();
-
- /**
- * The package name parameter for the "increase launch count" call.
- */
- public static final String INCREASE_LAUNCH_COUNT_PACKAGE = "packageName";
-
- /**
- * The classname parameter for the "increase launch count" call.
- */
- public static final String INCREASE_LAUNCH_COUNT_CLASS = "className";
-
- /**
* no public constructor since this is a utility class
*/
private Applications() {}
@@ -102,20 +79,6 @@ public class Applications {
}
/**
- * Increases the launch count of an application. Launch counts are used
- * by the ApplicationsProvider to improve ranking.
- */
- public static void increaseLaunchCount(
- final ContentResolver resolver, final ComponentName componentName) {
-
- ContentValues parameters = new ContentValues();
- parameters.put(INCREASE_LAUNCH_COUNT_PACKAGE, componentName.getPackageName());
- parameters.put(INCREASE_LAUNCH_COUNT_CLASS, componentName.getClassName());
-
- resolver.insert(INCREASE_LAUNCH_COUNT_URI, parameters);
- }
-
- /**
* Gets the application component name from an application URI.
*
* @param appUri A URI of the form
diff --git a/core/java/android/provider/Browser.java b/core/java/android/provider/Browser.java
index 3bfd005..a34d9c3 100644
--- a/core/java/android/provider/Browser.java
+++ b/core/java/android/provider/Browser.java
@@ -139,8 +139,6 @@ public class Browser {
public static final int SEARCHES_PROJECTION_SEARCH_INDEX = 1;
public static final int SEARCHES_PROJECTION_DATE_INDEX = 2;
- private static final String SEARCHES_WHERE_CLAUSE = "search = ?";
-
/* Set a cap on the count of history items in the history/bookmark
table, to prevent db and layout operations from dragging to a
crawl. Revisit this cap when/if db/layout performance
@@ -167,6 +165,13 @@ public class Browser {
}
/**
+ * Boolean extra passed along with an Intent to a browser, specifying that
+ * a new tab be created. Overrides EXTRA_APPLICATION_ID; if both are set,
+ * a new tab will be used, rather than using the same one.
+ */
+ public static final String EXTRA_CREATE_NEW_TAB = "create_new_tab";
+
+ /**
* Stores a Bitmap extra in an {@link Intent} representing the screenshot of
* a page to share. When receiving an {@link Intent#ACTION_SEND} from the
* Browser, use this to access the screenshot.
diff --git a/core/java/android/provider/ContactsContract.java b/core/java/android/provider/ContactsContract.java
index b05b078..4f88612 100644
--- a/core/java/android/provider/ContactsContract.java
+++ b/core/java/android/provider/ContactsContract.java
@@ -862,8 +862,9 @@ public final class ContactsContract {
}
/**
- * Types of data used to produce the display name for a contact. Listed in the order
- * of increasing priority.
+ * Types of data used to produce the display name for a contact. In the order
+ * of increasing priority: {@link #EMAIL}, {@link #PHONE},
+ * {@link #ORGANIZATION}, {@link #NICKNAME}, {@link #STRUCTURED_NAME}.
*/
public interface DisplayNameSources {
public static final int UNDEFINED = 0;
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index f5cf76e..1718189 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -1797,7 +1797,6 @@ public final class Settings {
*/
public static final String[] SETTINGS_TO_BACKUP = {
STAY_ON_WHILE_PLUGGED_IN,
- WIFI_SLEEP_POLICY,
WIFI_USE_STATIC_IP,
WIFI_STATIC_IP,
WIFI_STATIC_GATEWAY,
diff --git a/core/java/android/provider/Telephony.java b/core/java/android/provider/Telephony.java
index 62f66b6..d2d2557 100644
--- a/core/java/android/provider/Telephony.java
+++ b/core/java/android/provider/Telephony.java
@@ -1723,6 +1723,14 @@ public final class Telephony {
public static final String TYPE = "type";
+ public static final String INACTIVE_TIMER = "inactivetimer";
+
+ // Only if enabled try Data Connection.
+ public static final String ENABLED = "enabled";
+
+ // Rules apply based on class.
+ public static final String CLASS = "class";
+
/**
* The protocol to be used to connect to this APN.
*
diff --git a/core/java/android/server/BluetoothA2dpService.java b/core/java/android/server/BluetoothA2dpService.java
index b5e85a0..132c346 100644
--- a/core/java/android/server/BluetoothA2dpService.java
+++ b/core/java/android/server/BluetoothA2dpService.java
@@ -16,7 +16,7 @@
/**
* TODO: Move this to services.jar
- * and make the contructor package private again.
+ * and make the constructor package private again.
* @hide
*/
@@ -57,8 +57,6 @@ public class BluetoothA2dpService extends IBluetoothA2dp.Stub {
private static final String PROPERTY_STATE = "State";
- private static int mSinkCount;
-
private final Context mContext;
private final IntentFilter mIntentFilter;
private HashMap<BluetoothDevice, Integer> mAudioDevices;
@@ -128,7 +126,6 @@ public class BluetoothA2dpService extends IBluetoothA2dp.Stub {
}
};
-
private boolean isPhoneDocked(BluetoothDevice device) {
// This works only because these broadcast intents are "sticky"
Intent i = mContext.registerReceiver(null, new IntentFilter(Intent.ACTION_DOCK_EVENT));
@@ -184,7 +181,7 @@ public class BluetoothA2dpService extends IBluetoothA2dp.Stub {
}
}
- private int convertBluezSinkStringtoState(String value) {
+ private int convertBluezSinkStringToState(String value) {
if (value.equalsIgnoreCase("disconnected"))
return BluetoothA2dp.STATE_DISCONNECTED;
if (value.equalsIgnoreCase("connecting"))
@@ -204,7 +201,7 @@ public class BluetoothA2dpService extends IBluetoothA2dp.Stub {
return false;
}
- private synchronized boolean addAudioSink (BluetoothDevice device) {
+ private synchronized boolean addAudioSink(BluetoothDevice device) {
String path = mBluetoothService.getObjectPathFromAddress(device.getAddress());
String propValues[] = (String []) getSinkPropertiesNative(path);
if (propValues == null) {
@@ -215,7 +212,7 @@ public class BluetoothA2dpService extends IBluetoothA2dp.Stub {
// Properties are name-value pairs
for (int i = 0; i < propValues.length; i+=2) {
if (propValues[i].equals(PROPERTY_STATE)) {
- state = new Integer(convertBluezSinkStringtoState(propValues[i+1]));
+ state = new Integer(convertBluezSinkStringToState(propValues[i+1]));
break;
}
}
@@ -226,7 +223,6 @@ public class BluetoothA2dpService extends IBluetoothA2dp.Stub {
private synchronized void onBluetoothEnable() {
String devices = mBluetoothService.getProperty("Devices");
- mSinkCount = 0;
if (devices != null) {
String [] paths = devices.split(",");
for (String path: paths) {
@@ -274,18 +270,18 @@ public class BluetoothA2dpService extends IBluetoothA2dp.Stub {
private synchronized boolean isConnectSinkFeasible(BluetoothDevice device) {
if (!mBluetoothService.isEnabled() || !isSinkDevice(device) ||
getPriority(device) == BluetoothA2dp.PRIORITY_OFF) {
- return false;
- }
+ return false;
+ }
- if (mAudioDevices.get(device) == null && !addAudioSink(device)) {
- return false;
- }
+ if (mAudioDevices.get(device) == null && !addAudioSink(device)) {
+ return false;
+ }
- String path = mBluetoothService.getObjectPathFromAddress(device.getAddress());
- if (path == null) {
- return false;
- }
- return true;
+ String path = mBluetoothService.getObjectPathFromAddress(device.getAddress());
+ if (path == null) {
+ return false;
+ }
+ return true;
}
public synchronized boolean isA2dpPlaying(BluetoothDevice device) {
@@ -467,7 +463,15 @@ public class BluetoothA2dpService extends IBluetoothA2dp.Stub {
Settings.Secure.getBluetoothA2dpSinkPriorityKey(device.getAddress()), priority);
}
- private synchronized void onSinkPropertyChanged(String path, String []propValues) {
+ /**
+ * Called by native code on a PropertyChanged signal from
+ * org.bluez.AudioSink.
+ *
+ * @param path the object path for the changed device
+ * @param propValues a string array containing the key and one or more
+ * values.
+ */
+ private synchronized void onSinkPropertyChanged(String path, String[] propValues) {
if (!mBluetoothService.isEnabled()) {
return;
}
@@ -482,7 +486,7 @@ public class BluetoothA2dpService extends IBluetoothA2dp.Stub {
BluetoothDevice device = mAdapter.getRemoteDevice(address);
if (name.equals(PROPERTY_STATE)) {
- int state = convertBluezSinkStringtoState(propValues[1]);
+ int state = convertBluezSinkStringToState(propValues[1]);
log("A2DP: onSinkPropertyChanged newState is: " + state + "mPlayingA2dpDevice: " + mPlayingA2dpDevice);
if (mAudioDevices.get(device) == null) {
@@ -508,12 +512,6 @@ public class BluetoothA2dpService extends IBluetoothA2dp.Stub {
private void handleSinkStateChange(BluetoothDevice device, int prevState, int state) {
if (state != prevState) {
- if (state == BluetoothA2dp.STATE_DISCONNECTED ||
- state == BluetoothA2dp.STATE_DISCONNECTING) {
- mSinkCount--;
- } else if (state == BluetoothA2dp.STATE_CONNECTED) {
- mSinkCount ++;
- }
mAudioDevices.put(device, state);
checkSinkSuspendState(state);
@@ -577,6 +575,13 @@ public class BluetoothA2dpService extends IBluetoothA2dp.Stub {
return result;
}
+ /**
+ * Called by native code for the async response to a Connect
+ * method call to org.bluez.AudioSink.
+ *
+ * @param deviceObjectPath the object path for the connecting device
+ * @param result true on success; false on error
+ */
private void onConnectSinkResult(String deviceObjectPath, boolean result) {
// If the call was a success, ignore we will update the state
// when we a Sink Property Change
diff --git a/core/java/android/server/BluetoothAdapterProperties.java b/core/java/android/server/BluetoothAdapterProperties.java
new file mode 100644
index 0000000..ae8104b
--- /dev/null
+++ b/core/java/android/server/BluetoothAdapterProperties.java
@@ -0,0 +1,106 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.server;
+
+import android.content.Context;
+import android.util.Log;
+
+import java.util.HashMap;
+import java.util.Map;
+
+class BluetoothAdapterProperties {
+
+ private static final String TAG = "BluetoothAdapterProperties";
+
+ private final Map<String, String> mPropertiesMap;
+ private final Context mContext;
+ private final BluetoothService mService;
+
+ BluetoothAdapterProperties(Context context, BluetoothService service) {
+ mPropertiesMap = new HashMap<String, String>();
+ mContext = context;
+ mService = service;
+ }
+
+ synchronized String getProperty(String name) {
+ if (mPropertiesMap.isEmpty()) {
+ getAllProperties();
+ }
+ return mPropertiesMap.get(name);
+ }
+
+ String getObjectPath() {
+ return getProperty("ObjectPath");
+ }
+
+ synchronized void clear() {
+ mPropertiesMap.clear();
+ }
+
+ synchronized boolean isEmpty() {
+ return mPropertiesMap.isEmpty();
+ }
+
+ synchronized void setProperty(String name, String value) {
+ mPropertiesMap.put(name, value);
+ }
+
+ synchronized void getAllProperties() {
+ mContext.enforceCallingOrSelfPermission(
+ BluetoothService.BLUETOOTH_PERM,
+ "Need BLUETOOTH permission");
+ mPropertiesMap.clear();
+
+ String properties[] = (String[]) mService
+ .getAdapterPropertiesNative();
+ // The String Array consists of key-value pairs.
+ if (properties == null) {
+ Log.e(TAG, "*Error*: GetAdapterProperties returned NULL");
+ return;
+ }
+
+ for (int i = 0; i < properties.length; i++) {
+ String name = properties[i];
+ String newValue = null;
+ int len;
+ if (name == null) {
+ Log.e(TAG, "Error:Adapter Property at index " + i + " is null");
+ continue;
+ }
+ if (name.equals("Devices") || name.equals("UUIDs")) {
+ StringBuilder str = new StringBuilder();
+ len = Integer.valueOf(properties[++i]);
+ for (int j = 0; j < len; j++) {
+ str.append(properties[++i]);
+ str.append(",");
+ }
+ if (len > 0) {
+ newValue = str.toString();
+ }
+ } else {
+ newValue = properties[++i];
+ }
+ mPropertiesMap.put(name, newValue);
+ }
+
+ // Add adapter object path property.
+ String adapterPath = mService.getAdapterPathNative();
+ if (adapterPath != null) {
+ mPropertiesMap.put("ObjectPath", adapterPath + "/dev_");
+ }
+ }
+}
diff --git a/core/java/android/server/BluetoothBondState.java b/core/java/android/server/BluetoothBondState.java
new file mode 100644
index 0000000..2304a70
--- /dev/null
+++ b/core/java/android/server/BluetoothBondState.java
@@ -0,0 +1,368 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.server;
+
+import android.bluetooth.BluetoothAdapter;
+import android.bluetooth.BluetoothDevice;
+import android.content.Context;
+import android.content.Intent;
+import android.util.Log;
+
+import java.io.BufferedReader;
+import java.io.BufferedWriter;
+import java.io.DataInputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * Local cache of bonding state.
+ * We keep our own state to track the intermediate state BONDING, which
+ * bluez does not track.
+ * All addresses must be passed in upper case.
+ */
+class BluetoothBondState {
+ private static final String TAG = "BluetoothBondState";
+ private static final boolean DBG = true;
+
+ private final HashMap<String, Integer> mState = new HashMap<String, Integer>();
+ private final HashMap<String, Integer> mPinAttempt = new HashMap<String, Integer>();
+
+ private static final String AUTO_PAIRING_BLACKLIST =
+ "/etc/bluetooth/auto_pairing.conf";
+ private static final String DYNAMIC_AUTO_PAIRING_BLACKLIST =
+ "/data/misc/bluetooth/dynamic_auto_pairing.conf";
+ private ArrayList<String> mAutoPairingAddressBlacklist;
+ private ArrayList<String> mAutoPairingExactNameBlacklist;
+ private ArrayList<String> mAutoPairingPartialNameBlacklist;
+ private ArrayList<String> mAutoPairingFixedPinZerosKeyboardList;
+ // Addresses added to blacklist dynamically based on usage.
+ private ArrayList<String> mAutoPairingDynamicAddressBlacklist;
+
+ // If this is an outgoing connection, store the address.
+ // There can be only 1 pending outgoing connection at a time,
+ private String mPendingOutgoingBonding;
+
+ private final Context mContext;
+ private final BluetoothService mService;
+ private final BluetoothInputProfileHandler mBluetoothInputProfileHandler;
+
+ BluetoothBondState(Context context, BluetoothService service) {
+ mContext = context;
+ mService = service;
+ mBluetoothInputProfileHandler =
+ BluetoothInputProfileHandler.getInstance(mContext, mService);
+ }
+
+ synchronized void setPendingOutgoingBonding(String address) {
+ mPendingOutgoingBonding = address;
+ }
+
+ public synchronized String getPendingOutgoingBonding() {
+ return mPendingOutgoingBonding;
+ }
+
+ public synchronized void loadBondState() {
+ if (mService.getBluetoothStateInternal() !=
+ BluetoothAdapter.STATE_TURNING_ON) {
+ return;
+ }
+ String val = mService.getAdapterProperties().getProperty("Devices");
+ if (val == null) {
+ return;
+ }
+ String[] bonds = val.split(",");
+ if (bonds == null) {
+ return;
+ }
+ mState.clear();
+ if (DBG) Log.d(TAG, "found " + bonds.length + " bonded devices");
+ for (String device : bonds) {
+ mState.put(mService.getAddressFromObjectPath(device).toUpperCase(),
+ BluetoothDevice.BOND_BONDED);
+ }
+ }
+
+ public synchronized void setBondState(String address, int state) {
+ setBondState(address, state, 0);
+ }
+
+ /** reason is ignored unless state == BOND_NOT_BONDED */
+ public synchronized void setBondState(String address, int state, int reason) {
+ int oldState = getBondState(address);
+ if (oldState == state) {
+ return;
+ }
+
+ // Check if this was an pending outgoing bonding.
+ // If yes, reset the state.
+ if (oldState == BluetoothDevice.BOND_BONDING) {
+ if (address.equals(mPendingOutgoingBonding)) {
+ mPendingOutgoingBonding = null;
+ }
+ }
+
+ if (state == BluetoothDevice.BOND_BONDED) {
+ mService.addProfileState(address);
+ } else if (state == BluetoothDevice.BOND_NONE) {
+ mService.removeProfileState(address);
+ }
+
+ // HID is handled by BluetoothService, other profiles
+ // will be handled by their respective services.
+ mBluetoothInputProfileHandler.setInitialInputDevicePriority(
+ mService.getRemoteDevice(address), state);
+
+ if (DBG) {
+ Log.d(TAG, address + " bond state " + oldState + " -> " + state
+ + " (" + reason + ")");
+ }
+ Intent intent = new Intent(BluetoothDevice.ACTION_BOND_STATE_CHANGED);
+ intent.putExtra(BluetoothDevice.EXTRA_DEVICE, mService.getRemoteDevice(address));
+ intent.putExtra(BluetoothDevice.EXTRA_BOND_STATE, state);
+ intent.putExtra(BluetoothDevice.EXTRA_PREVIOUS_BOND_STATE, oldState);
+ if (state == BluetoothDevice.BOND_NONE) {
+ if (reason <= 0) {
+ Log.w(TAG, "setBondState() called to unbond device, but reason code is " +
+ "invalid. Overriding reason code with BOND_RESULT_REMOVED");
+ reason = BluetoothDevice.UNBOND_REASON_REMOVED;
+ }
+ intent.putExtra(BluetoothDevice.EXTRA_REASON, reason);
+ mState.remove(address);
+ } else {
+ mState.put(address, state);
+ }
+
+ mContext.sendBroadcast(intent, BluetoothService.BLUETOOTH_PERM);
+ }
+
+ public boolean isAutoPairingBlacklisted(String address) {
+ if (mAutoPairingAddressBlacklist != null) {
+ for (String blacklistAddress : mAutoPairingAddressBlacklist) {
+ if (address.startsWith(blacklistAddress)) return true;
+ }
+ }
+
+ if (mAutoPairingDynamicAddressBlacklist != null) {
+ for (String blacklistAddress: mAutoPairingDynamicAddressBlacklist) {
+ if (address.equals(blacklistAddress)) return true;
+ }
+ }
+
+ String name = mService.getRemoteName(address);
+ if (name != null) {
+ if (mAutoPairingExactNameBlacklist != null) {
+ for (String blacklistName : mAutoPairingExactNameBlacklist) {
+ if (name.equals(blacklistName)) return true;
+ }
+ }
+
+ if (mAutoPairingPartialNameBlacklist != null) {
+ for (String blacklistName : mAutoPairingPartialNameBlacklist) {
+ if (name.startsWith(blacklistName)) return true;
+ }
+ }
+ }
+ return false;
+ }
+
+ public boolean isFixedPinZerosAutoPairKeyboard(String address) {
+ // Note: the meaning of blacklist is reversed in this case.
+ // If its in the list, we can go ahead and auto pair since
+ // by default keyboard should have a variable PIN that we don't
+ // auto pair using 0000.
+ if (mAutoPairingFixedPinZerosKeyboardList != null) {
+ for (String blacklistAddress : mAutoPairingFixedPinZerosKeyboardList) {
+ if (address.startsWith(blacklistAddress)) return true;
+ }
+ }
+ return false;
+ }
+
+ public synchronized int getBondState(String address) {
+ Integer state = mState.get(address);
+ if (state == null) {
+ return BluetoothDevice.BOND_NONE;
+ }
+ return state.intValue();
+ }
+
+ /*package*/ synchronized String[] listInState(int state) {
+ ArrayList<String> result = new ArrayList<String>(mState.size());
+ for (Map.Entry<String, Integer> e : mState.entrySet()) {
+ if (e.getValue().intValue() == state) {
+ result.add(e.getKey());
+ }
+ }
+ return result.toArray(new String[result.size()]);
+ }
+
+ public synchronized void addAutoPairingFailure(String address) {
+ if (mAutoPairingDynamicAddressBlacklist == null) {
+ mAutoPairingDynamicAddressBlacklist = new ArrayList<String>();
+ }
+
+ updateAutoPairingData(address);
+ mAutoPairingDynamicAddressBlacklist.add(address);
+ }
+
+ public synchronized boolean isAutoPairingAttemptsInProgress(String address) {
+ return getAttempt(address) != 0;
+ }
+
+ public synchronized void clearPinAttempts(String address) {
+ mPinAttempt.remove(address);
+ }
+
+ public synchronized boolean hasAutoPairingFailed(String address) {
+ if (mAutoPairingDynamicAddressBlacklist == null) return false;
+
+ return mAutoPairingDynamicAddressBlacklist.contains(address);
+ }
+
+ public synchronized int getAttempt(String address) {
+ Integer attempt = mPinAttempt.get(address);
+ if (attempt == null) {
+ return 0;
+ }
+ return attempt.intValue();
+ }
+
+ public synchronized void attempt(String address) {
+ Integer attempt = mPinAttempt.get(address);
+ int newAttempt;
+ if (attempt == null) {
+ newAttempt = 1;
+ } else {
+ newAttempt = attempt.intValue() + 1;
+ }
+ mPinAttempt.put(address, new Integer(newAttempt));
+ }
+
+ private void copyAutoPairingData() {
+ FileInputStream in = null;
+ FileOutputStream out = null;
+ try {
+ File file = new File(DYNAMIC_AUTO_PAIRING_BLACKLIST);
+ if (file.exists()) return;
+
+ in = new FileInputStream(AUTO_PAIRING_BLACKLIST);
+ out= new FileOutputStream(DYNAMIC_AUTO_PAIRING_BLACKLIST);
+
+ byte[] buf = new byte[1024];
+ int len;
+ while ((len = in.read(buf)) > 0) {
+ out.write(buf, 0, len);
+ }
+ } catch (FileNotFoundException e) {
+ Log.e(TAG, "FileNotFoundException: copyAutoPairingData " + e);
+ } catch (IOException e) {
+ Log.e(TAG, "IOException: copyAutoPairingData " + e);
+ } finally {
+ try {
+ if (in != null) in.close();
+ if (out != null) out.close();
+ } catch (IOException e) {}
+ }
+ }
+
+ synchronized public void readAutoPairingData() {
+ if (mAutoPairingAddressBlacklist != null) return;
+ copyAutoPairingData();
+ FileInputStream fstream = null;
+ try {
+ fstream = new FileInputStream(DYNAMIC_AUTO_PAIRING_BLACKLIST);
+ DataInputStream in = new DataInputStream(fstream);
+ BufferedReader file = new BufferedReader(new InputStreamReader(in));
+ String line;
+ while((line = file.readLine()) != null) {
+ line = line.trim();
+ if (line.length() == 0 || line.startsWith("//")) continue;
+ String[] value = line.split("=");
+ if (value != null && value.length == 2) {
+ String[] val = value[1].split(",");
+ if (value[0].equalsIgnoreCase("AddressBlacklist")) {
+ mAutoPairingAddressBlacklist =
+ new ArrayList<String>(Arrays.asList(val));
+ } else if (value[0].equalsIgnoreCase("ExactNameBlacklist")) {
+ mAutoPairingExactNameBlacklist =
+ new ArrayList<String>(Arrays.asList(val));
+ } else if (value[0].equalsIgnoreCase("PartialNameBlacklist")) {
+ mAutoPairingPartialNameBlacklist =
+ new ArrayList<String>(Arrays.asList(val));
+ } else if (value[0].equalsIgnoreCase("FixedPinZerosKeyboardBlacklist")) {
+ mAutoPairingFixedPinZerosKeyboardList =
+ new ArrayList<String>(Arrays.asList(val));
+ } else if (value[0].equalsIgnoreCase("DynamicAddressBlacklist")) {
+ mAutoPairingDynamicAddressBlacklist =
+ new ArrayList<String>(Arrays.asList(val));
+ } else {
+ Log.e(TAG, "Error parsing Auto pairing blacklist file");
+ }
+ }
+ }
+ } catch (FileNotFoundException e) {
+ Log.e(TAG, "FileNotFoundException: readAutoPairingData " + e);
+ } catch (IOException e) {
+ Log.e(TAG, "IOException: readAutoPairingData " + e);
+ } finally {
+ if (fstream != null) {
+ try {
+ fstream.close();
+ } catch (IOException e) {
+ // Ignore
+ }
+ }
+ }
+ }
+
+ // This function adds a bluetooth address to the auto pairing blacklist
+ // file. These addresses are added to DynamicAddressBlacklistSection
+ private void updateAutoPairingData(String address) {
+ BufferedWriter out = null;
+ try {
+ out = new BufferedWriter(new FileWriter(DYNAMIC_AUTO_PAIRING_BLACKLIST, true));
+ StringBuilder str = new StringBuilder();
+ if (mAutoPairingDynamicAddressBlacklist.size() == 0) {
+ str.append("DynamicAddressBlacklist=");
+ }
+ str.append(address);
+ str.append(",");
+ out.write(str.toString());
+ } catch (FileNotFoundException e) {
+ Log.e(TAG, "FileNotFoundException: updateAutoPairingData " + e);
+ } catch (IOException e) {
+ Log.e(TAG, "IOException: updateAutoPairingData " + e);
+ } finally {
+ if (out != null) {
+ try {
+ out.close();
+ } catch (IOException e) {
+ // Ignore
+ }
+ }
+ }
+ }
+}
diff --git a/core/java/android/server/BluetoothDeviceProperties.java b/core/java/android/server/BluetoothDeviceProperties.java
new file mode 100644
index 0000000..3dc53d7
--- /dev/null
+++ b/core/java/android/server/BluetoothDeviceProperties.java
@@ -0,0 +1,128 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.server;
+
+import android.os.ParcelUuid;
+import android.util.Log;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Set;
+
+class BluetoothDeviceProperties {
+
+ private static final String TAG = "BluetoothDeviceProperties";
+
+ private final HashMap<String, Map<String, String>> mPropertiesMap;
+ private final BluetoothService mService;
+
+ BluetoothDeviceProperties(BluetoothService service) {
+ mPropertiesMap = new HashMap<String, Map<String, String>>();
+ mService = service;
+ }
+
+ synchronized Map<String, String> addProperties(String address,
+ String[] properties) {
+ /*
+ * We get a DeviceFound signal every time RSSI changes or name changes.
+ * Don't create a new Map object every time.
+ */
+ Map<String, String> propertyValues = mPropertiesMap.get(address);
+ if (propertyValues == null) {
+ propertyValues = new HashMap<String, String>();
+ }
+
+ for (int i = 0; i < properties.length; i++) {
+ String name = properties[i];
+ String newValue = null;
+ int len;
+ if (name == null) {
+ Log.e(TAG, "Error: Remote Device Property at index "
+ + i + " is null");
+ continue;
+ }
+ if (name.equals("UUIDs") || name.equals("Nodes")) {
+ StringBuilder str = new StringBuilder();
+ len = Integer.valueOf(properties[++i]);
+ for (int j = 0; j < len; j++) {
+ str.append(properties[++i]);
+ str.append(",");
+ }
+ if (len > 0) {
+ newValue = str.toString();
+ }
+ } else {
+ newValue = properties[++i];
+ }
+
+ propertyValues.put(name, newValue);
+ }
+ mPropertiesMap.put(address, propertyValues);
+
+ // We have added a new remote device or updated its properties.
+ // Also update the serviceChannel cache.
+ mService.updateDeviceServiceChannelCache(address);
+ return propertyValues;
+ }
+
+ synchronized void setProperty(String address, String name, String value) {
+ Map <String, String> propVal = mPropertiesMap.get(address);
+ if (propVal != null) {
+ propVal.put(name, value);
+ mPropertiesMap.put(address, propVal);
+ } else {
+ Log.e(TAG, "setRemoteDeviceProperty for a device not in cache:" + address);
+ }
+ }
+
+ synchronized boolean isInCache(String address) {
+ return (mPropertiesMap.get(address) != null);
+ }
+
+ synchronized boolean isEmpty() {
+ return mPropertiesMap.isEmpty();
+ }
+
+ synchronized Set<String> keySet() {
+ return mPropertiesMap.keySet();
+ }
+
+ synchronized String getProperty(String address, String property) {
+ Map<String, String> properties = mPropertiesMap.get(address);
+ if (properties != null) {
+ return properties.get(property);
+ } else {
+ // Query for remote device properties, again.
+ // We will need to reload the cache when we switch Bluetooth on / off
+ // or if we crash.
+ properties = updateCache(address);
+ if (properties != null) {
+ return properties.get(property);
+ }
+ }
+ Log.e(TAG, "getRemoteDeviceProperty: " + property + " not present: " + address);
+ return null;
+ }
+
+ synchronized Map<String, String> updateCache(String address) {
+ String[] propValues = mService.getRemoteDeviceProperties(address);
+ if (propValues != null) {
+ return addProperties(address, propValues);
+ }
+ return null;
+ }
+}
diff --git a/core/java/android/server/BluetoothEventLoop.java b/core/java/android/server/BluetoothEventLoop.java
index 3316ea5..e72aaa7 100644
--- a/core/java/android/server/BluetoothEventLoop.java
+++ b/core/java/android/server/BluetoothEventLoop.java
@@ -34,14 +34,9 @@ import android.util.Log;
import java.util.HashMap;
import java.util.List;
-import java.util.Set;
/**
- * TODO: Move this to
- * java/services/com/android/server/BluetoothEventLoop.java
- * and make the constructor package private again.
- *
* @hide
*/
class BluetoothEventLoop {
@@ -57,6 +52,7 @@ class BluetoothEventLoop {
private final BluetoothService mBluetoothService;
private final BluetoothAdapter mAdapter;
private BluetoothA2dp mA2dp;
+ private BluetoothInputDevice mInputDevice;
private final Context mContext;
// The WakeLock is used for bringing up the LCD during a pairing request
// from remote device when Android is in Suspend state.
@@ -113,7 +109,7 @@ class BluetoothEventLoop {
BluetoothService bluetoothService) {
mBluetoothService = bluetoothService;
mContext = context;
- mPasskeyAgentRequestData = new HashMap();
+ mPasskeyAgentRequestData = new HashMap<String, Integer>();
mAdapter = adapter;
//WakeLock instantiation in BluetoothEventLoop class
PowerManager pm = (PowerManager)context.getSystemService(Context.POWER_SERVICE);
@@ -125,15 +121,24 @@ class BluetoothEventLoop {
/*package*/ void getProfileProxy() {
mAdapter.getProfileProxy(mContext, mProfileServiceListener, BluetoothProfile.A2DP);
+ mAdapter.getProfileProxy(mContext, mProfileServiceListener, BluetoothProfile.INPUT_DEVICE);
}
private BluetoothProfile.ServiceListener mProfileServiceListener =
new BluetoothProfile.ServiceListener() {
public void onServiceConnected(int profile, BluetoothProfile proxy) {
- mA2dp = (BluetoothA2dp) proxy;
+ if (profile == BluetoothProfile.A2DP) {
+ mA2dp = (BluetoothA2dp) proxy;
+ } else if (profile == BluetoothProfile.INPUT_DEVICE) {
+ mInputDevice = (BluetoothInputDevice) proxy;
+ }
}
public void onServiceDisconnected(int profile) {
- mA2dp = null;
+ if (profile == BluetoothProfile.A2DP) {
+ mA2dp = null;
+ } else if (profile == BluetoothProfile.INPUT_DEVICE) {
+ mInputDevice = null;
+ }
}
};
@@ -170,10 +175,12 @@ class BluetoothEventLoop {
}
private void addDevice(String address, String[] properties) {
- mBluetoothService.addRemoteDeviceProperties(address, properties);
- String rssi = mBluetoothService.getRemoteDeviceProperty(address, "RSSI");
- String classValue = mBluetoothService.getRemoteDeviceProperty(address, "Class");
- String name = mBluetoothService.getRemoteDeviceProperty(address, "Name");
+ BluetoothDeviceProperties deviceProperties =
+ mBluetoothService.getDeviceProperties();
+ deviceProperties.addProperties(address, properties);
+ String rssi = deviceProperties.getProperty(address, "RSSI");
+ String classValue = deviceProperties.getProperty(address, "Class");
+ String name = deviceProperties.getProperty(address, "Name");
short rssiValue;
// For incoming connections, we don't get the RSSI value. Use a default of MIN_VALUE.
// If we accept the pairing, we will automatically show it at the top of the list.
@@ -196,6 +203,14 @@ class BluetoothEventLoop {
}
}
+ /**
+ * Called by native code on a DeviceFound signal from org.bluez.Adapter.
+ *
+ * @param address the MAC address of the new device
+ * @param properties an array of property keys and value strings
+ *
+ * @see BluetoothDeviceProperties#addProperties(String, String[])
+ */
private void onDeviceFound(String address, String[] properties) {
if (properties == null) {
Log.e(TAG, "ERROR: Remote device properties are null");
@@ -204,12 +219,24 @@ class BluetoothEventLoop {
addDevice(address, properties);
}
+ /**
+ * Called by native code on a DeviceDisappeared signal from
+ * org.bluez.Adapter.
+ *
+ * @param address the MAC address of the disappeared device
+ */
private void onDeviceDisappeared(String address) {
Intent intent = new Intent(BluetoothDevice.ACTION_DISAPPEARED);
intent.putExtra(BluetoothDevice.EXTRA_DEVICE, mAdapter.getRemoteDevice(address));
mContext.sendBroadcast(intent, BLUETOOTH_PERM);
}
+ /**
+ * Called by native code on a DisconnectRequested signal from
+ * org.bluez.Device.
+ *
+ * @param deviceObjectPath the object path for the disconnecting device
+ */
private void onDeviceDisconnectRequested(String deviceObjectPath) {
String address = mBluetoothService.getAddressFromObjectPath(deviceObjectPath);
if (address == null) {
@@ -221,11 +248,23 @@ class BluetoothEventLoop {
mContext.sendBroadcast(intent, BLUETOOTH_PERM);
}
+ /**
+ * Called by native code for the async response to a CreatePairedDevice
+ * method call to org.bluez.Adapter.
+ *
+ * @param address the MAC address of the device to pair
+ * @param result success or error result for the pairing operation
+ */
private void onCreatePairedDeviceResult(String address, int result) {
address = address.toUpperCase();
mBluetoothService.onCreatePairedDeviceResult(address, result);
}
+ /**
+ * Called by native code on a DeviceCreated signal from org.bluez.Adapter.
+ *
+ * @param deviceObjectPath the object path for the created device
+ */
private void onDeviceCreated(String deviceObjectPath) {
String address = mBluetoothService.getAddressFromObjectPath(deviceObjectPath);
if (!mBluetoothService.isRemoteDeviceInCache(address)) {
@@ -238,6 +277,11 @@ class BluetoothEventLoop {
return;
}
+ /**
+ * Called by native code on a DeviceRemoved signal from org.bluez.Adapter.
+ *
+ * @param deviceObjectPath the object path for the removed device
+ */
private void onDeviceRemoved(String deviceObjectPath) {
String address = mBluetoothService.getAddressFromObjectPath(deviceObjectPath);
if (address != null) {
@@ -247,31 +291,43 @@ class BluetoothEventLoop {
}
}
+ /**
+ * Called by native code on a PropertyChanged signal from
+ * org.bluez.Adapter. This method is also called from Java at
+ * {@link BluetoothService.EnableThread#run()} to set the "Pairable"
+ * property when Bluetooth is enabled.
+ *
+ * @param propValues a string array containing the key and one or more
+ * values.
+ */
/*package*/ void onPropertyChanged(String[] propValues) {
- if (mBluetoothService.isAdapterPropertiesEmpty()) {
+ BluetoothAdapterProperties adapterProperties =
+ mBluetoothService.getAdapterProperties();
+
+ if (adapterProperties.isEmpty()) {
// We have got a property change before
// we filled up our cache.
- mBluetoothService.getAllProperties();
+ adapterProperties.getAllProperties();
}
log("Property Changed: " + propValues[0] + " : " + propValues[1]);
String name = propValues[0];
if (name.equals("Name")) {
- mBluetoothService.setProperty(name, propValues[1]);
+ adapterProperties.setProperty(name, propValues[1]);
Intent intent = new Intent(BluetoothAdapter.ACTION_LOCAL_NAME_CHANGED);
intent.putExtra(BluetoothAdapter.EXTRA_LOCAL_NAME, propValues[1]);
intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
mContext.sendBroadcast(intent, BLUETOOTH_PERM);
} else if (name.equals("Pairable") || name.equals("Discoverable")) {
String pairable = name.equals("Pairable") ? propValues[1] :
- mBluetoothService.getPropertyInternal("Pairable");
+ adapterProperties.getProperty("Pairable");
String discoverable = name.equals("Discoverable") ? propValues[1] :
- mBluetoothService.getPropertyInternal("Discoverable");
+ adapterProperties.getProperty("Discoverable");
// This shouldn't happen, unless Adapter Properties are null.
if (pairable == null || discoverable == null)
return;
- mBluetoothService.setProperty(name, propValues[1]);
+ adapterProperties.setProperty(name, propValues[1]);
int mode = BluetoothService.bluezStringToScanMode(
pairable.equals("true"),
discoverable.equals("true"));
@@ -283,7 +339,7 @@ class BluetoothEventLoop {
}
} else if (name.equals("Discovering")) {
Intent intent;
- mBluetoothService.setProperty(name, propValues[1]);
+ adapterProperties.setProperty(name, propValues[1]);
if (propValues[1].equals("true")) {
mBluetoothService.setIsDiscovering(true);
intent = new Intent(BluetoothAdapter.ACTION_DISCOVERY_STARTED);
@@ -305,7 +361,7 @@ class BluetoothEventLoop {
}
value = str.toString();
}
- mBluetoothService.setProperty(name, value);
+ adapterProperties.setProperty(name, value);
if (name.equals("UUIDs")) {
mBluetoothService.updateBluetoothState(value);
}
@@ -315,10 +371,18 @@ class BluetoothEventLoop {
if (propValues[1].equals("true"))
onRestartRequired();
} else if (name.equals("DiscoverableTimeout")) {
- mBluetoothService.setProperty(name, propValues[1]);
+ adapterProperties.setProperty(name, propValues[1]);
}
}
+ /**
+ * Called by native code on a PropertyChanged signal from
+ * org.bluez.Device.
+ *
+ * @param deviceObjectPath the object path for the changed device
+ * @param propValues a string array containing the key and one or more
+ * values.
+ */
private void onDevicePropertyChanged(String deviceObjectPath, String[] propValues) {
String name = propValues[0];
String address = mBluetoothService.getAddressFromObjectPath(deviceObjectPath);
@@ -389,18 +453,26 @@ class BluetoothEventLoop {
}
} else if (name.equals("Trusted")) {
if (DBG)
- log("set trust state succeded, value is " + propValues[1]);
+ log("set trust state succeeded, value is: " + propValues[1]);
mBluetoothService.setRemoteDeviceProperty(address, name, propValues[1]);
}
}
+ /**
+ * Called by native code on a PropertyChanged signal from
+ * org.bluez.Input.
+ *
+ * @param path the object path for the changed input device
+ * @param propValues a string array containing the key and one or more
+ * values.
+ */
private void onInputDevicePropertyChanged(String path, String[] propValues) {
String address = mBluetoothService.getAddressFromObjectPath(path);
if (address == null) {
- Log.e(TAG, "onInputDevicePropertyChanged: Address of the remote device in null");
+ Log.e(TAG, "onInputDevicePropertyChanged: Address of the remote device is null");
return;
}
- log(" Input Device : Name of Property is:" + propValues[0]);
+ log("Input Device : Name of Property is: " + propValues[0]);
boolean state = false;
if (propValues[1].equals("true")) {
state = true;
@@ -408,6 +480,14 @@ class BluetoothEventLoop {
mBluetoothService.handleInputDevicePropertyChange(address, state);
}
+ /**
+ * Called by native code on a PropertyChanged signal from
+ * org.bluez.Network.
+ *
+ * @param deviceObjectPath the object path for the changed PAN device
+ * @param propValues a string array containing the key and one or more
+ * values.
+ */
private void onPanDevicePropertyChanged(String deviceObjectPath, String[] propValues) {
String name = propValues[0];
String address = mBluetoothService.getAddressFromObjectPath(deviceObjectPath);
@@ -461,6 +541,13 @@ class BluetoothEventLoop {
return address;
}
+ /**
+ * Called by native code on a RequestPairingConsent method call to
+ * org.bluez.Agent.
+ *
+ * @param objectPath the path of the device to request pairing consent for
+ * @param nativeData a native pointer to the original D-Bus message
+ */
private void onRequestPairingConsent(String objectPath, int nativeData) {
String address = checkPairingRequestAndGetAddress(objectPath, nativeData);
if (address == null) return;
@@ -484,11 +571,19 @@ class BluetoothEventLoop {
intent.putExtra(BluetoothDevice.EXTRA_PAIRING_VARIANT,
BluetoothDevice.PAIRING_VARIANT_CONSENT);
mContext.sendBroadcast(intent, BLUETOOTH_ADMIN_PERM);
- // Release wakelock to allow the LCD to go off after the PIN popup notifcation.
+ // Release wakelock to allow the LCD to go off after the PIN popup notification.
mWakeLock.release();
return;
}
+ /**
+ * Called by native code on a RequestConfirmation method call to
+ * org.bluez.Agent.
+ *
+ * @param objectPath the path of the device to confirm the passkey for
+ * @param passkey an integer containing the 6-digit passkey to confirm
+ * @param nativeData a native pointer to the original D-Bus message
+ */
private void onRequestPasskeyConfirmation(String objectPath, int passkey, int nativeData) {
String address = checkPairingRequestAndGetAddress(objectPath, nativeData);
if (address == null) return;
@@ -500,11 +595,18 @@ class BluetoothEventLoop {
intent.putExtra(BluetoothDevice.EXTRA_PAIRING_VARIANT,
BluetoothDevice.PAIRING_VARIANT_PASSKEY_CONFIRMATION);
mContext.sendBroadcast(intent, BLUETOOTH_ADMIN_PERM);
- // Release wakelock to allow the LCD to go off after the PIN popup notifcation.
+ // Release wakelock to allow the LCD to go off after the PIN popup notification.
mWakeLock.release();
return;
}
+ /**
+ * Called by native code on a RequestPasskey method call to
+ * org.bluez.Agent.
+ *
+ * @param objectPath the path of the device requesting a passkey
+ * @param nativeData a native pointer to the original D-Bus message
+ */
private void onRequestPasskey(String objectPath, int nativeData) {
String address = checkPairingRequestAndGetAddress(objectPath, nativeData);
if (address == null) return;
@@ -515,11 +617,18 @@ class BluetoothEventLoop {
intent.putExtra(BluetoothDevice.EXTRA_PAIRING_VARIANT,
BluetoothDevice.PAIRING_VARIANT_PASSKEY);
mContext.sendBroadcast(intent, BLUETOOTH_ADMIN_PERM);
- // Release wakelock to allow the LCD to go off after the PIN popup notifcation.
+ // Release wakelock to allow the LCD to go off after the PIN popup notification.
mWakeLock.release();
return;
}
+ /**
+ * Called by native code on a RequestPinCode method call to
+ * org.bluez.Agent.
+ *
+ * @param objectPath the path of the device requesting a PIN code
+ * @param nativeData a native pointer to the original D-Bus message
+ */
private void onRequestPinCode(String objectPath, int nativeData) {
String address = checkPairingRequestAndGetAddress(objectPath, nativeData);
if (address == null) return;
@@ -573,11 +682,19 @@ class BluetoothEventLoop {
intent.putExtra(BluetoothDevice.EXTRA_DEVICE, mAdapter.getRemoteDevice(address));
intent.putExtra(BluetoothDevice.EXTRA_PAIRING_VARIANT, BluetoothDevice.PAIRING_VARIANT_PIN);
mContext.sendBroadcast(intent, BLUETOOTH_ADMIN_PERM);
- // Release wakelock to allow the LCD to go off after the PIN popup notifcation.
+ // Release wakelock to allow the LCD to go off after the PIN popup notification.
mWakeLock.release();
return;
}
+ /**
+ * Called by native code on a DisplayPasskey method call to
+ * org.bluez.Agent.
+ *
+ * @param objectPath the path of the device to display the passkey for
+ * @param passkey an integer containing the 6-digit passkey
+ * @param nativeData a native pointer to the original D-Bus message
+ */
private void onDisplayPasskey(String objectPath, int passkey, int nativeData) {
String address = checkPairingRequestAndGetAddress(objectPath, nativeData);
if (address == null) return;
@@ -590,7 +707,7 @@ class BluetoothEventLoop {
intent.putExtra(BluetoothDevice.EXTRA_PAIRING_VARIANT,
BluetoothDevice.PAIRING_VARIANT_DISPLAY_PASSKEY);
mContext.sendBroadcast(intent, BLUETOOTH_ADMIN_PERM);
- //Release wakelock to allow the LCD to go off after the PIN popup notifcation.
+ //Release wakelock to allow the LCD to go off after the PIN popup notification.
mWakeLock.release();
}
@@ -607,7 +724,14 @@ class BluetoothEventLoop {
mWakeLock.release();
}
- private void onRequestOobData(String objectPath , int nativeData) {
+ /**
+ * Called by native code on a RequestOobData method call to
+ * org.bluez.Agent.
+ *
+ * @param objectPath the path of the device requesting OOB data
+ * @param nativeData a native pointer to the original D-Bus message
+ */
+ private void onRequestOobData(String objectPath, int nativeData) {
String address = checkPairingRequestAndGetAddress(objectPath, nativeData);
if (address == null) return;
@@ -618,6 +742,13 @@ class BluetoothEventLoop {
mContext.sendBroadcast(intent, BLUETOOTH_ADMIN_PERM);
}
+ /**
+ * Called by native code on an Authorize method call to org.bluez.Agent.
+ *
+ * @param objectPath the path of the device requesting to be authorized
+ * @param deviceUuid the UUID of the requesting device
+ * @return true if the authorization is allowed; false if not allowed
+ */
private boolean onAgentAuthorize(String objectPath, String deviceUuid) {
if (!mBluetoothService.isEnabled()) return false;
@@ -651,10 +782,9 @@ class BluetoothEventLoop {
} else {
Log.i(TAG, "Rejecting incoming A2DP / AVRCP connection from " + address);
}
- } else if (BluetoothUuid.isInputDevice(uuid) && !isOtherInputDeviceConnected(address)) {
- BluetoothInputDevice inputDevice = new BluetoothInputDevice(mContext);
- authorized = inputDevice.getInputDevicePriority(device) >
- BluetoothInputDevice.PRIORITY_OFF;
+ } else if (mInputDevice != null && BluetoothUuid.isInputDevice(uuid)) {
+ // We can have more than 1 input device connected.
+ authorized = mInputDevice.getPriority(device) > BluetoothInputDevice.PRIORITY_OFF;
if (authorized) {
Log.i(TAG, "Allowing incoming HID connection from " + address);
} else {
@@ -669,18 +799,6 @@ class BluetoothEventLoop {
return authorized;
}
- private boolean isOtherInputDeviceConnected(String address) {
- List<BluetoothDevice> devices =
- mBluetoothService.lookupInputDevicesMatchingStates(new int[] {
- BluetoothInputDevice.STATE_CONNECTING,
- BluetoothInputDevice.STATE_CONNECTED});
-
- for (BluetoothDevice device : devices) {
- if (!device.getAddress().equals(address)) return true;
- }
- return false;
- }
-
private boolean onAgentOutOfBandDataAvailable(String objectPath) {
if (!mBluetoothService.isEnabled()) return false;
@@ -707,6 +825,9 @@ class BluetoothEventLoop {
return false;
}
+ /**
+ * Called by native code on a Cancel method call to org.bluez.Agent.
+ */
private void onAgentCancel() {
Intent intent = new Intent(BluetoothDevice.ACTION_PAIRING_CANCEL);
mContext.sendBroadcast(intent, BLUETOOTH_ADMIN_PERM);
@@ -717,6 +838,13 @@ class BluetoothEventLoop {
return;
}
+ /**
+ * Called by native code for the async response to a DiscoverServices
+ * method call to org.bluez.Adapter.
+ *
+ * @param deviceObjectPath the path for the specified device
+ * @param result true for success; false on error
+ */
private void onDiscoverServicesResult(String deviceObjectPath, boolean result) {
String address = mBluetoothService.getAddressFromObjectPath(deviceObjectPath);
if (address == null) return;
@@ -729,6 +857,14 @@ class BluetoothEventLoop {
mBluetoothService.makeServiceChannelCallbacks(address);
}
+ /**
+ * Called by native code for the async response to a CreateDevice
+ * method call to org.bluez.Adapter.
+ *
+ * @param address the MAC address of the device to create
+ * @param result {@link #CREATE_DEVICE_SUCCESS},
+ * {@link #CREATE_DEVICE_ALREADY_EXISTS} or {@link #CREATE_DEVICE_FAILED}}
+ */
private void onCreateDeviceResult(String address, int result) {
if (DBG) log("Result of onCreateDeviceResult:" + result);
@@ -739,7 +875,7 @@ class BluetoothEventLoop {
mBluetoothService.discoverServicesNative(path, "");
break;
}
- Log.w(TAG, "Device exists, but we dont have the bluez path, failing");
+ Log.w(TAG, "Device exists, but we don't have the bluez path, failing");
// fall-through
case CREATE_DEVICE_FAILED:
mBluetoothService.sendUuidIntent(address);
@@ -750,6 +886,13 @@ class BluetoothEventLoop {
}
}
+ /**
+ * Called by native code for the async response to a Connect
+ * method call to org.bluez.Input.
+ *
+ * @param path the path of the specified input device
+ * @param result Result code of the operation.
+ */
private void onInputDeviceConnectionResult(String path, int result) {
// Success case gets handled by Property Change signal
if (result != BluetoothInputDevice.INPUT_OPERATION_SUCCESS) {
@@ -758,7 +901,7 @@ class BluetoothEventLoop {
boolean connected = false;
BluetoothDevice device = mAdapter.getRemoteDevice(address);
- int state = mBluetoothService.getInputDeviceState(device);
+ int state = mBluetoothService.getInputDeviceConnectionState(device);
if (state == BluetoothInputDevice.STATE_CONNECTING) {
if (result == BluetoothInputDevice.INPUT_CONNECT_FAILED_ALREADY_CONNECTED) {
connected = true;
@@ -779,6 +922,13 @@ class BluetoothEventLoop {
}
}
+ /**
+ * Called by native code for the async response to a Connect
+ * method call to org.bluez.Network.
+ *
+ * @param path the path of the specified PAN device
+ * @param result Result code of the operation.
+ */
private void onPanDeviceConnectionResult(String path, int result) {
log ("onPanDeviceConnectionResult " + path + " " + result);
// Success case gets handled by Property Change signal
@@ -788,7 +938,7 @@ class BluetoothEventLoop {
boolean connected = false;
BluetoothDevice device = mAdapter.getRemoteDevice(address);
- int state = mBluetoothService.getPanDeviceState(device);
+ int state = mBluetoothService.getPanDeviceConnectionState(device);
if (state == BluetoothPan.STATE_CONNECTING) {
if (result == BluetoothPan.PAN_CONNECT_FAILED_ALREADY_CONNECTED) {
connected = true;
@@ -813,12 +963,26 @@ class BluetoothEventLoop {
}
}
+ /**
+ * Called by native code on a DeviceDisconnected signal from
+ * org.bluez.NetworkServer.
+ *
+ * @param address the MAC address of the disconnected device
+ */
private void onNetworkDeviceDisconnected(String address) {
BluetoothDevice device = mAdapter.getRemoteDevice(address);
mBluetoothService.handlePanDeviceStateChange(device, BluetoothPan.STATE_DISCONNECTED,
BluetoothPan.LOCAL_NAP_ROLE);
}
+ /**
+ * Called by native code on a DeviceConnected signal from
+ * org.bluez.NetworkServer.
+ *
+ * @param address the MAC address of the connected device
+ * @param iface interface of remote network
+ * @param destUuid unused UUID parameter
+ */
private void onNetworkDeviceConnected(String address, String iface, int destUuid) {
BluetoothDevice device = mAdapter.getRemoteDevice(address);
mBluetoothService.handlePanDeviceStateChange(device, iface, BluetoothPan.STATE_CONNECTED,
diff --git a/core/java/android/server/BluetoothInputProfileHandler.java b/core/java/android/server/BluetoothInputProfileHandler.java
index 7ffa5ae..e6513fd 100644
--- a/core/java/android/server/BluetoothInputProfileHandler.java
+++ b/core/java/android/server/BluetoothInputProfileHandler.java
@@ -64,7 +64,7 @@ final class BluetoothInputProfileHandler {
BluetoothDeviceProfileState state) {
String objectPath = mBluetoothService.getObjectPathFromAddress(device.getAddress());
if (objectPath == null ||
- getInputDeviceState(device) != BluetoothInputDevice.STATE_DISCONNECTED ||
+ getInputDeviceConnectionState(device) != BluetoothInputDevice.STATE_DISCONNECTED ||
getInputDevicePriority(device) == BluetoothInputDevice.PRIORITY_OFF) {
return false;
}
@@ -92,7 +92,7 @@ final class BluetoothInputProfileHandler {
BluetoothDeviceProfileState state) {
String objectPath = mBluetoothService.getObjectPathFromAddress(device.getAddress());
if (objectPath == null ||
- getInputDeviceState(device) == BluetoothInputDevice.STATE_DISCONNECTED) {
+ getInputDeviceConnectionState(device) == BluetoothInputDevice.STATE_DISCONNECTED) {
return false;
}
if (state != null) {
@@ -115,7 +115,7 @@ final class BluetoothInputProfileHandler {
return true;
}
- synchronized int getInputDeviceState(BluetoothDevice device) {
+ synchronized int getInputDeviceConnectionState(BluetoothDevice device) {
if (mInputDevices.get(device) == null) {
return BluetoothInputDevice.STATE_DISCONNECTED;
}
@@ -128,6 +128,11 @@ final class BluetoothInputProfileHandler {
return devices;
}
+ synchronized List<BluetoothDevice> getInputDevicesMatchingConnectionStates(int[] states) {
+ List<BluetoothDevice> devices = lookupInputDevicesMatchingStates(states);
+ return devices;
+ }
+
synchronized int getInputDevicePriority(BluetoothDevice device) {
return Settings.Secure.getInt(mContext.getContentResolver(),
Settings.Secure.getBluetoothInputDevicePriorityKey(device.getAddress()),
@@ -147,7 +152,7 @@ final class BluetoothInputProfileHandler {
List<BluetoothDevice> inputDevices = new ArrayList<BluetoothDevice>();
for (BluetoothDevice device: mInputDevices.keySet()) {
- int inputDeviceState = getInputDeviceState(device);
+ int inputDeviceState = getInputDeviceConnectionState(device);
for (int state : states) {
if (state == inputDeviceState) {
inputDevices.add(device);
@@ -178,10 +183,11 @@ final class BluetoothInputProfileHandler {
setInputDevicePriority(device, BluetoothInputDevice.PRIORITY_AUTO_CONNECT);
}
- Intent intent = new Intent(BluetoothInputDevice.ACTION_INPUT_DEVICE_STATE_CHANGED);
+ Intent intent = new Intent(BluetoothInputDevice.ACTION_CONNECTION_STATE_CHANGED);
intent.putExtra(BluetoothDevice.EXTRA_DEVICE, device);
- intent.putExtra(BluetoothInputDevice.EXTRA_PREVIOUS_INPUT_DEVICE_STATE, prevState);
- intent.putExtra(BluetoothInputDevice.EXTRA_INPUT_DEVICE_STATE, state);
+ intent.putExtra(BluetoothInputDevice.EXTRA_PREVIOUS_STATE, prevState);
+ intent.putExtra(BluetoothInputDevice.EXTRA_STATE, state);
+ intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
mContext.sendBroadcast(intent, BluetoothService.BLUETOOTH_PERM);
debugLog("InputDevice state : device: " + device + " State:" + prevState + "->" + state);
diff --git a/core/java/android/server/BluetoothPanProfileHandler.java b/core/java/android/server/BluetoothPanProfileHandler.java
index 5476d7b..8925856 100644
--- a/core/java/android/server/BluetoothPanProfileHandler.java
+++ b/core/java/android/server/BluetoothPanProfileHandler.java
@@ -59,6 +59,9 @@ final class BluetoothPanProfileHandler {
private Context mContext;
private BluetoothService mBluetoothService;
+ static final String NAP_ROLE = "nap";
+ static final String NAP_BRIDGE = "pan1";
+
private BluetoothPanProfileHandler(Context context, BluetoothService service) {
mContext = context;
mPanDevices = new HashMap<BluetoothDevice, BluetoothPanDevice>();
@@ -115,7 +118,7 @@ final class BluetoothPanProfileHandler {
}
}
- synchronized int getPanDeviceState(BluetoothDevice device) {
+ synchronized int getPanDeviceConnectionState(BluetoothDevice device) {
BluetoothPanDevice panDevice = mPanDevices.get(device);
if (panDevice == null) {
return BluetoothPan.STATE_DISCONNECTED;
@@ -126,13 +129,13 @@ final class BluetoothPanProfileHandler {
synchronized boolean connectPanDevice(BluetoothDevice device) {
String objectPath = mBluetoothService.getObjectPathFromAddress(device.getAddress());
if (DBG) Log.d(TAG, "connect PAN(" + objectPath + ")");
- if (getPanDeviceState(device) != BluetoothPan.STATE_DISCONNECTED) {
+ if (getPanDeviceConnectionState(device) != BluetoothPan.STATE_DISCONNECTED) {
errorLog(device + " already connected to PAN");
}
int connectedCount = 0;
for (BluetoothDevice panDevice: mPanDevices.keySet()) {
- if (getPanDeviceState(panDevice) == BluetoothPan.STATE_CONNECTED) {
+ if (getPanDeviceConnectionState(panDevice) == BluetoothPan.STATE_CONNECTED) {
connectedCount ++;
}
}
@@ -188,18 +191,33 @@ final class BluetoothPanProfileHandler {
List<BluetoothDevice> devices = new ArrayList<BluetoothDevice>();
for (BluetoothDevice device: mPanDevices.keySet()) {
- if (getPanDeviceState(device) == BluetoothPan.STATE_CONNECTED) {
+ if (getPanDeviceConnectionState(device) == BluetoothPan.STATE_CONNECTED) {
devices.add(device);
}
}
return devices;
}
+ synchronized List<BluetoothDevice> getPanDevicesMatchingConnectionStates(int[] states) {
+ List<BluetoothDevice> devices = new ArrayList<BluetoothDevice>();
+
+ for (BluetoothDevice device: mPanDevices.keySet()) {
+ int panDeviceState = getPanDeviceConnectionState(device);
+ for (int state : states) {
+ if (state == panDeviceState) {
+ devices.add(device);
+ break;
+ }
+ }
+ }
+ return devices;
+ }
+
synchronized boolean disconnectPanDevice(BluetoothDevice device) {
String objectPath = mBluetoothService.getObjectPathFromAddress(device.getAddress());
debugLog("disconnect PAN(" + objectPath + ")");
- int state = getPanDeviceState(device);
+ int state = getPanDeviceConnectionState(device);
if (state != BluetoothPan.STATE_CONNECTED) {
debugLog(device + " already disconnected from PAN");
return false;
@@ -275,14 +293,10 @@ final class BluetoothPanProfileHandler {
panDevice.mLocalRole = role;
}
- if (state == BluetoothPan.STATE_DISCONNECTED) {
- mPanDevices.remove(device);
- }
-
- Intent intent = new Intent(BluetoothPan.ACTION_PAN_STATE_CHANGED);
+ Intent intent = new Intent(BluetoothPan.ACTION_CONNECTION_STATE_CHANGED);
intent.putExtra(BluetoothDevice.EXTRA_DEVICE, device);
- intent.putExtra(BluetoothPan.EXTRA_PREVIOUS_PAN_STATE, prevState);
- intent.putExtra(BluetoothPan.EXTRA_PAN_STATE, state);
+ intent.putExtra(BluetoothPan.EXTRA_PREVIOUS_STATE, prevState);
+ intent.putExtra(BluetoothPan.EXTRA_STATE, state);
intent.putExtra(BluetoothPan.EXTRA_LOCAL_ROLE, role);
mContext.sendBroadcast(intent, BluetoothService.BLUETOOTH_PERM);
diff --git a/core/java/android/server/BluetoothService.java b/core/java/android/server/BluetoothService.java
index a295de5..f98d275 100644
--- a/core/java/android/server/BluetoothService.java
+++ b/core/java/android/server/BluetoothService.java
@@ -31,6 +31,7 @@ import android.bluetooth.BluetoothClass;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothDeviceProfileState;
import android.bluetooth.BluetoothHeadset;
+import android.bluetooth.BluetoothInputDevice;
import android.bluetooth.BluetoothPan;
import android.bluetooth.BluetoothProfile;
import android.bluetooth.BluetoothProfileState;
@@ -56,17 +57,12 @@ import android.util.Log;
import android.util.Pair;
import java.io.BufferedInputStream;
-import java.io.BufferedReader;
import java.io.BufferedWriter;
-import java.io.DataInputStream;
-import java.io.File;
import java.io.FileDescriptor;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
-import java.io.FileOutputStream;
import java.io.FileWriter;
import java.io.IOException;
-import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.io.UnsupportedEncodingException;
import java.util.ArrayList;
@@ -83,6 +79,8 @@ public class BluetoothService extends IBluetooth.Stub {
private int mNativeData;
private BluetoothEventLoop mEventLoop;
private BluetoothHeadset mBluetoothHeadset;
+ private BluetoothInputDevice mInputDevice;
+ private BluetoothPan mPan;
private boolean mIsAirplaneSensitive;
private boolean mIsAirplaneToggleable;
private int mBluetoothState;
@@ -92,7 +90,7 @@ public class BluetoothService extends IBluetooth.Stub {
private ParcelUuid[] mAdapterUuids;
private BluetoothAdapter mAdapter; // constant after init()
- private final BondState mBondState = new BondState(); // local cache of bondings
+ private final BluetoothBondState mBondState; // local cache of bondings
private final IBatteryStats mBatteryStats;
private final Context mContext;
@@ -126,9 +124,8 @@ public class BluetoothService extends IBluetooth.Stub {
BluetoothUuid.HSP,
BluetoothUuid.ObexObjectPush };
- // TODO(): Optimize all these string handling
- private final Map<String, String> mAdapterProperties;
- private final HashMap<String, Map<String, String>> mDeviceProperties;
+ private final BluetoothAdapterProperties mAdapterProperties;
+ private final BluetoothDeviceProperties mDeviceProperties;
private final HashMap<String, Map<ParcelUuid, Integer>> mDeviceServiceChannelCache;
private final ArrayList<String> mUuidIntentTracker;
@@ -200,8 +197,9 @@ public class BluetoothService extends IBluetooth.Stub {
mBluetoothState = BluetoothAdapter.STATE_OFF;
mIsDiscovering = false;
- mAdapterProperties = new HashMap<String, String>();
- mDeviceProperties = new HashMap<String, Map<String,String>>();
+ mBondState = new BluetoothBondState(context, this);
+ mAdapterProperties = new BluetoothAdapterProperties(context, this);
+ mDeviceProperties = new BluetoothDeviceProperties(this);
mDeviceServiceChannelCache = new HashMap<String, Map<ParcelUuid, Integer>>();
mDeviceOobData = new HashMap<String, Pair<byte[], byte[]>>();
@@ -239,12 +237,13 @@ public class BluetoothService extends IBluetooth.Stub {
mDockAddress = dockAddress;
return mDockAddress;
} else {
- log("CheckBluetoothAddress failed for car dock address:" + dockAddress);
+ Log.e(TAG, "CheckBluetoothAddress failed for car dock address: "
+ + dockAddress);
}
} catch (FileNotFoundException e) {
- log("FileNotFoundException while trying to read dock address");
+ Log.e(TAG, "FileNotFoundException while trying to read dock address");
} catch (IOException e) {
- log("IOException while trying to read dock address");
+ Log.e(TAG, "IOException while trying to read dock address");
} finally {
if (file != null) {
try {
@@ -271,9 +270,9 @@ public class BluetoothService extends IBluetooth.Stub {
out.write(mDockPin);
return true;
} catch (FileNotFoundException e) {
- log("FileNotFoundException while trying to write dock pairing pin");
+ Log.e(TAG, "FileNotFoundException while trying to write dock pairing pin");
} catch (IOException e) {
- log("IOException while while trying to write dock pairing pin");
+ Log.e(TAG, "IOException while while trying to write dock pairing pin");
} finally {
if (out != null) {
try {
@@ -324,6 +323,9 @@ public class BluetoothService extends IBluetooth.Stub {
return mBluetoothState;
}
+ int getBluetoothStateInternal() {
+ return mBluetoothState;
+ }
/**
* Bring down bluetooth and disable BT in settings. Returns true on success.
@@ -355,7 +357,8 @@ public class BluetoothService extends IBluetooth.Stub {
setBluetoothState(BluetoothAdapter.STATE_TURNING_OFF);
if (mAdapterSdpHandles != null) removeReservedServiceRecordsNative(mAdapterSdpHandles);
- setBluetoothTetheringNative(false, BluetoothPan.NAP_ROLE, BluetoothPan.NAP_BRIDGE);
+ setBluetoothTetheringNative(false, BluetoothPanProfileHandler.NAP_ROLE,
+ BluetoothPanProfileHandler.NAP_BRIDGE);
// Allow 3 seconds for profiles to gracefully disconnect
// TODO: Introduce a callback mechanism so that each profile can notify
@@ -482,7 +485,7 @@ public class BluetoothService extends IBluetooth.Stub {
return;
}
- if (DBG) log("Bluetooth state " + mBluetoothState + " -> " + state);
+ if (DBG) Log.d(TAG, "Bluetooth state " + mBluetoothState + " -> " + state);
Intent intent = new Intent(BluetoothAdapter.ACTION_STATE_CHANGED);
intent.putExtra(BluetoothAdapter.EXTRA_PREVIOUS_STATE, mBluetoothState);
@@ -533,7 +536,7 @@ public class BluetoothService extends IBluetooth.Stub {
boolean running = false;
while ((retryCount-- > 0) && !running) {
mEventLoop.start();
- // it may take a momement for the other thread to do its
+ // it may take a moment for the other thread to do its
// thing. Check periodically for a while.
int pollCount = 5;
while ((pollCount-- > 0) && !running) {
@@ -547,7 +550,7 @@ public class BluetoothService extends IBluetooth.Stub {
}
}
if (!running) {
- log("bt EnableThread giving up");
+ Log.e(TAG, "bt EnableThread giving up");
res = false;
disableNative();
}
@@ -604,7 +607,8 @@ public class BluetoothService extends IBluetooth.Stub {
addReservedSdpRecords(uuids);
// Enable profiles maintained by Bluez userspace.
- setBluetoothTetheringNative(true, BluetoothPan.NAP_ROLE, BluetoothPan.NAP_BRIDGE);
+ setBluetoothTetheringNative(true, BluetoothPanProfileHandler.NAP_ROLE,
+ BluetoothPanProfileHandler.NAP_BRIDGE);
// Add SDP records for profiles maintained by Bluez userspace
uuids.add(BluetoothUuid.AudioSource);
@@ -630,6 +634,7 @@ public class BluetoothService extends IBluetooth.Stub {
if (mAdapterUuids != null &&
BluetoothUuid.containsAllUuids(adapterUuids, mAdapterUuids)) {
setBluetoothState(BluetoothAdapter.STATE_ON);
+ autoConnect();
String[] propVal = {"Pairable", getProperty("Pairable")};
mEventLoop.onPropertyChanged(propVal);
@@ -725,316 +730,8 @@ public class BluetoothService extends IBluetooth.Stub {
mBondState.attempt(address);
}
- /** local cache of bonding state.
- /* we keep our own state to track the intermediate state BONDING, which
- /* bluez does not track.
- * All addresses must be passed in upper case.
- */
- public class BondState {
- private final HashMap<String, Integer> mState = new HashMap<String, Integer>();
- private final HashMap<String, Integer> mPinAttempt = new HashMap<String, Integer>();
-
- private static final String AUTO_PAIRING_BLACKLIST =
- "/etc/bluetooth/auto_pairing.conf";
- private static final String DYNAMIC_AUTO_PAIRING_BLACKLIST =
- "/data/misc/bluetooth/dynamic_auto_pairing.conf";
- private ArrayList<String> mAutoPairingAddressBlacklist;
- private ArrayList<String> mAutoPairingExactNameBlacklist;
- private ArrayList<String> mAutoPairingPartialNameBlacklist;
- private ArrayList<String> mAutoPairingFixedPinZerosKeyboardList;
- // Addresses added to blacklist dynamically based on usage.
- private ArrayList<String> mAutoPairingDynamicAddressBlacklist;
-
-
- // If this is an outgoing connection, store the address.
- // There can be only 1 pending outgoing connection at a time,
- private String mPendingOutgoingBonding;
-
- private synchronized void setPendingOutgoingBonding(String address) {
- mPendingOutgoingBonding = address;
- }
-
- public synchronized String getPendingOutgoingBonding() {
- return mPendingOutgoingBonding;
- }
-
- public synchronized void loadBondState() {
- if (mBluetoothState != BluetoothAdapter.STATE_TURNING_ON) {
- return;
- }
- String []bonds = null;
- String val = getPropertyInternal("Devices");
- if (val != null) {
- bonds = val.split(",");
- }
- if (bonds == null) {
- return;
- }
- mState.clear();
- if (DBG) log("found " + bonds.length + " bonded devices");
- for (String device : bonds) {
- mState.put(getAddressFromObjectPath(device).toUpperCase(),
- BluetoothDevice.BOND_BONDED);
- }
- }
-
- public synchronized void setBondState(String address, int state) {
- setBondState(address, state, 0);
- }
-
- /** reason is ignored unless state == BOND_NOT_BONDED */
- public synchronized void setBondState(String address, int state, int reason) {
- int oldState = getBondState(address);
- if (oldState == state) {
- return;
- }
-
- // Check if this was an pending outgoing bonding.
- // If yes, reset the state.
- if (oldState == BluetoothDevice.BOND_BONDING) {
- if (address.equals(mPendingOutgoingBonding)) {
- mPendingOutgoingBonding = null;
- }
- }
-
- if (state == BluetoothDevice.BOND_BONDED) {
- addProfileState(address);
- } else if (state == BluetoothDevice.BOND_NONE) {
- removeProfileState(address);
- }
-
- // HID is handled by BluetoothService, other profiles
- // will be handled by their respective services.
- mBluetoothInputProfileHandler.setInitialInputDevicePriority(
- mAdapter.getRemoteDevice(address), state);
-
- if (DBG) log(address + " bond state " + oldState + " -> " + state + " (" +
- reason + ")");
- Intent intent = new Intent(BluetoothDevice.ACTION_BOND_STATE_CHANGED);
- intent.putExtra(BluetoothDevice.EXTRA_DEVICE, mAdapter.getRemoteDevice(address));
- intent.putExtra(BluetoothDevice.EXTRA_BOND_STATE, state);
- intent.putExtra(BluetoothDevice.EXTRA_PREVIOUS_BOND_STATE, oldState);
- if (state == BluetoothDevice.BOND_NONE) {
- if (reason <= 0) {
- Log.w(TAG, "setBondState() called to unbond device, but reason code is " +
- "invalid. Overriding reason code with BOND_RESULT_REMOVED");
- reason = BluetoothDevice.UNBOND_REASON_REMOVED;
- }
- intent.putExtra(BluetoothDevice.EXTRA_REASON, reason);
- mState.remove(address);
- } else {
- mState.put(address, state);
- }
-
- mContext.sendBroadcast(intent, BLUETOOTH_PERM);
- }
-
- public boolean isAutoPairingBlacklisted(String address) {
- if (mAutoPairingAddressBlacklist != null) {
- for (String blacklistAddress : mAutoPairingAddressBlacklist) {
- if (address.startsWith(blacklistAddress)) return true;
- }
- }
-
- if (mAutoPairingDynamicAddressBlacklist != null) {
- for (String blacklistAddress: mAutoPairingDynamicAddressBlacklist) {
- if (address.equals(blacklistAddress)) return true;
- }
- }
- String name = getRemoteName(address);
- if (name != null) {
- if (mAutoPairingExactNameBlacklist != null) {
- for (String blacklistName : mAutoPairingExactNameBlacklist) {
- if (name.equals(blacklistName)) return true;
- }
- }
-
- if (mAutoPairingPartialNameBlacklist != null) {
- for (String blacklistName : mAutoPairingPartialNameBlacklist) {
- if (name.startsWith(blacklistName)) return true;
- }
- }
- }
- return false;
- }
-
- public boolean isFixedPinZerosAutoPairKeyboard(String address) {
- // Note: the meaning of blacklist is reversed in this case.
- // If its in the list, we can go ahead and auto pair since
- // by default keyboard should have a variable PIN that we don't
- // auto pair using 0000.
- if (mAutoPairingFixedPinZerosKeyboardList != null) {
- for (String blacklistAddress : mAutoPairingFixedPinZerosKeyboardList) {
- if (address.startsWith(blacklistAddress)) return true;
- }
- }
- return false;
- }
-
- public synchronized int getBondState(String address) {
- Integer state = mState.get(address);
- if (state == null) {
- return BluetoothDevice.BOND_NONE;
- }
- return state.intValue();
- }
-
- /*package*/ synchronized String[] listInState(int state) {
- ArrayList<String> result = new ArrayList<String>(mState.size());
- for (Map.Entry<String, Integer> e : mState.entrySet()) {
- if (e.getValue().intValue() == state) {
- result.add(e.getKey());
- }
- }
- return result.toArray(new String[result.size()]);
- }
-
- public synchronized void addAutoPairingFailure(String address) {
- if (mAutoPairingDynamicAddressBlacklist == null) {
- mAutoPairingDynamicAddressBlacklist = new ArrayList<String>();
- }
-
- updateAutoPairingData(address);
- mAutoPairingDynamicAddressBlacklist.add(address);
- }
-
- public synchronized boolean isAutoPairingAttemptsInProgress(String address) {
- return getAttempt(address) != 0;
- }
-
- public synchronized void clearPinAttempts(String address) {
- mPinAttempt.remove(address);
- }
-
- public synchronized boolean hasAutoPairingFailed(String address) {
- if (mAutoPairingDynamicAddressBlacklist == null) return false;
-
- return mAutoPairingDynamicAddressBlacklist.contains(address);
- }
-
- public synchronized int getAttempt(String address) {
- Integer attempt = mPinAttempt.get(address);
- if (attempt == null) {
- return 0;
- }
- return attempt.intValue();
- }
-
- public synchronized void attempt(String address) {
- Integer attempt = mPinAttempt.get(address);
- int newAttempt;
- if (attempt == null) {
- newAttempt = 1;
- } else {
- newAttempt = attempt.intValue() + 1;
- }
- mPinAttempt.put(address, new Integer(newAttempt));
- }
-
- private void copyAutoPairingData() {
- File file = null;
- FileInputStream in = null;
- FileOutputStream out = null;
- try {
- file = new File(DYNAMIC_AUTO_PAIRING_BLACKLIST);
-
- in = new FileInputStream(AUTO_PAIRING_BLACKLIST);
- out= new FileOutputStream(DYNAMIC_AUTO_PAIRING_BLACKLIST);
-
- byte[] buf = new byte[1024];
- int len;
- while ((len = in.read(buf)) > 0) {
- out.write(buf, 0, len);
- }
- } catch (FileNotFoundException e) {
- log("FileNotFoundException: in copyAutoPairingData");
- } catch (IOException e) {
- log("IOException: in copyAutoPairingData");
- } finally {
- try {
- if (in != null) in.close();
- if (out != null) out.close();
- } catch (IOException e) {}
- }
- }
-
- public void readAutoPairingData() {
- if (mAutoPairingAddressBlacklist != null) return;
- copyAutoPairingData();
- FileInputStream fstream = null;
- try {
- fstream = new FileInputStream(DYNAMIC_AUTO_PAIRING_BLACKLIST);
- DataInputStream in = new DataInputStream(fstream);
- BufferedReader file = new BufferedReader(new InputStreamReader(in));
- String line;
- while((line = file.readLine()) != null) {
- line = line.trim();
- if (line.length() == 0 || line.startsWith("//")) continue;
- String[] value = line.split("=");
- if (value != null && value.length == 2) {
- String[] val = value[1].split(",");
- if (value[0].equalsIgnoreCase("AddressBlacklist")) {
- mAutoPairingAddressBlacklist =
- new ArrayList<String>(Arrays.asList(val));
- } else if (value[0].equalsIgnoreCase("ExactNameBlacklist")) {
- mAutoPairingExactNameBlacklist =
- new ArrayList<String>(Arrays.asList(val));
- } else if (value[0].equalsIgnoreCase("PartialNameBlacklist")) {
- mAutoPairingPartialNameBlacklist =
- new ArrayList<String>(Arrays.asList(val));
- } else if (value[0].equalsIgnoreCase("FixedPinZerosKeyboardBlacklist")) {
- mAutoPairingFixedPinZerosKeyboardList =
- new ArrayList<String>(Arrays.asList(val));
- } else if (value[0].equalsIgnoreCase("DynamicAddressBlacklist")) {
- mAutoPairingDynamicAddressBlacklist =
- new ArrayList<String>(Arrays.asList(val));
- } else {
- Log.e(TAG, "Error parsing Auto pairing blacklist file");
- }
- }
- }
- } catch (FileNotFoundException e) {
- log("FileNotFoundException: readAutoPairingData" + e.toString());
- } catch (IOException e) {
- log("IOException: readAutoPairingData" + e.toString());
- } finally {
- if (fstream != null) {
- try {
- fstream.close();
- } catch (IOException e) {
- // Ignore
- }
- }
- }
- }
-
- // This function adds a bluetooth address to the auto pairing blacklist
- // file. These addresses are added to DynamicAddressBlacklistSection
- private void updateAutoPairingData(String address) {
- BufferedWriter out = null;
- try {
- out = new BufferedWriter(new FileWriter(DYNAMIC_AUTO_PAIRING_BLACKLIST, true));
- StringBuilder str = new StringBuilder();
- if (mAutoPairingDynamicAddressBlacklist.size() == 0) {
- str.append("DynamicAddressBlacklist=");
- }
- str.append(address);
- str.append(",");
- out.write(str.toString());
- } catch (FileNotFoundException e) {
- log("FileNotFoundException: updateAutoPairingData" + e.toString());
- } catch (IOException e) {
- log("IOException: updateAutoPairingData" + e.toString());
- } finally {
- if (out != null) {
- try {
- out.close();
- } catch (IOException e) {
- // Ignore
- }
- }
- }
- }
+ /*package*/ BluetoothDevice getRemoteDevice(String address) {
+ return mAdapter.getRemoteDevice(address);
}
private static String toBondStateString(int bondState) {
@@ -1050,56 +747,6 @@ public class BluetoothService extends IBluetooth.Stub {
}
}
- /*package*/ synchronized boolean isAdapterPropertiesEmpty() {
- return mAdapterProperties.isEmpty();
- }
-
- /*package*/synchronized void getAllProperties() {
-
- mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
- mAdapterProperties.clear();
-
- String properties[] = (String [])getAdapterPropertiesNative();
- // The String Array consists of key-value pairs.
- if (properties == null) {
- Log.e(TAG, "*Error*: GetAdapterProperties returned NULL");
- return;
- }
-
- for (int i = 0; i < properties.length; i++) {
- String name = properties[i];
- String newValue = null;
- int len;
- if (name == null) {
- Log.e(TAG, "Error:Adapter Property at index" + i + "is null");
- continue;
- }
- if (name.equals("Devices") || name.equals("UUIDs")) {
- StringBuilder str = new StringBuilder();
- len = Integer.valueOf(properties[++i]);
- for (int j = 0; j < len; j++) {
- str.append(properties[++i]);
- str.append(",");
- }
- if (len > 0) {
- newValue = str.toString();
- }
- } else {
- newValue = properties[++i];
- }
- mAdapterProperties.put(name, newValue);
- }
-
- // Add adapter object path property.
- String adapterPath = getAdapterPathNative();
- if (adapterPath != null)
- mAdapterProperties.put("ObjectPath", adapterPath + "/dev_");
- }
-
- /* package */ synchronized void setProperty(String name, String value) {
- mAdapterProperties.put(name, value);
- }
-
public synchronized boolean setName(String name) {
mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
"Need BLUETOOTH_ADMIN permission");
@@ -1149,8 +796,8 @@ public class BluetoothService extends IBluetooth.Stub {
public synchronized boolean setScanMode(int mode, int duration) {
mContext.enforceCallingOrSelfPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS,
"Need WRITE_SECURE_SETTINGS permission");
- boolean pairable = false;
- boolean discoverable = false;
+ boolean pairable;
+ boolean discoverable;
switch (mode) {
case BluetoothAdapter.SCAN_MODE_NONE:
@@ -1178,14 +825,27 @@ public class BluetoothService extends IBluetooth.Stub {
/*package*/ synchronized String getProperty(String name) {
if (!isEnabledInternal()) return null;
- return getPropertyInternal(name);
+ return mAdapterProperties.getProperty(name);
+ }
+
+ BluetoothAdapterProperties getAdapterProperties() {
+ return mAdapterProperties;
+ }
+
+ BluetoothDeviceProperties getDeviceProperties() {
+ return mDeviceProperties;
}
- /*package*/ synchronized String getPropertyInternal(String name) {
- if (!mAdapterProperties.isEmpty())
- return mAdapterProperties.get(name);
- getAllProperties();
- return mAdapterProperties.get(name);
+ boolean isRemoteDeviceInCache(String address) {
+ return mDeviceProperties.isInCache(address);
+ }
+
+ void setRemoteDeviceProperty(String address, String name, String value) {
+ mDeviceProperties.setProperty(address, name, value);
+ }
+
+ void updateRemoteDevicePropertiesCache(String address) {
+ mDeviceProperties.updateCache(address);
}
public synchronized String getAddress() {
@@ -1234,7 +894,7 @@ public class BluetoothService extends IBluetooth.Stub {
if (!BluetoothAdapter.checkBluetoothAddress(address)) {
return null;
}
- return getRemoteDeviceProperty(address, "Name");
+ return mDeviceProperties.getProperty(address, "Name");
}
/**
@@ -1300,7 +960,7 @@ public class BluetoothService extends IBluetooth.Stub {
address = address.toUpperCase();
if (mBondState.getPendingOutgoingBonding() != null) {
- log("Ignoring createBond(): another device is bonding");
+ Log.d(TAG, "Ignoring createBond(): another device is bonding");
// a different device is currently bonding, fail
return false;
}
@@ -1309,13 +969,13 @@ public class BluetoothService extends IBluetooth.Stub {
// pairing exponential back-off attempts.
if (!mBondState.isAutoPairingAttemptsInProgress(address) &&
mBondState.getBondState(address) != BluetoothDevice.BOND_NONE) {
- log("Ignoring createBond(): this device is already bonding or bonded");
+ Log.d(TAG, "Ignoring createBond(): this device is already bonding or bonded");
return false;
}
if (address.equals(mDockAddress)) {
if (!writeDockPin()) {
- log("Error while writing Pin for the dock");
+ Log.e(TAG, "Error while writing Pin for the dock");
return false;
}
}
@@ -1359,8 +1019,8 @@ public class BluetoothService extends IBluetooth.Stub {
Pair <byte[], byte[]> value = new Pair<byte[], byte[]>(hash, randomizer);
if (DBG) {
- log("Setting out of band data for:" + address + ":" +
- Arrays.toString(hash) + ":" + Arrays.toString(randomizer));
+ Log.d(TAG, "Setting out of band data for: " + address + ":" +
+ Arrays.toString(hash) + ":" + Arrays.toString(randomizer));
}
mDeviceOobData.put(address, value);
@@ -1417,6 +1077,8 @@ public class BluetoothService extends IBluetooth.Stub {
}
public synchronized boolean removeBondInternal(String address) {
+ // Unset the trusted device state and then unpair
+ setTrust(address, false);
return removeDeviceNative(getObjectPathFromAddress(address));
}
@@ -1448,7 +1110,7 @@ public class BluetoothService extends IBluetooth.Stub {
public synchronized boolean isBluetoothDock(String address) {
SharedPreferences sp = mContext.getSharedPreferences(SHARED_PREFERENCES_NAME,
- mContext.MODE_PRIVATE);
+ Context.MODE_PRIVATE);
return sp.contains(SHARED_PREFERENCE_DOCK_ADDRESS + address);
}
@@ -1460,85 +1122,6 @@ public class BluetoothService extends IBluetooth.Stub {
return (String [])getDevicePropertiesNative(objectPath);
}
- /*package*/ synchronized String getRemoteDeviceProperty(String address, String property) {
- Map<String, String> properties = mDeviceProperties.get(address);
- if (properties != null) {
- return properties.get(property);
- } else {
- // Query for remote device properties, again.
- // We will need to reload the cache when we switch Bluetooth on / off
- // or if we crash.
- if (updateRemoteDevicePropertiesCache(address))
- return getRemoteDeviceProperty(address, property);
- }
- Log.e(TAG, "getRemoteDeviceProperty: " + property + " not present: " + address);
- return null;
- }
-
- /* package */ synchronized boolean updateRemoteDevicePropertiesCache(String address) {
- String[] propValues = getRemoteDeviceProperties(address);
- if (propValues != null) {
- addRemoteDeviceProperties(address, propValues);
- return true;
- }
- return false;
- }
-
- /* package */ synchronized void addRemoteDeviceProperties(String address, String[] properties) {
- /*
- * We get a DeviceFound signal every time RSSI changes or name changes.
- * Don't create a new Map object every time */
- Map<String, String> propertyValues = mDeviceProperties.get(address);
- if (propertyValues == null) {
- propertyValues = new HashMap<String, String>();
- }
-
- for (int i = 0; i < properties.length; i++) {
- String name = properties[i];
- String newValue = null;
- int len;
- if (name == null) {
- Log.e(TAG, "Error: Remote Device Property at index" + i + "is null");
- continue;
- }
- if (name.equals("UUIDs") || name.equals("Nodes")) {
- StringBuilder str = new StringBuilder();
- len = Integer.valueOf(properties[++i]);
- for (int j = 0; j < len; j++) {
- str.append(properties[++i]);
- str.append(",");
- }
- if (len > 0) {
- newValue = str.toString();
- }
- } else {
- newValue = properties[++i];
- }
-
- propertyValues.put(name, newValue);
- }
- mDeviceProperties.put(address, propertyValues);
-
- // We have added a new remote device or updated its properties.
- // Also update the serviceChannel cache.
- updateDeviceServiceChannelCache(address);
- }
-
- /* package */ void removeRemoteDeviceProperties(String address) {
- mDeviceProperties.remove(address);
- }
-
- /* package */ synchronized void setRemoteDeviceProperty(String address, String name,
- String value) {
- Map <String, String> propVal = mDeviceProperties.get(address);
- if (propVal != null) {
- propVal.put(name, value);
- mDeviceProperties.put(address, propVal);
- } else {
- Log.e(TAG, "setRemoteDeviceProperty for a device not in cache:" + address);
- }
- }
-
/**
* Sets the remote device trust state.
*
@@ -1553,8 +1136,8 @@ public class BluetoothService extends IBluetooth.Stub {
if (!isEnabledInternal()) return false;
- return setDevicePropertyBooleanNative(getObjectPathFromAddress(address), "Trusted",
- value ? 1 : 0);
+ return setDevicePropertyBooleanNative(
+ getObjectPathFromAddress(address), "Trusted", value ? 1 : 0);
}
/**
@@ -1562,7 +1145,7 @@ public class BluetoothService extends IBluetooth.Stub {
* Note: this value may be
* retrieved from cache if we retrieved the data before *
*
- * @return boolean to indicate trust or untrust state
+ * @return boolean to indicate trusted or untrusted state
*/
public synchronized boolean getTrustState(String address) {
if (!BluetoothAdapter.checkBluetoothAddress(address)) {
@@ -1570,11 +1153,11 @@ public class BluetoothService extends IBluetooth.Stub {
return false;
}
- String val = getRemoteDeviceProperty(address, "Trusted");
+ String val = mDeviceProperties.getProperty(address, "Trusted");
if (val == null) {
return false;
} else {
- return val.equals("true") ? true : false;
+ return val.equals("true");
}
}
@@ -1593,7 +1176,7 @@ public class BluetoothService extends IBluetooth.Stub {
mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
return BluetoothClass.ERROR;
}
- String val = getRemoteDeviceProperty(address, "Class");
+ String val = mDeviceProperties.getProperty(address, "Class");
if (val == null)
return BluetoothClass.ERROR;
else {
@@ -1615,8 +1198,8 @@ public class BluetoothService extends IBluetooth.Stub {
return getUuidFromCache(address);
}
- private ParcelUuid[] getUuidFromCache(String address) {
- String value = getRemoteDeviceProperty(address, "UUIDs");
+ ParcelUuid[] getUuidFromCache(String address) {
+ String value = mDeviceProperties.getProperty(address, "UUIDs");
if (value == null) return null;
String[] uuidStrings = null;
@@ -1667,7 +1250,7 @@ public class BluetoothService extends IBluetooth.Stub {
boolean ret;
// Just do the SDP if the device is already created and UUIDs are not
// NULL, else create the device and then do SDP.
- if (isRemoteDeviceInCache(address) && getRemoteUuids(address) != null) {
+ if (mDeviceProperties.isInCache(address) && getRemoteUuids(address) != null) {
String path = getObjectPathFromAddress(address);
if (path == null) return false;
@@ -1707,7 +1290,7 @@ public class BluetoothService extends IBluetooth.Stub {
}
// Check if we are recovering from a crash.
if (mDeviceProperties.isEmpty()) {
- if (!updateRemoteDevicePropertiesCache(address))
+ if (mDeviceProperties.updateCache(address) == null)
return -1;
}
@@ -1828,13 +1411,13 @@ public class BluetoothService extends IBluetooth.Stub {
}
/*package*/ void updateDeviceServiceChannelCache(String address) {
- ParcelUuid[] deviceUuids = getRemoteUuids(address);
+ if (DBG) Log.d(TAG, "updateDeviceServiceChannelCache(" + address + ")");
+
// We are storing the rfcomm channel numbers only for the uuids
// we are interested in.
- int channel;
- if (DBG) log("updateDeviceServiceChannelCache(" + address + ")");
+ ParcelUuid[] deviceUuids = getRemoteUuids(address);
- ArrayList<ParcelUuid> applicationUuids = new ArrayList();
+ ArrayList<ParcelUuid> applicationUuids = new ArrayList<ParcelUuid>();
synchronized (this) {
for (RemoteService service : mUuidCallbackTracker.keySet()) {
@@ -1844,24 +1427,22 @@ public class BluetoothService extends IBluetooth.Stub {
}
}
- Map <ParcelUuid, Integer> value = new HashMap<ParcelUuid, Integer>();
+ Map <ParcelUuid, Integer> uuidToChannelMap = new HashMap<ParcelUuid, Integer>();
// Retrieve RFCOMM channel for default uuids
for (ParcelUuid uuid : RFCOMM_UUIDS) {
if (BluetoothUuid.isUuidPresent(deviceUuids, uuid)) {
- channel = getDeviceServiceChannelNative(getObjectPathFromAddress(address),
- uuid.toString(), 0x0004);
- if (DBG) log("\tuuid(system): " + uuid + " " + channel);
- value.put(uuid, channel);
+ int channel = getDeviceServiceChannelForUuid(address, uuid);
+ uuidToChannelMap.put(uuid, channel);
+ if (DBG) Log.d(TAG, "\tuuid(system): " + uuid + " " + channel);
}
}
// Retrieve RFCOMM channel for application requested uuids
for (ParcelUuid uuid : applicationUuids) {
if (BluetoothUuid.isUuidPresent(deviceUuids, uuid)) {
- channel = getDeviceServiceChannelNative(getObjectPathFromAddress(address),
- uuid.toString(), 0x0004);
- if (DBG) log("\tuuid(application): " + uuid + " " + channel);
- value.put(uuid, channel);
+ int channel = getDeviceServiceChannelForUuid(address, uuid);
+ uuidToChannelMap.put(uuid, channel);
+ if (DBG) Log.d(TAG, "\tuuid(application): " + uuid + " " + channel);
}
}
@@ -1871,13 +1452,11 @@ public class BluetoothService extends IBluetooth.Stub {
iter.hasNext();) {
RemoteService service = iter.next();
if (service.address.equals(address)) {
- channel = -1;
- if (value.get(service.uuid) != null) {
- channel = value.get(service.uuid);
- }
- if (channel != -1) {
- if (DBG) log("Making callback for " + service.uuid + " with result " +
- channel);
+ if (uuidToChannelMap.containsKey(service.uuid)) {
+ int channel = uuidToChannelMap.get(service.uuid);
+
+ if (DBG) Log.d(TAG, "Making callback for " + service.uuid +
+ " with result " + channel);
IBluetoothCallback callback = mUuidCallbackTracker.get(service);
if (callback != null) {
try {
@@ -1891,10 +1470,16 @@ public class BluetoothService extends IBluetooth.Stub {
}
// Update cache
- mDeviceServiceChannelCache.put(address, value);
+ mDeviceServiceChannelCache.put(address, uuidToChannelMap);
}
}
+ private int getDeviceServiceChannelForUuid(String address,
+ ParcelUuid uuid) {
+ return getDeviceServiceChannelNative(getObjectPathFromAddress(address),
+ uuid.toString(), 0x0004);
+ }
+
/**
* b is a handle to a Binder instance, so that this service can be notified
* for Applications that terminate unexpectedly, to clean there service
@@ -1916,7 +1501,7 @@ public class BluetoothService extends IBluetooth.Stub {
int handle = addRfcommServiceRecordNative(serviceName,
uuid.getUuid().getMostSignificantBits(), uuid.getUuid().getLeastSignificantBits(),
(short)channel);
- if (DBG) log("new handle " + Integer.toHexString(handle));
+ if (DBG) Log.d(TAG, "new handle " + Integer.toHexString(handle));
if (handle == -1) {
return -1;
}
@@ -1939,8 +1524,8 @@ public class BluetoothService extends IBluetooth.Stub {
Integer handleInt = new Integer(handle);
Integer owner = mServiceRecordToPid.get(handleInt);
if (owner != null && pid == owner.intValue()) {
- if (DBG) log("Removing service record " + Integer.toHexString(handle) + " for pid " +
- pid);
+ if (DBG) Log.d(TAG, "Removing service record " +
+ Integer.toHexString(handle) + " for pid " + pid);
mServiceRecordToPid.remove(handleInt);
removeServiceRecordNative(handle);
}
@@ -1955,7 +1540,7 @@ public class BluetoothService extends IBluetooth.Stub {
}
public void binderDied() {
synchronized (BluetoothService.this) {
- if (DBG) log("Tracked app " + pid + " died");
+ if (DBG) Log.d(TAG, "Tracked app " + pid + " died");
checkAndRemoveRecord(handle, pid);
}
}
@@ -2028,10 +1613,7 @@ public class BluetoothService extends IBluetooth.Stub {
intent.putExtra(BluetoothDevice.EXTRA_DEVICE, mAdapter.getRemoteDevice(address));
intent.putExtra(BluetoothDevice.EXTRA_UUID, uuid);
mContext.sendBroadcast(intent, BLUETOOTH_ADMIN_PERM);
-
- if (mUuidIntentTracker.contains(address))
- mUuidIntentTracker.remove(address);
-
+ mUuidIntentTracker.remove(address);
}
/*package*/ synchronized void makeServiceChannelCallbacks(String address) {
@@ -2039,8 +1621,8 @@ public class BluetoothService extends IBluetooth.Stub {
iter.hasNext();) {
RemoteService service = iter.next();
if (service.address.equals(address)) {
- if (DBG) log("Cleaning up failed UUID channel lookup: " + service.address +
- " " + service.uuid);
+ if (DBG) Log.d(TAG, "Cleaning up failed UUID channel lookup: "
+ + service.address + " " + service.uuid);
IBluetoothCallback callback = mUuidCallbackTracker.get(service);
if (callback != null) {
try {
@@ -2055,18 +1637,9 @@ public class BluetoothService extends IBluetooth.Stub {
@Override
protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
- switch(mBluetoothState) {
- case BluetoothAdapter.STATE_OFF:
- pw.println("Bluetooth OFF\n");
- return;
- case BluetoothAdapter.STATE_TURNING_ON:
- pw.println("Bluetooth TURNING ON\n");
- return;
- case BluetoothAdapter.STATE_TURNING_OFF:
- pw.println("Bluetooth TURNING OFF\n");
+ dumpBluetoothState(pw);
+ if (mBluetoothState != BluetoothAdapter.STATE_ON) {
return;
- case BluetoothAdapter.STATE_ON:
- pw.println("Bluetooth ON\n");
}
pw.println("mIsAirplaneSensitive = " + mIsAirplaneSensitive);
@@ -2078,104 +1651,221 @@ public class BluetoothService extends IBluetooth.Stub {
mAdapter.getProfileProxy(mContext,
mBluetoothProfileServiceListener, BluetoothProfile.HEADSET);
+ mAdapter.getProfileProxy(mContext,
+ mBluetoothProfileServiceListener, BluetoothProfile.INPUT_DEVICE);
+ mAdapter.getProfileProxy(mContext,
+ mBluetoothProfileServiceListener, BluetoothProfile.PAN);
- pw.println("\n--Known devices--");
- for (String address : mDeviceProperties.keySet()) {
- int bondState = mBondState.getBondState(address);
- pw.printf("%s %10s (%d) %s\n", address,
- toBondStateString(bondState),
- mBondState.getAttempt(address),
- getRemoteName(address));
+ dumpKnownDevices(pw);
+ dumpAclConnectedDevices(pw);
+ dumpHeadsetService(pw);
+ dumpInputDeviceProfile(pw);
+ dumpPanProfile(pw);
+ dumpApplicationServiceRecords(pw);
+ }
- Map<ParcelUuid, Integer> uuidChannels = mDeviceServiceChannelCache.get(address);
- if (uuidChannels == null) {
- pw.println("\tuuids = null");
+ private void dumpHeadsetService(PrintWriter pw) {
+ pw.println("\n--Headset Service--");
+ if (mBluetoothHeadset != null) {
+ List<BluetoothDevice> deviceList = mBluetoothHeadset.getConnectedDevices();
+ if (deviceList.size() == 0) {
+ pw.println("No headsets connected");
} else {
- for (ParcelUuid uuid : uuidChannels.keySet()) {
- Integer channel = uuidChannels.get(uuid);
- if (channel == null) {
- pw.println("\t" + uuid);
- } else {
- pw.println("\t" + uuid + " RFCOMM channel = " + channel);
- }
- }
+ BluetoothDevice device = deviceList.get(0);
+ pw.println("\ngetConnectedDevices[0] = " + device);
+ dumpHeadsetConnectionState(pw, device);
+ pw.println("getBatteryUsageHint() = " +
+ mBluetoothHeadset.getBatteryUsageHint(device));
}
- for (RemoteService service : mUuidCallbackTracker.keySet()) {
- if (service.address.equals(address)) {
- pw.println("\tPENDING CALLBACK: " + service.uuid);
+
+ deviceList.clear();
+ deviceList = mBluetoothHeadset.getDevicesMatchingConnectionStates(new int[] {
+ BluetoothProfile.STATE_CONNECTED, BluetoothProfile.STATE_DISCONNECTED});
+ pw.println("--Connected and Disconnected Headsets");
+ for (BluetoothDevice device: deviceList) {
+ pw.println(device);
+ if (mBluetoothHeadset.isAudioConnected(device)) {
+ pw.println("SCO audio connected to device:" + device);
}
}
}
+ mAdapter.closeProfileProxy(BluetoothProfile.HEADSET, mBluetoothHeadset);
+ }
- String value = getProperty("Devices");
- String[] devicesObjectPath = null;
- if (value != null) {
- devicesObjectPath = value.split(",");
- }
- pw.println("\n--ACL connected devices--");
- if (devicesObjectPath != null) {
- for (String device : devicesObjectPath) {
- pw.println(getAddressFromObjectPath(device));
+ private void dumpInputDeviceProfile(PrintWriter pw) {
+ pw.println("\n--Bluetooth Service- Input Device Profile");
+ if (mInputDevice != null) {
+ List<BluetoothDevice> deviceList = mInputDevice.getConnectedDevices();
+ if (deviceList.size() == 0) {
+ pw.println("No input devices connected");
+ } else {
+ pw.println("Number of connected devices:" + deviceList.size());
+ BluetoothDevice device = deviceList.get(0);
+ pw.println("getConnectedDevices[0] = " + device);
+ pw.println("Priority of Connected device = " + mInputDevice.getPriority(device));
+
+ switch (mInputDevice.getConnectionState(device)) {
+ case BluetoothInputDevice.STATE_CONNECTING:
+ pw.println("getConnectionState() = STATE_CONNECTING");
+ break;
+ case BluetoothInputDevice.STATE_CONNECTED:
+ pw.println("getConnectionState() = STATE_CONNECTED");
+ break;
+ case BluetoothInputDevice.STATE_DISCONNECTING:
+ pw.println("getConnectionState() = STATE_DISCONNECTING");
+ break;
+ }
+ }
+ deviceList.clear();
+ deviceList = mInputDevice.getDevicesMatchingConnectionStates(new int[] {
+ BluetoothProfile.STATE_CONNECTED, BluetoothProfile.STATE_DISCONNECTED});
+ pw.println("--Connected and Disconnected input devices");
+ for (BluetoothDevice device: deviceList) {
+ pw.println(device);
}
}
+ mAdapter.closeProfileProxy(BluetoothProfile.INPUT_DEVICE, mBluetoothHeadset);
+ }
- // Rather not do this from here, but no-where else and I need this
- // dump
- pw.println("\n--Headset Service--");
- if (mBluetoothHeadset != null) {
- List<BluetoothDevice> deviceList = mBluetoothHeadset.getConnectedDevices();
+ private void dumpPanProfile(PrintWriter pw) {
+ pw.println("\n--Bluetooth Service- Pan Profile");
+ if (mPan != null) {
+ List<BluetoothDevice> deviceList = mPan.getConnectedDevices();
if (deviceList.size() == 0) {
- pw.println("\n--No headsets connected--");
+ pw.println("No Pan devices connected");
} else {
+ pw.println("Number of connected devices:" + deviceList.size());
BluetoothDevice device = deviceList.get(0);
- pw.println("\ngetConnectedDevices[0] = " + device);
+ pw.println("getConnectedDevices[0] = " + device);
+ pw.println("Priority of Connected device = " + mPan.getPriority(device));
- switch (mBluetoothHeadset.getConnectionState(device)) {
- case BluetoothHeadset.STATE_CONNECTING:
+ switch (mPan.getConnectionState(device)) {
+ case BluetoothInputDevice.STATE_CONNECTING:
pw.println("getConnectionState() = STATE_CONNECTING");
break;
- case BluetoothHeadset.STATE_CONNECTED:
+ case BluetoothInputDevice.STATE_CONNECTED:
pw.println("getConnectionState() = STATE_CONNECTED");
break;
- case BluetoothHeadset.STATE_DISCONNECTING:
+ case BluetoothInputDevice.STATE_DISCONNECTING:
pw.println("getConnectionState() = STATE_DISCONNECTING");
break;
- case BluetoothHeadset.STATE_AUDIO_CONNECTED:
- pw.println("getConnectionState() = STATE_AUDIO_CONNECTED");
- break;
}
- pw.println("getBatteryUsageHint() = " +
- mBluetoothHeadset.getBatteryUsageHint(device));
}
-
deviceList.clear();
- deviceList = mBluetoothHeadset.getDevicesMatchingConnectionStates(new int[] {
+ deviceList = mPan.getDevicesMatchingConnectionStates(new int[] {
BluetoothProfile.STATE_CONNECTED, BluetoothProfile.STATE_DISCONNECTED});
- pw.println("\n--Connected and Disconnected Headsets");
+ pw.println("--Connected and Disconnected Pan devices");
for (BluetoothDevice device: deviceList) {
pw.println(device);
- if (mBluetoothHeadset.isAudioConnected(device)) {
- pw.println("SCO audio connected to device:" + device);
- }
}
+ }
+ }
- mAdapter.closeProfileProxy(BluetoothProfile.HEADSET, mBluetoothHeadset);
+ private void dumpHeadsetConnectionState(PrintWriter pw,
+ BluetoothDevice device) {
+ switch (mBluetoothHeadset.getConnectionState(device)) {
+ case BluetoothHeadset.STATE_CONNECTING:
+ pw.println("getConnectionState() = STATE_CONNECTING");
+ break;
+ case BluetoothHeadset.STATE_CONNECTED:
+ pw.println("getConnectionState() = STATE_CONNECTED");
+ break;
+ case BluetoothHeadset.STATE_DISCONNECTING:
+ pw.println("getConnectionState() = STATE_DISCONNECTING");
+ break;
+ case BluetoothHeadset.STATE_AUDIO_CONNECTED:
+ pw.println("getConnectionState() = STATE_AUDIO_CONNECTED");
+ break;
}
+ }
+ private void dumpApplicationServiceRecords(PrintWriter pw) {
pw.println("\n--Application Service Records--");
for (Integer handle : mServiceRecordToPid.keySet()) {
Integer pid = mServiceRecordToPid.get(handle);
pw.println("\tpid " + pid + " handle " + Integer.toHexString(handle));
}
+ mAdapter.closeProfileProxy(BluetoothProfile.PAN, mBluetoothHeadset);
+ }
+
+ private void dumpAclConnectedDevices(PrintWriter pw) {
+ String[] devicesObjectPath = getKnownDevices();
+ pw.println("\n--ACL connected devices--");
+ if (devicesObjectPath != null) {
+ for (String device : devicesObjectPath) {
+ pw.println(getAddressFromObjectPath(device));
+ }
+ }
+ }
+
+ private void dumpKnownDevices(PrintWriter pw) {
+ pw.println("\n--Known devices--");
+ for (String address : mDeviceProperties.keySet()) {
+ int bondState = mBondState.getBondState(address);
+ pw.printf("%s %10s (%d) %s\n", address,
+ toBondStateString(bondState),
+ mBondState.getAttempt(address),
+ getRemoteName(address));
+
+ Map<ParcelUuid, Integer> uuidChannels = mDeviceServiceChannelCache.get(address);
+ if (uuidChannels == null) {
+ pw.println("\tuuids = null");
+ } else {
+ for (ParcelUuid uuid : uuidChannels.keySet()) {
+ Integer channel = uuidChannels.get(uuid);
+ if (channel == null) {
+ pw.println("\t" + uuid);
+ } else {
+ pw.println("\t" + uuid + " RFCOMM channel = " + channel);
+ }
+ }
+ }
+ for (RemoteService service : mUuidCallbackTracker.keySet()) {
+ if (service.address.equals(address)) {
+ pw.println("\tPENDING CALLBACK: " + service.uuid);
+ }
+ }
+ }
+ }
+
+ private void dumpBluetoothState(PrintWriter pw) {
+ switch(mBluetoothState) {
+ case BluetoothAdapter.STATE_OFF:
+ pw.println("Bluetooth OFF\n");
+ break;
+ case BluetoothAdapter.STATE_TURNING_ON:
+ pw.println("Bluetooth TURNING ON\n");
+ break;
+ case BluetoothAdapter.STATE_TURNING_OFF:
+ pw.println("Bluetooth TURNING OFF\n");
+ break;
+ case BluetoothAdapter.STATE_ON:
+ pw.println("Bluetooth ON\n");
+ break;
+ default:
+ pw.println("Bluetooth UNKNOWN STATE " + mBluetoothState);
+ }
}
private BluetoothProfile.ServiceListener mBluetoothProfileServiceListener =
new BluetoothProfile.ServiceListener() {
public void onServiceConnected(int profile, BluetoothProfile proxy) {
- mBluetoothHeadset = (BluetoothHeadset) proxy;
- }
+ if (profile == BluetoothProfile.HEADSET) {
+ mBluetoothHeadset = (BluetoothHeadset) proxy;
+ } else if (profile == BluetoothProfile.INPUT_DEVICE) {
+ mInputDevice = (BluetoothInputDevice) proxy;
+ } else if (profile == BluetoothProfile.PAN) {
+ mPan = (BluetoothPan) proxy;
+ }
+ }
public void onServiceDisconnected(int profile) {
- mBluetoothHeadset = null;
+ if (profile == BluetoothProfile.HEADSET) {
+ mBluetoothHeadset = null;
+ } else if (profile == BluetoothProfile.INPUT_DEVICE) {
+ mInputDevice = null;
+ } else if (profile == BluetoothProfile.PAN) {
+ mPan = null;
+ }
}
};
@@ -2201,7 +1891,7 @@ public class BluetoothService extends IBluetooth.Stub {
}
/*package*/ String getAddressFromObjectPath(String objectPath) {
- String adapterObjectPath = getPropertyInternal("ObjectPath");
+ String adapterObjectPath = mAdapterProperties.getObjectPath();
if (adapterObjectPath == null || objectPath == null) {
Log.e(TAG, "getAddressFromObjectPath: AdapterObjectPath:" + adapterObjectPath +
" or deviceObjectPath:" + objectPath + " is null");
@@ -2221,7 +1911,7 @@ public class BluetoothService extends IBluetooth.Stub {
}
/*package*/ String getObjectPathFromAddress(String address) {
- String path = getPropertyInternal("ObjectPath");
+ String path = mAdapterProperties.getObjectPath();
if (path == null) {
Log.e(TAG, "Error: Object Path is null");
return null;
@@ -2234,7 +1924,7 @@ public class BluetoothService extends IBluetooth.Stub {
String path = getObjectPathFromAddress(address);
boolean result = setLinkTimeoutNative(path, num_slots);
- if (!result) log("Set Link Timeout to:" + num_slots + " slots failed");
+ if (!result) Log.d(TAG, "Set Link Timeout to " + num_slots + " slots failed");
}
/**** Handlers for PAN Profile ****/
@@ -2253,9 +1943,9 @@ public class BluetoothService extends IBluetooth.Stub {
mBluetoothPanProfileHandler.setBluetoothTethering(value);
}
- public synchronized int getPanDeviceState(BluetoothDevice device) {
+ public synchronized int getPanDeviceConnectionState(BluetoothDevice device) {
mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
- return mBluetoothPanProfileHandler.getPanDeviceState(device);
+ return mBluetoothPanProfileHandler.getPanDeviceConnectionState(device);
}
public synchronized boolean connectPanDevice(BluetoothDevice device) {
@@ -2269,6 +1959,12 @@ public class BluetoothService extends IBluetooth.Stub {
return mBluetoothPanProfileHandler.getConnectedPanDevices();
}
+ public synchronized List<BluetoothDevice> getPanDevicesMatchingConnectionStates(
+ int[] states) {
+ mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
+ return mBluetoothPanProfileHandler.getPanDevicesMatchingConnectionStates(states);
+ }
+
public synchronized boolean disconnectPanDevice(BluetoothDevice device) {
mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
"Need BLUETOOTH_ADMIN permission");
@@ -2311,9 +2007,9 @@ public class BluetoothService extends IBluetooth.Stub {
return mBluetoothInputProfileHandler.disconnectInputDeviceInternal(device);
}
- public synchronized int getInputDeviceState(BluetoothDevice device) {
+ public synchronized int getInputDeviceConnectionState(BluetoothDevice device) {
mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
- return mBluetoothInputProfileHandler.getInputDeviceState(device);
+ return mBluetoothInputProfileHandler.getInputDeviceConnectionState(device);
}
@@ -2322,6 +2018,13 @@ public class BluetoothService extends IBluetooth.Stub {
return mBluetoothInputProfileHandler.getConnectedInputDevices();
}
+ public synchronized List<BluetoothDevice> getInputDevicesMatchingConnectionStates(
+ int[] states) {
+ mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
+ return mBluetoothInputProfileHandler.getInputDevicesMatchingConnectionStates(states);
+ }
+
+
public synchronized int getInputDevicePriority(BluetoothDevice device) {
mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
return mBluetoothInputProfileHandler.getInputDevicePriority(device);
@@ -2341,10 +2044,6 @@ public class BluetoothService extends IBluetooth.Stub {
mBluetoothInputProfileHandler.handleInputDevicePropertyChange(address, connected);
}
- /*package*/ boolean isRemoteDeviceInCache(String address) {
- return (mDeviceProperties.get(address) != null);
- }
-
public boolean connectHeadset(String address) {
if (getBondState(address) != BluetoothDevice.BOND_BONDED) return false;
@@ -2401,7 +2100,7 @@ public class BluetoothService extends IBluetooth.Stub {
return false;
}
- private BluetoothDeviceProfileState addProfileState(String address) {
+ BluetoothDeviceProfileState addProfileState(String address) {
BluetoothDeviceProfileState state = mDeviceProfileState.get(address);
if (state != null) return state;
@@ -2411,26 +2110,47 @@ public class BluetoothService extends IBluetooth.Stub {
return state;
}
- private void removeProfileState(String address) {
+ void removeProfileState(String address) {
mDeviceProfileState.remove(address);
}
+ synchronized String[] getKnownDevices() {
+ String[] bonds = null;
+ String val = getProperty("Devices");
+ if (val != null) {
+ bonds = val.split(",");
+ }
+ return bonds;
+ }
+
private void initProfileState() {
- String []bonds = null;
- String val = getPropertyInternal("Devices");
+ String[] bonds = null;
+ String val = mAdapterProperties.getProperty("Devices");
if (val != null) {
bonds = val.split(",");
}
if (bonds == null) {
return;
}
-
for (String path : bonds) {
String address = getAddressFromObjectPath(path);
BluetoothDeviceProfileState state = addProfileState(address);
- Message msg = new Message();
- msg.what = BluetoothDeviceProfileState.AUTO_CONNECT_PROFILES;
- state.sendMessage(msg);
+ }
+ }
+
+ private void autoConnect() {
+ String[] bonds = getKnownDevices();
+ if (bonds == null) {
+ return;
+ }
+ for (String path : bonds) {
+ String address = getAddressFromObjectPath(path);
+ BluetoothDeviceProfileState state = mDeviceProfileState.get(address);
+ if (state != null) {
+ Message msg = new Message();
+ msg.what = BluetoothDeviceProfileState.AUTO_CONNECT_PROFILES;
+ state.sendMessage(msg);
+ }
}
}
@@ -2478,78 +2198,91 @@ public class BluetoothService extends IBluetooth.Stub {
public synchronized void sendConnectionStateChange(BluetoothDevice device, int state,
int prevState) {
- if (updateCountersAndCheckForConnectionStateChange(device, state, prevState)) {
- state = translateToAdapterConnectionState(state);
- prevState = translateToAdapterConnectionState(prevState);
+ // Since this is a binder call check if Bluetooth is on still
+ if (mBluetoothState == BluetoothAdapter.STATE_OFF) return;
+
+ if (updateCountersAndCheckForConnectionStateChange(state, prevState)) {
+ if (!validateProfileConnectionState(state) ||
+ !validateProfileConnectionState(prevState)) {
+ // Previously, an invalid state was broadcast anyway,
+ // with the invalid state converted to -1 in the intent.
+ // Better to log an error and not send an intent with
+ // invalid contents or set mAdapterConnectionState to -1.
+ Log.e(TAG, "Error in sendConnectionStateChange: "
+ + "prevState " + prevState + " state " + state);
+ return;
+ }
mAdapterConnectionState = state;
Intent intent = new Intent(BluetoothAdapter.ACTION_CONNECTION_STATE_CHANGED);
intent.putExtra(BluetoothDevice.EXTRA_DEVICE, device);
- intent.putExtra(BluetoothAdapter.EXTRA_CONNECTION_STATE, state);
- intent.putExtra(BluetoothAdapter.EXTRA_PREVIOUS_CONNECTION_STATE, prevState);
+ intent.putExtra(BluetoothAdapter.EXTRA_CONNECTION_STATE,
+ convertToAdapterState(state));
+ intent.putExtra(BluetoothAdapter.EXTRA_PREVIOUS_CONNECTION_STATE,
+ convertToAdapterState(prevState));
mContext.sendBroadcast(intent, BLUETOOTH_PERM);
- log("CONNECTION_STATE_CHANGE: " + device + ": " + prevState + "-> " + state);
+ Log.d(TAG, "CONNECTION_STATE_CHANGE: " + device + ": "
+ + prevState + " -> " + state);
}
}
- private int translateToAdapterConnectionState(int state) {
+ private boolean validateProfileConnectionState(int state) {
+ return (state == BluetoothProfile.STATE_DISCONNECTED ||
+ state == BluetoothProfile.STATE_CONNECTING ||
+ state == BluetoothProfile.STATE_CONNECTED ||
+ state == BluetoothProfile.STATE_DISCONNECTING);
+ }
+
+ private int convertToAdapterState(int state) {
switch (state) {
+ case BluetoothProfile.STATE_DISCONNECTED:
+ return BluetoothAdapter.STATE_DISCONNECTED;
+ case BluetoothProfile.STATE_DISCONNECTING:
+ return BluetoothAdapter.STATE_DISCONNECTING;
+ case BluetoothProfile.STATE_CONNECTED:
+ return BluetoothAdapter.STATE_CONNECTED;
case BluetoothProfile.STATE_CONNECTING:
return BluetoothAdapter.STATE_CONNECTING;
+ }
+ Log.e(TAG, "Error in convertToAdapterState");
+ return -1;
+ }
+
+ private boolean updateCountersAndCheckForConnectionStateChange(int state, int prevState) {
+ switch (prevState) {
+ case BluetoothProfile.STATE_CONNECTING:
+ mProfilesConnecting--;
+ break;
+
case BluetoothProfile.STATE_CONNECTED:
- return BluetoothAdapter.STATE_CONNECTED;
+ mProfilesConnected--;
+ break;
+
case BluetoothProfile.STATE_DISCONNECTING:
- return BluetoothAdapter.STATE_DISCONNECTING;
- case BluetoothProfile.STATE_DISCONNECTED:
- return BluetoothAdapter.STATE_DISCONNECTED;
- default:
- Log.e(TAG, "Error in getAdapterConnectionState");
- return -1;
+ mProfilesDisconnecting--;
+ break;
}
- }
- private boolean updateCountersAndCheckForConnectionStateChange(BluetoothDevice device,
- int state,
- int prevState) {
switch (state) {
case BluetoothProfile.STATE_CONNECTING:
mProfilesConnecting++;
- if (prevState == BluetoothAdapter.STATE_DISCONNECTING) mProfilesDisconnecting--;
- if (mProfilesConnected > 0 || mProfilesConnecting > 1) return false;
+ return (mProfilesConnected == 0 && mProfilesConnecting == 1);
- break;
case BluetoothProfile.STATE_CONNECTED:
- if (prevState == BluetoothAdapter.STATE_CONNECTING) mProfilesConnecting--;
- if (prevState == BluetoothAdapter.STATE_DISCONNECTING) mProfilesDisconnecting--;
-
mProfilesConnected++;
+ return (mProfilesConnected == 1);
- if (mProfilesConnected > 1) return false;
- break;
case BluetoothProfile.STATE_DISCONNECTING:
mProfilesDisconnecting++;
- mProfilesConnected--;
-
- if (mProfilesConnected > 0 || mProfilesDisconnecting > 1) return false;
+ return (mProfilesConnected == 0 && mProfilesDisconnecting == 1);
- break;
case BluetoothProfile.STATE_DISCONNECTED:
- if (prevState == BluetoothAdapter.STATE_CONNECTING) mProfilesConnecting--;
- if (prevState == BluetoothAdapter.STATE_DISCONNECTING) mProfilesDisconnecting--;
-
- if (prevState == BluetoothAdapter.STATE_CONNECTED) {
- mProfilesConnected--;
- }
+ return (mProfilesConnected == 0 && mProfilesConnecting == 0);
- if (mProfilesConnected > 0 || mProfilesConnecting > 0) return false;
- break;
+ default:
+ return true;
}
- return true;
- }
-
- private static void log(String msg) {
- Log.d(TAG, msg);
}
private native static void classInitNative();
@@ -2557,13 +2290,13 @@ public class BluetoothService extends IBluetooth.Stub {
private native boolean setupNativeDataNative();
private native boolean tearDownNativeDataNative();
private native void cleanupNativeDataNative();
- private native String getAdapterPathNative();
+ /*package*/ native String getAdapterPathNative();
private native int isEnabledNative();
private native int enableNative();
private native int disableNative();
- private native Object[] getAdapterPropertiesNative();
+ /*package*/ native Object[] getAdapterPropertiesNative();
private native Object[] getDevicePropertiesNative(String objectPath);
private native boolean setAdapterPropertyStringNative(String key, String value);
private native boolean setAdapterPropertyIntegerNative(String key, int value);
diff --git a/core/java/android/service/wallpaper/WallpaperService.java b/core/java/android/service/wallpaper/WallpaperService.java
index dd39714..20661d7 100644
--- a/core/java/android/service/wallpaper/WallpaperService.java
+++ b/core/java/android/service/wallpaper/WallpaperService.java
@@ -460,16 +460,17 @@ public abstract class WallpaperService extends Service {
}
private void dispatchPointer(MotionEvent event) {
- synchronized (mLock) {
- if (event.getAction() == MotionEvent.ACTION_MOVE) {
- mPendingMove = event;
- } else {
- mPendingMove = null;
+ if (event.isTouchEvent()) {
+ synchronized (mLock) {
+ if (event.getAction() == MotionEvent.ACTION_MOVE) {
+ mPendingMove = event;
+ } else {
+ mPendingMove = null;
+ }
}
+ Message msg = mCaller.obtainMessageO(MSG_TOUCH_EVENT, event);
+ mCaller.sendMessage(msg);
}
-
- Message msg = mCaller.obtainMessageO(MSG_TOUCH_EVENT, event);
- mCaller.sendMessage(msg);
}
void updateSurface(boolean forceRelayout, boolean forceReport, boolean redrawNeeded) {
diff --git a/core/java/android/text/Layout.java b/core/java/android/text/Layout.java
index 97a216a..1e4cca9 100644
--- a/core/java/android/text/Layout.java
+++ b/core/java/android/text/Layout.java
@@ -1727,6 +1727,17 @@ public abstract class Layout {
}
}
+ /**
+ * Inform this layout that not all of its lines will be displayed, because a maximum number of
+ * lines has been set on the associated TextView.
+ *
+ * A non strictly positive value means that all lines are displayed.
+ *
+ * @param lineCount number of visible lines
+ * @hide
+ */
+ public void setMaximumVisibleLineCount(int lineCount) {}
+
private CharSequence mText;
private TextPaint mPaint;
/* package */ TextPaint mWorkPaint;
@@ -1765,14 +1776,4 @@ public abstract class Layout {
/* package */ static final Directions DIRS_ALL_RIGHT_TO_LEFT =
new Directions(new int[] { 0, RUN_LENGTH_MASK | RUN_RTL_FLAG });
- /**
- * Inform this layout that not all of its lines will be displayed, because a maximum number of
- * lines has been set on the associated TextView.
- *
- * A non positive value means that all lines are displayed.
- *
- * @param line line number of the last visible line (line numbers start at 1 for the first line)
- * @hide
- */
- public void setMaximumVisibleLineCount(int line) {}
}
diff --git a/core/java/android/text/StaticLayout.java b/core/java/android/text/StaticLayout.java
index a4546f0..a826a97 100644
--- a/core/java/android/text/StaticLayout.java
+++ b/core/java/android/text/StaticLayout.java
@@ -355,8 +355,6 @@ public class StaticLayout extends Layout {
okBottom = fitBottom;
}
} else {
- if (ellipsize != null) {
- // Break only at spaces using ok indexes.
if (ok != here) {
// Log.e("text", "output ok " + here + " to " +ok);
@@ -372,43 +370,7 @@ public class StaticLayout extends Layout {
chooseHtv, fm, hasTabOrEmoji,
needMultiply, paraStart, chdirs, dir, easy,
ok == bufEnd, includepad, trackpad,
- chs, widths, here - paraStart,
- ellipsize, ellipsizedWidth, okWidth,
- paint);
-
- here = ok;
- } else {
- // Act like it fit even though it didn't.
-
- fitWidth = w;
- here = fit = j + 1;
-
- if (fmTop < fitTop)
- fitTop = fmTop;
- if (fmAscent < fitAscent)
- fitAscent = fmAscent;
- if (fmDescent > fitDescent)
- fitDescent = fmDescent;
- if (fmBottom > fitBottom)
- fitBottom = fmBottom;
- }
- } else {
- if (ok != here) {
- // Log.e("text", "output ok " + here + " to " +ok);
-
- while (ok < spanEnd && chs[ok - paraStart] == CHAR_SPACE) {
- ok++;
- }
-
- v = out(source,
- here, ok,
- okAscent, okDescent, okTop, okBottom,
- v,
- spacingmult, spacingadd, chooseHt,
- chooseHtv, fm, hasTabOrEmoji,
- needMultiply, paraStart, chdirs, dir, easy,
- ok == bufEnd, includepad, trackpad,
- chs, widths, here - paraStart,
+ chs, widths, paraStart,
ellipsize, ellipsizedWidth, okWidth,
paint);
@@ -424,7 +386,7 @@ public class StaticLayout extends Layout {
chooseHtv, fm, hasTabOrEmoji,
needMultiply, paraStart, chdirs, dir, easy,
fit == bufEnd, includepad, trackpad,
- chs, widths, here - paraStart,
+ chs, widths, paraStart,
ellipsize, ellipsizedWidth, fitWidth,
paint);
@@ -446,13 +408,12 @@ public class StaticLayout extends Layout {
needMultiply, paraStart, chdirs, dir, easy,
here + 1 == bufEnd, includepad,
trackpad,
- chs, widths, here - paraStart,
+ chs, widths, paraStart,
ellipsize, ellipsizedWidth,
widths[here - paraStart], paint);
here = here + 1;
}
- }
if (here < spanStart) {
// didn't output all the text for this span
@@ -495,7 +456,7 @@ public class StaticLayout extends Layout {
chooseHtv, fm, hasTabOrEmoji,
needMultiply, paraStart, chdirs, dir, easy,
paraEnd == bufEnd, includepad, trackpad,
- chs, widths, here - paraStart,
+ chs, widths, paraStart,
ellipsize, ellipsizedWidth, w, paint);
}
@@ -614,19 +575,6 @@ public class StaticLayout extends Layout {
return false;
}
-/*
- private static void dump(byte[] data, int count, String label) {
- if (false) {
- System.out.print(label);
-
- for (int i = 0; i < count; i++)
- System.out.print(" " + data[i]);
-
- System.out.println();
- }
- }
-*/
-
private int out(CharSequence text, int start, int end,
int above, int below, int top, int bottom, int v,
float spacingmult, float spacingadd,
@@ -729,8 +677,8 @@ public class StaticLayout extends Layout {
if (easy) {
mLineDirections[j] = linedirs;
} else {
- mLineDirections[j] = AndroidBidi.directions(dir, chdirs, widthStart, chs,
- widthStart, end - start);
+ mLineDirections[j] = AndroidBidi.directions(dir, chdirs, start - widthStart, chs,
+ start - widthStart, end - start);
}
// If ellipsize is in marquee mode, do not apply ellipsis on the first line
@@ -869,7 +817,7 @@ public class StaticLayout extends Layout {
@Override
public int getLineDescent(int line) {
int descent = mLines[mColumns * line + DESCENT];
- if (mMaximumVisibleLineCount > 0 && line >= mMaximumVisibleLineCount - 1 &&
+ if (mMaximumVisibleLineCount > 0 && line >= mMaximumVisibleLineCount - 1 && // -1 intended
line != mLineCount) {
descent += getBottomPadding();
}
@@ -933,8 +881,8 @@ public class StaticLayout extends Layout {
* @hide
*/
@Override
- public void setMaximumVisibleLineCount(int line) {
- mMaximumVisibleLineCount = line;
+ public void setMaximumVisibleLineCount(int lineCount) {
+ mMaximumVisibleLineCount = lineCount;
}
private int mLineCount;
diff --git a/core/java/android/text/format/DateUtils.java b/core/java/android/text/format/DateUtils.java
index a95dad7..353b628 100644
--- a/core/java/android/text/format/DateUtils.java
+++ b/core/java/android/text/format/DateUtils.java
@@ -642,14 +642,18 @@ public class DateUtils
private static void initFormatStrings() {
synchronized (sLock) {
- Resources r = Resources.getSystem();
- Configuration cfg = r.getConfiguration();
- if (sLastConfig == null || !sLastConfig.equals(cfg)) {
- sLastConfig = cfg;
- sStatusTimeFormat = java.text.DateFormat.getTimeInstance(java.text.DateFormat.SHORT);
- sElapsedFormatMMSS = r.getString(com.android.internal.R.string.elapsed_time_short_format_mm_ss);
- sElapsedFormatHMMSS = r.getString(com.android.internal.R.string.elapsed_time_short_format_h_mm_ss);
- }
+ initFormatStringsLocked();
+ }
+ }
+
+ private static void initFormatStringsLocked() {
+ Resources r = Resources.getSystem();
+ Configuration cfg = r.getConfiguration();
+ if (sLastConfig == null || !sLastConfig.equals(cfg)) {
+ sLastConfig = cfg;
+ sStatusTimeFormat = java.text.DateFormat.getTimeInstance(java.text.DateFormat.SHORT);
+ sElapsedFormatMMSS = r.getString(com.android.internal.R.string.elapsed_time_short_format_mm_ss);
+ sElapsedFormatHMMSS = r.getString(com.android.internal.R.string.elapsed_time_short_format_h_mm_ss);
}
}
@@ -659,8 +663,10 @@ public class DateUtils
* @hide
*/
public static final CharSequence timeString(long millis) {
- initFormatStrings();
- return sStatusTimeFormat.format(millis);
+ synchronized (sLock) {
+ initFormatStringsLocked();
+ return sStatusTimeFormat.format(millis);
+ }
}
/**
diff --git a/core/java/android/text/method/BaseKeyListener.java b/core/java/android/text/method/BaseKeyListener.java
index 191c250..7e29dc7 100644
--- a/core/java/android/text/method/BaseKeyListener.java
+++ b/core/java/android/text/method/BaseKeyListener.java
@@ -33,23 +33,6 @@ public abstract class BaseKeyListener extends MetaKeyKeyListener
implements KeyListener {
/* package */ static final Object OLD_SEL_START = new NoCopySpan.Concrete();
- private static final int MODIFIER_NONE = 0;
- private static final int MODIFIER_ALT = 1;
- private static final int MODIFIER_INVALID = 2;
-
- private static int getModifier(Editable content, KeyEvent event) {
- if (event.hasModifiers(KeyEvent.META_ALT_ON)) {
- return MODIFIER_ALT;
- }
- if (!event.hasNoModifiers()) {
- return MODIFIER_INVALID;
- }
- if (getMetaState(content, META_ALT_ON) == 1) {
- return MODIFIER_ALT;
- }
- return MODIFIER_NONE;
- }
-
/**
* Performs the action that happens when you press the {@link KeyEvent#KEYCODE_DEL} key in
* a {@link TextView}. If there is a selection, deletes the selection; otherwise,
@@ -59,27 +42,7 @@ public abstract class BaseKeyListener extends MetaKeyKeyListener
* @return true if anything was deleted; false otherwise.
*/
public boolean backspace(View view, Editable content, int keyCode, KeyEvent event) {
- int modifier = getModifier(content, event);
- if (modifier == MODIFIER_INVALID) {
- return false;
- }
-
- if (deleteSelection(view, content)) {
- return true;
- }
-
- if (modifier == MODIFIER_ALT && deleteLine(view, content)) {
- return true;
- }
-
- final int start = Selection.getSelectionEnd(content);
- final int end = TextUtils.getOffsetBefore(content, start);
- if (start != end) {
- content.delete(Math.min(start, end), Math.max(start, end));
- return true;
- }
-
- return false;
+ return backspaceOrForwardDelete(view, content, keyCode, event, false);
}
/**
@@ -91,26 +54,42 @@ public abstract class BaseKeyListener extends MetaKeyKeyListener
* @return true if anything was deleted; false otherwise.
*/
public boolean forwardDelete(View view, Editable content, int keyCode, KeyEvent event) {
- int modifier = getModifier(content, event);
- if (modifier == MODIFIER_INVALID) {
+ return backspaceOrForwardDelete(view, content, keyCode, event, true);
+ }
+
+ private boolean backspaceOrForwardDelete(View view, Editable content, int keyCode,
+ KeyEvent event, boolean isForwardDelete) {
+ // Ensure the key event does not have modifiers except ALT or SHIFT.
+ if (!KeyEvent.metaStateHasNoModifiers(event.getMetaState()
+ & ~(KeyEvent.META_SHIFT_MASK | KeyEvent.META_ALT_MASK))) {
return false;
}
+ // If there is a current selection, delete it.
if (deleteSelection(view, content)) {
return true;
}
- if (modifier == MODIFIER_ALT && deleteLine(view, content)) {
- return true;
+ // Alt+Backspace or Alt+ForwardDelete deletes the current line, if possible.
+ if (event.isAltPressed() || getMetaState(content, META_ALT_ON) == 1) {
+ if (deleteLine(view, content)) {
+ return true;
+ }
}
+ // Delete a character.
final int start = Selection.getSelectionEnd(content);
- final int end = TextUtils.getOffsetAfter(content, start);
+ final int end;
+ if (isForwardDelete || event.isShiftPressed()
+ || getMetaState(content, META_SHIFT_ON) == 1) {
+ end = TextUtils.getOffsetAfter(content, start);
+ } else {
+ end = TextUtils.getOffsetBefore(content, start);
+ }
if (start != end) {
content.delete(Math.min(start, end), Math.max(start, end));
return true;
}
-
return false;
}
diff --git a/core/java/android/text/method/BaseMovementMethod.java b/core/java/android/text/method/BaseMovementMethod.java
index 2be18d6..94c6ed0 100644
--- a/core/java/android/text/method/BaseMovementMethod.java
+++ b/core/java/android/text/method/BaseMovementMethod.java
@@ -18,6 +18,7 @@ package android.text.method;
import android.text.Layout;
import android.text.Spannable;
+import android.view.InputDevice;
import android.view.KeyEvent;
import android.view.MotionEvent;
import android.widget.TextView;
@@ -88,6 +89,39 @@ public class BaseMovementMethod implements MovementMethod {
return false;
}
+ @Override
+ public boolean onGenericMotionEvent(TextView widget, Spannable text, MotionEvent event) {
+ if ((event.getSource() & InputDevice.SOURCE_CLASS_POINTER) != 0) {
+ switch (event.getAction()) {
+ case MotionEvent.ACTION_SCROLL: {
+ final float vscroll;
+ final float hscroll;
+ if ((event.getMetaState() & KeyEvent.META_SHIFT_ON) != 0) {
+ vscroll = 0;
+ hscroll = event.getAxisValue(MotionEvent.AXIS_VSCROLL);
+ } else {
+ vscroll = -event.getAxisValue(MotionEvent.AXIS_VSCROLL);
+ hscroll = event.getAxisValue(MotionEvent.AXIS_HSCROLL);
+ }
+
+ boolean handled = false;
+ if (hscroll < 0) {
+ handled |= scrollLeft(widget, text, (int)Math.ceil(-hscroll));
+ } else if (hscroll > 0) {
+ handled |= scrollRight(widget, text, (int)Math.ceil(hscroll));
+ }
+ if (vscroll < 0) {
+ handled |= scrollUp(widget, text, (int)Math.ceil(-vscroll));
+ } else if (vscroll > 0) {
+ handled |= scrollDown(widget, text, (int)Math.ceil(vscroll));
+ }
+ return handled;
+ }
+ }
+ }
+ return false;
+ }
+
/**
* Gets the meta state used for movement using the modifiers tracked by the text
* buffer as well as those present in the key event.
@@ -342,4 +376,276 @@ public class BaseMovementMethod implements MovementMethod {
protected boolean end(TextView widget, Spannable buffer) {
return false;
}
+
+ private int getTopLine(TextView widget) {
+ return widget.getLayout().getLineForVertical(widget.getScrollY());
+ }
+
+ private int getBottomLine(TextView widget) {
+ return widget.getLayout().getLineForVertical(widget.getScrollY() + getInnerHeight(widget));
+ }
+
+ private int getInnerWidth(TextView widget) {
+ return widget.getWidth() - widget.getTotalPaddingLeft() - widget.getTotalPaddingRight();
+ }
+
+ private int getInnerHeight(TextView widget) {
+ return widget.getHeight() - widget.getTotalPaddingTop() - widget.getTotalPaddingBottom();
+ }
+
+ private int getCharacterWidth(TextView widget) {
+ return (int) Math.ceil(widget.getPaint().getFontSpacing());
+ }
+
+ private int getScrollBoundsLeft(TextView widget) {
+ final Layout layout = widget.getLayout();
+ final int topLine = getTopLine(widget);
+ final int bottomLine = getBottomLine(widget);
+ if (topLine > bottomLine) {
+ return 0;
+ }
+ int left = Integer.MAX_VALUE;
+ for (int line = topLine; line <= bottomLine; line++) {
+ final int lineLeft = (int) Math.floor(layout.getLineLeft(line));
+ if (lineLeft < left) {
+ left = lineLeft;
+ }
+ }
+ return left;
+ }
+
+ private int getScrollBoundsRight(TextView widget) {
+ final Layout layout = widget.getLayout();
+ final int topLine = getTopLine(widget);
+ final int bottomLine = getBottomLine(widget);
+ if (topLine > bottomLine) {
+ return 0;
+ }
+ int right = Integer.MIN_VALUE;
+ for (int line = topLine; line <= bottomLine; line++) {
+ final int lineRight = (int) Math.ceil(layout.getLineRight(line));
+ if (lineRight > right) {
+ right = lineRight;
+ }
+ }
+ return right;
+ }
+
+ /**
+ * Performs a scroll left action.
+ * Scrolls left by the specified number of characters.
+ *
+ * @param widget The text view.
+ * @param buffer The text buffer.
+ * @param amount The number of characters to scroll by. Must be at least 1.
+ * @return True if the event was handled.
+ * @hide
+ */
+ protected boolean scrollLeft(TextView widget, Spannable buffer, int amount) {
+ final int minScrollX = getScrollBoundsLeft(widget);
+ int scrollX = widget.getScrollX();
+ if (scrollX > minScrollX) {
+ scrollX = Math.max(scrollX - getCharacterWidth(widget) * amount, minScrollX);
+ widget.scrollTo(scrollX, widget.getScrollY());
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * Performs a scroll right action.
+ * Scrolls right by the specified number of characters.
+ *
+ * @param widget The text view.
+ * @param buffer The text buffer.
+ * @param amount The number of characters to scroll by. Must be at least 1.
+ * @return True if the event was handled.
+ * @hide
+ */
+ protected boolean scrollRight(TextView widget, Spannable buffer, int amount) {
+ final int maxScrollX = getScrollBoundsRight(widget) - getInnerWidth(widget);
+ int scrollX = widget.getScrollX();
+ if (scrollX < maxScrollX) {
+ scrollX = Math.min(scrollX + getCharacterWidth(widget) * amount, maxScrollX);
+ widget.scrollTo(scrollX, widget.getScrollY());
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * Performs a scroll up action.
+ * Scrolls up by the specified number of lines.
+ *
+ * @param widget The text view.
+ * @param buffer The text buffer.
+ * @param amount The number of lines to scroll by. Must be at least 1.
+ * @return True if the event was handled.
+ * @hide
+ */
+ protected boolean scrollUp(TextView widget, Spannable buffer, int amount) {
+ final Layout layout = widget.getLayout();
+ final int top = widget.getScrollY();
+ int topLine = layout.getLineForVertical(top);
+ if (layout.getLineTop(topLine) == top) {
+ // If the top line is partially visible, bring it all the way
+ // into view; otherwise, bring the previous line into view.
+ topLine -= 1;
+ }
+ if (topLine >= 0) {
+ topLine = Math.max(topLine - amount + 1, 0);
+ Touch.scrollTo(widget, layout, widget.getScrollX(), layout.getLineTop(topLine));
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * Performs a scroll down action.
+ * Scrolls down by the specified number of lines.
+ *
+ * @param widget The text view.
+ * @param buffer The text buffer.
+ * @param amount The number of lines to scroll by. Must be at least 1.
+ * @return True if the event was handled.
+ * @hide
+ */
+ protected boolean scrollDown(TextView widget, Spannable buffer, int amount) {
+ final Layout layout = widget.getLayout();
+ final int innerHeight = getInnerHeight(widget);
+ final int bottom = widget.getScrollY() + innerHeight;
+ int bottomLine = layout.getLineForVertical(bottom);
+ if (layout.getLineTop(bottomLine + 1) < bottom + 1) {
+ // Less than a pixel of this line is out of view,
+ // so we must have tried to make it entirely in view
+ // and now want the next line to be in view instead.
+ bottomLine += 1;
+ }
+ final int limit = layout.getLineCount() - 1;
+ if (bottomLine <= limit) {
+ bottomLine = Math.min(bottomLine + amount - 1, limit);
+ Touch.scrollTo(widget, layout, widget.getScrollX(),
+ layout.getLineTop(bottomLine + 1) - innerHeight);
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * Performs a scroll page up action.
+ * Scrolls up by one page.
+ *
+ * @param widget The text view.
+ * @param buffer The text buffer.
+ * @return True if the event was handled.
+ * @hide
+ */
+ protected boolean scrollPageUp(TextView widget, Spannable buffer) {
+ final Layout layout = widget.getLayout();
+ final int top = widget.getScrollY() - getInnerHeight(widget);
+ int topLine = layout.getLineForVertical(top);
+ if (topLine >= 0) {
+ Touch.scrollTo(widget, layout, widget.getScrollX(), layout.getLineTop(topLine));
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * Performs a scroll page up action.
+ * Scrolls down by one page.
+ *
+ * @param widget The text view.
+ * @param buffer The text buffer.
+ * @return True if the event was handled.
+ * @hide
+ */
+ protected boolean scrollPageDown(TextView widget, Spannable buffer) {
+ final Layout layout = widget.getLayout();
+ final int innerHeight = getInnerHeight(widget);
+ final int bottom = widget.getScrollY() + innerHeight + innerHeight;
+ int bottomLine = layout.getLineForVertical(bottom);
+ if (bottomLine <= layout.getLineCount() - 1) {
+ Touch.scrollTo(widget, layout, widget.getScrollX(),
+ layout.getLineTop(bottomLine + 1) - innerHeight);
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * Performs a scroll to top action.
+ * Scrolls to the top of the document.
+ *
+ * @param widget The text view.
+ * @param buffer The text buffer.
+ * @return True if the event was handled.
+ * @hide
+ */
+ protected boolean scrollTop(TextView widget, Spannable buffer) {
+ final Layout layout = widget.getLayout();
+ if (getTopLine(widget) >= 0) {
+ Touch.scrollTo(widget, layout, widget.getScrollX(), layout.getLineTop(0));
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * Performs a scroll to bottom action.
+ * Scrolls to the bottom of the document.
+ *
+ * @param widget The text view.
+ * @param buffer The text buffer.
+ * @return True if the event was handled.
+ * @hide
+ */
+ protected boolean scrollBottom(TextView widget, Spannable buffer) {
+ final Layout layout = widget.getLayout();
+ final int lineCount = layout.getLineCount();
+ if (getBottomLine(widget) <= lineCount - 1) {
+ Touch.scrollTo(widget, layout, widget.getScrollX(),
+ layout.getLineTop(lineCount) - getInnerHeight(widget));
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * Performs a scroll to line start action.
+ * Scrolls to the start of the line.
+ *
+ * @param widget The text view.
+ * @param buffer The text buffer.
+ * @return True if the event was handled.
+ * @hide
+ */
+ protected boolean scrollLineStart(TextView widget, Spannable buffer) {
+ final int minScrollX = getScrollBoundsLeft(widget);
+ int scrollX = widget.getScrollX();
+ if (scrollX > minScrollX) {
+ widget.scrollTo(minScrollX, widget.getScrollY());
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * Performs a scroll to line end action.
+ * Scrolls to the end of the line.
+ *
+ * @param widget The text view.
+ * @param buffer The text buffer.
+ * @return True if the event was handled.
+ * @hide
+ */
+ protected boolean scrollLineEnd(TextView widget, Spannable buffer) {
+ final int maxScrollX = getScrollBoundsRight(widget) - getInnerWidth(widget);
+ int scrollX = widget.getScrollX();
+ if (scrollX < maxScrollX) {
+ widget.scrollTo(maxScrollX, widget.getScrollY());
+ return true;
+ }
+ return false;
+ }
}
diff --git a/core/java/android/text/method/MovementMethod.java b/core/java/android/text/method/MovementMethod.java
index 9167676..01979fd 100644
--- a/core/java/android/text/method/MovementMethod.java
+++ b/core/java/android/text/method/MovementMethod.java
@@ -47,6 +47,7 @@ public interface MovementMethod {
public void onTakeFocus(TextView widget, Spannable text, int direction);
public boolean onTrackballEvent(TextView widget, Spannable text, MotionEvent event);
public boolean onTouchEvent(TextView widget, Spannable text, MotionEvent event);
+ public boolean onGenericMotionEvent(TextView widget, Spannable text, MotionEvent event);
/**
* Returns true if this movement method allows arbitrary selection
diff --git a/core/java/android/text/method/ScrollingMovementMethod.java b/core/java/android/text/method/ScrollingMovementMethod.java
index 194ecc1..b9f5d5f 100644
--- a/core/java/android/text/method/ScrollingMovementMethod.java
+++ b/core/java/android/text/method/ScrollingMovementMethod.java
@@ -25,189 +25,54 @@ import android.view.View;
* A movement method that interprets movement keys by scrolling the text buffer.
*/
public class ScrollingMovementMethod extends BaseMovementMethod implements MovementMethod {
- private int getTopLine(TextView widget) {
- return widget.getLayout().getLineForVertical(widget.getScrollY());
- }
-
- private int getBottomLine(TextView widget) {
- return widget.getLayout().getLineForVertical(widget.getScrollY() + getInnerHeight(widget));
- }
-
- private int getInnerWidth(TextView widget) {
- return widget.getWidth() - widget.getTotalPaddingLeft() - widget.getTotalPaddingRight();
- }
-
- private int getInnerHeight(TextView widget) {
- return widget.getHeight() - widget.getTotalPaddingTop() - widget.getTotalPaddingBottom();
- }
-
- private int getCharacterWidth(TextView widget) {
- return (int) Math.ceil(widget.getPaint().getFontSpacing());
- }
-
- private int getScrollBoundsLeft(TextView widget) {
- final Layout layout = widget.getLayout();
- final int topLine = getTopLine(widget);
- final int bottomLine = getBottomLine(widget);
- if (topLine > bottomLine) {
- return 0;
- }
- int left = Integer.MAX_VALUE;
- for (int line = topLine; line <= bottomLine; line++) {
- final int lineLeft = (int) Math.floor(layout.getLineLeft(line));
- if (lineLeft < left) {
- left = lineLeft;
- }
- }
- return left;
- }
-
- private int getScrollBoundsRight(TextView widget) {
- final Layout layout = widget.getLayout();
- final int topLine = getTopLine(widget);
- final int bottomLine = getBottomLine(widget);
- if (topLine > bottomLine) {
- return 0;
- }
- int right = Integer.MIN_VALUE;
- for (int line = topLine; line <= bottomLine; line++) {
- final int lineRight = (int) Math.ceil(layout.getLineRight(line));
- if (lineRight > right) {
- right = lineRight;
- }
- }
- return right;
- }
-
@Override
protected boolean left(TextView widget, Spannable buffer) {
- final int minScrollX = getScrollBoundsLeft(widget);
- int scrollX = widget.getScrollX();
- if (scrollX > minScrollX) {
- scrollX = Math.max(scrollX - getCharacterWidth(widget), minScrollX);
- widget.scrollTo(scrollX, widget.getScrollY());
- return true;
- }
- return false;
+ return scrollLeft(widget, buffer, 1);
}
@Override
protected boolean right(TextView widget, Spannable buffer) {
- final int maxScrollX = getScrollBoundsRight(widget) - getInnerWidth(widget);
- int scrollX = widget.getScrollX();
- if (scrollX < maxScrollX) {
- scrollX = Math.min(scrollX + getCharacterWidth(widget), maxScrollX);
- widget.scrollTo(scrollX, widget.getScrollY());
- return true;
- }
- return false;
+ return scrollRight(widget, buffer, 1);
}
@Override
protected boolean up(TextView widget, Spannable buffer) {
- final Layout layout = widget.getLayout();
- final int top = widget.getScrollY();
- int topLine = layout.getLineForVertical(top);
- if (layout.getLineTop(topLine) == top) {
- // If the top line is partially visible, bring it all the way
- // into view; otherwise, bring the previous line into view.
- topLine -= 1;
- }
- if (topLine >= 0) {
- Touch.scrollTo(widget, layout, widget.getScrollX(), layout.getLineTop(topLine));
- return true;
- }
- return false;
+ return scrollUp(widget, buffer, 1);
}
@Override
protected boolean down(TextView widget, Spannable buffer) {
- final Layout layout = widget.getLayout();
- final int innerHeight = getInnerHeight(widget);
- final int bottom = widget.getScrollY() + innerHeight;
- int bottomLine = layout.getLineForVertical(bottom);
- if (layout.getLineTop(bottomLine + 1) < bottom + 1) {
- // Less than a pixel of this line is out of view,
- // so we must have tried to make it entirely in view
- // and now want the next line to be in view instead.
- bottomLine += 1;
- }
- if (bottomLine <= layout.getLineCount() - 1) {
- Touch.scrollTo(widget, layout, widget.getScrollX(),
- layout.getLineTop(bottomLine + 1) - innerHeight);
- return true;
- }
- return false;
+ return scrollDown(widget, buffer, 1);
}
@Override
protected boolean pageUp(TextView widget, Spannable buffer) {
- final Layout layout = widget.getLayout();
- final int top = widget.getScrollY() - getInnerHeight(widget);
- int topLine = layout.getLineForVertical(top);
- if (topLine >= 0) {
- Touch.scrollTo(widget, layout, widget.getScrollX(), layout.getLineTop(topLine));
- return true;
- }
- return false;
+ return scrollPageUp(widget, buffer);
}
@Override
protected boolean pageDown(TextView widget, Spannable buffer) {
- final Layout layout = widget.getLayout();
- final int innerHeight = getInnerHeight(widget);
- final int bottom = widget.getScrollY() + innerHeight + innerHeight;
- int bottomLine = layout.getLineForVertical(bottom);
- if (bottomLine <= layout.getLineCount() - 1) {
- Touch.scrollTo(widget, layout, widget.getScrollX(),
- layout.getLineTop(bottomLine + 1) - innerHeight);
- return true;
- }
- return false;
+ return scrollPageDown(widget, buffer);
}
@Override
protected boolean top(TextView widget, Spannable buffer) {
- final Layout layout = widget.getLayout();
- if (getTopLine(widget) >= 0) {
- Touch.scrollTo(widget, layout, widget.getScrollX(), layout.getLineTop(0));
- return true;
- }
- return false;
+ return scrollTop(widget, buffer);
}
@Override
protected boolean bottom(TextView widget, Spannable buffer) {
- final Layout layout = widget.getLayout();
- final int lineCount = layout.getLineCount();
- if (getBottomLine(widget) <= lineCount - 1) {
- Touch.scrollTo(widget, layout, widget.getScrollX(),
- layout.getLineTop(lineCount) - getInnerHeight(widget));
- return true;
- }
- return false;
+ return scrollBottom(widget, buffer);
}
@Override
protected boolean lineStart(TextView widget, Spannable buffer) {
- final int minScrollX = getScrollBoundsLeft(widget);
- int scrollX = widget.getScrollX();
- if (scrollX > minScrollX) {
- widget.scrollTo(minScrollX, widget.getScrollY());
- return true;
- }
- return false;
+ return scrollLineStart(widget, buffer);
}
@Override
protected boolean lineEnd(TextView widget, Spannable buffer) {
- final int maxScrollX = getScrollBoundsRight(widget) - getInnerWidth(widget);
- int scrollX = widget.getScrollX();
- if (scrollX < maxScrollX) {
- widget.scrollTo(maxScrollX, widget.getScrollY());
- return true;
- }
- return false;
+ return scrollLineEnd(widget, buffer);
}
@Override
diff --git a/core/java/android/util/AttributeSet.java b/core/java/android/util/AttributeSet.java
index 82592b9..470526c 100644
--- a/core/java/android/util/AttributeSet.java
+++ b/core/java/android/util/AttributeSet.java
@@ -56,10 +56,53 @@ package android.util;
* identifier associated with a particular XML attribute name.
*/
public interface AttributeSet {
+ /**
+ * Returns the number of attributes available in the set.
+ *
+ * @return A positive integer, or 0 if the set is empty.
+ */
public int getAttributeCount();
+
+ /**
+ * Returns the name of the specified attribute.
+ *
+ * @param index Index of the desired attribute, 0...count-1.
+ *
+ * @return A String containing the name of the attribute, or null if the
+ * attribute cannot be found.
+ */
public String getAttributeName(int index);
+
+ /**
+ * Returns the value of the specified attribute as a string representation.
+ *
+ * @param index Index of the desired attribute, 0...count-1.
+ *
+ * @return A String containing the value of the attribute, or null if the
+ * attribute cannot be found.
+ */
public String getAttributeValue(int index);
+
+ /**
+ * Returns the value of the specified attribute as a string representation.
+ * The lookup is performed using the attribute name.
+ *
+ * @param namespace The namespace of the attribute to get the value from.
+ * @param name The name of the attribute to get the value from.
+ *
+ * @return A String containing the value of the attribute, or null if the
+ * attribute cannot be found.
+ */
public String getAttributeValue(String namespace, String name);
+
+ /**
+ * Returns a description of the current position of the attribute set.
+ * For instance, if the attribute set is loaded from an XML document,
+ * the position description could indicate the current line number.
+ *
+ * @return A string representation of the current position in the set,
+ * may be null.
+ */
public String getPositionDescription();
/**
@@ -80,7 +123,8 @@ public interface AttributeSet {
/**
* Return the index of the value of 'attribute' in the list 'options'.
- *
+ *
+ * @param namespace Namespace of attribute to retrieve.
* @param attribute Name of attribute to retrieve.
* @param options List of strings whose values we are checking against.
* @param defaultValue Value returned if attribute doesn't exist or no
@@ -94,6 +138,7 @@ public interface AttributeSet {
/**
* Return the boolean value of 'attribute'.
*
+ * @param namespace Namespace of attribute to retrieve.
* @param attribute The attribute to retrieve.
* @param defaultValue What to return if the attribute isn't found.
*
@@ -111,6 +156,7 @@ public interface AttributeSet {
* "@package:type/resource"); the other method returns a resource
* identifier that identifies the name of the attribute.
*
+ * @param namespace Namespace of attribute to retrieve.
* @param attribute The attribute to retrieve.
* @param defaultValue What to return if the attribute isn't found.
*
@@ -122,6 +168,7 @@ public interface AttributeSet {
/**
* Return the integer value of 'attribute'.
*
+ * @param namespace Namespace of attribute to retrieve.
* @param attribute The attribute to retrieve.
* @param defaultValue What to return if the attribute isn't found.
*
@@ -135,6 +182,7 @@ public interface AttributeSet {
* unsigned value. In particular, the formats 0xn...n and #n...n are
* handled.
*
+ * @param namespace Namespace of attribute to retrieve.
* @param attribute The attribute to retrieve.
* @param defaultValue What to return if the attribute isn't found.
*
@@ -146,6 +194,7 @@ public interface AttributeSet {
/**
* Return the float value of 'attribute'.
*
+ * @param namespace Namespace of attribute to retrieve.
* @param attribute The attribute to retrieve.
* @param defaultValue What to return if the attribute isn't found.
*
@@ -165,8 +214,7 @@ public interface AttributeSet {
*
* @return Index in to 'options' or defaultValue.
*/
- public int getAttributeListValue(int index,
- String[] options, int defaultValue);
+ public int getAttributeListValue(int index, String[] options, int defaultValue);
/**
* Return the boolean value of attribute at 'index'.
@@ -176,8 +224,7 @@ public interface AttributeSet {
*
* @return Resulting value.
*/
- public boolean getAttributeBooleanValue(int index,
- boolean defaultValue);
+ public boolean getAttributeBooleanValue(int index, boolean defaultValue);
/**
* Return the value of attribute at 'index' as a resource identifier.
@@ -193,8 +240,7 @@ public interface AttributeSet {
*
* @return Resulting value.
*/
- public int getAttributeResourceValue(int index,
- int defaultValue);
+ public int getAttributeResourceValue(int index, int defaultValue);
/**
* Return the integer value of attribute at 'index'.
@@ -204,8 +250,7 @@ public interface AttributeSet {
*
* @return Resulting value.
*/
- public int getAttributeIntValue(int index,
- int defaultValue);
+ public int getAttributeIntValue(int index, int defaultValue);
/**
* Return the integer value of attribute at 'index' that is formatted as an
@@ -217,8 +262,7 @@ public interface AttributeSet {
*
* @return Resulting value.
*/
- public int getAttributeUnsignedIntValue(int index,
- int defaultValue);
+ public int getAttributeUnsignedIntValue(int index, int defaultValue);
/**
* Return the float value of attribute at 'index'.
@@ -228,8 +272,7 @@ public interface AttributeSet {
*
* @return Resulting value.
*/
- public float getAttributeFloatValue(int index,
- float defaultValue);
+ public float getAttributeFloatValue(int index, float defaultValue);
/**
* Return the value of the "id" attribute or null if there is not one.
@@ -266,4 +309,3 @@ public interface AttributeSet {
*/
public int getStyleAttribute();
}
-
diff --git a/core/java/android/util/Config.java b/core/java/android/util/Config.java
index 924b49d..becb882 100644
--- a/core/java/android/util/Config.java
+++ b/core/java/android/util/Config.java
@@ -21,8 +21,9 @@ package android.util;
* on release vs. debug build.
* {@more}
*/
-public final class Config
-{
+public final class Config {
+ /** @hide */ public Config() {}
+
/**
* If this is a debug build, this field will be true.
*/
diff --git a/core/java/android/util/DebugUtils.java b/core/java/android/util/DebugUtils.java
index 65fc35c..7e3c855 100644
--- a/core/java/android/util/DebugUtils.java
+++ b/core/java/android/util/DebugUtils.java
@@ -20,9 +20,11 @@ import java.lang.reflect.Method;
import java.lang.reflect.InvocationTargetException;
/**
- * <p>Various utilities for debugging and logging.</p>
+ * <p>Various utilities for debugging and logging.</p>
*/
public class DebugUtils {
+ /** @hide */ public DebugUtils() {}
+
/**
* <p>Filters objects against the <code>ANDROID_OBJECT_FILTER</code>
* environment variable. This environment variable can filter objects
diff --git a/core/java/android/util/EventLog.java b/core/java/android/util/EventLog.java
index b596d32..29c0ba2 100644
--- a/core/java/android/util/EventLog.java
+++ b/core/java/android/util/EventLog.java
@@ -42,6 +42,8 @@ import java.util.regex.Pattern;
* event-log-tags file defines the payload contents for each type code.
*/
public class EventLog {
+ /** @hide */ public EventLog() {}
+
private static final String TAG = "EventLog";
private static final String TAGS_FILE = "/system/etc/event-log-tags";
diff --git a/core/java/android/util/LruCache.java b/core/java/android/util/LruCache.java
index 5578e6a..a1501e6 100644
--- a/core/java/android/util/LruCache.java
+++ b/core/java/android/util/LruCache.java
@@ -26,8 +26,7 @@ import java.util.Map;
* become eligible for garbage collection.
*
* <p>If your cached values hold resources that need to be explicitly released,
- * override {@link #entryEvicted}. This method is only invoked when values are
- * evicted. Values replaced by calls to {@link #put} must be released manually.
+ * override {@link #entryRemoved}.
*
* <p>If a cache miss should be computed on demand for the corresponding keys,
* override {@link #create}. This simplifies the calling code, allowing it to
@@ -88,29 +87,52 @@ public class LruCache<K, V> {
* head of the queue. This returns null if a value is not cached and cannot
* be created.
*/
- public synchronized final V get(K key) {
+ public final V get(K key) {
if (key == null) {
throw new NullPointerException("key == null");
}
- V result = map.get(key);
- if (result != null) {
- hitCount++;
- return result;
+ V mapValue;
+ synchronized (this) {
+ mapValue = map.get(key);
+ if (mapValue != null) {
+ hitCount++;
+ return mapValue;
+ }
+ missCount++;
}
- missCount++;
+ /*
+ * Attempt to create a value. This may take a long time, and the map
+ * may be different when create() returns. If a conflicting value was
+ * added to the map while create() was working, we leave that value in
+ * the map and release the created value.
+ */
- // TODO: release the lock while calling this potentially slow user code
- result = create(key);
+ V createdValue = create(key);
+ if (createdValue == null) {
+ return null;
+ }
- if (result != null) {
+ synchronized (this) {
createCount++;
- size += safeSizeOf(key, result);
- map.put(key, result);
+ mapValue = map.put(key, createdValue);
+
+ if (mapValue != null) {
+ // There was a conflict so undo that last put
+ map.put(key, mapValue);
+ } else {
+ size += safeSizeOf(key, createdValue);
+ }
+ }
+
+ if (mapValue != null) {
+ entryRemoved(false, key, createdValue, mapValue);
+ return mapValue;
+ } else {
trimToSize(maxSize);
+ return createdValue;
}
- return result;
}
/**
@@ -120,42 +142,61 @@ public class LruCache<K, V> {
* @return the previous value mapped by {@code key}. Although that entry is
* no longer cached, it has not been passed to {@link #entryEvicted}.
*/
- public synchronized final V put(K key, V value) {
+ public final V put(K key, V value) {
if (key == null || value == null) {
throw new NullPointerException("key == null || value == null");
}
- putCount++;
- size += safeSizeOf(key, value);
- V previous = map.put(key, value);
+ V previous;
+ synchronized (this) {
+ putCount++;
+ size += safeSizeOf(key, value);
+ previous = map.put(key, value);
+ if (previous != null) {
+ size -= safeSizeOf(key, previous);
+ }
+ }
+
if (previous != null) {
- size -= safeSizeOf(key, previous);
+ entryRemoved(false, key, previous, value);
}
+
trimToSize(maxSize);
return previous;
}
+ /**
+ * @param maxSize the maximum size of the cache before returning. May be -1
+ * to evict even 0-sized elements.
+ */
private void trimToSize(int maxSize) {
- while (size > maxSize) {
- Map.Entry<K, V> toEvict = map.eldest(); // equal to map.entrySet().iterator().next();
- if (toEvict == null) {
- break; // map is empty; if size is not 0 then throw an error below
+ while (true) {
+ K key;
+ V value;
+ synchronized (this) {
+ if (size < 0 || (map.isEmpty() && size != 0)) {
+ throw new IllegalStateException(getClass().getName()
+ + ".sizeOf() is reporting inconsistent results!");
+ }
+
+ if (size <= maxSize) {
+ break;
+ }
+
+ Map.Entry<K, V> toEvict = map.eldest();
+ if (toEvict == null) {
+ break;
+ }
+
+ key = toEvict.getKey();
+ value = toEvict.getValue();
+ map.remove(key);
+ size -= safeSizeOf(key, value);
+ evictionCount++;
}
- K key = toEvict.getKey();
- V value = toEvict.getValue();
- map.remove(key);
- size -= safeSizeOf(key, value);
- evictionCount++;
-
- // TODO: release the lock while calling this potentially slow user code
entryEvicted(key, value);
}
-
- if (size < 0 || (map.isEmpty() && size != 0)) {
- throw new IllegalStateException(getClass().getName()
- + ".sizeOf() is reporting inconsistent results!");
- }
}
/**
@@ -164,28 +205,67 @@ public class LruCache<K, V> {
* @return the previous value mapped by {@code key}. Although that entry is
* no longer cached, it has not been passed to {@link #entryEvicted}.
*/
- public synchronized final V remove(K key) {
+ public final V remove(K key) {
if (key == null) {
throw new NullPointerException("key == null");
}
- V previous = map.remove(key);
+ V previous;
+ synchronized (this) {
+ previous = map.remove(key);
+ if (previous != null) {
+ size -= safeSizeOf(key, previous);
+ }
+ }
+
if (previous != null) {
- size -= safeSizeOf(key, previous);
+ entryRemoved(false, key, previous, null);
}
+
return previous;
}
/**
- * Called for entries that have reached the tail of the least recently used
- * queue and are be removed. The default implementation does nothing.
+ * Calls {@link #entryRemoved}.
+ *
+ * @deprecated replaced by entryRemoved
+ */
+ @Deprecated
+ protected void entryEvicted(K key, V value) {
+ entryRemoved(true, key, value, null);
+ }
+
+ /**
+ * Called for entries that have been evicted or removed. This method is
+ * invoked when a value is evicted to make space, removed by a call to
+ * {@link #remove}, or replaced by a call to {@link #put}. The default
+ * implementation does nothing.
+ *
+ * <p>The method is called without synchronization: other threads may
+ * access the cache while this method is executing.
+ *
+ * @param evicted true if the entry is being removed to make space, false
+ * if the removal was caused by a {@link #put} or {@link #remove}.
+ * @param newValue the new value for {@code key}, if it exists. If non-null,
+ * this removal was caused by a {@link #put}. Otherwise it was caused by
+ * an eviction or a {@link #remove}.
*/
- protected void entryEvicted(K key, V value) {}
+ protected void entryRemoved(boolean evicted, K key, V oldValue, V newValue) {}
/**
* Called after a cache miss to compute a value for the corresponding key.
* Returns the computed value or null if no value can be computed. The
* default implementation returns null.
+ *
+ * <p>The method is called without synchronization: other threads may
+ * access the cache while this method is executing.
+ *
+ * <p>If a value for {@code key} exists in the cache when this method
+ * returns, the created value will be released with {@link #entryRemoved}
+ * and discarded. This can occur when multiple threads request the same key
+ * at the same time (causing multiple values to be created), or when one
+ * thread calls {@link #put} while another is creating a value for the same
+ * key.
*/
protected V create(K key) {
return null;
@@ -213,7 +293,7 @@ public class LruCache<K, V> {
/**
* Clear the cache, calling {@link #entryEvicted} on each removed entry.
*/
- public synchronized final void evictAll() {
+ public final void evictAll() {
trimToSize(-1); // -1 will evict 0-sized elements
}
diff --git a/core/java/android/util/StateSet.java b/core/java/android/util/StateSet.java
index 21d8e45..2623638 100644
--- a/core/java/android/util/StateSet.java
+++ b/core/java/android/util/StateSet.java
@@ -36,13 +36,14 @@ import com.android.internal.R;
*/
public class StateSet {
+ /** @hide */ public StateSet() {}
public static final int[] WILD_CARD = new int[0];
public static final int[] NOTHING = new int[] { 0 };
/**
* Return whether the stateSetOrSpec is matched by all StateSets.
- *
+ *
* @param stateSetOrSpec a state set or state spec.
*/
public static boolean isWildCard(int[] stateSetOrSpec) {
@@ -51,7 +52,7 @@ public class StateSet {
/**
* Return whether the stateSet matches the desired stateSpec.
- *
+ *
* @param stateSpec an array of required (if positive) or
* prohibited (if negative) {@link android.view.View} states.
* @param stateSet an array of {@link android.view.View} states
@@ -111,7 +112,7 @@ public class StateSet {
/**
* Return whether the state matches the desired stateSpec.
- *
+ *
* @param stateSpec an array of required (if positive) or
* prohibited (if negative) {@link android.view.View} states.
* @param state a {@link android.view.View} state
@@ -148,13 +149,13 @@ public class StateSet {
System.arraycopy(states, 0, trimmedStates, 0, newSize);
return trimmedStates;
}
-
+
public static String dump(int[] states) {
StringBuilder sb = new StringBuilder();
-
+
int count = states.length;
for (int i = 0; i < count; i++) {
-
+
switch (states[i]) {
case R.attr.state_window_focused:
sb.append("W ");
@@ -173,7 +174,7 @@ public class StateSet {
break;
}
}
-
+
return sb.toString();
}
}
diff --git a/core/java/android/util/TimeUtils.java b/core/java/android/util/TimeUtils.java
index 85ce5e1..9042505 100644
--- a/core/java/android/util/TimeUtils.java
+++ b/core/java/android/util/TimeUtils.java
@@ -34,6 +34,7 @@ import com.android.internal.util.XmlUtils;
* A class containing utility methods related to time zones.
*/
public class TimeUtils {
+ /** @hide */ public TimeUtils() {}
private static final String TAG = "TimeUtils";
/**
@@ -116,14 +117,14 @@ public class TimeUtils {
* in use. The format of the string is dependent on the underlying time zone
* database implementation, but will typically contain the year in which the database
* was updated plus a letter from a to z indicating changes made within that year.
- *
+ *
* <p>Time zone database updates should be expected to occur periodically due to
* political and legal changes that cannot be anticipated in advance. Therefore,
* when computing the UTC time for a future event, applications should be aware that
* the results may differ following a time zone database update. This method allows
* applications to detect that a database change has occurred, and to recalculate any
* cached times accordingly.
- *
+ *
* <p>The time zone database may be assumed to change only when the device runtime
* is restarted. Therefore, it is not necessary to re-query the database version
* during the lifetime of an activity.
@@ -134,14 +135,14 @@ public class TimeUtils {
/** @hide Field length that can hold 999 days of time */
public static final int HUNDRED_DAY_FIELD_LEN = 19;
-
+
private static final int SECONDS_PER_MINUTE = 60;
private static final int SECONDS_PER_HOUR = 60 * 60;
private static final int SECONDS_PER_DAY = 24 * 60 * 60;
private static final Object sFormatSync = new Object();
private static char[] sFormatStr = new char[HUNDRED_DAY_FIELD_LEN+5];
-
+
static private int accumField(int amt, int suffix, boolean always, int zeropad) {
if (amt > 99 || (always && zeropad >= 3)) {
return 3+suffix;
@@ -154,7 +155,7 @@ public class TimeUtils {
}
return 0;
}
-
+
static private int printField(char[] formatStr, int amt, char suffix, int pos,
boolean always, int zeropad) {
if (always || amt > 0) {
@@ -178,24 +179,24 @@ public class TimeUtils {
}
return pos;
}
-
+
private static int formatDurationLocked(long duration, int fieldLen) {
if (sFormatStr.length < fieldLen) {
sFormatStr = new char[fieldLen];
}
-
+
char[] formatStr = sFormatStr;
-
+
if (duration == 0) {
int pos = 0;
fieldLen -= 1;
while (pos < fieldLen) {
- formatStr[pos] = ' ';
+ formatStr[pos++] = ' ';
}
formatStr[pos] = '0';
return pos+1;
}
-
+
char prefix;
if (duration > 0) {
prefix = '+';
@@ -222,7 +223,7 @@ public class TimeUtils {
}
int pos = 0;
-
+
if (fieldLen != 0) {
int myLen = accumField(days, 1, false, 0);
myLen += accumField(hours, 1, myLen > 0, 2);
@@ -235,10 +236,10 @@ public class TimeUtils {
myLen++;
}
}
-
+
formatStr[pos] = prefix;
pos++;
-
+
int start = pos;
boolean zeropad = fieldLen != 0;
pos = printField(formatStr, days, 'd', pos, false, 0);
@@ -249,7 +250,7 @@ public class TimeUtils {
formatStr[pos] = 's';
return pos + 1;
}
-
+
/** @hide Just for debugging; not internationalized. */
public static void formatDuration(long duration, StringBuilder builder) {
synchronized (sFormatSync) {
@@ -270,7 +271,7 @@ public class TimeUtils {
public static void formatDuration(long duration, PrintWriter pw) {
formatDuration(duration, pw, 0);
}
-
+
/** @hide Just for debugging; not internationalized. */
public static void formatDuration(long time, long now, PrintWriter pw) {
if (time == 0) {
diff --git a/core/java/android/util/Xml.java b/core/java/android/util/Xml.java
index 873a218..b0c33e5 100644
--- a/core/java/android/util/Xml.java
+++ b/core/java/android/util/Xml.java
@@ -38,6 +38,7 @@ import org.apache.harmony.xml.ExpatReader;
* XML utility methods.
*/
public class Xml {
+ /** @hide */ public Xml() {}
/**
* {@link org.xmlpull.v1.XmlPullParser} "relaxed" feature name.
@@ -156,21 +157,21 @@ public class Xml {
}
throw new UnsupportedEncodingException(encodingName);
}
-
+
/**
* Return an AttributeSet interface for use with the given XmlPullParser.
* If the given parser itself implements AttributeSet, that implementation
* is simply returned. Otherwise a wrapper class is
* instantiated on top of the XmlPullParser, as a proxy for retrieving its
* attributes, and returned to you.
- *
+ *
* @param parser The existing parser for which you would like an
* AttributeSet.
- *
+ *
* @return An AttributeSet you can use to retrieve the
* attribute values at each of the tags as the parser moves
* through its XML document.
- *
+ *
* @see AttributeSet
*/
public static AttributeSet asAttributeSet(XmlPullParser parser) {
diff --git a/core/java/android/view/Display.java b/core/java/android/view/Display.java
index b748064..126f409 100644
--- a/core/java/android/view/Display.java
+++ b/core/java/android/view/Display.java
@@ -79,6 +79,11 @@ public class Display
*/
native public int getHeight();
+ /** @hide special for when we are faking the screen size. */
+ native public int getRealWidth();
+ /** @hide special for when we are faking the screen size. */
+ native public int getRealHeight();
+
/**
* Returns the rotation of the screen from its "natural" orientation.
* The returned value may be {@link Surface#ROTATION_0 Surface.ROTATION_0}
@@ -136,11 +141,6 @@ public class Display
outMetrics.ydpi = mDpiY;
}
- /**
- * @hide Helper for our fake display size hack.
- */
- native public static int unmapDisplaySize(int newSize);
-
/*
* We use a class initializer to allow the native code to cache some
* field offsets.
diff --git a/core/java/android/view/IWindowManager.aidl b/core/java/android/view/IWindowManager.aidl
index 51653df..dd8242a 100644
--- a/core/java/android/view/IWindowManager.aidl
+++ b/core/java/android/view/IWindowManager.aidl
@@ -100,6 +100,8 @@ interface IWindowManager
void disableKeyguard(IBinder token, String tag);
void reenableKeyguard(IBinder token);
void exitKeyguardSecurely(IOnKeyguardExitResult callback);
+ boolean isKeyguardLocked();
+ boolean isKeyguardSecure();
boolean inKeyguardRestrictedInputMode();
void closeSystemDialogs(String reason);
diff --git a/core/java/android/view/MotionEvent.java b/core/java/android/view/MotionEvent.java
index cc37a28..a26dd04 100644
--- a/core/java/android/view/MotionEvent.java
+++ b/core/java/android/view/MotionEvent.java
@@ -40,6 +40,12 @@ import android.util.SparseArray;
* by a motion event with {@link #ACTION_UP} or when gesture is canceled
* with {@link #ACTION_CANCEL}.
* </p><p>
+ * Some pointing devices such as mice may support vertical and/or horizontal scrolling.
+ * A scroll event is reported as a generic motion event with {@link #ACTION_SCROLL} that
+ * includes the relative scroll offset in the {@link #AXIS_VSCROLL} and
+ * {@link #AXIS_HSCROLL} axes. See {@link #getAxisValue(int)} for information
+ * about retrieving these additional axes.
+ * </p><p>
* On trackball devices with source class {@link InputDevice#SOURCE_CLASS_TRACKBALL},
* the pointer coordinates specify relative movements as X/Y deltas.
* A trackball gesture consists of a sequence of movements described by motion
@@ -51,6 +57,8 @@ import android.util.SparseArray;
* The joystick axis values are normalized to a range of -1.0 to 1.0 where 0.0 corresponds
* to the center position. More information about the set of available axes and the
* range of motion can be obtained using {@link InputDevice#getMotionRange}.
+ * Some common joystick axes are {@link #AXIS_X}, {@link #AXIS_Y},
+ * {@link #AXIS_HAT_X}, {@link #AXIS_HAT_Y}, {@link #AXIS_Z} and {@link #AXIS_RZ}.
* </p><p>
* Motion events always report movements for all pointers at once. The number
* of pointers only ever changes by one as individual pointers go up and down,
@@ -163,10 +171,30 @@ public final class MotionEvent extends InputEvent implements Parcelable {
* is not down (unlike {@link #ACTION_MOVE}). The motion contains the most
* recent point, as well as any intermediate points since the last
* hover move event.
+ * <p>
+ * This action is not a touch event so it is delivered to
+ * {@link View#onGenericMotionEvent(MotionEvent)} rather than
+ * {@link View#onTouchEvent(MotionEvent)}.
+ * </p>
*/
public static final int ACTION_HOVER_MOVE = 7;
/**
+ * Constant for {@link #getAction}: The motion event contains relative
+ * vertical and/or horizontal scroll offsets. Use {@link #getAxisValue(int)}
+ * to retrieve the information from {@link #AXIS_VSCROLL} and {@link #AXIS_HSCROLL}.
+ * The pointer may or may not be down when this event is dispatched.
+ * This action is always delivered to the winder under the pointer, which
+ * may not be the window currently touched.
+ * <p>
+ * This action is not a touch event so it is delivered to
+ * {@link View#onGenericMotionEvent(MotionEvent)} rather than
+ * {@link View#onTouchEvent(MotionEvent)}.
+ * </p>
+ */
+ public static final int ACTION_SCROLL = 8;
+
+ /**
* Bits in the action code that represent a pointer index, used with
* {@link #ACTION_POINTER_DOWN} and {@link #ACTION_POINTER_UP}. Shifting
* down by {@link #ACTION_POINTER_INDEX_SHIFT} provides the actual pointer
@@ -483,7 +511,7 @@ public final class MotionEvent extends InputEvent implements Parcelable {
* <p>
* <ul>
* <li>For a mouse, reports the relative movement of the vertical scroll wheel.
- * The value is normalized to a range from -1.0 (up) to 1.0 (down).
+ * The value is normalized to a range from -1.0 (down) to 1.0 (up).
* </ul>
* </p><p>
* This axis should be used to scroll views vertically.
@@ -1237,6 +1265,32 @@ public final class MotionEvent extends InputEvent implements Parcelable {
}
/**
+ * Returns true if this motion event is a touch event.
+ * <p>
+ * Specifically excludes pointer events with action {@link #ACTION_HOVER_MOVE}
+ * or {@link #ACTION_SCROLL} because they are not actually touch events
+ * (the pointer is not down).
+ * </p>
+ * @return True if this motion event is a touch event.
+ * @hide
+ */
+ public final boolean isTouchEvent() {
+ if ((getSource() & InputDevice.SOURCE_CLASS_POINTER) != 0) {
+ switch (getActionMasked()) {
+ case MotionEvent.ACTION_DOWN:
+ case MotionEvent.ACTION_MOVE:
+ case MotionEvent.ACTION_UP:
+ case MotionEvent.ACTION_POINTER_DOWN:
+ case MotionEvent.ACTION_POINTER_UP:
+ case MotionEvent.ACTION_CANCEL:
+ case MotionEvent.ACTION_OUTSIDE:
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
* Gets the motion event flags.
*
* @see #FLAG_WINDOW_IS_OBSCURED
@@ -2174,10 +2228,14 @@ public final class MotionEvent extends InputEvent implements Parcelable {
return "ACTION_UP";
case ACTION_CANCEL:
return "ACTION_CANCEL";
+ case ACTION_OUTSIDE:
+ return "ACTION_OUTSIDE";
case ACTION_MOVE:
return "ACTION_MOVE";
case ACTION_HOVER_MOVE:
return "ACTION_HOVER_MOVE";
+ case ACTION_SCROLL:
+ return "ACTION_SCROLL";
}
int index = (action & ACTION_POINTER_INDEX_MASK) >> ACTION_POINTER_INDEX_SHIFT;
switch (action & ACTION_MASK) {
diff --git a/core/java/android/view/ScaleGestureDetector.java b/core/java/android/view/ScaleGestureDetector.java
index 17b5dd7..0124151 100644
--- a/core/java/android/view/ScaleGestureDetector.java
+++ b/core/java/android/view/ScaleGestureDetector.java
@@ -154,6 +154,11 @@ public class ScaleGestureDetector {
private float mBottomSlopEdge;
private boolean mSloppyGesture;
+ // Pointer IDs currently responsible for the two fingers controlling the gesture
+ private int mActiveId0;
+ private int mActiveId1;
+ private boolean mActive0MostRecent;
+
public ScaleGestureDetector(Context context, OnScaleGestureListener listener) {
ViewConfiguration config = ViewConfiguration.get(context);
mContext = context;
@@ -162,11 +167,21 @@ public class ScaleGestureDetector {
}
public boolean onTouchEvent(MotionEvent event) {
- final int action = event.getAction();
+ final int action = event.getActionMasked();
boolean handled = true;
if (!mGestureInProgress) {
- switch (action & MotionEvent.ACTION_MASK) {
+ switch (action) {
+ case MotionEvent.ACTION_DOWN: {
+ mActiveId0 = event.getPointerId(0);
+ mActive0MostRecent = true;
+ }
+ break;
+
+ case MotionEvent.ACTION_UP:
+ reset();
+ break;
+
case MotionEvent.ACTION_POINTER_DOWN: {
// We have a new multi-finger gesture
@@ -175,12 +190,15 @@ public class ScaleGestureDetector {
mRightSlopEdge = metrics.widthPixels - mEdgeSlop;
mBottomSlopEdge = metrics.heightPixels - mEdgeSlop;
- // Be paranoid in case we missed an event
- reset();
-
+ if (mPrevEvent != null) mPrevEvent.recycle();
mPrevEvent = MotionEvent.obtain(event);
mTimeDelta = 0;
+ int index1 = event.getActionIndex();
+ int index0 = event.findPointerIndex(mActiveId0);
+ mActiveId1 = event.getPointerId(index1);
+ mActive0MostRecent = false;
+
setContext(event);
// Check if we have a sloppy gesture. If so, delay
@@ -190,10 +208,10 @@ public class ScaleGestureDetector {
final float edgeSlop = mEdgeSlop;
final float rightSlop = mRightSlopEdge;
final float bottomSlop = mBottomSlopEdge;
- final float x0 = event.getRawX();
- final float y0 = event.getRawY();
- final float x1 = getRawX(event, 1);
- final float y1 = getRawY(event, 1);
+ float x0 = getRawX(event, index0);
+ float y0 = getRawY(event, index0);
+ float x1 = getRawX(event, index1);
+ float y1 = getRawY(event, index1);
boolean p0sloppy = x0 < edgeSlop || y0 < edgeSlop
|| x0 > rightSlop || y0 > bottomSlop;
@@ -205,14 +223,15 @@ public class ScaleGestureDetector {
mFocusY = -1;
mSloppyGesture = true;
} else if (p0sloppy) {
- mFocusX = event.getX(1);
- mFocusY = event.getY(1);
+ mFocusX = event.getX(index1);
+ mFocusY = event.getY(index1);
mSloppyGesture = true;
} else if (p1sloppy) {
- mFocusX = event.getX(0);
- mFocusY = event.getY(0);
+ mFocusX = event.getX(index0);
+ mFocusY = event.getY(index0);
mSloppyGesture = true;
} else {
+ mSloppyGesture = false;
mGestureInProgress = mListener.onScaleBegin(this);
}
}
@@ -224,25 +243,52 @@ public class ScaleGestureDetector {
final float edgeSlop = mEdgeSlop;
final float rightSlop = mRightSlopEdge;
final float bottomSlop = mBottomSlopEdge;
- final float x0 = event.getRawX();
- final float y0 = event.getRawY();
- final float x1 = getRawX(event, 1);
- final float y1 = getRawY(event, 1);
+ int index0 = event.findPointerIndex(mActiveId0);
+ int index1 = event.findPointerIndex(mActiveId1);
+
+ float x0 = getRawX(event, index0);
+ float y0 = getRawY(event, index0);
+ float x1 = getRawX(event, index1);
+ float y1 = getRawY(event, index1);
boolean p0sloppy = x0 < edgeSlop || y0 < edgeSlop
- || x0 > rightSlop || y0 > bottomSlop;
+ || x0 > rightSlop || y0 > bottomSlop;
boolean p1sloppy = x1 < edgeSlop || y1 < edgeSlop
- || x1 > rightSlop || y1 > bottomSlop;
+ || x1 > rightSlop || y1 > bottomSlop;
+
+ if (p0sloppy) {
+ // Do we have a different pointer that isn't sloppy?
+ int index = findNewActiveIndex(event, mActiveId1, index0);
+ if (index >= 0) {
+ index0 = index;
+ mActiveId0 = event.getPointerId(index);
+ x0 = getRawX(event, index);
+ y0 = getRawY(event, index);
+ p0sloppy = false;
+ }
+ }
+
+ if (p1sloppy) {
+ // Do we have a different pointer that isn't sloppy?
+ int index = findNewActiveIndex(event, mActiveId0, index1);
+ if (index >= 0) {
+ index1 = index;
+ mActiveId1 = event.getPointerId(index);
+ x1 = getRawX(event, index);
+ y1 = getRawY(event, index);
+ p1sloppy = false;
+ }
+ }
if(p0sloppy && p1sloppy) {
mFocusX = -1;
mFocusY = -1;
} else if (p0sloppy) {
- mFocusX = event.getX(1);
- mFocusY = event.getY(1);
+ mFocusX = event.getX(index1);
+ mFocusY = event.getY(index1);
} else if (p1sloppy) {
- mFocusX = event.getX(0);
- mFocusY = event.getY(0);
+ mFocusX = event.getX(index0);
+ mFocusY = event.getY(index0);
} else {
mSloppyGesture = false;
mGestureInProgress = mListener.onScaleBegin(this);
@@ -252,43 +298,119 @@ public class ScaleGestureDetector {
case MotionEvent.ACTION_POINTER_UP:
if (mSloppyGesture) {
- // Set focus point to the remaining finger
- int id = (((action & MotionEvent.ACTION_POINTER_INDEX_MASK)
- >> MotionEvent.ACTION_POINTER_INDEX_SHIFT) == 0) ? 1 : 0;
- mFocusX = event.getX(id);
- mFocusY = event.getY(id);
+ final int pointerCount = event.getPointerCount();
+ final int actionIndex = event.getActionIndex();
+ final int actionId = event.getPointerId(actionIndex);
+
+ if (pointerCount > 2) {
+ if (actionId == mActiveId0) {
+ final int newIndex = findNewActiveIndex(event, mActiveId1, actionIndex);
+ if (newIndex >= 0) mActiveId0 = event.getPointerId(newIndex);
+ } else if (actionId == mActiveId1) {
+ final int newIndex = findNewActiveIndex(event, mActiveId0, actionIndex);
+ if (newIndex >= 0) mActiveId1 = event.getPointerId(newIndex);
+ }
+ } else {
+ // Set focus point to the remaining finger
+ final int index = event.findPointerIndex(actionId == mActiveId0 ?
+ mActiveId1 : mActiveId0);
+ mActiveId0 = event.getPointerId(index);
+ mActive0MostRecent = true;
+ mActiveId1 = -1;
+ mFocusX = event.getX(index);
+ mFocusY = event.getY(index);
+ }
}
break;
}
} else {
// Transform gesture in progress - attempt to handle it
- switch (action & MotionEvent.ACTION_MASK) {
- case MotionEvent.ACTION_POINTER_UP:
- // Gesture ended
+ switch (action) {
+ case MotionEvent.ACTION_POINTER_DOWN: {
+ // End the old gesture and begin a new one with the most recent two fingers.
+ mListener.onScaleEnd(this);
+ final int oldActive0 = mActiveId0;
+ final int oldActive1 = mActiveId1;
+ reset();
+
+ mPrevEvent = MotionEvent.obtain(event);
+ mActiveId0 = mActive0MostRecent ? oldActive0 : oldActive1;
+ mActiveId1 = event.getPointerId(event.getActionIndex());
+ mActive0MostRecent = false;
+
setContext(event);
- // Set focus point to the remaining finger
- int id = (((action & MotionEvent.ACTION_POINTER_INDEX_MASK)
- >> MotionEvent.ACTION_POINTER_INDEX_SHIFT) == 0) ? 1 : 0;
- mFocusX = event.getX(id);
- mFocusY = event.getY(id);
+ mGestureInProgress = mListener.onScaleBegin(this);
+ }
+ break;
- if (!mSloppyGesture) {
- mListener.onScaleEnd(this);
+ case MotionEvent.ACTION_POINTER_UP: {
+ final int pointerCount = event.getPointerCount();
+ final int actionIndex = event.getActionIndex();
+ final int actionId = event.getPointerId(actionIndex);
+
+ boolean gestureEnded = false;
+ if (pointerCount > 2) {
+ if (actionId == mActiveId0) {
+ final int newIndex = findNewActiveIndex(event, mActiveId1, actionIndex);
+ if (newIndex >= 0) {
+ mListener.onScaleEnd(this);
+ mActiveId0 = event.getPointerId(newIndex);
+ mActive0MostRecent = true;
+ mPrevEvent = MotionEvent.obtain(event);
+ setContext(event);
+ mGestureInProgress = mListener.onScaleBegin(this);
+ } else {
+ gestureEnded = true;
+ }
+ } else if (actionId == mActiveId1) {
+ final int newIndex = findNewActiveIndex(event, mActiveId0, actionIndex);
+ if (newIndex >= 0) {
+ mListener.onScaleEnd(this);
+ mActiveId1 = event.getPointerId(newIndex);
+ mActive0MostRecent = false;
+ mPrevEvent = MotionEvent.obtain(event);
+ setContext(event);
+ mGestureInProgress = mListener.onScaleBegin(this);
+ } else {
+ gestureEnded = true;
+ }
+ }
+ mPrevEvent.recycle();
+ mPrevEvent = MotionEvent.obtain(event);
+ setContext(event);
+ } else {
+ gestureEnded = true;
}
- reset();
- break;
+ if (gestureEnded) {
+ // Gesture ended
+ setContext(event);
+
+ // Set focus point to the remaining finger
+ final int activeId = actionId == mActiveId0 ? mActiveId1 : mActiveId0;
+ final int index = event.findPointerIndex(activeId);
+ mFocusX = event.getX(index);
+ mFocusY = event.getY(index);
- case MotionEvent.ACTION_CANCEL:
- if (!mSloppyGesture) {
mListener.onScaleEnd(this);
+ reset();
+ mActiveId0 = activeId;
+ mActive0MostRecent = true;
}
+ }
+ break;
+ case MotionEvent.ACTION_CANCEL:
+ mListener.onScaleEnd(this);
+ reset();
+ break;
+
+ case MotionEvent.ACTION_UP:
reset();
break;
- case MotionEvent.ACTION_MOVE:
+ case MotionEvent.ACTION_MOVE: {
setContext(event);
// Only accept the event if our relative pressure is within
@@ -302,16 +424,44 @@ public class ScaleGestureDetector {
mPrevEvent = MotionEvent.obtain(event);
}
}
- break;
+ }
+ break;
}
}
return handled;
}
+ private int findNewActiveIndex(MotionEvent ev, int otherActiveId, int oldIndex) {
+ final int pointerCount = ev.getPointerCount();
+
+ // It's ok if this isn't found and returns -1, it simply won't match.
+ final int otherActiveIndex = ev.findPointerIndex(otherActiveId);
+ int newActiveIndex = -1;
+
+ // Pick a new id and update tracking state. Only pick pointers not on the slop edges.
+ for (int i = 0; i < pointerCount; i++) {
+ if (i != oldIndex && i != otherActiveIndex) {
+ final float edgeSlop = mEdgeSlop;
+ final float rightSlop = mRightSlopEdge;
+ final float bottomSlop = mBottomSlopEdge;
+ float x = getRawX(ev, i);
+ float y = getRawY(ev, i);
+ if (x >= edgeSlop && y >= edgeSlop && x <= rightSlop && y <= bottomSlop) {
+ newActiveIndex = i;
+ break;
+ }
+ }
+ }
+
+ return newActiveIndex;
+ }
+
/**
* MotionEvent has no getRawX(int) method; simulate it pending future API approval.
*/
private static float getRawX(MotionEvent event, int pointerIndex) {
+ if (pointerIndex < 0) return Float.MIN_VALUE;
+ if (pointerIndex == 0) return event.getRawX();
float offset = event.getRawX() - event.getX();
return event.getX(pointerIndex) + offset;
}
@@ -320,6 +470,8 @@ public class ScaleGestureDetector {
* MotionEvent has no getRawY(int) method; simulate it pending future API approval.
*/
private static float getRawY(MotionEvent event, int pointerIndex) {
+ if (pointerIndex < 0) return Float.MIN_VALUE;
+ if (pointerIndex == 0) return event.getRawY();
float offset = event.getRawY() - event.getY();
return event.getY(pointerIndex) + offset;
}
@@ -336,14 +488,19 @@ public class ScaleGestureDetector {
final MotionEvent prev = mPrevEvent;
- final float px0 = prev.getX(0);
- final float py0 = prev.getY(0);
- final float px1 = prev.getX(1);
- final float py1 = prev.getY(1);
- final float cx0 = curr.getX(0);
- final float cy0 = curr.getY(0);
- final float cx1 = curr.getX(1);
- final float cy1 = curr.getY(1);
+ final int prevIndex0 = prev.findPointerIndex(mActiveId0);
+ final int prevIndex1 = prev.findPointerIndex(mActiveId1);
+ final int currIndex0 = curr.findPointerIndex(mActiveId0);
+ final int currIndex1 = curr.findPointerIndex(mActiveId1);
+
+ final float px0 = prev.getX(prevIndex0);
+ final float py0 = prev.getY(prevIndex0);
+ final float px1 = prev.getX(prevIndex1);
+ final float py1 = prev.getY(prevIndex1);
+ final float cx0 = curr.getX(currIndex0);
+ final float cy0 = curr.getY(currIndex0);
+ final float cx1 = curr.getX(currIndex1);
+ final float cy1 = curr.getY(currIndex1);
final float pvx = px1 - px0;
final float pvy = py1 - py0;
@@ -357,8 +514,8 @@ public class ScaleGestureDetector {
mFocusX = cx0 + cvx * 0.5f;
mFocusY = cy0 + cvy * 0.5f;
mTimeDelta = curr.getEventTime() - prev.getEventTime();
- mCurrPressure = curr.getPressure(0) + curr.getPressure(1);
- mPrevPressure = prev.getPressure(0) + prev.getPressure(1);
+ mCurrPressure = curr.getPressure(currIndex0) + curr.getPressure(currIndex1);
+ mPrevPressure = prev.getPressure(prevIndex0) + prev.getPressure(prevIndex1);
}
private void reset() {
@@ -372,6 +529,8 @@ public class ScaleGestureDetector {
}
mSloppyGesture = false;
mGestureInProgress = false;
+ mActiveId0 = -1;
+ mActiveId1 = -1;
}
/**
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index eefce06..01bc2df 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -57,7 +57,9 @@ import android.util.Poolable;
import android.util.PoolableManager;
import android.util.Pools;
import android.util.SparseArray;
+import android.util.TypedValue;
import android.view.ContextMenu.ContextMenuInfo;
+import android.view.View.MeasureSpec;
import android.view.accessibility.AccessibilityEvent;
import android.view.accessibility.AccessibilityEventSource;
import android.view.accessibility.AccessibilityManager;
@@ -1771,12 +1773,10 @@ public class View implements Drawable.Callback, KeyEvent.Callback, Accessibility
*/
public static final int STATUS_BAR_DISABLE_CLOCK = 0x00800000;
-
/**
* @hide
*/
public static final int PUBLIC_STATUS_BAR_VISIBILITY_MASK = STATUS_BAR_HIDDEN;
-
/**
* Controls the over-scroll mode for this view.
@@ -1866,7 +1866,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback, Accessibility
* transform matrix, based on whether the rotation or scaleX/Y properties
* have changed since the matrix was last calculated.
*/
- private boolean mMatrixDirty = false;
+ boolean mMatrixDirty = false;
/**
* An internal variable that tracks whether we need to recalculate the
@@ -1914,66 +1914,66 @@ public class View implements Drawable.Callback, KeyEvent.Callback, Accessibility
* The degrees rotation around the vertical axis through the pivot point.
*/
@ViewDebug.ExportedProperty
- private float mRotationY = 0f;
+ float mRotationY = 0f;
/**
* The degrees rotation around the horizontal axis through the pivot point.
*/
@ViewDebug.ExportedProperty
- private float mRotationX = 0f;
+ float mRotationX = 0f;
/**
* The degrees rotation around the pivot point.
*/
@ViewDebug.ExportedProperty
- private float mRotation = 0f;
+ float mRotation = 0f;
/**
* The amount of translation of the object away from its left property (post-layout).
*/
@ViewDebug.ExportedProperty
- private float mTranslationX = 0f;
+ float mTranslationX = 0f;
/**
* The amount of translation of the object away from its top property (post-layout).
*/
@ViewDebug.ExportedProperty
- private float mTranslationY = 0f;
+ float mTranslationY = 0f;
/**
* The amount of scale in the x direction around the pivot point. A
* value of 1 means no scaling is applied.
*/
@ViewDebug.ExportedProperty
- private float mScaleX = 1f;
+ float mScaleX = 1f;
/**
* The amount of scale in the y direction around the pivot point. A
* value of 1 means no scaling is applied.
*/
@ViewDebug.ExportedProperty
- private float mScaleY = 1f;
+ float mScaleY = 1f;
/**
* The amount of scale in the x direction around the pivot point. A
* value of 1 means no scaling is applied.
*/
@ViewDebug.ExportedProperty
- private float mPivotX = 0f;
+ float mPivotX = 0f;
/**
* The amount of scale in the y direction around the pivot point. A
* value of 1 means no scaling is applied.
*/
@ViewDebug.ExportedProperty
- private float mPivotY = 0f;
+ float mPivotY = 0f;
/**
* The opacity of the View. This is a value from 0 to 1, where 0 means
* completely transparent and 1 means completely opaque.
*/
@ViewDebug.ExportedProperty
- private float mAlpha = 1f;
+ float mAlpha = 1f;
/**
* The distance in pixels from the left edge of this view's parent
@@ -2129,6 +2129,8 @@ public class View implements Drawable.Callback, KeyEvent.Callback, Accessibility
private OnTouchListener mOnTouchListener;
+ private OnGenericMotionListener mOnGenericMotionListener;
+
private OnDragListener mOnDragListener;
private OnSystemUiVisibilityChangeListener mOnSystemUiVisibilityChangeListener;
@@ -2237,6 +2239,11 @@ public class View implements Drawable.Callback, KeyEvent.Callback, Accessibility
private int mTouchSlop;
/**
+ * Object that handles automatic animation of view properties.
+ */
+ private ViewPropertyAnimator mAnimator = null;
+
+ /**
* Cache drag/drop state
*
*/
@@ -2253,6 +2260,11 @@ public class View implements Drawable.Callback, KeyEvent.Callback, Accessibility
public static final int DRAG_FLAG_GLOBAL = 1;
/**
+ * Vertical scroll factor cached by {@link #getVerticalScrollFactor}.
+ */
+ private float mVerticalScrollFactor;
+
+ /**
* Position of the vertical scroll bar.
*/
private int mVerticalScrollbarPosition;
@@ -3163,6 +3175,14 @@ public class View implements Drawable.Callback, KeyEvent.Callback, Accessibility
}
/**
+ * Register a callback to be invoked when a generic motion event is sent to this view.
+ * @param l the generic motion listener to attach to this view
+ */
+ public void setOnGenericMotionListener(OnGenericMotionListener l) {
+ mOnGenericMotionListener = l;
+ }
+
+ /**
* Register a drag event listener callback object for this View. The parameter is
* an implementation of {@link android.view.View.OnDragListener}. To send a drag event to a
* View, the system calls the
@@ -3180,8 +3200,8 @@ public class View implements Drawable.Callback, KeyEvent.Callback, Accessibility
* gives it focus no matter what. It should only be called internally by framework
* code that knows what it is doing, namely {@link #requestFocus(int, Rect)}.
*
- * @param direction values are View.FOCUS_UP, View.FOCUS_DOWN,
- * View.FOCUS_LEFT or View.FOCUS_RIGHT. This is the direction which
+ * @param direction values are {@link View#FOCUS_UP}, {@link View#FOCUS_DOWN},
+ * {@link View#FOCUS_LEFT} or {@link View#FOCUS_RIGHT}. This is the direction which
* focus moved when requestFocus() is called. It may not always
* apply, in which case use the default View.FOCUS_DOWN.
* @param previouslyFocusedRect The rectangle of the view that had focus
@@ -4332,9 +4352,9 @@ public class View implements Drawable.Callback, KeyEvent.Callback, Accessibility
* Call this to try to give focus to a specific view or to one of its
* descendants.
*
- * A view will not actually take focus if it is not focusable ({@link #isFocusable} returns false),
- * or if it is focusable and it is not focusable in touch mode ({@link #isFocusableInTouchMode})
- * while the device is in touch mode.
+ * A view will not actually take focus if it is not focusable ({@link #isFocusable} returns
+ * false), or if it is focusable and it is not focusable in touch mode
+ * ({@link #isFocusableInTouchMode}) while the device is in touch mode.
*
* See also {@link #focusSearch}, which is what you call to say that you
* have focus, and you want your parent to look for the next one.
@@ -4353,9 +4373,9 @@ public class View implements Drawable.Callback, KeyEvent.Callback, Accessibility
* Call this to try to give focus to a specific view or to one of its
* descendants and give it a hint about what direction focus is heading.
*
- * A view will not actually take focus if it is not focusable ({@link #isFocusable} returns false),
- * or if it is focusable and it is not focusable in touch mode ({@link #isFocusableInTouchMode})
- * while the device is in touch mode.
+ * A view will not actually take focus if it is not focusable ({@link #isFocusable} returns
+ * false), or if it is focusable and it is not focusable in touch mode
+ * ({@link #isFocusableInTouchMode}) while the device is in touch mode.
*
* See also {@link #focusSearch}, which is what you call to say that you
* have focus, and you want your parent to look for the next one.
@@ -4377,14 +4397,15 @@ public class View implements Drawable.Callback, KeyEvent.Callback, Accessibility
* about where focus is coming from, and therefore, where to show selection, or
* forward focus change internally.
*
- * A view will not actually take focus if it is not focusable ({@link #isFocusable} returns false),
- * or if it is focusable and it is not focusable in touch mode ({@link #isFocusableInTouchMode})
- * while the device is in touch mode.
+ * A view will not actually take focus if it is not focusable ({@link #isFocusable} returns
+ * false), or if it is focusable and it is not focusable in touch mode
+ * ({@link #isFocusableInTouchMode}) while the device is in touch mode.
*
* A View will not take focus if it is not visible.
*
- * A View will not take focus if one of its parents has {@link android.view.ViewGroup#getDescendantFocusability()}
- * equal to {@link ViewGroup#FOCUS_BLOCK_DESCENDANTS}.
+ * A View will not take focus if one of its parents has
+ * {@link android.view.ViewGroup#getDescendantFocusability()} equal to
+ * {@link ViewGroup#FOCUS_BLOCK_DESCENDANTS}.
*
* See also {@link #focusSearch}, which is what you call to say that you
* have focus, and you want your parent to look for the next one.
@@ -4619,16 +4640,47 @@ public class View implements Drawable.Callback, KeyEvent.Callback, Accessibility
}
/**
- * Pass a generic motion event down to the focused view.
+ * Dispatch a generic motion event.
+ * <p>
+ * Generic motion events with source class {@link InputDevice#SOURCE_CLASS_POINTER}
+ * are delivered to the view under the pointer. All other generic motion events are
+ * delivered to the focused view.
+ * </p>
*
* @param event The motion event to be dispatched.
* @return True if the event was handled by the view, false otherwise.
*/
public boolean dispatchGenericMotionEvent(MotionEvent event) {
+ if (mOnGenericMotionListener != null && (mViewFlags & ENABLED_MASK) == ENABLED
+ && mOnGenericMotionListener.onGenericMotion(this, event)) {
+ return true;
+ }
+
return onGenericMotionEvent(event);
}
/**
+ * Dispatch a pointer event.
+ * <p>
+ * Dispatches touch related pointer events to {@link #onTouchEvent} and all
+ * other events to {@link #onGenericMotionEvent}. This separation of concerns
+ * reinforces the invariant that {@link #onTouchEvent} is really about touches
+ * and should not be expected to handle other pointing device features.
+ * </p>
+ *
+ * @param event The motion event to be dispatched.
+ * @return True if the event was handled by the view, false otherwise.
+ * @hide
+ */
+ public final boolean dispatchPointerEvent(MotionEvent event) {
+ if (event.isTouchEvent()) {
+ return dispatchTouchEvent(event);
+ } else {
+ return dispatchGenericMotionEvent(event);
+ }
+ }
+
+ /**
* Called when the window containing this view gains or loses window focus.
* ViewGroups should override to route to their children.
*
@@ -5137,20 +5189,34 @@ public class View implements Drawable.Callback, KeyEvent.Callback, Accessibility
/**
* Implement this method to handle generic motion events.
* <p>
- * Generic motion events are dispatched to the focused view to describe
- * the motions of input devices such as joysticks. The
+ * Generic motion events describe joystick movements, mouse hovers, track pad
+ * touches, scroll wheel movements and other input events. The
* {@link MotionEvent#getSource() source} of the motion event specifies
* the class of input that was received. Implementations of this method
* must examine the bits in the source before processing the event.
* The following code example shows how this is done.
+ * </p><p>
+ * Generic motion events with source class {@link InputDevice#SOURCE_CLASS_POINTER}
+ * are delivered to the view under the pointer. All other generic motion events are
+ * delivered to the focused view.
* </p>
* <code>
* public boolean onGenericMotionEvent(MotionEvent event) {
* if ((event.getSource() &amp; InputDevice.SOURCE_CLASS_JOYSTICK) != 0) {
- * float x = event.getX();
- * float y = event.getY();
- * // process the joystick motion
- * return true;
+ * if (event.getAction() == MotionEvent.ACTION_MOVE) {
+ * // process the joystick movement...
+ * return true;
+ * }
+ * }
+ * if ((event.getSource() &amp; InputDevice.SOURCE_CLASS_POINTER) != 0) {
+ * switch (event.getAction()) {
+ * case MotionEvent.ACTION_HOVER_MOVE:
+ * // process the mouse hover movement...
+ * return true;
+ * case MotionEvent.ACTION_SCROLL:
+ * // process the scroll wheel movement...
+ * return true;
+ * }
* }
* return super.onGenericMotionEvent(event);
* }
@@ -5748,9 +5814,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback, Accessibility
}
mCamera.save();
mMatrix.preScale(mScaleX, mScaleY, mPivotX, mPivotY);
- mCamera.rotateX(mRotationX);
- mCamera.rotateY(mRotationY);
- mCamera.rotateZ(-mRotation);
+ mCamera.rotate(mRotationX, mRotationY, -mRotation);
mCamera.getMatrix(matrix3D);
matrix3D.preTranslate(-mPivotX, -mPivotY);
matrix3D.postTranslate(mPivotX + mTranslationX, mPivotY + mTranslationY);
@@ -5783,10 +5847,67 @@ public class View implements Drawable.Callback, KeyEvent.Callback, Accessibility
}
/**
+ * <p>Sets the distance along the Z axis (orthogonal to the X/Y plane on which
+ * views are drawn) from the camera to this view. The camera's distance
+ * affects 3D transformations, for instance rotations around the X and Y
+ * axis. If the rotationX or rotationY properties are changed and this view is
+ * large (more than half the size of the screen), it is recommended to always
+ * use a camera distance that's greater than the height (X axis rotation) or
+ * the width (Y axis rotation) of this view.</p>
+ *
+ * <p>The distance of the camera from the view plane can have an affect on the
+ * perspective distortion of the view when it is rotated around the x or y axis.
+ * For example, a large distance will result in a large viewing angle, and there
+ * will not be much perspective distortion of the view as it rotates. A short
+ * distance may cause much more perspective distortion upon rotation, and can
+ * also result in some drawing artifacts if the rotated view ends up partially
+ * behind the camera (which is why the recommendation is to use a distance at
+ * least as far as the size of the view, if the view is to be rotated.)</p>
+ *
+ * <p>The distance is expressed in "depth pixels." The default distance depends
+ * on the screen density. For instance, on a medium density display, the
+ * default distance is 1280. On a high density display, the default distance
+ * is 1920.</p>
+ *
+ * <p>If you want to specify a distance that leads to visually consistent
+ * results across various densities, use the following formula:</p>
+ * <pre>
+ * float scale = context.getResources().getDisplayMetrics().density;
+ * view.setCameraDistance(distance * scale);
+ * </pre>
+ *
+ * <p>The density scale factor of a high density display is 1.5,
+ * and 1920 = 1280 * 1.5.</p>
+ *
+ * @param distance The distance in "depth pixels", if negative the opposite
+ * value is used
+ *
+ * @see #setRotationX(float)
+ * @see #setRotationY(float)
+ */
+ public void setCameraDistance(float distance) {
+ invalidateParentCaches();
+ invalidate(false);
+
+ final float dpi = mResources.getDisplayMetrics().densityDpi;
+ if (mCamera == null) {
+ mCamera = new Camera();
+ matrix3D = new Matrix();
+ }
+
+ mCamera.setLocation(0.0f, 0.0f, -Math.abs(distance) / dpi);
+ mMatrixDirty = true;
+
+ invalidate(false);
+ }
+
+ /**
* The degrees that the view is rotated around the pivot point.
*
+ * @see #setRotation(float)
* @see #getPivotX()
* @see #getPivotY()
+ *
* @return The degrees of rotation.
*/
public float getRotation() {
@@ -5798,8 +5919,12 @@ public class View implements Drawable.Callback, KeyEvent.Callback, Accessibility
* result in clockwise rotation.
*
* @param rotation The degrees of rotation.
+ *
+ * @see #getRotation()
* @see #getPivotX()
* @see #getPivotY()
+ * @see #setRotationX(float)
+ * @see #setRotationY(float)
*
* @attr ref android.R.styleable#View_rotation
*/
@@ -5820,6 +5945,8 @@ public class View implements Drawable.Callback, KeyEvent.Callback, Accessibility
*
* @see #getPivotX()
* @see #getPivotY()
+ * @see #setRotationY(float)
+ *
* @return The degrees of Y rotation.
*/
public float getRotationY() {
@@ -5830,10 +5957,18 @@ public class View implements Drawable.Callback, KeyEvent.Callback, Accessibility
* Sets the degrees that the view is rotated around the vertical axis through the pivot point.
* Increasing values result in counter-clockwise rotation from the viewpoint of looking
* down the y axis.
+ *
+ * When rotating large views, it is recommended to adjust the camera distance
+ * accordingly. Refer to {@link #setCameraDistance(float)} for more information.
*
* @param rotationY The degrees of Y rotation.
+ *
+ * @see #getRotationY()
* @see #getPivotX()
* @see #getPivotY()
+ * @see #setRotation(float)
+ * @see #setRotationX(float)
+ * @see #setCameraDistance(float)
*
* @attr ref android.R.styleable#View_rotationY
*/
@@ -5854,6 +5989,8 @@ public class View implements Drawable.Callback, KeyEvent.Callback, Accessibility
*
* @see #getPivotX()
* @see #getPivotY()
+ * @see #setRotationX(float)
+ *
* @return The degrees of X rotation.
*/
public float getRotationX() {
@@ -5864,10 +6001,18 @@ public class View implements Drawable.Callback, KeyEvent.Callback, Accessibility
* Sets the degrees that the view is rotated around the horizontal axis through the pivot point.
* Increasing values result in clockwise rotation from the viewpoint of looking down the
* x axis.
+ *
+ * When rotating large views, it is recommended to adjust the camera distance
+ * accordingly. Refer to {@link #setCameraDistance(float)} for more information.
*
* @param rotationX The degrees of X rotation.
+ *
+ * @see #getRotationX()
* @see #getPivotX()
* @see #getPivotY()
+ * @see #setRotation(float)
+ * @see #setRotationY(float)
+ * @see #setCameraDistance(float)
*
* @attr ref android.R.styleable#View_rotationX
*/
@@ -6078,6 +6223,26 @@ public class View implements Drawable.Callback, KeyEvent.Callback, Accessibility
}
/**
+ * Faster version of setAlpha() which performs the same steps except there are
+ * no calls to invalidate(). The caller of this function should perform proper invalidation
+ * on the parent and this object. The return value indicates whether the subclass handles
+ * alpha (the return value for onSetAlpha()).
+ *
+ * @param alpha The new value for the alpha property
+ * @return true if the View subclass handles alpha (the return value for onSetAlpha())
+ */
+ boolean setAlphaNoInvalidation(float alpha) {
+ mAlpha = alpha;
+ boolean subclassHandlesAlpha = onSetAlpha((int) (alpha * 255));
+ if (subclassHandlesAlpha) {
+ mPrivateFlags |= ALPHA_SET;
+ } else {
+ mPrivateFlags &= ~ALPHA_SET;
+ }
+ return subclassHandlesAlpha;
+ }
+
+ /**
* Top position of this view relative to its parent.
*
* @return The top of this view, in pixels.
@@ -6455,7 +6620,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback, Accessibility
mTranslationY = y - mTop;
mMatrixDirty = true;
}
-
+
/**
* @hide
*/
@@ -6478,7 +6643,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback, Accessibility
public void setFastAlpha(float alpha) {
mAlpha = alpha;
}
-
+
/**
* @hide
*/
@@ -6486,7 +6651,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback, Accessibility
mRotationY = y;
mMatrixDirty = true;
}
-
+
/**
* Hit rectangle in parent's coordinates
*
@@ -6665,7 +6830,14 @@ public class View implements Drawable.Callback, KeyEvent.Callback, Accessibility
* view specifying how it should be arranged. There are many subclasses of
* ViewGroup.LayoutParams, and these correspond to the different subclasses
* of ViewGroup that are responsible for arranging their children.
- * @return The LayoutParams associated with this view
+ *
+ * This method may return null if this View is not attached to a parent
+ * ViewGroup or {@link #setLayoutParams(android.view.ViewGroup.LayoutParams)}
+ * was not invoked successfully. When a View is attached to a parent
+ * ViewGroup, this method must not return null.
+ *
+ * @return The LayoutParams associated with this view, or null if no
+ * parameters have been set yet
*/
@ViewDebug.ExportedProperty(deepExport = true, prefix = "layout_")
public ViewGroup.LayoutParams getLayoutParams() {
@@ -6679,11 +6851,11 @@ public class View implements Drawable.Callback, KeyEvent.Callback, Accessibility
* correspond to the different subclasses of ViewGroup that are responsible
* for arranging their children.
*
- * @param params the layout parameters for this view
+ * @param params The layout parameters for this view, cannot be null
*/
public void setLayoutParams(ViewGroup.LayoutParams params) {
if (params == null) {
- throw new NullPointerException("params == null");
+ throw new NullPointerException("Layout parameters cannot be null");
}
mLayoutParams = params;
requestLayout();
@@ -8657,7 +8829,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback, Accessibility
public void buildDrawingCache() {
buildDrawingCache(false);
}
-
+
/**
* <p>Forces the drawing cache to be built if the drawing cache is invalid.</p>
*
@@ -11542,6 +11714,37 @@ public class View implements Drawable.Callback, KeyEvent.Callback, Accessibility
}
/**
+ * Gets a scale factor that determines the distance the view should scroll
+ * vertically in response to {@link MotionEvent#ACTION_SCROLL}.
+ * @return The vertical scroll scale factor.
+ * @hide
+ */
+ protected float getVerticalScrollFactor() {
+ if (mVerticalScrollFactor == 0) {
+ TypedValue outValue = new TypedValue();
+ if (!mContext.getTheme().resolveAttribute(
+ com.android.internal.R.attr.listPreferredItemHeight, outValue, true)) {
+ throw new IllegalStateException(
+ "Expected theme to define listPreferredItemHeight.");
+ }
+ mVerticalScrollFactor = outValue.getDimension(
+ mContext.getResources().getDisplayMetrics());
+ }
+ return mVerticalScrollFactor;
+ }
+
+ /**
+ * Gets a scale factor that determines the distance the view should scroll
+ * horizontally in response to {@link MotionEvent#ACTION_SCROLL}.
+ * @return The horizontal scroll scale factor.
+ * @hide
+ */
+ protected float getHorizontalScrollFactor() {
+ // TODO: Should use something else.
+ return getVerticalScrollFactor();
+ }
+
+ /**
* A MeasureSpec encapsulates the layout requirements passed from parent to child.
* Each MeasureSpec represents a requirement for either the width or the height.
* A MeasureSpec is comprised of a size and a mode. There are three possible
@@ -11699,6 +11902,19 @@ public class View implements Drawable.Callback, KeyEvent.Callback, Accessibility
}
/**
+ * This method returns a ViewPropertyAnimator object, which can be used to animate
+ * specific properties on this View.
+ *
+ * @return ViewPropertyAnimator The ViewPropertyAnimator associated with this View.
+ */
+ public ViewPropertyAnimator animate() {
+ if (mAnimator == null) {
+ mAnimator = new ViewPropertyAnimator(this);
+ }
+ return mAnimator;
+ }
+
+ /**
* Interface definition for a callback to be invoked when a key event is
* dispatched to this view. The callback will be invoked before the key
* event is given to the view.
@@ -11736,6 +11952,24 @@ public class View implements Drawable.Callback, KeyEvent.Callback, Accessibility
}
/**
+ * Interface definition for a callback to be invoked when a generic motion event is
+ * dispatched to this view. The callback will be invoked before the generic motion
+ * event is given to the view.
+ */
+ public interface OnGenericMotionListener {
+ /**
+ * Called when a generic motion event is dispatched to a view. This allows listeners to
+ * get a chance to respond before the target view.
+ *
+ * @param v The view the generic motion event has been dispatched to.
+ * @param event The MotionEvent object containing full information about
+ * the event.
+ * @return True if the listener has consumed the event, false otherwise.
+ */
+ boolean onGenericMotion(View v, MotionEvent event);
+ }
+
+ /**
* Interface definition for a callback to be invoked when a view has been clicked and held.
*/
public interface OnLongClickListener {
diff --git a/core/java/android/view/ViewGroup.java b/core/java/android/view/ViewGroup.java
index a0d4263..af4c221 100644
--- a/core/java/android/view/ViewGroup.java
+++ b/core/java/android/view/ViewGroup.java
@@ -1145,6 +1145,53 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager
*/
@Override
public boolean dispatchGenericMotionEvent(MotionEvent event) {
+ if ((event.getSource() & InputDevice.SOURCE_CLASS_POINTER) != 0) {
+ // Send the event to the child under the pointer.
+ final int childrenCount = mChildrenCount;
+ if (childrenCount != 0) {
+ final View[] children = mChildren;
+ final float x = event.getX();
+ final float y = event.getY();
+
+ for (int i = childrenCount - 1; i >= 0; i--) {
+ final View child = children[i];
+ if ((child.mViewFlags & VISIBILITY_MASK) != VISIBLE
+ && child.getAnimation() == null) {
+ // Skip invisible child unless it is animating.
+ continue;
+ }
+
+ if (!isTransformedTouchPointInView(x, y, child, null)) {
+ // Scroll point is out of child's bounds.
+ continue;
+ }
+
+ final float offsetX = mScrollX - child.mLeft;
+ final float offsetY = mScrollY - child.mTop;
+ final boolean handled;
+ if (!child.hasIdentityMatrix()) {
+ MotionEvent transformedEvent = MotionEvent.obtain(event);
+ transformedEvent.offsetLocation(offsetX, offsetY);
+ transformedEvent.transform(child.getInverseMatrix());
+ handled = child.dispatchGenericMotionEvent(transformedEvent);
+ transformedEvent.recycle();
+ } else {
+ event.offsetLocation(offsetX, offsetY);
+ handled = child.dispatchGenericMotionEvent(event);
+ event.offsetLocation(-offsetX, -offsetY);
+ }
+
+ if (handled) {
+ return true;
+ }
+ }
+ }
+
+ // No child handled the event. Send it to this view group.
+ return super.dispatchGenericMotionEvent(event);
+ }
+
+ // Send the event to the focused child or to this view group if it has focus.
if ((mPrivateFlags & (FOCUSED | HAS_BOUNDS)) == (FOCUSED | HAS_BOUNDS)) {
return super.dispatchGenericMotionEvent(event);
} else if (mFocused != null && (mFocused.mPrivateFlags & HAS_BOUNDS) == HAS_BOUNDS) {
@@ -1178,7 +1225,6 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager
// Check for interception.
final boolean intercepted;
if (actionMasked == MotionEvent.ACTION_DOWN
- || actionMasked == MotionEvent.ACTION_HOVER_MOVE
|| mFirstTouchTarget != null) {
final boolean disallowIntercept = (mGroupFlags & FLAG_DISALLOW_INTERCEPT) != 0;
if (!disallowIntercept) {
@@ -1188,6 +1234,8 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager
intercepted = false;
}
} else {
+ // There are no touch targets and this action is not an initial down
+ // so this view group continues to intercept touches.
intercepted = true;
}
@@ -1548,8 +1596,6 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager
final int newAction;
if (cancel) {
newAction = MotionEvent.ACTION_CANCEL;
- } else if (oldAction == MotionEvent.ACTION_HOVER_MOVE) {
- newAction = MotionEvent.ACTION_HOVER_MOVE;
} else {
final int oldMaskedAction = oldAction & MotionEvent.ACTION_MASK;
if (oldMaskedAction == MotionEvent.ACTION_POINTER_DOWN
@@ -2401,21 +2447,26 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager
}
cache = child.getDrawingCache(true);
} else {
- if (layerType == LAYER_TYPE_SOFTWARE) {
- child.buildDrawingCache(true);
- cache = child.getDrawingCache(true);
- } else if (layerType == LAYER_TYPE_NONE) {
- // Delay getting the display list until animation-driven alpha values are
- // set up and possibly passed on to the view
- hasDisplayList = child.canHaveDisplayList();
+ switch (layerType) {
+ case LAYER_TYPE_SOFTWARE:
+ child.buildDrawingCache(true);
+ cache = child.getDrawingCache(true);
+ break;
+ case LAYER_TYPE_NONE:
+ // Delay getting the display list until animation-driven alpha values are
+ // set up and possibly passed on to the view
+ hasDisplayList = child.canHaveDisplayList();
+ break;
}
}
}
final boolean hasNoCache = cache == null || hasDisplayList;
+ final boolean offsetForScroll = cache == null && !hasDisplayList &&
+ layerType != LAYER_TYPE_HARDWARE;
final int restoreTo = canvas.save();
- if (cache == null && !hasDisplayList) {
+ if (offsetForScroll) {
canvas.translate(cl - sx, ct - sy);
} else {
canvas.translate(cl, ct);
@@ -2431,7 +2482,7 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager
int transX = 0;
int transY = 0;
- if (cache == null && !hasDisplayList) {
+ if (offsetForScroll) {
transX = -sx;
transY = -sy;
}
@@ -2471,8 +2522,10 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager
layerFlags |= Canvas.CLIP_TO_LAYER_SAVE_FLAG;
}
if (layerType == LAYER_TYPE_NONE) {
- canvas.saveLayerAlpha(sx, sy, sx + cr - cl, sy + cb - ct,
- multipliedAlpha, layerFlags);
+ final int scrollX = hasDisplayList ? 0 : sx;
+ final int scrollY = hasDisplayList ? 0 : sy;
+ canvas.saveLayerAlpha(scrollX, scrollY, scrollX + cr - cl,
+ scrollY + cb - ct, multipliedAlpha, layerFlags);
}
} else {
// Alpha is handled by the child directly, clobber the layer's alpha
@@ -2486,7 +2539,7 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager
}
if ((flags & FLAG_CLIP_CHILDREN) == FLAG_CLIP_CHILDREN) {
- if (cache == null && !hasDisplayList) {
+ if (offsetForScroll) {
canvas.clipRect(sx, sy, sx + (cr - cl), sy + (cb - ct));
} else {
if (!scalingRequired || cache == null) {
@@ -2510,7 +2563,10 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager
((HardwareCanvas) canvas).drawHardwareLayer(layer, 0, 0, child.mLayerPaint);
layerRendered = true;
} else {
- canvas.saveLayer(sx, sy, sx + cr - cl, sy + cb - ct, child.mLayerPaint,
+ final int scrollX = hasDisplayList ? 0 : sx;
+ final int scrollY = hasDisplayList ? 0 : sy;
+ canvas.saveLayer(scrollX, scrollY,
+ scrollX + cr - cl, scrollY + cb - ct, child.mLayerPaint,
Canvas.HAS_ALPHA_LAYER_SAVE_FLAG | Canvas.CLIP_TO_LAYER_SAVE_FLAG);
}
}
diff --git a/core/java/android/view/ViewPropertyAnimator.java b/core/java/android/view/ViewPropertyAnimator.java
new file mode 100644
index 0000000..1d56e9d
--- /dev/null
+++ b/core/java/android/view/ViewPropertyAnimator.java
@@ -0,0 +1,775 @@
+/*
+ * 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.view;
+
+import android.animation.Animator;
+import android.animation.ValueAnimator;
+import android.animation.TimeInterpolator;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Set;
+
+/**
+ * This class enables automatic and optimized animation of select properties on View objects.
+ * If only one or two properties on a View object are being animated, then using an
+ * {@link android.animation.ObjectAnimator} is fine; the property setters called by ObjectAnimator
+ * are well equipped to do the right thing to set the property and invalidate the view
+ * appropriately. But if several properties are animated simultaneously, or if you just want a
+ * more convenient syntax to animate a specific property, then ViewPropertyAnimator might be
+ * more well-suited to the task.
+ *
+ * <p>This class may provide better performance for several simultaneous animations, because
+ * it will optimize invalidate calls to take place only once for several properties instead of each
+ * animated property independently causing its own invalidation. Also, the syntax of using this
+ * class could be easier to use because the caller need only tell the View object which
+ * property to animate, and the value to animate either to or by, and this class handles the
+ * details of configuring the underlying Animator class and starting it.</p>
+ *
+ * <p>This class is not constructed by the caller, but rather by the View whose properties
+ * it will animate. Calls to {@link android.view.View#animate()} will return a reference
+ * to the appropriate ViewPropertyAnimator object for that View.</p>
+ *
+ */
+public class ViewPropertyAnimator {
+
+ /**
+ * The View whose properties are being animated by this class. This is set at
+ * construction time.
+ */
+ private View mView;
+
+ /**
+ * The duration of the underlying Animator object. By default, we don't set the duration
+ * on the Animator and just use its default duration. If the duration is ever set on this
+ * Animator, then we use the duration that it was set to.
+ */
+ private long mDuration;
+
+ /**
+ * A flag indicating whether the duration has been set on this object. If not, we don't set
+ * the duration on the underlying Animator, but instead just use its default duration.
+ */
+ private boolean mDurationSet = false;
+
+ /**
+ * The interpolator of the underlying Animator object. By default, we don't set the interpolator
+ * on the Animator and just use its default interpolator. If the interpolator is ever set on
+ * this Animator, then we use the interpolator that it was set to.
+ */
+ private TimeInterpolator mInterpolator;
+
+ /**
+ * A flag indicating whether the interpolator has been set on this object. If not, we don't set
+ * the interpolator on the underlying Animator, but instead just use its default interpolator.
+ */
+ private boolean mInterpolatorSet = false;
+
+ /**
+ * Listener for the lifecycle events of the underlying
+ */
+ private Animator.AnimatorListener mListener = null;
+
+ /**
+ * This listener is the mechanism by which the underlying Animator causes changes to the
+ * properties currently being animated, as well as the cleanup after an animation is
+ * complete.
+ */
+ private AnimatorEventListener mAnimatorEventListener = new AnimatorEventListener();
+
+ /**
+ * This list holds the properties that have been asked to animate. We allow the caller to
+ * request several animations prior to actually starting the underlying animator. This
+ * enables us to run one single animator to handle several properties in parallel. Each
+ * property is tossed onto the pending list until the animation actually starts (which is
+ * done by posting it onto mView), at which time the pending list is cleared and the properties
+ * on that list are added to the list of properties associated with that animator.
+ */
+ ArrayList<NameValuesHolder> mPendingAnimations = new ArrayList<NameValuesHolder>();
+
+ /**
+ * Constants used to associate a property being requested and the mechanism used to set
+ * the property (this class calls directly into View to set the properties in question).
+ */
+ private static final int NONE = 0x0000;
+ private static final int TRANSLATION_X = 0x0001;
+ private static final int TRANSLATION_Y = 0x0002;
+ private static final int SCALE_X = 0x0004;
+ private static final int SCALE_Y = 0x0008;
+ private static final int ROTATION = 0x0010;
+ private static final int ROTATION_X = 0x0020;
+ private static final int ROTATION_Y = 0x0040;
+ private static final int X = 0x0080;
+ private static final int Y = 0x0100;
+ private static final int ALPHA = 0x0200;
+
+ private static final int TRANSFORM_MASK = TRANSLATION_X | TRANSLATION_Y | SCALE_X | SCALE_Y |
+ ROTATION | ROTATION_X | ROTATION_Y | X | Y;
+
+ /**
+ * The mechanism by which the user can request several properties that are then animated
+ * together works by posting this Runnable to start the underlying Animator. Every time
+ * a property animation is requested, we cancel any previous postings of the Runnable
+ * and re-post it. This means that we will only ever run the Runnable (and thus start the
+ * underlying animator) after the caller is done setting the properties that should be
+ * animated together.
+ */
+ private Runnable mAnimationStarter = new Runnable() {
+ @Override
+ public void run() {
+ startAnimation();
+ }
+ };
+
+ /**
+ * This class holds information about the overall animation being run on the set of
+ * properties. The mask describes which properties are being animated and the
+ * values holder is the list of all property/value objects.
+ */
+ private static class PropertyBundle {
+ int mPropertyMask;
+ ArrayList<NameValuesHolder> mNameValuesHolder;
+
+ PropertyBundle(int propertyMask, ArrayList<NameValuesHolder> nameValuesHolder) {
+ mPropertyMask = propertyMask;
+ mNameValuesHolder = nameValuesHolder;
+ }
+
+ /**
+ * Removes the given property from being animated as a part of this
+ * PropertyBundle. If the property was a part of this bundle, it returns
+ * true to indicate that it was, in fact, canceled. This is an indication
+ * to the caller that a cancellation actually occurred.
+ *
+ * @param propertyConstant The property whose cancellation is requested.
+ * @return true if the given property is a part of this bundle and if it
+ * has therefore been canceled.
+ */
+ boolean cancel(int propertyConstant) {
+ if ((mPropertyMask & propertyConstant) != 0 && mNameValuesHolder != null) {
+ int count = mNameValuesHolder.size();
+ for (int i = 0; i < count; ++i) {
+ NameValuesHolder nameValuesHolder = mNameValuesHolder.get(i);
+ if (nameValuesHolder.mNameConstant == propertyConstant) {
+ mNameValuesHolder.remove(i);
+ mPropertyMask &= ~propertyConstant;
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+ }
+
+ /**
+ * This list tracks the list of properties being animated by any particular animator.
+ * In most situations, there would only ever be one animator running at a time. But it is
+ * possible to request some properties to animate together, then while those properties
+ * are animating, to request some other properties to animate together. The way that
+ * works is by having this map associate the group of properties being animated with the
+ * animator handling the animation. On every update event for an Animator, we ask the
+ * map for the associated properties and set them accordingly.
+ */
+ private HashMap<Animator, PropertyBundle> mAnimatorMap =
+ new HashMap<Animator, PropertyBundle>();
+
+ /**
+ * This is the information we need to set each property during the animation.
+ * mNameConstant is used to set the appropriate field in View, and the from/delta
+ * values are used to calculate the animated value for a given animation fraction
+ * during the animation.
+ */
+ private static class NameValuesHolder {
+ int mNameConstant;
+ float mFromValue;
+ float mDeltaValue;
+ NameValuesHolder(int nameConstant, float fromValue, float deltaValue) {
+ mNameConstant = nameConstant;
+ mFromValue = fromValue;
+ mDeltaValue = deltaValue;
+ }
+ }
+
+ /**
+ * Constructor, called by View. This is private by design, as the user should only
+ * get a ViewPropertyAnimator by calling View.animate().
+ *
+ * @param view The View associated with this ViewPropertyAnimator
+ */
+ ViewPropertyAnimator(View view) {
+ mView = view;
+ }
+
+ /**
+ * Sets the duration for the underlying animator that animates the requested properties.
+ * By default, the animator uses the default value for ValueAnimator. Calling this method
+ * will cause the declared value to be used instead.
+ * @param duration The length of ensuing property animations, in milliseconds. The value
+ * cannot be negative.
+ * @return This object, allowing calls to methods in this class to be chained.
+ */
+ public ViewPropertyAnimator setDuration(long duration) {
+ if (duration < 0) {
+ throw new IllegalArgumentException("Animators cannot have negative duration: " +
+ duration);
+ }
+ mDurationSet = true;
+ mDuration = duration;
+ return this;
+ }
+
+ /**
+ * Sets the interpolator for the underlying animator that animates the requested properties.
+ * By default, the animator uses the default interpolator for ValueAnimator. Calling this method
+ * will cause the declared object to be used instead.
+ *
+ * @param interpolator The TimeInterpolator to be used for ensuing property animations.
+ * @return This object, allowing calls to methods in this class to be chained.
+ */
+ public ViewPropertyAnimator setInterpolator(TimeInterpolator interpolator) {
+ mInterpolatorSet = true;
+ mInterpolator = interpolator;
+ return this;
+ }
+
+ /**
+ * Sets a listener for events in the underlying Animators that run the property
+ * animations.
+ *
+ * @param listener The listener to be called with AnimatorListener events.
+ * @return This object, allowing calls to methods in this class to be chained.
+ */
+ public ViewPropertyAnimator setListener(Animator.AnimatorListener listener) {
+ mListener = listener;
+ return this;
+ }
+
+ /**
+ * This method will cause the View's <code>x</code> property to be animated to the
+ * specified value. Animations already running on the property will be canceled.
+ *
+ * @param value The value to be animated to.
+ * @see View#setX(float)
+ * @return This object, allowing calls to methods in this class to be chained.
+ */
+ public ViewPropertyAnimator x(float value) {
+ animateProperty(X, value);
+ return this;
+ }
+
+ /**
+ * This method will cause the View's <code>x</code> property to be animated by the
+ * specified value. Animations already running on the property will be canceled.
+ *
+ * @param value The amount to be animated by, as an offset from the current value.
+ * @see View#setX(float)
+ * @return This object, allowing calls to methods in this class to be chained.
+ */
+ public ViewPropertyAnimator xBy(float value) {
+ animatePropertyBy(X, value);
+ return this;
+ }
+
+ /**
+ * This method will cause the View's <code>y</code> property to be animated to the
+ * specified value. Animations already running on the property will be canceled.
+ *
+ * @param value The value to be animated to.
+ * @see View#setY(float)
+ * @return This object, allowing calls to methods in this class to be chained.
+ */
+ public ViewPropertyAnimator y(float value) {
+ animateProperty(Y, value);
+ return this;
+ }
+
+ /**
+ * This method will cause the View's <code>y</code> property to be animated by the
+ * specified value. Animations already running on the property will be canceled.
+ *
+ * @param value The amount to be animated by, as an offset from the current value.
+ * @see View#setY(float)
+ * @return This object, allowing calls to methods in this class to be chained.
+ */
+ public ViewPropertyAnimator yBy(float value) {
+ animatePropertyBy(Y, value);
+ return this;
+ }
+
+ /**
+ * This method will cause the View's <code>rotation</code> property to be animated to the
+ * specified value. Animations already running on the property will be canceled.
+ *
+ * @param value The value to be animated to.
+ * @see View#setRotation(float)
+ * @return This object, allowing calls to methods in this class to be chained.
+ */
+ public ViewPropertyAnimator rotation(float value) {
+ animateProperty(ROTATION, value);
+ return this;
+ }
+
+ /**
+ * This method will cause the View's <code>rotation</code> property to be animated by the
+ * specified value. Animations already running on the property will be canceled.
+ *
+ * @param value The amount to be animated by, as an offset from the current value.
+ * @see View#setRotation(float)
+ * @return This object, allowing calls to methods in this class to be chained.
+ */
+ public ViewPropertyAnimator rotationBy(float value) {
+ animatePropertyBy(ROTATION, value);
+ return this;
+ }
+
+ /**
+ * This method will cause the View's <code>rotationX</code> property to be animated to the
+ * specified value. Animations already running on the property will be canceled.
+ *
+ * @param value The value to be animated to.
+ * @see View#setRotationX(float)
+ * @return This object, allowing calls to methods in this class to be chained.
+ */
+ public ViewPropertyAnimator rotationX(float value) {
+ animateProperty(ROTATION_X, value);
+ return this;
+ }
+
+ /**
+ * This method will cause the View's <code>rotationX</code> property to be animated by the
+ * specified value. Animations already running on the property will be canceled.
+ *
+ * @param value The amount to be animated by, as an offset from the current value.
+ * @see View#setRotationX(float)
+ * @return This object, allowing calls to methods in this class to be chained.
+ */
+ public ViewPropertyAnimator rotationXBy(float value) {
+ animatePropertyBy(ROTATION_X, value);
+ return this;
+ }
+
+ /**
+ * This method will cause the View's <code>rotationY</code> property to be animated to the
+ * specified value. Animations already running on the property will be canceled.
+ *
+ * @param value The value to be animated to.
+ * @see View#setRotationY(float)
+ * @return This object, allowing calls to methods in this class to be chained.
+ */
+ public ViewPropertyAnimator rotationY(float value) {
+ animateProperty(ROTATION_Y, value);
+ return this;
+ }
+
+ /**
+ * This method will cause the View's <code>rotationY</code> property to be animated by the
+ * specified value. Animations already running on the property will be canceled.
+ *
+ * @param value The amount to be animated by, as an offset from the current value.
+ * @see View#setRotationY(float)
+ * @return This object, allowing calls to methods in this class to be chained.
+ */
+ public ViewPropertyAnimator rotationYBy(float value) {
+ animatePropertyBy(ROTATION_Y, value);
+ return this;
+ }
+
+ /**
+ * This method will cause the View's <code>translationX</code> property to be animated to the
+ * specified value. Animations already running on the property will be canceled.
+ *
+ * @param value The value to be animated to.
+ * @see View#setTranslationX(float)
+ * @return This object, allowing calls to methods in this class to be chained.
+ */
+ public ViewPropertyAnimator translationX(float value) {
+ animateProperty(TRANSLATION_X, value);
+ return this;
+ }
+
+ /**
+ * This method will cause the View's <code>translationX</code> property to be animated by the
+ * specified value. Animations already running on the property will be canceled.
+ *
+ * @param value The amount to be animated by, as an offset from the current value.
+ * @see View#setTranslationX(float)
+ * @return This object, allowing calls to methods in this class to be chained.
+ */
+ public ViewPropertyAnimator translationXBy(float value) {
+ animatePropertyBy(TRANSLATION_X, value);
+ return this;
+ }
+
+ /**
+ * This method will cause the View's <code>translationY</code> property to be animated to the
+ * specified value. Animations already running on the property will be canceled.
+ *
+ * @param value The value to be animated to.
+ * @see View#setTranslationY(float)
+ * @return This object, allowing calls to methods in this class to be chained.
+ */
+ public ViewPropertyAnimator translationY(float value) {
+ animateProperty(TRANSLATION_Y, value);
+ return this;
+ }
+
+ /**
+ * This method will cause the View's <code>translationY</code> property to be animated by the
+ * specified value. Animations already running on the property will be canceled.
+ *
+ * @param value The amount to be animated by, as an offset from the current value.
+ * @see View#setTranslationY(float)
+ * @return This object, allowing calls to methods in this class to be chained.
+ */
+ public ViewPropertyAnimator translationYBy(float value) {
+ animatePropertyBy(TRANSLATION_Y, value);
+ return this;
+ }
+
+ /**
+ * This method will cause the View's <code>scaleX</code> property to be animated to the
+ * specified value. Animations already running on the property will be canceled.
+ *
+ * @param value The value to be animated to.
+ * @see View#setScaleX(float)
+ * @return This object, allowing calls to methods in this class to be chained.
+ */
+ public ViewPropertyAnimator scaleX(float value) {
+ animateProperty(SCALE_X, value);
+ return this;
+ }
+
+ /**
+ * This method will cause the View's <code>scaleX</code> property to be animated by the
+ * specified value. Animations already running on the property will be canceled.
+ *
+ * @param value The amount to be animated by, as an offset from the current value.
+ * @see View#setScaleX(float)
+ * @return This object, allowing calls to methods in this class to be chained.
+ */
+ public ViewPropertyAnimator scaleXBy(float value) {
+ animatePropertyBy(SCALE_X, value);
+ return this;
+ }
+
+ /**
+ * This method will cause the View's <code>scaleY</code> property to be animated to the
+ * specified value. Animations already running on the property will be canceled.
+ *
+ * @param value The value to be animated to.
+ * @see View#setScaleY(float)
+ * @return This object, allowing calls to methods in this class to be chained.
+ */
+ public ViewPropertyAnimator scaleY(float value) {
+ animateProperty(SCALE_Y, value);
+ return this;
+ }
+
+ /**
+ * This method will cause the View's <code>scaleY</code> property to be animated by the
+ * specified value. Animations already running on the property will be canceled.
+ *
+ * @param value The amount to be animated by, as an offset from the current value.
+ * @see View#setScaleY(float)
+ * @return This object, allowing calls to methods in this class to be chained.
+ */
+ public ViewPropertyAnimator scaleYBy(float value) {
+ animatePropertyBy(SCALE_Y, value);
+ return this;
+ }
+
+ /**
+ * This method will cause the View's <code>alpha</code> property to be animated to the
+ * specified value. Animations already running on the property will be canceled.
+ *
+ * @param value The value to be animated to.
+ * @see View#setAlpha(float)
+ * @return This object, allowing calls to methods in this class to be chained.
+ */
+ public ViewPropertyAnimator alpha(float value) {
+ animateProperty(ALPHA, value);
+ return this;
+ }
+
+ /**
+ * This method will cause the View's <code>alpha</code> property to be animated by the
+ * specified value. Animations already running on the property will be canceled.
+ *
+ * @param value The amount to be animated by, as an offset from the current value.
+ * @see View#setAlpha(float)
+ * @return This object, allowing calls to methods in this class to be chained.
+ */
+ public ViewPropertyAnimator alphaBy(float value) {
+ animatePropertyBy(ALPHA, value);
+ return this;
+ }
+
+ /**
+ * Starts the underlying Animator for a set of properties. We use a single animator that
+ * simply runs from 0 to 1, and then use that fractional value to set each property
+ * value accordingly.
+ */
+ private void startAnimation() {
+ ValueAnimator animator = ValueAnimator.ofFloat(1.0f);
+ ArrayList<NameValuesHolder> nameValueList =
+ (ArrayList<NameValuesHolder>) mPendingAnimations.clone();
+ mPendingAnimations.clear();
+ int propertyMask = 0;
+ int propertyCount = nameValueList.size();
+ for (int i = 0; i < propertyCount; ++i) {
+ NameValuesHolder nameValuesHolder = nameValueList.get(i);
+ propertyMask |= nameValuesHolder.mNameConstant;
+ }
+ mAnimatorMap.put(animator, new PropertyBundle(propertyMask, nameValueList));
+ animator.addUpdateListener(mAnimatorEventListener);
+ animator.addListener(mAnimatorEventListener);
+ if (mDurationSet) {
+ animator.setDuration(mDuration);
+ }
+ if (mInterpolatorSet) {
+ animator.setInterpolator(mInterpolator);
+ }
+ animator.start();
+ }
+
+ /**
+ * Utility function, called by the various x(), y(), etc. methods. This stores the
+ * constant name for the property along with the from/delta values that will be used to
+ * calculate and set the property during the animation. This structure is added to the
+ * pending animations, awaiting the eventual start() of the underlying animator. A
+ * Runnable is posted to start the animation, and any pending such Runnable is canceled
+ * (which enables us to end up starting just one animator for all of the properties
+ * specified at one time).
+ *
+ * @param constantName The specifier for the property being animated
+ * @param toValue The value to which the property will animate
+ */
+ private void animateProperty(int constantName, float toValue) {
+ float fromValue = getValue(constantName);
+ float deltaValue = toValue - fromValue;
+ animatePropertyBy(constantName, fromValue, deltaValue);
+ }
+
+ /**
+ * Utility function, called by the various xBy(), yBy(), etc. methods. This method is
+ * just like animateProperty(), except the value is an offset from the property's
+ * current value, instead of an absolute "to" value.
+ *
+ * @param constantName The specifier for the property being animated
+ * @param byValue The amount by which the property will change
+ */
+ private void animatePropertyBy(int constantName, float byValue) {
+ float fromValue = getValue(constantName);
+ animatePropertyBy(constantName, fromValue, byValue);
+ }
+
+ /**
+ * Utility function, called by animateProperty() and animatePropertyBy(), which handles the
+ * details of adding a pending animation and posting the request to start the animation.
+ *
+ * @param constantName The specifier for the property being animated
+ * @param startValue The starting value of the property
+ * @param byValue The amount by which the property will change
+ */
+ private void animatePropertyBy(int constantName, float startValue, float byValue) {
+ // First, cancel any existing animations on this property
+ if (mAnimatorMap.size() > 0) {
+ Animator animatorToCancel = null;
+ Set<Animator> animatorSet = mAnimatorMap.keySet();
+ for (Animator runningAnim : animatorSet) {
+ PropertyBundle bundle = mAnimatorMap.get(runningAnim);
+ if (bundle.cancel(constantName)) {
+ // property was canceled - cancel the animation if it's now empty
+ // Note that it's safe to break out here because every new animation
+ // on a property will cancel a previous animation on that property, so
+ // there can only ever be one such animation running.
+ if (bundle.mPropertyMask == NONE) {
+ // the animation is not longer changing anything - cancel it
+ animatorToCancel = runningAnim;
+ break;
+ }
+ }
+ }
+ if (animatorToCancel != null) {
+ animatorToCancel.cancel();
+ }
+ }
+
+ NameValuesHolder nameValuePair = new NameValuesHolder(constantName, startValue, byValue);
+ mPendingAnimations.add(nameValuePair);
+ mView.getHandler().removeCallbacks(mAnimationStarter);
+ mView.post(mAnimationStarter);
+ }
+
+ /**
+ * This method handles setting the property values directly in the View object's fields.
+ * propertyConstant tells it which property should be set, value is the value to set
+ * the property to.
+ *
+ * @param propertyConstant The property to be set
+ * @param value The value to set the property to
+ */
+ private void setValue(int propertyConstant, float value) {
+ switch (propertyConstant) {
+ case TRANSLATION_X:
+ mView.mTranslationX = value;
+ break;
+ case TRANSLATION_Y:
+ mView.mTranslationY = value;
+ break;
+ case ROTATION:
+ mView.mRotation = value;
+ break;
+ case ROTATION_X:
+ mView.mRotationX = value;
+ break;
+ case ROTATION_Y:
+ mView.mRotationY = value;
+ break;
+ case SCALE_X:
+ mView.mScaleX = value;
+ break;
+ case SCALE_Y:
+ mView.mScaleY = value;
+ break;
+ case X:
+ mView.mTranslationX = value - mView.mLeft;
+ break;
+ case Y:
+ mView.mTranslationY = value - mView.mTop;
+ break;
+ case ALPHA:
+ mView.mAlpha = value;
+ break;
+ }
+ }
+
+ /**
+ * This method gets the value of the named property from the View object.
+ *
+ * @param propertyConstant The property whose value should be returned
+ * @return float The value of the named property
+ */
+ private float getValue(int propertyConstant) {
+ switch (propertyConstant) {
+ case TRANSLATION_X:
+ return mView.mTranslationX;
+ case TRANSLATION_Y:
+ return mView.mTranslationY;
+ case ROTATION:
+ return mView.mRotation;
+ case ROTATION_X:
+ return mView.mRotationX;
+ case ROTATION_Y:
+ return mView.mRotationY;
+ case SCALE_X:
+ return mView.mScaleX;
+ case SCALE_Y:
+ return mView.mScaleY;
+ case X:
+ return mView.mLeft + mView.mTranslationX;
+ case Y:
+ return mView.mTop + mView.mTranslationY;
+ case ALPHA:
+ return mView.mAlpha;
+ }
+ return 0;
+ }
+
+ /**
+ * Utility class that handles the various Animator events. The only ones we care
+ * about are the end event (which we use to clean up the animator map when an animator
+ * finishes) and the update event (which we use to calculate the current value of each
+ * property and then set it on the view object).
+ */
+ private class AnimatorEventListener
+ implements Animator.AnimatorListener, ValueAnimator.AnimatorUpdateListener {
+ @Override
+ public void onAnimationStart(Animator animation) {
+ if (mListener != null) {
+ mListener.onAnimationStart(animation);
+ }
+ }
+
+ @Override
+ public void onAnimationCancel(Animator animation) {
+ if (mListener != null) {
+ mListener.onAnimationCancel(animation);
+ }
+ }
+
+ @Override
+ public void onAnimationRepeat(Animator animation) {
+ if (mListener != null) {
+ mListener.onAnimationRepeat(animation);
+ }
+ }
+
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ if (mListener != null) {
+ mListener.onAnimationEnd(animation);
+ }
+ mAnimatorMap.remove(animation);
+ }
+
+ /**
+ * Calculate the current value for each property and set it on the view. Invalidate
+ * the view object appropriately, depending on which properties are being animated.
+ *
+ * @param animation The animator associated with the properties that need to be
+ * set. This animator holds the animation fraction which we will use to calculate
+ * the current value of each property.
+ */
+ @Override
+ public void onAnimationUpdate(ValueAnimator animation) {
+ // alpha requires slightly different treatment than the other (transform) properties.
+ // The logic in setAlpha() is not simply setting mAlpha, plus the invalidation
+ // logic is dependent on how the view handles an internal call to onSetAlpha().
+ // We track what kinds of properties are set, and how alpha is handled when it is
+ // set, and perform the invalidation steps appropriately.
+ boolean alphaHandled = false;
+ mView.invalidateParentCaches();
+ float fraction = animation.getAnimatedFraction();
+ PropertyBundle propertyBundle = mAnimatorMap.get(animation);
+ int propertyMask = propertyBundle.mPropertyMask;
+ if ((propertyMask & TRANSFORM_MASK) != 0) {
+ mView.invalidate(false);
+ }
+ ArrayList<NameValuesHolder> valueList = propertyBundle.mNameValuesHolder;
+ if (valueList != null) {
+ int count = valueList.size();
+ for (int i = 0; i < count; ++i) {
+ NameValuesHolder values = valueList.get(i);
+ float value = values.mFromValue + fraction * values.mDeltaValue;
+ if (values.mNameConstant == ALPHA) {
+ alphaHandled = mView.setAlphaNoInvalidation(value);
+ } else {
+ setValue(values.mNameConstant, value);
+ }
+ }
+ }
+ if ((propertyMask & TRANSFORM_MASK) != 0) {
+ mView.mMatrixDirty = true;
+ mView.mPrivateFlags |= View.DRAWN; // force another invalidation
+ }
+ // invalidate(false) in all cases except if alphaHandled gets set to true
+ // via the call to setAlphaNoInvalidation(), above
+ mView.invalidate(alphaHandled);
+ }
+ }
+}
diff --git a/core/java/android/view/ViewRoot.java b/core/java/android/view/ViewRoot.java
index 39f99b8..965c959 100644
--- a/core/java/android/view/ViewRoot.java
+++ b/core/java/android/view/ViewRoot.java
@@ -155,6 +155,10 @@ public final class ViewRoot extends Handler implements ViewParent,
int mViewVisibility;
boolean mAppVisible = true;
+ // Set to true if the owner of this window is in the stopped state,
+ // so the window should no longer be active.
+ boolean mStopped = false;
+
SurfaceHolder.Callback2 mSurfaceHolderCallback;
BaseSurfaceHolder mSurfaceHolder;
boolean mIsCreating;
@@ -618,6 +622,15 @@ public final class ViewRoot extends Handler implements ViewParent,
scheduleTraversals();
}
+ void setStopped(boolean stopped) {
+ if (mStopped != stopped) {
+ mStopped = stopped;
+ if (!stopped) {
+ scheduleTraversals();
+ }
+ }
+ }
+
public ViewParent getParent() {
return null;
}
@@ -760,7 +773,7 @@ public final class ViewRoot extends Handler implements ViewParent,
boolean insetsChanged = false;
- if (mLayoutRequested) {
+ if (mLayoutRequested && !mStopped) {
// Execute enqueued actions on every layout in case a view that was detached
// enqueued an action after being detached
getRunQueue().executeActions(attachInfo.mHandler);
@@ -1143,54 +1156,56 @@ public final class ViewRoot extends Handler implements ViewParent,
mAttachInfo.mHardwareRenderer.setup(mWidth, mHeight);
}
- boolean focusChangedDueToTouchMode = ensureTouchModeLocally(
- (relayoutResult&WindowManagerImpl.RELAYOUT_IN_TOUCH_MODE) != 0);
- if (focusChangedDueToTouchMode || mWidth != host.getMeasuredWidth()
- || mHeight != host.getMeasuredHeight() || contentInsetsChanged) {
- childWidthMeasureSpec = getRootMeasureSpec(mWidth, lp.width);
- childHeightMeasureSpec = getRootMeasureSpec(mHeight, lp.height);
-
- if (DEBUG_LAYOUT) Log.v(TAG, "Ooops, something changed! mWidth="
- + mWidth + " measuredWidth=" + host.getMeasuredWidth()
- + " mHeight=" + mHeight
- + " measuredHeight=" + host.getMeasuredHeight()
- + " coveredInsetsChanged=" + contentInsetsChanged);
-
- // Ask host how big it wants to be
- host.measure(childWidthMeasureSpec, childHeightMeasureSpec);
-
- // Implementation of weights from WindowManager.LayoutParams
- // We just grow the dimensions as needed and re-measure if
- // needs be
- int width = host.getMeasuredWidth();
- int height = host.getMeasuredHeight();
- boolean measureAgain = false;
-
- if (lp.horizontalWeight > 0.0f) {
- width += (int) ((mWidth - width) * lp.horizontalWeight);
- childWidthMeasureSpec = MeasureSpec.makeMeasureSpec(width,
- MeasureSpec.EXACTLY);
- measureAgain = true;
- }
- if (lp.verticalWeight > 0.0f) {
- height += (int) ((mHeight - height) * lp.verticalWeight);
- childHeightMeasureSpec = MeasureSpec.makeMeasureSpec(height,
- MeasureSpec.EXACTLY);
- measureAgain = true;
- }
-
- if (measureAgain) {
- if (DEBUG_LAYOUT) Log.v(TAG,
- "And hey let's measure once more: width=" + width
- + " height=" + height);
+ if (!mStopped) {
+ boolean focusChangedDueToTouchMode = ensureTouchModeLocally(
+ (relayoutResult&WindowManagerImpl.RELAYOUT_IN_TOUCH_MODE) != 0);
+ if (focusChangedDueToTouchMode || mWidth != host.getMeasuredWidth()
+ || mHeight != host.getMeasuredHeight() || contentInsetsChanged) {
+ childWidthMeasureSpec = getRootMeasureSpec(mWidth, lp.width);
+ childHeightMeasureSpec = getRootMeasureSpec(mHeight, lp.height);
+
+ if (DEBUG_LAYOUT) Log.v(TAG, "Ooops, something changed! mWidth="
+ + mWidth + " measuredWidth=" + host.getMeasuredWidth()
+ + " mHeight=" + mHeight
+ + " measuredHeight=" + host.getMeasuredHeight()
+ + " coveredInsetsChanged=" + contentInsetsChanged);
+
+ // Ask host how big it wants to be
host.measure(childWidthMeasureSpec, childHeightMeasureSpec);
+
+ // Implementation of weights from WindowManager.LayoutParams
+ // We just grow the dimensions as needed and re-measure if
+ // needs be
+ int width = host.getMeasuredWidth();
+ int height = host.getMeasuredHeight();
+ boolean measureAgain = false;
+
+ if (lp.horizontalWeight > 0.0f) {
+ width += (int) ((mWidth - width) * lp.horizontalWeight);
+ childWidthMeasureSpec = MeasureSpec.makeMeasureSpec(width,
+ MeasureSpec.EXACTLY);
+ measureAgain = true;
+ }
+ if (lp.verticalWeight > 0.0f) {
+ height += (int) ((mHeight - height) * lp.verticalWeight);
+ childHeightMeasureSpec = MeasureSpec.makeMeasureSpec(height,
+ MeasureSpec.EXACTLY);
+ measureAgain = true;
+ }
+
+ if (measureAgain) {
+ if (DEBUG_LAYOUT) Log.v(TAG,
+ "And hey let's measure once more: width=" + width
+ + " height=" + height);
+ host.measure(childWidthMeasureSpec, childHeightMeasureSpec);
+ }
+
+ mLayoutRequested = true;
}
-
- mLayoutRequested = true;
}
}
- final boolean didLayout = mLayoutRequested;
+ final boolean didLayout = mLayoutRequested && !mStopped;
boolean triggerGlobalLayoutListener = didLayout
|| attachInfo.mRecomputeGlobalAttributes;
if (didLayout) {
@@ -2247,7 +2262,7 @@ public final class ViewRoot extends Handler implements ViewParent,
private void deliverPointerEvent(MotionEvent event, boolean sendDone) {
// If there is no view, then the event will not be handled.
if (mView == null || !mAdded) {
- finishPointerEvent(event, sendDone, false);
+ finishMotionEvent(event, sendDone, false);
return;
}
@@ -2270,7 +2285,7 @@ public final class ViewRoot extends Handler implements ViewParent,
event.offsetLocation(0, mCurScrollY);
}
if (MEASURE_LATENCY) {
- lt.sample("A Dispatching TouchEvents", System.nanoTime() - event.getEventTimeNano());
+ lt.sample("A Dispatching PointerEvents", System.nanoTime() - event.getEventTimeNano());
}
// Remember the touch position for possible drag-initiation.
@@ -2278,12 +2293,12 @@ public final class ViewRoot extends Handler implements ViewParent,
mLastTouchPoint.y = event.getRawY();
// Dispatch touch to view hierarchy.
- boolean handled = mView.dispatchTouchEvent(event);
+ boolean handled = mView.dispatchPointerEvent(event);
if (MEASURE_LATENCY) {
- lt.sample("B Dispatched TouchEvents ", System.nanoTime() - event.getEventTimeNano());
+ lt.sample("B Dispatched PointerEvents ", System.nanoTime() - event.getEventTimeNano());
}
if (handled) {
- finishPointerEvent(event, sendDone, true);
+ finishMotionEvent(event, sendDone, true);
return;
}
@@ -2325,23 +2340,27 @@ public final class ViewRoot extends Handler implements ViewParent,
if (nearest != null) {
event.offsetLocation(deltas[0], deltas[1]);
event.setEdgeFlags(0);
- if (mView.dispatchTouchEvent(event)) {
- finishPointerEvent(event, sendDone, true);
+ if (mView.dispatchPointerEvent(event)) {
+ finishMotionEvent(event, sendDone, true);
return;
}
}
}
// Pointer event was unhandled.
- finishPointerEvent(event, sendDone, false);
+ finishMotionEvent(event, sendDone, false);
}
- private void finishPointerEvent(MotionEvent event, boolean sendDone, boolean handled) {
+ private void finishMotionEvent(MotionEvent event, boolean sendDone, boolean handled) {
event.recycle();
if (sendDone) {
finishInputEvent(handled);
}
- if (LOCAL_LOGV || WATCH_POINTER) Log.i(TAG, "Done dispatching!");
+ if (LOCAL_LOGV || WATCH_POINTER) {
+ if ((event.getSource() & InputDevice.SOURCE_CLASS_POINTER) != 0) {
+ Log.i(TAG, "Done dispatching!");
+ }
+ }
}
private void deliverTrackballEvent(MotionEvent event, boolean sendDone) {
@@ -2349,7 +2368,7 @@ public final class ViewRoot extends Handler implements ViewParent,
// If there is no view, then the event will not be handled.
if (mView == null || !mAdded) {
- finishTrackballEvent(event, sendDone, false);
+ finishMotionEvent(event, sendDone, false);
return;
}
@@ -2361,7 +2380,7 @@ public final class ViewRoot extends Handler implements ViewParent,
// touch mode here.
ensureTouchMode(false);
- finishTrackballEvent(event, sendDone, true);
+ finishMotionEvent(event, sendDone, true);
mLastTrackballTime = Integer.MIN_VALUE;
return;
}
@@ -2471,14 +2490,7 @@ public final class ViewRoot extends Handler implements ViewParent,
// Unfortunately we can't tell whether the application consumed the keys, so
// we always consider the trackball event handled.
- finishTrackballEvent(event, sendDone, true);
- }
-
- private void finishTrackballEvent(MotionEvent event, boolean sendDone, boolean handled) {
- event.recycle();
- if (sendDone) {
- finishInputEvent(handled);
- }
+ finishMotionEvent(event, sendDone, true);
}
private void deliverGenericMotionEvent(MotionEvent event, boolean sendDone) {
@@ -2490,7 +2502,7 @@ public final class ViewRoot extends Handler implements ViewParent,
if (isJoystick) {
updateJoystickDirection(event, false);
}
- finishGenericMotionEvent(event, sendDone, false);
+ finishMotionEvent(event, sendDone, false);
return;
}
@@ -2499,23 +2511,16 @@ public final class ViewRoot extends Handler implements ViewParent,
if (isJoystick) {
updateJoystickDirection(event, false);
}
- finishGenericMotionEvent(event, sendDone, true);
+ finishMotionEvent(event, sendDone, true);
return;
}
if (isJoystick) {
// Translate the joystick event into DPAD keys and try to deliver those.
updateJoystickDirection(event, true);
- finishGenericMotionEvent(event, sendDone, true);
+ finishMotionEvent(event, sendDone, true);
} else {
- finishGenericMotionEvent(event, sendDone, false);
- }
- }
-
- private void finishGenericMotionEvent(MotionEvent event, boolean sendDone, boolean handled) {
- event.recycle();
- if (sendDone) {
- finishInputEvent(handled);
+ finishMotionEvent(event, sendDone, false);
}
}
diff --git a/core/java/android/view/WindowManagerImpl.java b/core/java/android/view/WindowManagerImpl.java
index 07953d6..a4c4544 100644
--- a/core/java/android/view/WindowManagerImpl.java
+++ b/core/java/android/view/WindowManagerImpl.java
@@ -302,6 +302,20 @@ public class WindowManagerImpl implements WindowManager {
}
}
+ public void setStoppedState(IBinder token, boolean stopped) {
+ synchronized (this) {
+ if (mViews == null)
+ return;
+ int count = mViews.length;
+ for (int i=0; i<count; i++) {
+ if (token == null || mParams[i].token == token) {
+ ViewRoot root = mRoots[i];
+ root.setStopped(stopped);
+ }
+ }
+ }
+ }
+
public WindowManager.LayoutParams getRootViewLayoutParameter(View view) {
ViewParent vp = view.getParent();
while (vp != null && !(vp instanceof ViewRoot)) {
diff --git a/core/java/android/view/WindowManagerPolicy.java b/core/java/android/view/WindowManagerPolicy.java
index ad06902..be68cb9 100644
--- a/core/java/android/view/WindowManagerPolicy.java
+++ b/core/java/android/view/WindowManagerPolicy.java
@@ -754,6 +754,24 @@ public interface WindowManagerPolicy {
void exitKeyguardSecurely(OnKeyguardExitResult callback);
/**
+ * isKeyguardLocked
+ *
+ * Return whether the keyguard is currently locked.
+ *
+ * @return true if in keyguard is locked.
+ */
+ public boolean isKeyguardLocked();
+
+ /**
+ * isKeyguardSecure
+ *
+ * Return whether the keyguard requires a password to unlock.
+ *
+ * @return true if in keyguard is secure.
+ */
+ public boolean isKeyguardSecure();
+
+ /**
* inKeyguardRestrictedKeyInputMode
*
* if keyguard screen is showing or in restricted key input mode (i.e. in
diff --git a/core/java/android/view/inputmethod/InputMethodManager.java b/core/java/android/view/inputmethod/InputMethodManager.java
index cb67b78..a39c7c7 100644
--- a/core/java/android/view/inputmethod/InputMethodManager.java
+++ b/core/java/android/view/inputmethod/InputMethodManager.java
@@ -762,8 +762,7 @@ public final class InputMethodManager {
* {@link #RESULT_UNCHANGED_HIDDEN}, {@link #RESULT_SHOWN}, or
* {@link #RESULT_HIDDEN}.
*/
- public boolean showSoftInput(View view, int flags,
- ResultReceiver resultReceiver) {
+ public boolean showSoftInput(View view, int flags, ResultReceiver resultReceiver) {
checkFocus();
synchronized (mH) {
if (mServedView != view && (mServedView == null
diff --git a/core/java/android/webkit/CookieManager.java b/core/java/android/webkit/CookieManager.java
index 40877e7..d6e36bb 100644
--- a/core/java/android/webkit/CookieManager.java
+++ b/core/java/android/webkit/CookieManager.java
@@ -293,6 +293,11 @@ public final class CookieManager {
* @param value The value for set-cookie: in http response header
*/
public void setCookie(String url, String value) {
+ if (JniUtil.useChromiumHttpStack()) {
+ setCookie(url, value, false);
+ return;
+ }
+
WebAddress uri;
try {
uri = new WebAddress(url);
@@ -301,11 +306,33 @@ public final class CookieManager {
return;
}
- if (JniUtil.useChromiumHttpStack()) {
- nativeSetCookie(uri.toString(), value);
- } else {
- setCookie(uri, value);
+ setCookie(uri, value);
+ }
+
+ /**
+ * Set cookie for a given url. The old cookie with same host/path/name will
+ * be removed. The new cookie will be added if it is not expired or it does
+ * not have expiration which implies it is session cookie.
+ * @param url The url which cookie is set for
+ * @param value The value for set-cookie: in http response header
+ * @param privateBrowsing cookie jar to use
+ * @hide hiding private browsing
+ */
+ public void setCookie(String url, String value, boolean privateBrowsing) {
+ if (!JniUtil.useChromiumHttpStack()) {
+ setCookie(url, value);
+ return;
}
+
+ WebAddress uri;
+ try {
+ uri = new WebAddress(url);
+ } catch (ParseException ex) {
+ Log.e(LOGTAG, "Bad address: " + url);
+ return;
+ }
+
+ nativeSetCookie(uri.toString(), value, privateBrowsing);
}
/**
@@ -424,6 +451,10 @@ public final class CookieManager {
* @return The cookies in the format of NAME=VALUE [; NAME=VALUE]
*/
public String getCookie(String url) {
+ if (JniUtil.useChromiumHttpStack()) {
+ return getCookie(url, false);
+ }
+
WebAddress uri;
try {
uri = new WebAddress(url);
@@ -432,11 +463,32 @@ public final class CookieManager {
return null;
}
- if (JniUtil.useChromiumHttpStack()) {
- return nativeGetCookie(uri.toString());
- } else {
- return getCookie(uri);
+ return getCookie(uri);
+ }
+
+ /**
+ * Get cookie(s) for a given url so that it can be set to "cookie:" in http
+ * request header.
+ * @param url The url needs cookie
+ * @param privateBrowsing cookie jar to use
+ * @return The cookies in the format of NAME=VALUE [; NAME=VALUE]
+ * @hide Private mode is not very well exposed for now
+ */
+ public String getCookie(String url, boolean privateBrowsing) {
+ if (!JniUtil.useChromiumHttpStack()) {
+ // Just redirect to regular get cookie for android stack
+ return getCookie(url);
}
+
+ WebAddress uri;
+ try {
+ uri = new WebAddress(url);
+ } catch (ParseException ex) {
+ Log.e(LOGTAG, "Bad address: " + url);
+ return null;
+ }
+
+ return nativeGetCookie(uri.toString(), privateBrowsing);
}
/**
@@ -605,13 +657,26 @@ public final class CookieManager {
*/
public synchronized boolean hasCookies() {
if (JniUtil.useChromiumHttpStack()) {
- return nativeHasCookies();
+ return hasCookies(false);
}
return CookieSyncManager.getInstance().hasCookies();
}
/**
+ * Return true if there are stored cookies.
+ * @param privateBrowsing cookie jar to use
+ * @hide Hiding private mode
+ */
+ public synchronized boolean hasCookies(boolean privateBrowsing) {
+ if (!JniUtil.useChromiumHttpStack()) {
+ return hasCookies();
+ }
+
+ return nativeHasCookies(privateBrowsing);
+ }
+
+ /**
* Remove all expired cookies
*/
public void removeExpiredCookie() {
@@ -1132,13 +1197,13 @@ public final class CookieManager {
// Native functions
private static native boolean nativeAcceptCookie();
- private static native String nativeGetCookie(String url);
- private static native boolean nativeHasCookies();
+ private static native String nativeGetCookie(String url, boolean privateBrowsing);
+ private static native boolean nativeHasCookies(boolean privateBrowsing);
private static native void nativeRemoveAllCookie();
private static native void nativeRemoveExpiredCookie();
private static native void nativeRemoveSessionCookie();
private static native void nativeSetAcceptCookie(boolean accept);
- private static native void nativeSetCookie(String url, String value);
+ private static native void nativeSetCookie(String url, String value, boolean privateBrowsing);
private static native void nativeFlushCookieStore();
private static native boolean nativeAcceptFileSchemeCookies();
private static native void nativeSetAcceptFileSchemeCookies(boolean accept);
diff --git a/core/java/android/webkit/HTML5Audio.java b/core/java/android/webkit/HTML5Audio.java
index a3906ddb..6fc0d11 100644
--- a/core/java/android/webkit/HTML5Audio.java
+++ b/core/java/android/webkit/HTML5Audio.java
@@ -173,7 +173,8 @@ class HTML5Audio extends Handler
mState = INITIALIZED;
mMediaPlayer.prepareAsync();
} catch (IOException e) {
- Log.e(LOGTAG, "couldn't load the resource: " + url + " exc: " + e);
+ String debugUrl = url.length() > 128 ? url.substring(0, 128) + "..." : url;
+ Log.e(LOGTAG, "couldn't load the resource: "+ debugUrl +" exc: " + e);
resetMediaPlayer();
}
}
diff --git a/core/java/android/webkit/HTML5VideoViewProxy.java b/core/java/android/webkit/HTML5VideoViewProxy.java
index 3caf345..85763da 100644
--- a/core/java/android/webkit/HTML5VideoViewProxy.java
+++ b/core/java/android/webkit/HTML5VideoViewProxy.java
@@ -77,6 +77,7 @@ class HTML5VideoViewProxy extends Handler
private static final int PAUSED = 203;
private static final String COOKIE = "Cookie";
+ private static final String HIDE_URL_LOGS = "x-hide-urls-from-log";
// Timer thread -> UI thread
private static final int TIMEUPDATE = 300;
@@ -183,12 +184,15 @@ class HTML5VideoViewProxy extends Handler
mVideoView.setWillNotDraw(false);
mVideoView.setMediaController(new MediaController(proxy.getContext()));
- String cookieValue = CookieManager.getInstance().getCookie(url);
- Map<String, String> headers = null;
+ boolean isPrivate = mCurrentProxy.getWebView().isPrivateBrowsingEnabled();
+ String cookieValue = CookieManager.getInstance().getCookie(url, isPrivate);
+ Map<String, String> headers = new HashMap<String, String>();
if (cookieValue != null) {
- headers = new HashMap<String, String>();
headers.put(COOKIE, cookieValue);
}
+ if (isPrivate) {
+ headers.put(HIDE_URL_LOGS, "true");
+ }
mVideoView.setVideoURI(Uri.parse(url), headers);
mVideoView.setOnCompletionListener(proxy);
diff --git a/core/java/android/webkit/L10nUtils.java b/core/java/android/webkit/L10nUtils.java
index 962492e..f59d7d0 100644
--- a/core/java/android/webkit/L10nUtils.java
+++ b/core/java/android/webkit/L10nUtils.java
@@ -18,8 +18,9 @@ package android.webkit;
import android.content.Context;
-import java.util.List;
-import java.util.Vector;
+import java.lang.ref.SoftReference;
+import java.util.Map;
+import java.util.HashMap;
/**
* @hide
@@ -32,23 +33,71 @@ public class L10nUtils {
com.android.internal.R.string.autofill_address_name_separator, // IDS_AUTOFILL_DIALOG_ADDRESS_NAME_SEPARATOR
com.android.internal.R.string.autofill_address_summary_name_format, // IDS_AUTOFILL_DIALOG_ADDRESS_SUMMARY_NAME_FORMAT
com.android.internal.R.string.autofill_address_summary_separator, // IDS_AUTOFILL_DIALOG_ADDRESS_SUMMARY_SEPARATOR
- com.android.internal.R.string.autofill_address_summary_format // IDS_AUTOFILL_DIALOG_ADDRESS_SUMMARY_FORMAT
+ com.android.internal.R.string.autofill_address_summary_format, // IDS_AUTOFILL_DIALOG_ADDRESS_SUMMARY_FORMAT
+ com.android.internal.R.string.autofill_attention_ignored_re, // IDS_AUTOFILL_ATTENTION_IGNORED_RE
+ com.android.internal.R.string.autofill_region_ignored_re, // IDS_AUTOFILL_REGION_IGNORED_RE
+ com.android.internal.R.string.autofill_company_re, // IDS_AUTOFILL_COMPANY_RE
+ com.android.internal.R.string.autofill_address_line_1_re, // IDS_AUTOFILL_ADDRESS_LINE_1_RE
+ com.android.internal.R.string.autofill_address_line_1_label_re, // IDS_AUTOFILL_ADDRESS_LINE_1_LABEL_RE
+ com.android.internal.R.string.autofill_address_line_2_re, // IDS_AUTOFILL_ADDRESS_LINE_2_RE
+ com.android.internal.R.string.autofill_address_line_3_re, // IDS_AUTOFILL_ADDRESS_LINE_3_RE
+ com.android.internal.R.string.autofill_country_re, // IDS_AUTOFILL_COUNTRY_RE
+ com.android.internal.R.string.autofill_zip_code_re, // IDS_AUTOFILL_ZIP_CODE_RE
+ com.android.internal.R.string.autofill_zip_4_re, // IDS_AUTOFILL_ZIP_4_RE
+ com.android.internal.R.string.autofill_city_re, // IDS_AUTOFILL_CITY_RE
+ com.android.internal.R.string.autofill_state_re, // IDS_AUTOFILL_STATE_RE
+ com.android.internal.R.string.autofill_address_type_same_as_re, // IDS_AUTOFILL_SAME_AS_RE
+ com.android.internal.R.string.autofill_address_type_use_my_re, // IDS_AUTOFILL_USE_MY_RE
+ com.android.internal.R.string.autofill_billing_designator_re, // IDS_AUTOFILL_BILLING_DESIGNATOR_RE
+ com.android.internal.R.string.autofill_shipping_designator_re, // IDS_AUTOFILL_SHIPPING_DESIGNATOR_RE
+ com.android.internal.R.string.autofill_email_re, // IDS_AUTOFILL_EMAIL_RE
+ com.android.internal.R.string.autofill_username_re, // IDS_AUTOFILL_USERNAME_RE
+ com.android.internal.R.string.autofill_name_re, // IDS_AUTOFILL_NAME_RE
+ com.android.internal.R.string.autofill_name_specific_re, // IDS_AUTOFILL_NAME_SPECIFIC_RE
+ com.android.internal.R.string.autofill_first_name_re, // IDS_AUTOFILL_FIRST_NAME_RE
+ com.android.internal.R.string.autofill_middle_initial_re, // IDS_AUTOFILL_MIDDLE_INITIAL_RE
+ com.android.internal.R.string.autofill_middle_name_re, // IDS_AUTOFILL_MIDDLE_NAME_RE
+ com.android.internal.R.string.autofill_last_name_re, // IDS_AUTOFILL_LAST_NAME_RE
+ com.android.internal.R.string.autofill_phone_re, // IDS_AUTOFILL_PHONE_RE
+ com.android.internal.R.string.autofill_area_code_re, // IDS_AUTOFILL_AREA_CODE_RE
+ com.android.internal.R.string.autofill_phone_prefix_re, // IDS_AUTOFILL_PHONE_PREFIX_RE
+ com.android.internal.R.string.autofill_phone_suffix_re, // IDS_AUTOFILL_PHONE_SUFFIX_RE
+ com.android.internal.R.string.autofill_phone_extension_re, // IDS_AUTOFILL_PHONE_EXTENSION_RE
+ com.android.internal.R.string.autofill_name_on_card_re, // IDS_AUTOFILL_NAME_ON_CARD_RE
+ com.android.internal.R.string.autofill_name_on_card_contextual_re, // IDS_AUTOFILL_NAME_ON_CARD_CONTEXTUAL_RE
+ com.android.internal.R.string.autofill_card_cvc_re, // IDS_AUTOFILL_CARD_CVC_RE
+ com.android.internal.R.string.autofill_card_number_re, // IDS_AUTOFILL_CARD_NUMBER_RE
+ com.android.internal.R.string.autofill_expiration_month_re, // IDS_AUTOFILL_EXPIRATION_MONTH_RE
+ com.android.internal.R.string.autofill_expiration_date_re, // IDS_AUTOFILL_EXPIRATION_DATE_RE
+ com.android.internal.R.string.autofill_card_ignored_re // IDS_AUTOFILL_CARD_IGNORED_RE
};
- private static List<String> mStrings;
+ private static Context mApplicationContext;
+ private static Map<Integer, SoftReference<String> > mStrings;
- public static void loadStrings(Context context) {
- if (mStrings != null) {
- return;
- }
+ public static void setApplicationContext(Context applicationContext) {
+ mApplicationContext = applicationContext.getApplicationContext();
+ }
- mStrings = new Vector<String>(mIdsArray.length);
- for (int i = 0; i < mIdsArray.length; i++) {
- mStrings.add(context.getResources().getString(mIdsArray[i]));
+ private static String loadString(int id) {
+ if (mStrings == null) {
+ mStrings = new HashMap<Integer, SoftReference<String> >(mIdsArray.length);
}
+
+ String localisedString = mApplicationContext.getResources().getString(mIdsArray[id]);
+ mStrings.put(id, new SoftReference<String>(localisedString));
+ return localisedString;
}
public static String getLocalisedString(int id) {
- return mStrings.get(id);
+ if (mStrings == null) {
+ // This is the first time we need a localised string.
+ // loadString will create the Map.
+ return loadString(id);
+ }
+
+ SoftReference<String> ref = mStrings.get(id);
+ boolean needToLoad = ref == null || ref.get() == null;
+ return needToLoad ? loadString(id) : ref.get();
}
}
diff --git a/core/java/android/webkit/Plugin.java b/core/java/android/webkit/Plugin.java
index 34a30a9..529820b 100644
--- a/core/java/android/webkit/Plugin.java
+++ b/core/java/android/webkit/Plugin.java
@@ -27,12 +27,23 @@ import android.webkit.WebView;
* Represents a plugin (Java equivalent of the PluginPackageAndroid
* C++ class in libs/WebKitLib/WebKit/WebCore/plugins/android/)
*
+ * @hide
* @deprecated This interface was intended to be used by Gears. Since Gears was
* deprecated, so is this class.
*/
@Deprecated
public class Plugin {
+ /*
+ * @hide
+ * @deprecated This interface was intended to be used by Gears. Since Gears was
+ * deprecated, so is this class.
+ */
public interface PreferencesClickHandler {
+ /*
+ * @hide
+ * @deprecated This interface was intended to be used by Gears. Since Gears was
+ * deprecated, so is this class.
+ */
public void handleClickEvent(Context context);
}
@@ -43,6 +54,7 @@ public class Plugin {
private PreferencesClickHandler mHandler;
/**
+ * @hide
* @deprecated This interface was intended to be used by Gears. Since Gears was
* deprecated, so is this class.
*/
@@ -59,6 +71,7 @@ public class Plugin {
}
/**
+ * @hide
* @deprecated This interface was intended to be used by Gears. Since Gears was
* deprecated, so is this class.
*/
@@ -68,6 +81,7 @@ public class Plugin {
}
/**
+ * @hide
* @deprecated This interface was intended to be used by Gears. Since Gears was
* deprecated, so is this class.
*/
@@ -77,6 +91,7 @@ public class Plugin {
}
/**
+ * @hide
* @deprecated This interface was intended to be used by Gears. Since Gears was
* deprecated, so is this class.
*/
@@ -86,6 +101,7 @@ public class Plugin {
}
/**
+ * @hide
* @deprecated This interface was intended to be used by Gears. Since Gears was
* deprecated, so is this class.
*/
@@ -95,6 +111,7 @@ public class Plugin {
}
/**
+ * @hide
* @deprecated This interface was intended to be used by Gears. Since Gears was
* deprecated, so is this class.
*/
@@ -104,6 +121,7 @@ public class Plugin {
}
/**
+ * @hide
* @deprecated This interface was intended to be used by Gears. Since Gears was
* deprecated, so is this class.
*/
@@ -113,6 +131,7 @@ public class Plugin {
}
/**
+ * @hide
* @deprecated This interface was intended to be used by Gears. Since Gears was
* deprecated, so is this class.
*/
@@ -122,6 +141,7 @@ public class Plugin {
}
/**
+ * @hide
* @deprecated This interface was intended to be used by Gears. Since Gears was
* deprecated, so is this class.
*/
@@ -131,6 +151,7 @@ public class Plugin {
}
/**
+ * @hide
* @deprecated This interface was intended to be used by Gears. Since Gears was
* deprecated, so is this class.
*/
@@ -140,6 +161,7 @@ public class Plugin {
}
/**
+ * @hide
* @deprecated This interface was intended to be used by Gears. Since Gears was
* deprecated, so is this class.
*/
@@ -151,6 +173,7 @@ public class Plugin {
/**
* Invokes the click handler for this plugin.
*
+ * @hide
* @deprecated This interface was intended to be used by Gears. Since Gears was
* deprecated, so is this class.
*/
@@ -164,6 +187,7 @@ public class Plugin {
/**
* Default click handler. The plugins should implement their own.
*
+ * @hide
* @deprecated This interface was intended to be used by Gears. Since Gears was
* deprecated, so is this class.
*/
@@ -185,6 +209,7 @@ public class Plugin {
}
}
/**
+ * @hide
* @deprecated This interface was intended to be used by Gears. Since Gears was
* deprecated, so is this class.
*/
diff --git a/core/java/android/webkit/PluginData.java b/core/java/android/webkit/PluginData.java
index 2dd445e..88fc9b7 100644
--- a/core/java/android/webkit/PluginData.java
+++ b/core/java/android/webkit/PluginData.java
@@ -28,6 +28,7 @@ import java.util.Map;
* status code. The PluginData class is the container for all these
* parts.
*
+ * @hide
* @deprecated This class was intended to be used by Gears. Since Gears was
* deprecated, so is this class.
*/
@@ -63,6 +64,7 @@ public final class PluginData {
* lowercase header name to [ unmodified header name, header value]
* @param length The HTTP response status code.
*
+ * @hide
* @deprecated This class was intended to be used by Gears. Since Gears was
* deprecated, so is this class.
*/
@@ -83,6 +85,7 @@ public final class PluginData {
*
* @return An InputStream instance with the plugin content.
*
+ * @hide
* @deprecated This class was intended to be used by Gears. Since Gears was
* deprecated, so is this class.
*/
@@ -96,6 +99,7 @@ public final class PluginData {
*
* @return the length of the plugin content.
*
+ * @hide
* @deprecated This class was intended to be used by Gears. Since Gears was
* deprecated, so is this class.
*/
@@ -112,6 +116,7 @@ public final class PluginData {
* mapping is 'lowercase header name' to ['unmodified header
* name', header value].
*
+ * @hide
* @deprecated This class was intended to be used by Gears. Since Gears was
* deprecated, so is this class.
*/
@@ -125,6 +130,7 @@ public final class PluginData {
*
* @return The HTTP statue code, e.g 200.
*
+ * @hide
* @deprecated This class was intended to be used by Gears. Since Gears was
* deprecated, so is this class.
*/
diff --git a/core/java/android/webkit/PluginList.java b/core/java/android/webkit/PluginList.java
index a61b07b..d07b8a0 100644
--- a/core/java/android/webkit/PluginList.java
+++ b/core/java/android/webkit/PluginList.java
@@ -25,6 +25,7 @@ import java.util.List;
* populated when the plugins are initialized (at
* browser startup, at the moment).
*
+ * @hide
* @deprecated This interface was intended to be used by Gears. Since Gears was
* deprecated, so is this class.
*/
@@ -35,6 +36,7 @@ public class PluginList {
/**
* Public constructor. Initializes the list of plugins.
*
+ * @hide
* @deprecated This interface was intended to be used by Gears. Since Gears was
* deprecated, so is this class.
*/
@@ -46,6 +48,7 @@ public class PluginList {
/**
* Returns the list of plugins as a java.util.List.
*
+ * @hide
* @deprecated This interface was intended to be used by Gears. Since Gears was
* deprecated, so is this class.
*/
@@ -57,6 +60,7 @@ public class PluginList {
/**
* Adds a plugin to the list.
*
+ * @hide
* @deprecated This interface was intended to be used by Gears. Since Gears was
* deprecated, so is this class.
*/
@@ -70,6 +74,7 @@ public class PluginList {
/**
* Removes a plugin from the list.
*
+ * @hide
* @deprecated This interface was intended to be used by Gears. Since Gears was
* deprecated, so is this class.
*/
@@ -84,6 +89,7 @@ public class PluginList {
/**
* Clears the plugin list.
*
+ * @hide
* @deprecated This interface was intended to be used by Gears. Since Gears was
* deprecated, so is this class.
*/
@@ -95,6 +101,7 @@ public class PluginList {
/**
* Dispatches the click event to the appropriate plugin.
*
+ * @hide
* @deprecated This interface was intended to be used by Gears. Since Gears was
* deprecated, so is this class.
*/
diff --git a/core/java/android/webkit/SelectActionModeCallback.java b/core/java/android/webkit/SelectActionModeCallback.java
index ea09fc0..104deb1 100644
--- a/core/java/android/webkit/SelectActionModeCallback.java
+++ b/core/java/android/webkit/SelectActionModeCallback.java
@@ -83,6 +83,7 @@ class SelectActionModeCallback implements ActionMode.Callback {
case com.android.internal.R.id.websearch:
mode.finish();
Intent i = new Intent(Intent.ACTION_WEB_SEARCH);
+ i.putExtra(SearchManager.EXTRA_NEW_SEARCH, true);
i.putExtra(SearchManager.QUERY, mWebView.getSelection());
mWebView.getContext().startActivity(i);
break;
diff --git a/core/java/android/webkit/UrlInterceptHandler.java b/core/java/android/webkit/UrlInterceptHandler.java
index 78bab04..59fc0cb 100644
--- a/core/java/android/webkit/UrlInterceptHandler.java
+++ b/core/java/android/webkit/UrlInterceptHandler.java
@@ -21,6 +21,7 @@ import android.webkit.PluginData;
import java.util.Map;
/**
+ * @hide
* @deprecated This interface was inteded to be used by Gears. Since Gears was
* deprecated, so is this class.
*/
@@ -36,6 +37,7 @@ public interface UrlInterceptHandler {
* @param headers The headers associated with the request. May be null.
* @return The CacheResult containing the surrogate response.
*
+ * @hide
* @deprecated Do not use, this interface is deprecated.
*/
@Deprecated
@@ -50,6 +52,7 @@ public interface UrlInterceptHandler {
* @param headers The headers associated with the request. May be null.
* @return The PluginData containing the surrogate response.
*
+ * @hide
* @deprecated Do not use, this interface is deprecated.
*/
@Deprecated
diff --git a/core/java/android/webkit/UrlInterceptRegistry.java b/core/java/android/webkit/UrlInterceptRegistry.java
index eca5acd..bdf6747 100644
--- a/core/java/android/webkit/UrlInterceptRegistry.java
+++ b/core/java/android/webkit/UrlInterceptRegistry.java
@@ -25,6 +25,7 @@ import java.util.LinkedList;
import java.util.Map;
/**
+ * @hide
* @deprecated This class was intended to be used by Gears. Since Gears was
* deprecated, so is this class.
*/
@@ -48,6 +49,7 @@ public final class UrlInterceptRegistry {
*
* @param disabled true to disable the cache
*
+ * @hide
* @deprecated This class was intended to be used by Gears. Since Gears was
* deprecated, so is this class.
*/
@@ -61,6 +63,7 @@ public final class UrlInterceptRegistry {
*
* @return return if it is disabled
*
+ * @hide
* @deprecated This class was intended to be used by Gears. Since Gears was
* deprecated, so is this class.
*/
@@ -76,6 +79,7 @@ public final class UrlInterceptRegistry {
* @param handler The new UrlInterceptHandler object
* @return true if the handler was not previously registered.
*
+ * @hide
* @deprecated This class was intended to be used by Gears. Since Gears was
* deprecated, so is this class.
*/
@@ -96,6 +100,7 @@ public final class UrlInterceptRegistry {
* @param handler A previously registered UrlInterceptHandler.
* @return true if the handler was found and removed from the list.
*
+ * @hide
* @deprecated This class was intended to be used by Gears. Since Gears was
* deprecated, so is this class.
*/
@@ -111,6 +116,7 @@ public final class UrlInterceptRegistry {
*
* @return A CacheResult containing surrogate content.
*
+ * @hide
* @deprecated This class was intended to be used by Gears. Since Gears was
* deprecated, so is this class.
*/
@@ -138,6 +144,7 @@ public final class UrlInterceptRegistry {
*
* @return A PluginData instance containing surrogate content.
*
+ * @hide
* @deprecated This class was intended to be used by Gears. Since Gears was
* deprecated, so is this class.
*/
diff --git a/core/java/android/webkit/WebTextView.java b/core/java/android/webkit/WebTextView.java
index 492cb80..47c69be 100644
--- a/core/java/android/webkit/WebTextView.java
+++ b/core/java/android/webkit/WebTextView.java
@@ -947,6 +947,8 @@ import junit.framework.Assert;
@Override
public void setBounds(int left, int top, int right, int bottom) {
super.setBounds(left, top, right, bottom);
+ bottom--;
+ right -= 2;
// Top line
mLines[0] = left;
mLines[1] = top + 1;
diff --git a/core/java/android/webkit/WebView.java b/core/java/android/webkit/WebView.java
index 74e6628..43f8790 100644
--- a/core/java/android/webkit/WebView.java
+++ b/core/java/android/webkit/WebView.java
@@ -62,6 +62,7 @@ import android.util.EventLog;
import android.util.Log;
import android.view.Gravity;
import android.view.HardwareCanvas;
+import android.view.InputDevice;
import android.view.KeyCharacterMap;
import android.view.KeyEvent;
import android.view.LayoutInflater;
@@ -986,7 +987,7 @@ public class WebView extends AbsoluteLayout
mCallbackProxy = new CallbackProxy(context, this);
mViewManager = new ViewManager(this);
- L10nUtils.loadStrings(context);
+ L10nUtils.setApplicationContext(context.getApplicationContext());
mWebViewCore = new WebViewCore(context, this, mCallbackProxy, javaScriptInterfaces);
mDatabase = WebViewDatabase.getInstance(context);
mScroller = new OverScroller(context, null, 0, 0, false); //TODO Use OverScroller's flywheel
@@ -1339,11 +1340,12 @@ public class WebView extends AbsoluteLayout
}
}
- /*
+ /**
* returns the height of the titlebarview (if any). Does not care about
* scrolling
+ * @hide
*/
- int getTitleHeight() {
+ protected int getTitleHeight() {
return mTitleBar != null ? mTitleBar.getHeight() : 0;
}
@@ -2271,6 +2273,17 @@ public class WebView extends AbsoluteLayout
}
int contentX = viewToContentX(mLastTouchX + mScrollX);
int contentY = viewToContentY(mLastTouchY + mScrollY);
+ if (nativeHasCursorNode()) {
+ Rect cursorBounds = nativeGetCursorRingBounds();
+ if (!cursorBounds.contains(contentX, contentY)) {
+ int slop = viewToContentDimension(mNavSlop);
+ cursorBounds.inset(-slop, -slop);
+ if (cursorBounds.contains(contentX, contentY)) {
+ contentX = (int) cursorBounds.centerX();
+ contentY = (int) cursorBounds.centerY();
+ }
+ }
+ }
mWebViewCore.sendMessage(EventHub.REQUEST_CURSOR_HREF,
contentX, contentY, hrefMsg);
}
@@ -3672,6 +3685,7 @@ public class WebView extends AbsoluteLayout
* Return the list of currently loaded plugins.
* @return The list of currently loaded plugins.
*
+ * @hide
* @deprecated This was used for Gears, which has been deprecated.
*/
@Deprecated
@@ -3680,6 +3694,7 @@ public class WebView extends AbsoluteLayout
}
/**
+ * @hide
* @deprecated This was used for Gears, which has been deprecated.
*/
@Deprecated
@@ -3710,7 +3725,7 @@ public class WebView extends AbsoluteLayout
} else if (mTitleGravity == Gravity.TOP) {
newTop = mScrollY;
}
- mTitleBar.setBottom(newTop + getTitleHeight());
+ mTitleBar.setBottom(newTop + mTitleBar.getHeight());
mTitleBar.setTop(newTop);
}
return super.drawChild(canvas, child, drawingTime);
@@ -3790,7 +3805,7 @@ public class WebView extends AbsoluteLayout
drawOverScrollBackground(canvas);
}
if (mTitleBar != null) {
- canvas.translate(0, (int) mTitleBar.getHeight());
+ canvas.translate(0, getTitleHeight());
}
drawContent(canvas);
canvas.restoreToCount(saveCount);
@@ -5028,15 +5043,13 @@ public class WebView extends AbsoluteLayout
super.onAttachedToWindow();
if (hasWindowFocus()) setActive(true);
final ViewTreeObserver treeObserver = getViewTreeObserver();
- if (treeObserver != null) {
- if (mGlobalLayoutListener == null) {
- mGlobalLayoutListener = new InnerGlobalLayoutListener();
- treeObserver.addOnGlobalLayoutListener(mGlobalLayoutListener);
- }
- if (mScrollChangedListener == null) {
- mScrollChangedListener = new InnerScrollChangedListener();
- treeObserver.addOnScrollChangedListener(mScrollChangedListener);
- }
+ if (mGlobalLayoutListener == null) {
+ mGlobalLayoutListener = new InnerGlobalLayoutListener();
+ treeObserver.addOnGlobalLayoutListener(mGlobalLayoutListener);
+ }
+ if (mScrollChangedListener == null) {
+ mScrollChangedListener = new InnerScrollChangedListener();
+ treeObserver.addOnScrollChangedListener(mScrollChangedListener);
}
addAccessibilityApisToJavaScript();
@@ -5049,15 +5062,13 @@ public class WebView extends AbsoluteLayout
if (hasWindowFocus()) setActive(false);
final ViewTreeObserver treeObserver = getViewTreeObserver();
- if (treeObserver != null) {
- if (mGlobalLayoutListener != null) {
- treeObserver.removeGlobalOnLayoutListener(mGlobalLayoutListener);
- mGlobalLayoutListener = null;
- }
- if (mScrollChangedListener != null) {
- treeObserver.removeOnScrollChangedListener(mScrollChangedListener);
- mScrollChangedListener = null;
- }
+ if (mGlobalLayoutListener != null) {
+ treeObserver.removeGlobalOnLayoutListener(mGlobalLayoutListener);
+ mGlobalLayoutListener = null;
+ }
+ if (mScrollChangedListener != null) {
+ treeObserver.removeOnScrollChangedListener(mScrollChangedListener);
+ mScrollChangedListener = null;
}
removeAccessibilityApisFromJavaScript();
@@ -5091,8 +5102,7 @@ public class WebView extends AbsoluteLayout
/**
* @deprecated WebView should not have implemented
- * ViewTreeObserver.OnGlobalFocusChangeListener. This method
- * does nothing now.
+ * ViewTreeObserver.OnGlobalFocusChangeListener. This method does nothing now.
*/
@Deprecated
public void onGlobalFocusChanged(View oldFocus, View newFocus) {
@@ -5400,12 +5410,20 @@ public class WebView extends AbsoluteLayout
// If WebKit already showed no interests in this sequence of events,
// WebView handles them directly.
- if (mPreventDefault == PREVENT_DEFAULT_NO && action == MotionEvent.ACTION_MOVE) {
+ if (mPreventDefault == PREVENT_DEFAULT_NO) {
handleMultiTouchInWebView(ev);
} else {
passMultiTouchToWebKit(ev);
}
return true;
+ } else {
+ final ScaleGestureDetector detector = mZoomManager.getMultiTouchGestureDetector();
+ if (detector != null) {
+ // ScaleGestureDetector needs a consistent event stream to operate properly.
+ // It won't take any action with fewer than two pointers, but it needs to
+ // update internal bookkeeping state.
+ detector.onTouchEvent(ev);
+ }
}
// Skip ACTION_MOVE for single touch if it's still handling multi-touch.
@@ -5531,6 +5549,8 @@ public class WebView extends AbsoluteLayout
ted.mPoints[0] = new Point(contentX, contentY);
ted.mMetaState = ev.getMetaState();
ted.mReprocess = mDeferTouchProcess;
+ ted.mNativeLayer = nativeScrollableLayer(
+ contentX, contentY, ted.mNativeLayerRect, null);
mWebViewCore.sendMessage(EventHub.TOUCH_EVENT, ted);
if (mDeferTouchProcess) {
// still needs to set them for compute deltaX/Y
@@ -5575,6 +5595,8 @@ public class WebView extends AbsoluteLayout
ted.mPoints[0] = new Point(contentX, contentY);
ted.mMetaState = ev.getMetaState();
ted.mReprocess = mDeferTouchProcess;
+ ted.mNativeLayer = mScrollingLayer;
+ ted.mNativeLayerRect.set(mScrollingLayerRect);
mWebViewCore.sendMessage(EventHub.TOUCH_EVENT, ted);
mLastSentTouchTime = eventTime;
if (mDeferTouchProcess) {
@@ -5754,6 +5776,8 @@ public class WebView extends AbsoluteLayout
ted.mPoints[0] = new Point(contentX, contentY);
ted.mMetaState = ev.getMetaState();
ted.mReprocess = mDeferTouchProcess;
+ ted.mNativeLayer = mScrollingLayer;
+ ted.mNativeLayerRect.set(mScrollingLayerRect);
mWebViewCore.sendMessage(EventHub.TOUCH_EVENT, ted);
}
mLastTouchUpTime = eventTime;
@@ -5773,6 +5797,9 @@ public class WebView extends AbsoluteLayout
ted.mPoints[0] = new Point(contentX, contentY);
ted.mMetaState = ev.getMetaState();
ted.mReprocess = mDeferTouchProcess;
+ ted.mNativeLayer = nativeScrollableLayer(
+ contentX, contentY,
+ ted.mNativeLayerRect, null);
mWebViewCore.sendMessage(EventHub.TOUCH_EVENT, ted);
} else if (mPreventDefault != PREVENT_DEFAULT_YES){
mZoomManager.handleDoubleTap(mLastTouchX, mLastTouchY);
@@ -5936,23 +5963,6 @@ public class WebView extends AbsoluteLayout
float x = ev.getX();
float y = ev.getY();
- if (!detector.isInProgress() &&
- ev.getActionMasked() != MotionEvent.ACTION_POINTER_DOWN) {
- // Insert a fake pointer down event in order to start
- // the zoom scale detector.
- MotionEvent temp = MotionEvent.obtain(ev);
- // Clear the original event and set it to
- // ACTION_POINTER_DOWN.
- try {
- temp.setAction(temp.getAction() &
- ~MotionEvent.ACTION_MASK |
- MotionEvent.ACTION_POINTER_DOWN);
- detector.onTouchEvent(temp);
- } finally {
- temp.recycle();
- }
- }
-
detector.onTouchEvent(ev);
if (detector.isInProgress()) {
@@ -6004,6 +6014,8 @@ public class WebView extends AbsoluteLayout
ted.mPoints = new Point[1];
ted.mPoints[0] = new Point(x, y);
ted.mAction = MotionEvent.ACTION_CANCEL;
+ ted.mNativeLayer = nativeScrollableLayer(
+ x, y, ted.mNativeLayerRect, null);
mWebViewCore.sendMessage(EventHub.TOUCH_EVENT, ted);
mPreventDefault = PREVENT_DEFAULT_IGNORE;
}
@@ -6131,6 +6143,33 @@ public class WebView extends AbsoluteLayout
nativeHideCursor();
}
+ @Override
+ public boolean onGenericMotionEvent(MotionEvent event) {
+ if ((event.getSource() & InputDevice.SOURCE_CLASS_POINTER) != 0) {
+ switch (event.getAction()) {
+ case MotionEvent.ACTION_SCROLL: {
+ final float vscroll;
+ final float hscroll;
+ if ((event.getMetaState() & KeyEvent.META_SHIFT_ON) != 0) {
+ vscroll = 0;
+ hscroll = event.getAxisValue(MotionEvent.AXIS_VSCROLL);
+ } else {
+ vscroll = -event.getAxisValue(MotionEvent.AXIS_VSCROLL);
+ hscroll = event.getAxisValue(MotionEvent.AXIS_HSCROLL);
+ }
+ if (hscroll != 0 || vscroll != 0) {
+ final int vdelta = (int) (vscroll * getVerticalScrollFactor());
+ final int hdelta = (int) (hscroll * getHorizontalScrollFactor());
+ if (pinScrollBy(hdelta, vdelta, true, 0)) {
+ return true;
+ }
+ }
+ }
+ }
+ }
+ return super.onGenericMotionEvent(event);
+ }
+
private long mTrackballFirstTime = 0;
private long mTrackballLastTime = 0;
private float mTrackballRemainsX = 0.0f;
@@ -6643,8 +6682,9 @@ public class WebView extends AbsoluteLayout
// mLastTouchX and mLastTouchY are the point in the current viewport
int contentX = viewToContentX(mLastTouchX + mScrollX);
int contentY = viewToContentY(mLastTouchY + mScrollY);
- Rect rect = new Rect(contentX - mNavSlop, contentY - mNavSlop,
- contentX + mNavSlop, contentY + mNavSlop);
+ int slop = viewToContentDimension(mNavSlop);
+ Rect rect = new Rect(contentX - slop, contentY - slop,
+ contentX + slop, contentY + slop);
nativeSelectBestAt(rect);
mInitialHitTestResult = hitTestResult(null);
}
@@ -6718,7 +6758,8 @@ public class WebView extends AbsoluteLayout
}
int x = viewToContentX((int) event.getX() + mWebTextView.getLeft());
int y = viewToContentY((int) event.getY() + mWebTextView.getTop());
- nativeMotionUp(x, y, mNavSlop);
+ int slop = viewToContentDimension(mNavSlop);
+ nativeMotionUp(x, y, slop);
}
/**
@@ -6741,6 +6782,7 @@ public class WebView extends AbsoluteLayout
// mLastTouchX and mLastTouchY are the point in the current viewport
int contentX = viewToContentX(mLastTouchX + mScrollX);
int contentY = viewToContentY(mLastTouchY + mScrollY);
+ int slop = viewToContentDimension(mNavSlop);
if (getSettings().supportTouchOnly()) {
removeTouchHighlight(false);
WebViewCore.TouchUpData touchUpData = new WebViewCore.TouchUpData();
@@ -6748,7 +6790,7 @@ public class WebView extends AbsoluteLayout
// it used when processing GET_TOUCH_HIGHLIGHT_RECTS
touchUpData.mMoveGeneration = 0;
mWebViewCore.sendMessage(EventHub.TOUCH_UP, touchUpData);
- } else if (nativePointInNavCache(contentX, contentY, mNavSlop)) {
+ } else if (nativePointInNavCache(contentX, contentY, slop)) {
WebViewCore.MotionUpData motionUpData = new WebViewCore
.MotionUpData();
motionUpData.mFrame = nativeCacheHitFramePointer();
@@ -6764,7 +6806,8 @@ public class WebView extends AbsoluteLayout
}
private void doMotionUp(int contentX, int contentY) {
- if (nativeMotionUp(contentX, contentY, mNavSlop) && mLogEvent) {
+ int slop = viewToContentDimension(mNavSlop);
+ if (nativeMotionUp(contentX, contentY, slop) && mLogEvent) {
EventLog.writeEvent(EventLogTags.BROWSER_SNAP_CENTER);
}
if (nativeHasCursorNode() && !nativeCursorIsTextInput()) {
@@ -6777,7 +6820,8 @@ public class WebView extends AbsoluteLayout
* plugin. Otherwise a NULL rectangle is returned.
*/
Rect getPluginBounds(int x, int y) {
- if (nativePointInNavCache(x, y, mNavSlop) && nativeCacheHitIsPlugin()) {
+ int slop = viewToContentDimension(mNavSlop);
+ if (nativePointInNavCache(x, y, slop) && nativeCacheHitIsPlugin()) {
return nativeCacheHitNodeBounds();
} else {
return null;
@@ -7161,6 +7205,9 @@ public class WebView extends AbsoluteLayout
// simplicity for now, we don't set it.
ted.mMetaState = 0;
ted.mReprocess = mDeferTouchProcess;
+ ted.mNativeLayer = nativeScrollableLayer(
+ ted.mPoints[0].x, ted.mPoints[0].y,
+ ted.mNativeLayerRect, null);
mWebViewCore.sendMessage(EventHub.TOUCH_EVENT, ted);
} else if (mPreventDefault != PREVENT_DEFAULT_YES) {
mTouchMode = TOUCH_DONE_MODE;
@@ -7706,6 +7753,7 @@ public class WebView extends AbsoluteLayout
int mEnabled;
int mId;
+ @Override
public String toString() {
return mString;
}
@@ -7716,11 +7764,11 @@ public class WebView extends AbsoluteLayout
* and allow filtering.
*/
private class MyArrayListAdapter extends ArrayAdapter<Container> {
- public MyArrayListAdapter(Context context, Container[] objects, boolean multiple) {
- super(context,
- multiple ? com.android.internal.R.layout.select_dialog_multichoice :
- com.android.internal.R.layout.select_dialog_singlechoice,
- objects);
+ public MyArrayListAdapter() {
+ super(mContext,
+ mMultiple ? com.android.internal.R.layout.select_dialog_multichoice :
+ com.android.internal.R.layout.webview_select_singlechoice,
+ mContainers);
}
@Override
@@ -7746,13 +7794,12 @@ public class WebView extends AbsoluteLayout
}
if (Container.OPTGROUP == c.mEnabled) {
- // Currently select_dialog_multichoice and
- // select_dialog_singlechoice are CheckedTextViews. If
- // that changes, the class cast will no longer be valid.
- Assert.assertTrue(
- convertView instanceof CheckedTextView);
- ((CheckedTextView) convertView).setCheckMarkDrawable(
- null);
+ // Currently select_dialog_multichoice uses CheckedTextViews.
+ // If that changes, the class cast will no longer be valid.
+ if (mMultiple) {
+ Assert.assertTrue(convertView instanceof CheckedTextView);
+ ((CheckedTextView) convertView).setCheckMarkDrawable(null);
+ }
} else {
// c.mEnabled == Container.OPTION_DISABLED
// Draw the disabled element in a disabled state.
@@ -7859,6 +7906,7 @@ public class WebView extends AbsoluteLayout
mAdapter = a;
}
+ @Override
public void onChanged() {
// The filter may have changed which item is checked. Find the
// item that the ListView thinks is checked.
@@ -7879,15 +7927,12 @@ public class WebView extends AbsoluteLayout
}
}
}
-
- public void onInvalidate() {}
}
public void run() {
final ListView listView = (ListView) LayoutInflater.from(mContext)
.inflate(com.android.internal.R.layout.select_dialog, null);
- final MyArrayListAdapter adapter = new
- MyArrayListAdapter(mContext, mContainers, mMultiple);
+ final MyArrayListAdapter adapter = new MyArrayListAdapter();
AlertDialog.Builder b = new AlertDialog.Builder(mContext)
.setView(listView).setCancelable(true)
.setInverseBackgroundForced(true);
@@ -7925,7 +7970,7 @@ public class WebView extends AbsoluteLayout
}
} else {
listView.setOnItemClickListener(new OnItemClickListener() {
- public void onItemClick(AdapterView parent, View v,
+ public void onItemClick(AdapterView<?> parent, View v,
int position, long id) {
// Rather than sending the message right away, send it
// after the page regains focus.
@@ -8000,18 +8045,17 @@ public class WebView extends AbsoluteLayout
/*
* Send a mouse move event to the webcore thread.
*
- * @param removeFocus Pass true if the "mouse" cursor is now over a node
- * which wants key events, but it is not the focus. This
- * will make the visual appear as though nothing is in
- * focus. Remove the WebTextView, if present, and stop
- * drawing the blinking caret.
+ * @param removeFocus Pass true to remove the WebTextView, if present.
+ * @param stopPaintingCaret Stop drawing the blinking caret if true.
* called by JNI
*/
- private void sendMoveMouseIfLatest(boolean removeFocus) {
+ @SuppressWarnings("unused")
+ private void sendMoveMouseIfLatest(boolean removeFocus, boolean stopPaintingCaret) {
if (removeFocus) {
clearTextEntry();
}
mWebViewCore.sendMessage(EventHub.SET_MOVE_MOUSE_IF_LATEST,
+ stopPaintingCaret ? 1 : 0, 0,
cursorData());
}
@@ -8033,6 +8077,8 @@ public class WebView extends AbsoluteLayout
touchUpData.mNode = node;
touchUpData.mX = x;
touchUpData.mY = y;
+ touchUpData.mNativeLayer = nativeScrollableLayer(
+ x, y, touchUpData.mNativeLayerRect, null);
mWebViewCore.sendMessage(EventHub.TOUCH_UP, touchUpData);
}
@@ -8172,6 +8218,7 @@ public class WebView extends AbsoluteLayout
* zero to make the view transparent.
* @param color the ARGB color described by Color.java
*/
+ @Override
public void setBackgroundColor(int color) {
mBackgroundColor = color;
mWebViewCore.sendMessage(EventHub.SET_BACKGROUND_COLOR, color);
diff --git a/core/java/android/webkit/WebViewCore.java b/core/java/android/webkit/WebViewCore.java
index da4ce43..38288c5 100644
--- a/core/java/android/webkit/WebViewCore.java
+++ b/core/java/android/webkit/WebViewCore.java
@@ -558,7 +558,7 @@ final class WebViewCore {
private native String nativeRetrieveHref(int x, int y);
private native String nativeRetrieveAnchorText(int x, int y);
private native String nativeRetrieveImageSource(int x, int y);
-
+ private native void nativeStopPaintingCaret();
private native void nativeTouchUp(int touchGeneration,
int framePtr, int nodePtr, int x, int y);
@@ -778,6 +778,8 @@ final class WebViewCore {
int mNode;
int mX;
int mY;
+ int mNativeLayer;
+ Rect mNativeLayerRect = new Rect();
}
static class TouchHighlightData {
@@ -821,6 +823,8 @@ final class WebViewCore {
int mMetaState;
boolean mReprocess;
MotionEvent mMotionEvent;
+ int mNativeLayer;
+ Rect mNativeLayerRect = new Rect();
}
static class GeolocationPermissionsData {
@@ -1304,6 +1308,10 @@ final class WebViewCore {
case TOUCH_UP:
TouchUpData touchUpData = (TouchUpData) msg.obj;
+ if (touchUpData.mNativeLayer != 0) {
+ nativeScrollLayer(touchUpData.mNativeLayer,
+ touchUpData.mNativeLayerRect);
+ }
nativeTouchUp(touchUpData.mMoveGeneration,
touchUpData.mFrame, touchUpData.mNode,
touchUpData.mX, touchUpData.mY);
@@ -1318,6 +1326,10 @@ final class WebViewCore {
xArray[c] = ted.mPoints[c].x;
yArray[c] = ted.mPoints[c].y;
}
+ if (ted.mNativeLayer != 0) {
+ nativeScrollLayer(ted.mNativeLayer,
+ ted.mNativeLayerRect);
+ }
Message.obtain(
mWebView.mPrivateHandler,
WebView.PREVENT_TOUCH_ID,
@@ -1369,6 +1381,9 @@ final class WebViewCore {
nativeMoveMouseIfLatest(cData.mMoveGeneration,
cData.mFrame,
cData.mX, cData.mY);
+ if (msg.arg1 == 1) {
+ nativeStopPaintingCaret();
+ }
break;
case REQUEST_CURSOR_HREF: {
@@ -2357,15 +2372,42 @@ final class WebViewCore {
// mViewScale as 0 means it is in zoom overview mode. So we don't
// know the exact scale. If mRestoredScale is non-zero, use it;
// otherwise just use mTextWrapScale as the initial scale.
- data.mScale = mInitialViewState.mViewScale == 0
- ? (mRestoredScale > 0 ? mRestoredScale
- : mInitialViewState.mTextWrapScale)
- : mInitialViewState.mViewScale;
+ float tentativeScale = mInitialViewState.mViewScale;
+ if (tentativeScale == 0) {
+ // The following tries to figure out more correct view scale
+ // and text wrap scale to be sent to webkit, by using some
+ // knowledge from web settings and zoom manager.
+
+ // Calculated window width will be used to guess the scale
+ // in zoom overview mode.
+ tentativeScale = mInitialViewState.mTextWrapScale;
+ int tentativeViewWidth = Math.round(webViewWidth / tentativeScale);
+ int windowWidth = calculateWindowWidth(tentativeViewWidth,
+ tentativeViewWidth);
+ // In viewport setup time, since no content width is known, we assume
+ // the windowWidth will be the content width, to get a more likely
+ // zoom overview scale.
+ data.mScale = (float) webViewWidth / windowWidth;
+ if (!mSettings.getLoadWithOverviewMode()) {
+ // If user choose non-overview mode.
+ data.mScale = Math.max(data.mScale, tentativeScale);
+ }
+ if (mSettings.isNarrowColumnLayout() &&
+ mSettings.getUseFixedViewport()) {
+ // In case of automatic text reflow in fixed view port mode.
+ mInitialViewState.mTextWrapScale =
+ ZoomManager.computeReadingLevelScale(data.mScale);
+ }
+ } else {
+ // Scale is given such as when page is restored, use it.
+ data.mScale = tentativeScale;
+ }
if (DebugFlags.WEB_VIEW_CORE) {
Log.v(LOGTAG, "setupViewport"
+ " mRestoredScale=" + mRestoredScale
+ " mViewScale=" + mInitialViewState.mViewScale
+ " mTextWrapScale=" + mInitialViewState.mTextWrapScale
+ + " data.mScale= " + data.mScale
);
}
data.mWidth = Math.round(webViewWidth / data.mScale);
@@ -2384,8 +2426,9 @@ final class WebViewCore {
// send VIEW_SIZE_CHANGED to the front of the queue so that we
// can avoid pushing the wrong picture to the WebView side.
mEventHub.removeMessages(EventHub.VIEW_SIZE_CHANGED);
- mEventHub.sendMessageAtFrontOfQueue(Message.obtain(null,
- EventHub.VIEW_SIZE_CHANGED, data));
+ // Let webkit know the scale and inner width/height immediately
+ // in viewport setup time to avoid wrong information.
+ viewSizeChanged(data);
}
}
}
@@ -2702,4 +2745,5 @@ final class WebViewCore {
int slop);
private native void nativeAutoFillForm(int queryId);
+ private native void nativeScrollLayer(int layer, Rect rect);
}
diff --git a/core/java/android/webkit/ZoomManager.java b/core/java/android/webkit/ZoomManager.java
index 86aef4c..88c8b2a 100644
--- a/core/java/android/webkit/ZoomManager.java
+++ b/core/java/android/webkit/ZoomManager.java
@@ -282,11 +282,13 @@ class ZoomManager {
}
public final float getReadingLevelScale() {
- // The reading scale is at least 0.5f apart from the overview scale.
+ return computeScaleWithLimits(computeReadingLevelScale(getZoomOverviewScale()));
+ }
+
+ /* package */ final static float computeReadingLevelScale(float scale) {
+ // The reading scale is at least 0.5f apart from the input scale.
final float MIN_SCALE_DIFF = 0.5f;
- return computeScaleWithLimits(
- Math.max(getZoomOverviewScale() + MIN_SCALE_DIFF,
- DEFAULT_READING_LEVEL_SCALE));
+ return Math.max(scale + MIN_SCALE_DIFF, DEFAULT_READING_LEVEL_SCALE);
}
public final float getInvDefaultScale() {
@@ -627,7 +629,7 @@ class ZoomManager {
}
/* package */ float getZoomOverviewScale() {
- return mWebView.getViewWidth() * mInvZoomOverviewWidth;
+ return computeScaleWithLimits(mWebView.getViewWidth() * mInvZoomOverviewWidth);
}
public boolean isInZoomOverview() {
@@ -699,9 +701,10 @@ class ZoomManager {
* false otherwise.
*/
public boolean isPreventingWebkitUpdates() {
- // currently only animating a multi-touch zoom prevents updates, but
- // others can add their own conditions to this method if necessary.
- return mPinchToZoomAnimating;
+ // currently only animating a multi-touch zoom and fixed length
+ // animations prevent updates, but others can add their own conditions
+ // to this method if necessary.
+ return isZoomAnimating();
}
public ScaleGestureDetector getMultiTouchGestureDetector() {
@@ -720,7 +723,8 @@ class ZoomManager {
public boolean onScale(ScaleGestureDetector detector) {
// Prevent scaling beyond overview scale.
- float scale = Math.max(detector.getScaleFactor() * mActualScale,
+ float scale = Math.max(
+ computeScaleWithLimits(detector.getScaleFactor() * mActualScale),
getZoomOverviewScale());
if (mPinchToZoomAnimating || willScaleTriggerZoom(scale)) {
mPinchToZoomAnimating = true;
@@ -730,6 +734,7 @@ class ZoomManager {
} else {
scale = Math.max(scale, mActualScale * 0.8f);
}
+ scale = computeScaleWithLimits(scale);
// if the scale change is too small, regard it as jitter and skip it.
if (Math.abs(scale - mActualScale) < MINIMUM_SCALE_WITHOUT_JITTER) {
return false;
diff --git a/core/java/android/widget/AbsListView.java b/core/java/android/widget/AbsListView.java
index eb53e56..2925632 100644
--- a/core/java/android/widget/AbsListView.java
+++ b/core/java/android/widget/AbsListView.java
@@ -43,6 +43,7 @@ import android.view.ActionMode;
import android.view.ContextMenu.ContextMenuInfo;
import android.view.Gravity;
import android.view.HapticFeedbackConstants;
+import android.view.InputDevice;
import android.view.KeyEvent;
import android.view.LayoutInflater;
import android.view.Menu;
@@ -1250,6 +1251,7 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
if (mOnScrollListener != null) {
mOnScrollListener.onScroll(this, mFirstPosition, getChildCount(), mItemCount);
}
+ onScrollChanged(0, 0, 0, 0); // dummy values, View's implementation does not use these.
}
/**
@@ -2267,11 +2269,9 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
super.onAttachedToWindow();
final ViewTreeObserver treeObserver = getViewTreeObserver();
- if (treeObserver != null) {
- treeObserver.addOnTouchModeChangeListener(this);
- if (mTextFilterEnabled && mPopup != null && !mGlobalLayoutListenerAddedFilter) {
- treeObserver.addOnGlobalLayoutListener(this);
- }
+ treeObserver.addOnTouchModeChangeListener(this);
+ if (mTextFilterEnabled && mPopup != null && !mGlobalLayoutListenerAddedFilter) {
+ treeObserver.addOnGlobalLayoutListener(this);
}
if (mAdapter != null && mDataSetObserver == null) {
@@ -2296,12 +2296,10 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
mRecycler.clear();
final ViewTreeObserver treeObserver = getViewTreeObserver();
- if (treeObserver != null) {
- treeObserver.removeOnTouchModeChangeListener(this);
- if (mTextFilterEnabled && mPopup != null) {
- treeObserver.removeGlobalOnLayoutListener(this);
- mGlobalLayoutListenerAddedFilter = false;
- }
+ treeObserver.removeOnTouchModeChangeListener(this);
+ if (mTextFilterEnabled && mPopup != null) {
+ treeObserver.removeGlobalOnLayoutListener(this);
+ mGlobalLayoutListenerAddedFilter = false;
}
if (mAdapter != null) {
@@ -2792,8 +2790,9 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
if (!mDataChanged) {
if ((mTouchMode != TOUCH_MODE_FLING) && (motionPosition >= 0)
&& (getAdapter().isEnabled(motionPosition))) {
- // User clicked on an actual view (and was not stopping a fling). It might be a
- // click or a scroll. Assume it is a click until proven otherwise
+ // User clicked on an actual view (and was not stopping a fling).
+ // It might be a click or a scroll. Assume it is a click until
+ // proven otherwise
mTouchMode = TOUCH_MODE_DOWN;
// FIXME Debounce
if (mPendingCheckForTap == null) {
@@ -2802,9 +2801,10 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
postDelayed(mPendingCheckForTap, ViewConfiguration.getTapTimeout());
} else {
if (ev.getEdgeFlags() != 0 && motionPosition < 0) {
- // If we couldn't find a view to click on, but the down event was touching
- // the edge, we will bail out and try again. This allows the edge correcting
- // code in ViewRoot to try to find a nearby view to select
+ // If we couldn't find a view to click on, but the down event
+ // was touching the edge, we will bail out and try again.
+ // This allows the edge correcting code in ViewRoot to try to
+ // find a nearby view to select
return false;
}
@@ -3018,7 +3018,11 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
case TOUCH_MODE_DONE_WAITING:
final int motionPosition = mMotionPosition;
final View child = getChildAt(motionPosition - mFirstPosition);
- if (child != null && !child.hasFocusable()) {
+
+ final float x = ev.getX();
+ final boolean inList = x > mListPadding.left && x < getWidth() - mListPadding.right;
+
+ if (child != null && !child.hasFocusable() && inList) {
if (mTouchMode != TOUCH_MODE_DOWN) {
child.setPressed(false);
}
@@ -3240,24 +3244,67 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
mLastY = y;
break;
}
+
+ case MotionEvent.ACTION_POINTER_DOWN: {
+ // New pointers take over dragging duties
+ final int index = ev.getActionIndex();
+ final int id = ev.getPointerId(index);
+ final int x = (int) ev.getX(index);
+ final int y = (int) ev.getY(index);
+ mMotionCorrection = 0;
+ mActivePointerId = id;
+ mMotionX = x;
+ mMotionY = y;
+ final int motionPosition = pointToPosition(x, y);
+ if (motionPosition >= 0) {
+ // Remember where the motion event started
+ v = getChildAt(motionPosition - mFirstPosition);
+ mMotionViewOriginalTop = v.getTop();
+ mMotionPosition = motionPosition;
+ }
+ mLastY = y;
+ break;
+ }
}
return true;
}
@Override
- protected void onOverScrolled(int scrollX, int scrollY,
- boolean clampedX, boolean clampedY) {
- mScrollY = scrollY;
- invalidateParentIfNeeded();
+ protected void onOverScrolled(int scrollX, int scrollY, boolean clampedX, boolean clampedY) {
+ if (mScrollY != scrollY) {
+ onScrollChanged(mScrollX, scrollY, mScrollX, mScrollY);
+ mScrollY = scrollY;
+ invalidateParentIfNeeded();
+
+ if (clampedY) {
+ // Velocity is broken by hitting the limit; don't start a fling off of this.
+ if (mVelocityTracker != null) {
+ mVelocityTracker.clear();
+ }
+ }
+ awakenScrollBars();
+ }
+ }
- if (clampedY) {
- // Velocity is broken by hitting the limit; don't start a fling off of this.
- if (mVelocityTracker != null) {
- mVelocityTracker.clear();
+ @Override
+ public boolean onGenericMotionEvent(MotionEvent event) {
+ if ((event.getSource() & InputDevice.SOURCE_CLASS_POINTER) != 0) {
+ switch (event.getAction()) {
+ case MotionEvent.ACTION_SCROLL: {
+ if (mTouchMode == TOUCH_MODE_REST) {
+ final float vscroll = event.getAxisValue(MotionEvent.AXIS_VSCROLL);
+ if (vscroll != 0) {
+ final int delta = (int) (vscroll * getVerticalScrollFactor());
+ if (!trackMotionScroll(delta, delta)) {
+ return true;
+ }
+ }
+ }
+ }
}
}
- awakenScrollBars();
+ return super.onGenericMotionEvent(event);
}
@Override
@@ -3391,9 +3438,6 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
mMotionY = (int) ev.getY(newPointerIndex);
mMotionCorrection = 0;
mActivePointerId = ev.getPointerId(newPointerIndex);
- if (mVelocityTracker != null) {
- mVelocityTracker.clear();
- }
}
}
@@ -3508,6 +3552,7 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
post(this);
} else {
mTouchMode = TOUCH_MODE_REST;
+ reportScrollStateChange(OnScrollListener.SCROLL_STATE_IDLE);
}
}
@@ -4257,17 +4302,12 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
mLastPositionDistanceGuess += incrementalDeltaY;
}
- if (firstPosition == 0 && firstTop >= listPadding.top && incrementalDeltaY >= 0) {
- // Don't need to move views down if the top of the first position
- // is already visible
- return incrementalDeltaY != 0;
- }
+ final boolean cannotScrollDown = (firstPosition == 0 &&
+ firstTop >= listPadding.top && incrementalDeltaY >= 0);
+ final boolean cannotScrollUp = (firstPosition + childCount == mItemCount &&
+ lastBottom <= getHeight() - listPadding.bottom && incrementalDeltaY <= 0);
- if (firstPosition + childCount == mItemCount &&
- lastBottom <= getHeight() - listPadding.bottom &&
- incrementalDeltaY <= 0) {
- // Don't need to move views up if the bottom of the last position
- // is already visible
+ if (cannotScrollDown || cannotScrollUp) {
return incrementalDeltaY != 0;
}
diff --git a/core/java/android/widget/DatePicker.java b/core/java/android/widget/DatePicker.java
index cd3862f..1d442db 100644
--- a/core/java/android/widget/DatePicker.java
+++ b/core/java/android/widget/DatePicker.java
@@ -366,12 +366,23 @@ public class DatePicker extends FrameLayout {
* Gets whether the {@link CalendarView} is shown.
*
* @return True if the calendar view is shown.
+ * @see #getCalendarView()
*/
public boolean getCalendarViewShown() {
return mCalendarView.isShown();
}
/**
+ * Gets the {@link CalendarView}.
+ *
+ * @return The calendar view.
+ * @see #getCalendarViewShown()
+ */
+ public CalendarView getCalendarView () {
+ return mCalendarView;
+ }
+
+ /**
* Sets whether the {@link CalendarView} is shown.
*
* @param shown True if the calendar view is to be shown.
@@ -709,3 +720,4 @@ public class DatePicker extends FrameLayout {
};
}
}
+
diff --git a/core/java/android/widget/EdgeGlow.java b/core/java/android/widget/EdgeGlow.java
index 2a0e849..c2cb0a0 100644
--- a/core/java/android/widget/EdgeGlow.java
+++ b/core/java/android/widget/EdgeGlow.java
@@ -339,6 +339,7 @@ public class EdgeGlow {
mEdgeScaleY = mEdgeScaleYStart +
(mEdgeScaleYFinish - mEdgeScaleYStart) *
interp * factor;
+ mState = STATE_RECEDE;
break;
case STATE_RECEDE:
mState = STATE_IDLE;
diff --git a/core/java/android/widget/ExpandableListView.java b/core/java/android/widget/ExpandableListView.java
index 8279ee5..f862368 100644
--- a/core/java/android/widget/ExpandableListView.java
+++ b/core/java/android/widget/ExpandableListView.java
@@ -299,6 +299,9 @@ public class ExpandableListView extends ListView {
indicatorRect.right = mIndicatorRight;
}
+ indicatorRect.left += mPaddingLeft;
+ indicatorRect.right += mPaddingLeft;
+
lastItemType = pos.position.type;
}
diff --git a/core/java/android/widget/GridView.java b/core/java/android/widget/GridView.java
index a84df16..0383b5c 100644
--- a/core/java/android/widget/GridView.java
+++ b/core/java/android/widget/GridView.java
@@ -37,14 +37,46 @@ import android.widget.RemoteViews.RemoteView;
*
* <p>See the <a href="{@docRoot}resources/tutorials/views/hello-gridview.html">Grid
* View tutorial</a>.</p>
+ *
+ * @attr ref android.R.styleable#GridView_horizontalSpacing
+ * @attr ref android.R.styleable#GridView_verticalSpacing
+ * @attr ref android.R.styleable#GridView_stretchMode
+ * @attr ref android.R.styleable#GridView_columnWidth
+ * @attr ref android.R.styleable#GridView_numColumns
+ * @attr ref android.R.styleable#GridView_gravity
*/
@RemoteView
public class GridView extends AbsListView {
+ /**
+ * Disables stretching.
+ *
+ * @see #setStretchMode(int)
+ */
public static final int NO_STRETCH = 0;
+ /**
+ * Stretches the spacing between columns.
+ *
+ * @see #setStretchMode(int)
+ */
public static final int STRETCH_SPACING = 1;
+ /**
+ * Stretches columns.
+ *
+ * @see #setStretchMode(int)
+ */
public static final int STRETCH_COLUMN_WIDTH = 2;
+ /**
+ * Stretches the spacing between columns. The spacing is uniform.
+ *
+ * @see #setStretchMode(int)
+ */
public static final int STRETCH_SPACING_UNIFORM = 3;
-
+
+ /**
+ * Creates as many columns as can fit on screen.
+ *
+ * @see #setNumColumns(int)
+ */
public static final int AUTO_FIT = -1;
private int mNumColumns = AUTO_FIT;
diff --git a/core/java/android/widget/HorizontalScrollView.java b/core/java/android/widget/HorizontalScrollView.java
index d75748f..d92588c 100644
--- a/core/java/android/widget/HorizontalScrollView.java
+++ b/core/java/android/widget/HorizontalScrollView.java
@@ -16,25 +16,26 @@
package android.widget;
-import android.view.ViewDebug;
import com.android.internal.R;
-import android.util.AttributeSet;
+import android.content.Context;
+import android.content.res.Resources;
+import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
-import android.view.View;
+import android.util.AttributeSet;
+import android.view.FocusFinder;
+import android.view.InputDevice;
+import android.view.KeyEvent;
+import android.view.MotionEvent;
import android.view.VelocityTracker;
+import android.view.View;
import android.view.ViewConfiguration;
+import android.view.ViewDebug;
import android.view.ViewGroup;
-import android.view.KeyEvent;
-import android.view.FocusFinder;
-import android.view.MotionEvent;
import android.view.ViewParent;
import android.view.animation.AnimationUtils;
-import android.content.Context;
-import android.content.res.Resources;
-import android.content.res.TypedArray;
import java.util.List;
@@ -76,13 +77,6 @@ public class HorizontalScrollView extends FrameLayout {
private EdgeGlow mEdgeGlowRight;
/**
- * Flag to indicate that we are moving focus ourselves. This is so the
- * code that watches for focus changes initiated outside this ScrollView
- * knows that it does not have to do anything.
- */
- private boolean mScrollViewMovedFocus;
-
- /**
* Position of the last motion event.
*/
private float mLastMotionX;
@@ -481,8 +475,16 @@ public class HorizontalScrollView extends FrameLayout {
invalidate();
}
break;
+ case MotionEvent.ACTION_POINTER_DOWN: {
+ final int index = ev.getActionIndex();
+ final float x = ev.getX(index);
+ mLastMotionX = x;
+ mActivePointerId = ev.getPointerId(index);
+ break;
+ }
case MotionEvent.ACTION_POINTER_UP:
onSecondaryPointerUp(ev);
+ mLastMotionX = ev.getX(ev.findPointerIndex(mActivePointerId));
break;
}
@@ -641,6 +643,40 @@ public class HorizontalScrollView extends FrameLayout {
}
@Override
+ public boolean onGenericMotionEvent(MotionEvent event) {
+ if ((event.getSource() & InputDevice.SOURCE_CLASS_POINTER) != 0) {
+ switch (event.getAction()) {
+ case MotionEvent.ACTION_SCROLL: {
+ if (!mIsBeingDragged) {
+ final float hscroll;
+ if ((event.getMetaState() & KeyEvent.META_SHIFT_ON) != 0) {
+ hscroll = -event.getAxisValue(MotionEvent.AXIS_VSCROLL);
+ } else {
+ hscroll = event.getAxisValue(MotionEvent.AXIS_HSCROLL);
+ }
+ if (hscroll != 0) {
+ final int delta = (int) (hscroll * getHorizontalScrollFactor());
+ final int range = getScrollRange();
+ int oldScrollX = mScrollX;
+ int newScrollX = oldScrollX + delta;
+ if (newScrollX < 0) {
+ newScrollX = 0;
+ } else if (newScrollX > range) {
+ newScrollX = range;
+ }
+ if (newScrollX != oldScrollX) {
+ super.scrollTo(newScrollX, mScrollY);
+ return true;
+ }
+ }
+ }
+ }
+ }
+ }
+ return super.onGenericMotionEvent(event);
+ }
+
+ @Override
protected void onOverScrolled(int scrollX, int scrollY,
boolean clampedX, boolean clampedY) {
// Treat animating scrolls differently; see #computeScroll() for why.
@@ -885,10 +921,7 @@ public class HorizontalScrollView extends FrameLayout {
doScrollX(delta);
}
- if (newFocused != findFocus() && newFocused.requestFocus(direction)) {
- mScrollViewMovedFocus = true;
- mScrollViewMovedFocus = false;
- }
+ if (newFocused != findFocus()) newFocused.requestFocus(direction);
return handled;
}
@@ -1239,13 +1272,11 @@ public class HorizontalScrollView extends FrameLayout {
@Override
public void requestChildFocus(View child, View focused) {
- if (!mScrollViewMovedFocus) {
- if (!mIsLayoutDirty) {
- scrollToChild(focused);
- } else {
- // The child may not be laid out yet, we can't compute the scroll yet
- mChildToScrollTo = focused;
- }
+ if (!mIsLayoutDirty) {
+ scrollToChild(focused);
+ } else {
+ // The child may not be laid out yet, we can't compute the scroll yet
+ mChildToScrollTo = focused;
}
super.requestChildFocus(child, focused);
}
@@ -1363,17 +1394,16 @@ public class HorizontalScrollView extends FrameLayout {
final boolean movingRight = velocityX > 0;
+ View currentFocused = findFocus();
View newFocused = findFocusableViewInMyBounds(movingRight,
- mScroller.getFinalX(), findFocus());
+ mScroller.getFinalX(), currentFocused);
if (newFocused == null) {
newFocused = this;
}
- if (newFocused != findFocus()
- && newFocused.requestFocus(movingRight ? View.FOCUS_RIGHT : View.FOCUS_LEFT)) {
- mScrollViewMovedFocus = true;
- mScrollViewMovedFocus = false;
+ if (newFocused != currentFocused) {
+ newFocused.requestFocus(movingRight ? View.FOCUS_RIGHT : View.FOCUS_LEFT);
}
invalidate();
@@ -1385,6 +1415,7 @@ public class HorizontalScrollView extends FrameLayout {
*
* <p>This version also clamps the scrolling to the bounds of our child.
*/
+ @Override
public void scrollTo(int x, int y) {
// we rely on the fact the View.scrollBy calls scrollTo.
if (getChildCount() > 0) {
diff --git a/core/java/android/widget/ListAdapter.java b/core/java/android/widget/ListAdapter.java
index 0fd2e70..d8fd1c9 100644
--- a/core/java/android/widget/ListAdapter.java
+++ b/core/java/android/widget/ListAdapter.java
@@ -26,10 +26,14 @@ package android.widget;
public interface ListAdapter extends Adapter {
/**
- * Are all items in this ListAdapter enabled?
- * If yes it means all items are selectable and clickable.
+ * Indicates whether all the items in this adapter are enabled. If the
+ * value returned by this method changes over time, there is no guarantee
+ * it will take effect. If true, it means all items are selectable and
+ * clickable (there is no separator.)
*
- * @return True if all items are enabled
+ * @return True if all items are enabled, false otherwise.
+ *
+ * @see #isEnabled(int)
*/
public boolean areAllItemsEnabled();
@@ -41,7 +45,10 @@ public interface ListAdapter extends Adapter {
* should be thrown in that case for fast failure.
*
* @param position Index of the item
+ *
* @return True if the item is not a separator
+ *
+ * @see #areAllItemsEnabled()
*/
boolean isEnabled(int position);
}
diff --git a/core/java/android/widget/NumberPicker.java b/core/java/android/widget/NumberPicker.java
index 8e660ff..2947ebe 100644
--- a/core/java/android/widget/NumberPicker.java
+++ b/core/java/android/widget/NumberPicker.java
@@ -608,6 +608,7 @@ public class NumberPicker extends LinearLayout {
case MotionEvent.ACTION_DOWN:
mLastMotionEventY = mLastDownEventY = event.getY();
removeAllCallbacks();
+ mShowInputControlsAnimator.cancel();
mBeginEditOnUpEvent = false;
mAdjustScrollerOnUpEvent = true;
if (mDrawSelectorWheel) {
@@ -1265,7 +1266,6 @@ public class NumberPicker extends LinearLayout {
}
}
- postAdjustScrollerCommand(flingScroller.getDuration());
invalidate();
}
diff --git a/core/java/android/widget/PopupWindow.java b/core/java/android/widget/PopupWindow.java
index 4b858d0..9002b1d 100644
--- a/core/java/android/widget/PopupWindow.java
+++ b/core/java/android/widget/PopupWindow.java
@@ -378,8 +378,7 @@ public class PopupWindow {
* <p>Change the popup's content. The content is represented by an instance
* of {@link android.view.View}.</p>
*
- * <p>This method has no effect if called when the popup is showing. To
- * apply it while a popup is showing, call </p>
+ * <p>This method has no effect if called when the popup is showing.</p>
*
* @param contentView the new content for the popup
*
@@ -1040,7 +1039,7 @@ public class PopupWindow {
*
* @return true if the popup is translated upwards to fit on screen
*/
- private boolean findDropDownPosition(View anchor, WindowManager.LayoutParams p,
+ boolean findDropDownPosition(View anchor, WindowManager.LayoutParams p,
int xoff, int yoff) {
anchor.getLocationInWindow(mDrawingLocation);
@@ -1374,6 +1373,7 @@ public class PopupWindow {
* height can be set to -1 to update location only. Calling this function
* also updates the window with the current popup state as
* described for {@link #update()}.</p>
+ *
* <p>If the view later scrolls to move <code>anchor</code> to a different
* location, the popup will be moved correspondingly.</p>
*
@@ -1395,9 +1395,13 @@ public class PopupWindow {
}
WeakReference<View> oldAnchor = mAnchor;
- if (oldAnchor == null || oldAnchor.get() != anchor ||
- (updateLocation && (mAnchorXoff != xoff || mAnchorYoff != yoff))) {
+ final boolean needsUpdate = updateLocation && (mAnchorXoff != xoff || mAnchorYoff != yoff);
+ if (oldAnchor == null || oldAnchor.get() != anchor || (needsUpdate && !mIsDropdown)) {
registerForScrollChanged(anchor, xoff, yoff);
+ } else if (needsUpdate) {
+ // No need to register again if this is a DropDown, showAsDropDown already did.
+ mAnchorXoff = xoff;
+ mAnchorYoff = yoff;
}
WindowManager.LayoutParams p = (WindowManager.LayoutParams) mPopupView.getLayoutParams();
diff --git a/core/java/android/widget/ProgressBar.java b/core/java/android/widget/ProgressBar.java
index ef4e4e0..cf72ec4 100644
--- a/core/java/android/widget/ProgressBar.java
+++ b/core/java/android/widget/ProgressBar.java
@@ -701,8 +701,8 @@ public class ProgressBar extends View {
if (mProgress > max) {
mProgress = max;
- refreshProgress(R.id.progress, mProgress, false);
}
+ refreshProgress(R.id.progress, mProgress, false);
}
}
diff --git a/core/java/android/widget/RemoteViewsAdapter.java b/core/java/android/widget/RemoteViewsAdapter.java
index 13a911b..2d2165b 100644
--- a/core/java/android/widget/RemoteViewsAdapter.java
+++ b/core/java/android/widget/RemoteViewsAdapter.java
@@ -20,7 +20,6 @@ import java.lang.ref.WeakReference;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedList;
-import java.util.Map;
import android.appwidget.AppWidgetManager;
import android.content.Context;
@@ -33,8 +32,8 @@ import android.os.Message;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
-import android.view.ViewGroup;
import android.view.View.MeasureSpec;
+import android.view.ViewGroup;
import com.android.internal.widget.IRemoteViewsAdapterConnection;
import com.android.internal.widget.IRemoteViewsFactory;
diff --git a/core/java/android/widget/RemoteViewsService.java b/core/java/android/widget/RemoteViewsService.java
index fb2c416..e0b08d4 100644
--- a/core/java/android/widget/RemoteViewsService.java
+++ b/core/java/android/widget/RemoteViewsService.java
@@ -21,8 +21,6 @@ import java.util.HashMap;
import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
-import android.util.Log;
-import android.util.Pair;
import com.android.internal.widget.IRemoteViewsFactory;
@@ -40,9 +38,9 @@ public abstract class RemoteViewsService extends Service {
// reclaimed), the references to the factories that are created need to be stored and used when
// the service is restarted (in response to user input for example). When the process is
// destroyed, so is this static cache of RemoteViewsFactories.
- private static final HashMap<Intent.FilterComparison, RemoteViewsFactory> mRemoteViewFactories =
+ private static final HashMap<Intent.FilterComparison, RemoteViewsFactory> sRemoteViewFactories =
new HashMap<Intent.FilterComparison, RemoteViewsFactory>();
- private final Object mLock = new Object();
+ private static final Object sLock = new Object();
/**
* An interface for an adapter between a remote collection view (ListView, GridView, etc) and
@@ -162,6 +160,16 @@ public abstract class RemoteViewsService extends Service {
public synchronized boolean hasStableIds() {
return mFactory.hasStableIds();
}
+ public void onDestroy(Intent intent) {
+ synchronized (sLock) {
+ Intent.FilterComparison fc = new Intent.FilterComparison(intent);
+ if (RemoteViewsService.sRemoteViewFactories.containsKey(fc)) {
+ RemoteViewsFactory factory = RemoteViewsService.sRemoteViewFactories.get(fc);
+ factory.onDestroy();
+ RemoteViewsService.sRemoteViewFactories.remove(fc);
+ }
+ }
+ }
private RemoteViewsFactory mFactory;
private boolean mIsCreated;
@@ -169,17 +177,17 @@ public abstract class RemoteViewsService extends Service {
@Override
public IBinder onBind(Intent intent) {
- synchronized (mLock) {
+ synchronized (sLock) {
Intent.FilterComparison fc = new Intent.FilterComparison(intent);
RemoteViewsFactory factory = null;
boolean isCreated = false;
- if (!mRemoteViewFactories.containsKey(fc)) {
+ if (!sRemoteViewFactories.containsKey(fc)) {
factory = onGetViewFactory(intent);
- mRemoteViewFactories.put(fc, factory);
+ sRemoteViewFactories.put(fc, factory);
factory.onCreate();
isCreated = false;
} else {
- factory = mRemoteViewFactories.get(fc);
+ factory = sRemoteViewFactories.get(fc);
isCreated = true;
}
return new RemoteViewsFactoryAdapter(factory, isCreated);
diff --git a/core/java/android/widget/ScrollView.java b/core/java/android/widget/ScrollView.java
index 4cc4a27..4b4f5f2 100644
--- a/core/java/android/widget/ScrollView.java
+++ b/core/java/android/widget/ScrollView.java
@@ -16,7 +16,6 @@
package android.widget;
-import android.view.ViewDebug;
import com.android.internal.R;
import android.content.Context;
@@ -28,11 +27,13 @@ import android.graphics.drawable.Drawable;
import android.os.StrictMode;
import android.util.AttributeSet;
import android.view.FocusFinder;
+import android.view.InputDevice;
import android.view.KeyEvent;
import android.view.MotionEvent;
import android.view.VelocityTracker;
import android.view.View;
import android.view.ViewConfiguration;
+import android.view.ViewDebug;
import android.view.ViewGroup;
import android.view.ViewParent;
import android.view.animation.AnimationUtils;
@@ -71,13 +72,6 @@ public class ScrollView extends FrameLayout {
private EdgeGlow mEdgeGlowBottom;
/**
- * Flag to indicate that we are moving focus ourselves. This is so the
- * code that watches for focus changes initiated outside this ScrollView
- * knows that it does not have to do anything.
- */
- private boolean mScrollViewMovedFocus;
-
- /**
* Position of the last motion event.
*/
private float mLastMotionY;
@@ -613,8 +607,16 @@ public class ScrollView extends FrameLayout {
endDrag();
}
break;
+ case MotionEvent.ACTION_POINTER_DOWN: {
+ final int index = ev.getActionIndex();
+ final float y = ev.getY(index);
+ mLastMotionY = y;
+ mActivePointerId = ev.getPointerId(index);
+ break;
+ }
case MotionEvent.ACTION_POINTER_UP:
onSecondaryPointerUp(ev);
+ mLastMotionY = ev.getY(ev.findPointerIndex(mActivePointerId));
break;
}
return true;
@@ -638,6 +640,35 @@ public class ScrollView extends FrameLayout {
}
@Override
+ public boolean onGenericMotionEvent(MotionEvent event) {
+ if ((event.getSource() & InputDevice.SOURCE_CLASS_POINTER) != 0) {
+ switch (event.getAction()) {
+ case MotionEvent.ACTION_SCROLL: {
+ if (!mIsBeingDragged) {
+ final float vscroll = event.getAxisValue(MotionEvent.AXIS_VSCROLL);
+ if (vscroll != 0) {
+ final int delta = (int) (vscroll * getVerticalScrollFactor());
+ final int range = getScrollRange();
+ int oldScrollY = mScrollY;
+ int newScrollY = oldScrollY - delta;
+ if (newScrollY < 0) {
+ newScrollY = 0;
+ } else if (newScrollY > range) {
+ newScrollY = range;
+ }
+ if (newScrollY != oldScrollY) {
+ super.scrollTo(mScrollX, newScrollY);
+ return true;
+ }
+ }
+ }
+ }
+ }
+ }
+ return super.onGenericMotionEvent(event);
+ }
+
+ @Override
protected void onOverScrolled(int scrollX, int scrollY,
boolean clampedX, boolean clampedY) {
// Treat animating scrolls differently; see #computeScroll() for why.
@@ -671,15 +702,13 @@ public class ScrollView extends FrameLayout {
* the parameter top.
* </p>
*
- * @param topFocus look for a candidate is the one at the top of the bounds
- * if topFocus is true, or at the bottom of the bounds if topFocus is
- * false
+ * @param topFocus look for a candidate at the top of the bounds if topFocus is true,
+ * or at the bottom of the bounds if topFocus is false
* @param top the top offset of the bounds in which a focusable must be
* found (the fading edge is assumed to start at this position)
* @param preferredFocusable the View that has highest priority and will be
* returned if it is within my bounds (null is valid)
- * @return the next focusable component in the bounds or null if none can be
- * found
+ * @return the next focusable component in the bounds or null if none can be found
*/
private View findFocusableViewInMyBounds(final boolean topFocus,
final int top, View preferredFocusable) {
@@ -856,11 +885,10 @@ public class ScrollView extends FrameLayout {
* <p>Scrolls the view to make the area defined by <code>top</code> and
* <code>bottom</code> visible. This method attempts to give the focus
* to a component visible in this area. If no component can be focused in
- * the new visible area, the focus is reclaimed by this scrollview.</p>
+ * the new visible area, the focus is reclaimed by this ScrollView.</p>
*
* @param direction the scroll direction: {@link android.view.View#FOCUS_UP}
- * to go upward
- * {@link android.view.View#FOCUS_DOWN} to downward
+ * to go upward, {@link android.view.View#FOCUS_DOWN} to downward
* @param top the top offset of the new area to be made visible
* @param bottom the bottom offset of the new area to be made visible
* @return true if the key event is consumed by this method, false otherwise
@@ -885,10 +913,7 @@ public class ScrollView extends FrameLayout {
doScrollY(delta);
}
- if (newFocused != findFocus() && newFocused.requestFocus(direction)) {
- mScrollViewMovedFocus = true;
- mScrollViewMovedFocus = false;
- }
+ if (newFocused != findFocus()) newFocused.requestFocus(direction);
return handled;
}
@@ -1249,13 +1274,11 @@ public class ScrollView extends FrameLayout {
@Override
public void requestChildFocus(View child, View focused) {
- if (!mScrollViewMovedFocus) {
- if (!mIsLayoutDirty) {
- scrollToChild(focused);
- } else {
- // The child may not be laid out yet, we can't compute the scroll yet
- mChildToScrollTo = focused;
- }
+ if (!mIsLayoutDirty) {
+ scrollToChild(focused);
+ } else {
+ // The child may not be laid out yet, we can't compute the scroll yet
+ mChildToScrollTo = focused;
}
super.requestChildFocus(child, focused);
}
@@ -1388,16 +1411,15 @@ public class ScrollView extends FrameLayout {
final boolean movingDown = velocityY > 0;
+ View currentFocused = findFocus();
View newFocused =
- findFocusableViewInMyBounds(movingDown, mScroller.getFinalY(), findFocus());
+ findFocusableViewInMyBounds(movingDown, mScroller.getFinalY(), currentFocused);
if (newFocused == null) {
newFocused = this;
}
- if (newFocused != findFocus()
- && newFocused.requestFocus(movingDown ? View.FOCUS_DOWN : View.FOCUS_UP)) {
- mScrollViewMovedFocus = true;
- mScrollViewMovedFocus = false;
+ if (newFocused != currentFocused) {
+ newFocused.requestFocus(movingDown ? View.FOCUS_DOWN : View.FOCUS_UP);
}
if (mFlingStrictSpan == null) {
diff --git a/core/java/android/widget/StackView.java b/core/java/android/widget/StackView.java
index e6cf31e..bab469b 100644
--- a/core/java/android/widget/StackView.java
+++ b/core/java/android/widget/StackView.java
@@ -33,6 +33,7 @@ import android.graphics.Region;
import android.graphics.TableMaskFilter;
import android.util.AttributeSet;
import android.util.Log;
+import android.view.InputDevice;
import android.view.MotionEvent;
import android.view.VelocityTracker;
import android.view.View;
@@ -114,6 +115,8 @@ public class StackView extends AdapterViewAnimator {
private static final int MIN_TIME_BETWEEN_INTERACTION_AND_AUTOADVANCE = 5000;
+ private static long MIN_TIME_BETWEEN_SCROLLS = 100;
+
/**
* These variables are all related to the current state of touch interaction
* with the stack
@@ -137,6 +140,7 @@ public class StackView extends AdapterViewAnimator {
private StackSlider mStackSlider;
private boolean mFirstLayoutHappened = false;
private long mLastInteractionTime = 0;
+ private long mLastScrollTime;
private int mStackMode;
private int mFramePadding;
private final Rect stackInvalidateRect = new Rect();
@@ -565,6 +569,38 @@ public class StackView extends AdapterViewAnimator {
}
}
+ @Override
+ public boolean onGenericMotionEvent(MotionEvent event) {
+ if ((event.getSource() & InputDevice.SOURCE_CLASS_POINTER) != 0) {
+ switch (event.getAction()) {
+ case MotionEvent.ACTION_SCROLL: {
+ final float vscroll = event.getAxisValue(MotionEvent.AXIS_VSCROLL);
+ if (vscroll < 0) {
+ pacedScroll(false);
+ return true;
+ } else if (vscroll > 0) {
+ pacedScroll(true);
+ return true;
+ }
+ }
+ }
+ }
+ return super.onGenericMotionEvent(event);
+ }
+
+ // This ensures that the frequency of stack flips caused by scrolls is capped
+ private void pacedScroll(boolean up) {
+ long timeSinceLastScroll = System.currentTimeMillis() - mLastScrollTime;
+ if (timeSinceLastScroll > MIN_TIME_BETWEEN_SCROLLS) {
+ if (up) {
+ showPrevious();
+ } else {
+ showNext();
+ }
+ mLastScrollTime = System.currentTimeMillis();
+ }
+ }
+
/**
* {@inheritDoc}
*/
diff --git a/core/java/android/widget/TabHost.java b/core/java/android/widget/TabHost.java
index 03eea66..57a8531 100644
--- a/core/java/android/widget/TabHost.java
+++ b/core/java/android/widget/TabHost.java
@@ -183,18 +183,14 @@ mTabHost.addTab(TAB_TAG_1, "Hello, world!", "Tab 1");
protected void onAttachedToWindow() {
super.onAttachedToWindow();
final ViewTreeObserver treeObserver = getViewTreeObserver();
- if (treeObserver != null) {
- treeObserver.addOnTouchModeChangeListener(this);
- }
+ treeObserver.addOnTouchModeChangeListener(this);
}
@Override
protected void onDetachedFromWindow() {
super.onDetachedFromWindow();
final ViewTreeObserver treeObserver = getViewTreeObserver();
- if (treeObserver != null) {
- treeObserver.removeOnTouchModeChangeListener(this);
- }
+ treeObserver.removeOnTouchModeChangeListener(this);
}
/**
diff --git a/core/java/android/widget/TabWidget.java b/core/java/android/widget/TabWidget.java
index 22f6f4e..6f76dd0 100644
--- a/core/java/android/widget/TabWidget.java
+++ b/core/java/android/widget/TabWidget.java
@@ -172,10 +172,15 @@ public class TabWidget extends LinearLayout implements OnFocusChangeListener {
@Override
void measureHorizontal(int widthMeasureSpec, int heightMeasureSpec) {
+ if (MeasureSpec.getMode(widthMeasureSpec) == MeasureSpec.UNSPECIFIED) {
+ super.measureHorizontal(widthMeasureSpec, heightMeasureSpec);
+ return;
+ }
+
// First, measure with no constraint
final int unspecifiedWidth = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED);
- super.measureHorizontal(unspecifiedWidth, heightMeasureSpec);
mImposedTabsHeight = -1;
+ super.measureHorizontal(unspecifiedWidth, heightMeasureSpec);
int extraWidth = getMeasuredWidth() - MeasureSpec.getSize(widthMeasureSpec);
if (extraWidth > 0) {
@@ -208,9 +213,7 @@ public class TabWidget extends LinearLayout implements OnFocusChangeListener {
}
// Measure again, this time with imposed tab widths and respecting initial spec request
- if (mImposedTabsHeight >= 0 || unspecifiedWidth != widthMeasureSpec) {
- super.measureHorizontal(widthMeasureSpec, heightMeasureSpec);
- }
+ super.measureHorizontal(widthMeasureSpec, heightMeasureSpec);
}
/**
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index d90d5be..09c1ac5 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -46,7 +46,6 @@ import android.os.Handler;
import android.os.Message;
import android.os.Parcel;
import android.os.Parcelable;
-import android.os.ResultReceiver;
import android.os.SystemClock;
import android.text.BoringLayout;
import android.text.DynamicLayout;
@@ -206,7 +205,7 @@ import java.util.ArrayList;
public class TextView extends View implements ViewTreeObserver.OnPreDrawListener {
static final String LOG_TAG = "TextView";
static final boolean DEBUG_EXTRACT = false;
-
+
private static final int PRIORITY = 100;
private int mCurrentAlpha = 255;
@@ -3874,9 +3873,6 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
private void registerForPreDraw() {
final ViewTreeObserver observer = getViewTreeObserver();
- if (observer == null) {
- return;
- }
if (mPreDrawState == PREDRAW_NOT_REGISTERED) {
observer.addOnPreDrawListener(this);
@@ -3962,15 +3958,13 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
}
final ViewTreeObserver observer = getViewTreeObserver();
- if (observer != null) {
- // No need to create the controller.
- // The get method will add the listener on controller creation.
- if (mInsertionPointCursorController != null) {
- observer.addOnTouchModeChangeListener(mInsertionPointCursorController);
- }
- if (mSelectionModifierCursorController != null) {
- observer.addOnTouchModeChangeListener(mSelectionModifierCursorController);
- }
+ // No need to create the controller.
+ // The get method will add the listener on controller creation.
+ if (mInsertionPointCursorController != null) {
+ observer.addOnTouchModeChangeListener(mInsertionPointCursorController);
+ }
+ if (mSelectionModifierCursorController != null) {
+ observer.addOnTouchModeChangeListener(mSelectionModifierCursorController);
}
}
@@ -3979,18 +3973,16 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
super.onDetachedFromWindow();
final ViewTreeObserver observer = getViewTreeObserver();
- if (observer != null) {
- if (mPreDrawState != PREDRAW_NOT_REGISTERED) {
- observer.removeOnPreDrawListener(this);
- mPreDrawState = PREDRAW_NOT_REGISTERED;
- }
- // No need to create the controller, as getXXController would.
- if (mInsertionPointCursorController != null) {
- observer.removeOnTouchModeChangeListener(mInsertionPointCursorController);
- }
- if (mSelectionModifierCursorController != null) {
- observer.removeOnTouchModeChangeListener(mSelectionModifierCursorController);
- }
+ if (mPreDrawState != PREDRAW_NOT_REGISTERED) {
+ observer.removeOnPreDrawListener(this);
+ mPreDrawState = PREDRAW_NOT_REGISTERED;
+ }
+ // No need to create the controller, as getXXController would.
+ if (mInsertionPointCursorController != null) {
+ observer.removeOnTouchModeChangeListener(mInsertionPointCursorController);
+ }
+ if (mSelectionModifierCursorController != null) {
+ observer.removeOnTouchModeChangeListener(mSelectionModifierCursorController);
}
if (mError != null) {
@@ -3998,7 +3990,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
}
if (mBlink != null) {
- mBlink.cancel();
+ mBlink.removeCallbacks(mBlink);
}
if (mInsertionPointCursorController != null) {
@@ -4291,10 +4283,8 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
if (mPreDrawState == PREDRAW_DONE) {
final ViewTreeObserver observer = getViewTreeObserver();
- if (observer != null) {
- observer.removeOnPreDrawListener(this);
- mPreDrawState = PREDRAW_NOT_REGISTERED;
- }
+ observer.removeOnPreDrawListener(this);
+ mPreDrawState = PREDRAW_NOT_REGISTERED;
}
int color = mCurTextColor;
@@ -4404,7 +4394,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
}
mHighlightPaint.setStyle(Paint.Style.STROKE);
highlight = mHighlightPath;
- drawCursor = true;
+ drawCursor = mCursorCount > 0;
}
} else {
if (mHighlightPathBogus) {
@@ -4513,7 +4503,10 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
}
private void updateCursorsPositions() {
- if (mCursorDrawableRes == 0) return;
+ if (mCursorDrawableRes == 0) {
+ mCursorCount = 0;
+ return;
+ }
final int offset = getSelectionStart();
final int line = mLayout.getLineForOffset(offset);
@@ -5422,18 +5415,13 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
invalidate();
int curs = getSelectionStart();
- if (curs >= 0 || (mGravity & Gravity.VERTICAL_GRAVITY_MASK) ==
- Gravity.BOTTOM) {
+ if (curs >= 0 || (mGravity & Gravity.VERTICAL_GRAVITY_MASK) == Gravity.BOTTOM) {
registerForPreDraw();
}
if (curs >= 0) {
mHighlightPathBogus = true;
-
- if (isFocused()) {
- mShowCursor = SystemClock.uptimeMillis();
- makeBlink();
- }
+ makeBlink();
}
checkForResize();
@@ -5547,8 +5535,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
ellipsisWidth);
} else {
if (boring == UNKNOWN_BORING) {
- boring = BoringLayout.isBoring(mTransformed, mTextPaint,
- mBoring);
+ boring = BoringLayout.isBoring(mTransformed, mTextPaint, mBoring);
if (boring != null) {
mBoring = boring;
}
@@ -6590,13 +6577,15 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
*/
@android.view.RemotableViewMethod
public void setCursorVisible(boolean visible) {
- mCursorVisible = visible;
- invalidate();
+ if (mCursorVisible != visible) {
+ mCursorVisible = visible;
+ invalidate();
- makeBlink();
+ makeBlink();
- // InsertionPointCursorController depends on mCursorVisible
- prepareCursorControllers();
+ // InsertionPointCursorController depends on mCursorVisible
+ prepareCursorControllers();
+ }
}
private boolean isCursorVisible() {
@@ -6935,11 +6924,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
if (oldStart >= 0 || newStart >= 0) {
invalidateCursor(Selection.getSelectionStart(buf), oldStart, newStart);
registerForPreDraw();
-
- if (isFocused()) {
- mShowCursor = SystemClock.uptimeMillis();
- makeBlink();
- }
+ makeBlink();
}
}
@@ -7090,22 +7075,6 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
}
}
- private void makeBlink() {
- if (!isCursorVisible()) {
- if (mBlink != null) {
- mBlink.removeCallbacks(mBlink);
- }
-
- return;
- }
-
- if (mBlink == null)
- mBlink = new Blink(this);
-
- mBlink.removeCallbacks(mBlink);
- mBlink.postAtTime(mBlink, mShowCursor + BLINK);
- }
-
/**
* @hide
*/
@@ -7122,6 +7091,11 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
// Only track when onStartTemporaryDetach() is called directly,
// usually because this instance is an editable field in a list
if (!mDispatchTemporaryDetach) mTemporaryDetach = true;
+
+ // Because of View recycling in ListView, there is no easy way to know when a TextView with
+ // selection becomes visible again. Until a better solution is found, stop text selection
+ // mode (if any) as soon as this TextView is recycled.
+ stopSelectionActionMode();
}
@Override
@@ -7212,16 +7186,15 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
// Don't leave us in the middle of a batch edit.
onEndBatchEdit();
- hideInsertionPointCursorController();
if (this instanceof ExtractEditText) {
// terminateTextSelectionMode removes selection, which we want to keep when
// ExtractEditText goes out of focus.
final int selStart = getSelectionStart();
final int selEnd = getSelectionEnd();
- terminateSelectionActionMode();
+ hideControllers();
Selection.setSelection((Spannable) mText, selStart, selEnd);
} else {
- terminateSelectionActionMode();
+ hideControllers();
}
// No need to create the controller
@@ -7243,7 +7216,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
// does not happen in that case (using the arrows on a bluetooth keyboard).
if (focused && isTextEditable()) {
final InputMethodManager imm = InputMethodManager.peekInstance();
- if (imm != null) imm.showSoftInput(this, 0, null);
+ if (imm != null) imm.showSoftInput(this, 0);
}
}
@@ -7272,11 +7245,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
if (hasWindowFocus) {
if (mBlink != null) {
mBlink.uncancel();
-
- if (isFocused()) {
- mShowCursor = SystemClock.uptimeMillis();
- makeBlink();
- }
+ makeBlink();
}
} else {
if (mBlink != null) {
@@ -7327,33 +7296,6 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
}
}
- class CommitSelectionReceiver extends ResultReceiver {
- private final int mPrevStart, mPrevEnd;
-
- public CommitSelectionReceiver(int prevStart, int prevEnd) {
- super(getHandler());
- mPrevStart = prevStart;
- mPrevEnd = prevEnd;
- }
-
- @Override
- protected void onReceiveResult(int resultCode, Bundle resultData) {
- // If this tap was actually used to show the IMM, leave cursor or selection unchanged
- // by restoring its previous position.
- if (resultCode == InputMethodManager.RESULT_SHOWN) {
- final int len = mText.length();
- int start = Math.min(len, mPrevStart);
- int end = Math.min(len, mPrevEnd);
- Selection.setSelection((Spannable)mText, start, end);
-
- boolean selectAllGotFocus = mSelectAllOnFocus && mTouchFocusSelected;
- if (hasSelection() && !selectAllGotFocus) {
- startSelectionActionMode();
- }
- }
- }
- }
-
@Override
public boolean onTouchEvent(MotionEvent event) {
final int action = event.getActionMasked();
@@ -7394,10 +7336,6 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
&& mText instanceof Spannable && mLayout != null) {
boolean handled = false;
- // Save previous selection, in case this event is used to show the IME.
- int oldSelStart = getSelectionStart();
- int oldSelEnd = getSelectionEnd();
-
final int oldScrollX = mScrollX;
final int oldScrollY = mScrollY;
@@ -7429,22 +7367,21 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
}
if (touchIsFinished) {
- CommitSelectionReceiver csr = null;
- if (getSelectionStart() != oldSelStart || getSelectionEnd() != oldSelEnd ||
- didTouchFocusSelect()) {
- csr = new CommitSelectionReceiver(oldSelStart, oldSelEnd);
- }
-
// Show the IME, except when selecting in read-only text.
if (!mTextIsSelectable) {
final InputMethodManager imm = InputMethodManager.peekInstance();
- handled |= imm != null && imm.showSoftInput(this, 0, csr) && (csr != null);
+ handled |= imm != null && imm.showSoftInput(this, 0);
}
- stopSelectionActionMode();
- boolean selectAllGotFocus = mSelectAllOnFocus && mTouchFocusSelected;
- if (hasInsertionController() && !selectAllGotFocus && mText.length() > 0) {
- getInsertionController().show();
+
+ boolean selectAllGotFocus = mSelectAllOnFocus && didTouchFocusSelect();
+ if (!selectAllGotFocus && hasSelection()) {
+ startSelectionActionMode();
+ } else {
+ stopSelectionActionMode();
+ if (hasInsertionController() && !selectAllGotFocus && mText.length() > 0) {
+ getInsertionController().show();
+ }
}
}
}
@@ -7457,6 +7394,22 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
return superResult;
}
+ @Override
+ public boolean onGenericMotionEvent(MotionEvent event) {
+ if (mMovement != null && mText instanceof Spannable && mLayout != null) {
+ try {
+ if (mMovement.onGenericMotionEvent(this, (Spannable) mText, event)) {
+ return true;
+ }
+ } catch (AbstractMethodError ex) {
+ // onGenericMotionEvent was added to the MovementMethod interface in API 12.
+ // Ignore its absence in case third party applications implemented the
+ // interface directly.
+ }
+ }
+ return super.onGenericMotionEvent(event);
+ }
+
private void prepareCursorControllers() {
boolean windowSupportsHandles = false;
@@ -7545,17 +7498,12 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
TextView tv = mView.get();
- if (tv != null && tv.isFocused()) {
- int st = tv.getSelectionStart();
- int en = tv.getSelectionEnd();
-
- if (st == en && st >= 0 && en >= 0) {
- if (tv.mLayout != null) {
- tv.invalidateCursorPath();
- }
-
- postAtTime(this, SystemClock.uptimeMillis() + BLINK);
+ if (tv != null && tv.shouldBlink()) {
+ if (tv.mLayout != null) {
+ tv.invalidateCursorPath();
}
+
+ postAtTime(this, SystemClock.uptimeMillis() + BLINK);
}
}
@@ -7571,6 +7519,34 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
}
}
+ /**
+ * @return True when the TextView isFocused and has a valid zero-length selection (cursor).
+ */
+ private boolean shouldBlink() {
+ if (!isFocused()) return false;
+
+ final int start = getSelectionStart();
+ if (start < 0) return false;
+
+ final int end = getSelectionEnd();
+ if (end < 0) return false;
+
+ return start == end;
+ }
+
+ private void makeBlink() {
+ if (isCursorVisible()) {
+ if (shouldBlink()) {
+ mShowCursor = SystemClock.uptimeMillis();
+ if (mBlink == null) mBlink = new Blink(this);
+ mBlink.removeCallbacks(mBlink);
+ mBlink.postAtTime(mBlink, mShowCursor + BLINK);
+ }
+ } else {
+ if (mBlink != null) mBlink.removeCallbacks(mBlink);
+ }
+ }
+
@Override
protected float getLeftFadingEdgeStrength() {
if (mCurrentAlpha <= ViewConfiguration.ALPHA_THRESHOLD_INT) return 0.0f;
@@ -8354,21 +8330,6 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
return selectionStarted;
}
- /**
- * Same as {@link #stopSelectionActionMode()}, except that there is no cursor controller
- * fade out animation. Needed since the drawable and their alpha values are shared by all
- * TextViews. Switching from one TextView to another would fade the cursor controllers in the
- * new one otherwise.
- */
- private void terminateSelectionActionMode() {
- stopSelectionActionMode();
-
- // No need to create the controller, nothing to cancel in that case.
- if (mSelectionModifierCursorController != null) {
- mSelectionModifierCursorController.cancelFadeOutAnimation();
- }
- }
-
private void stopSelectionActionMode() {
if (mSelectionActionMode != null) {
// This will hide the mSelectionModifierCursorController
@@ -8692,9 +8653,9 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
}
}
- private class HandleView extends View {
+ private class HandleView extends View implements ViewTreeObserver.OnScrollChangedListener {
private Drawable mDrawable;
- private final PopupWindow mContainer;
+ private final ScrollingPopupWindow mContainer;
private int mPositionX;
private int mPositionY;
private final CursorController mController;
@@ -8702,9 +8663,10 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
private float mTouchToWindowOffsetX;
private float mTouchToWindowOffsetY;
private float mHotspotX;
- private float mHotspotY;
- private int mHeight;
+ // Offsets the hotspot point up, so that cursor is not hidden by the finger when moving up
private float mTouchOffsetY;
+ // Where the touch position should be on the handle to ensure a maximum cursor visibility
+ private float mIdealVerticalOffset;
private int mLastParentX;
private int mLastParentY;
private float mDownPositionX, mDownPositionY;
@@ -8715,7 +8677,8 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
// Touch-up filter: number of previous positions remembered
private static final int HISTORY_SIZE = 5;
- private static final int TOUCH_UP_FILTER_DELAY = 150;
+ private static final int TOUCH_UP_FILTER_DELAY_AFTER = 150;
+ private static final int TOUCH_UP_FILTER_DELAY_BEFORE = 350;
private final long[] mPreviousOffsetsTimes = new long[HISTORY_SIZE];
private final int[] mPreviousOffsets = new int[HISTORY_SIZE];
private int mPreviousOffsetIndex = 0;
@@ -8742,15 +8705,17 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
public void filterOnTouchUp() {
final long now = SystemClock.uptimeMillis();
int i = 0;
- int index = 0;
+ int index = mPreviousOffsetIndex;
final int iMax = Math.min(mNumberPreviousOffsets, HISTORY_SIZE);
- while (i < iMax) {
- index = (mPreviousOffsetIndex - i + HISTORY_SIZE) % HISTORY_SIZE;
- if ((now - mPreviousOffsetsTimes[index]) >= TOUCH_UP_FILTER_DELAY) break;
+ while (i < iMax && (now - mPreviousOffsetsTimes[index]) < TOUCH_UP_FILTER_DELAY_AFTER) {
i++;
+ index = (mPreviousOffsetIndex - i + HISTORY_SIZE) % HISTORY_SIZE;
}
- mController.updateOffset(this, mPreviousOffsets[index]);
+ if (i > 0 && i < iMax &&
+ (now - mPreviousOffsetsTimes[index]) > TOUCH_UP_FILTER_DELAY_BEFORE) {
+ mController.updateOffset(this, mPreviousOffsets[index]);
+ }
}
public static final int LEFT = 0;
@@ -8760,7 +8725,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
public HandleView(CursorController controller, int pos) {
super(TextView.this.mContext);
mController = controller;
- mContainer = new PopupWindow(TextView.this.mContext, null,
+ mContainer = new ScrollingPopupWindow(TextView.this.mContext, null,
com.android.internal.R.attr.textSelectHandleWindowStyle);
mContainer.setSplitTouchEnabled(true);
mContainer.setClippingEnabled(false);
@@ -8772,47 +8737,46 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
public void setOrientation(int pos) {
int handleWidth;
switch (pos) {
- case LEFT: {
- if (mSelectHandleLeft == null) {
- mSelectHandleLeft = mContext.getResources().getDrawable(
- mTextSelectHandleLeftRes);
+ case LEFT: {
+ if (mSelectHandleLeft == null) {
+ mSelectHandleLeft = mContext.getResources().getDrawable(
+ mTextSelectHandleLeftRes);
+ }
+ mDrawable = mSelectHandleLeft;
+ handleWidth = mDrawable.getIntrinsicWidth();
+ mHotspotX = handleWidth * 3.0f / 4.0f;
+ break;
}
- mDrawable = mSelectHandleLeft;
- handleWidth = mDrawable.getIntrinsicWidth();
- mHotspotX = handleWidth * 3.0f / 4.0f;
- break;
- }
- case RIGHT: {
- if (mSelectHandleRight == null) {
- mSelectHandleRight = mContext.getResources().getDrawable(
- mTextSelectHandleRightRes);
+ case RIGHT: {
+ if (mSelectHandleRight == null) {
+ mSelectHandleRight = mContext.getResources().getDrawable(
+ mTextSelectHandleRightRes);
+ }
+ mDrawable = mSelectHandleRight;
+ handleWidth = mDrawable.getIntrinsicWidth();
+ mHotspotX = handleWidth / 4.0f;
+ break;
}
- mDrawable = mSelectHandleRight;
- handleWidth = mDrawable.getIntrinsicWidth();
- mHotspotX = handleWidth / 4.0f;
- break;
- }
- case CENTER:
- default: {
- if (mSelectHandleCenter == null) {
- mSelectHandleCenter = mContext.getResources().getDrawable(
- mTextSelectHandleRes);
+ case CENTER:
+ default: {
+ if (mSelectHandleCenter == null) {
+ mSelectHandleCenter = mContext.getResources().getDrawable(
+ mTextSelectHandleRes);
+ }
+ mDrawable = mSelectHandleCenter;
+ handleWidth = mDrawable.getIntrinsicWidth();
+ mHotspotX = handleWidth / 2.0f;
+ mIsInsertionHandle = true;
+ break;
}
- mDrawable = mSelectHandleCenter;
- handleWidth = mDrawable.getIntrinsicWidth();
- mHotspotX = handleWidth / 2.0f;
- mIsInsertionHandle = true;
- break;
- }
}
final int handleHeight = mDrawable.getIntrinsicHeight();
- mTouchOffsetY = -handleHeight * 0.3f;
- mHotspotY = 0;
- mHeight = handleHeight;
+ mTouchOffsetY = -0.3f * handleHeight;
+ mIdealVerticalOffset = 0.7f * handleHeight;
invalidate();
}
@@ -8828,24 +8792,20 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
return;
}
mContainer.setContentView(this);
- final int[] coords = mTempCoords;
- TextView.this.getLocationInWindow(coords);
- mContainerPositionX = coords[0] + mPositionX;
- mContainerPositionY = coords[1] + mPositionY;
- mContainer.showAtLocation(TextView.this, 0, mContainerPositionX, mContainerPositionY);
+ mContainerPositionX = mPositionX;
+ mContainerPositionY = mPositionY - TextView.this.getHeight();
+ mContainer.showAsDropDown(TextView.this, mContainerPositionX, mContainerPositionY);
// Hide paste view when handle is moved on screen.
- if (mPastePopupWindow != null) {
- mPastePopupWindow.hide();
- }
+ hidePastePopupWindow();
}
public void hide() {
mIsDragging = false;
mContainer.dismiss();
- if (mPastePopupWindow != null) {
- mPastePopupWindow.hide();
- }
+ hidePastePopupWindow();
+ ViewTreeObserver vto = TextView.this.getViewTreeObserver();
+ vto.removeOnScrollChangedListener(this);
}
public boolean isShowing() {
@@ -8868,19 +8828,15 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
final int compoundPaddingRight = getCompoundPaddingRight();
final TextView hostView = TextView.this;
- final int left = 0;
- final int right = hostView.getWidth();
- final int top = 0;
- final int bottom = hostView.getHeight();
if (mTempRect == null) {
mTempRect = new Rect();
}
final Rect clip = mTempRect;
- clip.left = left + compoundPaddingLeft;
- clip.top = top + extendedPaddingTop;
- clip.right = right - compoundPaddingRight;
- clip.bottom = bottom - extendedPaddingBottom;
+ clip.left = compoundPaddingLeft;
+ clip.top = extendedPaddingTop;
+ clip.right = hostView.getWidth() - compoundPaddingRight;
+ clip.bottom = hostView.getHeight() - extendedPaddingBottom;
final ViewParent parent = hostView.getParent();
if (parent == null || !parent.getChildVisibleRect(hostView, clip, null)) {
@@ -8890,9 +8846,10 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
final int[] coords = mTempCoords;
hostView.getLocationInWindow(coords);
final int posX = coords[0] + mPositionX + (int) mHotspotX;
- final int posY = coords[1] + mPositionY + (int) mHotspotY;
+ final int posY = coords[1] + mPositionY;
- return posX >= clip.left && posX <= clip.right &&
+ // Offset by 1 to take into account 0.5 and int rounding around getPrimaryHorizontal.
+ return posX >= clip.left - 1 && posX <= clip.right + 1 &&
posY >= clip.top && posY <= clip.bottom;
}
@@ -8902,23 +8859,19 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
if (isPositionVisible()) {
int[] coords = null;
if (mContainer.isShowing()) {
- coords = mTempCoords;
- TextView.this.getLocationInWindow(coords);
- final int containerPositionX = coords[0] + mPositionX;
- final int containerPositionY = coords[1] + mPositionY;
+ final int containerPositionX = mPositionX;
+ final int containerPositionY = mPositionY - TextView.this.getHeight();
if (containerPositionX != mContainerPositionX ||
containerPositionY != mContainerPositionY) {
mContainerPositionX = containerPositionX;
mContainerPositionY = containerPositionY;
- mContainer.update(mContainerPositionX, mContainerPositionY,
+ mContainer.update(TextView.this, mContainerPositionX, mContainerPositionY,
mRight - mLeft, mBottom - mTop);
// Hide paste popup window as soon as a scroll occurs.
- if (mPastePopupWindow != null) {
- mPastePopupWindow.hide();
- }
+ hidePastePopupWindow();
}
} else {
show();
@@ -8936,9 +8889,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
mLastParentY = coords[1];
}
// Hide paste popup window as soon as the handle is dragged.
- if (mPastePopupWindow != null) {
- mPastePopupWindow.hide();
- }
+ hidePastePopupWindow();
}
} else {
hide();
@@ -8960,6 +8911,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
mDownPositionY = ev.getRawY();
mTouchToWindowOffsetX = mDownPositionX - mPositionX;
mTouchToWindowOffsetY = mDownPositionY - mPositionY;
+
final int[] coords = mTempCoords;
TextView.this.getLocationInWindow(coords);
mLastParentX = coords[0];
@@ -8974,8 +8926,22 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
case MotionEvent.ACTION_MOVE: {
final float rawX = ev.getRawX();
final float rawY = ev.getRawY();
+
+ // Vertical hysteresis: vertical down movement tends to snap to ideal offset
+ final float previousVerticalOffset = mTouchToWindowOffsetY - mLastParentY;
+ final float currentVerticalOffset = rawY - mPositionY - mLastParentY;
+ float newVerticalOffset;
+ if (previousVerticalOffset < mIdealVerticalOffset) {
+ newVerticalOffset = Math.min(currentVerticalOffset, mIdealVerticalOffset);
+ newVerticalOffset = Math.max(newVerticalOffset, previousVerticalOffset);
+ } else {
+ newVerticalOffset = Math.max(currentVerticalOffset, mIdealVerticalOffset);
+ newVerticalOffset = Math.min(newVerticalOffset, previousVerticalOffset);
+ }
+ mTouchToWindowOffsetY = newVerticalOffset + mLastParentY;
+
final float newPosX = rawX - mTouchToWindowOffsetX + mHotspotX;
- final float newPosY = rawY - mTouchToWindowOffsetY + mHotspotY + mTouchOffsetY;
+ final float newPosY = rawY - mTouchToWindowOffsetY + mTouchOffsetY;
mController.updatePosition(this, Math.round(newPosX), Math.round(newPosY));
break;
@@ -8985,11 +8951,16 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
if (mIsInsertionHandle) {
long delay = SystemClock.uptimeMillis() - mTouchTimer;
if (delay < ViewConfiguration.getTapTimeout()) {
- if (mPastePopupWindow != null && mPastePopupWindow.isShowing()) {
- // Tapping on the handle dismisses the displayed paste view,
- mPastePopupWindow.hide();
- } else {
- ((InsertionPointCursorController) mController).show(0);
+ final float deltaX = mDownPositionX - ev.getRawX();
+ final float deltaY = mDownPositionY - ev.getRawY();
+ final float distanceSquared = deltaX * deltaX + deltaY * deltaY;
+ if (distanceSquared < mSquaredTouchSlopDistance) {
+ if (mPastePopupWindow != null && mPastePopupWindow.isShowing()) {
+ // Tapping on the handle dismisses the displayed paste view,
+ mPastePopupWindow.hide();
+ } else {
+ ((InsertionPointCursorController) mController).show(0);
+ }
}
}
}
@@ -9008,18 +8979,17 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
return mIsDragging;
}
- void positionAtCursor(final int offset, boolean bottom) {
+ void positionAtCursor(final int offset) {
addPositionToTouchUpFilter(offset);
final int width = mDrawable.getIntrinsicWidth();
final int height = mDrawable.getIntrinsicHeight();
final int line = mLayout.getLineForOffset(offset);
- final int lineTop = mLayout.getLineTop(line);
final int lineBottom = mLayout.getLineBottom(line);
final Rect bounds = sCursorControllerTempRect;
bounds.left = (int) (mLayout.getPrimaryHorizontal(offset) - 0.5f - mHotspotX) +
TextView.this.mScrollX;
- bounds.top = (bottom ? lineBottom : lineTop - mHeight) + TextView.this.mScrollY;
+ bounds.top = lineBottom + TextView.this.mScrollY;
bounds.right = bounds.left + width;
bounds.bottom = bounds.top + height;
@@ -9037,10 +9007,60 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
mPastePopupWindow.show();
}
}
+
+ void hidePastePopupWindow() {
+ if (mPastePopupWindow != null) {
+ mPastePopupWindow.hide();
+ }
+ }
+
+ /**
+ * A popup window, attached to a view, and that listens to scroll events in its anchors'
+ * view hierarchy, so that it is automatically moved on such events.
+ */
+ private class ScrollingPopupWindow extends PopupWindow {
+
+ private int[] mDrawingLocations = new int[2];
+
+ public ScrollingPopupWindow(Context context, AttributeSet attrs, int defStyle) {
+ super(context, attrs, defStyle);
+ }
+
+ @Override
+ public boolean findDropDownPosition(View anchor, WindowManager.LayoutParams p,
+ int xoff, int yoff) {
+ anchor.getLocationInWindow(mDrawingLocations);
+ p.x = mDrawingLocations[0] + xoff;
+ p.y = mDrawingLocations[1] + anchor.getHeight() + yoff;
+
+ // Hide paste popup as soon as the view is scrolled.
+ hidePastePopupWindow();
+
+ if (!isPositionVisible()) {
+ dismiss();
+ onHandleBecomeInvisible();
+ }
+
+ return false;
+ }
+ }
+
+ public void onScrollChanged() {
+ if (isPositionVisible()) {
+ show();
+ ViewTreeObserver vto = TextView.this.getViewTreeObserver();
+ vto.removeOnScrollChangedListener(this);
+ }
+ }
+
+ public void onHandleBecomeInvisible() {
+ ViewTreeObserver vto = TextView.this.getViewTreeObserver();
+ vto.addOnScrollChangedListener(this);
+ }
}
private class InsertionPointCursorController implements CursorController {
- private static final int DELAY_BEFORE_FADE_OUT = 4100;
+ private static final int DELAY_BEFORE_FADE_OUT = 4000;
private static final int DELAY_BEFORE_PASTE = 2000;
private static final int RECENT_CUT_COPY_DURATION = 15 * 1000;
@@ -9056,7 +9076,6 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
public void show(int delayBeforePaste) {
updatePosition();
hideDelayed();
- getHandle().show();
removePastePopupCallback();
final long durationSinceCutOrCopy = SystemClock.uptimeMillis() - sLastCutOrCopyTime;
if (durationSinceCutOrCopy < RECENT_CUT_COPY_DURATION) {
@@ -9112,10 +9131,10 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
public void updatePosition(HandleView handle, int x, int y) {
final int previousOffset = getSelectionStart();
- int offset = getHysteresisOffset(x, y, previousOffset);
+ final int newOffset = getOffset(x, y);
- if (offset != previousOffset) {
- updateOffset(handle, offset);
+ if (newOffset != previousOffset) {
+ updateOffset(handle, newOffset);
removePastePopupCallback();
}
hideDelayed();
@@ -9136,7 +9155,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
return;
}
- getHandle().positionAtCursor(offset, true);
+ getHandle().positionAtCursor(offset);
}
public int getCurrentOffset(HandleView handle) {
@@ -9212,16 +9231,11 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
return mIsShowing;
}
- public void cancelFadeOutAnimation() {
- hide();
- }
-
public void updatePosition(HandleView handle, int x, int y) {
int selectionStart = getSelectionStart();
int selectionEnd = getSelectionEnd();
- final int previousOffset = handle == mStartHandle ? selectionStart : selectionEnd;
- int offset = getHysteresisOffset(x, y, previousOffset);
+ int offset = getOffset(x, y);
// Handle the case where start and end are swapped, making sure start <= end
if (handle == mStartHandle) {
@@ -9280,8 +9294,8 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
}
// The handles have been created since the controller isShowing().
- mStartHandle.positionAtCursor(selectionStart, true);
- mEndHandle.positionAtCursor(selectionEnd, true);
+ mStartHandle.positionAtCursor(selectionStart);
+ mEndHandle.positionAtCursor(selectionEnd);
}
public int getCurrentOffset(HandleView handle) {
@@ -9411,26 +9425,6 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
return offset;
}
- int getHysteresisOffset(int x, int y, int previousOffset) {
- final Layout layout = getLayout();
- if (layout == null) return -1;
-
- int line = getLineAtCoordinate(y);
- final int previousLine = layout.getLineForOffset(previousOffset);
- final int previousLineTop = layout.getLineTop(previousLine);
- final int previousLineBottom = layout.getLineBottom(previousLine);
- final int hysteresisThreshold = (previousLineBottom - previousLineTop) / 8;
-
- // If new line is just before or after previous line and y position is less than
- // hysteresisThreshold away from previous line, keep cursor on previous line.
- if (((line == previousLine + 1) && ((y - previousLineBottom) < hysteresisThreshold)) ||
- ((line == previousLine - 1) && ((previousLineTop - y) < hysteresisThreshold))) {
- line = previousLine;
- }
-
- return getOffsetAtCoordinate(line, x);
- }
-
private int convertToLocalHorizontalCoordinate(int x) {
x -= getTotalPaddingLeft();
// Clamp the position to inside of the view.
@@ -9576,9 +9570,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
mInsertionPointCursorController = new InsertionPointCursorController();
final ViewTreeObserver observer = getViewTreeObserver();
- if (observer != null) {
- observer.addOnTouchModeChangeListener(mInsertionPointCursorController);
- }
+ observer.addOnTouchModeChangeListener(mInsertionPointCursorController);
}
return mInsertionPointCursorController;
@@ -9593,9 +9585,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
mSelectionModifierCursorController = new SelectionModifierCursorController();
final ViewTreeObserver observer = getViewTreeObserver();
- if (observer != null) {
- observer.addOnTouchModeChangeListener(mSelectionModifierCursorController);
- }
+ observer.addOnTouchModeChangeListener(mSelectionModifierCursorController);
}
return mSelectionModifierCursorController;
diff --git a/core/java/com/android/internal/app/ResolverActivity.java b/core/java/com/android/internal/app/ResolverActivity.java
index 841de06..fb2a72b 100644
--- a/core/java/com/android/internal/app/ResolverActivity.java
+++ b/core/java/com/android/internal/app/ResolverActivity.java
@@ -68,7 +68,7 @@ public class ResolverActivity extends AlertActivity implements
protected void onCreate(Bundle savedInstanceState, Intent intent,
CharSequence title, Intent[] initialIntents, List<ResolveInfo> rList,
- boolean alwaysUseOption) {
+ boolean alwaysUseOption, boolean alwaysChoose) {
super.onCreate(savedInstanceState);
mPm = getPackageManager();
intent.setComponent(null);
@@ -90,9 +90,10 @@ public class ResolverActivity extends AlertActivity implements
mClearDefaultHint.setVisibility(View.GONE);
}
mAdapter = new ResolveListAdapter(this, intent, initialIntents, rList);
- if (mAdapter.getCount() > 1) {
+ int count = mAdapter.getCount();
+ if (count > 1 || (count == 1 && alwaysChoose)) {
ap.mAdapter = mAdapter;
- } else if (mAdapter.getCount() == 1) {
+ } else if (count == 1) {
startActivity(mAdapter.intentForPosition(0));
finish();
return;
@@ -103,11 +104,22 @@ public class ResolverActivity extends AlertActivity implements
setupAlert();
}
+ protected void onCreate(Bundle savedInstanceState, Intent intent,
+ CharSequence title, Intent[] initialIntents, List<ResolveInfo> rList,
+ boolean alwaysUseOption) {
+ onCreate(savedInstanceState, intent, title, initialIntents, rList, alwaysUseOption, false);
+ }
+
public void onClick(DialogInterface dialog, int which) {
ResolveInfo ri = mAdapter.resolveInfoForPosition(which);
Intent intent = mAdapter.intentForPosition(which);
+ boolean alwaysCheck = (mAlwaysCheck != null && mAlwaysCheck.isChecked());
+ onIntentSelected(ri, intent, alwaysCheck);
+ finish();
+ }
- if ((mAlwaysCheck != null) && mAlwaysCheck.isChecked()) {
+ protected void onIntentSelected(ResolveInfo ri, Intent intent, boolean alwaysCheck) {
+ if (alwaysCheck) {
// Build a reasonable intent filter, based on what matched.
IntentFilter filter = new IntentFilter();
@@ -190,7 +202,6 @@ public class ResolverActivity extends AlertActivity implements
if (intent != null) {
startActivity(intent);
}
- finish();
}
private final class DisplayResolveInfo {
diff --git a/core/java/com/android/internal/widget/IRemoteViewsFactory.aidl b/core/java/com/android/internal/widget/IRemoteViewsFactory.aidl
index 60eca00..5857acb 100644
--- a/core/java/com/android/internal/widget/IRemoteViewsFactory.aidl
+++ b/core/java/com/android/internal/widget/IRemoteViewsFactory.aidl
@@ -16,11 +16,13 @@
package com.android.internal.widget;
+import android.content.Intent;
import android.widget.RemoteViews;
/** {@hide} */
interface IRemoteViewsFactory {
void onDataSetChanged();
+ void onDestroy(in Intent intent);
int getCount();
RemoteViews getViewAt(int position);
RemoteViews getLoadingView();
diff --git a/core/java/com/android/internal/widget/PointerLocationView.java b/core/java/com/android/internal/widget/PointerLocationView.java
index c72d0e8..5ac903d 100644
--- a/core/java/com/android/internal/widget/PointerLocationView.java
+++ b/core/java/com/android/internal/widget/PointerLocationView.java
@@ -318,10 +318,56 @@ public class PointerLocationView extends View {
}
}
- private void logPointerCoords(MotionEvent.PointerCoords coords, int id) {
+ private void logPointerCoords(int action, int index, MotionEvent.PointerCoords coords, int id) {
+ final String prefix;
+ switch (action & MotionEvent.ACTION_MASK) {
+ case MotionEvent.ACTION_DOWN:
+ prefix = "DOWN";
+ break;
+ case MotionEvent.ACTION_UP:
+ prefix = "UP";
+ break;
+ case MotionEvent.ACTION_MOVE:
+ prefix = "MOVE";
+ break;
+ case MotionEvent.ACTION_CANCEL:
+ prefix = "CANCEL";
+ break;
+ case MotionEvent.ACTION_OUTSIDE:
+ prefix = "OUTSIDE";
+ break;
+ case MotionEvent.ACTION_POINTER_DOWN:
+ if (index == ((action & MotionEvent.ACTION_POINTER_INDEX_MASK)
+ >> MotionEvent.ACTION_POINTER_INDEX_SHIFT)) {
+ prefix = "DOWN";
+ } else {
+ prefix = "MOVE";
+ }
+ break;
+ case MotionEvent.ACTION_POINTER_UP:
+ if (index == ((action & MotionEvent.ACTION_POINTER_INDEX_MASK)
+ >> MotionEvent.ACTION_POINTER_INDEX_SHIFT)) {
+ prefix = "UP";
+ } else {
+ prefix = "MOVE";
+ }
+ break;
+ case MotionEvent.ACTION_HOVER_MOVE:
+ prefix = "HOVER MOVE";
+ break;
+ case MotionEvent.ACTION_SCROLL:
+ prefix = "SCROLL";
+ break;
+ default:
+ prefix = Integer.toString(action);
+ break;
+ }
+
Log.i(TAG, mText.clear()
.append("Pointer ").append(id + 1)
- .append(": (").append(coords.x, 3).append(", ").append(coords.y, 3)
+ .append(": ")
+ .append(prefix)
+ .append(" (").append(coords.x, 3).append(", ").append(coords.y, 3)
.append(") Pressure=").append(coords.pressure, 3)
.append(" Size=").append(coords.size, 3)
.append(" TouchMajor=").append(coords.touchMajor, 3)
@@ -335,7 +381,7 @@ public class PointerLocationView extends View {
.toString());
}
- public void addTouchEvent(MotionEvent event) {
+ public void addPointerEvent(MotionEvent event) {
synchronized (mPointers) {
int action = event.getAction();
@@ -363,10 +409,16 @@ public class PointerLocationView extends View {
ps.mCurDown = false;
}
mCurDown = true;
+ mCurNumPointers = 0;
mMaxNumPointers = 0;
mVelocity.clear();
}
-
+
+ mCurNumPointers += 1;
+ if (mMaxNumPointers < mCurNumPointers) {
+ mMaxNumPointers = mCurNumPointers;
+ }
+
final int id = event.getPointerId(index);
while (NP <= id) {
PointerState ps = new PointerState();
@@ -375,49 +427,41 @@ public class PointerLocationView extends View {
}
if (mActivePointerId < 0 ||
- ! mPointers.get(mActivePointerId).mCurDown) {
+ !mPointers.get(mActivePointerId).mCurDown) {
mActivePointerId = id;
}
final PointerState ps = mPointers.get(id);
ps.mCurDown = true;
- if (mPrintCoords) {
- Log.i(TAG, mText.clear().append("Pointer ")
- .append(id + 1).append(": DOWN").toString());
- }
}
-
- final int NI = event.getPointerCount();
- final boolean hover = (action == MotionEvent.ACTION_HOVER_MOVE);
- mCurDown = action != MotionEvent.ACTION_UP
- && action != MotionEvent.ACTION_CANCEL
- && !hover;
- mCurNumPointers = mCurDown ? NI : 0;
- if (mMaxNumPointers < mCurNumPointers) {
- mMaxNumPointers = mCurNumPointers;
- }
+ final int NI = event.getPointerCount();
mVelocity.addMovement(event);
mVelocity.computeCurrentVelocity(1);
-
- for (int i=0; i<NI; i++) {
- final int id = event.getPointerId(i);
- final PointerState ps = hover ? null : mPointers.get(id);
- final PointerCoords coords = ps != null ? ps.mCoords : mHoverCoords;
- final int N = event.getHistorySize();
- for (int j=0; j<N; j++) {
- event.getHistoricalPointerCoords(i, j, coords);
+
+ final int N = event.getHistorySize();
+ for (int historyPos = 0; historyPos < N; historyPos++) {
+ for (int i = 0; i < NI; i++) {
+ final int id = event.getPointerId(i);
+ final PointerState ps = mCurDown ? mPointers.get(id) : null;
+ final PointerCoords coords = ps != null ? ps.mCoords : mHoverCoords;
+ event.getHistoricalPointerCoords(i, historyPos, coords);
if (mPrintCoords) {
- logPointerCoords(coords, id);
+ logPointerCoords(action, i, coords, id);
}
if (ps != null) {
- ps.addTrace(event.getHistoricalX(i, j), event.getHistoricalY(i, j));
+ ps.addTrace(coords.x, coords.y);
}
}
+ }
+ for (int i = 0; i < NI; i++) {
+ final int id = event.getPointerId(i);
+ final PointerState ps = mCurDown ? mPointers.get(id) : null;
+ final PointerCoords coords = ps != null ? ps.mCoords : mHoverCoords;
event.getPointerCoords(i, coords);
if (mPrintCoords) {
- logPointerCoords(coords, id);
+ logPointerCoords(action, i, coords, id);
}
if (ps != null) {
ps.addTrace(coords.x, coords.y);
@@ -425,7 +469,7 @@ public class PointerLocationView extends View {
ps.mYVelocity = mVelocity.getYVelocity(id);
}
}
-
+
if (action == MotionEvent.ACTION_UP
|| action == MotionEvent.ACTION_CANCEL
|| (action & MotionEvent.ACTION_MASK) == MotionEvent.ACTION_POINTER_UP) {
@@ -435,15 +479,13 @@ public class PointerLocationView extends View {
final int id = event.getPointerId(index);
final PointerState ps = mPointers.get(id);
ps.mCurDown = false;
- if (mPrintCoords) {
- Log.i(TAG, mText.clear().append("Pointer ")
- .append(id + 1).append(": UP").toString());
- }
if (action == MotionEvent.ACTION_UP
|| action == MotionEvent.ACTION_CANCEL) {
mCurDown = false;
+ mCurNumPointers = 0;
} else {
+ mCurNumPointers -= 1;
if (mActivePointerId == id) {
mActivePointerId = event.getPointerId(index == 0 ? 1 : 0);
}
@@ -462,11 +504,20 @@ public class PointerLocationView extends View {
@Override
public boolean onTouchEvent(MotionEvent event) {
- addTouchEvent(event);
+ addPointerEvent(event);
return true;
}
@Override
+ public boolean onGenericMotionEvent(MotionEvent event) {
+ if ((event.getSource() & InputDevice.SOURCE_CLASS_POINTER) != 0) {
+ addPointerEvent(event);
+ return true;
+ }
+ return super.onGenericMotionEvent(event);
+ }
+
+ @Override
public boolean onTrackballEvent(MotionEvent event) {
Log.i(TAG, "Trackball: " + event);
return super.onTrackballEvent(event);
diff --git a/core/jni/Android.mk b/core/jni/Android.mk
index 41baca2..2ed938a 100644
--- a/core/jni/Android.mk
+++ b/core/jni/Android.mk
@@ -183,7 +183,6 @@ LOCAL_SHARED_LIBRARIES := \
libgui \
libsurfaceflinger_client \
libcamera_client \
- libskiagl \
libskia \
libsqlite \
libdvm \
diff --git a/core/jni/android/graphics/Bitmap.cpp b/core/jni/android/graphics/Bitmap.cpp
index 1d961ec..8064836 100644
--- a/core/jni/android/graphics/Bitmap.cpp
+++ b/core/jni/android/graphics/Bitmap.cpp
@@ -378,12 +378,12 @@ static jobject Bitmap_createFromParcel(JNIEnv* env, jobject, jobject parcel) {
jbyteArray buffer = GraphicsJNI::allocateJavaPixelRef(env, bitmap, ctable);
if (NULL == buffer) {
- ctable->safeUnref();
+ SkSafeUnref(ctable);
delete bitmap;
return NULL;
}
- ctable->safeUnref();
+ SkSafeUnref(ctable);
size_t size = bitmap->getSize();
bitmap->lockPixels();
@@ -447,6 +447,13 @@ static jobject Bitmap_extractAlpha(JNIEnv* env, jobject clazz,
JavaPixelAllocator allocator(env);
src->extractAlpha(dst, paint, &allocator, &offset);
+ // If Skia can't allocate pixels for destination bitmap, it resets
+ // it, that is set its pixels buffer to NULL, and zero width and height.
+ if (dst->getPixels() == NULL && src->getPixels() != NULL) {
+ delete dst;
+ doThrowOOME(env, "failed to allocate pixels for alpha");
+ return NULL;
+ }
if (offsetXY != 0 && env->GetArrayLength(offsetXY) >= 2) {
int* array = env->GetIntArrayElements(offsetXY, NULL);
array[0] = offset.fX;
@@ -651,4 +658,3 @@ int register_android_graphics_Bitmap(JNIEnv* env)
return android::AndroidRuntime::registerNativeMethods(env, kClassPathName,
gBitmapMethods, SK_ARRAY_COUNT(gBitmapMethods));
}
-
diff --git a/core/jni/android/graphics/Camera.cpp b/core/jni/android/graphics/Camera.cpp
index 980003e..0d715fd 100644
--- a/core/jni/android/graphics/Camera.cpp
+++ b/core/jni/android/graphics/Camera.cpp
@@ -45,6 +45,18 @@ static void Camera_rotateZ(JNIEnv* env, jobject obj, float degrees) {
v->rotateZ(SkFloatToScalar(degrees));
}
+static void Camera_rotate(JNIEnv* env, jobject obj, jfloat x, jfloat y, jfloat z) {
+ Sk3DView* v = (Sk3DView*)env->GetIntField(obj, gNativeInstanceFieldID);
+ v->rotateX(SkFloatToScalar(x));
+ v->rotateY(SkFloatToScalar(y));
+ v->rotateZ(SkFloatToScalar(z));
+}
+
+static void Camera_setLocation(JNIEnv* env, jobject obj, jfloat x, jfloat y, jfloat z) {
+ Sk3DView* v = (Sk3DView*)env->GetIntField(obj, gNativeInstanceFieldID);
+ v->setCameraLocation(SkFloatToScalar(x), SkFloatToScalar(y), SkFloatToScalar(z));
+}
+
static void Camera_getMatrix(JNIEnv* env, jobject obj, int native_matrix) {
Sk3DView* v = (Sk3DView*)env->GetIntField(obj, gNativeInstanceFieldID);
v->getMatrix((SkMatrix*)native_matrix);
@@ -79,6 +91,8 @@ static JNINativeMethod gCameraMethods[] = {
{ "rotateX", "(F)V", (void*)Camera_rotateX },
{ "rotateY", "(F)V", (void*)Camera_rotateY },
{ "rotateZ", "(F)V", (void*)Camera_rotateZ },
+ { "rotate", "(FFF)V", (void*)Camera_rotate },
+ { "setLocation", "(FFF)V", (void*)Camera_setLocation },
{ "nativeGetMatrix", "(I)V", (void*)Camera_getMatrix },
{ "nativeApplyToCanvas", "(I)V", (void*)Camera_applyToCanvas },
{ "dotWithNormal", "(FFF)F", (void*)Camera_dotWithNormal }
diff --git a/core/jni/android/graphics/Canvas.cpp b/core/jni/android/graphics/Canvas.cpp
index 8944d47..0cdb357 100644
--- a/core/jni/android/graphics/Canvas.cpp
+++ b/core/jni/android/graphics/Canvas.cpp
@@ -673,7 +673,7 @@ public:
}
SkShader* shader = SkShader::CreateBitmapShader(*bitmap,
SkShader::kClamp_TileMode, SkShader::kClamp_TileMode);
- tmpPaint.setShader(shader)->safeUnref();
+ SkSafeUnref(tmpPaint.setShader(shader));
canvas->drawVertices(SkCanvas::kTriangles_VertexMode, ptCount, verts,
texs, (const SkColor*)colorA.ptr(), NULL, indices,
diff --git a/core/jni/android/graphics/ColorFilter.cpp b/core/jni/android/graphics/ColorFilter.cpp
index e2a959d..dd1177b 100644
--- a/core/jni/android/graphics/ColorFilter.cpp
+++ b/core/jni/android/graphics/ColorFilter.cpp
@@ -33,7 +33,7 @@ using namespace uirenderer;
class SkColorFilterGlue {
public:
static void finalizer(JNIEnv* env, jobject clazz, SkColorFilter* obj, SkiaColorFilter* f) {
- obj->safeUnref();
+ SkSafeUnref(obj);
// f == NULL when not !USE_OPENGL_RENDERER, so no need to delete outside the ifdef
#ifdef USE_OPENGL_RENDERER
if (android::uirenderer::Caches::hasInstance()) {
diff --git a/core/jni/android/graphics/DrawFilter.cpp b/core/jni/android/graphics/DrawFilter.cpp
index 496e712..2f9fe7e 100644
--- a/core/jni/android/graphics/DrawFilter.cpp
+++ b/core/jni/android/graphics/DrawFilter.cpp
@@ -34,7 +34,7 @@ class SkDrawFilterGlue {
public:
static void finalizer(JNIEnv* env, jobject clazz, SkDrawFilter* obj) {
- obj->safeUnref();
+ SkSafeUnref(obj);
}
static SkDrawFilter* CreatePaintFlagsDF(JNIEnv* env, jobject clazz,
diff --git a/core/jni/android/graphics/MaskFilter.cpp b/core/jni/android/graphics/MaskFilter.cpp
index 455449e..d3f9b78 100644
--- a/core/jni/android/graphics/MaskFilter.cpp
+++ b/core/jni/android/graphics/MaskFilter.cpp
@@ -14,7 +14,7 @@ static void ThrowIAE_IfNull(JNIEnv* env, void* ptr) {
class SkMaskFilterGlue {
public:
static void destructor(JNIEnv* env, jobject, SkMaskFilter* filter) {
- filter->safeUnref();
+ SkSafeUnref(filter);
}
static SkMaskFilter* createBlur(JNIEnv* env, jobject, float radius, int blurStyle) {
diff --git a/core/jni/android/graphics/PathEffect.cpp b/core/jni/android/graphics/PathEffect.cpp
index 0ecb004..cfa9ce4 100644
--- a/core/jni/android/graphics/PathEffect.cpp
+++ b/core/jni/android/graphics/PathEffect.cpp
@@ -12,7 +12,7 @@ class SkPathEffectGlue {
public:
static void destructor(JNIEnv* env, jobject, SkPathEffect* effect) {
- effect->safeUnref();
+ SkSafeUnref(effect);
}
static SkPathEffect* Compose_constructor(JNIEnv* env, jobject,
diff --git a/core/jni/android/graphics/Rasterizer.cpp b/core/jni/android/graphics/Rasterizer.cpp
index db70b57..4e1b36a 100644
--- a/core/jni/android/graphics/Rasterizer.cpp
+++ b/core/jni/android/graphics/Rasterizer.cpp
@@ -32,7 +32,7 @@ class SkRasterizerGlue {
public:
static void finalizer(JNIEnv* env, jobject clazz, SkRasterizer* obj) {
- obj->safeUnref();
+ SkSafeUnref(obj);
}
};
diff --git a/core/jni/android/graphics/Shader.cpp b/core/jni/android/graphics/Shader.cpp
index 3efc41d..0ea8225 100644
--- a/core/jni/android/graphics/Shader.cpp
+++ b/core/jni/android/graphics/Shader.cpp
@@ -53,7 +53,7 @@ static int Color_HSVToColor(JNIEnv* env, jobject, int alpha, jfloatArray hsvArra
static void Shader_destructor(JNIEnv* env, jobject o, SkShader* shader, SkiaShader* skiaShader)
{
- shader->safeUnref();
+ SkSafeUnref(shader);
// skiaShader == NULL when not !USE_OPENGL_RENDERER, so no need to delete it outside the ifdef
#ifdef USE_OPENGL_RENDERER
if (android::uirenderer::Caches::hasInstance()) {
diff --git a/core/jni/android/graphics/TextLayout.cpp b/core/jni/android/graphics/TextLayout.cpp
index 147e1fa..e957635 100644
--- a/core/jni/android/graphics/TextLayout.cpp
+++ b/core/jni/android/graphics/TextLayout.cpp
@@ -23,6 +23,8 @@
#include "unicode/ushape.h"
#include <utils/Log.h>
+// Log debug messages from RTL related allocations
+#define DEBUG_RTL_ALLOCATIONS 0
namespace android {
// Returns true if we might need layout. If bidiFlags force LTR, assume no layout, if
@@ -38,7 +40,7 @@ bool TextLayout::needsLayout(const jchar* text, jint len, jint bidiFlags) {
return true;
}
for (int i = 0; i < len; ++i) {
- if (text[i] >= 0x0590) {
+ if (text[i] >= UNICODE_FIRST_RTL_CHAR) {
return true;
}
}
@@ -59,7 +61,12 @@ bool TextLayout::needsLayout(const jchar* text, jint len, jint bidiFlags) {
*/
int TextLayout::shapeRtlText(const jchar* context, jsize start, jsize count, jsize contextCount,
jchar* shaped, UErrorCode &status) {
- jchar buffer[contextCount];
+ SkAutoSTMalloc<CHAR_BUFFER_SIZE, jchar> tempBuffer(contextCount);
+ jchar* buffer = tempBuffer.get();
+
+#if DEBUG_RTL_ALLOCATIONS
+ LOGD("TextLayout::shapeRtlText - allocated buffer with size: %d", contextCount);
+#endif
// Use fixed length since we need to keep start and count valid
u_shapeArabic(context, contextCount, buffer, contextCount,
@@ -68,10 +75,10 @@ int TextLayout::shapeRtlText(const jchar* context, jsize start, jsize count, jsi
U_SHAPE_X_LAMALEF_SUB_ALTERNATE, &status);
if (U_SUCCESS(status)) {
- // trim out 0xffff following ligatures, if any
+ // trim out UNICODE_NOT_A_CHAR following ligatures, if any
int end = 0;
for (int i = start, e = start + count; i < e; ++i) {
- if (buffer[i] != 0xffff) {
+ if (buffer[i] != UNICODE_NOT_A_CHAR) {
buffer[end++] = buffer[i];
}
}
@@ -83,7 +90,6 @@ int TextLayout::shapeRtlText(const jchar* context, jsize start, jsize count, jsi
return count;
}
}
-
return -1;
}
@@ -160,6 +166,11 @@ bool TextLayout::prepareText(SkPaint *paint, const jchar* text, jsize len, jint
if (!buffer) {
return false;
}
+
+#if DEBUG_RTL_ALLOCATIONS
+ LOGD("TextLayout::prepareText - allocated buffer with size: %d", len);
+#endif
+
UErrorCode status = U_ZERO_ERROR;
len = layoutLine(text, len, bidiFlags, dir, buffer, status); // might change len, dir
if (!U_SUCCESS(status)) {
@@ -228,7 +239,7 @@ bool TextLayout::prepareRtlTextRun(const jchar* context, jsize start, jsize& cou
if (U_SUCCESS(status)) {
return true;
} else {
- LOG(LOG_WARN, "LAYOUT", "drawTextRun error %d\n", status);
+ LOGW("drawTextRun error %d\n", status);
}
return false;
}
@@ -242,7 +253,7 @@ void TextLayout::drawTextRun(SkPaint* paint, const jchar* chars,
uint8_t rtl = dirFlags & 0x1;
if (rtl) {
- SkAutoSTMalloc<80, jchar> buffer(contextCount);
+ SkAutoSTMalloc<CHAR_BUFFER_SIZE, jchar> buffer(contextCount);
if (prepareRtlTextRun(chars, start, count, contextCount, buffer.get())) {
canvas->drawText(buffer.get(), count << 1, x_, y_, *paint);
}
@@ -254,11 +265,17 @@ void TextLayout::drawTextRun(SkPaint* paint, const jchar* chars,
void TextLayout::getTextRunAdvances(SkPaint *paint, const jchar *chars, jint start,
jint count, jint contextCount, jint dirFlags,
jfloat *resultAdvances, jfloat &resultTotalAdvance) {
- jchar buffer[contextCount];
-
- SkScalar* scalarArray = (SkScalar *)resultAdvances;
resultTotalAdvance = 0;
+ SkAutoSTMalloc<CHAR_BUFFER_SIZE, jchar> tempBuffer(contextCount);
+ jchar* buffer = tempBuffer.get();
+
+#if DEBUG_RTL_ALLOCATIONS
+ LOGD("TextLayout::getTextRunAdvances - allocated buffer with size: %d", contextCount);
+#endif
+
+ SkScalar* scalarArray = (SkScalar*)resultAdvances;
+
// this is where we'd call harfbuzz
// for now we just use ushape.c
@@ -274,8 +291,8 @@ void TextLayout::getTextRunAdvances(SkPaint *paint, const jchar *chars, jint sta
// we shouldn't fail unless there's an out of memory condition,
// in which case we're hosed anyway
for (int i = start, e = i + count; i < e; ++i) {
- if (buffer[i] == 0xffff) {
- buffer[i] = 0x200b; // zero-width-space for skia
+ if (buffer[i] == UNICODE_NOT_A_CHAR) {
+ buffer[i] = UNICODE_ZWSP; // zero-width-space for skia
}
}
text = buffer + start;
@@ -293,8 +310,11 @@ void TextLayout::getTextRunAdvances(SkPaint *paint, const jchar *chars, jint sta
// leaving the remaining widths zero. Not nice.
for (int i = 0, p = 0; i < widths; ++i) {
resultTotalAdvance += resultAdvances[p++] = SkScalarToFloat(scalarArray[i]);
- if (p < count && text[p] >= 0xdc00 && text[p] < 0xe000 &&
- text[p-1] >= 0xd800 && text[p-1] < 0xdc00) {
+ if (p < count &&
+ text[p] >= UNICODE_FIRST_LOW_SURROGATE &&
+ text[p] < UNICODE_FIRST_PRIVATE_USE &&
+ text[p-1] >= UNICODE_FIRST_HIGH_SURROGATE &&
+ text[p-1] < UNICODE_FIRST_LOW_SURROGATE) {
resultAdvances[p++] = 0;
}
}
@@ -331,7 +351,12 @@ void TextLayout::drawTextOnPath(SkPaint* paint, const jchar* text, int count,
return;
}
- SkAutoSTMalloc<80, jchar> buffer(count);
+ SkAutoSTMalloc<CHAR_BUFFER_SIZE, jchar> buffer(count);
+
+#if DEBUG_RTL_ALLOCATIONS
+ LOGD("TextLayout::drawTextOnPath - allocated buffer with size: %d", count);
+#endif
+
int dir = kDirection_LTR;
UErrorCode status = U_ZERO_ERROR;
count = layoutLine(text, count, bidiFlags, dir, buffer.get(), status);
diff --git a/core/jni/android/graphics/TextLayout.h b/core/jni/android/graphics/TextLayout.h
index 8f666c0..c98f745 100644
--- a/core/jni/android/graphics/TextLayout.h
+++ b/core/jni/android/graphics/TextLayout.h
@@ -22,6 +22,18 @@
namespace android {
+#define UNICODE_NOT_A_CHAR 0xffff
+#define UNICODE_ZWSP 0x200b
+#define UNICODE_FIRST_LOW_SURROGATE 0xdc00
+#define UNICODE_FIRST_HIGH_SURROGATE 0xd800
+#define UNICODE_FIRST_PRIVATE_USE 0xe000
+#define UNICODE_FIRST_RTL_CHAR 0x0590
+
+/*
+ * Temporary buffer size
+ */
+#define CHAR_BUFFER_SIZE 80
+
class TextLayout {
public:
diff --git a/core/jni/android/graphics/Xfermode.cpp b/core/jni/android/graphics/Xfermode.cpp
index 2b53d28..976a91f 100644
--- a/core/jni/android/graphics/Xfermode.cpp
+++ b/core/jni/android/graphics/Xfermode.cpp
@@ -28,7 +28,7 @@ public:
static void finalizer(JNIEnv* env, jobject, SkXfermode* obj)
{
- obj->safeUnref();
+ SkSafeUnref(obj);
}
static SkXfermode* avoid_create(JNIEnv* env, jobject, SkColor opColor,
diff --git a/core/jni/android_app_NativeActivity.cpp b/core/jni/android_app_NativeActivity.cpp
index 0430a81..56f2646 100644
--- a/core/jni/android_app_NativeActivity.cpp
+++ b/core/jni/android_app_NativeActivity.cpp
@@ -150,12 +150,12 @@ int32_t AInputQueue::hasEvents() {
pfd[0].events = POLLIN;
pfd[0].revents = 0;
pfd[1].fd = mDispatchKeyRead;
- pfd[0].events = POLLIN;
- pfd[0].revents = 0;
+ pfd[1].events = POLLIN;
+ pfd[1].revents = 0;
int nfd = poll(pfd, 2, 0);
if (nfd <= 0) return 0;
- return (pfd[0].revents == POLLIN || pfd[1].revents == POLLIN) ? 1 : -1;
+ return ((pfd[0].revents & POLLIN) || (pfd[1].revents & POLLIN)) ? 1 : -1;
}
int32_t AInputQueue::getEvent(AInputEvent** outEvent) {
diff --git a/core/jni/android_bluetooth_BluetoothAudioGateway.cpp b/core/jni/android_bluetooth_BluetoothAudioGateway.cpp
index bf23650..acf858a 100755
--- a/core/jni/android_bluetooth_BluetoothAudioGateway.cpp
+++ b/core/jni/android_bluetooth_BluetoothAudioGateway.cpp
@@ -89,40 +89,40 @@ static int setup_listening_socket(int dev, int channel);
#endif
static void classInitNative(JNIEnv* env, jclass clazz) {
- LOGV(__FUNCTION__);
+ LOGV("%s", __FUNCTION__);
#ifdef HAVE_BLUETOOTH
/* in */
field_mNativeData = get_field(env, clazz, "mNativeData", "I");
- field_mHandsfreeAgRfcommChannel =
+ field_mHandsfreeAgRfcommChannel =
get_field(env, clazz, "mHandsfreeAgRfcommChannel", "I");
- field_mHeadsetAgRfcommChannel =
+ field_mHeadsetAgRfcommChannel =
get_field(env, clazz, "mHeadsetAgRfcommChannel", "I");
/* out */
- field_mConnectingHeadsetAddress =
- get_field(env, clazz,
+ field_mConnectingHeadsetAddress =
+ get_field(env, clazz,
"mConnectingHeadsetAddress", "Ljava/lang/String;");
- field_mConnectingHeadsetRfcommChannel =
+ field_mConnectingHeadsetRfcommChannel =
get_field(env, clazz, "mConnectingHeadsetRfcommChannel", "I");
- field_mConnectingHeadsetSocketFd =
+ field_mConnectingHeadsetSocketFd =
get_field(env, clazz, "mConnectingHeadsetSocketFd", "I");
- field_mConnectingHandsfreeAddress =
- get_field(env, clazz,
+ field_mConnectingHandsfreeAddress =
+ get_field(env, clazz,
"mConnectingHandsfreeAddress", "Ljava/lang/String;");
- field_mConnectingHandsfreeRfcommChannel =
+ field_mConnectingHandsfreeRfcommChannel =
get_field(env, clazz, "mConnectingHandsfreeRfcommChannel", "I");
- field_mConnectingHandsfreeSocketFd =
+ field_mConnectingHandsfreeSocketFd =
get_field(env, clazz, "mConnectingHandsfreeSocketFd", "I");
- field_mTimeoutRemainingMs =
+ field_mTimeoutRemainingMs =
get_field(env, clazz, "mTimeoutRemainingMs", "I");
#endif
}
static void initializeNativeDataNative(JNIEnv* env, jobject object) {
- LOGV(__FUNCTION__);
+ LOGV("%s", __FUNCTION__);
#ifdef HAVE_BLUETOOTH
native_data_t *nat = (native_data_t *)calloc(1, sizeof(native_data_t));
if (NULL == nat) {
@@ -150,7 +150,7 @@ static void initializeNativeDataNative(JNIEnv* env, jobject object) {
}
static void cleanupNativeDataNative(JNIEnv* env, jobject object) {
- LOGV(__FUNCTION__);
+ LOGV("%s", __FUNCTION__);
#ifdef HAVE_BLUETOOTH
native_data_t *nat = get_native_data(env, object);
if (nat) {
@@ -165,7 +165,7 @@ static void cleanupNativeDataNative(JNIEnv* env, jobject object) {
static int set_nb(int sk, bool nb) {
int flags = fcntl(sk, F_GETFL);
if (flags < 0) {
- LOGE("Can't get socket flags with fcntl(): %s (%d)",
+ LOGE("Can't get socket flags with fcntl(): %s (%d)",
strerror(errno), errno);
close(sk);
return -1;
@@ -255,7 +255,7 @@ static inline int on_accept_set_fields(JNIEnv* env, jobject object,
static jboolean waitForHandsfreeConnectNative(JNIEnv* env, jobject object,
jint timeout_ms) {
-// LOGV(__FUNCTION__);
+// LOGV("%s", __FUNCTION__);
#ifdef HAVE_BLUETOOTH
env->SetIntField(object, field_mTimeoutRemainingMs, timeout_ms);
@@ -264,11 +264,11 @@ static jboolean waitForHandsfreeConnectNative(JNIEnv* env, jobject object,
native_data_t *nat = get_native_data(env, object);
#if USE_ACCEPT_DIRECTLY
if (nat->hf_ag_rfcomm_channel > 0) {
- LOGI("Setting HF AG server socket to RFCOMM port %d!",
+ LOGI("Setting HF AG server socket to RFCOMM port %d!",
nat->hf_ag_rfcomm_channel);
struct timeval tv;
int len = sizeof(tv);
- if (getsockopt(nat->hf_ag_rfcomm_channel,
+ if (getsockopt(nat->hf_ag_rfcomm_channel,
SOL_SOCKET, SO_RCVTIMEO, &tv, &len) < 0) {
LOGE("getsockopt(%d, SOL_SOCKET, SO_RCVTIMEO): %s (%d)",
nat->hf_ag_rfcomm_channel,
@@ -276,12 +276,12 @@ static jboolean waitForHandsfreeConnectNative(JNIEnv* env, jobject object,
errno);
return JNI_FALSE;
}
- LOGI("Current HF AG server socket RCVTIMEO is (%d(s), %d(us))!",
+ LOGI("Current HF AG server socket RCVTIMEO is (%d(s), %d(us))!",
(int)tv.tv_sec, (int)tv.tv_usec);
if (timeout_ms >= 0) {
tv.tv_sec = timeout_ms / 1000;
tv.tv_usec = 1000 * (timeout_ms % 1000);
- if (setsockopt(nat->hf_ag_rfcomm_channel,
+ if (setsockopt(nat->hf_ag_rfcomm_channel,
SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv)) < 0) {
LOGE("setsockopt(%d, SOL_SOCKET, SO_RCVTIMEO): %s (%d)",
nat->hf_ag_rfcomm_channel,
@@ -289,11 +289,11 @@ static jboolean waitForHandsfreeConnectNative(JNIEnv* env, jobject object,
errno);
return JNI_FALSE;
}
- LOGI("Changed HF AG server socket RCVTIMEO to (%d(s), %d(us))!",
+ LOGI("Changed HF AG server socket RCVTIMEO to (%d(s), %d(us))!",
(int)tv.tv_sec, (int)tv.tv_usec);
}
- if (!do_accept(env, object, nat->hf_ag_rfcomm_sock,
+ if (!do_accept(env, object, nat->hf_ag_rfcomm_sock,
field_mConnectingHandsfreeSocketFd,
field_mConnectingHandsfreeAddress,
field_mConnectingHandsfreeRfcommChannel))
@@ -309,13 +309,13 @@ static jboolean waitForHandsfreeConnectNative(JNIEnv* env, jobject object,
FD_ZERO(&rset);
int cnt = 0;
if (nat->hf_ag_rfcomm_channel > 0) {
- LOGI("Setting HF AG server socket to RFCOMM port %d!",
+ LOGI("Setting HF AG server socket to RFCOMM port %d!",
nat->hf_ag_rfcomm_channel);
cnt++;
FD_SET(nat->hf_ag_rfcomm_sock, &rset);
}
if (nat->hs_ag_rfcomm_channel > 0) {
- LOGI("Setting HS AG server socket to RFCOMM port %d!",
+ LOGI("Setting HS AG server socket to RFCOMM port %d!",
nat->hs_ag_rfcomm_channel);
cnt++;
FD_SET(nat->hs_ag_rfcomm_sock, &rset);
@@ -330,7 +330,7 @@ static jboolean waitForHandsfreeConnectNative(JNIEnv* env, jobject object,
to.tv_sec = timeout_ms / 1000;
to.tv_usec = 1000 * (timeout_ms % 1000);
}
- n = select(MAX(nat->hf_ag_rfcomm_sock,
+ n = select(MAX(nat->hf_ag_rfcomm_sock,
nat->hs_ag_rfcomm_sock) + 1,
&rset,
NULL,
@@ -354,7 +354,7 @@ static jboolean waitForHandsfreeConnectNative(JNIEnv* env, jobject object,
return JNI_FALSE;
}
- n = on_accept_set_fields(env, object,
+ n = on_accept_set_fields(env, object,
&rset, nat->hf_ag_rfcomm_sock,
field_mConnectingHandsfreeSocketFd,
field_mConnectingHandsfreeAddress,
@@ -371,7 +371,7 @@ static jboolean waitForHandsfreeConnectNative(JNIEnv* env, jobject object,
struct pollfd fds[2];
int cnt = 0;
if (nat->hf_ag_rfcomm_channel > 0) {
-// LOGI("Setting HF AG server socket %d to RFCOMM port %d!",
+// LOGI("Setting HF AG server socket %d to RFCOMM port %d!",
// nat->hf_ag_rfcomm_sock,
// nat->hf_ag_rfcomm_channel);
fds[cnt].fd = nat->hf_ag_rfcomm_sock;
@@ -379,7 +379,7 @@ static jboolean waitForHandsfreeConnectNative(JNIEnv* env, jobject object,
cnt++;
}
if (nat->hs_ag_rfcomm_channel > 0) {
-// LOGI("Setting HS AG server socket %d to RFCOMM port %d!",
+// LOGI("Setting HS AG server socket %d to RFCOMM port %d!",
// nat->hs_ag_rfcomm_sock,
// nat->hs_ag_rfcomm_channel);
fds[cnt].fd = nat->hs_ag_rfcomm_sock;
@@ -411,7 +411,7 @@ static jboolean waitForHandsfreeConnectNative(JNIEnv* env, jobject object,
if (fds[cnt].fd == nat->hf_ag_rfcomm_sock) {
if (fds[cnt].revents & (POLLIN | POLLPRI | POLLOUT)) {
LOGI("Accepting HF connection.\n");
- err += do_accept(env, object, fds[cnt].fd,
+ err += do_accept(env, object, fds[cnt].fd,
field_mConnectingHandsfreeSocketFd,
field_mConnectingHandsfreeAddress,
field_mConnectingHandsfreeRfcommChannel);
@@ -421,7 +421,7 @@ static jboolean waitForHandsfreeConnectNative(JNIEnv* env, jobject object,
else if (fds[cnt].fd == nat->hs_ag_rfcomm_sock) {
if (fds[cnt].revents & (POLLIN | POLLPRI | POLLOUT)) {
LOGI("Accepting HS connection.\n");
- err += do_accept(env, object, fds[cnt].fd,
+ err += do_accept(env, object, fds[cnt].fd,
field_mConnectingHeadsetSocketFd,
field_mConnectingHeadsetAddress,
field_mConnectingHeadsetRfcommChannel);
@@ -444,7 +444,7 @@ static jboolean waitForHandsfreeConnectNative(JNIEnv* env, jobject object,
}
static jboolean setUpListeningSocketsNative(JNIEnv* env, jobject object) {
- LOGV(__FUNCTION__);
+ LOGV("%s", __FUNCTION__);
#ifdef HAVE_BLUETOOTH
native_data_t *nat = get_native_data(env, object);
@@ -509,7 +509,7 @@ static int setup_listening_socket(int dev, int channel) {
private native void tearDownListeningSocketsNative();
*/
static void tearDownListeningSocketsNative(JNIEnv *env, jobject object) {
- LOGV(__FUNCTION__);
+ LOGV("%s", __FUNCTION__);
#ifdef HAVE_BLUETOOTH
native_data_t *nat = get_native_data(env, object);
diff --git a/core/jni/android_bluetooth_BluetoothSocket.cpp b/core/jni/android_bluetooth_BluetoothSocket.cpp
index 31ebf8c..b87f7c4 100644
--- a/core/jni/android_bluetooth_BluetoothSocket.cpp
+++ b/core/jni/android_bluetooth_BluetoothSocket.cpp
@@ -66,7 +66,7 @@ static struct asocket *get_socketData(JNIEnv *env, jobject obj) {
static void initSocketFromFdNative(JNIEnv *env, jobject obj, jint fd) {
#ifdef HAVE_BLUETOOTH
- LOGV(__FUNCTION__);
+ LOGV("%s", __FUNCTION__);
struct asocket *s = asocket_init(fd);
@@ -85,7 +85,7 @@ static void initSocketFromFdNative(JNIEnv *env, jobject obj, jint fd) {
static void initSocketNative(JNIEnv *env, jobject obj) {
#ifdef HAVE_BLUETOOTH
- LOGV(__FUNCTION__);
+ LOGV("%s", __FUNCTION__);
int fd;
int lm = 0;
@@ -161,7 +161,7 @@ static void initSocketNative(JNIEnv *env, jobject obj) {
static void connectNative(JNIEnv *env, jobject obj) {
#ifdef HAVE_BLUETOOTH
- LOGV(__FUNCTION__);
+ LOGV("%s", __FUNCTION__);
int ret;
jint type;
@@ -240,7 +240,7 @@ static void connectNative(JNIEnv *env, jobject obj) {
/* Returns errno instead of throwing, so java can check errno */
static int bindListenNative(JNIEnv *env, jobject obj) {
#ifdef HAVE_BLUETOOTH
- LOGV(__FUNCTION__);
+ LOGV("%s", __FUNCTION__);
jint type;
socklen_t addr_sz;
@@ -307,7 +307,7 @@ static int bindListenNative(JNIEnv *env, jobject obj) {
static jobject acceptNative(JNIEnv *env, jobject obj, int timeout) {
#ifdef HAVE_BLUETOOTH
- LOGV(__FUNCTION__);
+ LOGV("%s", __FUNCTION__);
int fd;
jint type;
@@ -380,7 +380,7 @@ static jobject acceptNative(JNIEnv *env, jobject obj, int timeout) {
static jint availableNative(JNIEnv *env, jobject obj) {
#ifdef HAVE_BLUETOOTH
- LOGV(__FUNCTION__);
+ LOGV("%s", __FUNCTION__);
int available;
struct asocket *s = get_socketData(env, obj);
@@ -403,7 +403,7 @@ static jint availableNative(JNIEnv *env, jobject obj) {
static jint readNative(JNIEnv *env, jobject obj, jbyteArray jb, jint offset,
jint length) {
#ifdef HAVE_BLUETOOTH
- LOGV(__FUNCTION__);
+ LOGV("%s", __FUNCTION__);
int ret;
jbyte *b;
@@ -446,7 +446,7 @@ static jint readNative(JNIEnv *env, jobject obj, jbyteArray jb, jint offset,
static jint writeNative(JNIEnv *env, jobject obj, jbyteArray jb, jint offset,
jint length) {
#ifdef HAVE_BLUETOOTH
- LOGV(__FUNCTION__);
+ LOGV("%s", __FUNCTION__);
int ret;
jbyte *b;
@@ -488,7 +488,7 @@ static jint writeNative(JNIEnv *env, jobject obj, jbyteArray jb, jint offset,
static void abortNative(JNIEnv *env, jobject obj) {
#ifdef HAVE_BLUETOOTH
- LOGV(__FUNCTION__);
+ LOGV("%s", __FUNCTION__);
struct asocket *s = get_socketData(env, obj);
if (!s)
@@ -504,7 +504,7 @@ static void abortNative(JNIEnv *env, jobject obj) {
static void destroyNative(JNIEnv *env, jobject obj) {
#ifdef HAVE_BLUETOOTH
- LOGV(__FUNCTION__);
+ LOGV("%s", __FUNCTION__);
struct asocket *s = get_socketData(env, obj);
int fd = s->fd;
diff --git a/core/jni/android_bluetooth_HeadsetBase.cpp b/core/jni/android_bluetooth_HeadsetBase.cpp
index 4e9fbaf..bbf1ae5 100644
--- a/core/jni/android_bluetooth_HeadsetBase.cpp
+++ b/core/jni/android_bluetooth_HeadsetBase.cpp
@@ -180,7 +180,7 @@ again:
#endif
static void classInitNative(JNIEnv* env, jclass clazz) {
- LOGV(__FUNCTION__);
+ LOGV("%s", __FUNCTION__);
#ifdef HAVE_BLUETOOTH
field_mNativeData = get_field(env, clazz, "mNativeData", "I");
field_mAddress = get_field(env, clazz, "mAddress", "Ljava/lang/String;");
@@ -191,7 +191,7 @@ static void classInitNative(JNIEnv* env, jclass clazz) {
static void initializeNativeDataNative(JNIEnv* env, jobject object,
jint socketFd) {
- LOGV(__FUNCTION__);
+ LOGV("%s", __FUNCTION__);
#ifdef HAVE_BLUETOOTH
native_data_t *nat = (native_data_t *)calloc(1, sizeof(native_data_t));
if (NULL == nat) {
@@ -213,7 +213,7 @@ static void initializeNativeDataNative(JNIEnv* env, jobject object,
}
static void cleanupNativeDataNative(JNIEnv* env, jobject object) {
- LOGV(__FUNCTION__);
+ LOGV("%s", __FUNCTION__);
#ifdef HAVE_BLUETOOTH
native_data_t *nat =
(native_data_t *)env->GetIntField(object, field_mNativeData);
@@ -226,7 +226,7 @@ static void cleanupNativeDataNative(JNIEnv* env, jobject object) {
static jboolean connectNative(JNIEnv *env, jobject obj)
{
- LOGV(__FUNCTION__);
+ LOGV("%s", __FUNCTION__);
#ifdef HAVE_BLUETOOTH
int lm;
struct sockaddr_rc addr;
@@ -278,7 +278,7 @@ static jboolean connectNative(JNIEnv *env, jobject obj)
}
static jint connectAsyncNative(JNIEnv *env, jobject obj) {
- LOGV(__FUNCTION__);
+ LOGV("%s", __FUNCTION__);
#ifdef HAVE_BLUETOOTH
struct sockaddr_rc addr;
native_data_t *nat = get_native_data(env, obj);
@@ -357,7 +357,7 @@ static jint connectAsyncNative(JNIEnv *env, jobject obj) {
static jint waitForAsyncConnectNative(JNIEnv *env, jobject obj,
jint timeout_ms) {
- LOGV(__FUNCTION__);
+ LOGV("%s", __FUNCTION__);
#ifdef HAVE_BLUETOOTH
struct sockaddr_rc addr;
native_data_t *nat = get_native_data(env, obj);
@@ -463,7 +463,7 @@ static jint waitForAsyncConnectNative(JNIEnv *env, jobject obj,
}
static void disconnectNative(JNIEnv *env, jobject obj) {
- LOGV(__FUNCTION__);
+ LOGV("%s", __FUNCTION__);
#ifdef HAVE_BLUETOOTH
native_data_t *nat = get_native_data(env, obj);
if (nat->rfcomm_sock >= 0) {
diff --git a/core/jni/android_database_CursorWindow.cpp b/core/jni/android_database_CursorWindow.cpp
index a428151..ddac820 100644
--- a/core/jni/android_database_CursorWindow.cpp
+++ b/core/jni/android_database_CursorWindow.cpp
@@ -208,7 +208,10 @@ LOG_WINDOW("Getting blob for %d,%d from %p", row, column, window);
uint8_t type = field.type;
if (type == FIELD_TYPE_BLOB || type == FIELD_TYPE_STRING) {
jbyteArray byteArray = env->NewByteArray(field.data.buffer.size);
- LOG_ASSERT(byteArray, "Native could not create new byte[]");
+ if (!byteArray) {
+ throw_sqlite3_exception(env, "Native could not create new byte[]");
+ return NULL;
+ }
env->SetByteArrayRegion(byteArray, 0, field.data.buffer.size,
(const jbyte*)window->offsetToPtr(field.data.buffer.offset));
return byteArray;
diff --git a/core/jni/android_hardware_Camera.cpp b/core/jni/android_hardware_Camera.cpp
index 9f70509..bfbfd37 100644
--- a/core/jni/android_hardware_Camera.cpp
+++ b/core/jni/android_hardware_Camera.cpp
@@ -53,25 +53,48 @@ public:
virtual void notify(int32_t msgType, int32_t ext1, int32_t ext2);
virtual void postData(int32_t msgType, const sp<IMemory>& dataPtr);
virtual void postDataTimestamp(nsecs_t timestamp, int32_t msgType, const sp<IMemory>& dataPtr);
- void addCallbackBuffer(JNIEnv *env, jbyteArray cbb);
+ void addCallbackBuffer(JNIEnv *env, jbyteArray cbb, int msgType);
void setCallbackMode(JNIEnv *env, bool installed, bool manualMode);
sp<Camera> getCamera() { Mutex::Autolock _l(mLock); return mCamera; }
+ bool isRawImageCallbackBufferAvailable() const;
void release();
private:
void copyAndPost(JNIEnv* env, const sp<IMemory>& dataPtr, int msgType);
+ void clearCallbackBuffers_l(JNIEnv *env, Vector<jbyteArray> *buffers);
void clearCallbackBuffers_l(JNIEnv *env);
+ jbyteArray getCallbackBuffer(JNIEnv *env, Vector<jbyteArray> *buffers, size_t bufferSize);
jobject mCameraJObjectWeak; // weak reference to java object
jclass mCameraJClass; // strong reference to java class
sp<Camera> mCamera; // strong reference to native object
Mutex mLock;
+ /*
+ * Global reference application-managed raw image buffer queue.
+ *
+ * Manual-only mode is supported for raw image callbacks, which is
+ * set whenever method addCallbackBuffer() with msgType =
+ * CAMERA_MSG_RAW_IMAGE is called; otherwise, null is returned
+ * with raw image callbacks.
+ */
+ Vector<jbyteArray> mRawImageCallbackBuffers;
+
+ /*
+ * Application-managed preview buffer queue and the flags
+ * associated with the usage of the preview buffer callback.
+ */
Vector<jbyteArray> mCallbackBuffers; // Global reference application managed byte[]
bool mManualBufferMode; // Whether to use application managed buffers.
- bool mManualCameraCallbackSet; // Whether the callback has been set, used to reduce unnecessary calls to set the callback.
+ bool mManualCameraCallbackSet; // Whether the callback has been set, used to
+ // reduce unnecessary calls to set the callback.
};
+bool JNICameraContext::isRawImageCallbackBufferAvailable() const
+{
+ return !mRawImageCallbackBuffers.isEmpty();
+}
+
sp<Camera> get_native_camera(JNIEnv *env, jobject thiz, JNICameraContext** pContext)
{
sp<Camera> camera;
@@ -128,10 +151,48 @@ void JNICameraContext::notify(int32_t msgType, int32_t ext1, int32_t ext2)
return;
}
JNIEnv *env = AndroidRuntime::getJNIEnv();
+
+ /*
+ * If the notification or msgType is CAMERA_MSG_RAW_IMAGE_NOTIFY, change it
+ * to CAMERA_MSG_RAW_IMAGE since CAMERA_MSG_RAW_IMAGE_NOTIFY is not exposed
+ * to the Java app.
+ */
+ if (msgType == CAMERA_MSG_RAW_IMAGE_NOTIFY) {
+ msgType = CAMERA_MSG_RAW_IMAGE;
+ }
+
env->CallStaticVoidMethod(mCameraJClass, fields.post_event,
mCameraJObjectWeak, msgType, ext1, ext2, NULL);
}
+jbyteArray JNICameraContext::getCallbackBuffer(
+ JNIEnv* env, Vector<jbyteArray>* buffers, size_t bufferSize)
+{
+ jbyteArray obj = NULL;
+
+ // Vector access should be protected by lock in postData()
+ if (!buffers->isEmpty()) {
+ LOGV("Using callback buffer from queue of length %d", buffers->size());
+ jbyteArray globalBuffer = buffers->itemAt(0);
+ buffers->removeAt(0);
+
+ obj = (jbyteArray)env->NewLocalRef(globalBuffer);
+ env->DeleteGlobalRef(globalBuffer);
+
+ if (obj != NULL) {
+ jsize bufferLength = env->GetArrayLength(obj);
+ if ((int)bufferLength < (int)bufferSize) {
+ LOGE("Callback buffer was too small! Expected %d bytes, but got %d bytes!",
+ bufferSize, bufferLength);
+ env->DeleteLocalRef(obj);
+ return NULL;
+ }
+ }
+ }
+
+ return obj;
+}
+
void JNICameraContext::copyAndPost(JNIEnv* env, const sp<IMemory>& dataPtr, int msgType)
{
jbyteArray obj = NULL;
@@ -141,7 +202,7 @@ void JNICameraContext::copyAndPost(JNIEnv* env, const sp<IMemory>& dataPtr, int
ssize_t offset;
size_t size;
sp<IMemoryHeap> heap = dataPtr->getMemory(&offset, &size);
- LOGV("postData: off=%d, size=%d", offset, size);
+ LOGV("copyAndPost: off=%ld, size=%d", offset, size);
uint8_t *heapBase = (uint8_t*)heap->base();
if (heapBase != NULL) {
@@ -151,32 +212,28 @@ void JNICameraContext::copyAndPost(JNIEnv* env, const sp<IMemory>& dataPtr, int
LOGV("Allocating callback buffer");
obj = env->NewByteArray(size);
} else {
- // Vector access should be protected by lock in postData()
- if(!mCallbackBuffers.isEmpty()) {
- LOGV("Using callback buffer from queue of length %d", mCallbackBuffers.size());
- jbyteArray globalBuffer = mCallbackBuffers.itemAt(0);
- mCallbackBuffers.removeAt(0);
-
- obj = (jbyteArray)env->NewLocalRef(globalBuffer);
- env->DeleteGlobalRef(globalBuffer);
-
- if (obj != NULL) {
- jsize bufferLength = env->GetArrayLength(obj);
- if ((int)bufferLength < (int)size) {
- LOGE("Manually set buffer was too small! Expected %d bytes, but got %d!",
- size, bufferLength);
- env->DeleteLocalRef(obj);
- return;
+ switch (msgType) {
+ case CAMERA_MSG_PREVIEW_FRAME: {
+ obj = getCallbackBuffer(env, &mCallbackBuffers, size);
+
+ if (mCallbackBuffers.isEmpty()) {
+ LOGV("Out of buffers, clearing callback!");
+ mCamera->setPreviewCallbackFlags(FRAME_CALLBACK_FLAG_NOOP);
+ mManualCameraCallbackSet = false;
+
+ if (obj == NULL) {
+ return;
+ }
}
+ break;
}
- }
-
- if(mCallbackBuffers.isEmpty()) {
- LOGV("Out of buffers, clearing callback!");
- mCamera->setPreviewCallbackFlags(FRAME_CALLBACK_FLAG_NOOP);
- mManualCameraCallbackSet = false;
-
- if (obj == NULL) {
+ case CAMERA_MSG_RAW_IMAGE: {
+ obj = getCallbackBuffer(env, &mRawImageCallbackBuffers, size);
+ break;
+ }
+ default: {
+ jniThrowException(env,
+ "java/lang/RuntimeException", "Unsupported message type");
return;
}
}
@@ -212,21 +269,27 @@ void JNICameraContext::postData(int32_t msgType, const sp<IMemory>& dataPtr)
}
// return data based on callback type
- switch(msgType) {
- case CAMERA_MSG_VIDEO_FRAME:
- // should never happen
- break;
- // don't return raw data to Java
- case CAMERA_MSG_RAW_IMAGE:
- LOGV("rawCallback");
- env->CallStaticVoidMethod(mCameraJClass, fields.post_event,
- mCameraJObjectWeak, msgType, 0, 0, NULL);
- break;
- default:
- // TODO: Change to LOGV
- LOGV("dataCallback(%d, %p)", msgType, dataPtr.get());
- copyAndPost(env, dataPtr, msgType);
- break;
+ switch (msgType) {
+ case CAMERA_MSG_VIDEO_FRAME:
+ // should never happen
+ break;
+
+ // For backward-compatibility purpose, if there is no callback
+ // buffer for raw image, the callback returns null.
+ case CAMERA_MSG_RAW_IMAGE:
+ LOGV("rawCallback");
+ if (mRawImageCallbackBuffers.isEmpty()) {
+ env->CallStaticVoidMethod(mCameraJClass, fields.post_event,
+ mCameraJObjectWeak, msgType, 0, 0, NULL);
+ } else {
+ copyAndPost(env, dataPtr, msgType);
+ }
+ break;
+
+ default:
+ LOGV("dataCallback(%d, %p)", msgType, dataPtr.get());
+ copyAndPost(env, dataPtr, msgType);
+ break;
}
}
@@ -251,7 +314,7 @@ void JNICameraContext::setCallbackMode(JNIEnv *env, bool installed, bool manualM
if (!installed) {
mCamera->setPreviewCallbackFlags(FRAME_CALLBACK_FLAG_NOOP);
- clearCallbackBuffers_l(env);
+ clearCallbackBuffers_l(env, &mCallbackBuffers);
} else if (mManualBufferMode) {
if (!mCallbackBuffers.isEmpty()) {
mCamera->setPreviewCallbackFlags(FRAME_CALLBACK_FLAG_CAMERA);
@@ -259,24 +322,44 @@ void JNICameraContext::setCallbackMode(JNIEnv *env, bool installed, bool manualM
}
} else {
mCamera->setPreviewCallbackFlags(FRAME_CALLBACK_FLAG_BARCODE_SCANNER);
- clearCallbackBuffers_l(env);
+ clearCallbackBuffers_l(env, &mCallbackBuffers);
}
}
-void JNICameraContext::addCallbackBuffer(JNIEnv *env, jbyteArray cbb)
+void JNICameraContext::addCallbackBuffer(
+ JNIEnv *env, jbyteArray cbb, int msgType)
{
+ LOGV("addCallbackBuffer: 0x%x", msgType);
if (cbb != NULL) {
Mutex::Autolock _l(mLock);
- jbyteArray callbackBuffer = (jbyteArray)env->NewGlobalRef(cbb);
- mCallbackBuffers.push(cbb);
-
- LOGV("Adding callback buffer to queue, %d total", mCallbackBuffers.size());
-
- // We want to make sure the camera knows we're ready for the next frame.
- // This may have come unset had we not had a callbackbuffer ready for it last time.
- if (mManualBufferMode && !mManualCameraCallbackSet) {
- mCamera->setPreviewCallbackFlags(FRAME_CALLBACK_FLAG_CAMERA);
- mManualCameraCallbackSet = true;
+ switch (msgType) {
+ case CAMERA_MSG_PREVIEW_FRAME: {
+ jbyteArray callbackBuffer = (jbyteArray)env->NewGlobalRef(cbb);
+ mCallbackBuffers.push(callbackBuffer);
+
+ LOGV("Adding callback buffer to queue, %d total",
+ mCallbackBuffers.size());
+
+ // We want to make sure the camera knows we're ready for the
+ // next frame. This may have come unset had we not had a
+ // callbackbuffer ready for it last time.
+ if (mManualBufferMode && !mManualCameraCallbackSet) {
+ mCamera->setPreviewCallbackFlags(FRAME_CALLBACK_FLAG_CAMERA);
+ mManualCameraCallbackSet = true;
+ }
+ break;
+ }
+ case CAMERA_MSG_RAW_IMAGE: {
+ jbyteArray callbackBuffer = (jbyteArray)env->NewGlobalRef(cbb);
+ mRawImageCallbackBuffers.push(callbackBuffer);
+ break;
+ }
+ default: {
+ jniThrowException(env,
+ "java/lang/IllegalArgumentException",
+ "Unsupported message type");
+ return;
+ }
}
} else {
LOGE("Null byte array!");
@@ -285,10 +368,15 @@ void JNICameraContext::addCallbackBuffer(JNIEnv *env, jbyteArray cbb)
void JNICameraContext::clearCallbackBuffers_l(JNIEnv *env)
{
- LOGV("Clearing callback buffers, %d remained", mCallbackBuffers.size());
- while(!mCallbackBuffers.isEmpty()) {
- env->DeleteGlobalRef(mCallbackBuffers.top());
- mCallbackBuffers.pop();
+ clearCallbackBuffers_l(env, &mCallbackBuffers);
+ clearCallbackBuffers_l(env, &mRawImageCallbackBuffers);
+}
+
+void JNICameraContext::clearCallbackBuffers_l(JNIEnv *env, Vector<jbyteArray> *buffers) {
+ LOGV("Clearing callback buffers, %d remained", buffers->size());
+ while (!buffers->isEmpty()) {
+ env->DeleteGlobalRef(buffers->top());
+ buffers->pop();
}
}
@@ -458,13 +546,13 @@ static void android_hardware_Camera_setHasPreviewCallback(JNIEnv *env, jobject t
context->setCallbackMode(env, installed, manualBuffer);
}
-static void android_hardware_Camera_addCallbackBuffer(JNIEnv *env, jobject thiz, jbyteArray bytes) {
- LOGV("addCallbackBuffer");
+static void android_hardware_Camera_addCallbackBuffer(JNIEnv *env, jobject thiz, jbyteArray bytes, int msgType) {
+ LOGV("addCallbackBuffer: 0x%x", msgType);
JNICameraContext* context = reinterpret_cast<JNICameraContext*>(env->GetIntField(thiz, fields.context));
if (context != NULL) {
- context->addCallbackBuffer(env, bytes);
+ context->addCallbackBuffer(env, bytes, msgType);
}
}
@@ -492,14 +580,32 @@ static void android_hardware_Camera_cancelAutoFocus(JNIEnv *env, jobject thiz)
}
}
-static void android_hardware_Camera_takePicture(JNIEnv *env, jobject thiz)
+static void android_hardware_Camera_takePicture(JNIEnv *env, jobject thiz, int msgType)
{
LOGV("takePicture");
JNICameraContext* context;
sp<Camera> camera = get_native_camera(env, thiz, &context);
if (camera == 0) return;
- if (camera->takePicture() != NO_ERROR) {
+ /*
+ * When CAMERA_MSG_RAW_IMAGE is requested, if the raw image callback
+ * buffer is available, CAMERA_MSG_RAW_IMAGE is enabled to get the
+ * notification _and_ the data; otherwise, CAMERA_MSG_RAW_IMAGE_NOTIFY
+ * is enabled to receive the callback notification but no data.
+ *
+ * Note that CAMERA_MSG_RAW_IMAGE_NOTIFY is not exposed to the
+ * Java application.
+ */
+ if (msgType & CAMERA_MSG_RAW_IMAGE) {
+ LOGV("Enable raw image callback buffer");
+ if (!context->isRawImageCallbackBufferAvailable()) {
+ LOGV("Enable raw image notification, since no callback buffer exists");
+ msgType &= ~CAMERA_MSG_RAW_IMAGE;
+ msgType |= CAMERA_MSG_RAW_IMAGE_NOTIFY;
+ }
+ }
+
+ if (camera->takePicture(msgType) != NO_ERROR) {
jniThrowException(env, "java/lang/RuntimeException", "takePicture failed");
return;
}
@@ -638,8 +744,8 @@ static JNINativeMethod camMethods[] = {
{ "setHasPreviewCallback",
"(ZZ)V",
(void *)android_hardware_Camera_setHasPreviewCallback },
- { "addCallbackBuffer",
- "([B)V",
+ { "_addCallbackBuffer",
+ "([BI)V",
(void *)android_hardware_Camera_addCallbackBuffer },
{ "native_autoFocus",
"()V",
@@ -648,7 +754,7 @@ static JNINativeMethod camMethods[] = {
"()V",
(void *)android_hardware_Camera_cancelAutoFocus },
{ "native_takePicture",
- "()V",
+ "(I)V",
(void *)android_hardware_Camera_takePicture },
{ "native_setParameters",
"(Ljava/lang/String;)V",
diff --git a/core/jni/android_hardware_UsbDevice.cpp b/core/jni/android_hardware_UsbDevice.cpp
index 9014450..b01820c 100644
--- a/core/jni/android_hardware_UsbDevice.cpp
+++ b/core/jni/android_hardware_UsbDevice.cpp
@@ -237,7 +237,7 @@ static JNINativeMethod method_table[] = {
(void *)android_hardware_UsbDevice_control_request},
{"native_bulk_request", "(I[BII)I",
(void *)android_hardware_UsbDevice_bulk_request},
- {"native_request_wait", "()Landroid/hardware/UsbRequest;",
+ {"native_request_wait", "()Landroid/hardware/usb/UsbRequest;",
(void *)android_hardware_UsbDevice_request_wait},
{ "native_get_serial", "()Ljava/lang/String;",
(void*)android_hardware_UsbDevice_get_serial },
@@ -251,9 +251,9 @@ static JNINativeMethod method_table[] = {
int register_android_hardware_UsbDevice(JNIEnv *env)
{
- jclass clazz = env->FindClass("android/hardware/UsbDevice");
+ jclass clazz = env->FindClass("android/hardware/usb/UsbDevice");
if (clazz == NULL) {
- LOGE("Can't find android/hardware/UsbDevice");
+ LOGE("Can't find android/hardware/usb/UsbDevice");
return -1;
}
field_context = env->GetFieldID(clazz, "mNativeContext", "I");
@@ -262,7 +262,7 @@ int register_android_hardware_UsbDevice(JNIEnv *env)
return -1;
}
- return AndroidRuntime::registerNativeMethods(env, "android/hardware/UsbDevice",
+ return AndroidRuntime::registerNativeMethods(env, "android/hardware/usb/UsbDevice",
method_table, NELEM(method_table));
}
diff --git a/core/jni/android_hardware_UsbEndpoint.cpp b/core/jni/android_hardware_UsbEndpoint.cpp
deleted file mode 100644
index 00c8235..0000000
--- a/core/jni/android_hardware_UsbEndpoint.cpp
+++ /dev/null
@@ -1,124 +0,0 @@
-/*
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#define LOG_TAG "UsbEndpoint"
-
-#include "utils/Log.h"
-
-#include "jni.h"
-#include "JNIHelp.h"
-#include "android_runtime/AndroidRuntime.h"
-
-#include <usbhost/usbhost.h>
-
-#include <stdio.h>
-
-using namespace android;
-
-static jfieldID field_context;
-static jfieldID field_address;
-static jfieldID field_attributes;
-static jfieldID field_max_packet_size;
-static jfieldID field_interval;
-
-struct usb_endpoint* get_endpoint_from_object(JNIEnv* env, jobject javaEndpoint)
-{
- return (struct usb_endpoint*)env->GetIntField(javaEndpoint, field_context);
-}
-
-// in android_hardware_UsbDevice.cpp
-extern struct usb_device* get_device_from_object(JNIEnv* env, jobject javaDevice);
-
-static jboolean
-android_hardware_UsbEndpoint_init(JNIEnv *env, jobject thiz, jobject javaDevice)
-{
- LOGD("open\n");
-
- struct usb_device* device = get_device_from_object(env, javaDevice);
- if (!device) {
- LOGE("device null in native_init");
- return false;
- }
-
- // construct an endpoint descriptor from the Java object fields
- struct usb_endpoint_descriptor desc;
- desc.bLength = USB_DT_ENDPOINT_SIZE;
- desc.bDescriptorType = USB_DT_ENDPOINT;
- desc.bEndpointAddress = env->GetIntField(thiz, field_address);
- desc.bmAttributes = env->GetIntField(thiz, field_attributes);
- desc.wMaxPacketSize = env->GetIntField(thiz, field_max_packet_size);
- desc.bInterval = env->GetIntField(thiz, field_interval);
-
- struct usb_endpoint* endpoint = usb_endpoint_init(device, &desc);
- if (endpoint)
- env->SetIntField(thiz, field_context, (int)device);
- return (endpoint != NULL);
-}
-
-static void
-android_hardware_UsbEndpoint_close(JNIEnv *env, jobject thiz)
-{
- LOGD("close\n");
- struct usb_endpoint* endpoint = get_endpoint_from_object(env, thiz);
- if (endpoint) {
- usb_endpoint_close(endpoint);
- env->SetIntField(thiz, field_context, 0);
- }
-}
-
-static JNINativeMethod method_table[] = {
- {"native_init", "(Landroid/hardware/UsbDevice;)Z",
- (void *)android_hardware_UsbEndpoint_init},
- {"native_close", "()V", (void *)android_hardware_UsbEndpoint_close},
-};
-
-int register_android_hardware_UsbEndpoint(JNIEnv *env)
-{
- jclass clazz = env->FindClass("android/hardware/UsbEndpoint");
- if (clazz == NULL) {
- LOGE("Can't find android/hardware/UsbEndpoint");
- return -1;
- }
- field_context = env->GetFieldID(clazz, "mNativeContext", "I");
- if (field_context == NULL) {
- LOGE("Can't find UsbEndpoint.mNativeContext");
- return -1;
- }
- field_address = env->GetFieldID(clazz, "mAddress", "I");
- if (field_address == NULL) {
- LOGE("Can't find UsbEndpoint.mAddress");
- return -1;
- }
- field_attributes = env->GetFieldID(clazz, "mAttributes", "I");
- if (field_attributes == NULL) {
- LOGE("Can't find UsbEndpoint.mAttributes");
- return -1;
- }
- field_max_packet_size = env->GetFieldID(clazz, "mMaxPacketSize", "I");
- if (field_max_packet_size == NULL) {
- LOGE("Can't find UsbEndpoint.mMaxPacketSize");
- return -1;
- }
- field_interval = env->GetFieldID(clazz, "mInterval", "I");
- if (field_interval == NULL) {
- LOGE("Can't find UsbEndpoint.mInterval");
- return -1;
- }
-
- return AndroidRuntime::registerNativeMethods(env, "android/hardware/UsbEndpoint",
- method_table, NELEM(method_table));
-}
-
diff --git a/core/jni/android_hardware_UsbRequest.cpp b/core/jni/android_hardware_UsbRequest.cpp
index 710afae..b497adb 100644
--- a/core/jni/android_hardware_UsbRequest.cpp
+++ b/core/jni/android_hardware_UsbRequest.cpp
@@ -187,7 +187,7 @@ android_hardware_UsbRequest_cancel(JNIEnv *env, jobject thiz)
}
static JNINativeMethod method_table[] = {
- {"native_init", "(Landroid/hardware/UsbDevice;IIII)Z",
+ {"native_init", "(Landroid/hardware/usb/UsbDevice;IIII)Z",
(void *)android_hardware_UsbRequest_init},
{"native_close", "()V", (void *)android_hardware_UsbRequest_close},
{"native_queue_array", "([BIZ)Z", (void *)android_hardware_UsbRequest_queue_array},
@@ -200,9 +200,9 @@ static JNINativeMethod method_table[] = {
int register_android_hardware_UsbRequest(JNIEnv *env)
{
- jclass clazz = env->FindClass("android/hardware/UsbRequest");
+ jclass clazz = env->FindClass("android/hardware/usb/UsbRequest");
if (clazz == NULL) {
- LOGE("Can't find android/hardware/UsbRequest");
+ LOGE("Can't find android/hardware/usb/UsbRequest");
return -1;
}
field_context = env->GetFieldID(clazz, "mNativeContext", "I");
@@ -211,7 +211,7 @@ int register_android_hardware_UsbRequest(JNIEnv *env)
return -1;
}
- return AndroidRuntime::registerNativeMethods(env, "android/hardware/UsbRequest",
+ return AndroidRuntime::registerNativeMethods(env, "android/hardware/usb/UsbRequest",
method_table, NELEM(method_table));
}
diff --git a/core/jni/android_net_wifi_Wifi.cpp b/core/jni/android_net_wifi_Wifi.cpp
index fc806a5..667ba75 100644
--- a/core/jni/android_net_wifi_Wifi.cpp
+++ b/core/jni/android_net_wifi_Wifi.cpp
@@ -556,6 +556,18 @@ static jboolean android_net_wifi_setSuspendOptimizationsCommand(JNIEnv* env, job
return doBooleanCommand(cmdstr, "OK");
}
+static void android_net_wifi_enableBackgroundScan(JNIEnv* env, jobject clazz, jboolean enable)
+{
+ //Note: BGSCAN-START and BGSCAN-STOP are documented in core/res/res/values/config.xml
+ //and will need an update if the names are changed
+ if (enable) {
+ doBooleanCommand("DRIVER BGSCAN-START", "OK");
+ }
+ else {
+ doBooleanCommand("DRIVER BGSCAN-STOP", "OK");
+ }
+}
+
// ----------------------------------------------------------------------------
/*
@@ -623,6 +635,7 @@ static JNINativeMethod gWifiMethods[] = {
(void*) android_net_wifi_setSuspendOptimizationsCommand},
{ "setCountryCodeCommand", "(Ljava/lang/String;)Z",
(void*) android_net_wifi_setCountryCodeCommand},
+ { "enableBackgroundScan", "(Z)V", (void*) android_net_wifi_enableBackgroundScan},
};
int register_android_net_wifi_WifiManager(JNIEnv* env)
diff --git a/core/jni/android_os_ParcelFileDescriptor.cpp b/core/jni/android_os_ParcelFileDescriptor.cpp
index eceef1c..1f737f9 100644
--- a/core/jni/android_os_ParcelFileDescriptor.cpp
+++ b/core/jni/android_os_ParcelFileDescriptor.cpp
@@ -126,6 +126,17 @@ static jlong android_os_ParcelFileDescriptor_seekTo(JNIEnv* env,
return lseek(fd, pos, SEEK_SET);
}
+static jlong android_os_ParcelFileDescriptor_getFdNative(JNIEnv* env, jobject clazz)
+{
+ jint fd = getFd(env, clazz);
+ if (fd < 0) {
+ jniThrowException(env, "java/lang/IllegalArgumentException", "bad file descriptor");
+ return -1;
+ }
+
+ return fd;
+}
+
static const JNINativeMethod gParcelFileDescriptorMethods[] = {
{"getFileDescriptorFromSocket", "(Ljava/net/Socket;)Ljava/io/FileDescriptor;",
(void*)android_os_ParcelFileDescriptor_getFileDescriptorFromSocket},
@@ -134,7 +145,9 @@ static const JNINativeMethod gParcelFileDescriptorMethods[] = {
{"getStatSize", "()J",
(void*)android_os_ParcelFileDescriptor_getStatSize},
{"seekTo", "(J)J",
- (void*)android_os_ParcelFileDescriptor_seekTo}
+ (void*)android_os_ParcelFileDescriptor_seekTo},
+ {"getFdNative", "()I",
+ (void*)android_os_ParcelFileDescriptor_getFdNative}
};
const char* const kParcelFileDescriptorPathName = "android/os/ParcelFileDescriptor";
diff --git a/core/jni/android_server_BluetoothA2dpService.cpp b/core/jni/android_server_BluetoothA2dpService.cpp
index 8c795af..1851ad6 100644
--- a/core/jni/android_server_BluetoothA2dpService.cpp
+++ b/core/jni/android_server_BluetoothA2dpService.cpp
@@ -61,7 +61,7 @@ static Properties sink_properties[] = {
* Return false if dbus is down, or another serious error (out of memory)
*/
static bool initNative(JNIEnv* env, jobject object) {
- LOGV(__FUNCTION__);
+ LOGV("%s", __FUNCTION__);
#ifdef HAVE_BLUETOOTH
nat = (native_data_t *)calloc(1, sizeof(native_data_t));
if (NULL == nat) {
@@ -88,7 +88,7 @@ static bool initNative(JNIEnv* env, jobject object) {
static void cleanupNative(JNIEnv* env, jobject object) {
#ifdef HAVE_BLUETOOTH
- LOGV(__FUNCTION__);
+ LOGV("%s", __FUNCTION__);
if (nat) {
dbus_connection_close(nat->conn);
env->DeleteGlobalRef(nat->me);
@@ -101,7 +101,7 @@ static void cleanupNative(JNIEnv* env, jobject object) {
static jobjectArray getSinkPropertiesNative(JNIEnv *env, jobject object,
jstring path) {
#ifdef HAVE_BLUETOOTH
- LOGV(__FUNCTION__);
+ LOGV("%s", __FUNCTION__);
if (nat) {
DBusMessage *msg, *reply;
DBusError err;
@@ -132,7 +132,7 @@ static jobjectArray getSinkPropertiesNative(JNIEnv *env, jobject object,
static jboolean connectSinkNative(JNIEnv *env, jobject object, jstring path) {
#ifdef HAVE_BLUETOOTH
- LOGV(__FUNCTION__);
+ LOGV("%s", __FUNCTION__);
if (nat) {
const char *c_path = env->GetStringUTFChars(path, NULL);
int len = env->GetStringLength(path) + 1;
@@ -153,7 +153,7 @@ static jboolean connectSinkNative(JNIEnv *env, jobject object, jstring path) {
static jboolean disconnectSinkNative(JNIEnv *env, jobject object,
jstring path) {
#ifdef HAVE_BLUETOOTH
- LOGV(__FUNCTION__);
+ LOGV("%s", __FUNCTION__);
if (nat) {
const char *c_path = env->GetStringUTFChars(path, NULL);
@@ -171,7 +171,7 @@ static jboolean disconnectSinkNative(JNIEnv *env, jobject object,
static jboolean suspendSinkNative(JNIEnv *env, jobject object,
jstring path) {
#ifdef HAVE_BLUETOOTH
- LOGV(__FUNCTION__);
+ LOGV("%s", __FUNCTION__);
if (nat) {
const char *c_path = env->GetStringUTFChars(path, NULL);
bool ret = dbus_func_args_async(env, nat->conn, -1, NULL, NULL, nat,
@@ -187,7 +187,7 @@ static jboolean suspendSinkNative(JNIEnv *env, jobject object,
static jboolean resumeSinkNative(JNIEnv *env, jobject object,
jstring path) {
#ifdef HAVE_BLUETOOTH
- LOGV(__FUNCTION__);
+ LOGV("%s", __FUNCTION__);
if (nat) {
const char *c_path = env->GetStringUTFChars(path, NULL);
bool ret = dbus_func_args_async(env, nat->conn, -1, NULL, NULL, nat,
@@ -203,7 +203,7 @@ static jboolean resumeSinkNative(JNIEnv *env, jobject object,
static jboolean avrcpVolumeUpNative(JNIEnv *env, jobject object,
jstring path) {
#ifdef HAVE_BLUETOOTH
- LOGV(__FUNCTION__);
+ LOGV("%s", __FUNCTION__);
if (nat) {
const char *c_path = env->GetStringUTFChars(path, NULL);
bool ret = dbus_func_args_async(env, nat->conn, -1, NULL, NULL, nat,
@@ -219,7 +219,7 @@ static jboolean avrcpVolumeUpNative(JNIEnv *env, jobject object,
static jboolean avrcpVolumeDownNative(JNIEnv *env, jobject object,
jstring path) {
#ifdef HAVE_BLUETOOTH
- LOGV(__FUNCTION__);
+ LOGV("%s", __FUNCTION__);
if (nat) {
const char *c_path = env->GetStringUTFChars(path, NULL);
bool ret = dbus_func_args_async(env, nat->conn, -1, NULL, NULL, nat,
@@ -278,7 +278,7 @@ DBusHandlerResult a2dp_event_filter(DBusMessage *msg, JNIEnv *env) {
}
void onConnectSinkResult(DBusMessage *msg, void *user, void *n) {
- LOGV(__FUNCTION__);
+ LOGV("%s", __FUNCTION__);
native_data_t *nat = (native_data_t *)n;
const char *path = (const char *)user;
diff --git a/core/jni/android_server_BluetoothEventLoop.cpp b/core/jni/android_server_BluetoothEventLoop.cpp
index fd12c2d..afaade8 100644
--- a/core/jni/android_server_BluetoothEventLoop.cpp
+++ b/core/jni/android_server_BluetoothEventLoop.cpp
@@ -88,7 +88,7 @@ native_data_t *get_EventLoop_native_data(JNIEnv *env, jobject object) {
#endif
static void classInitNative(JNIEnv* env, jclass clazz) {
- LOGV(__FUNCTION__);
+ LOGV("%s", __FUNCTION__);
#ifdef HAVE_BLUETOOTH
method_onPropertyChanged = env->GetMethodID(clazz, "onPropertyChanged",
@@ -147,7 +147,7 @@ static void classInitNative(JNIEnv* env, jclass clazz) {
}
static void initializeNativeDataNative(JNIEnv* env, jobject object) {
- LOGV(__FUNCTION__);
+ LOGV("%s", __FUNCTION__);
#ifdef HAVE_BLUETOOTH
native_data_t *nat = (native_data_t *)calloc(1, sizeof(native_data_t));
if (NULL == nat) {
@@ -175,7 +175,7 @@ static void initializeNativeDataNative(JNIEnv* env, jobject object) {
}
static void cleanupNativeDataNative(JNIEnv* env, jobject object) {
- LOGV(__FUNCTION__);
+ LOGV("%s", __FUNCTION__);
#ifdef HAVE_BLUETOOTH
native_data_t *nat =
(native_data_t *)env->GetIntField(object, field_mNativeData);
@@ -216,7 +216,7 @@ static short dbus_flags_to_unix_events(unsigned int flags) {
}
static jboolean setUpEventLoop(native_data_t *nat) {
- LOGV(__FUNCTION__);
+ LOGV("%s", __FUNCTION__);
if (nat != NULL && nat->conn != NULL) {
dbus_threads_init_default();
@@ -395,7 +395,7 @@ static int register_agent(native_data_t *nat,
}
static void tearDownEventLoop(native_data_t *nat) {
- LOGV(__FUNCTION__);
+ LOGV("%s", __FUNCTION__);
if (nat != NULL && nat->conn != NULL) {
DBusMessage *msg, *reply;
@@ -1229,7 +1229,7 @@ success:
#ifdef HAVE_BLUETOOTH
void onCreatePairedDeviceResult(DBusMessage *msg, void *user, void *n) {
- LOGV(__FUNCTION__);
+ LOGV("%s", __FUNCTION__);
native_data_t *nat = (native_data_t *)n;
const char *address = (const char *)user;
@@ -1298,7 +1298,7 @@ done:
}
void onCreateDeviceResult(DBusMessage *msg, void *user, void *n) {
- LOGV(__FUNCTION__);
+ LOGV("%s", __FUNCTION__);
native_data_t *nat = (native_data_t *)n;
const char *address= (const char *)user;
@@ -1328,7 +1328,7 @@ void onCreateDeviceResult(DBusMessage *msg, void *user, void *n) {
}
void onDiscoverServicesResult(DBusMessage *msg, void *user, void *n) {
- LOGV(__FUNCTION__);
+ LOGV("%s", __FUNCTION__);
native_data_t *nat = (native_data_t *)n;
const char *path = (const char *)user;
@@ -1354,7 +1354,7 @@ void onDiscoverServicesResult(DBusMessage *msg, void *user, void *n) {
}
void onGetDeviceServiceChannelResult(DBusMessage *msg, void *user, void *n) {
- LOGV(__FUNCTION__);
+ LOGV("%s", __FUNCTION__);
const char *address = (const char *) user;
native_data_t *nat = (native_data_t *) n;
@@ -1387,7 +1387,7 @@ done:
}
void onInputDeviceConnectionResult(DBusMessage *msg, void *user, void *n) {
- LOGV(__FUNCTION__);
+ LOGV("%s", __FUNCTION__);
native_data_t *nat = (native_data_t *)n;
const char *path = (const char *)user;
@@ -1426,7 +1426,7 @@ void onInputDeviceConnectionResult(DBusMessage *msg, void *user, void *n) {
}
void onPanDeviceConnectionResult(DBusMessage *msg, void *user, void *n) {
- LOGV(__FUNCTION__);
+ LOGV("%s", __FUNCTION__);
native_data_t *nat = (native_data_t *)n;
const char *path = (const char *)user;
diff --git a/core/jni/android_server_BluetoothService.cpp b/core/jni/android_server_BluetoothService.cpp
index bf0504f..158e475 100644
--- a/core/jni/android_server_BluetoothService.cpp
+++ b/core/jni/android_server_BluetoothService.cpp
@@ -1,16 +1,16 @@
/*
** Copyright 2006, 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
+** 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
+** 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
+** 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.
*/
@@ -93,7 +93,7 @@ static inline native_data_t * get_native_data(JNIEnv *env, jobject object) {
#endif
static void classInitNative(JNIEnv* env, jclass clazz) {
- LOGV(__FUNCTION__);
+ LOGV("%s", __FUNCTION__);
#ifdef HAVE_BLUETOOTH
field_mNativeData = get_field(env, clazz, "mNativeData", "I");
field_mEventLoop = get_field(env, clazz, "mEventLoop",
@@ -105,7 +105,7 @@ static void classInitNative(JNIEnv* env, jclass clazz) {
* Return false if dbus is down, or another serious error (out of memory)
*/
static bool initializeNativeDataNative(JNIEnv* env, jobject object) {
- LOGV(__FUNCTION__);
+ LOGV("%s", __FUNCTION__);
#ifdef HAVE_BLUETOOTH
native_data_t *nat = (native_data_t *)calloc(1, sizeof(native_data_t));
if (NULL == nat) {
@@ -144,7 +144,7 @@ static const char *get_adapter_path(JNIEnv* env, jobject object) {
// This function is called when the adapter is enabled.
static jboolean setupNativeDataNative(JNIEnv* env, jobject object) {
- LOGV(__FUNCTION__);
+ LOGV("%s", __FUNCTION__);
#ifdef HAVE_BLUETOOTH
native_data_t *nat =
(native_data_t *)env->GetIntField(object, field_mNativeData);
@@ -167,7 +167,7 @@ static jboolean setupNativeDataNative(JNIEnv* env, jobject object) {
}
static jboolean tearDownNativeDataNative(JNIEnv *env, jobject object) {
- LOGV(__FUNCTION__);
+ LOGV("%s", __FUNCTION__);
#ifdef HAVE_BLUETOOTH
native_data_t *nat =
(native_data_t *)env->GetIntField(object, field_mNativeData);
@@ -181,7 +181,7 @@ static jboolean tearDownNativeDataNative(JNIEnv *env, jobject object) {
}
static void cleanupNativeDataNative(JNIEnv* env, jobject object) {
- LOGV(__FUNCTION__);
+ LOGV("%s", __FUNCTION__);
#ifdef HAVE_BLUETOOTH
native_data_t *nat =
(native_data_t *)env->GetIntField(object, field_mNativeData);
@@ -193,7 +193,7 @@ static void cleanupNativeDataNative(JNIEnv* env, jobject object) {
}
static jstring getAdapterPathNative(JNIEnv *env, jobject object) {
- LOGV(__FUNCTION__);
+ LOGV("%s", __FUNCTION__);
#ifdef HAVE_BLUETOOTH
native_data_t *nat = get_native_data(env, object);
if (nat) {
@@ -205,7 +205,7 @@ static jstring getAdapterPathNative(JNIEnv *env, jobject object) {
static jboolean startDiscoveryNative(JNIEnv *env, jobject object) {
- LOGV(__FUNCTION__);
+ LOGV("%s", __FUNCTION__);
#ifdef HAVE_BLUETOOTH
DBusMessage *msg = NULL;
DBusMessage *reply = NULL;
@@ -251,7 +251,7 @@ done:
}
static void stopDiscoveryNative(JNIEnv *env, jobject object) {
- LOGV(__FUNCTION__);
+ LOGV("%s", __FUNCTION__);
#ifdef HAVE_BLUETOOTH
DBusMessage *msg = NULL;
DBusMessage *reply = NULL;
@@ -297,7 +297,7 @@ done:
}
static jbyteArray readAdapterOutOfBandDataNative(JNIEnv *env, jobject object) {
- LOGV(__FUNCTION__);
+ LOGV("%s", __FUNCTION__);
#ifdef HAVE_BLUETOOTH
native_data_t *nat = get_native_data(env, object);
DBusError err;
@@ -338,7 +338,7 @@ static jbyteArray readAdapterOutOfBandDataNative(JNIEnv *env, jobject object) {
static jboolean createPairedDeviceNative(JNIEnv *env, jobject object,
jstring address, jint timeout_ms) {
- LOGV(__FUNCTION__);
+ LOGV("%s", __FUNCTION__);
#ifdef HAVE_BLUETOOTH
native_data_t *nat = get_native_data(env, object);
jobject eventLoop = env->GetObjectField(object, field_mEventLoop);
@@ -374,7 +374,7 @@ static jboolean createPairedDeviceNative(JNIEnv *env, jobject object,
static jboolean createPairedDeviceOutOfBandNative(JNIEnv *env, jobject object,
jstring address, jint timeout_ms) {
- LOGV(__FUNCTION__);
+ LOGV("%s", __FUNCTION__);
#ifdef HAVE_BLUETOOTH
native_data_t *nat = get_native_data(env, object);
jobject eventLoop = env->GetObjectField(object, field_mEventLoop);
@@ -411,7 +411,7 @@ static jint getDeviceServiceChannelNative(JNIEnv *env, jobject object,
jstring path,
jstring pattern, jint attr_id) {
#ifdef HAVE_BLUETOOTH
- LOGV(__FUNCTION__);
+ LOGV("%s", __FUNCTION__);
native_data_t *nat = get_native_data(env, object);
jobject eventLoop = env->GetObjectField(object, field_mEventLoop);
struct event_loop_native_data_t *eventLoopNat =
@@ -437,7 +437,7 @@ static jint getDeviceServiceChannelNative(JNIEnv *env, jobject object,
static jboolean cancelDeviceCreationNative(JNIEnv *env, jobject object,
jstring address) {
- LOGV(__FUNCTION__);
+ LOGV("%s", __FUNCTION__);
jboolean result = JNI_FALSE;
#ifdef HAVE_BLUETOOTH
native_data_t *nat = get_native_data(env, object);
@@ -469,7 +469,7 @@ static jboolean cancelDeviceCreationNative(JNIEnv *env, jobject object,
}
static jboolean removeDeviceNative(JNIEnv *env, jobject object, jstring object_path) {
- LOGV(__FUNCTION__);
+ LOGV("%s", __FUNCTION__);
#ifdef HAVE_BLUETOOTH
native_data_t *nat = get_native_data(env, object);
if (nat) {
@@ -492,7 +492,7 @@ static jboolean removeDeviceNative(JNIEnv *env, jobject object, jstring object_p
static jint enableNative(JNIEnv *env, jobject object) {
#ifdef HAVE_BLUETOOTH
- LOGV(__FUNCTION__);
+ LOGV("%s", __FUNCTION__);
return bt_enable();
#endif
return -1;
@@ -500,7 +500,7 @@ static jint enableNative(JNIEnv *env, jobject object) {
static jint disableNative(JNIEnv *env, jobject object) {
#ifdef HAVE_BLUETOOTH
- LOGV(__FUNCTION__);
+ LOGV("%s", __FUNCTION__);
return bt_disable();
#endif
return -1;
@@ -508,7 +508,7 @@ static jint disableNative(JNIEnv *env, jobject object) {
static jint isEnabledNative(JNIEnv *env, jobject object) {
#ifdef HAVE_BLUETOOTH
- LOGV(__FUNCTION__);
+ LOGV("%s", __FUNCTION__);
return bt_is_enabled();
#endif
return -1;
@@ -518,7 +518,7 @@ static jboolean setPairingConfirmationNative(JNIEnv *env, jobject object,
jstring address, bool confirm,
int nativeData) {
#ifdef HAVE_BLUETOOTH
- LOGV(__FUNCTION__);
+ LOGV("%s", __FUNCTION__);
native_data_t *nat = get_native_data(env, object);
if (nat) {
DBusMessage *msg = (DBusMessage *)nativeData;
@@ -549,7 +549,7 @@ static jboolean setPairingConfirmationNative(JNIEnv *env, jobject object,
static jboolean setPasskeyNative(JNIEnv *env, jobject object, jstring address,
int passkey, int nativeData) {
#ifdef HAVE_BLUETOOTH
- LOGV(__FUNCTION__);
+ LOGV("%s", __FUNCTION__);
native_data_t *nat = get_native_data(env, object);
if (nat) {
DBusMessage *msg = (DBusMessage *)nativeData;
@@ -576,7 +576,7 @@ static jboolean setPasskeyNative(JNIEnv *env, jobject object, jstring address,
static jboolean setRemoteOutOfBandDataNative(JNIEnv *env, jobject object, jstring address,
jbyteArray hash, jbyteArray randomizer, int nativeData) {
#ifdef HAVE_BLUETOOTH
- LOGV(__FUNCTION__);
+ LOGV("%s", __FUNCTION__);
native_data_t *nat = get_native_data(env, object);
if (nat) {
DBusMessage *msg = (DBusMessage *)nativeData;
@@ -610,7 +610,7 @@ static jboolean setRemoteOutOfBandDataNative(JNIEnv *env, jobject object, jstrin
static jboolean setPinNative(JNIEnv *env, jobject object, jstring address,
jstring pin, int nativeData) {
#ifdef HAVE_BLUETOOTH
- LOGV(__FUNCTION__);
+ LOGV("%s", __FUNCTION__);
native_data_t *nat = get_native_data(env, object);
if (nat) {
DBusMessage *msg = (DBusMessage *)nativeData;
@@ -640,7 +640,7 @@ static jboolean setPinNative(JNIEnv *env, jobject object, jstring address,
static jboolean cancelPairingUserInputNative(JNIEnv *env, jobject object,
jstring address, int nativeData) {
#ifdef HAVE_BLUETOOTH
- LOGV(__FUNCTION__);
+ LOGV("%s", __FUNCTION__);
native_data_t *nat = get_native_data(env, object);
if (nat) {
DBusMessage *msg = (DBusMessage *)nativeData;
@@ -666,7 +666,7 @@ static jobjectArray getDevicePropertiesNative(JNIEnv *env, jobject object,
jstring path)
{
#ifdef HAVE_BLUETOOTH
- LOGV(__FUNCTION__);
+ LOGV("%s", __FUNCTION__);
native_data_t *nat = get_native_data(env, object);
if (nat) {
DBusMessage *msg, *reply;
@@ -705,7 +705,7 @@ static jobjectArray getDevicePropertiesNative(JNIEnv *env, jobject object,
static jobjectArray getAdapterPropertiesNative(JNIEnv *env, jobject object) {
#ifdef HAVE_BLUETOOTH
- LOGV(__FUNCTION__);
+ LOGV("%s", __FUNCTION__);
native_data_t *nat = get_native_data(env, object);
if (nat) {
DBusMessage *msg, *reply;
@@ -741,7 +741,7 @@ static jobjectArray getAdapterPropertiesNative(JNIEnv *env, jobject object) {
static jboolean setAdapterPropertyNative(JNIEnv *env, jobject object, jstring key,
void *value, jint type) {
#ifdef HAVE_BLUETOOTH
- LOGV(__FUNCTION__);
+ LOGV("%s", __FUNCTION__);
native_data_t *nat = get_native_data(env, object);
if (nat) {
DBusMessage *msg;
@@ -808,7 +808,7 @@ static jboolean setAdapterPropertyBooleanNative(JNIEnv *env, jobject object, jst
static jboolean setDevicePropertyNative(JNIEnv *env, jobject object, jstring path,
jstring key, void *value, jint type) {
#ifdef HAVE_BLUETOOTH
- LOGV(__FUNCTION__);
+ LOGV("%s", __FUNCTION__);
native_data_t *nat = get_native_data(env, object);
if (nat) {
DBusMessage *reply, *msg;
@@ -863,7 +863,7 @@ static jboolean setDevicePropertyBooleanNative(JNIEnv *env, jobject object,
static jboolean createDeviceNative(JNIEnv *env, jobject object,
jstring address) {
- LOGV(__FUNCTION__);
+ LOGV("%s", __FUNCTION__);
#ifdef HAVE_BLUETOOTH
native_data_t *nat = get_native_data(env, object);
jobject eventLoop = env->GetObjectField(object, field_mEventLoop);
@@ -894,7 +894,7 @@ static jboolean createDeviceNative(JNIEnv *env, jobject object,
static jboolean discoverServicesNative(JNIEnv *env, jobject object,
jstring path, jstring pattern) {
- LOGV(__FUNCTION__);
+ LOGV("%s", __FUNCTION__);
#ifdef HAVE_BLUETOOTH
native_data_t *nat = get_native_data(env, object);
jobject eventLoop = env->GetObjectField(object, field_mEventLoop);
@@ -955,7 +955,7 @@ static jintArray extract_handles(JNIEnv *env, DBusMessage *reply) {
static jintArray addReservedServiceRecordsNative(JNIEnv *env, jobject object,
jintArray uuids) {
- LOGV(__FUNCTION__);
+ LOGV("%s", __FUNCTION__);
#ifdef HAVE_BLUETOOTH
DBusMessage *reply = NULL;
@@ -979,7 +979,7 @@ static jintArray addReservedServiceRecordsNative(JNIEnv *env, jobject object,
static jboolean removeReservedServiceRecordsNative(JNIEnv *env, jobject object,
jintArray handles) {
- LOGV(__FUNCTION__);
+ LOGV("%s", __FUNCTION__);
#ifdef HAVE_BLUETOOTH
native_data_t *nat = get_native_data(env, object);
jint *values = env->GetIntArrayElements(handles, NULL);
@@ -1002,7 +1002,7 @@ static jboolean removeReservedServiceRecordsNative(JNIEnv *env, jobject object,
static jint addRfcommServiceRecordNative(JNIEnv *env, jobject object,
jstring name, jlong uuidMsb, jlong uuidLsb, jshort channel) {
- LOGV(__FUNCTION__);
+ LOGV("%s", __FUNCTION__);
#ifdef HAVE_BLUETOOTH
native_data_t *nat = get_native_data(env, object);
if (nat) {
@@ -1027,7 +1027,7 @@ static jint addRfcommServiceRecordNative(JNIEnv *env, jobject object,
}
static jboolean removeServiceRecordNative(JNIEnv *env, jobject object, jint handle) {
- LOGV(__FUNCTION__);
+ LOGV("%s", __FUNCTION__);
#ifdef HAVE_BLUETOOTH
native_data_t *nat = get_native_data(env, object);
if (nat) {
@@ -1045,7 +1045,7 @@ static jboolean removeServiceRecordNative(JNIEnv *env, jobject object, jint hand
static jboolean setLinkTimeoutNative(JNIEnv *env, jobject object, jstring object_path,
jint num_slots) {
- LOGV(__FUNCTION__);
+ LOGV("%s", __FUNCTION__);
#ifdef HAVE_BLUETOOTH
native_data_t *nat = get_native_data(env, object);
if (nat) {
@@ -1064,7 +1064,7 @@ static jboolean setLinkTimeoutNative(JNIEnv *env, jobject object, jstring object
}
static jboolean connectInputDeviceNative(JNIEnv *env, jobject object, jstring path) {
- LOGV(__FUNCTION__);
+ LOGV("%s", __FUNCTION__);
#ifdef HAVE_BLUETOOTH
native_data_t *nat = get_native_data(env, object);
jobject eventLoop = env->GetObjectField(object, field_mEventLoop);
@@ -1092,7 +1092,7 @@ static jboolean connectInputDeviceNative(JNIEnv *env, jobject object, jstring pa
static jboolean disconnectInputDeviceNative(JNIEnv *env, jobject object,
jstring path) {
- LOGV(__FUNCTION__);
+ LOGV("%s", __FUNCTION__);
#ifdef HAVE_BLUETOOTH
native_data_t *nat = get_native_data(env, object);
jobject eventLoop = env->GetObjectField(object, field_mEventLoop);
@@ -1120,7 +1120,7 @@ static jboolean disconnectInputDeviceNative(JNIEnv *env, jobject object,
static jboolean setBluetoothTetheringNative(JNIEnv *env, jobject object, jboolean value,
jstring src_role, jstring bridge) {
- LOGV(__FUNCTION__);
+ LOGV("%s", __FUNCTION__);
#ifdef HAVE_BLUETOOTH
native_data_t *nat = get_native_data(env, object);
if (nat) {
@@ -1155,7 +1155,7 @@ static jboolean setBluetoothTetheringNative(JNIEnv *env, jobject object, jboolea
static jboolean connectPanDeviceNative(JNIEnv *env, jobject object, jstring path,
jstring dstRole) {
- LOGV(__FUNCTION__);
+ LOGV("%s", __FUNCTION__);
#ifdef HAVE_BLUETOOTH
LOGE("connectPanDeviceNative");
native_data_t *nat = get_native_data(env, object);
@@ -1187,7 +1187,7 @@ static jboolean connectPanDeviceNative(JNIEnv *env, jobject object, jstring path
static jboolean disconnectPanDeviceNative(JNIEnv *env, jobject object,
jstring path) {
- LOGV(__FUNCTION__);
+ LOGV("%s", __FUNCTION__);
#ifdef HAVE_BLUETOOTH
LOGE("disconnectPanDeviceNative");
native_data_t *nat = get_native_data(env, object);
@@ -1217,7 +1217,7 @@ static jboolean disconnectPanDeviceNative(JNIEnv *env, jobject object,
static jboolean disconnectPanServerDeviceNative(JNIEnv *env, jobject object,
jstring path, jstring address,
jstring iface) {
- LOGV(__FUNCTION__);
+ LOGV("%s", __FUNCTION__);
#ifdef HAVE_BLUETOOTH
LOGE("disconnectPanServerDeviceNative");
native_data_t *nat = get_native_data(env, object);
diff --git a/core/jni/android_util_Binder.cpp b/core/jni/android_util_Binder.cpp
index 7a53874..5deed1e 100644
--- a/core/jni/android_util_Binder.cpp
+++ b/core/jni/android_util_Binder.cpp
@@ -31,6 +31,8 @@
#include <binder/IPCThreadState.h>
#include <utils/Log.h>
#include <utils/SystemClock.h>
+#include <utils/List.h>
+#include <utils/KeyedVector.h>
#include <cutils/logger.h>
#include <binder/Parcel.h>
#include <binder/ProcessState.h>
@@ -103,6 +105,7 @@ static struct binderproxy_offsets_t
// Object state.
jfieldID mObject;
jfieldID mSelf;
+ jfieldID mOrgue;
} gBinderProxyOffsets;
@@ -322,25 +325,15 @@ private:
class JavaBBinderHolder : public RefBase
{
public:
- JavaBBinderHolder(JNIEnv* env, jobject object)
- : mObject(object)
- {
- LOGV("Creating JavaBBinderHolder for Object %p\n", object);
- }
- ~JavaBBinderHolder()
- {
- LOGV("Destroying JavaBBinderHolder for Object %p\n", mObject);
- }
-
- sp<JavaBBinder> get(JNIEnv* env)
+ sp<JavaBBinder> get(JNIEnv* env, jobject obj)
{
AutoMutex _l(mLock);
sp<JavaBBinder> b = mBinder.promote();
if (b == NULL) {
- b = new JavaBBinder(env, mObject);
+ b = new JavaBBinder(env, obj);
mBinder = b;
LOGV("Creating JavaBinder %p (refs %p) for Object %p, weakCount=%d\n",
- b.get(), b->getWeakRefs(), mObject, b->getWeakRefs()->getWeakCount());
+ b.get(), b->getWeakRefs(), obj, b->getWeakRefs()->getWeakCount());
}
return b;
@@ -354,20 +347,41 @@ public:
private:
Mutex mLock;
- jobject mObject;
wp<JavaBBinder> mBinder;
};
// ----------------------------------------------------------------------------
+// Per-IBinder death recipient bookkeeping. This is how we reconcile local jobject
+// death recipient references passed in through JNI with the permanent corresponding
+// JavaDeathRecipient objects.
+
+class JavaDeathRecipient;
+
+class DeathRecipientList : public RefBase {
+ List< sp<JavaDeathRecipient> > mList;
+ Mutex mLock;
+
+public:
+ ~DeathRecipientList();
+
+ void add(const sp<JavaDeathRecipient>& recipient);
+ void remove(const sp<JavaDeathRecipient>& recipient);
+ sp<JavaDeathRecipient> find(jobject recipient);
+};
+
+// ----------------------------------------------------------------------------
+
class JavaDeathRecipient : public IBinder::DeathRecipient
{
public:
- JavaDeathRecipient(JNIEnv* env, jobject object)
- : mVM(jnienv_to_javavm(env)), mObject(env->NewGlobalRef(object)),
- mHoldsRef(true)
+ JavaDeathRecipient(JNIEnv* env, jobject object, const sp<DeathRecipientList>& list)
+ : mVM(jnienv_to_javavm(env)), mObject(env->NewGlobalRef(object)), mList(list)
{
- incStrong(this);
+ // These objects manage their own lifetimes so are responsible for final bookkeeping.
+ // The list holds a strong reference to this object.
+ list->add(this);
+
android_atomic_inc(&gNumDeathRefs);
incRefsCreated(env);
}
@@ -391,18 +405,17 @@ public:
void clearReference()
{
- bool release = false;
- mLock.lock();
- if (mHoldsRef) {
- mHoldsRef = false;
- release = true;
- }
- mLock.unlock();
- if (release) {
- decStrong(this);
+ sp<DeathRecipientList> list = mList.promote();
+ if (list != NULL) {
+ list->remove(this);
}
}
+ bool matches(jobject obj) {
+ JNIEnv* env = javavm_to_jnienv(mVM);
+ return env->IsSameObject(obj, mObject);
+ }
+
protected:
virtual ~JavaDeathRecipient()
{
@@ -415,12 +428,54 @@ protected:
private:
JavaVM* const mVM;
jobject const mObject;
- Mutex mLock;
- bool mHoldsRef;
+ wp<DeathRecipientList> mList;
};
// ----------------------------------------------------------------------------
+DeathRecipientList::~DeathRecipientList() {
+ AutoMutex _l(mLock);
+
+ // Should never happen -- the JavaDeathRecipient objects that have added themselves
+ // to the list are holding references on the list object. Only when they are torn
+ // down can the list header be destroyed.
+ if (mList.size() > 0) {
+ LOGE("Retiring DRL %p with extant death recipients\n", this);
+ }
+}
+
+void DeathRecipientList::add(const sp<JavaDeathRecipient>& recipient) {
+ AutoMutex _l(mLock);
+
+ mList.push_back(recipient);
+}
+
+void DeathRecipientList::remove(const sp<JavaDeathRecipient>& recipient) {
+ AutoMutex _l(mLock);
+
+ List< sp<JavaDeathRecipient> >::iterator iter;
+ for (iter = mList.begin(); iter != mList.end(); iter++) {
+ if (*iter == recipient) {
+ mList.erase(iter);
+ return;
+ }
+ }
+}
+
+sp<JavaDeathRecipient> DeathRecipientList::find(jobject recipient) {
+ AutoMutex _l(mLock);
+
+ List< sp<JavaDeathRecipient> >::iterator iter;
+ for (iter = mList.begin(); iter != mList.end(); iter++) {
+ if ((*iter)->matches(recipient)) {
+ return *iter;
+ }
+ }
+ return NULL;
+}
+
+// ----------------------------------------------------------------------------
+
namespace android {
static void proxy_cleanup(const void* id, void* obj, void* cleanupCookie)
@@ -463,7 +518,7 @@ jobject javaObjectForIBinder(JNIEnv* env, const sp<IBinder>& val)
object = env->NewObject(gBinderProxyOffsets.mClass, gBinderProxyOffsets.mConstructor);
if (object != NULL) {
- LOGV("objectForBinder %p: created new %p!\n", val.get(), object);
+ LOGV("objectForBinder %p: created new proxy %p !\n", val.get(), object);
// The proxy holds a reference to the native object.
env->SetIntField(object, gBinderProxyOffsets.mObject, (int)val.get());
val->incStrong(object);
@@ -475,6 +530,11 @@ jobject javaObjectForIBinder(JNIEnv* env, const sp<IBinder>& val)
val->attachObject(&gBinderProxyOffsets, refObject,
jnienv_to_javavm(env), proxy_cleanup);
+ // Also remember the death recipients registered on this proxy
+ sp<DeathRecipientList> drl = new DeathRecipientList;
+ drl->incStrong((void*)javaObjectForIBinder);
+ env->SetIntField(object, gBinderProxyOffsets.mOrgue, reinterpret_cast<jint>(drl.get()));
+
// Note that a new object reference has been created.
android_atomic_inc(&gNumProxyRefs);
incRefsCreated(env);
@@ -490,7 +550,7 @@ sp<IBinder> ibinderForJavaObject(JNIEnv* env, jobject obj)
if (env->IsInstanceOf(obj, gBinderOffsets.mClass)) {
JavaBBinderHolder* jbh = (JavaBBinderHolder*)
env->GetIntField(obj, gBinderOffsets.mObject);
- return jbh != NULL ? jbh->get(env) : NULL;
+ return jbh != NULL ? jbh->get(env, obj) : NULL;
}
if (env->IsInstanceOf(obj, gBinderProxyOffsets.mClass)) {
@@ -621,26 +681,26 @@ static void android_os_Binder_flushPendingCommands(JNIEnv* env, jobject clazz)
IPCThreadState::self()->flushCommands();
}
-static void android_os_Binder_init(JNIEnv* env, jobject clazz)
+static void android_os_Binder_init(JNIEnv* env, jobject obj)
{
- JavaBBinderHolder* jbh = new JavaBBinderHolder(env, clazz);
+ JavaBBinderHolder* jbh = new JavaBBinderHolder();
if (jbh == NULL) {
jniThrowException(env, "java/lang/OutOfMemoryError", NULL);
return;
}
- LOGV("Java Binder %p: acquiring first ref on holder %p", clazz, jbh);
- jbh->incStrong(clazz);
- env->SetIntField(clazz, gBinderOffsets.mObject, (int)jbh);
+ LOGV("Java Binder %p: acquiring first ref on holder %p", obj, jbh);
+ jbh->incStrong((void*)android_os_Binder_init);
+ env->SetIntField(obj, gBinderOffsets.mObject, (int)jbh);
}
-static void android_os_Binder_destroy(JNIEnv* env, jobject clazz)
+static void android_os_Binder_destroy(JNIEnv* env, jobject obj)
{
JavaBBinderHolder* jbh = (JavaBBinderHolder*)
- env->GetIntField(clazz, gBinderOffsets.mObject);
+ env->GetIntField(obj, gBinderOffsets.mObject);
if (jbh != NULL) {
- env->SetIntField(clazz, gBinderOffsets.mObject, 0);
- LOGV("Java Binder %p: removing ref on holder %p", clazz, jbh);
- jbh->decStrong(clazz);
+ env->SetIntField(obj, gBinderOffsets.mObject, 0);
+ LOGV("Java Binder %p: removing ref on holder %p", obj, jbh);
+ jbh->decStrong((void*)android_os_Binder_init);
} else {
// Encountering an uninitialized binder is harmless. All it means is that
// the Binder was only partially initialized when its finalizer ran and called
@@ -648,7 +708,7 @@ static void android_os_Binder_destroy(JNIEnv* env, jobject clazz)
// For example, a Binder subclass constructor might have thrown an exception before
// it could delegate to its superclass's constructor. Consequently init() would
// not have been called and the holder pointer would remain NULL.
- LOGV("Java Binder %p: ignoring uninitialized binder", clazz);
+ LOGV("Java Binder %p: ignoring uninitialized binder", obj);
}
}
@@ -973,8 +1033,10 @@ static void android_os_BinderProxy_linkToDeath(JNIEnv* env, jobject obj,
LOGV("linkToDeath: binder=%p recipient=%p\n", target, recipient);
if (!target->localBinder()) {
- sp<JavaDeathRecipient> jdr = new JavaDeathRecipient(env, recipient);
- status_t err = target->linkToDeath(jdr, recipient, flags);
+ DeathRecipientList* list = (DeathRecipientList*)
+ env->GetIntField(obj, gBinderProxyOffsets.mOrgue);
+ sp<JavaDeathRecipient> jdr = new JavaDeathRecipient(env, recipient, list);
+ status_t err = target->linkToDeath(jdr, NULL, flags);
if (err != NO_ERROR) {
// Failure adding the death recipient, so clear its reference
// now.
@@ -1003,15 +1065,24 @@ static jboolean android_os_BinderProxy_unlinkToDeath(JNIEnv* env, jobject obj,
LOGV("unlinkToDeath: binder=%p recipient=%p\n", target, recipient);
if (!target->localBinder()) {
- wp<IBinder::DeathRecipient> dr;
- status_t err = target->unlinkToDeath(NULL, recipient, flags, &dr);
- if (err == NO_ERROR && dr != NULL) {
- sp<IBinder::DeathRecipient> sdr = dr.promote();
- JavaDeathRecipient* jdr = static_cast<JavaDeathRecipient*>(sdr.get());
- if (jdr != NULL) {
- jdr->clearReference();
+ status_t err = NAME_NOT_FOUND;
+
+ // If we find the matching recipient, proceed to unlink using that
+ DeathRecipientList* list = (DeathRecipientList*)
+ env->GetIntField(obj, gBinderProxyOffsets.mOrgue);
+ sp<JavaDeathRecipient> origJDR = list->find(recipient);
+ if (origJDR != NULL) {
+ wp<IBinder::DeathRecipient> dr;
+ err = target->unlinkToDeath(origJDR, NULL, flags, &dr);
+ if (err == NO_ERROR && dr != NULL) {
+ sp<IBinder::DeathRecipient> sdr = dr.promote();
+ JavaDeathRecipient* jdr = static_cast<JavaDeathRecipient*>(sdr.get());
+ if (jdr != NULL) {
+ jdr->clearReference();
+ }
}
}
+
if (err == NO_ERROR || err == DEAD_OBJECT) {
res = JNI_TRUE;
} else {
@@ -1026,10 +1097,16 @@ static jboolean android_os_BinderProxy_unlinkToDeath(JNIEnv* env, jobject obj,
static void android_os_BinderProxy_destroy(JNIEnv* env, jobject obj)
{
IBinder* b = (IBinder*)
- env->GetIntField(obj, gBinderProxyOffsets.mObject);
- LOGV("Destroying BinderProxy %p: binder=%p\n", obj, b);
+ env->GetIntField(obj, gBinderProxyOffsets.mObject);
+ DeathRecipientList* drl = (DeathRecipientList*)
+ env->GetIntField(obj, gBinderProxyOffsets.mOrgue);
+
+ LOGV("Destroying BinderProxy %p: binder=%p drl=%p\n", obj, b, drl);
env->SetIntField(obj, gBinderProxyOffsets.mObject, 0);
+ env->SetIntField(obj, gBinderProxyOffsets.mOrgue, 0);
+ drl->decStrong((void*)javaObjectForIBinder);
b->decStrong(obj);
+
IPCThreadState::self()->flushCommands();
}
@@ -1080,6 +1157,9 @@ static int int_register_android_os_BinderProxy(JNIEnv* env)
gBinderProxyOffsets.mSelf
= env->GetFieldID(clazz, "mSelf", "Ljava/lang/ref/WeakReference;");
assert(gBinderProxyOffsets.mSelf);
+ gBinderProxyOffsets.mOrgue
+ = env->GetFieldID(clazz, "mOrgue", "I");
+ assert(gBinderProxyOffsets.mOrgue);
return AndroidRuntime::registerNativeMethods(
env, kBinderProxyPathName,
@@ -1152,15 +1232,13 @@ static void android_os_Parcel_writeNative(JNIEnv* env, jobject clazz,
if (parcel == NULL) {
return;
}
- void *dest;
const status_t err = parcel->writeInt32(length);
if (err != NO_ERROR) {
jniThrowException(env, "java/lang/OutOfMemoryError", NULL);
}
- dest = parcel->writeInplace(length);
-
+ void* dest = parcel->writeInplace(length);
if (dest == NULL) {
jniThrowException(env, "java/lang/OutOfMemoryError", NULL);
return;
@@ -1168,7 +1246,7 @@ static void android_os_Parcel_writeNative(JNIEnv* env, jobject clazz,
jbyte* ar = (jbyte*)env->GetPrimitiveArrayCritical((jarray)data, 0);
if (ar) {
- memcpy(dest, ar, length);
+ memcpy(dest, ar + offset, length);
env->ReleasePrimitiveArrayCritical((jarray)data, ar, 0);
}
}
@@ -1424,6 +1502,14 @@ static void android_os_Parcel_closeFileDescriptor(JNIEnv* env, jobject clazz, jo
}
}
+static void android_os_Parcel_clearFileDescriptor(JNIEnv* env, jobject clazz, jobject object)
+{
+ int fd = env->GetIntField(object, gFileDescriptorOffsets.mDescriptor);
+ if (fd >= 0) {
+ env->SetIntField(object, gFileDescriptorOffsets.mDescriptor, -1);
+ }
+}
+
static void android_os_Parcel_freeBuffer(JNIEnv* env, jobject clazz)
{
int32_t own = env->GetIntField(clazz, gParcelOffsets.mOwnObject);
@@ -1623,6 +1709,7 @@ static const JNINativeMethod gParcelMethods[] = {
{"internalReadFileDescriptor", "()Ljava/io/FileDescriptor;", (void*)android_os_Parcel_readFileDescriptor},
{"openFileDescriptor", "(Ljava/lang/String;I)Ljava/io/FileDescriptor;", (void*)android_os_Parcel_openFileDescriptor},
{"closeFileDescriptor", "(Ljava/io/FileDescriptor;)V", (void*)android_os_Parcel_closeFileDescriptor},
+ {"clearFileDescriptor", "(Ljava/io/FileDescriptor;)V", (void*)android_os_Parcel_clearFileDescriptor},
{"freeBuffer", "()V", (void*)android_os_Parcel_freeBuffer},
{"init", "(I)V", (void*)android_os_Parcel_init},
{"destroy", "()V", (void*)android_os_Parcel_destroy},
diff --git a/core/jni/android_view_Display.cpp b/core/jni/android_view_Display.cpp
index ac8835a..160d654 100644
--- a/core/jni/android_view_Display.cpp
+++ b/core/jni/android_view_Display.cpp
@@ -44,6 +44,8 @@ struct offsets_t {
};
static offsets_t offsets;
+static int gShortSize = -1;
+static int gLongSize = -1;
static int gOldSize = -1;
static int gNewSize = -1;
@@ -76,6 +78,10 @@ static jint android_view_Display_getWidth(
{
DisplayID dpy = env->GetIntField(clazz, offsets.display);
jint w = SurfaceComposerClient::getDisplayWidth(dpy);
+ if (gShortSize > 0) {
+ jint h = SurfaceComposerClient::getDisplayHeight(dpy);
+ return w < h ? gShortSize : gLongSize;
+ }
return w == gOldSize ? gNewSize : w;
}
@@ -84,9 +90,27 @@ static jint android_view_Display_getHeight(
{
DisplayID dpy = env->GetIntField(clazz, offsets.display);
int h = SurfaceComposerClient::getDisplayHeight(dpy);
+ if (gShortSize > 0) {
+ jint w = SurfaceComposerClient::getDisplayWidth(dpy);
+ return h < w ? gShortSize : gLongSize;
+ }
return h == gOldSize ? gNewSize : h;
}
+static jint android_view_Display_getRealWidth(
+ JNIEnv* env, jobject clazz)
+{
+ DisplayID dpy = env->GetIntField(clazz, offsets.display);
+ return SurfaceComposerClient::getDisplayWidth(dpy);
+}
+
+static jint android_view_Display_getRealHeight(
+ JNIEnv* env, jobject clazz)
+{
+ DisplayID dpy = env->GetIntField(clazz, offsets.display);
+ return SurfaceComposerClient::getDisplayHeight(dpy);
+}
+
static jint android_view_Display_getOrientation(
JNIEnv* env, jobject clazz)
{
@@ -100,13 +124,6 @@ static jint android_view_Display_getDisplayCount(
return SurfaceComposerClient::getNumberOfDisplays();
}
-static jint android_view_Display_unmapDisplaySize(
- JNIEnv* env, jclass clazz, jint newSize)
-{
- if (newSize == gNewSize) return gOldSize;
- return newSize;
-}
-
// ----------------------------------------------------------------------------
const char* const kClassPathName = "android/view/Display";
@@ -124,10 +141,12 @@ static JNINativeMethod gMethods[] = {
(void*)android_view_Display_getWidth },
{ "getHeight", "()I",
(void*)android_view_Display_getHeight },
+ { "getRealWidth", "()I",
+ (void*)android_view_Display_getRealWidth },
+ { "getRealHeight", "()I",
+ (void*)android_view_Display_getRealHeight },
{ "getOrientation", "()I",
- (void*)android_view_Display_getOrientation },
- { "unmapDisplaySize", "(I)I",
- (void*)android_view_Display_unmapDisplaySize }
+ (void*)android_view_Display_getOrientation }
};
void nativeClassInit(JNIEnv* env, jclass clazz)
@@ -146,7 +165,15 @@ int register_android_view_Display(JNIEnv* env)
int len = property_get("persist.demo.screensizehack", buf, "");
if (len > 0) {
int temp1, temp2;
- if (sscanf(buf, "%d=%d", &temp1, &temp2) == 2) {
+ if (sscanf(buf, "%dx%d", &temp1, &temp2) == 2) {
+ if (temp1 < temp2) {
+ gShortSize = temp1;
+ gLongSize = temp2;
+ } else {
+ gShortSize = temp2;
+ gLongSize = temp1;
+ }
+ } else if (sscanf(buf, "%d=%d", &temp1, &temp2) == 2) {
gOldSize = temp1;
gNewSize = temp2;
}
@@ -157,4 +184,3 @@ int register_android_view_Display(JNIEnv* env)
}
};
-
diff --git a/core/jni/android_view_InputChannel.cpp b/core/jni/android_view_InputChannel.cpp
index 4a4393a..0c2801c 100644
--- a/core/jni/android_view_InputChannel.cpp
+++ b/core/jni/android_view_InputChannel.cpp
@@ -186,9 +186,21 @@ static void android_view_InputChannel_nativeReadFromParcel(JNIEnv* env, jobject
bool isInitialized = parcel->readInt32();
if (isInitialized) {
String8 name = parcel->readString8();
- int32_t ashmemFd = dup(parcel->readFileDescriptor());
- int32_t receivePipeFd = dup(parcel->readFileDescriptor());
- int32_t sendPipeFd = dup(parcel->readFileDescriptor());
+ int32_t parcelAshmemFd = parcel->readFileDescriptor();
+ int32_t ashmemFd = dup(parcelAshmemFd);
+ if (ashmemFd < 0) {
+ LOGE("Error %d dup ashmem fd %d.", errno, parcelAshmemFd);
+ }
+ int32_t parcelReceivePipeFd = parcel->readFileDescriptor();
+ int32_t receivePipeFd = dup(parcelReceivePipeFd);
+ if (receivePipeFd < 0) {
+ LOGE("Error %d dup receive pipe fd %d.", errno, parcelReceivePipeFd);
+ }
+ int32_t parcelSendPipeFd = parcel->readFileDescriptor();
+ int32_t sendPipeFd = dup(parcelSendPipeFd);
+ if (sendPipeFd < 0) {
+ LOGE("Error %d dup send pipe fd %d.", errno, parcelSendPipeFd);
+ }
if (ashmemFd < 0 || receivePipeFd < 0 || sendPipeFd < 0) {
if (ashmemFd >= 0) ::close(ashmemFd);
if (receivePipeFd >= 0) ::close(receivePipeFd);
diff --git a/core/jni/android_view_Surface.cpp b/core/jni/android_view_Surface.cpp
index aa9c107..bd2e669 100644
--- a/core/jni/android_view_Surface.cpp
+++ b/core/jni/android_view_Surface.cpp
@@ -177,7 +177,7 @@ static sp<Surface> getSurface(JNIEnv* env, jobject clazz)
sp<ANativeWindow> android_Surface_getNativeWindow(
JNIEnv* env, jobject clazz) {
- return getSurface(env, clazz).get();
+ return getSurface(env, clazz);
}
static void setSurface(JNIEnv* env, jobject clazz, const sp<Surface>& surface)
@@ -451,7 +451,7 @@ class ScreenshotPixelRef : public SkPixelRef {
public:
ScreenshotPixelRef(SkColorTable* ctable) {
fCTable = ctable;
- ctable->safeRef();
+ SkSafeRef(ctable);
setImmutable();
}
virtual ~ScreenshotPixelRef() {
diff --git a/core/jni/com_google_android_gles_jni_EGLImpl.cpp b/core/jni/com_google_android_gles_jni_EGLImpl.cpp
index 941ed63..e7ea8c8 100644
--- a/core/jni/com_google_android_gles_jni_EGLImpl.cpp
+++ b/core/jni/com_google_android_gles_jni_EGLImpl.cpp
@@ -290,7 +290,7 @@ static void jni_eglCreatePixmapSurface(JNIEnv *_env, jobject _this, jobject out_
return;
}
- ref->safeRef();
+ SkSafeRef(ref);
ref->lockPixels();
egl_native_pixmap_t pixmap;
@@ -310,7 +310,7 @@ static void jni_eglCreatePixmapSurface(JNIEnv *_env, jobject _this, jobject out_
_env->SetIntField(out_sur, gSurface_NativePixelRefFieldID, (int)ref);
} else {
ref->unlockPixels();
- ref->safeUnref();
+ SkSafeUnref(ref);
}
}
@@ -430,7 +430,7 @@ static jboolean jni_eglDestroySurface(JNIEnv *_env, jobject _this, jobject displ
gSurface_NativePixelRefFieldID));
if (ref) {
ref->unlockPixels();
- ref->safeUnref();
+ SkSafeUnref(ref);
}
}
return eglDestroySurface(dpy, sur);
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 1df6fe5..0ad174f 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -35,10 +35,12 @@
<protected-broadcast android:name="android.intent.action.PACKAGE_INSTALL" />
<protected-broadcast android:name="android.intent.action.PACKAGE_ADDED" />
<protected-broadcast android:name="android.intent.action.PACKAGE_REPLACED" />
+ <protected-broadcast android:name="android.intent.action.MY_PACKAGE_REPLACED" />
<protected-broadcast android:name="android.intent.action.PACKAGE_REMOVED" />
<protected-broadcast android:name="android.intent.action.PACKAGE_CHANGED" />
<protected-broadcast android:name="android.intent.action.PACKAGE_RESTARTED" />
<protected-broadcast android:name="android.intent.action.PACKAGE_DATA_CLEARED" />
+ <protected-broadcast android:name="android.intent.action.PACKAGE_FIRST_LAUNCH" />
<protected-broadcast android:name="android.intent.action.UID_REMOVED" />
<protected-broadcast android:name="android.intent.action.CONFIGURATION_CHANGED" />
<protected-broadcast android:name="android.intent.action.LOCALE_CHANGED" />
@@ -82,11 +84,11 @@
<protected-broadcast android:name="android.bluetooth.device.action.PAIRING_REQUEST" />
<protected-broadcast android:name="android.bluetooth.device.action.PAIRING_CANCEL" />
- <protected-broadcast android:name="android.hardware.action.USB_STATE" />
- <protected-broadcast android:name="android.hardware.action.USB_ACCESSORY_ATTACHED" />
- <protected-broadcast android:name="android.hardware.action.USB_ACCESSORY_ATTACHED" />
- <protected-broadcast android:name="android.hardware.action.USB_DEVICE_ATTACHED" />
- <protected-broadcast android:name="android.hardware.action.USB_DEVICE_DETACHED" />
+ <protected-broadcast android:name="android.hardware.usb.action.USB_STATE" />
+ <protected-broadcast android:name="android.hardware.usb.action.USB_ACCESSORY_ATTACHED" />
+ <protected-broadcast android:name="android.hardware.usb.action.USB_ACCESSORY_ATTACHED" />
+ <protected-broadcast android:name="android.hardware.usb.action.USB_DEVICE_ATTACHED" />
+ <protected-broadcast android:name="android.hardware.usb.action.USB_DEVICE_DETACHED" />
<protected-broadcast android:name="android.nfc.action.LLCP_LINK_STATE_CHANGED" />
<protected-broadcast android:name="android.nfc.action.TRANSACTION_DETECTED" />
@@ -464,12 +466,13 @@
android:label="@string/permlab_flashlight"
android:description="@string/permdesc_flashlight" />
- <!-- Allows an application to access USB devices -->
- <permission android:name="android.permission.ACCESS_USB"
+ <!-- Allows an application to manage preferences and permissions for USB devices
+ @hide -->
+ <permission android:name="android.permission.MANAGE_USB"
android:permissionGroup="android.permission-group.HARDWARE_CONTROLS"
- android:protectionLevel="normal"
- android:label="@string/permlab_accessUsb"
- android:description="@string/permdesc_accessUsb" />
+ android:protectionLevel="signatureOrSystem"
+ android:label="@string/permlab_manageUsb"
+ android:description="@string/permdesc_manageUsb" />
<!-- Allows an application to access the MTP USB kernel driver.
For use only by the device side MTP implementation.
@@ -1196,7 +1199,7 @@
<permission android:name="android.permission.PACKAGE_USAGE_STATS"
android:label="@string/permlab_pkgUsageStats"
android:description="@string/permdesc_pkgUsageStats"
- android:protectionLevel="signature" />
+ android:protectionLevel="signatureOrSystem" />
<!-- Allows an application to collect battery statistics -->
<permission android:name="android.permission.BATTERY_STATS"
@@ -1370,11 +1373,18 @@
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</activity>
+
<activity android:name="com.android.internal.app.NetInitiatedActivity"
android:theme="@style/Theme.Holo.Dialog.Alert"
android:excludeFromRecents="true">
</activity>
+ <activity android:name="com.android.server.usb.UsbResolverActivity"
+ android:theme="@style/Theme.Holo.Dialog.Alert"
+ android:finishOnCloseSystemDialogs="true"
+ android:excludeFromRecents="true">
+ </activity>
+
<service android:name="com.android.server.LoadAverageService"
android:exported="true" />
diff --git a/core/res/res/drawable-hdpi/btn_check_off_holo.png b/core/res/res/drawable-hdpi/btn_check_off_holo.png
new file mode 100644
index 0000000..4021a3b
--- /dev/null
+++ b/core/res/res/drawable-hdpi/btn_check_off_holo.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_check_on_holo.png b/core/res/res/drawable-hdpi/btn_check_on_holo.png
new file mode 100644
index 0000000..4c1bfbc
--- /dev/null
+++ b/core/res/res/drawable-hdpi/btn_check_on_holo.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_radio_off_holo.png b/core/res/res/drawable-hdpi/btn_radio_off_holo.png
new file mode 100644
index 0000000..f159c62
--- /dev/null
+++ b/core/res/res/drawable-hdpi/btn_radio_off_holo.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_radio_on_holo.png b/core/res/res/drawable-hdpi/btn_radio_on_holo.png
new file mode 100644
index 0000000..0fcfbe1
--- /dev/null
+++ b/core/res/res/drawable-hdpi/btn_radio_on_holo.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_check_off_holo.png b/core/res/res/drawable-mdpi/btn_check_off_holo.png
new file mode 100644
index 0000000..67d70b4
--- /dev/null
+++ b/core/res/res/drawable-mdpi/btn_check_off_holo.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_check_on_holo.png b/core/res/res/drawable-mdpi/btn_check_on_holo.png
new file mode 100644
index 0000000..38ab51a
--- /dev/null
+++ b/core/res/res/drawable-mdpi/btn_check_on_holo.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_radio_off_holo.png b/core/res/res/drawable-mdpi/btn_radio_off_holo.png
new file mode 100644
index 0000000..ba90d96
--- /dev/null
+++ b/core/res/res/drawable-mdpi/btn_radio_off_holo.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_radio_on_holo.png b/core/res/res/drawable-mdpi/btn_radio_on_holo.png
new file mode 100644
index 0000000..41b603c
--- /dev/null
+++ b/core/res/res/drawable-mdpi/btn_radio_on_holo.png
Binary files differ
diff --git a/core/res/res/layout/webview_select_singlechoice.xml b/core/res/res/layout/webview_select_singlechoice.xml
new file mode 100644
index 0000000..c0753a8
--- /dev/null
+++ b/core/res/res/layout/webview_select_singlechoice.xml
@@ -0,0 +1,30 @@
+<?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.
+-->
+
+<TextView xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@android:id/text1"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:minHeight="?android:attr/listPreferredItemHeight"
+ android:textAppearance="?android:attr/textAppearanceLarge"
+ android:textColor="?android:attr/textColorAlertDialogListItem"
+ android:gravity="center_vertical"
+ android:paddingLeft="12dip"
+ android:paddingRight="7dip"
+ android:ellipsize="marquee"
+ style="?android:attr/spinnerDropDownItemStyle"
+ android:background="?android:attr/activatedBackgroundIndicator"
+/>
diff --git a/core/res/res/values-ar/strings.xml b/core/res/res/values-ar/strings.xml
index f8c6885..6d1f1aa 100644
--- a/core/res/res/values-ar/strings.xml
+++ b/core/res/res/values-ar/strings.xml
@@ -484,8 +484,8 @@
<string name="policydesc_wipeData" product="default" msgid="7669895333814222586">"محو بيانات الهاتف بدون تحذير، وذلك عبر إجراء إعادة الضبط بحسب بيانات المصنع"</string>
<string name="policylab_setGlobalProxy" msgid="2784828293747791446">"تعيين الخادم الوكيل العمومي للجهاز"</string>
<string name="policydesc_setGlobalProxy" msgid="6387497466660154931">"تعيين الخادم الوكيل العمومي للجهاز لكي يتم استخدامه أثناء تمكين السياسة. يعين مشرف الجهاز الأول فقط الخادم الوكيل العمومي الفعال."</string>
- <string name="policylab_expirePassword" msgid="2314569545488269564">"تعيين انتهاء صلاحية كلمة المرور"</string>
- <string name="policydesc_expirePassword" msgid="7276906351852798814">"التحكم في الوقت المستغرق قبل الحاجة إلى تغيير كلمة مرور شاشة التوقف"</string>
+ <!-- outdated translation 4740941403188940274 --> <string name="policylab_expirePassword" msgid="885279151847254056">"تعيين انتهاء صلاحية كلمة المرور"</string>
+ <!-- outdated translation 6626724939177185949 --> <string name="policydesc_expirePassword" msgid="4844430354224822074">"التحكم في الوقت المستغرق قبل الحاجة إلى تغيير كلمة مرور شاشة التوقف"</string>
<string name="policylab_encryptedStorage" msgid="8901326199909132915">"تعيين تشفير التخزين"</string>
<string name="policydesc_encryptedStorage" msgid="2504984732631479399">"طلب تشفير بيانات التطبيق المخزنة"</string>
<string-array name="phoneTypes">
diff --git a/core/res/res/values-bg/strings.xml b/core/res/res/values-bg/strings.xml
index 039ead2..ca36b5c 100644
--- a/core/res/res/values-bg/strings.xml
+++ b/core/res/res/values-bg/strings.xml
@@ -484,8 +484,8 @@
<string name="policydesc_wipeData" product="default" msgid="7669895333814222586">"Изтриване на данните в телефона без предупреждение чрез възстановяване на фабричните настройки"</string>
<string name="policylab_setGlobalProxy" msgid="2784828293747791446">"Задаване на глобален прокси сървър за устройството"</string>
<string name="policydesc_setGlobalProxy" msgid="6387497466660154931">"Задаване на глобалния прокси сървър, който да се използва, когато правилото е активирано. Само първият администратор на устройството задава действителния глобален прокси сървър."</string>
- <string name="policylab_expirePassword" msgid="2314569545488269564">"Срок на валидност на паролата"</string>
- <string name="policydesc_expirePassword" msgid="7276906351852798814">"Контролирайте след колко време трябва да се променя паролата при заключване на екрана"</string>
+ <!-- outdated translation 4740941403188940274 --> <string name="policylab_expirePassword" msgid="885279151847254056">"Задаване на срок на валидност на паролата"</string>
+ <!-- outdated translation 6626724939177185949 --> <string name="policydesc_expirePassword" msgid="4844430354224822074">"Контролирайте след колко време трябва да се променя паролата за заключване на екрана"</string>
<string name="policylab_encryptedStorage" msgid="8901326199909132915">"Шифроване за хранилището"</string>
<string name="policydesc_encryptedStorage" msgid="2504984732631479399">"Изисква съхраняваните данни за приложенията да бъдат шифровани"</string>
<string-array name="phoneTypes">
diff --git a/core/res/res/values-ca/strings.xml b/core/res/res/values-ca/strings.xml
index f88f5de..d506c67 100644
--- a/core/res/res/values-ca/strings.xml
+++ b/core/res/res/values-ca/strings.xml
@@ -484,8 +484,8 @@
<string name="policydesc_wipeData" product="default" msgid="7669895333814222586">"Esborra les dades del telèfon sense advertiment mitjançant un restabliment de les dades de fàbrica"</string>
<string name="policylab_setGlobalProxy" msgid="2784828293747791446">"Defineix el servidor intermediari global del dispositiu"</string>
<string name="policydesc_setGlobalProxy" msgid="6387497466660154931">"Defineix el servidor intermediari global del dispositiu que cal utilitzar mentre la política estigui activada. Només el primer administrador del dispositiu pot definir el servidor intermediari global efectiu."</string>
- <string name="policylab_expirePassword" msgid="2314569545488269564">"Defineix la caducitat de la contrasenya"</string>
- <string name="policydesc_expirePassword" msgid="7276906351852798814">"Controla quant de temps abans de la pantalla de bloqueig cal canviar la contrasenya"</string>
+ <!-- outdated translation 4740941403188940274 --> <string name="policylab_expirePassword" msgid="885279151847254056">"Defineix la caducitat de la contrasenya"</string>
+ <!-- outdated translation 6626724939177185949 --> <string name="policydesc_expirePassword" msgid="4844430354224822074">"Controla quant de temps abans de la pantalla de bloqueig cal canviar la contrasenya"</string>
<string name="policylab_encryptedStorage" msgid="8901326199909132915">"Encriptació d’emmagatzematge"</string>
<string name="policydesc_encryptedStorage" msgid="2504984732631479399">"Requereix que les dades de l\'aplicació emmagatzemades estiguin encriptades"</string>
<string-array name="phoneTypes">
@@ -873,7 +873,7 @@
<string name="date_time_set" msgid="5777075614321087758">"Defineix"</string>
<string name="default_permission_group" msgid="2690160991405646128">"Predeterminat"</string>
<string name="no_permissions" msgid="7283357728219338112">"No cal cap permís"</string>
- <string name="perms_hide" msgid="7283915391320676226"><b>"Oculta"</b></string>
+ <string name="perms_hide" msgid="7283915391320676226"><b>"Oamaga"</b></string>
<string name="perms_show_all" msgid="2671791163933091180"><b>"Mostra\'ls tots"</b></string>
<string name="usb_storage_activity_title" msgid="2399289999608900443">"Emmagatzematge massiu USB"</string>
<string name="usb_storage_title" msgid="5901459041398751495">"USB connectat"</string>
diff --git a/core/res/res/values-cs/strings.xml b/core/res/res/values-cs/strings.xml
index a7c74bc..afc8a2e 100644
--- a/core/res/res/values-cs/strings.xml
+++ b/core/res/res/values-cs/strings.xml
@@ -484,8 +484,8 @@
<string name="policydesc_wipeData" product="default" msgid="7669895333814222586">"Bez upozornění smazat všechna data telefonu obnovením továrních dat"</string>
<string name="policylab_setGlobalProxy" msgid="2784828293747791446">"Nastavit globální proxy server zařízení"</string>
<string name="policydesc_setGlobalProxy" msgid="6387497466660154931">"Vyberte globální proxy server, který se bude používat, když jsou zásady aktivní. Aktuální globální proxy server nastavuje pouze první správce zařízení."</string>
- <string name="policylab_expirePassword" msgid="2314569545488269564">"Nastavit konec platnosti hesla"</string>
- <string name="policydesc_expirePassword" msgid="7276906351852798814">"Ovládání doby, po jejímž uplynutí je nutné změnit heslo pro odemknutí obrazovky"</string>
+ <!-- outdated translation 4740941403188940274 --> <string name="policylab_expirePassword" msgid="885279151847254056">"Nastavit konec platnosti hesla"</string>
+ <!-- outdated translation 6626724939177185949 --> <string name="policydesc_expirePassword" msgid="4844430354224822074">"Ovládání doby, po jejímž uplynutí je nutné změnit heslo pro odemknutí obrazovky"</string>
<string name="policylab_encryptedStorage" msgid="8901326199909132915">"Nastavit šifrování úložiště"</string>
<string name="policydesc_encryptedStorage" msgid="2504984732631479399">"Požadovat šifrování ukládaných dat"</string>
<string-array name="phoneTypes">
diff --git a/core/res/res/values-da/strings.xml b/core/res/res/values-da/strings.xml
index b29307d..3e283fc 100644
--- a/core/res/res/values-da/strings.xml
+++ b/core/res/res/values-da/strings.xml
@@ -484,8 +484,8 @@
<string name="policydesc_wipeData" product="default" msgid="7669895333814222586">"Slet telefonens data uden varsel ved at gendanne fabriksindstillinger"</string>
<string name="policylab_setGlobalProxy" msgid="2784828293747791446">"Angiv enhedens globale proxy"</string>
<string name="policydesc_setGlobalProxy" msgid="6387497466660154931">"Angiv enhedens globale proxy, der skal bruges, mens politikken er aktiveret. Kun den første enhedsadministrator angiver den effektive globale proxy."</string>
- <string name="policylab_expirePassword" msgid="2314569545488269564">"Indstil udløb for adgangskode"</string>
- <string name="policydesc_expirePassword" msgid="7276906351852798814">"Kontroller, hvor lang tid der skal gå, før adgangskoden til skærmlåsen skal ændres."</string>
+ <!-- outdated translation 4740941403188940274 --> <string name="policylab_expirePassword" msgid="885279151847254056">"Angiv udløb for adgangskode"</string>
+ <!-- outdated translation 6626724939177185949 --> <string name="policydesc_expirePassword" msgid="4844430354224822074">"Kontroller, hvor lang tid der skal gå, før adgangskoden til skærmlåsen skal ændres."</string>
<string name="policylab_encryptedStorage" msgid="8901326199909132915">"Angiv kryptering af lager"</string>
<string name="policydesc_encryptedStorage" msgid="2504984732631479399">"Kræv, at gemte programdata krypteres"</string>
<string-array name="phoneTypes">
diff --git a/core/res/res/values-de/strings.xml b/core/res/res/values-de/strings.xml
index 3961b9f..ccee3d0 100644
--- a/core/res/res/values-de/strings.xml
+++ b/core/res/res/values-de/strings.xml
@@ -484,8 +484,8 @@
<string name="policydesc_wipeData" product="default" msgid="7669895333814222586">"Auf Werkseinstellungen zurücksetzen und Daten auf dem Telefon ohne Warnung löschen"</string>
<string name="policylab_setGlobalProxy" msgid="2784828293747791446">"Den globalen Proxy des Geräts festlegen"</string>
<string name="policydesc_setGlobalProxy" msgid="6387497466660154931">"Den globalen Proxy des Geräts zur Verwendung während der Aktivierung der Richtlinie festlegen. Nur der erste Geräteadministrator kann den gültigen globalen Proxy festlegen."</string>
- <string name="policylab_expirePassword" msgid="2314569545488269564">"Ablauf des Passworts festlegen"</string>
- <string name="policydesc_expirePassword" msgid="7276906351852798814">"Zeitraum bis zur Änderung des Passworts für die Bildschirmsperre festlegen"</string>
+ <!-- outdated translation 4740941403188940274 --> <string name="policylab_expirePassword" msgid="885279151847254056">"Ablauf des Passworts festlegen"</string>
+ <!-- outdated translation 6626724939177185949 --> <string name="policydesc_expirePassword" msgid="4844430354224822074">"Zeitraum bis zur Änderung des Passworts für die Bildschirmsperre festlegen"</string>
<string name="policylab_encryptedStorage" msgid="8901326199909132915">"Speicherverschlüsselung"</string>
<string name="policydesc_encryptedStorage" msgid="2504984732631479399">"Anforderung, dass gespeicherte Anwendungsdaten verschlüsselt werden"</string>
<string-array name="phoneTypes">
@@ -659,7 +659,7 @@
<string name="factorytest_failed" msgid="5410270329114212041">"Werkstest fehlgeschlagen"</string>
<string name="factorytest_not_system" msgid="4435201656767276723">"Die Aktion FACTORY_TEST wird nur für unter \"/system/app\" gespeicherte Pakete unterstützt."</string>
<string name="factorytest_no_action" msgid="872991874799998561">"Es wurden kein Paket mit der Aktion FACTORY_TEST gefunden."</string>
- <string name="factorytest_reboot" msgid="6320168203050791643">"Neu booten"</string>
+ <string name="factorytest_reboot" msgid="6320168203050791643">"Neustart"</string>
<string name="js_dialog_title" msgid="8143918455087008109">"Die Seite auf \'<xliff:g id="TITLE">%s</xliff:g>\' sagt:"</string>
<string name="js_dialog_title_default" msgid="6961903213729667573">"JavaScript"</string>
<string name="js_dialog_before_unload" msgid="1901675448179653089">"Von dieser Seite navigieren?"\n\n"<xliff:g id="MESSAGE">%s</xliff:g>"\n\n"Wählen Sie \"OK\", um fortzufahren, oder wählen Sie \"Abbrechen\", um auf der aktuellen Seite zu bleiben."</string>
@@ -683,7 +683,7 @@
<string name="save_password_message" msgid="767344687139195790">"Möchten Sie, dass der Browser dieses Passwort speichert?"</string>
<string name="save_password_notnow" msgid="6389675316706699758">"Nicht jetzt"</string>
<string name="save_password_remember" msgid="6491879678996749466">"Speichern"</string>
- <string name="save_password_never" msgid="8274330296785855105">"Niemals"</string>
+ <string name="save_password_never" msgid="8274330296785855105">"Nie"</string>
<string name="open_permission_deny" msgid="5661861460947222274">"Sie sind zum Öffnen dieser Seite nicht berechtigt."</string>
<string name="text_copied" msgid="4985729524670131385">"Text in Zwischenablage kopiert."</string>
<string name="more_item_label" msgid="4650918923083320495">"Mehr"</string>
diff --git a/core/res/res/values-el/strings.xml b/core/res/res/values-el/strings.xml
index e1c2c39..edcb213 100644
--- a/core/res/res/values-el/strings.xml
+++ b/core/res/res/values-el/strings.xml
@@ -484,8 +484,8 @@
<string name="policydesc_wipeData" product="default" msgid="7669895333814222586">"Διαγραφή των δεδομένων του τηλεφώνου χωρίς προειδοποίηση με επαναφορά των εργοστασιακών δεδομένων"</string>
<string name="policylab_setGlobalProxy" msgid="2784828293747791446">"Ρύθμιση του γενικού διακομιστή μεσολάβησης της συσκευής"</string>
<string name="policydesc_setGlobalProxy" msgid="6387497466660154931">"Ορίστε τη χρήση του γενικού διακομιστή μεσολάβησης της συσκευής όταν είναι ενεργοποιημένη η πολιτική. Μόνο ο διαχειριστής της πρώτης συσκευής ορίζει τον ισχύοντα γενικό διακομιστή μεσολάβησης."</string>
- <string name="policylab_expirePassword" msgid="2314569545488269564">"Ορισμός λήξης κωδ. πρόσβασης"</string>
- <string name="policydesc_expirePassword" msgid="7276906351852798814">"Ελέγξτε πόσος χρόνος απομένει προτού πρέπει να αλλάξετε τον κωδικό πρόσβασης κλειδώματος της οθόνης"</string>
+ <!-- outdated translation 4740941403188940274 --> <string name="policylab_expirePassword" msgid="885279151847254056">"Ορισμός λήξης κωδικού πρόσβασης"</string>
+ <!-- outdated translation 6626724939177185949 --> <string name="policydesc_expirePassword" msgid="4844430354224822074">"Ελέγξτε πόσος χρόνος απομένει προτού πρέπει να αλλάξετε τον κωδικό πρόσβασης κλειδώματος της οθόνης"</string>
<string name="policylab_encryptedStorage" msgid="8901326199909132915">"Ορισμός κρυπτογρ. αποθ. χώρου"</string>
<string name="policydesc_encryptedStorage" msgid="2504984732631479399">"Να απαιτείται η κρυπτογράφηση των αποθηκευμένων δεδομένων εφαρμογής"</string>
<string-array name="phoneTypes">
diff --git a/core/res/res/values-en-rGB/strings.xml b/core/res/res/values-en-rGB/strings.xml
index 0ee0e50..b8f624e 100644
--- a/core/res/res/values-en-rGB/strings.xml
+++ b/core/res/res/values-en-rGB/strings.xml
@@ -484,8 +484,8 @@
<string name="policydesc_wipeData" product="default" msgid="7669895333814222586">"Erase the phone\'s data without warning by performing a factory data reset"</string>
<string name="policylab_setGlobalProxy" msgid="2784828293747791446">"Set the device global proxy"</string>
<string name="policydesc_setGlobalProxy" msgid="6387497466660154931">"Set the device\'s global proxy to be used while policy is enabled. Only the first device admin sets the effective global proxy."</string>
- <string name="policylab_expirePassword" msgid="2314569545488269564">"Set password expiry"</string>
- <string name="policydesc_expirePassword" msgid="7276906351852798814">"Control how long before lock-screen password needs to be changed"</string>
+ <!-- outdated translation 4740941403188940274 --> <string name="policylab_expirePassword" msgid="885279151847254056">"Set password expiry"</string>
+ <!-- outdated translation 6626724939177185949 --> <string name="policydesc_expirePassword" msgid="4844430354224822074">"Control how long before lock-screen password needs to be changed"</string>
<string name="policylab_encryptedStorage" msgid="8901326199909132915">"Set storage encryption"</string>
<string name="policydesc_encryptedStorage" msgid="2504984732631479399">"Require that stored application data be encrypted"</string>
<string-array name="phoneTypes">
diff --git a/core/res/res/values-es-rUS/strings.xml b/core/res/res/values-es-rUS/strings.xml
index aac30d3..35d425b 100644
--- a/core/res/res/values-es-rUS/strings.xml
+++ b/core/res/res/values-es-rUS/strings.xml
@@ -484,8 +484,8 @@
<string name="policydesc_wipeData" product="default" msgid="7669895333814222586">"Borrar los datos del teléfono sin advertencias al restablecer la configuración original"</string>
<string name="policylab_setGlobalProxy" msgid="2784828293747791446">"Configura el proxy global de dispositivo"</string>
<string name="policydesc_setGlobalProxy" msgid="6387497466660154931">"Configuración del proxy global de dispositivo que se utilizará mientras se habilita la política. Sólo la primera administración de dispositivo configura el proxy global efectivo."</string>
- <string name="policylab_expirePassword" msgid="2314569545488269564">"Establecer la caducidad de la contraseña"</string>
- <string name="policydesc_expirePassword" msgid="7276906351852798814">"Verifica cuánto tiempo antes debes cambiar la contraseña de la pantalla de bloqueo"</string>
+ <!-- outdated translation 4740941403188940274 --> <string name="policylab_expirePassword" msgid="885279151847254056">"Establecer la caducidad de la contraseña"</string>
+ <!-- outdated translation 6626724939177185949 --> <string name="policydesc_expirePassword" msgid="4844430354224822074">"Verifica cuánto tiempo antes debes cambiar la contraseña de la pantalla de bloqueo"</string>
<string name="policylab_encryptedStorage" msgid="8901326199909132915">"Establecer la encriptación del almacenamiento"</string>
<string name="policydesc_encryptedStorage" msgid="2504984732631479399">"Requiere que los datos almacenados de la aplicación estén encriptados"</string>
<string-array name="phoneTypes">
diff --git a/core/res/res/values-es/strings.xml b/core/res/res/values-es/strings.xml
index 51bbd3c..41fa758 100644
--- a/core/res/res/values-es/strings.xml
+++ b/core/res/res/values-es/strings.xml
@@ -125,10 +125,10 @@
<string name="contentServiceSync" msgid="8353523060269335667">"Sincronización"</string>
<string name="contentServiceSyncNotificationTitle" msgid="397743349191901458">"Sincronización"</string>
<string name="contentServiceTooManyDeletesNotificationDesc" msgid="8100981435080696431">"Demasiadas eliminaciones de <xliff:g id="CONTENT_TYPE">%s</xliff:g>"</string>
- <string name="low_memory" product="tablet" msgid="2292820184396262278">"Se ha agotado el espacio de almacenamiento de la tableta. Elimina algunos archivos para liberar espacio."</string>
+ <string name="low_memory" product="tablet" msgid="2292820184396262278">"Se ha agotado el espacio de almacenamiento del tablet. Elimina algunos archivos para liberar espacio."</string>
<string name="low_memory" product="default" msgid="6632412458436461203">"Se ha agotado el espacio de almacenamiento del teléfono. Elimina algunos archivos para liberar espacio."</string>
<string name="me" msgid="6545696007631404292">"Yo"</string>
- <string name="power_dialog" product="tablet" msgid="8545351420865202853">"Opciones de tableta"</string>
+ <string name="power_dialog" product="tablet" msgid="8545351420865202853">"Opciones del tablet"</string>
<string name="power_dialog" product="default" msgid="1319919075463988638">"Opciones del teléfono"</string>
<string name="silent_mode" msgid="7167703389802618663">"Modo silencio"</string>
<string name="turn_on_radio" msgid="3912793092339962371">"Activar conexión inalámbrica"</string>
@@ -136,12 +136,12 @@
<string name="screen_lock" msgid="799094655496098153">"Bloqueo de pantalla"</string>
<string name="power_off" msgid="4266614107412865048">"Apagar"</string>
<string name="shutdown_progress" msgid="2281079257329981203">"Apagando..."</string>
- <string name="shutdown_confirm" product="tablet" msgid="3385745179555731470">"La tableta se apagará."</string>
+ <string name="shutdown_confirm" product="tablet" msgid="3385745179555731470">"El tablet se apagará."</string>
<string name="shutdown_confirm" product="default" msgid="649792175242821353">"El teléfono se apagará."</string>
<string name="shutdown_confirm_question" msgid="6656441286856415014">"¿Quieres apagar el teléfono?"</string>
<string name="recent_tasks_title" msgid="3691764623638127888">"Reciente"</string>
<string name="no_recent_tasks" msgid="279702952298056674">"No hay aplicaciones recientes"</string>
- <string name="global_actions" product="tablet" msgid="408477140088053665">"Opciones de tableta"</string>
+ <string name="global_actions" product="tablet" msgid="408477140088053665">"Opciones del tablet"</string>
<string name="global_actions" product="default" msgid="2406416831541615258">"Opciones del teléfono"</string>
<string name="global_action_lock" msgid="2844945191792119712">"Bloqueo de pantalla"</string>
<string name="global_action_power_off" msgid="4471879440839879722">"Apagar"</string>
@@ -159,7 +159,7 @@
<string name="permgrouplab_messages" msgid="7521249148445456662">"Tus mensajes"</string>
<string name="permgroupdesc_messages" msgid="7045736972019211994">"Leer y escribir SMS, mensajes de correo electrónico y otros mensajes"</string>
<string name="permgrouplab_personalInfo" msgid="3519163141070533474">"Tu información personal"</string>
- <string name="permgroupdesc_personalInfo" product="tablet" msgid="6975389054186265786">"Accede directamente al calendario y a los contactos almacenados en la tableta."</string>
+ <string name="permgroupdesc_personalInfo" product="tablet" msgid="6975389054186265786">"Accede directamente al calendario y a los contactos almacenados en el tablet."</string>
<string name="permgroupdesc_personalInfo" product="default" msgid="5488050357388806068">"Acceso directo al calendario y a los contactos almacenados en el teléfono"</string>
<string name="permgrouplab_location" msgid="635149742436692049">"Tu ubicación"</string>
<string name="permgroupdesc_location" msgid="2430258821648348660">"Controlar su ubicación física"</string>
@@ -193,10 +193,10 @@
<string name="permlab_sendSms" msgid="5600830612147671529">"enviar mensajes SMS"</string>
<string name="permdesc_sendSms" msgid="1946540351763502120">"Permite que la aplicación envíe mensajes SMS. Es posible que tengas que pagar si las aplicaciones malintencionadas envían mensajes sin tu confirmación."</string>
<string name="permlab_readSms" msgid="4085333708122372256">"leer SMS o MMS"</string>
- <string name="permdesc_readSms" product="tablet" msgid="5836710350295631545">"Permite que la aplicación lea mensajes SMS almacenados en la tableta o en la tarjeta SIM. Las aplicaciones malintencionadas pueden leer los mensajes confidenciales."</string>
+ <string name="permdesc_readSms" product="tablet" msgid="5836710350295631545">"Permite que la aplicación lea mensajes SMS almacenados en el tablet o en la tarjeta SIM. Las aplicaciones malintencionadas pueden leer los mensajes confidenciales."</string>
<string name="permdesc_readSms" product="default" msgid="3002170087197294591">"Permite que la aplicación lea mensajes SMS almacenados en el teléfono o en la tarjeta SIM. Las aplicaciones malintencionadas pueden leer los mensajes confidenciales."</string>
<string name="permlab_writeSms" msgid="6881122575154940744">"editar SMS o MMS"</string>
- <string name="permdesc_writeSms" product="tablet" msgid="5332124772918835437">"Permite que la aplicación escriba en mensajes SMS almacenados en la tableta o en la tarjeta SIM. Las aplicaciones malintencionadas pueden borrar los mensajes."</string>
+ <string name="permdesc_writeSms" product="tablet" msgid="5332124772918835437">"Permite que la aplicación escriba en mensajes SMS almacenados en el tablet o en la tarjeta SIM. Las aplicaciones malintencionadas pueden borrar los mensajes."</string>
<string name="permdesc_writeSms" product="default" msgid="6299398896177548095">"Permite que la aplicación escriba en mensajes SMS almacenados en el teléfono o en la tarjeta SIM. Las aplicaciones malintencionadas pueden borrar los mensajes."</string>
<string name="permlab_receiveWapPush" msgid="8258226427716551388">"recibir WAP"</string>
<string name="permdesc_receiveWapPush" msgid="5979623826128082171">"Permite que la aplicación reciba y procese mensajes WAP. Las aplicaciones malintencionadas pueden controlar los mensajes o eliminarlos sin mostrarlos al usuario."</string>
@@ -247,7 +247,7 @@
<string name="permlab_manageAppTokens" msgid="17124341698093865">"administrar tokens de aplicación"</string>
<string name="permdesc_manageAppTokens" msgid="977127907524195988">"Permite que las aplicaciones creen y administren sus propios tokens, ignorando su orden z normal. Nunca debería ser necesario para las aplicaciones normales."</string>
<string name="permlab_injectEvents" msgid="1378746584023586600">"pulsar teclas y botones de control"</string>
- <string name="permdesc_injectEvents" product="tablet" msgid="7200014808195664505">"Permite que la aplicación proporcione sus propios eventos de entrada (pulsación de teclas, etc.) a otras aplicaciones. Las aplicaciones malintencionadas pueden utilizar este permiso para controlar la tableta."</string>
+ <string name="permdesc_injectEvents" product="tablet" msgid="7200014808195664505">"Permite que la aplicación proporcione sus propios eventos de entrada (pulsación de teclas, etc.) a otras aplicaciones. Las aplicaciones malintencionadas pueden utilizar este permiso para controlar el tablet."</string>
<string name="permdesc_injectEvents" product="default" msgid="3946098050410874715">"Permite que la aplicación proporcione sus propios eventos de entrada (pulsación de teclas, etc.) a otras aplicaciones. Las aplicaciones malintencionadas pueden utilizar este permiso para controlar el teléfono."</string>
<string name="permlab_readInputState" msgid="469428900041249234">"registrar lo que se escribe y las acciones que se realizan"</string>
<string name="permdesc_readInputState" msgid="5132879321450325445">"Permite que las aplicaciones observen las teclas que pulsas incluso cuando interactúas con otra aplicación (como, por ejemplo, al introducir una contraseña). No debería ser necesario nunca para las aplicaciones normales."</string>
@@ -276,17 +276,17 @@
<string name="permlab_installPackages" msgid="335800214119051089">"instalar aplicaciones directamente"</string>
<string name="permdesc_installPackages" msgid="526669220850066132">"Permite que una aplicación instale paquetes Android nuevos o actualizados. Las aplicaciones malintencionadas pueden utilizar este permiso para añadir aplicaciones nuevas con permisos arbitrariamente potentes."</string>
<string name="permlab_clearAppCache" msgid="4747698311163766540">"eliminar todos los datos de caché de la aplicación"</string>
- <string name="permdesc_clearAppCache" product="tablet" msgid="3097119797652477973">"Permite que una aplicación libere espacio de almacenamiento en la tableta mediante la eliminación de archivos del directorio de caché de la aplicación. El acceso está muy restringido (limitado normalmente al proceso del sistema)."</string>
+ <string name="permdesc_clearAppCache" product="tablet" msgid="3097119797652477973">"Permite que una aplicación libere espacio de almacenamiento en el tablet mediante la eliminación de archivos del directorio de caché de la aplicación. El acceso está muy restringido (limitado normalmente al proceso del sistema)."</string>
<string name="permdesc_clearAppCache" product="default" msgid="7740465694193671402">"Permite que una aplicación libere espacio de almacenamiento en el teléfono mediante la eliminación de archivos en el directorio de caché de la aplicación. El acceso al proceso del sistema suele estar muy restringido."</string>
<string name="permlab_movePackage" msgid="728454979946503926">"Mover recursos de aplicaciones"</string>
<string name="permdesc_movePackage" msgid="6323049291923925277">"Permite que una aplicación mueva los recursos de aplicaciones de un medio interno a otro externo y viceversa."</string>
<string name="permlab_readLogs" msgid="6615778543198967614">"leer datos de registro personales"</string>
- <string name="permdesc_readLogs" product="tablet" msgid="4077356893924755294">"Permite que una aplicación lea diversos archivos de registro del sistema. Con este permiso, la aplicación puede ver información general sobre las acciones que se realizan con la tableta (que puede incluir datos personales o privados)."</string>
+ <string name="permdesc_readLogs" product="tablet" msgid="4077356893924755294">"Permite que una aplicación lea diversos archivos de registro del sistema. Con este permiso, la aplicación puede ver información general sobre las acciones que se realizan con el tablet (que puede incluir datos personales o privados)."</string>
<string name="permdesc_readLogs" product="default" msgid="8896449437464867766">"Permite que una aplicación lea distintos archivos de registro del sistema. Con este permiso, la aplicación puede ver información general sobre las acciones que realizas con el teléfono, que puede incluir datos personales o privados."</string>
<string name="permlab_diagnostic" msgid="8076743953908000342">"leer/escribir en los recursos propiedad del grupo de diagnóstico"</string>
<string name="permdesc_diagnostic" msgid="3121238373951637049">"Permite que una aplicación lea y escriba en cualquier recurso propiedad del grupo de diagnóstico como, por ejemplo, archivos in/dev. Este permiso podría afectar a la seguridad y estabilidad del sistema. SÓLO se debe utilizar para diagnósticos específicos de hardware realizados por el fabricante o el operador."</string>
<string name="permlab_changeComponentState" msgid="79425198834329406">"habilitar o inhabilitar componentes de la aplicación"</string>
- <string name="permdesc_changeComponentState" product="tablet" msgid="4647419365510068321">"Permite que una aplicación cambie si un componente de otra aplicación está habilitado o inhabilitado. Las aplicaciones malintencionadas pueden utilizar este permiso para inhabilitar funciones importantes de la tableta. Este permiso se debe utilizar con precaución, ya que es posible que los componentes se vuelvan inservibles, inconsistentes o inestables."</string>
+ <string name="permdesc_changeComponentState" product="tablet" msgid="4647419365510068321">"Permite que una aplicación cambie si un componente de otra aplicación está habilitado o inhabilitado. Las aplicaciones malintencionadas pueden utilizar este permiso para inhabilitar funciones importantes del tablet. Este permiso se debe utilizar con precaución, ya que es posible que los componentes se vuelvan inservibles, inconsistentes o inestables."</string>
<string name="permdesc_changeComponentState" product="default" msgid="3443473726140080761">"Permite que una aplicación cambie si un componente de otra aplicación está habilitado o inhabilitado. Las aplicaciones malintencionadas pueden utilizar este permiso para inhabilitar funciones importantes del teléfono. Este permiso se debe utilizar con precaución, ya que es posible que los componentes se vuelvan inservibles, inconsistentes o inestables."</string>
<string name="permlab_setPreferredApplications" msgid="3393305202145172005">"establecer aplicaciones preferidas"</string>
<string name="permdesc_setPreferredApplications" msgid="760008293501937546">"Permite que una aplicación modifique las aplicaciones preferidas del usuario. De esta forma, las aplicaciones malintencionadas pueden cambiar de forma silenciosa las aplicaciones que se están ejecutando, falsificando las aplicaciones existentes para recopilar datos privados del usuario."</string>
@@ -297,19 +297,19 @@
<string name="permlab_writeGservices" msgid="2149426664226152185">"modificar la asignación de servicios de Google"</string>
<string name="permdesc_writeGservices" msgid="6602362746516676175">"Permite que una aplicación modifique la asignación de servicios de Google. No está destinado al uso por parte de aplicaciones normales."</string>
<string name="permlab_receiveBootCompleted" msgid="7776779842866993377">"ejecutar automáticamente al iniciar"</string>
- <string name="permdesc_receiveBootCompleted" product="tablet" msgid="7530977064379338199">"Permite que una aplicación se ejecute automáticamente en cuanto se haya terminado de iniciar el sistema. Esto puede hacer que la tableta tarde más en iniciarse y permite que la aplicación ralentice el funcionamiento global de la tableta al ejecutarse continuamente."</string>
+ <string name="permdesc_receiveBootCompleted" product="tablet" msgid="7530977064379338199">"Permite que una aplicación se ejecute automáticamente en cuanto se haya terminado de iniciar el sistema. Esto puede hacer que el tablet tarde más en iniciarse y permite que la aplicación ralentice el funcionamiento global del tablet al ejecutarse continuamente."</string>
<string name="permdesc_receiveBootCompleted" product="default" msgid="698336728415008796">"Permite que una aplicación se ejecute automáticamente en cuanto se haya terminado de iniciar el sistema. Esto puede provocar que el teléfono tarde más en iniciarse y permite que la aplicación ralentice el funcionamiento global del teléfono al ejecutarse continuamente."</string>
<string name="permlab_broadcastSticky" msgid="7919126372606881614">"enviar emisión persistente"</string>
- <string name="permdesc_broadcastSticky" product="tablet" msgid="6322249605930062595">"Permite que una aplicación envíe emisiones persistentes que permanecen en el teléfono una vez que la emisión finaliza. Las aplicaciones malintencionadas pueden ralentizar la tableta o volverla inestable al hacer que emplee demasiada memoria."</string>
+ <string name="permdesc_broadcastSticky" product="tablet" msgid="6322249605930062595">"Permite que una aplicación envíe emisiones persistentes que permanecen en el tablet una vez que la emisión finaliza. Las aplicaciones malintencionadas pueden ralentizar el tablet o volverlo inestable al hacer que emplee demasiada memoria."</string>
<string name="permdesc_broadcastSticky" product="default" msgid="1920045289234052219">"Permite que una aplicación envíe emisiones persistentes, que permanecen en el teléfono una vez que la emisión finaliza. Las aplicaciones malintencionadas pueden ralentizar el teléfono o volverlo inestable al hacer que emplee demasiada memoria."</string>
<string name="permlab_readContacts" msgid="6219652189510218240">"leer los datos de contacto"</string>
- <string name="permdesc_readContacts" product="tablet" msgid="7596158687301157686">"Permite que una aplicación lea todos los datos de contacto (direcciones) almacenados en la tableta. Las aplicaciones malintencionadas pueden utilizar este permiso para enviar tus datos a otras personas."</string>
+ <string name="permdesc_readContacts" product="tablet" msgid="7596158687301157686">"Permite que una aplicación lea todos los datos de contacto (direcciones) almacenados en el tablet. Las aplicaciones malintencionadas pueden utilizar este permiso para enviar tus datos a otras personas."</string>
<string name="permdesc_readContacts" product="default" msgid="3371591512896545975">"Permite que una aplicación lea todos los datos de contacto (direcciones) almacenados en el teléfono. Las aplicaciones malintencionadas pueden utilizar este permiso para enviar tus datos a otras personas."</string>
<string name="permlab_writeContacts" msgid="644616215860933284">"escribir datos de contacto"</string>
- <string name="permdesc_writeContacts" product="tablet" msgid="7782689510038568495">"Permite que una aplicación modifique los datos de contacto (direcciones) almacenados en la tableta. Las aplicaciones malintencionadas pueden utilizar este permiso para borrar o modificar los datos de contacto."</string>
+ <string name="permdesc_writeContacts" product="tablet" msgid="7782689510038568495">"Permite que una aplicación modifique los datos de contacto (direcciones) almacenados en el tablet. Las aplicaciones malintencionadas pueden utilizar este permiso para borrar o modificar los datos de contacto."</string>
<string name="permdesc_writeContacts" product="default" msgid="3924383579108183601">"Permite que una aplicación modifique los datos de contacto (direcciones) almacenados en el teléfono. Las aplicaciones malintencionadas pueden utilizar este permiso para borrar o modificar tus datos de contacto."</string>
<string name="permlab_readCalendar" msgid="6898987798303840534">"leer eventos de calendario"</string>
- <string name="permdesc_readCalendar" product="tablet" msgid="5905870265734599678">"Permite que una aplicación lea todos los eventos de calendario almacenados en la tableta. Las aplicaciones malintencionadas pueden utilizar este permiso para enviar tus eventos de calendario a otras personas."</string>
+ <string name="permdesc_readCalendar" product="tablet" msgid="5905870265734599678">"Permite que una aplicación lea todos los eventos de calendario almacenados en el tablet. Las aplicaciones malintencionadas pueden utilizar este permiso para enviar tus eventos de calendario a otras personas."</string>
<string name="permdesc_readCalendar" product="default" msgid="5533029139652095734">"Permite que una aplicación lea todos los eventos de calendario almacenados en el teléfono. Las aplicaciones malintencionadas pueden utilizar este permiso para enviar tus eventos de calendario a otras personas."</string>
<string name="permlab_writeCalendar" msgid="3894879352594904361">"añadir o modificar eventos de calendario y enviar mensajes de correo electrónico a los invitados"</string>
<string name="permdesc_writeCalendar" msgid="2988871373544154221">"Permite que una aplicación añada o modifique los eventos de tu calendario, que puede enviar mensajes de correo electrónico a los invitados. Las aplicaciones malintencionadas pueden utilizar este permiso para borrar o modificar tus eventos de calendario o para enviar mensajes a los invitados."</string>
@@ -320,10 +320,10 @@
<string name="permlab_installLocationProvider" msgid="6578101199825193873">"permiso para instalar un proveedor de ubicación"</string>
<string name="permdesc_installLocationProvider" msgid="5449175116732002106">"Crear fuentes de origen simuladas para realizar pruebas. Las aplicaciones malintencionadas pueden utilizar este permiso para sobrescribir la ubicación o el estado devueltos por orígenes de ubicación reales, tales como los proveedores de red o GPS, o para controlar y notificar tu ubicación a una fuente externa."</string>
<string name="permlab_accessFineLocation" msgid="8116127007541369477">"precisar la ubicación (GPS)"</string>
- <string name="permdesc_accessFineLocation" product="tablet" msgid="243973693233359681">"Permite acceder a fuentes de ubicación precisas como, por ejemplo, el sistema de posicionamiento global, en la tableta, si hay alguna disponible. Las aplicaciones malintencionadas pueden utilizar este permiso para determinar la ubicación del usuario y pueden consumir batería adicional."</string>
+ <string name="permdesc_accessFineLocation" product="tablet" msgid="243973693233359681">"Permite acceder a fuentes de ubicación precisas como, por ejemplo, el sistema de posicionamiento global, en el tablet, si hay alguna disponible. Las aplicaciones malintencionadas pueden utilizar este permiso para determinar la ubicación del usuario y pueden consumir batería adicional."</string>
<string name="permdesc_accessFineLocation" product="default" msgid="7411213317434337331">"Permite precisar las fuentes de ubicación como, por ejemplo, el sistema de posicionamiento global, en el teléfono, en los casos en que estén disponibles. Las aplicaciones malintencionadas pueden utilizar este permiso para determinar dónde se encuentra el usuario y pueden consumir batería adicional."</string>
<string name="permlab_accessCoarseLocation" msgid="4642255009181975828">"ubicación común (basada en red)"</string>
- <string name="permdesc_accessCoarseLocation" product="tablet" msgid="3704633168985466045">"Permite acceder a fuentes de ubicación comunes como, por ejemplo, la base de datos de la red de telefonía móvil, para determinar la ubicación aproximada de una tableta, si hay alguna disponible. Las aplicaciones malintencionadas pueden utilizar este permiso para determinar tu ubicación aproximada."</string>
+ <string name="permdesc_accessCoarseLocation" product="tablet" msgid="3704633168985466045">"Permite acceder a fuentes de ubicación comunes como, por ejemplo, la base de datos de la red de telefonía móvil, para determinar la ubicación aproximada de un tablet, si hay alguna disponible. Las aplicaciones malintencionadas pueden utilizar este permiso para determinar tu ubicación aproximada."</string>
<string name="permdesc_accessCoarseLocation" product="default" msgid="8235655958070862293">"Acceder a fuentes de ubicación comunes como, por ejemplo, la base de datos de red de un teléfono móvil, para determinar una ubicación telefónica aproximada, en los casos en que esté disponible. Las aplicaciones malintencionadas pueden utilizar este permiso para determinar dónde te encuentras aproximadamente."</string>
<string name="permlab_accessSurfaceFlinger" msgid="2363969641792388947">"acceder a SurfaceFlinger"</string>
<string name="permdesc_accessSurfaceFlinger" msgid="6805241830020733025">"Permite que la aplicación utilice funciones de SurfaceFlinger de nivel inferior."</string>
@@ -335,13 +335,13 @@
<string name="permdesc_recordAudio" msgid="6493228261176552356">"Permite que la aplicación acceda a la ruta de grabación de audio."</string>
<string name="permlab_camera" msgid="3616391919559751192">"realizar fotografías y vídeos"</string>
<string name="permdesc_camera" msgid="6004878235852154239">"Permite que la aplicación realice fotografías y vídeos con la cámara. De este modo, puede recopilar en cualquier momento las imágenes que ve la cámara."</string>
- <string name="permlab_brick" product="tablet" msgid="2961292205764488304">"inhabilitar tableta de forma permanente"</string>
+ <string name="permlab_brick" product="tablet" msgid="2961292205764488304">"inhabilitar tablet de forma permanente"</string>
<string name="permlab_brick" product="default" msgid="8337817093326370537">"inhabilitar el teléfono de forma permanente"</string>
- <string name="permdesc_brick" product="tablet" msgid="7379164636920817963">"Permite que la aplicación inhabilite todas las funciones de la tableta de forma permanente. Este permiso es muy peligroso."</string>
+ <string name="permdesc_brick" product="tablet" msgid="7379164636920817963">"Permite que la aplicación inhabilite todas las funciones del tablet de forma permanente. Este permiso es muy peligroso."</string>
<string name="permdesc_brick" product="default" msgid="5569526552607599221">"Permite que la aplicación inhabilite todas las funciones del teléfono de forma permanente. Este permiso es muy peligroso."</string>
- <string name="permlab_reboot" product="tablet" msgid="3436634972561795002">"forzar reinicio de la tableta"</string>
+ <string name="permlab_reboot" product="tablet" msgid="3436634972561795002">"forzar reinicio del tablet"</string>
<string name="permlab_reboot" product="default" msgid="2898560872462638242">"forzar reinicio del teléfono"</string>
- <string name="permdesc_reboot" product="tablet" msgid="4555793623560701557">"Permite que la aplicación fuerce a la tableta a reiniciarse."</string>
+ <string name="permdesc_reboot" product="tablet" msgid="4555793623560701557">"Permite que la aplicación fuerce al tablet a reiniciarse."</string>
<string name="permdesc_reboot" product="default" msgid="7914933292815491782">"Permite que la aplicación fuerce al teléfono a reiniciarse."</string>
<string name="permlab_mount_unmount_filesystems" msgid="1761023272170956541">"activar y desactivar sistemas de archivos"</string>
<string name="permdesc_mount_unmount_filesystems" msgid="6253263792535859767">"Permite que las aplicaciones activen y desactiven sistemas de archivos para un almacenamiento extraíble."</string>
@@ -371,7 +371,7 @@
<string name="permdesc_callPhone" msgid="3369867353692722456">"Permite que la aplicación llame a números de teléfono sin la intervención del usuario. Las aplicaciones malintencionadas pueden originar llamadas inesperadas en la factura telefónica. Ten en cuenta que con este permiso la aplicación no puede realizar llamadas a números de emergencia."</string>
<string name="permlab_callPrivileged" msgid="4198349211108497879">"llamar directamente a cualquier número de teléfono"</string>
<string name="permdesc_callPrivileged" msgid="244405067160028452">"Permite que la aplicación llame a cualquier número de teléfono, incluidos los números de emergencia, sin que el usuario intervenga. Las aplicaciones malintencionadas pueden realizar llamadas innecesarias e ilícitas a los servicios de emergencias."</string>
- <string name="permlab_performCdmaProvisioning" product="tablet" msgid="4842576994144604821">"iniciar directamente el método de acceso CDMA de la tableta"</string>
+ <string name="permlab_performCdmaProvisioning" product="tablet" msgid="4842576994144604821">"iniciar directamente el método de acceso CDMA del tablet"</string>
<string name="permlab_performCdmaProvisioning" product="default" msgid="5604848095315421425">"iniciar directamente el método de acceso CDMA del teléfono"</string>
<string name="permdesc_performCdmaProvisioning" msgid="6457447676108355905">"Permite que la aplicación inicie el método de acceso CDMA. Las aplicaciones malintencionadas pueden iniciar el método CDMA de forma innecesaria."</string>
<string name="permlab_locationUpdates" msgid="7785408253364335740">"controlar las notificaciones de actualización de la ubicación"</string>
@@ -384,16 +384,16 @@
<string name="permdesc_modifyPhoneState" msgid="3302284561346956587">"Permite que la aplicación controle las funciones de teléfono del dispositivo. Una aplicación con este permiso puede cambiar redes, activar y desactivar la señal móvil, etc., sin necesidad de notificar al usuario."</string>
<string name="permlab_readPhoneState" msgid="2326172951448691631">"leer la identidad y el estado del teléfono"</string>
<string name="permdesc_readPhoneState" msgid="188877305147626781">"Permite que la aplicación acceda a las funciones de teléfono del dispositivo. Una aplicación con este permiso puede determinar el número de teléfono y el número de serie de este teléfono, si una llamada está activa, el número al que está vinculada esa llamada, etc."</string>
- <string name="permlab_wakeLock" product="tablet" msgid="1531731435011495015">"impedir que la tableta entre en modo de suspensión"</string>
+ <string name="permlab_wakeLock" product="tablet" msgid="1531731435011495015">"impedir que el tablet entre en modo de suspensión"</string>
<string name="permlab_wakeLock" product="default" msgid="573480187941496130">"impedir que el teléfono entre en modo de suspensión"</string>
- <string name="permdesc_wakeLock" product="tablet" msgid="4032181488045338551">"Permite que una aplicación impida que la tableta entre en modo de suspensión."</string>
+ <string name="permdesc_wakeLock" product="tablet" msgid="4032181488045338551">"Permite que una aplicación impida que el tablet entre en modo de suspensión."</string>
<string name="permdesc_wakeLock" product="default" msgid="7584036471227467099">"Permite que una aplicación impida que el teléfono entre en modo de suspensión."</string>
- <string name="permlab_devicePower" product="tablet" msgid="2787034722616350417">"encender o apagar la tableta"</string>
+ <string name="permlab_devicePower" product="tablet" msgid="2787034722616350417">"encender o apagar el tablet"</string>
<string name="permlab_devicePower" product="default" msgid="4928622470980943206">"encender o apagar el teléfono"</string>
- <string name="permdesc_devicePower" product="tablet" msgid="3853773100100451905">"Permite que la aplicación active o desactive la tableta."</string>
+ <string name="permdesc_devicePower" product="tablet" msgid="3853773100100451905">"Permite que la aplicación active o desactive el tablet."</string>
<string name="permdesc_devicePower" product="default" msgid="4577331933252444818">"Permite que la aplicación active o desactive el teléfono."</string>
<string name="permlab_factoryTest" msgid="3715225492696416187">"ejecutar en modo de prueba de fábrica"</string>
- <string name="permdesc_factoryTest" product="tablet" msgid="3952059318359653091">"Permite la ejecución como prueba de fabricante de nivel inferior, lo que posibilita un acceso completo al hardware de la tableta. Sólo está disponible cuando una tableta se está ejecutando en modo de prueba."</string>
+ <string name="permdesc_factoryTest" product="tablet" msgid="3952059318359653091">"Permite la ejecución como prueba de fabricante de nivel inferior, lo que posibilita un acceso completo al hardware del tablet. Solo está disponible cuando un tablet se está ejecutando en modo de prueba."</string>
<string name="permdesc_factoryTest" product="default" msgid="8136644990319244802">"Ejecutar como prueba de fabricante de nivel inferior, permitiendo un acceso íntegro al hardware del teléfono. Sólo está disponible cuando un teléfono se está ejecutando en modo de prueba."</string>
<string name="permlab_setWallpaper" msgid="6627192333373465143">"establecer fondo de pantalla"</string>
<string name="permdesc_setWallpaper" msgid="6417041752170585837">"Permite que la aplicación establezca el fondo de pantalla del sistema."</string>
@@ -402,15 +402,15 @@
<string name="permlab_masterClear" msgid="2315750423139697397">"restablecer el sistema a los valores predeterminados de fábrica"</string>
<string name="permdesc_masterClear" msgid="5033465107545174514">"Permite que una aplicación restablezca por completo el sistema a su configuración de fábrica, borrando todos los datos, la configuración y las aplicaciones instaladas."</string>
<string name="permlab_setTime" msgid="2021614829591775646">"establecer hora"</string>
- <string name="permdesc_setTime" product="tablet" msgid="209693136361006073">"Permite que una aplicación cambie la hora del reloj de la tableta."</string>
+ <string name="permdesc_setTime" product="tablet" msgid="209693136361006073">"Permite que una aplicación cambie la hora del reloj del tablet."</string>
<string name="permdesc_setTime" product="default" msgid="667294309287080045">"Permite que una aplicación cambie la hora del reloj del teléfono."</string>
<string name="permlab_setTimeZone" msgid="2945079801013077340">"establecer zona horaria"</string>
- <string name="permdesc_setTimeZone" product="tablet" msgid="2522877107613885139">"Permite que una aplicación cambie la zona horaria de la tableta."</string>
+ <string name="permdesc_setTimeZone" product="tablet" msgid="2522877107613885139">"Permite que una aplicación cambie la zona horaria del tablet."</string>
<string name="permdesc_setTimeZone" product="default" msgid="1902540227418179364">"Permite que una aplicación cambie la zona horaria del teléfono."</string>
<string name="permlab_accountManagerService" msgid="4829262349691386986">"actuar como servicio de administrador de cuentas"</string>
<string name="permdesc_accountManagerService" msgid="6056903274106394752">"Permite que una aplicación realice llamadas a los autenticadores de cuentas."</string>
<string name="permlab_getAccounts" msgid="4549918644233460103">"ver cuentas reconocidas"</string>
- <string name="permdesc_getAccounts" product="tablet" msgid="857622793935544694">"Permite que una aplicación obtenga una lista de cuentas reconocidas por la tableta."</string>
+ <string name="permdesc_getAccounts" product="tablet" msgid="857622793935544694">"Permite que una aplicación obtenga una lista de cuentas reconocidas por el tablet."</string>
<string name="permdesc_getAccounts" product="default" msgid="6839262446413155394">"Permite que una aplicación obtenga una lista de cuentas reconocidas por el teléfono."</string>
<string name="permlab_authenticateAccounts" msgid="3940505577982882450">"actuar como autenticador de cuentas"</string>
<string name="permdesc_authenticateAccounts" msgid="4006839406474208874">"Permite que una aplicación utilice las funciones de autenticador de cuentas del administrador de cuentas, incluida la creación de cuentas y la obtención y el establecimiento de sus contraseñas."</string>
@@ -437,10 +437,10 @@
<string name="permlab_changeWifiMulticastState" msgid="1368253871483254784">"permitir recepción multidifusión Wi-Fi"</string>
<string name="permdesc_changeWifiMulticastState" msgid="8199464507656067553">"Permite que una aplicación reciba paquetes no dirigidos directamente a tu dispositivo. Esta función puede resultar útil para descubrir servicios cercanos. Utiliza más energía que el modo de no multidifusión."</string>
<string name="permlab_bluetoothAdmin" msgid="1092209628459341292">"administración de Bluetooth"</string>
- <string name="permdesc_bluetoothAdmin" product="tablet" msgid="3511795757324345837">"Permite que una aplicación configure la tableta Bluetooth local, vea dispositivos remotos y sincronice el teléfono con ellos."</string>
+ <string name="permdesc_bluetoothAdmin" product="tablet" msgid="3511795757324345837">"Permite que una aplicación configure el tablet Bluetooth local, vea dispositivos remotos y sincronice el tablet con ellos."</string>
<string name="permdesc_bluetoothAdmin" product="default" msgid="7256289774667054555">"Permite que una aplicación configure el teléfono Bluetooth local, y vea dispositivos remotos y sincronice el teléfono con ellos."</string>
<string name="permlab_bluetooth" msgid="8361038707857018732">"crear conexiones de Bluetooth"</string>
- <string name="permdesc_bluetooth" product="tablet" msgid="4191941825910543803">"Permite que una aplicación vea la configuración de la tableta Bluetooth local, y cree y acepte conexiones con los dispositivos sincronizados."</string>
+ <string name="permdesc_bluetooth" product="tablet" msgid="4191941825910543803">"Permite que una aplicación vea la configuración del tablet Bluetooth local, y cree y acepte conexiones con los dispositivos sincronizados."</string>
<string name="permdesc_bluetooth" product="default" msgid="762515380679392945">"Permite que una aplicación vea la configuración del teléfono Bluetooth local, y cree y acepte conexiones con los dispositivos sincronizados."</string>
<string name="permlab_nfc" msgid="4423351274757876953">"controlar Comunicación de campo cercano (NFC)"</string>
<string name="permdesc_nfc" msgid="9171401851954407226">"Permite que la aplicación se comunique con lectores, tarjetas y etiquetas de Comunicación de campo cercano (NFC)."</string>
@@ -473,19 +473,19 @@
<string name="policylab_limitPassword" msgid="4497420728857585791">"Establecimiento de reglas de contraseña"</string>
<string name="policydesc_limitPassword" msgid="9083400080861728056">"Control de la longitud y de los caracteres permitidos en las contraseñas de bloqueo de pantalla"</string>
<string name="policylab_watchLogin" msgid="914130646942199503">"Control de intentos de bloqueo de pantalla"</string>
- <string name="policydesc_watchLogin" product="tablet" msgid="933601759466308092">"Controla el número de contraseñas incorrectas introducidas al desbloquear la pantalla, bloquea la tableta o borra todos los datos de la tableta si se introducen demasiadas contraseñas incorrectas."</string>
+ <string name="policydesc_watchLogin" product="tablet" msgid="933601759466308092">"Controla el número de contraseñas incorrectas introducidas al desbloquear la pantalla, bloquea el tablet o borra todos los datos del tablet si se introducen demasiadas contraseñas incorrectas."</string>
<string name="policydesc_watchLogin" product="default" msgid="7227578260165172673">"Control del número de contraseñas incorrectas introducidas al desbloquear la pantalla, así como bloqueo del teléfono o borrado de todos los datos si se introducen demasiadas contraseñas incorrectas"</string>
<string name="policylab_resetPassword" msgid="2620077191242688955">"Modificación de contraseña de bloqueo de pantalla"</string>
<string name="policydesc_resetPassword" msgid="5391240616981297361">"Modificación de contraseña de bloqueo de pantalla"</string>
<string name="policylab_forceLock" msgid="2274085384704248431">"Bloqueo de pantalla"</string>
<string name="policydesc_forceLock" msgid="5696964126226028442">"Control de la forma en que se bloquea la pantalla y del momento en que se bloquea"</string>
<string name="policylab_wipeData" msgid="3910545446758639713">"Borrar todos los datos"</string>
- <string name="policydesc_wipeData" product="tablet" msgid="314455232799486222">"Borrado de los datos de la tableta sin avisar restableciendo datos de fábrica"</string>
+ <string name="policydesc_wipeData" product="tablet" msgid="314455232799486222">"Borrado de los datos del tablet sin avisar restableciendo datos de fábrica"</string>
<string name="policydesc_wipeData" product="default" msgid="7669895333814222586">"Borrado de los datos del teléfono sin avisar restableciendo datos de fábrica"</string>
<string name="policylab_setGlobalProxy" msgid="2784828293747791446">"Definir el servidor proxy global"</string>
<string name="policydesc_setGlobalProxy" msgid="6387497466660154931">"Define el servidor proxy global que se debe utilizar mientras la política esté habilitada. Solo el primer administrador de dispositivos define el servidor proxy global efectivo."</string>
- <string name="policylab_expirePassword" msgid="2314569545488269564">"Definir caducidad contraseña"</string>
- <string name="policydesc_expirePassword" msgid="7276906351852798814">"Permite controlar cuándo se debe cambiar la contraseña de bloqueo de la pantalla."</string>
+ <!-- outdated translation 4740941403188940274 --> <string name="policylab_expirePassword" msgid="885279151847254056">"Definir caducidad de contraseña"</string>
+ <!-- outdated translation 6626724939177185949 --> <string name="policydesc_expirePassword" msgid="4844430354224822074">"Permite controlar cuándo se debe cambiar la contraseña de bloqueo de la pantalla."</string>
<string name="policylab_encryptedStorage" msgid="8901326199909132915">"Encriptación de almacenamiento"</string>
<string name="policydesc_encryptedStorage" msgid="2504984732631479399">"Exige que se encripten los datos de la aplicación almacenados."</string>
<string-array name="phoneTypes">
@@ -623,7 +623,7 @@
<string name="lockscreen_battery_short" msgid="3617549178603354656">"<xliff:g id="NUMBER">%d</xliff:g> <xliff:g id="PERCENT">%%</xliff:g>"</string>
<string name="lockscreen_low_battery" msgid="1482873981919249740">"Conecta el cargador"</string>
<string name="lockscreen_missing_sim_message_short" msgid="7381499217732227295">"Falta la tarjeta SIM"</string>
- <string name="lockscreen_missing_sim_message" product="tablet" msgid="151659196095791474">"No se ha insertado ninguna tarjeta SIM en la tableta."</string>
+ <string name="lockscreen_missing_sim_message" product="tablet" msgid="151659196095791474">"No se ha insertado ninguna tarjeta SIM en el tablet."</string>
<string name="lockscreen_missing_sim_message" product="default" msgid="2186920585695169078">"No se ha insertado ninguna tarjeta SIM en el teléfono."</string>
<string name="lockscreen_missing_sim_instructions" msgid="8874620818937719067">"Inserta una tarjeta SIM"</string>
<string name="emergency_calls_only" msgid="6733978304386365407">"Solo llamadas de emergencia"</string>
@@ -635,7 +635,7 @@
<string name="lockscreen_too_many_failed_attempts_dialog_message" msgid="3514742106066877476">"Has realizado <xliff:g id="NUMBER_0">%d</xliff:g> intentos fallidos de creación de un patrón de desbloqueo. "\n\n"Inténtalo de nuevo dentro de <xliff:g id="NUMBER_1">%d</xliff:g> segundos."</string>
<string name="lockscreen_too_many_failed_password_attempts_dialog_message" msgid="4906034376425175381">"Has introducido una contraseña incorrecta <xliff:g id="NUMBER_0">%d</xliff:g> veces. "\n\n"Inténtalo de nuevo dentro de <xliff:g id="NUMBER_1">%d</xliff:g> segundos."</string>
<string name="lockscreen_too_many_failed_pin_attempts_dialog_message" msgid="6827749231465145590">"Has introducido un PIN incorrecto <xliff:g id="NUMBER_0">%d</xliff:g> veces. "\n\n"Inténtalo de nuevo dentro de <xliff:g id="NUMBER_1">%d</xliff:g> segundos."</string>
- <string name="lockscreen_failed_attempts_almost_glogin" product="tablet" msgid="8687762517114904651">"Has realizado <xliff:g id="NUMBER_0">%d</xliff:g> intentos fallidos de creación del patrón de desbloqueo. Si realizas <xliff:g id="NUMBER_1">%d</xliff:g> intentos fallidos más, se te pedirá que desbloquees la tableta con tus credenciales de acceso de Google."\n\n" Espera <xliff:g id="NUMBER_2">%d</xliff:g> segundos e inténtalo de nuevo."</string>
+ <string name="lockscreen_failed_attempts_almost_glogin" product="tablet" msgid="8687762517114904651">"Has realizado <xliff:g id="NUMBER_0">%d</xliff:g> intentos fallidos de creación del patrón de desbloqueo. Si realizas <xliff:g id="NUMBER_1">%d</xliff:g> intentos fallidos más, se te pedirá que desbloquees el tablet con tus credenciales de acceso de Google."\n\n" Espera <xliff:g id="NUMBER_2">%d</xliff:g> segundos e inténtalo de nuevo."</string>
<string name="lockscreen_failed_attempts_almost_glogin" product="default" msgid="3351013842320127827">"Has realizado <xliff:g id="NUMBER_0">%d</xliff:g> intentos fallidos de creación del patrón de desbloqueo. Si realizas <xliff:g id="NUMBER_1">%d</xliff:g> intentos fallidos más, se te pedirá que desbloquees el teléfono con tus credenciales de acceso de Google."\n\n" Espera <xliff:g id="NUMBER_2">%d</xliff:g> segundos e inténtalo de nuevo."</string>
<string name="lockscreen_too_many_failed_attempts_countdown" msgid="6251480343394389665">"Espera <xliff:g id="NUMBER">%d</xliff:g> segundos y vuelve a intentarlo."</string>
<string name="lockscreen_forgot_pattern_button_text" msgid="2626999449610695930">"¿Has olvidado el patrón?"</string>
@@ -674,7 +674,7 @@
<string name="permlab_readHistoryBookmarks" msgid="1284843728203412135">"leer información de marcadores y del historial del navegador"</string>
<string name="permdesc_readHistoryBookmarks" msgid="4981489815467617191">"Permite que la aplicación lea todas las URL que ha visitado el navegador y todos sus marcadores."</string>
<string name="permlab_writeHistoryBookmarks" msgid="9009434109836280374">"escribir en marcadores y en el historial del navegador"</string>
- <string name="permdesc_writeHistoryBookmarks" product="tablet" msgid="7193514090469945307">"Permite que una aplicación modifique la información de los marcadores o del historial del navegador almacenada en la tableta. Las aplicaciones malintencionadas pueden utilizar este permiso para borrar o modificar los datos del navegador."</string>
+ <string name="permdesc_writeHistoryBookmarks" product="tablet" msgid="7193514090469945307">"Permite que una aplicación modifique la información de los marcadores o del historial del navegador almacenada en el tablet. Las aplicaciones malintencionadas pueden utilizar este permiso para borrar o modificar los datos del navegador."</string>
<string name="permdesc_writeHistoryBookmarks" product="default" msgid="945571990357114950">"Permite que una aplicación modifique la información de los marcadores o del historial del navegador almacenada en el teléfono. Las aplicaciones malintencionadas pueden utilizar este permiso para borrar o modificar los datos del navegador."</string>
<string name="permlab_setAlarm" msgid="5924401328803615165">"establecer alarma en un reloj"</string>
<string name="permdesc_setAlarm" msgid="5966966598149875082">"Permite a la aplicación establecer una alarma en una aplicación de reloj instalada. Es posible que algunas aplicaciones de reloj no incluyan esta función."</string>
@@ -800,7 +800,7 @@
<string name="inputMethod" msgid="1653630062304567879">"Método de introducción de texto"</string>
<string name="editTextMenuTitle" msgid="4909135564941815494">"Acciones de texto"</string>
<string name="low_internal_storage_view_title" msgid="1399732408701697546">"Poco espacio"</string>
- <string name="low_internal_storage_view_text" product="tablet" msgid="4231085657068852042">"Se está agotando el espacio de almacenamiento de la tableta."</string>
+ <string name="low_internal_storage_view_text" product="tablet" msgid="4231085657068852042">"Se está agotando el espacio de almacenamiento del tablet."</string>
<string name="low_internal_storage_view_text" product="default" msgid="635106544616378836">"Se está agotando el espacio de almacenamiento del teléfono."</string>
<string name="ok" msgid="5970060430562524910">"Aceptar"</string>
<string name="cancel" msgid="6442560571259935130">"Cancelar"</string>
diff --git a/core/res/res/values-fa/strings.xml b/core/res/res/values-fa/strings.xml
index fe06a32..fa74391 100644
--- a/core/res/res/values-fa/strings.xml
+++ b/core/res/res/values-fa/strings.xml
@@ -484,8 +484,8 @@
<string name="policydesc_wipeData" product="default" msgid="7669895333814222586">"پاک کردن داده های گوشی بدون هشدار با انجام یک عملکرد بازنشانی داده های کارخانه"</string>
<string name="policylab_setGlobalProxy" msgid="2784828293747791446">"تنظیم پروکسی جهانی دستگاه"</string>
<string name="policydesc_setGlobalProxy" msgid="6387497466660154931">"پروکسی جهانی دستگاه مورد نظر را جهت استفاده هنگام فعال بودن خط مشی تنظیم کنید. فقط اولین سرپرست دستگاه پروکسی جهانی مفید را تنظیم می کند."</string>
- <string name="policylab_expirePassword" msgid="2314569545488269564">"تنظیم زمان انقضای رمز ورود"</string>
- <string name="policydesc_expirePassword" msgid="7276906351852798814">"کنترل مدت زمانی که رمز ورود صفحه قفل قبل از تغییر یافتن لازم دارد"</string>
+ <!-- outdated translation 4740941403188940274 --> <string name="policylab_expirePassword" msgid="885279151847254056">"تنظیم زمان انقضای رمز ورود"</string>
+ <!-- outdated translation 6626724939177185949 --> <string name="policydesc_expirePassword" msgid="4844430354224822074">"کنترل مدت زمانی که رمز ورود صفحه قفل قبل از تغییر یافتن لازم دارد"</string>
<string name="policylab_encryptedStorage" msgid="8901326199909132915">"تنظیم رمزگذاری حافظه"</string>
<string name="policydesc_encryptedStorage" msgid="2504984732631479399">"نیاز به رمزگذاری داده های برنامه کاربردی ذخیره شده دارد"</string>
<string-array name="phoneTypes">
diff --git a/core/res/res/values-fi/strings.xml b/core/res/res/values-fi/strings.xml
index dc594db..9c525cf 100644
--- a/core/res/res/values-fi/strings.xml
+++ b/core/res/res/values-fi/strings.xml
@@ -484,8 +484,8 @@
<string name="policydesc_wipeData" product="default" msgid="7669895333814222586">"Tyhjennä puhelimen tiedot varoituksetta palauttamalla tehdasasetukset."</string>
<string name="policylab_setGlobalProxy" msgid="2784828293747791446">"Aseta laitteen yleinen välityspalvelin"</string>
<string name="policydesc_setGlobalProxy" msgid="6387497466660154931">"Aseta laitteen yleinen välityspalvelin käyttöön, kun käytäntö on käytössä. Vain ensimmäinen laitteen järjestelmänhallitsija voi asettaa käytettävän yleisen välityspalvelimen."</string>
- <string name="policylab_expirePassword" msgid="2314569545488269564">"Aseta salasanan umpeutuminen"</string>
- <string name="policydesc_expirePassword" msgid="7276906351852798814">"Valitse, kuinka pian ruudunlukituksen poiston salasana tulee vaihtaa"</string>
+ <!-- outdated translation 4740941403188940274 --> <string name="policylab_expirePassword" msgid="885279151847254056">"Aseta salasanan voimassaoloaika"</string>
+ <!-- outdated translation 6626724939177185949 --> <string name="policydesc_expirePassword" msgid="4844430354224822074">"Valitse, kuinka pian ruudunlukituksen poiston salasana tulee vaihtaa"</string>
<string name="policylab_encryptedStorage" msgid="8901326199909132915">"Aseta tallennustilan salaus"</string>
<string name="policydesc_encryptedStorage" msgid="2504984732631479399">"Pakota tallennettujen sovellustietojen salaus"</string>
<string-array name="phoneTypes">
diff --git a/core/res/res/values-fr/strings.xml b/core/res/res/values-fr/strings.xml
index 3e09691..39276af 100644
--- a/core/res/res/values-fr/strings.xml
+++ b/core/res/res/values-fr/strings.xml
@@ -484,8 +484,8 @@
<string name="policydesc_wipeData" product="default" msgid="7669895333814222586">"Effacer les données du téléphone sans avertissement, en restaurant les valeurs d\'usine"</string>
<string name="policylab_setGlobalProxy" msgid="2784828293747791446">"Définir le proxy global du mobile"</string>
<string name="policydesc_setGlobalProxy" msgid="6387497466660154931">"Indiquez le proxy global à utiliser pour ce mobile lorsque les règles sont activées. Seul l\'administrateur principal du mobile peut définir le proxy global utilisé."</string>
- <string name="policylab_expirePassword" msgid="2314569545488269564">"Définir date exp. mot de passe"</string>
- <string name="policydesc_expirePassword" msgid="7276906351852798814">"Définir la fréquence de changement du mot de passe de verrouillage d\'écran"</string>
+ <!-- outdated translation 4740941403188940274 --> <string name="policylab_expirePassword" msgid="885279151847254056">"Définir la date d\'expiration du mot de passe"</string>
+ <!-- outdated translation 6626724939177185949 --> <string name="policydesc_expirePassword" msgid="4844430354224822074">"Définir la fréquence de changement du mot de passe de verrouillage d\'écran"</string>
<string name="policylab_encryptedStorage" msgid="8901326199909132915">"Définir cryptage du stockage"</string>
<string name="policydesc_encryptedStorage" msgid="2504984732631479399">"Exiger que les données d\'application stockées soient cryptées"</string>
<string-array name="phoneTypes">
diff --git a/core/res/res/values-hr/strings.xml b/core/res/res/values-hr/strings.xml
index b9e2753..2fd6d19 100644
--- a/core/res/res/values-hr/strings.xml
+++ b/core/res/res/values-hr/strings.xml
@@ -484,8 +484,8 @@
<string name="policydesc_wipeData" product="default" msgid="7669895333814222586">"Izbriši podatke telefona bez upozorenja vraćanjem u tvorničko stanje"</string>
<string name="policylab_setGlobalProxy" msgid="2784828293747791446">"postavi globalni proxy uređaja"</string>
<string name="policydesc_setGlobalProxy" msgid="6387497466660154931">"Postavi globalni proxy uređaja za upotrebu dok su pravila omogućena. Samo prvi administrator uređaja postavlja djelotvoran globalni proxy."</string>
- <string name="policylab_expirePassword" msgid="2314569545488269564">"Postavi istek zaporke"</string>
- <string name="policydesc_expirePassword" msgid="7276906351852798814">"Nadzirite za koliko vremena zaporka za zaključani zaslon treba biti promijenjena"</string>
+ <!-- outdated translation 4740941403188940274 --> <string name="policylab_expirePassword" msgid="885279151847254056">"Postavi istek zaporke"</string>
+ <!-- outdated translation 6626724939177185949 --> <string name="policydesc_expirePassword" msgid="4844430354224822074">"Nadzirite za koliko vremena zaporka za zaključani zaslon treba biti promijenjena"</string>
<string name="policylab_encryptedStorage" msgid="8901326199909132915">"Postavi enkripciju za pohranu"</string>
<string name="policydesc_encryptedStorage" msgid="2504984732631479399">"Zahtijevaj da pohranjeni podaci aplikacije budu kriptirani"</string>
<string-array name="phoneTypes">
diff --git a/core/res/res/values-hu/strings.xml b/core/res/res/values-hu/strings.xml
index a4ee0cb..aa4af42 100644
--- a/core/res/res/values-hu/strings.xml
+++ b/core/res/res/values-hu/strings.xml
@@ -484,8 +484,8 @@
<string name="policydesc_wipeData" product="default" msgid="7669895333814222586">"Figyelmeztetés nélkül törli a telefon összes adatát, visszaállítva a gyári adatokat"</string>
<string name="policylab_setGlobalProxy" msgid="2784828293747791446">"Az eszköz globális proxyjának beállítása"</string>
<string name="policydesc_setGlobalProxy" msgid="6387497466660154931">"Az eszköz globális proxyja lesz használatban, amíg az irányelv engedélyezve van. Csak az eszköz első rendszergazdája állíthatja be a tényleges globális proxyt."</string>
- <string name="policylab_expirePassword" msgid="2314569545488269564">"Jelszó lejáratának beállítása"</string>
- <string name="policydesc_expirePassword" msgid="7276906351852798814">"Azt vezérli, mennyi időnként kell módosítani a képernyőt zároló jelszót"</string>
+ <!-- outdated translation 4740941403188940274 --> <string name="policylab_expirePassword" msgid="885279151847254056">"Jelszó lejáratának beállítása"</string>
+ <!-- outdated translation 6626724939177185949 --> <string name="policydesc_expirePassword" msgid="4844430354224822074">"Azt vezérli, mennyi időnként kell módosítani a képernyőt zároló jelszót"</string>
<string name="policylab_encryptedStorage" msgid="8901326199909132915">"Tárhelytitkosítás beállítása"</string>
<string name="policydesc_encryptedStorage" msgid="2504984732631479399">"Megköveteli a tárolt alkalmazásadatok titkosítását"</string>
<string-array name="phoneTypes">
diff --git a/core/res/res/values-in/strings.xml b/core/res/res/values-in/strings.xml
index b6d0d43..eb14169 100644
--- a/core/res/res/values-in/strings.xml
+++ b/core/res/res/values-in/strings.xml
@@ -130,7 +130,7 @@
<string name="me" msgid="6545696007631404292">"Saya"</string>
<string name="power_dialog" product="tablet" msgid="8545351420865202853">"Opsi tablet"</string>
<string name="power_dialog" product="default" msgid="1319919075463988638">"Opsi telepon"</string>
- <string name="silent_mode" msgid="7167703389802618663">"Mode senyap"</string>
+ <string name="silent_mode" msgid="7167703389802618663">"Modus senyap"</string>
<string name="turn_on_radio" msgid="3912793092339962371">"Hidupkan nirkabel"</string>
<string name="turn_off_radio" msgid="8198784949987062346">"Matikan nirkabel"</string>
<string name="screen_lock" msgid="799094655496098153">"Kunci layar"</string>
@@ -484,8 +484,8 @@
<string name="policydesc_wipeData" product="default" msgid="7669895333814222586">"Hapus data ponsel tanpa peringatan, dengan menyetel ulang data pabrik"</string>
<string name="policylab_setGlobalProxy" msgid="2784828293747791446">"Setel proxy global perangkat"</string>
<string name="policydesc_setGlobalProxy" msgid="6387497466660154931">"Setel proxy global perangkat yang akandigunakan ketika kebijakan diaktifkan. Hanya admin perangkat pertama yang menyetel procy global yang berlaku."</string>
- <string name="policylab_expirePassword" msgid="2314569545488269564">"Setel kedaluwarsa sandi"</string>
- <string name="policydesc_expirePassword" msgid="7276906351852798814">"Kontrol berapa lama sebelum sandi penguncian layar perlu diubah"</string>
+ <!-- outdated translation 4740941403188940274 --> <string name="policylab_expirePassword" msgid="885279151847254056">"Setel waktu kedaluwarsa sandi"</string>
+ <!-- outdated translation 6626724939177185949 --> <string name="policydesc_expirePassword" msgid="4844430354224822074">"Kontrol berapa lama sebelum sandi penguncian layar perlu diubah"</string>
<string name="policylab_encryptedStorage" msgid="8901326199909132915">"Setel enkripsi penyimpanan"</string>
<string name="policydesc_encryptedStorage" msgid="2504984732631479399">"Mengharuskan data aplikasi yang disimpan untuk dienkripsi"</string>
<string-array name="phoneTypes">
@@ -683,7 +683,7 @@
<string name="save_password_message" msgid="767344687139195790">"Apakah Anda ingin peramban menyimpan sandi ini?"</string>
<string name="save_password_notnow" msgid="6389675316706699758">"Tidak sekarang"</string>
<string name="save_password_remember" msgid="6491879678996749466">"Ingat"</string>
- <string name="save_password_never" msgid="8274330296785855105">"Tidak pernah"</string>
+ <string name="save_password_never" msgid="8274330296785855105">"Jangan"</string>
<string name="open_permission_deny" msgid="5661861460947222274">"Anda tidak memiliki izin untuk membuka laman ini."</string>
<string name="text_copied" msgid="4985729524670131385">"Teks disalin ke clipboard."</string>
<string name="more_item_label" msgid="4650918923083320495">"Lainnya"</string>
diff --git a/core/res/res/values-it/strings.xml b/core/res/res/values-it/strings.xml
index 047f9b8..1507467 100644
--- a/core/res/res/values-it/strings.xml
+++ b/core/res/res/values-it/strings.xml
@@ -484,8 +484,8 @@
<string name="policydesc_wipeData" product="default" msgid="7669895333814222586">"Cancella i dati del telefono senza preavviso eseguendo un ripristino dati di fabbrica"</string>
<string name="policylab_setGlobalProxy" msgid="2784828293747791446">"Imposta il proxy globale del dispositivo"</string>
<string name="policydesc_setGlobalProxy" msgid="6387497466660154931">"Imposta il proxy globale del dispositivo in modo da utilizzarlo mentre la norma è attiva. Il proxy globale effettivo è impostabile solo dal primo amministratore del dispositivo."</string>
- <string name="policylab_expirePassword" msgid="2314569545488269564">"Imposta scadenza password"</string>
- <string name="policydesc_expirePassword" msgid="7276906351852798814">"Stabilisci la scadenza della password di blocco dello schermo"</string>
+ <!-- outdated translation 4740941403188940274 --> <string name="policylab_expirePassword" msgid="885279151847254056">"Imposta scadenza password"</string>
+ <!-- outdated translation 6626724939177185949 --> <string name="policydesc_expirePassword" msgid="4844430354224822074">"Stabilisci la scadenza della password di blocco dello schermo"</string>
<string name="policylab_encryptedStorage" msgid="8901326199909132915">"Imposta crittografia archivio"</string>
<string name="policydesc_encryptedStorage" msgid="2504984732631479399">"Richiede la crittografia dei dati applicazione memorizzati"</string>
<string-array name="phoneTypes">
@@ -957,7 +957,7 @@
<string name="permission_request_notification_with_subtitle" msgid="4325409589686688000">"Autorizzazione richiesta"\n"per l\'account <xliff:g id="ACCOUNT">%s</xliff:g>"</string>
<string name="input_method_binding_label" msgid="1283557179944992649">"Metodo inserimento"</string>
<string name="sync_binding_label" msgid="3687969138375092423">"Sinc"</string>
- <string name="accessibility_binding_label" msgid="4148120742096474641">"Accesso facilitato"</string>
+ <string name="accessibility_binding_label" msgid="4148120742096474641">"Accessibilità"</string>
<string name="wallpaper_binding_label" msgid="1240087844304687662">"Sfondo"</string>
<string name="chooser_wallpaper" msgid="7873476199295190279">"Cambia sfondo"</string>
<string name="pptp_vpn_description" msgid="2688045385181439401">"Protocollo di tunneling Point-to-Point"</string>
diff --git a/core/res/res/values-iw/strings.xml b/core/res/res/values-iw/strings.xml
index f268fbf..7aa7b30 100644
--- a/core/res/res/values-iw/strings.xml
+++ b/core/res/res/values-iw/strings.xml
@@ -484,12 +484,12 @@
<string name="policydesc_wipeData" product="default" msgid="7669895333814222586">"מחק את נתוני הטלפון ללא אזהרה, על ידי ביצוע איפוס נתוני יצרן"</string>
<string name="policylab_setGlobalProxy" msgid="2784828293747791446">"הגדר את שרת ה-proxy הגלובלי של ההתקן"</string>
<string name="policydesc_setGlobalProxy" msgid="6387497466660154931">"הגדר את שרת proxy הגלובלי של ההתקן לשימוש כאשר המדיניות מופעלת. רק מנהל ההתקן הראשון מגדיר את שרת ה-proxy הגלובלי הפעיל."</string>
- <string name="policylab_expirePassword" msgid="2314569545488269564">"הגדר תפוגת תוקף של סיסמה"</string>
- <string name="policydesc_expirePassword" msgid="7276906351852798814">"שלוט בפרק הזמן הדרוש לשינוי הסיסמה של נעילת המסך"</string>
+ <!-- outdated translation 4740941403188940274 --> <string name="policylab_expirePassword" msgid="885279151847254056">"הגדר תפוגת תוקף של סיסמה"</string>
+ <!-- outdated translation 6626724939177185949 --> <string name="policydesc_expirePassword" msgid="4844430354224822074">"שלוט בפרק הזמן הדרוש לשינוי הסיסמה של נעילת המסך"</string>
<string name="policylab_encryptedStorage" msgid="8901326199909132915">"הגדר הצפנת אחסון"</string>
<string name="policydesc_encryptedStorage" msgid="2504984732631479399">"דורש שנתוני היישום המאוחסנים יהיו מוצפנים"</string>
<string-array name="phoneTypes">
- <item msgid="8901098336658710359">"דף הבית"</item>
+ <item msgid="8901098336658710359">"בית"</item>
<item msgid="869923650527136615">"נייד"</item>
<item msgid="7897544654242874543">"עבודה"</item>
<item msgid="1103601433382158155">"פקס בעבודה"</item>
@@ -499,19 +499,19 @@
<item msgid="9192514806975898961">"מותאם אישית"</item>
</string-array>
<string-array name="emailAddressTypes">
- <item msgid="8073994352956129127">"דף הבית"</item>
+ <item msgid="8073994352956129127">"בית"</item>
<item msgid="7084237356602625604">"עבודה"</item>
<item msgid="1112044410659011023">"אחר"</item>
<item msgid="2374913952870110618">"מותאם אישית"</item>
</string-array>
<string-array name="postalAddressTypes">
- <item msgid="6880257626740047286">"דף הבית"</item>
+ <item msgid="6880257626740047286">"בית"</item>
<item msgid="5629153956045109251">"עבודה"</item>
<item msgid="4966604264500343469">"אחר"</item>
<item msgid="4932682847595299369">"מותאם אישית"</item>
</string-array>
<string-array name="imAddressTypes">
- <item msgid="1738585194601476694">"דף הבית"</item>
+ <item msgid="1738585194601476694">"בית"</item>
<item msgid="1359644565647383708">"עבודה"</item>
<item msgid="7868549401053615677">"אחר"</item>
<item msgid="3145118944639869809">"מותאם אישית"</item>
@@ -532,7 +532,7 @@
<item msgid="1648797903785279353">"Jabber"</item>
</string-array>
<string name="phoneTypeCustom" msgid="1644738059053355820">"מותאם אישית"</string>
- <string name="phoneTypeHome" msgid="2570923463033985887">"דף הבית"</string>
+ <string name="phoneTypeHome" msgid="2570923463033985887">"בית"</string>
<string name="phoneTypeMobile" msgid="6501463557754751037">"נייד"</string>
<string name="phoneTypeWork" msgid="8863939667059911633">"עבודה"</string>
<string name="phoneTypeFaxWork" msgid="3517792160008890912">"פקס בעבודה"</string>
@@ -557,16 +557,16 @@
<string name="eventTypeAnniversary" msgid="3876779744518284000">"יום השנה"</string>
<string name="eventTypeOther" msgid="7388178939010143077">"אחר"</string>
<string name="emailTypeCustom" msgid="8525960257804213846">"מותאם אישית"</string>
- <string name="emailTypeHome" msgid="449227236140433919">"דף הבית"</string>
+ <string name="emailTypeHome" msgid="449227236140433919">"בית"</string>
<string name="emailTypeWork" msgid="3548058059601149973">"עבודה"</string>
<string name="emailTypeOther" msgid="2923008695272639549">"אחר"</string>
<string name="emailTypeMobile" msgid="119919005321166205">"סלולרי"</string>
<string name="postalTypeCustom" msgid="8903206903060479902">"מותאם אישית"</string>
- <string name="postalTypeHome" msgid="8165756977184483097">"דף הבית"</string>
+ <string name="postalTypeHome" msgid="8165756977184483097">"בית"</string>
<string name="postalTypeWork" msgid="5268172772387694495">"עבודה"</string>
<string name="postalTypeOther" msgid="2726111966623584341">"אחר"</string>
<string name="imTypeCustom" msgid="2074028755527826046">"מותאם אישית"</string>
- <string name="imTypeHome" msgid="6241181032954263892">"דף הבית"</string>
+ <string name="imTypeHome" msgid="6241181032954263892">"בית"</string>
<string name="imTypeWork" msgid="1371489290242433090">"עבודה"</string>
<string name="imTypeOther" msgid="5377007495735915478">"אחר"</string>
<string name="imProtocolCustom" msgid="6919453836618749992">"מותאם אישית"</string>
@@ -598,7 +598,7 @@
<string name="relationTypeSister" msgid="1735983554479076481">"אחות"</string>
<string name="relationTypeSpouse" msgid="394136939428698117">"בן/בת זוג"</string>
<string name="sipAddressTypeCustom" msgid="2473580593111590945">"מותאם אישית"</string>
- <string name="sipAddressTypeHome" msgid="6093598181069359295">"דף הבית"</string>
+ <string name="sipAddressTypeHome" msgid="6093598181069359295">"בית"</string>
<string name="sipAddressTypeWork" msgid="6920725730797099047">"עבודה"</string>
<string name="sipAddressTypeOther" msgid="4408436162950119849">"אחר"</string>
<string name="keyguard_password_enter_pin_code" msgid="3731488827218876115">"הזן קוד PIN"</string>
diff --git a/core/res/res/values-ja/strings.xml b/core/res/res/values-ja/strings.xml
index ce6d13d..af2e4d4 100644
--- a/core/res/res/values-ja/strings.xml
+++ b/core/res/res/values-ja/strings.xml
@@ -484,8 +484,8 @@
<string name="policydesc_wipeData" product="default" msgid="7669895333814222586">"警告せずにデータの初期化を実行して端末内のデータを消去します。"</string>
<string name="policylab_setGlobalProxy" msgid="2784828293747791446">"端末のグローバルプロキシを設定"</string>
<string name="policydesc_setGlobalProxy" msgid="6387497466660154931">"ポリシーが有効になっている場合は端末のグローバルプロキシが使用されるように設定します。有効なグローバルプロキシを設定できるのは最初のデバイス管理者だけです。"</string>
- <string name="policylab_expirePassword" msgid="2314569545488269564">"パスワードの有効期限の設定"</string>
- <string name="policydesc_expirePassword" msgid="7276906351852798814">"画面ロックパスワードの変更が必要になるまでの期間を指定します"</string>
+ <!-- outdated translation 4740941403188940274 --> <string name="policylab_expirePassword" msgid="885279151847254056">"パスワードの有効期限の設定"</string>
+ <!-- outdated translation 6626724939177185949 --> <string name="policydesc_expirePassword" msgid="4844430354224822074">"画面ロックパスワードの変更が必要になるまでの期間を指定します"</string>
<string name="policylab_encryptedStorage" msgid="8901326199909132915">"ストレージ暗号化の設定"</string>
<string name="policydesc_encryptedStorage" msgid="2504984732631479399">"保存したアプリケーションデータが暗号化されるようにする"</string>
<string-array name="phoneTypes">
diff --git a/core/res/res/values-ko/strings.xml b/core/res/res/values-ko/strings.xml
index 704f453..6d1423c 100644
--- a/core/res/res/values-ko/strings.xml
+++ b/core/res/res/values-ko/strings.xml
@@ -484,8 +484,8 @@
<string name="policydesc_wipeData" product="default" msgid="7669895333814222586">"공장 초기화를 수행하여 경고 없이 휴대전화 데이터를 지웁니다."</string>
<string name="policylab_setGlobalProxy" msgid="2784828293747791446">"기기 전체 프록시 설정"</string>
<string name="policydesc_setGlobalProxy" msgid="6387497466660154931">"정책이 사용 설정되어 있는 동안 사용될 기기 전체 프록시를 설정합니다. 첫 번째 기기 관리자가 설정한 전체 프록시만 유효합니다."</string>
- <string name="policylab_expirePassword" msgid="2314569545488269564">"비밀번호 만료 설정"</string>
- <string name="policydesc_expirePassword" msgid="7276906351852798814">"화면 잠금 비밀번호를 변경해야 하는 기간 변경"</string>
+ <!-- outdated translation 4740941403188940274 --> <string name="policylab_expirePassword" msgid="885279151847254056">"비밀번호 만료 설정"</string>
+ <!-- outdated translation 6626724939177185949 --> <string name="policydesc_expirePassword" msgid="4844430354224822074">"화면 잠금 비밀번호를 변경해야 하는 기간 변경"</string>
<string name="policylab_encryptedStorage" msgid="8901326199909132915">"저장소 암호화 설정"</string>
<string name="policydesc_encryptedStorage" msgid="2504984732631479399">"저장한 애플리케이션 데이터를 암호화해야 합니다."</string>
<string-array name="phoneTypes">
diff --git a/core/res/res/values-lt/strings.xml b/core/res/res/values-lt/strings.xml
index f3de6dd..b014815 100644
--- a/core/res/res/values-lt/strings.xml
+++ b/core/res/res/values-lt/strings.xml
@@ -484,8 +484,8 @@
<string name="policydesc_wipeData" product="default" msgid="7669895333814222586">"Be įspėjimo ištrinti telefono duomenis iš naujo nustatant gamyklinius duomenis"</string>
<string name="policylab_setGlobalProxy" msgid="2784828293747791446">"Nustatyti įrenginio bendrąjį tarpinį serverį"</string>
<string name="policydesc_setGlobalProxy" msgid="6387497466660154931">"Nustatyti įrenginio bendrąjį tarpinį serverį, kad būtų naudojamas, kol įgalinta politika. Tik pirmasis įrenginio administratorius nustato efektyvų bendrąjį tarpinį serverį."</string>
- <string name="policylab_expirePassword" msgid="2314569545488269564">"Nust. slaptaž. galiojimo pab."</string>
- <string name="policydesc_expirePassword" msgid="7276906351852798814">"Valdyti, per kiek laiko iki ekrano užrakinimo turi būti pakeistas slaptažodis"</string>
+ <!-- outdated translation 4740941403188940274 --> <string name="policylab_expirePassword" msgid="885279151847254056">"Nustatyti slaptažodžio galiojimo pabaigą"</string>
+ <!-- outdated translation 6626724939177185949 --> <string name="policydesc_expirePassword" msgid="4844430354224822074">"Valdyti, per kiek laiko iki ekrano užrakinimo turi būti pakeistas slaptažodis"</string>
<string name="policylab_encryptedStorage" msgid="8901326199909132915">"Nustatyti atmintinės šifruotę"</string>
<string name="policydesc_encryptedStorage" msgid="2504984732631479399">"Saugomos programos duomenys turi būti šifruoti"</string>
<string-array name="phoneTypes">
diff --git a/core/res/res/values-lv/strings.xml b/core/res/res/values-lv/strings.xml
index 9756e91..3f69434 100644
--- a/core/res/res/values-lv/strings.xml
+++ b/core/res/res/values-lv/strings.xml
@@ -484,8 +484,8 @@
<string name="policydesc_wipeData" product="default" msgid="7669895333814222586">"Dzēš tālruņa datus bez brīdinājuma, veicot rūpnīcas datu atiestatīšanu"</string>
<string name="policylab_setGlobalProxy" msgid="2784828293747791446">"Iestatīt ierīces globālo starpniekserveri"</string>
<string name="policydesc_setGlobalProxy" msgid="6387497466660154931">"Iestatiet izmantojamo ierīces globālo starpniekserveri, kad ir iespējota politika. Spēkā esošo globālo starpniekserveri iestata tikai pirmās ierīces administrators."</string>
- <string name="policylab_expirePassword" msgid="2314569545488269564">"Paroles termiņa izb. iest."</string>
- <string name="policydesc_expirePassword" msgid="7276906351852798814">"Kontrolē ekrāna bloķēšanas paroles maiņas intervālu"</string>
+ <!-- outdated translation 4740941403188940274 --> <string name="policylab_expirePassword" msgid="885279151847254056">"Paroles beigu termiņa iestatīšana"</string>
+ <!-- outdated translation 6626724939177185949 --> <string name="policydesc_expirePassword" msgid="4844430354224822074">"Kontrolē ekrāna bloķēšanas paroles maiņas intervālu"</string>
<string name="policylab_encryptedStorage" msgid="8901326199909132915">"Skatīt atmiņas šifrējumu"</string>
<string name="policydesc_encryptedStorage" msgid="2504984732631479399">"Pieprasīt, lai saglabātie lietojumprogrammas dati tiktu šifrēti"</string>
<string-array name="phoneTypes">
diff --git a/core/res/res/values-nb/strings.xml b/core/res/res/values-nb/strings.xml
index 743c8df..09a2cd4 100644
--- a/core/res/res/values-nb/strings.xml
+++ b/core/res/res/values-nb/strings.xml
@@ -484,8 +484,8 @@
<string name="policydesc_wipeData" product="default" msgid="7669895333814222586">"Tilbakestill telefonens data uten advarsel ved å utføre tilbakestilling til fabrikkstandard"</string>
<string name="policylab_setGlobalProxy" msgid="2784828293747791446">"Angi enhetens globale mellomtjener"</string>
<string name="policydesc_setGlobalProxy" msgid="6387497466660154931">"Angir den globale mellomtjeneren på enheten som skal brukes når regelen er aktivert. Kun den opprinnelige administratoren av enheten kan angi den globale mellomtjeneren."</string>
- <string name="policylab_expirePassword" msgid="2314569545488269564">"Angi utløpsdato for passordet"</string>
- <string name="policydesc_expirePassword" msgid="7276906351852798814">"Velg hvor lenge det skal gå før passordet til låseskjermen må byttes"</string>
+ <!-- outdated translation 4740941403188940274 --> <string name="policylab_expirePassword" msgid="885279151847254056">"Angi utløpsdato for passordet"</string>
+ <!-- outdated translation 6626724939177185949 --> <string name="policydesc_expirePassword" msgid="4844430354224822074">"Velg hvor lenge det skal gå før passordet til låseskjermen må byttes"</string>
<string name="policylab_encryptedStorage" msgid="8901326199909132915">"Angi lagringskryptering"</string>
<string name="policydesc_encryptedStorage" msgid="2504984732631479399">"Krever at lagrede programdata krypteres"</string>
<string-array name="phoneTypes">
diff --git a/core/res/res/values-nl/strings.xml b/core/res/res/values-nl/strings.xml
index a149a53..85a7a2d 100644
--- a/core/res/res/values-nl/strings.xml
+++ b/core/res/res/values-nl/strings.xml
@@ -179,78 +179,78 @@
<string name="permgroupdesc_storage" product="nosdcard" msgid="7442318502446874999">"Toegang krijgen tot USB-opslag."</string>
<string name="permgroupdesc_storage" product="default" msgid="9203302214915355774">"Toegang tot de SD-kaart."</string>
<string name="permlab_statusBar" msgid="7417192629601890791">"statusbalk uitschakelen of wijzigen"</string>
- <string name="permdesc_statusBar" msgid="1365473595331989732">"Hiermee kan een toepassing de statusbalk uitschakelen of systeempictogrammen toevoegen en verwijderen."</string>
+ <string name="permdesc_statusBar" msgid="1365473595331989732">"Hiermee kan een app de statusbalk uitschakelen of systeempictogrammen toevoegen en verwijderen."</string>
<string name="permlab_statusBarService" msgid="7247281911387931485">"statusbalk"</string>
- <string name="permdesc_statusBarService" msgid="4097605867643520920">"Hiermee kan de toepassing de statusbalk zijn."</string>
+ <string name="permdesc_statusBarService" msgid="4097605867643520920">"Hiermee kan de app de statusbalk zijn."</string>
<string name="permlab_expandStatusBar" msgid="1148198785937489264">"statusbalk uitvouwen/samenvouwen"</string>
- <string name="permdesc_expandStatusBar" msgid="7088604400110768665">"Hiermee kan de toepassing de statusbalk uitvouwen of samenvouwen."</string>
+ <string name="permdesc_expandStatusBar" msgid="7088604400110768665">"Hiermee kan de app de statusbalk uitvouwen of samenvouwen."</string>
<string name="permlab_processOutgoingCalls" msgid="1136262550878335980">"uitgaande oproepen onderscheppen"</string>
- <string name="permdesc_processOutgoingCalls" msgid="2228988201852654461">"Hiermee kan een toepassing uitgaande oproepen verwerken en het nummer wijzigen dat wordt gebeld. Schadelijke toepassingen kunnen uitgaande oproepen bijhouden, omleiden of tegenhouden."</string>
+ <string name="permdesc_processOutgoingCalls" msgid="2228988201852654461">"Hiermee kan een app uitgaande oproepen verwerken en het nummer wijzigen dat wordt gebeld. Schadelijke apps kunnen uitgaande oproepen bijhouden, omleiden of tegenhouden."</string>
<string name="permlab_receiveSms" msgid="2697628268086208535">"SMS ontvangen"</string>
- <string name="permdesc_receiveSms" msgid="6298292335965966117">"Hiermee kan een toepassing SMS-berichten ontvangen en verwerken. Schadelijke toepassingen kunnen uw berichten bijhouden of deze verwijderen zonder dat u ze te zien krijgt."</string>
+ <string name="permdesc_receiveSms" msgid="6298292335965966117">"Hiermee kan een app SMS-berichten ontvangen en verwerken. Schadelijke apps kunnen uw berichten bijhouden of deze verwijderen zonder dat u ze te zien krijgt."</string>
<string name="permlab_receiveMms" msgid="8894700916188083287">"MMS ontvangen"</string>
- <string name="permdesc_receiveMms" msgid="4563346832000174373">"Hiermee kan een toepassing MMS-berichten ontvangen en verwerken. Schadelijke toepassingen kunnen uw berichten bijhouden of deze verwijderen zonder dat u ze te zien krijgt."</string>
+ <string name="permdesc_receiveMms" msgid="4563346832000174373">"Hiermee kan een app MMS-berichten ontvangen en verwerken. Schadelijke apps kunnen uw berichten bijhouden of deze verwijderen zonder dat u ze te zien krijgt."</string>
<string name="permlab_sendSms" msgid="5600830612147671529">"SMS-berichten verzenden"</string>
- <string name="permdesc_sendSms" msgid="1946540351763502120">"Hiermee kan de toepassing SMS-berichten verzenden. Schadelijke toepassingen kunnen u geld kosten door berichten te verzenden zonder uw toestemming."</string>
+ <string name="permdesc_sendSms" msgid="1946540351763502120">"Hiermee kan de app SMS-berichten verzenden. Schadelijke apps kunnen u geld kosten door berichten te verzenden zonder uw toestemming."</string>
<string name="permlab_readSms" msgid="4085333708122372256">"SMS of MMS lezen"</string>
- <string name="permdesc_readSms" product="tablet" msgid="5836710350295631545">"Hiermee kan een toepassing de op uw tablet of SIM-kaart opgeslagen SMS-berichten lezen. Schadelijke toepassingen kunnen uw vertrouwelijke berichten mogelijk lezen."</string>
- <string name="permdesc_readSms" product="default" msgid="3002170087197294591">"Hiermee kan een toepassing de op uw telefoon of SIM-kaart opgeslagen SMS-berichten lezen. Schadelijke toepassingen kunnen uw vertrouwelijke berichten mogelijk lezen."</string>
+ <string name="permdesc_readSms" product="tablet" msgid="5836710350295631545">"Hiermee kan een app de op uw tablet of SIM-kaart opgeslagen SMS-berichten lezen. Schadelijke apps kunnen uw vertrouwelijke berichten mogelijk lezen."</string>
+ <string name="permdesc_readSms" product="default" msgid="3002170087197294591">"Hiermee kan een app de op uw telefoon of SIM-kaart opgeslagen SMS-berichten lezen. Schadelijke apps kunnen uw vertrouwelijke berichten mogelijk lezen."</string>
<string name="permlab_writeSms" msgid="6881122575154940744">"SMS of MMS bewerken"</string>
- <string name="permdesc_writeSms" product="tablet" msgid="5332124772918835437">"Hiermee kan een toepassing naar de op uw tablet of SIM-kaart opgeslagen SMS-berichten schrijven. Schadelijke toepassingen kunnen uw berichten mogelijk verwijderen."</string>
- <string name="permdesc_writeSms" product="default" msgid="6299398896177548095">"Hiermee kan een toepassing naar de op uw telefoon of SIM-kaart opgeslagen SMS-berichten schrijven. Schadelijke toepassingen kunnen uw berichten mogelijk verwijderen."</string>
+ <string name="permdesc_writeSms" product="tablet" msgid="5332124772918835437">"Hiermee kan een app naar de op uw tablet of SIM-kaart opgeslagen SMS-berichten schrijven. Schadelijke apps kunnen uw berichten mogelijk verwijderen."</string>
+ <string name="permdesc_writeSms" product="default" msgid="6299398896177548095">"Hiermee kan een app naar de op uw telefoon of SIM-kaart opgeslagen SMS-berichten schrijven. Schadelijke apps kunnen uw berichten mogelijk verwijderen."</string>
<string name="permlab_receiveWapPush" msgid="8258226427716551388">"WAP ontvangen"</string>
- <string name="permdesc_receiveWapPush" msgid="5979623826128082171">"Hiermee kan een toepassing WAP-berichten ontvangen en verwerken. Schadelijke toepassingen kunnen uw berichten bijhouden of deze verwijderen zonder dat u ze te zien krijgt."</string>
+ <string name="permdesc_receiveWapPush" msgid="5979623826128082171">"Hiermee kan een app WAP-berichten ontvangen en verwerken. Schadelijke apps kunnen uw berichten bijhouden of deze verwijderen zonder dat u ze te zien krijgt."</string>
<string name="permlab_getTasks" msgid="5005277531132573353">"actieve toepassingen ophalen"</string>
- <string name="permdesc_getTasks" msgid="7048711358713443341">"Hiermee kan een toepassing informatie over huidige en recent uitgevoerde taken ophalen. Schadelijke toepassingen kunnen op deze manier mogelijk privé-informatie over andere toepassingen achterhalen."</string>
+ <string name="permdesc_getTasks" msgid="7048711358713443341">"Hiermee kan een app informatie over huidige en recent uitgevoerde taken ophalen. Schadelijke apps kunnen op deze manier mogelijk privé-informatie over andere apps achterhalen."</string>
<string name="permlab_reorderTasks" msgid="5669588525059921549">"actieve toepassingen opnieuw indelen"</string>
- <string name="permdesc_reorderTasks" msgid="126252774270522835">"Hiermee kan een toepassing taken naar de voor- en achtergrond verplaatsen. Schadelijke toepassingen kunnen zichzelf op de voorgrond plaatsen zonder dat u hier iets aan kunt doen."</string>
+ <string name="permdesc_reorderTasks" msgid="126252774270522835">"Hiermee kan een app taken naar de voor- en achtergrond verplaatsen. Schadelijke apps kunnen zichzelf op de voorgrond plaatsen zonder dat u hier iets aan kunt doen."</string>
<string name="permlab_setDebugApp" msgid="4339730312925176742">"foutopsporing in toepassingen inschakelen"</string>
- <string name="permdesc_setDebugApp" msgid="5584310661711990702">"Hiermee kan een toepassing de foutopsporing voor een andere toepassing inschakelen. Schadelijke toepassingen kunnen dit gebruiken om andere toepassingen af te sluiten."</string>
+ <string name="permdesc_setDebugApp" msgid="5584310661711990702">"Hiermee kan een app de foutopsporing voor een andere app inschakelen. Schadelijke apps kunnen dit gebruiken om andere apps af te sluiten."</string>
<string name="permlab_changeConfiguration" msgid="8214475779521218295">"uw UI-instellingen wijzigen"</string>
- <string name="permdesc_changeConfiguration" msgid="3465121501528064399">"Hiermee kan een toepassing de huidige configuratie, zoals de landinstelling of de algemene lettergrootte, wijzigen."</string>
+ <string name="permdesc_changeConfiguration" msgid="3465121501528064399">"Hiermee kan een app de huidige configuratie, zoals de landinstelling of de algemene lettergrootte, wijzigen."</string>
<string name="permlab_enableCarMode" msgid="5684504058192921098">"automodus inschakelen"</string>
- <string name="permdesc_enableCarMode" msgid="5673461159384850628">"Staat een toepassing toe de automodus in te schakelen."</string>
+ <string name="permdesc_enableCarMode" msgid="5673461159384850628">"Staat een app toe de automodus in te schakelen."</string>
<string name="permlab_killBackgroundProcesses" msgid="8373714752793061963">"processen op de achtergrond beëindigen"</string>
- <string name="permdesc_killBackgroundProcesses" msgid="2908829602869383753">"Staat een toepassing toe processen op de achtergrond te beëindigen, zelfs als er voldoende geheugen beschikbaar is."</string>
+ <string name="permdesc_killBackgroundProcesses" msgid="2908829602869383753">"Staat een app toe processen op de achtergrond te beëindigen, zelfs als er voldoende geheugen beschikbaar is."</string>
<string name="permlab_forceStopPackages" msgid="1447830113260156236">"andere toepassingen gedwongen stoppen"</string>
- <string name="permdesc_forceStopPackages" msgid="7263036616161367402">"Staat een toepassing toe andere toepassingen te stoppen."</string>
- <string name="permlab_forceBack" msgid="1804196839880393631">"toepassing nu sluiten"</string>
- <string name="permdesc_forceBack" msgid="6534109744159919013">"Hiermee kan een toepassing elke willekeurige activiteit die op de voorgrond wordt uitgevoerd, sluiten en naar de achtergrond verplaatsen. Nooit vereist voor normale toepassingen."</string>
+ <string name="permdesc_forceStopPackages" msgid="7263036616161367402">"Staat een app toe andere apps te stoppen."</string>
+ <string name="permlab_forceBack" msgid="1804196839880393631">"app nu sluiten"</string>
+ <string name="permdesc_forceBack" msgid="6534109744159919013">"Hiermee kan een app elke willekeurige activiteit die op de voorgrond wordt uitgevoerd, sluiten en naar de achtergrond verplaatsen. Nooit vereist voor normale apps."</string>
<string name="permlab_dump" msgid="1681799862438954752">"interne systeemstatus ophalen"</string>
- <string name="permdesc_dump" msgid="2198776174276275220">"Hiermee kan een toepassing de interne status van het systeem ophalen. Schadelijke toepassingen kunnen privé- of veiligheidsgegevens ophalen die ze normaal niet nodig hebben."</string>
+ <string name="permdesc_dump" msgid="2198776174276275220">"Hiermee kan een app de interne status van het systeem ophalen. Schadelijke apps kunnen privé- of veiligheidsgegevens ophalen die ze normaal niet nodig hebben."</string>
<string name="permlab_shutdown" msgid="7185747824038909016">"gedeeltelijke uitschakeling"</string>
<string name="permdesc_shutdown" msgid="7046500838746291775">"Hiermee wordt activiteitenbeheer uitgeschakeld. Er wordt geen volledige uitschakeling uitgevoerd."</string>
<string name="permlab_stopAppSwitches" msgid="4138608610717425573">"schakelen tussen toepassingen voorkomen"</string>
- <string name="permdesc_stopAppSwitches" msgid="3857886086919033794">"Hiermee wordt voorkomen dat de gebruiker overschakelt naar een andere toepassing."</string>
+ <string name="permdesc_stopAppSwitches" msgid="3857886086919033794">"Hiermee wordt voorkomen dat de gebruiker overschakelt naar een andere app."</string>
<string name="permlab_runSetActivityWatcher" msgid="7811586187574696296">"alle startende toepassingen bijhouden en beheren"</string>
- <string name="permdesc_runSetActivityWatcher" msgid="2149363027173451218">"Hiermee kan een toepassing de manier waarop het systeem activiteiten start, bijhouden en beheren. Schadelijke toepassingen kunnen het systeem volledig in gevaar brengen. Deze machtiging is alleen voor ontwikkeling vereist, nooit voor normaal gebruik."</string>
+ <string name="permdesc_runSetActivityWatcher" msgid="2149363027173451218">"Hiermee kan een app de manier waarop het systeem activiteiten start, bijhouden en beheren. Schadelijke apps kunnen het systeem volledig in gevaar brengen. Deze machtiging is alleen voor ontwikkeling vereist, nooit voor normaal gebruik."</string>
<string name="permlab_broadcastPackageRemoved" msgid="2576333434893532475">"melding verzenden dat pakket is verwijderd"</string>
- <string name="permdesc_broadcastPackageRemoved" msgid="3453286591439891260">"Hiermee kan een toepassing een melding verzenden dat een toepassingspakket is verwijderd. Schadelijke toepassingen kunnen hiervan gebruik maken om alle andere actieve toepassingen af te sluiten."</string>
+ <string name="permdesc_broadcastPackageRemoved" msgid="3453286591439891260">"Hiermee kan een app een melding verzenden dat een applicatiepakket (APK) is verwijderd. Schadelijke apps kunnen hiervan gebruik maken om alle andere actieve apps af te sluiten."</string>
<string name="permlab_broadcastSmsReceived" msgid="5689095009030336593">"melding over ontvangen SMS-bericht verzenden"</string>
- <string name="permdesc_broadcastSmsReceived" msgid="9122419277306740155">"Hiermee kan een toepassing een melding verzenden dat een SMS-bericht is ontvangen. Schadelijke toepassingen kunnen hiervan gebruik maken om inkomende SMS-berichten te vervalsen."</string>
+ <string name="permdesc_broadcastSmsReceived" msgid="9122419277306740155">"Hiermee kan een app een melding verzenden dat een SMS-bericht is ontvangen. Schadelijke apps kunnen hiervan gebruik maken om inkomende SMS-berichten te vervalsen."</string>
<string name="permlab_broadcastWapPush" msgid="3145347413028582371">"melding over ontvangen WAP-PUSH-bericht verzenden"</string>
- <string name="permdesc_broadcastWapPush" msgid="3955303669461378091">"Hiermee kan een toepassing een melding verzenden dat een WAP PUSH-bericht is ontvangen. Schadelijke toepassingen kunnen hiervan gebruik maken om een valse MMS-ontvangst te melden of de inhoud van willekeurige webpagina\'s door schadelijke varianten te vervangen."</string>
+ <string name="permdesc_broadcastWapPush" msgid="3955303669461378091">"Hiermee kan een app een melding verzenden dat een WAP PUSH-bericht is ontvangen. Schadelijke apps kunnen hiervan gebruik maken om een valse MMS-ontvangst te melden of de inhoud van willekeurige webpagina\'s door schadelijke varianten te vervangen."</string>
<string name="permlab_setProcessLimit" msgid="2451873664363662666">"aantal actieve processen beperken"</string>
- <string name="permdesc_setProcessLimit" msgid="7824786028557379539">"Hiermee kan een toepassing het maximum aantal processen bepalen dat wordt uitgevoerd. Nooit vereist voor normale toepassingen."</string>
+ <string name="permdesc_setProcessLimit" msgid="7824786028557379539">"Hiermee kan een app het maximum aantal processen bepalen dat wordt uitgevoerd. Nooit vereist voor normale apps."</string>
<string name="permlab_setAlwaysFinish" msgid="5342837862439543783">"alle achtergrondtoepassingen sluiten"</string>
- <string name="permdesc_setAlwaysFinish" msgid="8773936403987091620">"Hiermee kan een toepassing bepalen of activiteiten altijd worden afgesloten zodra deze naar de achtergrond gaan. Nooit nodig voor normale toepassingen."</string>
+ <string name="permdesc_setAlwaysFinish" msgid="8773936403987091620">"Hiermee kan een app bepalen of activiteiten altijd worden afgesloten zodra deze naar de achtergrond gaan. Nooit nodig voor normale apps."</string>
<string name="permlab_batteryStats" msgid="7863923071360031652">"accustatistieken aanpassen"</string>
<string name="permdesc_batteryStats" msgid="5847319823772230560">"Hiermee kunnen verzamelde accustatistieken worden gewijzigd. Niet voor gebruik door normale toepassingen."</string>
<string name="permlab_backup" msgid="470013022865453920">"systeemback-up en -herstel beheren"</string>
- <string name="permdesc_backup" msgid="4837493065154256525">"Hiermee kan de toepassing het mechanisme voor systeemback-up en -herstel beheren. Niet voor gebruik door normale toepassingen."</string>
+ <string name="permdesc_backup" msgid="4837493065154256525">"Hiermee kan de app het mechanisme voor systeemback-up en -herstel beheren. Niet voor gebruik door normale apps."</string>
<string name="permlab_internalSystemWindow" msgid="2148563628140193231">"niet-geautoriseerde vensters weergeven"</string>
<string name="permdesc_internalSystemWindow" msgid="5895082268284998469">"Hiermee kunnen vensters worden gemaakt die door de interne systeemgebruikersinterface worden gebruikt. Niet voor gebruik door normale toepassingen."</string>
<string name="permlab_systemAlertWindow" msgid="3372321942941168324">"waarschuwingen op systeemniveau weergeven"</string>
- <string name="permdesc_systemAlertWindow" msgid="2884149573672821318">"Hiermee kan een toepassing systeemwaarschuwingen weergeven. Schadelijke toepassingen kunnen op deze manier het hele scherm van de tablet overnemen."</string>
+ <string name="permdesc_systemAlertWindow" msgid="2884149573672821318">"Hiermee kan een app systeemwaarschuwingen weergeven. Schadelijke apps kunnen op deze manier het hele scherm van de tablet overnemen."</string>
<string name="permlab_setAnimationScale" msgid="2805103241153907174">"algemene animatiesnelheid wijzigen"</string>
- <string name="permdesc_setAnimationScale" msgid="7181522138912391988">"Hiermee kan een toepassing op elk gewenst moment de algemene animatiesnelheid wijzigen (snellere of tragere animaties)."</string>
+ <string name="permdesc_setAnimationScale" msgid="7181522138912391988">"Hiermee kan een app op elk gewenst moment de algemene animatiesnelheid wijzigen (snellere of tragere animaties)."</string>
<string name="permlab_manageAppTokens" msgid="17124341698093865">"toepassingstokens beheren"</string>
<string name="permdesc_manageAppTokens" msgid="977127907524195988">"Hiermee kunnen toepassingen hun eigen tokens maken en beheren, waarbij de normale Z-volgorde wordt overgeslagen. Nooit nodig voor normale toepassingen."</string>
<string name="permlab_injectEvents" msgid="1378746584023586600">"drukken op toetsen en bedieningselementen"</string>
- <string name="permdesc_injectEvents" product="tablet" msgid="7200014808195664505">"Hiermee kan een toepassing zijn eigen invoergebeurtenissen (toetsaanslagen, enzovoort) aan andere toepassingen doorgeven. Schadelijke toepassingen kunnen dit gebruiken om de tablet over te nemen."</string>
- <string name="permdesc_injectEvents" product="default" msgid="3946098050410874715">"Hiermee kan een toepassing zijn eigen invoergebeurtenissen (toetsaanslagen, enzovoort) aan andere toepassingen doorgeven. Schadelijke toepassingen kunnen dit gebruiken om de telefoon over te nemen."</string>
+ <string name="permdesc_injectEvents" product="tablet" msgid="7200014808195664505">"Hiermee kan een app de eigen invoergebeurtenissen (toetsaanslagen, enzovoort) aan andere apps doorgeven. Schadelijke apps kunnen dit gebruiken om de tablet over te nemen."</string>
+ <string name="permdesc_injectEvents" product="default" msgid="3946098050410874715">"Hiermee kan een app zijn de invoergebeurtenissen (toetsaanslagen, enzovoort) aan andere apps doorgeven. Schadelijke apps kunnen dit gebruiken om de telefoon over te nemen."</string>
<string name="permlab_readInputState" msgid="469428900041249234">"uw invoer en acties vastleggen"</string>
- <string name="permdesc_readInputState" msgid="5132879321450325445">"Hiermee kan een toepassing uw toetsaanslagen registreren, zelfs tijdens de interactie met een andere toepassing (zoals de invoer van een wachtwoord). Nooit vereist voor normale toepassingen."</string>
+ <string name="permdesc_readInputState" msgid="5132879321450325445">"Hiermee kan een app uw toetsaanslagen registreren, zelfs tijdens de interactie met een andere app (zoals de invoer van een wachtwoord). Nooit vereist voor normale apps."</string>
<string name="permlab_bindInputMethod" msgid="3360064620230515776">"verbinden aan een invoermethode"</string>
<string name="permdesc_bindInputMethod" msgid="3734838321027317228">"Hiermee staat u de houder toe zich te verbinden met de hoofdinterface van een invoermethode. Nooit vereist voor normale toepassingen."</string>
<string name="permlab_bindWallpaper" msgid="8716400279937856462">"verbinden met een achtergrond"</string>
@@ -260,59 +260,59 @@
<string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"interactie met apparaatbeheer"</string>
<string name="permdesc_bindDeviceAdmin" msgid="8714424333082216979">"Staat de houder toe intenties te verzenden naar een apparaatbeheerder. Nooit vereist voor normale toepassingen."</string>
<string name="permlab_setOrientation" msgid="3365947717163866844">"schermstand wijzigen"</string>
- <string name="permdesc_setOrientation" msgid="6335814461615851863">"Hiermee kan een toepassing op elk gewenst moment de oriëntatie van het scherm wijzigen. Nooit vereist voor normale toepassingen."</string>
+ <string name="permdesc_setOrientation" msgid="6335814461615851863">"Hiermee kan een app op elk gewenst moment de oriëntatie van het scherm wijzigen. Nooit vereist voor normale apps."</string>
<string name="permlab_signalPersistentProcesses" msgid="4255467255488653854">"Linux-signalen verzenden naar toepassingen"</string>
- <string name="permdesc_signalPersistentProcesses" msgid="3565530463215015289">"Hiermee kan de toepassing ervoor zorgen dat het geleverde signaal wordt verzonden naar alle persistente processen."</string>
- <string name="permlab_persistentActivity" msgid="8659652042401085862">"toepassing altijd laten uitvoeren"</string>
- <string name="permdesc_persistentActivity" msgid="5037199778265006008">"Hiermee kan een toepassing delen van zichzelf persistent maken, zodat het systeem dat deel niet voor andere toepassingen kan gebruiken."</string>
+ <string name="permdesc_signalPersistentProcesses" msgid="3565530463215015289">"Hiermee kan de app ervoor zorgen dat het geleverde signaal wordt verzonden naar alle persistente processen."</string>
+ <string name="permlab_persistentActivity" msgid="8659652042401085862">"app altijd laten uitvoeren"</string>
+ <string name="permdesc_persistentActivity" msgid="5037199778265006008">"Hiermee kan een app delen van zichzelf persistent maken, zodat het systeem dat deel niet voor andere apps kan gebruiken."</string>
<string name="permlab_deletePackages" msgid="3343439331576348805">"toepassingen verwijderen"</string>
- <string name="permdesc_deletePackages" msgid="3634943677518723314">"Hiermee kan een toepassing Android-pakketten verwijderen. Schadelijke toepassingen kunnen dit gebruiken om belangrijke toepassingen te verwijderen."</string>
+ <string name="permdesc_deletePackages" msgid="3634943677518723314">"Hiermee kan een app Android-pakketten verwijderen. Schadelijke apps kunnen dit gebruiken om belangrijke apps te verwijderen."</string>
<string name="permlab_clearAppUserData" msgid="2192134353540277878">"gegevens van andere toepassingen verwijderen"</string>
- <string name="permdesc_clearAppUserData" msgid="7546345080434325456">"Hiermee kan een toepassing gebruikersgegevens wissen."</string>
+ <string name="permdesc_clearAppUserData" msgid="7546345080434325456">"Hiermee kan een app gebruikersgegevens wissen."</string>
<string name="permlab_deleteCacheFiles" msgid="1518556602634276725">"caches van andere toepassingen verwijderen"</string>
- <string name="permdesc_deleteCacheFiles" msgid="2283074077168165971">"Hiermee kan een toepassing cachebestanden verwijderen."</string>
- <string name="permlab_getPackageSize" msgid="4799785352306641460">"opslagruimte van toepassing bepalen"</string>
- <string name="permdesc_getPackageSize" msgid="5557253039670753437">"Hiermee kan een toepassing de bijbehorende code, gegevens en cachegrootten ophalen."</string>
+ <string name="permdesc_deleteCacheFiles" msgid="2283074077168165971">"Hiermee kan een app cachebestanden verwijderen."</string>
+ <string name="permlab_getPackageSize" msgid="4799785352306641460">"opslagruimte van app bepalen"</string>
+ <string name="permdesc_getPackageSize" msgid="5557253039670753437">"Hiermee kan een app de bijbehorende code, gegevens en cachegrootten ophalen."</string>
<string name="permlab_installPackages" msgid="335800214119051089">"toepassingen rechtstreeks installeren"</string>
- <string name="permdesc_installPackages" msgid="526669220850066132">"Hiermee kan een toepassing nieuwe of bijgewerkte Android-pakketten installeren. Schadelijke toepassingen kunnen hiervan gebruik maken om nieuwe toepassingen met willekeurig krachtige machtigingen toe te voegen."</string>
- <string name="permlab_clearAppCache" msgid="4747698311163766540">"alle cachegegevens van toepassing verwijderen"</string>
- <string name="permdesc_clearAppCache" product="tablet" msgid="3097119797652477973">"Hiermee kan een toepassing opslagruimte op de tablet vrij maken door bestanden te verwijderen uit de cachemap van de toepassing. De toegang is doorgaans beperkt tot het systeemproces."</string>
- <string name="permdesc_clearAppCache" product="default" msgid="7740465694193671402">"Hiermee kan een toepassing opslagruimte op de telefoon vrij maken door bestanden te verwijderen uit de cachemap van de toepassing. De toegang is doorgaans beperkt tot het systeemproces."</string>
+ <string name="permdesc_installPackages" msgid="526669220850066132">"Hiermee kan een app nieuwe of bijgewerkte Android-pakketten installeren. Schadelijke apps kunnen hiervan gebruik maken om nieuwe apps met willekeurig krachtige machtigingen toe te voegen."</string>
+ <string name="permlab_clearAppCache" msgid="4747698311163766540">"alle cachegegevens van app verwijderen"</string>
+ <string name="permdesc_clearAppCache" product="tablet" msgid="3097119797652477973">"Hiermee kan een app opslagruimte op de tablet vrij maken door bestanden te verwijderen uit de cachemap van de app. De toegang is doorgaans beperkt tot het systeemproces."</string>
+ <string name="permdesc_clearAppCache" product="default" msgid="7740465694193671402">"Hiermee kan een app opslagruimte op de telefoon vrij maken door bestanden te verwijderen uit de cachemap van de app. De toegang is doorgaans beperkt tot het systeemproces."</string>
<string name="permlab_movePackage" msgid="728454979946503926">"Toepassingsbronnen verplaatsen"</string>
- <string name="permdesc_movePackage" msgid="6323049291923925277">"Een toepassing toestaan toepassingsbronnen te verplaatsen van interne naar externe media en omgekeerd."</string>
+ <string name="permdesc_movePackage" msgid="6323049291923925277">"Een app toestaan app-bronnen te verplaatsen van interne naar externe media en omgekeerd."</string>
<string name="permlab_readLogs" msgid="6615778543198967614">"gevoelige logbestandsgegevens lezen"</string>
- <string name="permdesc_readLogs" product="tablet" msgid="4077356893924755294">"Hiermee kan een toepassing de verschillende logbestanden van het systeem lezen. De toepassing kan op deze manier algemene informatie achterhalen over uw tabletgebruik, mogelijk inclusief persoonlijke of privé-informatie."</string>
- <string name="permdesc_readLogs" product="default" msgid="8896449437464867766">"Hiermee kan een toepassing de verschillende logbestanden van het systeem lezen. De toepassing kan op deze manier algemene informatie achterhalen over uw telefoongebruik, mogelijk inclusief persoonlijke of privé-informatie."</string>
+ <string name="permdesc_readLogs" product="tablet" msgid="4077356893924755294">"Hiermee kan een app de verschillende logbestanden van het systeem lezen. De app kan op deze manier algemene informatie achterhalen over uw tabletgebruik, mogelijk inclusief persoonlijke of privé-informatie."</string>
+ <string name="permdesc_readLogs" product="default" msgid="8896449437464867766">"Hiermee kan een app de verschillende logbestanden van het systeem lezen. De app kan op deze manier algemene informatie achterhalen over uw telefoongebruik, mogelijk inclusief persoonlijke of privé-informatie."</string>
<string name="permlab_diagnostic" msgid="8076743953908000342">"lezen/schrijven naar bronnen van diag"</string>
- <string name="permdesc_diagnostic" msgid="3121238373951637049">"Hiermee kan een toepassing lezen en schrijven naar elke bron die hoort bij de diagnostische groep, zoals bestanden in /dev. Hierdoor kan de systeemstabiliteit en -veiligheid worden beïnvloed. Dit mag ALLEEN worden gebruikt voor hardwarespecifieke diagnostiek door de fabrikant of operator."</string>
+ <string name="permdesc_diagnostic" msgid="3121238373951637049">"Hiermee kan een app lezen en schrijven naar elke bron die hoort bij de diagnostische groep, zoals bestanden in /dev. Hierdoor kan de systeemstabiliteit en -veiligheid worden beïnvloed. Dit mag ALLEEN worden gebruikt voor hardwarespecifieke diagnostiek door de fabrikant of operator."</string>
<string name="permlab_changeComponentState" msgid="79425198834329406">"toepassingscomponenten in- of uitschakelen"</string>
- <string name="permdesc_changeComponentState" product="tablet" msgid="4647419365510068321">"Hiermee kan een toepassing bepalen of een component van een andere toepassing is ingeschakeld. Schadelijke toepassingen kunnen hiervan gebruik maken om belangrijke tabletfuncties uit te schakelen. Een machtiging moet zorgvuldig worden overwogen, aangezien toepassingscomponenten onbruikbaar, inconsistent of instabiel kunnen worden."</string>
- <string name="permdesc_changeComponentState" product="default" msgid="3443473726140080761">"Hiermee kan een toepassing bepalen of een component van een andere toepassing is ingeschakeld. Schadelijke toepassingen kunnen dit gebruiken om belangrijke telefoonfuncties uit te schakelen. Een machtiging moet zorgvuldig worden overwogen, aangezien toepassingscomponenten onbruikbaar, inconsistent of instabiel kunnen worden."</string>
+ <string name="permdesc_changeComponentState" product="tablet" msgid="4647419365510068321">"Hiermee kan een app bepalen of een component van een andere app is ingeschakeld. Schadelijke apps kunnen hiervan gebruik maken om belangrijke tabletfuncties uit te schakelen. Een machtiging moet zorgvuldig worden overwogen, aangezien app-componenten onbruikbaar, inconsistent of instabiel kunnen worden."</string>
+ <string name="permdesc_changeComponentState" product="default" msgid="3443473726140080761">"Hiermee kan een app bepalen of een component van een andere app is ingeschakeld. Schadelijke apps kunnen dit gebruiken om belangrijke telefoonfuncties uit te schakelen. Een machtiging moet zorgvuldig worden overwogen, aangezien app-componenten onbruikbaar, inconsistent of instabiel kunnen worden."</string>
<string name="permlab_setPreferredApplications" msgid="3393305202145172005">"voorkeurstoepassingen instellen"</string>
- <string name="permdesc_setPreferredApplications" msgid="760008293501937546">"Hiermee kan een toepassing uw voorkeurstoepassingen wijzigen. Schadelijke toepassingen kunnen op deze manier de actieve toepassingen zonder uw medeweten wijzigen en uw bestaande toepassingen doorzoeken om privégegevens van u te verzamelen."</string>
+ <string name="permdesc_setPreferredApplications" msgid="760008293501937546">"Hiermee kan een app uw voorkeurs-apps wijzigen. Schadelijke apps kunnen op deze manier de actieve apps zonder uw medeweten wijzigen en uw bestaande apps doorzoeken om privégegevens van u te verzamelen."</string>
<string name="permlab_writeSettings" msgid="1365523497395143704">"algemene systeeminstellingen wijzigen"</string>
- <string name="permdesc_writeSettings" msgid="838789419871034696">"Hiermee kan een toepassing de systeeminstellingen wijzigen. Schadelijke toepassingen kunnen hiermee uw systeemconfiguratie beschadigen."</string>
+ <string name="permdesc_writeSettings" msgid="838789419871034696">"Hiermee kan een app de systeeminstellingen wijzigen. Schadelijke apps kunnen hiermee uw systeemconfiguratie beschadigen."</string>
<string name="permlab_writeSecureSettings" msgid="204676251876718288">"beveiligde systeeminstellingen wijzigen"</string>
- <string name="permdesc_writeSecureSettings" msgid="5497873143539034724">"Hiermee kan een toepassing beveiligde systeeminstellingen wijzigen. Niet voor gebruik door normale toepassingen."</string>
+ <string name="permdesc_writeSecureSettings" msgid="5497873143539034724">"Hiermee kan een app beveiligde systeeminstellingen wijzigen. Niet voor gebruik door normale apps."</string>
<string name="permlab_writeGservices" msgid="2149426664226152185">"de Google-serviceskaart wijzigen"</string>
- <string name="permdesc_writeGservices" msgid="6602362746516676175">"Hiermee kan een toepassing de Google-serviceskaart wijzigen. Niet voor gebruik door normale toepassingen."</string>
+ <string name="permdesc_writeGservices" msgid="6602362746516676175">"Hiermee kan een app de Google-serviceskaart wijzigen. Niet voor gebruik door normale apps."</string>
<string name="permlab_receiveBootCompleted" msgid="7776779842866993377">"automatisch starten bij opstarten"</string>
- <string name="permdesc_receiveBootCompleted" product="tablet" msgid="7530977064379338199">"Hiermee kan een toepassing zichzelf starten zodra het systeem klaar is met opstarten. Hierdoor kan het langer duren voordat de tablet is opgestart en kan de toepassing de tabletprocessen vertragen door altijd actief te zijn."</string>
- <string name="permdesc_receiveBootCompleted" product="default" msgid="698336728415008796">"Hiermee kan een toepassing zichzelf starten zodra het systeem klaar is met opstarten. Hierdoor kan het langer duren voordat de telefoon is opgestart en kan de toepassing de telefoonprocessen vertragen door altijd actief te zijn."</string>
+ <string name="permdesc_receiveBootCompleted" product="tablet" msgid="7530977064379338199">"Hiermee kan een app zichzelf starten zodra het systeem klaar is met opstarten. Hierdoor kan het langer duren voordat de tablet is opgestart en kan de app de tabletprocessen vertragen door altijd actief te zijn."</string>
+ <string name="permdesc_receiveBootCompleted" product="default" msgid="698336728415008796">"Hiermee kan een app zichzelf starten zodra het systeem klaar is met opstarten. Hierdoor kan het langer duren voordat de telefoon is opgestart en kan de app de telefoonprocessen vertragen door altijd actief te zijn."</string>
<string name="permlab_broadcastSticky" msgid="7919126372606881614">"sticky broadcast verzenden"</string>
- <string name="permdesc_broadcastSticky" product="tablet" msgid="6322249605930062595">"Hiermee kan een toepassing sticky broadcasts verzenden die achterblijven als de broadcast eindigt. Schadelijke toepassingen kunnen hiermee de tablet traag of instabiel maken door ervoor te zorgen dat er te veel geheugenruimte wordt gebruikt."</string>
- <string name="permdesc_broadcastSticky" product="default" msgid="1920045289234052219">"Hiermee kan een toepassing sticky broadcasts verzenden die achterblijven als de broadcast eindigt. Schadelijke toepassingen kunnen hiermee de telefoon traag of instabiel maken door ervoor te zorgen dat er te veel geheugenruimte wordt gebruikt."</string>
+ <string name="permdesc_broadcastSticky" product="tablet" msgid="6322249605930062595">"Hiermee kan een app sticky broadcasts verzenden die achterblijven als de broadcast eindigt. Schadelijke apps kunnen hiermee de tablet traag of instabiel maken door ervoor te zorgen dat er te veel geheugenruimte wordt gebruikt."</string>
+ <string name="permdesc_broadcastSticky" product="default" msgid="1920045289234052219">"Hiermee kan een app sticky broadcasts verzenden die achterblijven als de broadcast eindigt. Schadelijke apps kunnen hiermee de telefoon traag of instabiel maken door ervoor te zorgen dat er te veel geheugenruimte wordt gebruikt."</string>
<string name="permlab_readContacts" msgid="6219652189510218240">"contactgegevens lezen"</string>
- <string name="permdesc_readContacts" product="tablet" msgid="7596158687301157686">"Hiermee kan een toepassing alle contactgegevens (adresgegevens) zien die op uw tablet zijn opgeslagen. Schadelijke toepassingen kunnen hiervan gebruik maken om uw gegevens te verzenden naar andere personen."</string>
- <string name="permdesc_readContacts" product="default" msgid="3371591512896545975">"Hiermee kan een toepassing alle contactgegevens (adresgegevens) zien die op uw telefoon zijn opgeslagen. Schadelijke toepassingen kunnen hiervan gebruik maken om uw gegevens te verzenden naar andere personen."</string>
+ <string name="permdesc_readContacts" product="tablet" msgid="7596158687301157686">"Hiermee kan een app alle contactgegevens (adresgegevens) zien die op uw tablet zijn opgeslagen. Schadelijke apps kunnen hiervan gebruik maken om uw gegevens te verzenden naar andere personen."</string>
+ <string name="permdesc_readContacts" product="default" msgid="3371591512896545975">"Hiermee kan een app alle contactgegevens (adresgegevens) zien die op uw telefoon zijn opgeslagen. Schadelijke apps kunnen hiervan gebruik maken om uw gegevens te verzenden naar andere personen."</string>
<string name="permlab_writeContacts" msgid="644616215860933284">"contactgegevens schrijven"</string>
- <string name="permdesc_writeContacts" product="tablet" msgid="7782689510038568495">"Hiermee kan een toepassing de op uw tablet opgeslagen contactgegevens (adresgegevens) wijzigen. Schadelijke toepassingen kunnen hiermee uw contactgegevens verwijderen of wijzigen."</string>
- <string name="permdesc_writeContacts" product="default" msgid="3924383579108183601">"Hiermee kan een toepassing de op uw telefoon opgeslagen contactgegevens (adresgegevens) wijzigen. Schadelijke toepassingen kunnen hiermee uw contactgegevens verwijderen of wijzigen."</string>
+ <string name="permdesc_writeContacts" product="tablet" msgid="7782689510038568495">"Hiermee kan een app de op uw tablet opgeslagen contactgegevens (adresgegevens) wijzigen. Schadelijke apps kunnen hiermee uw contactgegevens verwijderen of wijzigen."</string>
+ <string name="permdesc_writeContacts" product="default" msgid="3924383579108183601">"Hiermee kan een app de op uw telefoon opgeslagen contactgegevens (adresgegevens) wijzigen. Schadelijke apps kunnen hiermee uw contactgegevens verwijderen of wijzigen."</string>
<string name="permlab_readCalendar" msgid="6898987798303840534">"agendagebeurtenissen lezen"</string>
- <string name="permdesc_readCalendar" product="tablet" msgid="5905870265734599678">"Hiermee kan een toepassing alle agendagebeurtenissen lezen die zijn opgeslagen op uw tablet. Schadelijke toepassingen kunnen hiervan gebruik maken om uw agendagebeurtenissen te verzenden naar andere personen."</string>
- <string name="permdesc_readCalendar" product="default" msgid="5533029139652095734">"Hiermee kan een toepassing alle agendagebeurtenissen lezen die zijn opgeslagen op uw telefoon. Schadelijke toepassingen kunnen hiervan gebruik maken om uw agendagebeurtenissen te verzenden naar andere personen."</string>
+ <string name="permdesc_readCalendar" product="tablet" msgid="5905870265734599678">"Hiermee kan een app alle agendagebeurtenissen lezen die zijn opgeslagen op uw tablet. Schadelijke apps kunnen hiervan gebruik maken om uw agendagebeurtenissen te verzenden naar andere personen."</string>
+ <string name="permdesc_readCalendar" product="default" msgid="5533029139652095734">"Hiermee kan een app alle agendagebeurtenissen lezen die zijn opgeslagen op uw telefoon. Schadelijke apps kunnen hiervan gebruik maken om uw agendagebeurtenissen te verzenden naar andere personen."</string>
<string name="permlab_writeCalendar" msgid="3894879352594904361">"agendagebeurtenissen toevoegen of aanpassen en e-mail verzenden naar gasten"</string>
- <string name="permdesc_writeCalendar" msgid="2988871373544154221">"Een toepassing toestaan gebeurtenissen aan uw agenda toe te voegen of te wijzigen, wat inhoudt dat er e-mails kunnen worden verzonden naar gasten. Schadelijke toepassingen kunnen dit gebruiken om uw agendagebeurtenissen te wissen of aan te passen of om e-mail naar gasten te verzenden."</string>
+ <string name="permdesc_writeCalendar" msgid="2988871373544154221">"Een app toestaan gebeurtenissen aan uw agenda toe te voegen of te wijzigen, wat inhoudt dat er e-mails kunnen worden verzonden naar gasten. Schadelijke apps kunnen dit gebruiken om uw agendagebeurtenissen te wissen of aan te passen of om e-mail naar gasten te verzenden."</string>
<string name="permlab_accessMockLocation" msgid="8688334974036823330">"neplocatiebronnen voor test"</string>
<string name="permdesc_accessMockLocation" msgid="7648286063459727252">"Neplocatiebronnen voor testdoeleinden maken. Schadelijke toepassingen kunnen dit gebruiken om de locatie en/of status te overschrijven die door de echte locatiebronnen wordt aangegeven, zoals GPS of netwerkaanbieders."</string>
<string name="permlab_accessLocationExtraCommands" msgid="2836308076720553837">"toegang tot extra opdrachten van locatieaanbieder"</string>
@@ -326,150 +326,150 @@
<string name="permdesc_accessCoarseLocation" product="tablet" msgid="3704633168985466045">"Toegang tot globale locatiebronnen, zoals de mobiele netwerkdatabase om een globale tabletlocatie te bepalen, indien beschikbaar. Schadelijke toepassingen kunnen hiervan gebruik maken om bij benadering te bepalen waar u zich bevindt."</string>
<string name="permdesc_accessCoarseLocation" product="default" msgid="8235655958070862293">"Toegang tot globale locatiebronnen, zoals de mobiele netwerkdatabase om een globale telefoonlocatie te bepalen, indien beschikbaar. Schadelijke toepassingen kunnen hiervan gebruik maken om bij benadering te bepalen waar u zich bevindt."</string>
<string name="permlab_accessSurfaceFlinger" msgid="2363969641792388947">"toegang tot SurfaceFlinger"</string>
- <string name="permdesc_accessSurfaceFlinger" msgid="6805241830020733025">"Hiermee kan een toepassing SurfaceFlinger-functies op laag niveau gebruiken."</string>
+ <string name="permdesc_accessSurfaceFlinger" msgid="6805241830020733025">"Hiermee kan een app SurfaceFlinger-functies op laag niveau gebruiken."</string>
<string name="permlab_readFrameBuffer" msgid="6690504248178498136">"framebuffer lezen"</string>
- <string name="permdesc_readFrameBuffer" msgid="7530020370469942528">"Hiermee kan een toepassing de inhoud van de framebuffer lezen."</string>
+ <string name="permdesc_readFrameBuffer" msgid="7530020370469942528">"Hiermee kan een app de inhoud van de framebuffer lezen."</string>
<string name="permlab_modifyAudioSettings" msgid="6095859937069146086">"uw audio-instellingen wijzigen"</string>
- <string name="permdesc_modifyAudioSettings" msgid="5793461287365991922">"Hiermee kan een toepassing de algemene audio-instellingen, zoals volume en omleiding, wijzigen."</string>
+ <string name="permdesc_modifyAudioSettings" msgid="5793461287365991922">"Hiermee kan een app de algemene audio-instellingen, zoals volume en omleiding, wijzigen."</string>
<string name="permlab_recordAudio" msgid="3876049771427466323">"audio opnemen"</string>
- <string name="permdesc_recordAudio" msgid="6493228261176552356">"Hiermee krijgt de toepassing toegang tot het audio-opnamepad."</string>
+ <string name="permdesc_recordAudio" msgid="6493228261176552356">"Hiermee krijgt de app toegang tot het audio-opnamepad."</string>
<string name="permlab_camera" msgid="3616391919559751192">"foto\'s en video\'s maken"</string>
- <string name="permdesc_camera" msgid="6004878235852154239">"Hiermee kan een toepassing foto\'s en video\'s maken met de camera. De toepassing kan op deze manier op elk gewenste moment beelden verzamelen van wat de camera ziet."</string>
+ <string name="permdesc_camera" msgid="6004878235852154239">"Hiermee kan een app foto\'s en video\'s maken met de camera. De app kan op deze manier op elk gewenste moment beelden verzamelen van wat de camera ziet."</string>
<string name="permlab_brick" product="tablet" msgid="2961292205764488304">"tablet permanent uitschakelen"</string>
<string name="permlab_brick" product="default" msgid="8337817093326370537">"telefoon permanent uitschakelen"</string>
- <string name="permdesc_brick" product="tablet" msgid="7379164636920817963">"Hiermee kan de toepassing de tablet permanent uitschakelen. Dit is erg gevaarlijk."</string>
- <string name="permdesc_brick" product="default" msgid="5569526552607599221">"Hiermee kan de toepassing de telefoon permanent uitschakelen. Dit is erg gevaarlijk."</string>
+ <string name="permdesc_brick" product="tablet" msgid="7379164636920817963">"Hiermee kan de app de tablet permanent uitschakelen. Dit is erg gevaarlijk."</string>
+ <string name="permdesc_brick" product="default" msgid="5569526552607599221">"Hiermee kan de app de telefoon permanent uitschakelen. Dit is erg gevaarlijk."</string>
<string name="permlab_reboot" product="tablet" msgid="3436634972561795002">"opnieuw opstarten van tablet afdwingen"</string>
<string name="permlab_reboot" product="default" msgid="2898560872462638242">"telefoon nu opnieuw opstarten"</string>
- <string name="permdesc_reboot" product="tablet" msgid="4555793623560701557">"Hiermee kan de toepassing de tablet nu opnieuw opstarten."</string>
- <string name="permdesc_reboot" product="default" msgid="7914933292815491782">"Hiermee kan de toepassing de telefoon nu opnieuw opstarten."</string>
+ <string name="permdesc_reboot" product="tablet" msgid="4555793623560701557">"Hiermee kan de app de tablet opnieuw opstarten."</string>
+ <string name="permdesc_reboot" product="default" msgid="7914933292815491782">"Hiermee kan de app de telefoon nu opnieuw opstarten."</string>
<string name="permlab_mount_unmount_filesystems" msgid="1761023272170956541">"bestandssystemen koppelen en ontkoppelen"</string>
- <string name="permdesc_mount_unmount_filesystems" msgid="6253263792535859767">"Hiermee kan de toepassing bestandssystemen koppelen en ontkoppelen voor verwisselbare opslagruimte."</string>
+ <string name="permdesc_mount_unmount_filesystems" msgid="6253263792535859767">"Hiermee kan de app bestandssystemen koppelen en ontkoppelen voor verwisselbare opslagruimte."</string>
<string name="permlab_mount_format_filesystems" msgid="5523285143576718981">"externe opslag formatteren"</string>
- <string name="permdesc_mount_format_filesystems" msgid="574060044906047386">"Hiermee kan de toepassing de externe opslag formatteren."</string>
+ <string name="permdesc_mount_format_filesystems" msgid="574060044906047386">"Hiermee kan de app de externe opslag formatteren."</string>
<string name="permlab_asec_access" msgid="3411338632002193846">"informatie over de interne opslag verkrijgen"</string>
- <string name="permdesc_asec_access" msgid="8820326551687285439">"Hiermee kan de toepassing informatie over de interne opslag verkrijgen."</string>
+ <string name="permdesc_asec_access" msgid="8820326551687285439">"Hiermee kan de app informatie over de interne opslag verkrijgen."</string>
<string name="permlab_asec_create" msgid="6414757234789336327">"interne opslag maken"</string>
- <string name="permdesc_asec_create" msgid="2621346764995731250">"Hiermee kan de toepassing interne opslag maken."</string>
+ <string name="permdesc_asec_create" msgid="2621346764995731250">"Hiermee kan de app interne opslag maken."</string>
<string name="permlab_asec_destroy" msgid="526928328301618022">"interne opslag vernietigen"</string>
- <string name="permdesc_asec_destroy" msgid="2746706889208066256">"Hiermee kan de toepassing de interne opslag vernietigen."</string>
+ <string name="permdesc_asec_destroy" msgid="2746706889208066256">"Hiermee kan de app de interne opslag vernietigen."</string>
<string name="permlab_asec_mount_unmount" msgid="2456287623689029744">"interne opslag koppelen/ontkoppelen"</string>
- <string name="permdesc_asec_mount_unmount" msgid="5934375590189368200">"Hiermee kan de toepassing de interne opslag koppelen/ontkoppelen."</string>
+ <string name="permdesc_asec_mount_unmount" msgid="5934375590189368200">"Hiermee kan de app de interne opslag koppelen/ontkoppelen."</string>
<string name="permlab_asec_rename" msgid="7496633954080472417">"naam van interne opslag wijzigen"</string>
- <string name="permdesc_asec_rename" msgid="2152829985238876790">"Hiermee kan de toepassing de naam van de interne opslag wijzigen."</string>
+ <string name="permdesc_asec_rename" msgid="2152829985238876790">"Hiermee kan de app de naam van de interne opslag wijzigen."</string>
<string name="permlab_vibrate" msgid="7768356019980849603">"trilstand beheren"</string>
- <string name="permdesc_vibrate" msgid="2886677177257789187">"Hiermee kan de toepassing de trilstand beheren."</string>
+ <string name="permdesc_vibrate" msgid="2886677177257789187">"Hiermee kan de app de trilstand beheren."</string>
<string name="permlab_flashlight" msgid="2155920810121984215">"zaklamp bedienen"</string>
- <string name="permdesc_flashlight" msgid="6433045942283802309">"Hiermee kan de toepassing de zaklamp bedienen."</string>
+ <string name="permdesc_flashlight" msgid="6433045942283802309">"Hiermee kan de app de zaklamp bedienen."</string>
<string name="permlab_accessUsb" msgid="7362327818655760496">"toegang krijgen tot USB-apparaten"</string>
- <string name="permdesc_accessUsb" msgid="2414271762914049292">"Hiermee kan de toepassing toegang krijgen tot USB-apparaten."</string>
+ <string name="permdesc_accessUsb" msgid="2414271762914049292">"Hiermee kan de app toegang krijgen tot USB-apparaten."</string>
<string name="permlab_accessMtp" msgid="4953468676795917042">"MTP-protocol implementeren"</string>
<string name="permdesc_accessMtp" msgid="6532961200486791570">"Staat toegang tot de kernel van de MTP-driver toe voor het implementeren van het MTP-USB-protocol."</string>
<string name="permlab_hardware_test" msgid="4148290860400659146">"hardware testen"</string>
- <string name="permdesc_hardware_test" msgid="3668894686500081699">"Hiermee kan de toepassing verschillende randapparaten beheren om de hardware te testen."</string>
+ <string name="permdesc_hardware_test" msgid="3668894686500081699">"Hiermee kan de app verschillende randapparaten beheren om de hardware te testen."</string>
<string name="permlab_callPhone" msgid="3925836347681847954">"telefoonnummers rechtstreeks bellen"</string>
- <string name="permdesc_callPhone" msgid="3369867353692722456">"Hiermee kan de toepassing telefoonnummers bellen zonder uw tussenkomst. Door schadelijke toepassingen kunnen onverwachte oproepen op uw telefoonrekening verschijnen. De toepassing kan hiermee geen alarmnummers bellen."</string>
+ <string name="permdesc_callPhone" msgid="3369867353692722456">"Hiermee kan de app telefoonnummers bellen zonder uw tussenkomst. Door schadelijke apps kunnen onverwachte oproepen op uw telefoonrekening verschijnen. De app kan hiermee geen alarmnummers bellen."</string>
<string name="permlab_callPrivileged" msgid="4198349211108497879">"alle telefoonnummers rechtstreeks bellen"</string>
- <string name="permdesc_callPrivileged" msgid="244405067160028452">"Hiermee kan een toepassing elk telefoonnummer, inclusief alarmnummers, bellen zonder uw tussenkomst. Schadelijke toepassingen kunnen onnodige en illegale oproepen uitvoeren naar alarmdiensten."</string>
+ <string name="permdesc_callPrivileged" msgid="244405067160028452">"Hiermee kan een app elk telefoonnummer, inclusief alarmnummers, bellen zonder uw tussenkomst. Schadelijke apps kunnen onnodige en illegale oproepen uitvoeren naar alarmdiensten."</string>
<string name="permlab_performCdmaProvisioning" product="tablet" msgid="4842576994144604821">"meteen starten met CDMA-tabletinstelling"</string>
<string name="permlab_performCdmaProvisioning" product="default" msgid="5604848095315421425">"meteen starten met CDMA-telefooninstelling"</string>
- <string name="permdesc_performCdmaProvisioning" msgid="6457447676108355905">"Hiermee kan de toepassing starten met CDMA-provisioning. Schadelijke applicaties kunnen de CDMA-provisioning onnodig starten"</string>
+ <string name="permdesc_performCdmaProvisioning" msgid="6457447676108355905">"Hiermee kan de app starten met CDMA-provisioning. Schadelijke apps kunnen de CDMA-provisioning onnodig starten"</string>
<string name="permlab_locationUpdates" msgid="7785408253364335740">"meldingen over locatie-updates beheren"</string>
<string name="permdesc_locationUpdates" msgid="2300018303720930256">"Hiermee kunnen updatemeldingen voor locaties van de radio worden ingeschakeld/uitgeschakeld. Niet voor gebruik door normale toepassingen."</string>
<string name="permlab_checkinProperties" msgid="7855259461268734914">"toegang tot checkin-eigenschappen"</string>
<string name="permdesc_checkinProperties" msgid="7150307006141883832">"Hiermee wordt lees-/schrijftoegang gegeven tot eigenschappen die door de checkin-service zijn geüpload. Niet voor gebruik door normale toepassingen."</string>
<string name="permlab_bindGadget" msgid="776905339015863471">"widgets kiezen"</string>
- <string name="permdesc_bindGadget" msgid="2098697834497452046">"Hiermee kan een toepassing het systeem melden welke widgets door welke toepassing kunnen worden gebruikt. Met deze toestemming kunnen toepassingen andere toepassingen toegang geven tot persoonlijke gegevens. Niet voor gebruik door normale toepassingen."</string>
+ <string name="permdesc_bindGadget" msgid="2098697834497452046">"Hiermee kan een app het systeem melden welke widgets door welke app kunnen worden gebruikt. Met deze toestemming kunnen apps andere apps toegang geven tot persoonlijke gegevens. Niet voor gebruik door normale apps."</string>
<string name="permlab_modifyPhoneState" msgid="8423923777659292228">"telefoonstatus wijzigen"</string>
- <string name="permdesc_modifyPhoneState" msgid="3302284561346956587">"Hiermee kan de toepassing de telefoonfuncties van het apparaat beheren. Een toepassing met deze machtiging kan schakelen tussen netwerken, de radio van de telefoon in- of uitschakelen en dergelijke zonder dat u hiervan op de hoogte wordt gesteld."</string>
+ <string name="permdesc_modifyPhoneState" msgid="3302284561346956587">"Hiermee kan de app de telefoonfuncties van het apparaat beheren. Een app met deze machtiging kan schakelen tussen netwerken, de radio van de telefoon in- of uitschakelen en dergelijke zonder dat u hiervan op de hoogte wordt gesteld."</string>
<string name="permlab_readPhoneState" msgid="2326172951448691631">"telefoonstatus en -identiteit lezen"</string>
- <string name="permdesc_readPhoneState" msgid="188877305147626781">"Hiermee krijgt de toepassing toegang tot de telefoonfuncties van het apparaat. Een toepassing met de betreffende machtiging kan het telefoonnummer en serienummer van deze telefoon achterhalen, bepalen of een oproep actief is, het gekozen nummer achterhalen en dergelijke."</string>
+ <string name="permdesc_readPhoneState" msgid="188877305147626781">"Hiermee krijgt de app toegang tot de telefoonfuncties van het apparaat. Een app met de betreffende machtiging kan het telefoonnummer en serienummer van deze telefoon achterhalen, bepalen of een oproep actief is, het gekozen nummer achterhalen en dergelijke."</string>
<string name="permlab_wakeLock" product="tablet" msgid="1531731435011495015">"voorkomen dat tablet overschakelt naar slaapmodus"</string>
<string name="permlab_wakeLock" product="default" msgid="573480187941496130">"voorkomen dat telefoon overschakelt naar slaapmodus"</string>
- <string name="permdesc_wakeLock" product="tablet" msgid="4032181488045338551">"Hiermee kan een toepassing voorkomen dat de tablet overschakelt naar de slaapmodus."</string>
- <string name="permdesc_wakeLock" product="default" msgid="7584036471227467099">"Hiermee kan een toepassing voorkomen dat de telefoon overschakelt naar de slaapmodus."</string>
+ <string name="permdesc_wakeLock" product="tablet" msgid="4032181488045338551">"Hiermee kan een app voorkomen dat de tablet overschakelt naar de slaapmodus."</string>
+ <string name="permdesc_wakeLock" product="default" msgid="7584036471227467099">"Hiermee kan een app voorkomen dat de telefoon overschakelt naar de slaapmodus."</string>
<string name="permlab_devicePower" product="tablet" msgid="2787034722616350417">"tablet in- of uitschakelen"</string>
<string name="permlab_devicePower" product="default" msgid="4928622470980943206">"telefoon in- of uitschakelen"</string>
- <string name="permdesc_devicePower" product="tablet" msgid="3853773100100451905">"Hiermee kan de toepassing de tablet in- of uitschakelen."</string>
- <string name="permdesc_devicePower" product="default" msgid="4577331933252444818">"Hiermee kan de toepassing de telefoon in- of uitschakelen."</string>
+ <string name="permdesc_devicePower" product="tablet" msgid="3853773100100451905">"Hiermee kan de app de tablet in- of uitschakelen."</string>
+ <string name="permdesc_devicePower" product="default" msgid="4577331933252444818">"Hiermee kan de app de telefoon in- of uitschakelen."</string>
<string name="permlab_factoryTest" msgid="3715225492696416187">"uitvoeren in fabriekstestmodus"</string>
<string name="permdesc_factoryTest" product="tablet" msgid="3952059318359653091">"Uitvoeren als fabrikanttest op laag niveau, waardoor toegang wordt gegeven tot de hardware van de tablet. Alleen beschikbaar als een tablet zich in de fabrikanttestmodus bevindt."</string>
<string name="permdesc_factoryTest" product="default" msgid="8136644990319244802">"Uitvoeren als fabrikanttest op laag niveau, waardoor toegang wordt gegeven tot de hardware van de telefoon. Alleen beschikbaar als een telefoon zich in de fabrikanttestmodus bevindt."</string>
<string name="permlab_setWallpaper" msgid="6627192333373465143">"achtergrond instellen"</string>
- <string name="permdesc_setWallpaper" msgid="6417041752170585837">"Hiermee kan de toepassing de systeemachtergrond instellen."</string>
+ <string name="permdesc_setWallpaper" msgid="6417041752170585837">"Hiermee kan de app de systeemachtergrond instellen."</string>
<string name="permlab_setWallpaperHints" msgid="3600721069353106851">"grootte achtergrond instellen"</string>
- <string name="permdesc_setWallpaperHints" msgid="6019479164008079626">"Hiermee kan de toepassing de grootte van de achtergrond instellen."</string>
+ <string name="permdesc_setWallpaperHints" msgid="6019479164008079626">"Hiermee kan de app de grootte van de achtergrond instellen."</string>
<string name="permlab_masterClear" msgid="2315750423139697397">"systeem terugzetten op fabrieksinstellingen"</string>
- <string name="permdesc_masterClear" msgid="5033465107545174514">"Hiermee kan een toepassing het systeem terugzetten op de fabrieksinstellingen, waarbij alle gegevens, configuraties en geïnstalleerde toepassingen worden verwijderd."</string>
+ <string name="permdesc_masterClear" msgid="5033465107545174514">"Hiermee kan een app het systeem terugzetten op de fabrieksinstellingen, waarbij alle gegevens, configuraties en geïnstalleerde apps worden verwijderd."</string>
<string name="permlab_setTime" msgid="2021614829591775646">"tijd instellen"</string>
- <string name="permdesc_setTime" product="tablet" msgid="209693136361006073">"Staat een toepassing toe de kloktijd van de tablet te wijzigen."</string>
- <string name="permdesc_setTime" product="default" msgid="667294309287080045">"Staat een toepassing toe de kloktijd van de telefoon te wijzigen."</string>
+ <string name="permdesc_setTime" product="tablet" msgid="209693136361006073">"Staat een app toe de kloktijd van de tablet te wijzigen."</string>
+ <string name="permdesc_setTime" product="default" msgid="667294309287080045">"Staat een app toe de kloktijd van de telefoon te wijzigen."</string>
<string name="permlab_setTimeZone" msgid="2945079801013077340">"tijdzone instellen"</string>
- <string name="permdesc_setTimeZone" product="tablet" msgid="2522877107613885139">"Hiermee kan een toepassing de tijdzone van de tablet wijzigen."</string>
- <string name="permdesc_setTimeZone" product="default" msgid="1902540227418179364">"Hiermee kan een toepassing de tijdzone van de telefoon wijzigen."</string>
+ <string name="permdesc_setTimeZone" product="tablet" msgid="2522877107613885139">"Hiermee kan een app de tijdzone van de tablet wijzigen."</string>
+ <string name="permdesc_setTimeZone" product="default" msgid="1902540227418179364">"Hiermee kan een app de tijdzone van de telefoon wijzigen."</string>
<string name="permlab_accountManagerService" msgid="4829262349691386986">"fungeren als de AccountManagerService"</string>
- <string name="permdesc_accountManagerService" msgid="6056903274106394752">"Hiermee kan een toepassing aanroepen plaatsen naar AccountAuthenticators"</string>
+ <string name="permdesc_accountManagerService" msgid="6056903274106394752">"Hiermee kan een app aanroepen plaatsen naar AccountAuthenticators"</string>
<string name="permlab_getAccounts" msgid="4549918644233460103">"bekende accounts zoeken"</string>
- <string name="permdesc_getAccounts" product="tablet" msgid="857622793935544694">"Hiermee kan een toepassing de lijst met accounts van een tablet ophalen."</string>
- <string name="permdesc_getAccounts" product="default" msgid="6839262446413155394">"Hiermee kan een toepassing de lijst met accounts van een telefoon ophalen."</string>
+ <string name="permdesc_getAccounts" product="tablet" msgid="857622793935544694">"Hiermee kan een app de lijst met accounts van een tablet ophalen."</string>
+ <string name="permdesc_getAccounts" product="default" msgid="6839262446413155394">"Hiermee kan een app de lijst met accounts van een telefoon ophalen."</string>
<string name="permlab_authenticateAccounts" msgid="3940505577982882450">"fungeren als verificatie-instantie voor het account"</string>
- <string name="permdesc_authenticateAccounts" msgid="4006839406474208874">"Hiermee kan een toepassing de mogelijkheden voor verificatie-instanties voor het account van de AccountManager gebruiken, waaronder het maken van accounts en het ophalen en instellen van de bijbehorende wachtwoorden."</string>
+ <string name="permdesc_authenticateAccounts" msgid="4006839406474208874">"Hiermee kan een app de mogelijkheden voor verificatie-instanties voor het account van de AccountManager gebruiken, waaronder het maken van accounts en het ophalen en instellen van de bijbehorende wachtwoorden."</string>
<string name="permlab_manageAccounts" msgid="4440380488312204365">"de lijst met accounts beheren"</string>
- <string name="permdesc_manageAccounts" msgid="8804114016661104517">"Hiermee kan een toepassing bewerkingen uitvoeren, zoals het toevoegen en verwijderen van accounts en het verwijderen van de bijbehorende wachtwoorden."</string>
+ <string name="permdesc_manageAccounts" msgid="8804114016661104517">"Hiermee kan een app bewerkingen uitvoeren, zoals het toevoegen en verwijderen van accounts en het verwijderen van de bijbehorende wachtwoorden."</string>
<string name="permlab_useCredentials" msgid="6401886092818819856">"de verificatiegegevens van een account gebruiken"</string>
- <string name="permdesc_useCredentials" msgid="7416570544619546974">"Hiermee kan een toepassing verificatietokens aanvragen."</string>
+ <string name="permdesc_useCredentials" msgid="7416570544619546974">"Hiermee kan een app verificatietokens aanvragen."</string>
<string name="permlab_accessNetworkState" msgid="6865575199464405769">"netwerkstatus bekijken"</string>
- <string name="permdesc_accessNetworkState" msgid="558721128707712766">"Hiermee kan een toepassing de status van alle netwerken bekijken."</string>
+ <string name="permdesc_accessNetworkState" msgid="558721128707712766">"Hiermee kan een app de status van alle netwerken bekijken."</string>
<string name="permlab_createNetworkSockets" msgid="9121633680349549585">"volledige internettoegang"</string>
- <string name="permdesc_createNetworkSockets" msgid="4593339106921772192">"Hiermee kan een toepassing netwerksockets maken."</string>
+ <string name="permdesc_createNetworkSockets" msgid="4593339106921772192">"Hiermee kan een app netwerksockets maken."</string>
<string name="permlab_writeApnSettings" msgid="7823599210086622545">"instellingen voor toegangspuntnaam schrijven"</string>
- <string name="permdesc_writeApnSettings" msgid="7443433457842966680">"Hiermee kan een toepassing de APN-instellingen, zoals proxy en poort, van elke APN wijzigen."</string>
+ <string name="permdesc_writeApnSettings" msgid="7443433457842966680">"Hiermee kan een app de APN-instellingen, zoals proxy en poort, van elke APN wijzigen."</string>
<string name="permlab_changeNetworkState" msgid="958884291454327309">"netwerkverbinding wijzigen"</string>
- <string name="permdesc_changeNetworkState" msgid="4199958910396387075">"Staat een toepassing toe de status van de netwerkverbinding te wijzigen."</string>
+ <string name="permdesc_changeNetworkState" msgid="4199958910396387075">"Staat een app toe de status van de netwerkverbinding te wijzigen."</string>
<string name="permlab_changeTetherState" msgid="2702121155761140799">"Getetherde verbinding wijzigen"</string>
- <string name="permdesc_changeTetherState" msgid="8905815579146349568">"Staat een toepassing toe de status van de getetherde netwerkverbinding te wijzigen."</string>
+ <string name="permdesc_changeTetherState" msgid="8905815579146349568">"Staat een app toe de status van de getetherde netwerkverbinding te wijzigen."</string>
<string name="permlab_changeBackgroundDataSetting" msgid="1400666012671648741">"instelling voor gebruik van achtergrondgegevens van gegevens wijzigen"</string>
- <string name="permdesc_changeBackgroundDataSetting" msgid="1001482853266638864">"Hiermee kan een toepassing de instelling voor gebruik van achtergrondgegevens wijzigen."</string>
+ <string name="permdesc_changeBackgroundDataSetting" msgid="1001482853266638864">"Hiermee kan een app de instelling voor gebruik van achtergrondgegevens wijzigen."</string>
<string name="permlab_accessWifiState" msgid="8100926650211034400">"Wi-Fi-status bekijken"</string>
- <string name="permdesc_accessWifiState" msgid="485796529139236346">"Hiermee kan een toepassing informatie over de Wi-Fi-status bekijken."</string>
+ <string name="permdesc_accessWifiState" msgid="485796529139236346">"Hiermee kan een app informatie over de Wi-Fi-status bekijken."</string>
<string name="permlab_changeWifiState" msgid="7280632711057112137">"Wi-Fi-status wijzigen"</string>
- <string name="permdesc_changeWifiState" msgid="2950383153656873267">"Hiermee kan een toepassing zich koppelen aan en loskoppelen van Wi-Fi toegangspunten en wijzigingen aanbrengen in geconfigureerde Wi-Fi-netwerken."</string>
+ <string name="permdesc_changeWifiState" msgid="2950383153656873267">"Hiermee kan een app zich koppelen aan en loskoppelen van Wi-Fi toegangspunten en wijzigingen aanbrengen in geconfigureerde Wi-Fi-netwerken."</string>
<string name="permlab_changeWifiMulticastState" msgid="1368253871483254784">"Wi-Fi Multicast-ontvangst toestaan"</string>
- <string name="permdesc_changeWifiMulticastState" msgid="8199464507656067553">"Hiermee kan een toepassing pakketten ontvangen die niet rechtstreeks zijn geadresseerd aan uw apparaat. Dit kan handig zijn wanneer services in de buurt worden ontdekt. Dit verbruikt meer energie dan de niet-multicastmodus."</string>
+ <string name="permdesc_changeWifiMulticastState" msgid="8199464507656067553">"Hiermee kan een app pakketten ontvangen die niet rechtstreeks zijn geadresseerd aan uw apparaat. Dit kan handig zijn wanneer services in de buurt worden ontdekt. Dit verbruikt meer energie dan de niet-multicastmodus."</string>
<string name="permlab_bluetoothAdmin" msgid="1092209628459341292">"bluetooth-beheer"</string>
- <string name="permdesc_bluetoothAdmin" product="tablet" msgid="3511795757324345837">"Hiermee kan een toepassing de lokale Bluetooth-tablet configureren en externe apparaten zoeken en aansluiten."</string>
- <string name="permdesc_bluetoothAdmin" product="default" msgid="7256289774667054555">"Hiermee kan een toepassing de lokale Bluetooth-telefoon configureren en externe apparaten zoeken en aansluiten."</string>
+ <string name="permdesc_bluetoothAdmin" product="tablet" msgid="3511795757324345837">"Hiermee kan een app de lokale Bluetooth-tablet configureren en externe apparaten zoeken en aansluiten."</string>
+ <string name="permdesc_bluetoothAdmin" product="default" msgid="7256289774667054555">"Hiermee kan een app de lokale Bluetooth-telefoon configureren en externe apparaten zoeken en aansluiten."</string>
<string name="permlab_bluetooth" msgid="8361038707857018732">"Bluetooth-verbindingen maken"</string>
- <string name="permdesc_bluetooth" product="tablet" msgid="4191941825910543803">"Hiermee kan een toepassing de configuratie van een lokale Bluetooth-tablet bekijken en verbindingen met gekoppelde apparaten maken en accepteren."</string>
- <string name="permdesc_bluetooth" product="default" msgid="762515380679392945">"Hiermee kan een toepassing de configuratie van een lokale Bluetooth-telefoon bekijken en verbindingen met gekoppelde apparaten maken en accepteren."</string>
+ <string name="permdesc_bluetooth" product="tablet" msgid="4191941825910543803">"Hiermee kan een app de configuratie van een lokale Bluetooth-tablet bekijken en verbindingen met gekoppelde apparaten maken en accepteren."</string>
+ <string name="permdesc_bluetooth" product="default" msgid="762515380679392945">"Hiermee kan een app de configuratie van een lokale Bluetooth-telefoon bekijken en verbindingen met gekoppelde apparaten maken en accepteren."</string>
<string name="permlab_nfc" msgid="4423351274757876953">"Near Field Communication regelen"</string>
- <string name="permdesc_nfc" msgid="9171401851954407226">"Hiermee kan een toepassing communiceren met NFC-tags (Near Field Communication), kaarten en lezers."</string>
+ <string name="permdesc_nfc" msgid="9171401851954407226">"Hiermee kan een app communiceren met NFC-tags (Near Field Communication), kaarten en lezers."</string>
<string name="permlab_disableKeyguard" msgid="4977406164311535092">"toetsvergrendeling uitschakelen"</string>
- <string name="permdesc_disableKeyguard" msgid="3189763479326302017">"Hiermee kan een toepassing de toetsvergrendeling en bijbehorende wachtwoordbeveiliging uitschakelen. Een voorbeeld: de telefoon schakelt de toetsvergrendeling uit als er een oproep binnenkomt en schakelt de toetsvergrendeling weer in als de oproep is beëindigd."</string>
+ <string name="permdesc_disableKeyguard" msgid="3189763479326302017">"Hiermee kan een app de toetsvergrendeling en bijbehorende wachtwoordbeveiliging uitschakelen. Een voorbeeld: de telefoon schakelt de toetsvergrendeling uit wanneer een oproep binnenkomt en schakelt de toetsvergrendeling weer in zodra de oproep wordt beëindigd."</string>
<string name="permlab_readSyncSettings" msgid="6201810008230503052">"synchronisatie-instellingen lezen"</string>
- <string name="permdesc_readSyncSettings" msgid="5315925706353341823">"Hiermee kan een toepassing de synchronisatie-instellingen lezen, bijvoorbeeld of de synchronisatie van contacten is ingeschakeld."</string>
+ <string name="permdesc_readSyncSettings" msgid="5315925706353341823">"Hiermee kan een app de synchronisatie-instellingen lezen, bijvoorbeeld of de synchronisatie van contacten is ingeschakeld."</string>
<string name="permlab_writeSyncSettings" msgid="6297138566442486462">"synchronisatie-instellingen schrijven"</string>
- <string name="permdesc_writeSyncSettings" msgid="2498201614431360044">"Hiermee kan een toepassing uw synchronisatie-instellingen wijzigen, bijvoorbeeld of de synchronisatie van contacten is ingeschakeld."</string>
+ <string name="permdesc_writeSyncSettings" msgid="2498201614431360044">"Hiermee kan een app uw synchronisatie-instellingen wijzigen, bijvoorbeeld of de synchronisatie van contacten is ingeschakeld."</string>
<string name="permlab_readSyncStats" msgid="7396577451360202448">"synchronisatiestatistieken lezen"</string>
- <string name="permdesc_readSyncStats" msgid="7511448343374465000">"Hiermee kan een toepassing de synchronisatiestatistieken lezen, zoals de geschiedenis van uitgevoerde synchronisaties."</string>
+ <string name="permdesc_readSyncStats" msgid="7511448343374465000">"Hiermee kan een app de synchronisatiestatistieken lezen, zoals de geschiedenis van uitgevoerde synchronisaties."</string>
<string name="permlab_subscribedFeedsRead" msgid="4756609637053353318">"geabonneerde feeds lezen"</string>
- <string name="permdesc_subscribedFeedsRead" msgid="3622200625634207660">"Hiermee kan een toepassing details over de huidige gesynchroniseerde feeds achterhalen."</string>
+ <string name="permdesc_subscribedFeedsRead" msgid="3622200625634207660">"Hiermee kan een app details over de huidige gesynchroniseerde feeds achterhalen."</string>
<string name="permlab_subscribedFeedsWrite" msgid="9015246325408209296">"geabonneerde feeds schrijven"</string>
- <string name="permdesc_subscribedFeedsWrite" msgid="8121607099326533878">"Hiermee kan een toepassing uw huidige gesynchroniseerde feeds wijzigen. Een schadelijke toepassing kan op deze manier uw gesynchroniseerde feeds wijzigen."</string>
+ <string name="permdesc_subscribedFeedsWrite" msgid="8121607099326533878">"Hiermee kan een app uw huidige gesynchroniseerde feeds wijzigen. Een schadelijke app kan op deze manier uw gesynchroniseerde feeds wijzigen."</string>
<string name="permlab_readDictionary" msgid="432535716804748781">"door gebruiker gedefinieerd woordenboek lezen"</string>
- <string name="permdesc_readDictionary" msgid="1082972603576360690">"Hiermee kan een toepassing privéwoorden, namen en woordcombinaties lezen die de gebruiker heeft opgeslagen in het gebruikerswoordenboek."</string>
+ <string name="permdesc_readDictionary" msgid="1082972603576360690">"Hiermee kan een app privéwoorden, namen en woordcombinaties lezen die de gebruiker heeft opgeslagen in het gebruikerswoordenboek."</string>
<string name="permlab_writeDictionary" msgid="6703109511836343341">"schrijven naar door gebruiker gedefinieerd woordenboek"</string>
- <string name="permdesc_writeDictionary" msgid="2241256206524082880">"Hiermee kan een toepassing nieuwe woorden schrijven naar het gebruikerswoordenboek."</string>
+ <string name="permdesc_writeDictionary" msgid="2241256206524082880">"Hiermee kan een app nieuwe woorden schrijven naar het gebruikerswoordenboek."</string>
<string name="permlab_sdcardWrite" product="nosdcard" msgid="85430876310764752">"inhoud van USB-opslag aanpassen/verwijderen"</string>
<string name="permlab_sdcardWrite" product="default" msgid="8079403759001777291">"inhoud op de SD-kaart aanpassen/verwijderen"</string>
- <string name="permdesc_sdcardWrite" product="nosdcard" msgid="6594393334785738252">"Hiermee kan een toepassing schrijven naar de USB-opslag."</string>
- <string name="permdesc_sdcardWrite" product="default" msgid="6643963204976471878">"Hiermee kan een toepassing schrijven naar de SD-kaart."</string>
+ <string name="permdesc_sdcardWrite" product="nosdcard" msgid="6594393334785738252">"Hiermee kan een app schrijven naar de USB-opslag."</string>
+ <string name="permdesc_sdcardWrite" product="default" msgid="6643963204976471878">"Hiermee kan een app schrijven naar de SD-kaart."</string>
<string name="permlab_mediaStorageWrite" product="default" msgid="6859839199706879015">"inh. mediaopsl. wijz./verw."</string>
- <string name="permdesc_mediaStorageWrite" product="default" msgid="8232008512478316233">"Hiermee kan een toepassing de inhoud van interne mediaopslag aanpassen."</string>
+ <string name="permdesc_mediaStorageWrite" product="default" msgid="8232008512478316233">"Hiermee kan een app de inhoud van interne mediaopslag aanpassen."</string>
<string name="permlab_cache_filesystem" msgid="5656487264819669824">"het cachebestandssysteem openen"</string>
- <string name="permdesc_cache_filesystem" msgid="1624734528435659906">"Staat een toepassing toe het cachebestandssysteem te lezen en te schrijven."</string>
+ <string name="permdesc_cache_filesystem" msgid="1624734528435659906">"Staat een app toe het cachebestandssysteem te lezen en te schrijven."</string>
<string name="permlab_use_sip" msgid="5986952362795870502">"internetoproepen starten/ontvangen"</string>
- <string name="permdesc_use_sip" msgid="6320376185606661843">"Hiermee kan een toepassing de SIP-service gebruiken om internetoproepen te starten/te ontvangen."</string>
+ <string name="permdesc_use_sip" msgid="6320376185606661843">"Hiermee kan een app de SIP-service gebruiken om internetoproepen te starten/te ontvangen."</string>
<string name="policylab_limitPassword" msgid="4497420728857585791">"Wachtwoordregels instellen"</string>
<string name="policydesc_limitPassword" msgid="9083400080861728056">"De lengte en tekens beheren die zijn toegestaan in wachtwoorden voor schermontgrendeling"</string>
<string name="policylab_watchLogin" msgid="914130646942199503">"Pogingen voor schermontgrendeling bijhouden"</string>
@@ -484,8 +484,8 @@
<string name="policydesc_wipeData" product="default" msgid="7669895333814222586">"De gegevens van de telefoon zonder waarschuwing wissen door de fabrieksinstellingen te herstellen"</string>
<string name="policylab_setGlobalProxy" msgid="2784828293747791446">"Algemene proxy voor het apparaat instellen"</string>
<string name="policydesc_setGlobalProxy" msgid="6387497466660154931">"Stel de algemene proxy voor het apparaat in die moet worden gebruikt terwijl het beleid is geactiveerd. Alleen de eerste apparaatbeheerder stelt de algemene proxy in."</string>
- <string name="policylab_expirePassword" msgid="2314569545488269564">"Verval wachtwoord instellen"</string>
- <string name="policydesc_expirePassword" msgid="7276906351852798814">"Beheren hoe lang het duurt voordat het wachtwoord voor schermvergrendeling moet worden gewijzigd"</string>
+ <!-- outdated translation 4740941403188940274 --> <string name="policylab_expirePassword" msgid="885279151847254056">"Verval wachtwoord instellen"</string>
+ <!-- outdated translation 6626724939177185949 --> <string name="policydesc_expirePassword" msgid="4844430354224822074">"Beheren hoe lang het duurt voordat het wachtwoord voor schermvergrendeling moet worden gewijzigd"</string>
<string name="policylab_encryptedStorage" msgid="8901326199909132915">"Codering voor opslag instellen"</string>
<string name="policydesc_encryptedStorage" msgid="2504984732631479399">"Vereisen dat opgeslagen toepassingsgegevens kunnen worden gecodeerd"</string>
<string-array name="phoneTypes">
@@ -672,14 +672,14 @@
<string name="autofill_address_summary_separator" msgid="7483307893170324129">", "</string>
<string name="autofill_address_summary_format" msgid="4874459455786827344">"$1$2$3"</string>
<string name="permlab_readHistoryBookmarks" msgid="1284843728203412135">"browsergeschiedenis en bladwijzers lezen"</string>
- <string name="permdesc_readHistoryBookmarks" msgid="4981489815467617191">"Hiermee kan een toepassing de URL\'s lezen die u via de browser heeft bezocht, evenals alle bladwijzers van de browser."</string>
+ <string name="permdesc_readHistoryBookmarks" msgid="4981489815467617191">"Hiermee kan een app de URL\'s lezen die u via de browser heeft bezocht, evenals alle bladwijzers van de browser."</string>
<string name="permlab_writeHistoryBookmarks" msgid="9009434109836280374">"browsergeschiedenis en bladwijzers schrijven"</string>
- <string name="permdesc_writeHistoryBookmarks" product="tablet" msgid="7193514090469945307">"Hiermee kan een toepassing de op uw tablet opgeslagen browsergeschiedenis of bladwijzers wijzigen. Schadelijke toepassingen kunnen hiermee uw browsergegevens verwijderen of wijzigen."</string>
- <string name="permdesc_writeHistoryBookmarks" product="default" msgid="945571990357114950">"Hiermee kan een toepassing de op uw telefoon opgeslagen browsergeschiedenis of bladwijzers wijzigen. Schadelijke toepassingen kunnen hiermee uw browsergegevens verwijderen of wijzigen."</string>
+ <string name="permdesc_writeHistoryBookmarks" product="tablet" msgid="7193514090469945307">"Hiermee kan een app de op uw tablet opgeslagen browsergeschiedenis of bladwijzers wijzigen. Schadelijke apps kunnen hiermee uw browsergegevens verwijderen of wijzigen."</string>
+ <string name="permdesc_writeHistoryBookmarks" product="default" msgid="945571990357114950">"Hiermee kan een app de op uw telefoon opgeslagen browsergeschiedenis of bladwijzers wijzigen. Schadelijke apps kunnen hiermee uw browsergegevens verwijderen of wijzigen."</string>
<string name="permlab_setAlarm" msgid="5924401328803615165">"alarm instellen in wekker"</string>
- <string name="permdesc_setAlarm" msgid="5966966598149875082">"Hiermee kan de toepassing een alarm instellen in een geïnstalleerde wekkertoepassing. Deze functie wordt door sommige wekkertoepassingen niet geïmplementeerd."</string>
+ <string name="permdesc_setAlarm" msgid="5966966598149875082">"Hiermee kan de app een alarm instellen in een geïnstalleerde wekker-app. Deze functie wordt door sommige wekker-apps niet geïmplementeerd."</string>
<string name="permlab_writeGeolocationPermissions" msgid="4715212655598275532">"Geolocatierechten voor browser aanpassen"</string>
- <string name="permdesc_writeGeolocationPermissions" msgid="4011908282980861679">"Staat een toepassing toe de geolocatierechten van de browser aan te passen. Schadelijke toepassingen kunnen dit gebruiken om locatiegegevens te verzenden naar willekeurige websites."</string>
+ <string name="permdesc_writeGeolocationPermissions" msgid="4011908282980861679">"Staat een app toe de geolocatierechten van de browser aan te passen. Schadelijke apps kunnen dit gebruiken om locatiegegevens te verzenden naar willekeurige websites."</string>
<string name="save_password_message" msgid="767344687139195790">"Wilt u dat de browser dit wachtwoord onthoudt?"</string>
<string name="save_password_notnow" msgid="6389675316706699758">"Niet nu"</string>
<string name="save_password_remember" msgid="6491879678996749466">"Onthouden"</string>
@@ -814,31 +814,31 @@
<string name="alwaysUse" msgid="4583018368000610438">"Standaard gebruiken voor deze actie."</string>
<string name="clearDefaultHintMsg" msgid="4815455344600932173">"Wis standaardinstelling via startscherm: \'Instellingen\' &gt; \'Toepassingen\' &gt; \'Toepassingen beheren\'."</string>
<string name="chooseActivity" msgid="1009246475582238425">"Een actie selecteren"</string>
- <string name="noApplications" msgid="1691104391758345586">"Geen enkele toepassing kan deze actie uitvoeren."</string>
+ <string name="noApplications" msgid="1691104391758345586">"Geen enkele app kan deze actie uitvoeren."</string>
<string name="aerr_title" msgid="653922989522758100">"Helaas!"</string>
- <string name="aerr_application" msgid="4683614104336409186">"De toepassing <xliff:g id="APPLICATION">%1$s</xliff:g> (proces <xliff:g id="PROCESS">%2$s</xliff:g>) is onverwachts gestopt. Probeer het opnieuw."</string>
+ <string name="aerr_application" msgid="4683614104336409186">"De app <xliff:g id="APPLICATION">%1$s</xliff:g> (proces <xliff:g id="PROCESS">%2$s</xliff:g>) is onverwachts gestopt. Probeer het opnieuw."</string>
<string name="aerr_process" msgid="1551785535966089511">"Het proces <xliff:g id="PROCESS">%1$s</xliff:g> is onverwachts gestopt. Probeer het opnieuw."</string>
<string name="anr_title" msgid="3100070910664756057">"Helaas!"</string>
- <string name="anr_activity_application" msgid="3538242413112507636">"Activiteit <xliff:g id="ACTIVITY">%1$s</xliff:g> (in toepassing <xliff:g id="APPLICATION">%2$s</xliff:g>) reageert niet."</string>
+ <string name="anr_activity_application" msgid="3538242413112507636">"Activiteit <xliff:g id="ACTIVITY">%1$s</xliff:g> (in app <xliff:g id="APPLICATION">%2$s</xliff:g>) reageert niet."</string>
<string name="anr_activity_process" msgid="5420826626009561014">"Activiteit <xliff:g id="ACTIVITY">%1$s</xliff:g> (in proces <xliff:g id="PROCESS">%2$s</xliff:g>) reageert niet."</string>
- <string name="anr_application_process" msgid="4185842666452210193">"Toepassing <xliff:g id="APPLICATION">%1$s</xliff:g> (in proces <xliff:g id="PROCESS">%2$s</xliff:g>) reageert niet."</string>
+ <string name="anr_application_process" msgid="4185842666452210193">"App <xliff:g id="APPLICATION">%1$s</xliff:g> (in proces <xliff:g id="PROCESS">%2$s</xliff:g>) reageert niet."</string>
<string name="anr_process" msgid="1246866008169975783">"Proces <xliff:g id="PROCESS">%1$s</xliff:g> reageert niet."</string>
<string name="force_close" msgid="3653416315450806396">"Nu sluiten"</string>
<string name="report" msgid="4060218260984795706">"Rapport"</string>
<string name="wait" msgid="7147118217226317732">"Wachten"</string>
- <string name="launch_warning_title" msgid="8323761616052121936">"Toepassing omgeleid"</string>
+ <string name="launch_warning_title" msgid="8323761616052121936">"App omgeleid"</string>
<string name="launch_warning_replace" msgid="6202498949970281412">"<xliff:g id="APP_NAME">%1$s</xliff:g> is nu actief."</string>
<string name="launch_warning_original" msgid="188102023021668683">"<xliff:g id="APP_NAME">%1$s</xliff:g> was het eerst gestart."</string>
- <string name="smv_application" msgid="295583804361236288">"De toepassing <xliff:g id="APPLICATION">%1$s</xliff:g> (proces <xliff:g id="PROCESS">%2$s</xliff:g>) heeft het zelf afgedwongen StrictMode-beleid geschonden."</string>
+ <string name="smv_application" msgid="295583804361236288">"De app <xliff:g id="APPLICATION">%1$s</xliff:g> (proces <xliff:g id="PROCESS">%2$s</xliff:g>) heeft het zelf afgedwongen StrictMode-beleid geschonden."</string>
<string name="smv_process" msgid="5120397012047462446">"Het proces <xliff:g id="PROCESS">%1$s</xliff:g> heeft het zelf afgedwongen StrictMode-beleid geschonden."</string>
<string name="heavy_weight_notification" msgid="9087063985776626166">"<xliff:g id="APP">%1$s</xliff:g> wordt uitgevoerd"</string>
- <string name="heavy_weight_notification_detail" msgid="2423977499339403402">"Selecteren om over te schakelen naar toepassing"</string>
+ <string name="heavy_weight_notification_detail" msgid="2423977499339403402">"Selecteren om over te schakelen naar app"</string>
<string name="heavy_weight_switcher_title" msgid="1135403633766694316">"Toepassingen wijzigen?"</string>
- <string name="heavy_weight_switcher_text" msgid="4592075610079319667">"Er wordt al een andere toepassing uitgevoerd die moet worden gestopt voordat u een nieuwe toepassing kunt starten."</string>
+ <string name="heavy_weight_switcher_text" msgid="4592075610079319667">"Er wordt al een andere app uitgevoerd die moet worden gestopt voordat u een nieuwe app kunt starten."</string>
<string name="old_app_action" msgid="493129172238566282">"Terug naar <xliff:g id="OLD_APP">%1$s</xliff:g>"</string>
- <string name="old_app_description" msgid="942967900237208466">"De nieuwe toepassing niet starten."</string>
+ <string name="old_app_description" msgid="942967900237208466">"De nieuwe app niet starten."</string>
<string name="new_app_action" msgid="5472756926945440706">"<xliff:g id="OLD_APP">%1$s</xliff:g> starten"</string>
- <string name="new_app_description" msgid="6830398339826789493">"De oude toepassing stoppen zonder opslaan."</string>
+ <string name="new_app_description" msgid="6830398339826789493">"De oude app stoppen zonder opslaan."</string>
<string name="sendText" msgid="5132506121645618310">"Selecteer een actie voor tekst"</string>
<string name="volume_ringtone" msgid="6885421406845734650">"Belvolume"</string>
<string name="volume_music" msgid="5421651157138628171">"Mediavolume"</string>
@@ -863,7 +863,7 @@
<item quantity="other" msgid="7915895323644292768">"Open Wi-Fi-netwerken beschikbaar"</item>
</plurals>
<string name="select_character" msgid="3365550120617701745">"Teken invoegen"</string>
- <string name="sms_control_default_app_name" msgid="7630529934366549163">"Onbekende toepassing"</string>
+ <string name="sms_control_default_app_name" msgid="7630529934366549163">"Onbekende app"</string>
<string name="sms_control_title" msgid="7296612781128917719">"SMS-berichten verzenden"</string>
<string name="sms_control_message" msgid="1289331457999236205">"Er wordt een groot aantal SMS-berichten verzonden. Selecteer \'OK\' om door te gaan of \'Annuleren\' om de verzending te stoppen."</string>
<string name="sms_control_yes" msgid="2532062172402615953">"OK"</string>
diff --git a/core/res/res/values-pl/strings.xml b/core/res/res/values-pl/strings.xml
index 3035e96..99f723c 100644
--- a/core/res/res/values-pl/strings.xml
+++ b/core/res/res/values-pl/strings.xml
@@ -484,8 +484,8 @@
<string name="policydesc_wipeData" product="default" msgid="7669895333814222586">"Wymazywanie danych z telefonu bez ostrzeżenia, przez przywrócenie danych fabrycznych"</string>
<string name="policylab_setGlobalProxy" msgid="2784828293747791446">"Ustaw globalny serwer proxy urządzenia"</string>
<string name="policydesc_setGlobalProxy" msgid="6387497466660154931">"Ustaw globalny serwer proxy urządzenia do wykorzystywania przy włączonych zasadach. Tylko pierwszy administrator urządzenia ustawia obowiązujący globalny serwer proxy."</string>
- <string name="policylab_expirePassword" msgid="2314569545488269564">"Ustaw wygasanie hasła"</string>
- <string name="policydesc_expirePassword" msgid="7276906351852798814">"Kontrola czasu, po którym należy zmienić hasło blokowania ekranu"</string>
+ <!-- outdated translation 4740941403188940274 --> <string name="policylab_expirePassword" msgid="885279151847254056">"Ustaw wygasanie hasła"</string>
+ <!-- outdated translation 6626724939177185949 --> <string name="policydesc_expirePassword" msgid="4844430354224822074">"Kontrola czasu, po którym należy zmienić hasło blokowania ekranu"</string>
<string name="policylab_encryptedStorage" msgid="8901326199909132915">"Ustaw szyfrowanie pamięci"</string>
<string name="policydesc_encryptedStorage" msgid="2504984732631479399">"Wymaga szyfrowania danych zapisanych aplikacji"</string>
<string-array name="phoneTypes">
diff --git a/core/res/res/values-pt-rPT/strings.xml b/core/res/res/values-pt-rPT/strings.xml
index f6ab376..9c069c4 100644
--- a/core/res/res/values-pt-rPT/strings.xml
+++ b/core/res/res/values-pt-rPT/strings.xml
@@ -484,8 +484,8 @@
<string name="policydesc_wipeData" product="default" msgid="7669895333814222586">"Apagar os dados do telefone sem avisar, ao efectuar uma reposição de dados de fábrica"</string>
<string name="policylab_setGlobalProxy" msgid="2784828293747791446">"Definir o proxy global do aparelho"</string>
<string name="policydesc_setGlobalProxy" msgid="6387497466660154931">"Definir o proxy global do aparelho a ser utilizado quando a política estiver activada. Só o primeiro administrador do aparelho define o proxy global efectivo."</string>
- <string name="policylab_expirePassword" msgid="2314569545488269564">"Def. valid. da palavra-passe"</string>
- <string name="policydesc_expirePassword" msgid="7276906351852798814">"Controle com que antecedência é necessário alterar a palavra-passe de bloqueio do ecrã"</string>
+ <!-- outdated translation 4740941403188940274 --> <string name="policylab_expirePassword" msgid="885279151847254056">"Definir tempo de validade da palavra-passe"</string>
+ <!-- outdated translation 6626724939177185949 --> <string name="policydesc_expirePassword" msgid="4844430354224822074">"Controle com que antecedência é necessário alterar a palavra-passe de bloqueio do ecrã"</string>
<string name="policylab_encryptedStorage" msgid="8901326199909132915">"Def. encriptação armazenamento"</string>
<string name="policydesc_encryptedStorage" msgid="2504984732631479399">"Requerer encriptação dos dados da aplicação armazenados"</string>
<string-array name="phoneTypes">
diff --git a/core/res/res/values-pt/strings.xml b/core/res/res/values-pt/strings.xml
index 6542cd3..e8b230f 100644
--- a/core/res/res/values-pt/strings.xml
+++ b/core/res/res/values-pt/strings.xml
@@ -484,8 +484,8 @@
<string name="policydesc_wipeData" product="default" msgid="7669895333814222586">"Apaga os dados do telefone sem aviso, executando uma redefinição da configuração original"</string>
<string name="policylab_setGlobalProxy" msgid="2784828293747791446">"Definir o proxy global do dispositivo"</string>
<string name="policydesc_setGlobalProxy" msgid="6387497466660154931">"Configura o proxy global do dispositivo para ser usado enquanto a política estiver ativada. Somente o primeiro administrador do dispositivo pode configurar um verdadeiro proxy global."</string>
- <string name="policylab_expirePassword" msgid="2314569545488269564">"Definir validade da senha"</string>
- <string name="policydesc_expirePassword" msgid="7276906351852798814">"Controle quanto tempo uma senha de bloqueio de tela deve ficar ativa antes de ser alterada"</string>
+ <!-- outdated translation 4740941403188940274 --> <string name="policylab_expirePassword" msgid="885279151847254056">"Definir validade da senha"</string>
+ <!-- outdated translation 6626724939177185949 --> <string name="policydesc_expirePassword" msgid="4844430354224822074">"Controle quanto tempo uma senha de bloqueio de tela deve ficar ativa antes de ser alterada"</string>
<string name="policylab_encryptedStorage" msgid="8901326199909132915">"Definir criptografia de armazenamento"</string>
<string name="policydesc_encryptedStorage" msgid="2504984732631479399">"Exigir que os dados do aplicativo armazenado sejam criptografados"</string>
<string-array name="phoneTypes">
diff --git a/core/res/res/values-rm/strings.xml b/core/res/res/values-rm/strings.xml
index e28b304..f3073bd 100644
--- a/core/res/res/values-rm/strings.xml
+++ b/core/res/res/values-rm/strings.xml
@@ -498,9 +498,9 @@
<!-- outdated translation 2314060933796396205 --> <string name="policydesc_wipeData" product="default" msgid="7669895333814222586">"Restaurar ils parameters originals dal telefonin. Qua tras vegnan tut Vossas datas stizzadas senza dumonda da conferma."</string>
<string name="policylab_setGlobalProxy" msgid="2784828293747791446">"Definir il proxy global da l\'apparat"</string>
<string name="policydesc_setGlobalProxy" msgid="6387497466660154931">"Definir il proxy global da l\'apparat che duai vegnir utilisà sche la directiva è activada. Mo l\'emprim administratur dad apparats definescha il vair proxy global."</string>
- <!-- no translation found for policylab_expirePassword (2314569545488269564) -->
+ <!-- no translation found for policylab_expirePassword (885279151847254056) -->
<skip />
- <!-- no translation found for policydesc_expirePassword (7276906351852798814) -->
+ <!-- no translation found for policydesc_expirePassword (4844430354224822074) -->
<skip />
<!-- no translation found for policylab_encryptedStorage (8901326199909132915) -->
<skip />
diff --git a/core/res/res/values-ro/strings.xml b/core/res/res/values-ro/strings.xml
index 5326a4c..217c965 100644
--- a/core/res/res/values-ro/strings.xml
+++ b/core/res/res/values-ro/strings.xml
@@ -484,8 +484,8 @@
<string name="policydesc_wipeData" product="default" msgid="7669895333814222586">"Ştergeţi datele din telefon fără avertisment, efectuând resetarea configurării din fabrică"</string>
<string name="policylab_setGlobalProxy" msgid="2784828293747791446">"Setaţi serverul proxy global pentru dispozitiv"</string>
<string name="policydesc_setGlobalProxy" msgid="6387497466660154931">"Setaţi serverul proxy global pentru dispozitiv care să fie utilizat cât timp politica este activă. Numai primul administrator al dispozitivului poate seta serverul proxy global activ."</string>
- <string name="policylab_expirePassword" msgid="2314569545488269564">"Setaţi expirarea parolei"</string>
- <string name="policydesc_expirePassword" msgid="7276906351852798814">"Controlarea duratei până când parola de blocare a ecranului trebuie modificată"</string>
+ <!-- outdated translation 4740941403188940274 --> <string name="policylab_expirePassword" msgid="885279151847254056">"Setaţi expirarea parolei"</string>
+ <!-- outdated translation 6626724939177185949 --> <string name="policydesc_expirePassword" msgid="4844430354224822074">"Controlarea duratei până când parola de blocare a ecranului trebuie modificată"</string>
<string name="policylab_encryptedStorage" msgid="8901326199909132915">"Setaţi criptarea stocării"</string>
<string name="policydesc_encryptedStorage" msgid="2504984732631479399">"Necesită ca datele aplicaţiei stocate să fie criptate"</string>
<string-array name="phoneTypes">
diff --git a/core/res/res/values-ru/strings.xml b/core/res/res/values-ru/strings.xml
index 436d09b..405fbc0 100644
--- a/core/res/res/values-ru/strings.xml
+++ b/core/res/res/values-ru/strings.xml
@@ -484,8 +484,8 @@
<string name="policydesc_wipeData" product="default" msgid="7669895333814222586">"Уничтожить все данные на телефоне без предупреждения путем сброса настроек"</string>
<string name="policylab_setGlobalProxy" msgid="2784828293747791446">"Глобальный прокси-сервер"</string>
<string name="policydesc_setGlobalProxy" msgid="6387497466660154931">"Настройте глобальный прокси-сервер устройства, который будет использоваться при активной политике. Глобальный прокси-сервер должен настроить первый администратор устройства."</string>
- <string name="policylab_expirePassword" msgid="2314569545488269564">"Задать время действия пароля"</string>
- <string name="policydesc_expirePassword" msgid="7276906351852798814">"Задать время действия пароля перед появлением экрана блокировки"</string>
+ <!-- outdated translation 4740941403188940274 --> <string name="policylab_expirePassword" msgid="885279151847254056">"Задать время действия пароля"</string>
+ <!-- outdated translation 6626724939177185949 --> <string name="policydesc_expirePassword" msgid="4844430354224822074">"Задать время действия пароля перед появлением экрана блокировки"</string>
<string name="policylab_encryptedStorage" msgid="8901326199909132915">"Настроить шифрование хранилища"</string>
<string name="policydesc_encryptedStorage" msgid="2504984732631479399">"Требует шифровать данные приложений, находящиеся в хранилище."</string>
<string-array name="phoneTypes">
diff --git a/core/res/res/values-sk/strings.xml b/core/res/res/values-sk/strings.xml
index 0895aa1..9605af2 100644
--- a/core/res/res/values-sk/strings.xml
+++ b/core/res/res/values-sk/strings.xml
@@ -484,8 +484,8 @@
<string name="policydesc_wipeData" product="default" msgid="7669895333814222586">"Bez predchádzajúceho upozornenia zmazať všetky údaje tým, že sa obnovia továrenské nastavenia telefónu"</string>
<string name="policylab_setGlobalProxy" msgid="2784828293747791446">"Nastaviť globálny server proxy zariadenia"</string>
<string name="policydesc_setGlobalProxy" msgid="6387497466660154931">"Vyberte globálny server proxy, ktorý sa bude používať po aktivácii pravidiel. Platný globálny server proxy nastavuje iba prvý správca zariadenia."</string>
- <string name="policylab_expirePassword" msgid="2314569545488269564">"Nastav. koniec platnosti hesla"</string>
- <string name="policydesc_expirePassword" msgid="7276906351852798814">"Ovládanie doby, po uplynutí ktorej treba zmeniť heslo na odomknutie obrazovky"</string>
+ <!-- outdated translation 4740941403188940274 --> <string name="policylab_expirePassword" msgid="885279151847254056">"Nastaviť dátum vypršania platnosti hesla"</string>
+ <!-- outdated translation 6626724939177185949 --> <string name="policydesc_expirePassword" msgid="4844430354224822074">"Ovládanie doby, po uplynutí ktorej treba zmeniť heslo na odomknutie obrazovky"</string>
<string name="policylab_encryptedStorage" msgid="8901326199909132915">"Nastaviť šifr. ukl. priestoru"</string>
<string name="policydesc_encryptedStorage" msgid="2504984732631479399">"Vyžaduje šifrovanie uložených údajov aplikácií"</string>
<string-array name="phoneTypes">
diff --git a/core/res/res/values-sl/strings.xml b/core/res/res/values-sl/strings.xml
index 486e266..a460627 100644
--- a/core/res/res/values-sl/strings.xml
+++ b/core/res/res/values-sl/strings.xml
@@ -484,8 +484,8 @@
<string name="policydesc_wipeData" product="default" msgid="7669895333814222586">"Brisanje (s tovarniško ponastavitvijo) vseh podatkov v telefonu brez opozorila"</string>
<string name="policylab_setGlobalProxy" msgid="2784828293747791446">"Nastavitev globalnega strežnika proxy za napravo"</string>
<string name="policydesc_setGlobalProxy" msgid="6387497466660154931">"Nastavite globalni strežnik proxy naprave, ki bo v uporabi, ko je pravilnik omogočen. Samo skrbnik prve naprave lahko nastavi veljaven globalni strežnik proxy."</string>
- <string name="policylab_expirePassword" msgid="2314569545488269564">"Nastavitev poteka gesla"</string>
- <string name="policydesc_expirePassword" msgid="7276906351852798814">"Nastavite, koliko časa prej je treba spremeniti geslo za odklepanje zaslona"</string>
+ <!-- outdated translation 4740941403188940274 --> <string name="policylab_expirePassword" msgid="885279151847254056">"Nastavitev poteka gesla"</string>
+ <!-- outdated translation 6626724939177185949 --> <string name="policydesc_expirePassword" msgid="4844430354224822074">"Nastavite, koliko časa prej je treba spremeniti geslo za odklepanje zaslona"</string>
<string name="policylab_encryptedStorage" msgid="8901326199909132915">"Nastavitev šifriranja shrambe"</string>
<string name="policydesc_encryptedStorage" msgid="2504984732631479399">"Shranjeni podatki programa morajo biti šifrirani"</string>
<string-array name="phoneTypes">
diff --git a/core/res/res/values-sr/strings.xml b/core/res/res/values-sr/strings.xml
index aebd8e2..a6f1e5f 100644
--- a/core/res/res/values-sr/strings.xml
+++ b/core/res/res/values-sr/strings.xml
@@ -484,8 +484,8 @@
<string name="policydesc_wipeData" product="default" msgid="7669895333814222586">"Брисање података на телефону без упозорења враћањем фабричких података"</string>
<string name="policylab_setGlobalProxy" msgid="2784828293747791446">"Подесите глобални прокси сервер уређаја"</string>
<string name="policydesc_setGlobalProxy" msgid="6387497466660154931">"Подесите глобални прокси сервер уређаја који ће се користити док су омогућене смернице. Само први администратор уређаја поставља ефективни глобални прокси сервер."</string>
- <string name="policylab_expirePassword" msgid="2314569545488269564">"Подеси време истека лозинке"</string>
- <string name="policydesc_expirePassword" msgid="7276906351852798814">"Контролишите време када лозинка за закључавање екрана треба да се промени"</string>
+ <!-- outdated translation 4740941403188940274 --> <string name="policylab_expirePassword" msgid="885279151847254056">"Подеси време истека лозинке"</string>
+ <!-- outdated translation 6626724939177185949 --> <string name="policydesc_expirePassword" msgid="4844430354224822074">"Контролишите време када лозинка за закључавање екрана треба да се промени"</string>
<string name="policylab_encryptedStorage" msgid="8901326199909132915">"Подешавање шифровања складишта"</string>
<string name="policydesc_encryptedStorage" msgid="2504984732631479399">"Захтева да сачувани подаци апликације буду шифровани"</string>
<string-array name="phoneTypes">
diff --git a/core/res/res/values-sv/strings.xml b/core/res/res/values-sv/strings.xml
index 296c2a3..1c234c2 100644
--- a/core/res/res/values-sv/strings.xml
+++ b/core/res/res/values-sv/strings.xml
@@ -140,7 +140,7 @@
<string name="shutdown_confirm" product="default" msgid="649792175242821353">"Din telefon stängs av."</string>
<string name="shutdown_confirm_question" msgid="6656441286856415014">"Vill du stänga av?"</string>
<string name="recent_tasks_title" msgid="3691764623638127888">"Senaste"</string>
- <string name="no_recent_tasks" msgid="279702952298056674">"Inga nya program."</string>
+ <string name="no_recent_tasks" msgid="279702952298056674">"Inga nya appar."</string>
<string name="global_actions" product="tablet" msgid="408477140088053665">"Alternativ för pekdatorn"</string>
<string name="global_actions" product="default" msgid="2406416831541615258">"Telefonalternativ"</string>
<string name="global_action_lock" msgid="2844945191792119712">"Skärmlås"</string>
@@ -202,7 +202,7 @@
<string name="permdesc_receiveWapPush" msgid="5979623826128082171">"Tillåter att program tar emot och bearbetar WAP-meddelanden. Skadliga program kan övervaka dina meddelanden eller ta bort dem utan att visa dem för dig."</string>
<string name="permlab_getTasks" msgid="5005277531132573353">"hämta appar som körs"</string>
<string name="permdesc_getTasks" msgid="7048711358713443341">"Tillåter att program hämtar information om uppgifter som körs och har körts. Skadliga program kan upptäcka privat information om andra program."</string>
- <string name="permlab_reorderTasks" msgid="5669588525059921549">"byt ordning på program som körs"</string>
+ <string name="permlab_reorderTasks" msgid="5669588525059921549">"byt ordning på appar som körs"</string>
<string name="permdesc_reorderTasks" msgid="126252774270522835">"Tillåter att ett program flyttar uppgifter till förgrunden eller bakgrunden. Skadliga program kan tvinga sig till förgrunden utan att du kan styra det."</string>
<string name="permlab_setDebugApp" msgid="4339730312925176742">"aktivera felsökning av appar"</string>
<string name="permdesc_setDebugApp" msgid="5584310661711990702">"Tillåter att ett program aktiverar felsökning för ett annat program. Skadliga program kan använda detta för att avsluta andra program."</string>
@@ -212,17 +212,17 @@
<string name="permdesc_enableCarMode" msgid="5673461159384850628">"Tillåter att ett program aktiverar trafikläge."</string>
<string name="permlab_killBackgroundProcesses" msgid="8373714752793061963">"avbryt bakgrundsprocesser"</string>
<string name="permdesc_killBackgroundProcesses" msgid="2908829602869383753">"Tillåter att ett program avslutar bakgrundsprocesser för andra program även om det inte finns för lite ledigt minne."</string>
- <string name="permlab_forceStopPackages" msgid="1447830113260156236">"framtvinga avslutning av andra program"</string>
+ <string name="permlab_forceStopPackages" msgid="1447830113260156236">"framtvinga avslutning av andra appar"</string>
<string name="permdesc_forceStopPackages" msgid="7263036616161367402">"Tillåter att ett program framtvingar avslutning av andra program."</string>
- <string name="permlab_forceBack" msgid="1804196839880393631">"tvinga program att avsluta"</string>
+ <string name="permlab_forceBack" msgid="1804196839880393631">"tvinga appar att avsluta"</string>
<string name="permdesc_forceBack" msgid="6534109744159919013">"Tillåter att ett program tvingar en aktivitet som finns i förgrunden att avsluta och gå tillbaka. Behövs inte för vanliga program."</string>
<string name="permlab_dump" msgid="1681799862438954752">"hämta systemets interna status"</string>
<string name="permdesc_dump" msgid="2198776174276275220">"Tillåter att ett program hämtar systemets interna status. Skadliga program kan hämta privat och skyddad information som de normalt aldrig ska behöva."</string>
<string name="permlab_shutdown" msgid="7185747824038909016">"avsluta delvis"</string>
<string name="permdesc_shutdown" msgid="7046500838746291775">"Sätter aktivitetshanteraren i avstängningsläge. Utför inte en fullständig avstängning."</string>
<string name="permlab_stopAppSwitches" msgid="4138608610717425573">"förhindrar programbyten"</string>
- <string name="permdesc_stopAppSwitches" msgid="3857886086919033794">"Hindrar att användaren byter till ett annat program."</string>
- <string name="permlab_runSetActivityWatcher" msgid="7811586187574696296">"övervaka och styra alla program som öppnas"</string>
+ <string name="permdesc_stopAppSwitches" msgid="3857886086919033794">"Hindrar att användaren byter till en annan app."</string>
+ <string name="permlab_runSetActivityWatcher" msgid="7811586187574696296">"övervaka och styra alla appar som öppnas"</string>
<string name="permdesc_runSetActivityWatcher" msgid="2149363027173451218">"Tillåter att ett program övervakar och styr hur systemet startar aktiviteter. Skadliga program kan kompromettera systemet helt. Den här behörigheten behövs bara för programmering, aldrig för vanlig användning."</string>
<string name="permlab_broadcastPackageRemoved" msgid="2576333434893532475">"skicka meddelande om borttaget paket"</string>
<string name="permdesc_broadcastPackageRemoved" msgid="3453286591439891260">"Tillåter att ett program skickar ett meddelande om att ett programpaket har tagits bort. Skadliga program kan använda detta för att avsluta alla andra program som körs."</string>
@@ -254,7 +254,7 @@
<string name="permlab_bindInputMethod" msgid="3360064620230515776">"binda till en metod för indata"</string>
<string name="permdesc_bindInputMethod" msgid="3734838321027317228">"Innehavaren tillåts att binda till den översta nivåns gränssnitt för en inmatningsmetod. Ska inte behövas för vanliga program."</string>
<string name="permlab_bindWallpaper" msgid="8716400279937856462">"binda till en bakgrund"</string>
- <string name="permdesc_bindWallpaper" msgid="5287754520361915347">"Innehavaren tillåts att binda till den översta nivåns gränssnitt för en bakgrund. Ska inte behövas för vanliga program."</string>
+ <string name="permdesc_bindWallpaper" msgid="5287754520361915347">"Innehavaren tillåts att binda till den översta nivåns gränssnitt för en bakgrund. Ska inte behövas för vanliga appar."</string>
<string name="permlab_bindRemoteViews" msgid="5697987759897367099">"bind till en widget"</string>
<string name="permdesc_bindRemoteViews" msgid="2930855984822926963">"Innehavaren tillåts att binda till den översta nivåns gränssnitt för en widget. Ska inte behövas för vanliga appar."</string>
<string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"arbeta med en enhetsadministratör"</string>
@@ -273,7 +273,7 @@
<string name="permdesc_deleteCacheFiles" msgid="2283074077168165971">"Tillåter att ett program raderar cachefiler."</string>
<string name="permlab_getPackageSize" msgid="4799785352306641460">"mäta telefonens lagringsutrymme"</string>
<string name="permdesc_getPackageSize" msgid="5557253039670753437">"Tillåter att ett program hämtar kod, data och cachestorlekar"</string>
- <string name="permlab_installPackages" msgid="335800214119051089">"installera program direkt"</string>
+ <string name="permlab_installPackages" msgid="335800214119051089">"installera appar direkt"</string>
<string name="permdesc_installPackages" msgid="526669220850066132">"Tillåter att ett program installerar nya eller uppdaterade Android-paket. Skadliga program kan använda detta för att lägga till nya program med godtyckliga och starka behörigheter."</string>
<string name="permlab_clearAppCache" msgid="4747698311163766540">"ta bort cacheinformation för alla appar"</string>
<string name="permdesc_clearAppCache" product="tablet" msgid="3097119797652477973">"Tillåter att ett program frigör lagringsutrymme på pekdatorn genom att ta bort filer i programmets katalog för cachelagring. Mycket begränsad åtkomst, vanligtvis till systemprocesser."</string>
@@ -288,7 +288,7 @@
<string name="permlab_changeComponentState" msgid="79425198834329406">"aktivera eller inaktivera programkomponenter"</string>
<string name="permdesc_changeComponentState" product="tablet" msgid="4647419365510068321">"Tillåter att ett program ändrar inställningen för om en komponent i ett annat program har aktiverats eller inte. Skadliga program kan använda detta för att inaktivera viktiga funktioner i pekdatorn. Var försiktig med behörigheten, eftersom programkomponenter kan bli oanvändbara, inkonsekventa eller instabila."</string>
<string name="permdesc_changeComponentState" product="default" msgid="3443473726140080761">"Tillåter att en app ändrar inställningen för om en komponent i en annan app ska aktiveras eller inte. Skadliga appar kan använda detta för att inaktivera viktiga funktioner i telefonen. Var försiktig med behörigheten, eftersom programkomponenter kan bli oanvändbara, inkonsekventa eller instabila."</string>
- <string name="permlab_setPreferredApplications" msgid="3393305202145172005">"ange önskade program"</string>
+ <string name="permlab_setPreferredApplications" msgid="3393305202145172005">"ange önskade appar"</string>
<string name="permdesc_setPreferredApplications" msgid="760008293501937546">"Tillåter att ett program ändrar dina önskade program. Skadliga program kan utan varning ändra de program som körs och förfalska dina befintliga program så att de samlar privata data från dig."</string>
<string name="permlab_writeSettings" msgid="1365523497395143704">"ändra globala systeminställningar"</string>
<string name="permdesc_writeSettings" msgid="838789419871034696">"Tillåter att ett program ändrar systemets inställningar. Skadliga program kan skada systemets konfiguration."</string>
@@ -484,8 +484,8 @@
<string name="policydesc_wipeData" product="default" msgid="7669895333814222586">"Ta bort data från telefonen utan förvarning genom att återställa standardinställningarna"</string>
<string name="policylab_setGlobalProxy" msgid="2784828293747791446">"Ange global proxyserver"</string>
<string name="policydesc_setGlobalProxy" msgid="6387497466660154931">"Ange vilken global proxyserver som ska användas när policyn är aktiverad. Endast den första enhetsadministratören anger den faktiska globala proxyservern."</string>
- <string name="policylab_expirePassword" msgid="2314569545488269564">"Ange lösenordets utgångsdatum"</string>
- <string name="policydesc_expirePassword" msgid="7276906351852798814">"Se hur långt det är kvar till du måste ändra lösenordet till låsningsskärmen"</string>
+ <!-- outdated translation 4740941403188940274 --> <string name="policylab_expirePassword" msgid="885279151847254056">"Ange lösenordets utgångsdatum"</string>
+ <!-- outdated translation 6626724939177185949 --> <string name="policydesc_expirePassword" msgid="4844430354224822074">"Se hur långt det är kvar till du måste ändra lösenordet till låsningsskärmen"</string>
<string name="policylab_encryptedStorage" msgid="8901326199909132915">"Ange krypterad lagring"</string>
<string name="policydesc_encryptedStorage" msgid="2504984732631479399">"Kräv att sparade applikationsdata krypteras."</string>
<string-array name="phoneTypes">
@@ -814,7 +814,7 @@
<string name="alwaysUse" msgid="4583018368000610438">"Använd som standard för denna åtgärd."</string>
<string name="clearDefaultHintMsg" msgid="4815455344600932173">"Rensa standardinställning i Startinställningar &gt; Appar &gt; Hantera appar."</string>
<string name="chooseActivity" msgid="1009246475582238425">"Välj en åtgärd"</string>
- <string name="noApplications" msgid="1691104391758345586">"Inga program kan utföra den här åtgärden."</string>
+ <string name="noApplications" msgid="1691104391758345586">"Inga appar kan utföra den här åtgärden."</string>
<string name="aerr_title" msgid="653922989522758100">"Tyvärr!"</string>
<string name="aerr_application" msgid="4683614104336409186">"Processen <xliff:g id="PROCESS">%2$s</xliff:g> för programmet <xliff:g id="APPLICATION">%1$s</xliff:g> stoppades oväntat. Försök igen."</string>
<string name="aerr_process" msgid="1551785535966089511">"Processen <xliff:g id="PROCESS">%1$s</xliff:g> avslutades oväntat. Försök igen."</string>
@@ -823,7 +823,7 @@
<string name="anr_activity_process" msgid="5420826626009561014">"Aktiviteten <xliff:g id="ACTIVITY">%1$s</xliff:g> (i processen <xliff:g id="PROCESS">%2$s</xliff:g>) svarar inte."</string>
<string name="anr_application_process" msgid="4185842666452210193">"Programmet <xliff:g id="APPLICATION">%1$s</xliff:g> (i processen <xliff:g id="PROCESS">%2$s</xliff:g>) svarar inte."</string>
<string name="anr_process" msgid="1246866008169975783">"Processen <xliff:g id="PROCESS">%1$s</xliff:g> svarar inte."</string>
- <string name="force_close" msgid="3653416315450806396">"Tvinga fram en stängning"</string>
+ <string name="force_close" msgid="3653416315450806396">"Tvinga stängning"</string>
<string name="report" msgid="4060218260984795706">"Rapportera"</string>
<string name="wait" msgid="7147118217226317732">"Vänta"</string>
<string name="launch_warning_title" msgid="8323761616052121936">"Programmet omdirigerades"</string>
@@ -833,8 +833,8 @@
<string name="smv_process" msgid="5120397012047462446">"Processen <xliff:g id="PROCESS">%1$s</xliff:g> har brutit mot sin egen StrictMode-policy."</string>
<string name="heavy_weight_notification" msgid="9087063985776626166">"<xliff:g id="APP">%1$s</xliff:g> körs"</string>
<string name="heavy_weight_notification_detail" msgid="2423977499339403402">"Välj om du vill växla till programmet"</string>
- <string name="heavy_weight_switcher_title" msgid="1135403633766694316">"Vill du byta program?"</string>
- <string name="heavy_weight_switcher_text" msgid="4592075610079319667">"Ett annat program som körs måste avslutas innan du kan starta ett nytt."</string>
+ <string name="heavy_weight_switcher_title" msgid="1135403633766694316">"Vill du byta app?"</string>
+ <string name="heavy_weight_switcher_text" msgid="4592075610079319667">"En annan app som körs måste avslutas innan du kan starta en ny."</string>
<string name="old_app_action" msgid="493129172238566282">"Gå tillbaka till <xliff:g id="OLD_APP">%1$s</xliff:g>"</string>
<string name="old_app_description" msgid="942967900237208466">"Starta inte det nya programmet."</string>
<string name="new_app_action" msgid="5472756926945440706">"Starta <xliff:g id="OLD_APP">%1$s</xliff:g>"</string>
@@ -892,7 +892,7 @@
<string name="usb_storage_stop_button_mount" msgid="7060218034900696029">"Inaktivera USB-lagring"</string>
<string name="usb_storage_stop_error_message" msgid="143881914840412108">"Ett problem uppstod när USB-lagringsplatsen skulle inaktiveras. Kontrollera att USB-värden har demonterats och försök igen."</string>
<string name="dlg_confirm_kill_storage_users_title" msgid="963039033470478697">"Aktivera USB-lagring"</string>
- <string name="dlg_confirm_kill_storage_users_text" msgid="3202838234780505886">"Om du aktiverar USB-lagring avbryts några av de program som körs och de kanske inte blir tillgängliga igen förrän du inaktiverar USB-lagring."</string>
+ <string name="dlg_confirm_kill_storage_users_text" msgid="3202838234780505886">"Om du aktiverar USB-lagring avbryts några av de appar som körs och de kanske inte blir tillgängliga igen förrän du inaktiverar USB-lagring."</string>
<string name="dlg_error_title" msgid="8048999973837339174">"USB-åtgärd misslyckades"</string>
<string name="dlg_ok" msgid="7376953167039865701">"OK"</string>
<string name="extmedia_format_title" product="nosdcard" msgid="7980995592595097841">"Formatera USB-enhet"</string>
@@ -933,8 +933,8 @@
<string name="activity_list_empty" msgid="4168820609403385789">"Inga matchande aktiviteter hittades"</string>
<string name="permlab_pkgUsageStats" msgid="8787352074326748892">"uppdatera statistik över användning av komponenter"</string>
<string name="permdesc_pkgUsageStats" msgid="891553695716752835">"Tillåter att samlad komponentstatistik ändras. Används inte av vanliga program."</string>
- <string name="permlab_copyProtectedData" msgid="1660908117394854464">"Tillåter att innehåll kopieras genom att standardbehållartjänsten startas. Vanliga program behöver aldrig göra detta."</string>
- <string name="permdesc_copyProtectedData" msgid="537780957633976401">"Tillåter att innehåll kopieras genom att standardbehållartjänsten startas. Vanliga program behöver aldrig göra detta."</string>
+ <string name="permlab_copyProtectedData" msgid="1660908117394854464">"Tillåter att innehåll kopieras genom att standardbehållartjänsten startas. Vanliga appar behöver aldrig göra detta."</string>
+ <string name="permdesc_copyProtectedData" msgid="537780957633976401">"Tillåter att innehåll kopieras genom att standardbehållartjänsten startas. Vanliga appar behöver aldrig göra detta."</string>
<string name="tutorial_double_tap_to_zoom_message_short" msgid="1311810005957319690">"Peka två gånger för zoomkontroll"</string>
<string name="gadget_host_error_inflating" msgid="2613287218853846830">"Fel när widgeten expanderades"</string>
<string name="ime_action_go" msgid="8320845651737369027">"Kör"</string>
@@ -948,7 +948,7 @@
<string name="create_contact_using" msgid="4947405226788104538">"Skapa kontakt"\n"med <xliff:g id="NUMBER">%s</xliff:g>"</string>
<string name="accessibility_compound_button_selected" msgid="5612776946036285686">"markerad"</string>
<string name="accessibility_compound_button_unselected" msgid="8864512895673924091">"inte markerad"</string>
- <string name="grant_credentials_permission_message_header" msgid="6824538733852821001">"Följande program begär behörighet till konto, både nu och i framtiden."</string>
+ <string name="grant_credentials_permission_message_header" msgid="6824538733852821001">"Följande appar begär behörighet till konto, både nu och i framtiden."</string>
<string name="grant_credentials_permission_message_footer" msgid="3125211343379376561">"Vill du tillåta den här begäran?"</string>
<string name="grant_permissions_header_text" msgid="2722567482180797717">"Begäran om åtkomst"</string>
<string name="allow" msgid="7225948811296386551">"Tillåt"</string>
diff --git a/core/res/res/values-th/strings.xml b/core/res/res/values-th/strings.xml
index ce9e131..90747d7 100644
--- a/core/res/res/values-th/strings.xml
+++ b/core/res/res/values-th/strings.xml
@@ -484,8 +484,8 @@
<string name="policydesc_wipeData" product="default" msgid="7669895333814222586">"ลบข้อมูลของโทรศัพท์โดยไม่มีการเตือน ด้วยการดำเนินการรีเซ็ตข้อมูลเป็นค่าเริ่มต้น"</string>
<string name="policylab_setGlobalProxy" msgid="2784828293747791446">"ตั้งค่าพร็อกซีส่วนกลางของอุปกรณ์"</string>
<string name="policydesc_setGlobalProxy" msgid="6387497466660154931">"ตั้งค่าพร็อกซีส่วนกลางของอุปกรณ์ที่จะใช้ขณะเปิดการใช้งานนโยบาย เฉพาะผู้ดูแลอุปกรณ์คนแรกเท่านั้นที่ตั้งค่าพร็อกซีส่วนกลางที่มีผลบังคับ"</string>
- <string name="policylab_expirePassword" msgid="2314569545488269564">"ตั้งค่าการหมดอายุของรหัสผ่าน"</string>
- <string name="policydesc_expirePassword" msgid="7276906351852798814">"ควบคุมระยะเวลาก่อนที่จะต้องเปลี่ยนรหัสผ่านการล็อกหน้าจอ"</string>
+ <!-- outdated translation 4740941403188940274 --> <string name="policylab_expirePassword" msgid="885279151847254056">"ตั้งค่าการหมดอายุของรหัสผ่าน"</string>
+ <!-- outdated translation 6626724939177185949 --> <string name="policydesc_expirePassword" msgid="4844430354224822074">"ควบคุมระยะเวลาก่อนที่จะต้องเปลี่ยนรหัสผ่านการล็อกหน้าจอ"</string>
<string name="policylab_encryptedStorage" msgid="8901326199909132915">"ตั้งค่าการเข้ารหัสที่เก็บข้อมูล"</string>
<string name="policydesc_encryptedStorage" msgid="2504984732631479399">"กำหนดว่าแอปพลิเคชันที่จัดเก็บต้องมีการเข้ารหัส"</string>
<string-array name="phoneTypes">
diff --git a/core/res/res/values-tl/strings.xml b/core/res/res/values-tl/strings.xml
index c26d789..713fca9 100644
--- a/core/res/res/values-tl/strings.xml
+++ b/core/res/res/values-tl/strings.xml
@@ -484,8 +484,8 @@
<string name="policydesc_wipeData" product="default" msgid="7669895333814222586">"Burahin ang data ng telepono nang walang babala, sa pamamagitan ng pagsasagawa ng pag-reset sa data ng factory"</string>
<string name="policylab_setGlobalProxy" msgid="2784828293747791446">"Itakda ang pandaigdigang proxy ng device"</string>
<string name="policydesc_setGlobalProxy" msgid="6387497466660154931">"Itakda ang pandaigdigang proxy ng device na gagamitin habang pinagana ang patakaran. Tanging ang unang admin ng device ang magtatakda sa may bisang pandaigdigang proxy."</string>
- <string name="policylab_expirePassword" msgid="2314569545488269564">"Itakda pag-expire ng password"</string>
- <string name="policydesc_expirePassword" msgid="7276906351852798814">"Kontrolin kung gaano katagal bago kailangang palitan ang password sa pag-lock ng screen"</string>
+ <!-- outdated translation 4740941403188940274 --> <string name="policylab_expirePassword" msgid="885279151847254056">"Itakda pag-expire ng password"</string>
+ <!-- outdated translation 6626724939177185949 --> <string name="policydesc_expirePassword" msgid="4844430354224822074">"Kontrolin kung gaano katagal bago kailangang palitan ang password sa pag-lock ng screen"</string>
<string name="policylab_encryptedStorage" msgid="8901326199909132915">"Itakda pag-encrypt ng imbakan"</string>
<string name="policydesc_encryptedStorage" msgid="2504984732631479399">"Hinging naka-encrypt ang nakaimbak na data ng application"</string>
<string-array name="phoneTypes">
diff --git a/core/res/res/values-tr/strings.xml b/core/res/res/values-tr/strings.xml
index 08e4e71..d7a5008 100644
--- a/core/res/res/values-tr/strings.xml
+++ b/core/res/res/values-tr/strings.xml
@@ -484,8 +484,8 @@
<string name="policydesc_wipeData" product="default" msgid="7669895333814222586">"Fabrika verilerine sıfırlama işlemi gerçekleştirerek telefondaki verileri uyarıda bulunmadan silin"</string>
<string name="policylab_setGlobalProxy" msgid="2784828293747791446">"Cihaz genelinde geçerli proxy\'i ayarla"</string>
<string name="policydesc_setGlobalProxy" msgid="6387497466660154931">"Politika etkin olduğunda kullanılacak cihaz genelinde geçerli proxy\'yi ayarlayın. Etkin genel proxy\'yi yalnızca ilk cihaz yöneticisi ayarlar."</string>
- <string name="policylab_expirePassword" msgid="2314569545488269564">"Şifre süre sonu tarihi ayarla"</string>
- <string name="policydesc_expirePassword" msgid="7276906351852798814">"Ekran kilitleme şifresinin ne kadar süre sonra değiştirilmesi gerekeceğini denetleyin."</string>
+ <!-- outdated translation 4740941403188940274 --> <string name="policylab_expirePassword" msgid="885279151847254056">"Şifre süre sonu tarihi ayarla"</string>
+ <!-- outdated translation 6626724939177185949 --> <string name="policydesc_expirePassword" msgid="4844430354224822074">"Ekran kilitleme şifresinin ne kadar süre sonra değiştirilmesi gerekeceğini denetleyin."</string>
<string name="policylab_encryptedStorage" msgid="8901326199909132915">"Deplm şifrelemesini ayarla"</string>
<string name="policydesc_encryptedStorage" msgid="2504984732631479399">"Depolanan uygulama verisinin şifrelenmiş olmasını gerektir"</string>
<string-array name="phoneTypes">
diff --git a/core/res/res/values-uk/strings.xml b/core/res/res/values-uk/strings.xml
index 2a3624f..7c329c5 100644
--- a/core/res/res/values-uk/strings.xml
+++ b/core/res/res/values-uk/strings.xml
@@ -484,8 +484,8 @@
<string name="policydesc_wipeData" product="default" msgid="7669895333814222586">"Видаляє дані телефону без попередження, відновлюючи заводські налаштування"</string>
<string name="policylab_setGlobalProxy" msgid="2784828293747791446">"Установ. глоб. проксі пристрою"</string>
<string name="policydesc_setGlobalProxy" msgid="6387497466660154931">"Устан. використ. глоб. проксі, коли ввімкнено політику. Лише адміністратор першого пристрою встановлює активний глоб. проксі."</string>
- <string name="policylab_expirePassword" msgid="2314569545488269564">"Установити термін дії пароля"</string>
- <string name="policydesc_expirePassword" msgid="7276906351852798814">"Регулює, за скільки часу перед блокуванням екрана треба змінювати пароль"</string>
+ <!-- outdated translation 4740941403188940274 --> <string name="policylab_expirePassword" msgid="885279151847254056">"Установити термін дії пароля"</string>
+ <!-- outdated translation 6626724939177185949 --> <string name="policydesc_expirePassword" msgid="4844430354224822074">"Регулює, за скільки часу перед блокуванням екрана треба змінювати пароль"</string>
<string name="policylab_encryptedStorage" msgid="8901326199909132915">"Установити шифрування носія"</string>
<string name="policydesc_encryptedStorage" msgid="2504984732631479399">"Потрібно, щоб дані збереженої програми були зашифровані"</string>
<string-array name="phoneTypes">
diff --git a/core/res/res/values-vi/strings.xml b/core/res/res/values-vi/strings.xml
index 3306125..49c9e44 100644
--- a/core/res/res/values-vi/strings.xml
+++ b/core/res/res/values-vi/strings.xml
@@ -484,8 +484,8 @@
<string name="policydesc_wipeData" product="default" msgid="7669895333814222586">"Xóa dữ liệu trên điện thoại mà không cần cảnh báo, bằng cách thực hiện đặt lại về dữ liệu gốc"</string>
<string name="policylab_setGlobalProxy" msgid="2784828293747791446">"Đặt proxy chung của điện thoại"</string>
<string name="policydesc_setGlobalProxy" msgid="6387497466660154931">"Đặt proxy chung của điện thoại được sử dụng trong khi chính sách được bật. Chỉ quản trị viên đầu tiên của điện thoại mới có thể đặt proxy chung hiệu quả."</string>
- <string name="policylab_expirePassword" msgid="2314569545488269564">"Đặt hết hạn mật khẩu"</string>
- <string name="policydesc_expirePassword" msgid="7276906351852798814">"Kiểm soát thời lượng trước khi mật khẩu khóa màn hình cần được thay đổi"</string>
+ <!-- outdated translation 4740941403188940274 --> <string name="policylab_expirePassword" msgid="885279151847254056">"Đặt hết hạn mật khẩu"</string>
+ <!-- outdated translation 6626724939177185949 --> <string name="policydesc_expirePassword" msgid="4844430354224822074">"Kiểm soát thời lượng trước khi mật khẩu khóa màn hình cần được thay đổi"</string>
<string name="policylab_encryptedStorage" msgid="8901326199909132915">"Đặt mã hóa dung lượng lưu trữ"</string>
<string name="policydesc_encryptedStorage" msgid="2504984732631479399">"Yêu cầu dữ liệu ứng dụng được lưu trữ phải được mã hóa"</string>
<string-array name="phoneTypes">
diff --git a/core/res/res/values-zh-rCN/strings.xml b/core/res/res/values-zh-rCN/strings.xml
index 40ae40f..640b9bc 100644
--- a/core/res/res/values-zh-rCN/strings.xml
+++ b/core/res/res/values-zh-rCN/strings.xml
@@ -484,8 +484,8 @@
<string name="policydesc_wipeData" product="default" msgid="7669895333814222586">"恢复出厂设置时,将擦除手机上的数据而不发送警告"</string>
<string name="policylab_setGlobalProxy" msgid="2784828293747791446">"设置设备全局代理"</string>
<string name="policydesc_setGlobalProxy" msgid="6387497466660154931">"请设置在启用政策的情况下要使用的设备全局代理。只有第一设备管理员才可设置有效的全局代理。"</string>
- <string name="policylab_expirePassword" msgid="2314569545488269564">"设置密码有效期"</string>
- <string name="policydesc_expirePassword" msgid="7276906351852798814">"控制屏幕锁定密码的使用期限"</string>
+ <!-- outdated translation 4740941403188940274 --> <string name="policylab_expirePassword" msgid="885279151847254056">"设置密码有效期"</string>
+ <!-- outdated translation 6626724939177185949 --> <string name="policydesc_expirePassword" msgid="4844430354224822074">"控制屏幕锁定密码的使用期限"</string>
<string name="policylab_encryptedStorage" msgid="8901326199909132915">"设置存储设备加密"</string>
<string name="policydesc_encryptedStorage" msgid="2504984732631479399">"需要对存储的应用程序数据进行加密"</string>
<string-array name="phoneTypes">
diff --git a/core/res/res/values-zh-rTW/strings.xml b/core/res/res/values-zh-rTW/strings.xml
index 784d86f..fe1d78d 100644
--- a/core/res/res/values-zh-rTW/strings.xml
+++ b/core/res/res/values-zh-rTW/strings.xml
@@ -484,8 +484,8 @@
<string name="policydesc_wipeData" product="default" msgid="7669895333814222586">"執行重設為原廠設定時,系統會直接清除手機資料而不提出警告"</string>
<string name="policylab_setGlobalProxy" msgid="2784828293747791446">"設定裝置全域 Proxy"</string>
<string name="policydesc_setGlobalProxy" msgid="6387497466660154931">"設定政策啟用時所要使用的裝置全域 Proxy,只有第一個裝置管理員所設定的全域 Proxy 具有效力。"</string>
- <string name="policylab_expirePassword" msgid="2314569545488269564">"設定密碼到期日"</string>
- <string name="policydesc_expirePassword" msgid="7276906351852798814">"控制螢幕鎖定密碼的使用期限"</string>
+ <!-- outdated translation 4740941403188940274 --> <string name="policylab_expirePassword" msgid="885279151847254056">"設定密碼到期日"</string>
+ <!-- outdated translation 6626724939177185949 --> <string name="policydesc_expirePassword" msgid="4844430354224822074">"控制螢幕鎖定密碼的使用期限"</string>
<string name="policylab_encryptedStorage" msgid="8901326199909132915">"設定儲存裝置加密"</string>
<string name="policydesc_encryptedStorage" msgid="2504984732631479399">"必須為儲存的應用程式資料加密"</string>
<string-array name="phoneTypes">
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index 6f37dc0..3b225a4 100755
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -2256,18 +2256,29 @@
<attr name="unselectedAlpha" format="float" />
</declare-styleable>
<declare-styleable name="GridView">
+ <!-- Defines the default horizontal spacing between columns. -->
<attr name="horizontalSpacing" format="dimension" />
+ <!-- Defines the default vertical spacing between rows. -->
<attr name="verticalSpacing" format="dimension" />
+ <!-- Defines how columns should stretch to fill the available empty space, if any. -->
<attr name="stretchMode">
+ <!-- Stretching is disabled. -->
<enum name="none" value="0"/>
+ <!-- The spacing between each column is stretched. -->
<enum name="spacingWidth" value="1" />
+ <!-- Each column is stretched equally. -->
<enum name="columnWidth" value="2" />
+ <!-- The spacing between each column is uniformly stretched.. -->
<enum name="spacingWidthUniform" value="3" />
</attr>
+ <!-- Specifies the fixed width for each column. -->
<attr name="columnWidth" format="dimension" />
+ <!-- Defines how many columns to show. -->
<attr name="numColumns" format="integer" min="0">
+ <!-- Display as many columns as possible to fill the available space. -->
<enum name="auto_fit" value="-1" />
</attr>
+ <!-- Specifies the gravity within each cell. -->
<attr name="gravity" />
</declare-styleable>
<declare-styleable name="ImageSwitcher">
@@ -3165,7 +3176,10 @@
<attr name="visible" format="boolean" />
</declare-styleable>
+ <!-- Drawable used to render several states. Each state is represented by
+ a child drawable. -->
<declare-styleable name="StateListDrawable">
+ <!-- Indicates whether the drawable should be initially visible. -->
<attr name="visible" />
<!-- If true, allows the drawable's padding to change based on the
current state that is selected. If false, the padding will
@@ -3189,6 +3203,7 @@
<attr name="exitFadeDuration" format="integer" />
</declare-styleable>
+ <!-- Drawable used to render several animated frames. -->
<declare-styleable name="AnimationDrawable">
<attr name="visible" />
<attr name="variablePadding" />
@@ -3198,6 +3213,7 @@
<attr name="oneshot" format="boolean" />
</declare-styleable>
+ <!-- Represents a single frame inside an AnimationDrawable. -->
<declare-styleable name="AnimationDrawableItem">
<!-- Amount of time (in milliseconds) to display this frame. -->
<attr name="duration" format="integer" />
@@ -3206,12 +3222,21 @@
<attr name="drawable" format="reference" />
</declare-styleable>
+ <!-- Drawable used to render a geometric shape, with a gradient or a solid color. -->
<declare-styleable name="GradientDrawable">
+ <!-- Indicates whether the drawable should intially be visible. -->
<attr name="visible" />
+ <!-- Enables or disables dithering. -->
+ <attr name="dither" />
+ <!-- Indicates what shape to fill with a gradient. -->
<attr name="shape">
+ <!-- Rectangle shape, with optional rounder corners. -->
<enum name="rectangle" value="0" />
+ <!-- Oval shape. -->
<enum name="oval" value="1" />
+ <!-- Line shape. -->
<enum name="line" value="2" />
+ <!-- Ring shape. -->
<enum name="ring" value="3" />
</attr>
<!-- Inner radius of the ring expressed as a ratio of the ring's width. For instance,
@@ -3226,71 +3251,123 @@
<attr name="innerRadius" format="dimension" />
<!-- Thickness of the ring. When defined, thicknessRatio is ignored. -->
<attr name="thickness" format="dimension" />
+ <!-- Indicates whether the drawable's level affects the way the gradient is drawn. -->
<attr name="useLevel" />
</declare-styleable>
+ <!-- Used to specify the size of the shape for GradientDrawable. -->
<declare-styleable name="GradientDrawableSize">
+ <!-- Width of the gradient shape. -->
<attr name="width" />
+ <!-- Height of the gradient shape. -->
<attr name="height" />
</declare-styleable>
+ <!-- Used to describe the gradient used to fill the shape of a GradientDrawable. -->
<declare-styleable name="GradientDrawableGradient">
+ <!-- Start color of the gradient. -->
<attr name="startColor" format="color" />
- <!-- Optional center color. For linear gradients, use centerX or centerY to place the center color. -->
+ <!-- Optional center color. For linear gradients, use centerX or centerY
+ to place the center color. -->
<attr name="centerColor" format="color" />
+ <!-- End color of the gradient. -->
<attr name="endColor" format="color" />
<attr name="useLevel" format="boolean" />
+ <!-- Angle of the gradient. -->
<attr name="angle" format="float" />
+ <!-- Type of gradient. The default type is linear. -->
<attr name="type">
+ <!-- Linear gradient. -->
<enum name="linear" value="0" />
+ <!-- Radial, or circular, gradient. -->
<enum name="radial" value="1" />
+ <!-- Sweep, or angled or diamond, gradient. -->
<enum name="sweep" value="2" />
</attr>
+ <!-- X coordinate of the origin of the gradient within the shape. -->
<attr name="centerX" format="float|fraction" />
+ <!-- Y coordinate of the origin of the gradient within the shape. -->
<attr name="centerY" format="float|fraction" />
+ <!-- Radius of the gradient, used only with radial gradient. -->
<attr name="gradientRadius" format="float|fraction" />
</declare-styleable>
+ <!-- Used to fill the shape of GradientDrawable with a solid color. -->
<declare-styleable name="GradientDrawableSolid">
+ <!-- Solid color for the gradient shape. -->
<attr name="color" format="color" />
</declare-styleable>
+ <!-- Used to describe the optional stroke of a GradientDrawable. -->
<declare-styleable name="GradientDrawableStroke">
+ <!-- Width of the gradient shape's stroke. -->
<attr name="width" />
+ <!-- Color of the gradient shape's stroke. -->
<attr name="color" />
+ <!-- Length of a dash in the stroke. -->
<attr name="dashWidth" format="dimension" />
+ <!-- Gap between dashes in the stroke. -->
<attr name="dashGap" format="dimension" />
</declare-styleable>
+ <!-- Describes the corners for the rectangle shape of a GradientDrawable.
+ This can be used to render rounded corners. -->
<declare-styleable name="DrawableCorners">
+ <!-- Defines the radius of the four corners. -->
<attr name="radius" format="dimension" />
+ <!-- Radius of the top left corner. -->
<attr name="topLeftRadius" format="dimension" />
+ <!-- Radius of the top right corner. -->
<attr name="topRightRadius" format="dimension" />
+ <!-- Radius of the bottom left corner. -->
<attr name="bottomLeftRadius" format="dimension" />
+ <!-- Radius of the bottom right corner. -->
<attr name="bottomRightRadius" format="dimension" />
</declare-styleable>
+ <!-- Used to specify the optional padding of a GradientDrawable. -->
<declare-styleable name="GradientDrawablePadding">
+ <!-- Amount of left padding inside the gradient shape. -->
<attr name="left" format="dimension" />
+ <!-- Amount of top padding inside the gradient shape. -->
<attr name="top" format="dimension" />
+ <!-- Amount of right padding inside the gradient shape. -->
<attr name="right" format="dimension" />
+ <!-- Amount of bottom padding inside the gradient shape. -->
<attr name="bottom" format="dimension" />
</declare-styleable>
+ <!-- Drawable used to render several drawables stacked on top of each other.
+ Each child drawable can be controlled individually. -->
<declare-styleable name="LayerDrawable">
+ <!-- Indicates the opacity of the layer. This can be useful to allow the
+ system to enable drawing optimizations. The default value is
+ translucent. -->
<attr name="opacity">
+ <!-- Indicates that the layer is opaque and contains no transparent
+ nor translucent pixels. -->
<enum name="opaque" value="-1" />
+ <!-- The layer is completely transparent (no pixel will be drawn.) -->
<enum name="transparent" value="-2" />
+ <!-- The layer has translucent pixels. -->
<enum name="translucent" value="-3" />
</attr>
</declare-styleable>
+ <!-- Describes an item (or child) of a LayerDrawable. -->
<declare-styleable name="LayerDrawableItem">
+ <!-- Left coordinate of the layer. -->
<attr name="left" />
+ <!-- Top coordinate of the layer. -->
<attr name="top" />
+ <!-- Right coordinate of the layer. -->
<attr name="right" />
+ <!-- Bottom coordinate of the layer. -->
<attr name="bottom" />
+ <!-- Drawable used to render the layer. -->
<attr name="drawable" />
+ <!-- Identifier of the layer. This can be used to retrieve the layer
+ from a drawbable container. -->
<attr name="id" />
</declare-styleable>
@@ -3306,6 +3383,7 @@
<attr name="drawable" />
</declare-styleable>
+ <!-- Drawable used to rotate another drawable. -->
<declare-styleable name="RotateDrawable">
<attr name="visible" />
<attr name="fromDegrees" format="float" />
@@ -3464,6 +3542,8 @@
<attr name="width" />
<!-- Defines the height of the shape. -->
<attr name="height" />
+ <!-- Enables or disables dithering. -->
+ <attr name="dither" />
</declare-styleable>
<!-- ========================== -->
@@ -4469,6 +4549,13 @@
<!-- The view id of the AppWidget subview which should be auto-advanced.
by the widget's host. -->
<attr name="autoAdvanceViewId" format="reference" />
+ <!-- Optional parameter which indicates if and how this widget can be
+ resized. -->
+ <attr name="resizeMode" format="integer">
+ <flag name="none" value="0x0" />
+ <flag name="horizontal" value="0x1" />
+ <flag name="vertical" value="0x2" />
+ </attr>
</declare-styleable>
<!-- =============================== -->
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 0edd33e..c815758 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -51,6 +51,11 @@
manager will disable alpha trasformation in animations where not
strictly needed. -->
<bool name="config_sf_limitedAlpha">false</bool>
+
+ <!-- Default value used to block data calls if ims is not
+ connected. If you use the ims apn DCT will block
+ any other apn from connecting until ims apn is connected-->
+ <bool name="ImsConnectedDefaultValue">false</bool>
<!-- Flag indicating whether the surface flinger is inefficient
at performing a blur. Used by parts of the UI to turn off
@@ -133,6 +138,9 @@
<item>"mobile_mms,2,0,2"</item>
<item>"mobile_supl,3,0,2"</item>
<item>"mobile_hipri,5,0,3"</item>
+ <item>"mobile_fota,8,0,2"</item>
+ <item>"mobile_ims,9,0,2"</item>
+ <item>"mobile_cbs,10,0,2"</item>
</string-array>
<!-- This string array should be overridden by the device to present a list of radio
@@ -194,6 +202,13 @@
<!-- Boolean indicating whether the wifi chipset has dual frequency band support -->
<bool translatable="false" name="config_wifi_dual_band_support">false</bool>
+ <!-- Boolean indicating whether the wifi chipset supports background scanning mechanism.
+ This mechanism allows the host to remain in suspend state and the dongle to actively
+ scan and wake the host when a configured SSID is detected by the dongle. This chipset
+ capability can provide power savings when wifi needs to be always kept on.
+ The driver commands needed to support the feature are BGSCAN-START and BGSCAN-STOP -->
+ <bool translatable="false" name="config_wifi_background_scan_support">false</bool>
+
<!-- Flag indicating whether the keyguard should be bypassed when
the slider is open. This can be set or unset depending how easily
the slider can be opened (for example, in a pocket or purse). -->
@@ -281,9 +296,6 @@
<!-- Indicate whether the SD card is accessible without removing the battery. -->
<bool name="config_batterySdCardAccessibility">false</bool>
- <!-- Indicate whether the device has USB host support. -->
- <bool name="config_hasUsbHostSupport">false</bool>
-
<!-- List of file paths for USB host busses to exclude from USB host support.
For example, if the first USB bus on the device is used to communicate
with the modem or some other restricted hardware, add "/dev/bus/usb/001/"
@@ -556,4 +568,7 @@
<!-- Do not translate. Defines the slots is Two Digit Number for dialing normally not USSD -->
<string-array name="config_twoDigitNumberPattern">
</string-array>
+
+ <!-- The VoiceMail default value is displayed to my own number if it is true -->
+ <bool name="config_telephony_use_own_number_for_voicemail">false</bool>
</resources>
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index 4542575..f1ec398 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -1642,7 +1642,10 @@
<!-- Default icon for applications that don't specify an icon. -->
<public type="mipmap" name="sym_def_app_icon" id="0x010d0000" />
- <!-- Theme attribute used to customize the text insertion cursor -->
- <!-- Commented out for HC MR1 to prevent an API change -->
- <!-- <public type="attr" name="textCursorDrawable" id="0x01010362" /> -->
+<!-- ===============================================================
+ Resources added in version 12 of the platform (Honeycomb / 3.1)
+ =============================================================== -->
+ <eat-comment />
+ <public type="attr" name="textCursorDrawable" id="0x01010362" />
+ <public type="attr" name="resizeMode" />
</resources>
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index 361bb6c..8ef9a3b 100755
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -1031,9 +1031,9 @@
the flashlight.</string>
<!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
- <string name="permlab_accessUsb">access USB devices</string>
+ <string name="permlab_manageUsb">manage preferences and permissions for USB devices</string>
<!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
- <string name="permdesc_accessUsb">Allows the application to access USB devices.</string>
+ <string name="permdesc_manageUsb">Allows the application to manage preferences and permissions for USB devices.</string>
<!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
<string name="permlab_accessMtp">implement MTP protocol</string>
@@ -1869,6 +1869,115 @@
e.g. (John Smith)(, )(123 Main Street) -->
<string name="autofill_address_summary_format">$1$2$3</string>
+ <!-- Do not translate. Regex used by AutoFill. -->
+ <string name="autofill_attention_ignored_re">attention|attn</string>
+
+ <!-- Do not translate. Regex used by AutoFill. -->
+ <string name="autofill_region_ignored_re">province|region|other<!-- es -->|provincia<!-- pt-BR, pt-PT -->|bairro|suburb</string>
+
+ <!-- Do not translate. Regex used by AutoFill. -->
+ <string name="autofill_company_re">company|business|organization|organisation|department<!-- de-DE -->|firma|firmenname<!-- es -->|empresa<!-- fr-FR -->|societe|société<!-- it-IT -->|ragione.?sociale<!-- ja-JP -->|会社<!-- ru -->|название.?компании<!-- zh-CN -->|单位|公司</string>
+
+ <!-- Do not translate. Regex used by AutoFill. -->
+ <string name="autofill_address_line_1_re">address.?line|address1|addr1|street<!-- de-DE -->|strasse|straße|hausnummer|housenumber<!-- en-GB -->|house.?name<!-- es -->|direccion|dirección<!-- fr-FR -->|adresse<!-- it-IT -->|indirizzo<!-- ja-JP -->|住所1<!-- pt-BR, pt-PT -->|morada|endereço<!-- ru -->|Адрес<!-- zh-CN -->|地址</string>
+
+ <!-- Do not translate. Regex used by AutoFill. -->
+ <string name="autofill_address_line_1_label_re">address<!-- fr-FR -->|adresse<!-- it-IT -->|indirizzo<!-- ja-JP -->|住所<!-- zh-CN -->|地址</string>
+
+ <!-- Do not translate. Regex used by AutoFill. -->
+ <string name="autofill_address_line_2_re">address.?line2|address2|addr2|street|suite|unit<!-- de-DE -->|adresszusatz|ergänzende.?angaben<!-- es -->|direccion2|colonia|adicional<!-- fr-FR -->|addresssuppl|complementnom|appartement<!-- it-IT -->|indirizzo2<!-- ja-JP -->|住所2</string>
+
+ <!-- Do not translate. Regex used by AutoFill. -->
+ <string name="autofill_address_line_3_re">address.?line3|address3|addr3|street|line3<!-- es -->|municipio<!-- fr-FR -->|batiment|residence<!-- it-IT -->|indirizzo3</string>
+
+ <!-- Do not translate. Regex used by AutoFill. -->
+ <string name="autofill_country_re">country|location<!-- ja-JP -->|国<!-- zh-CN -->|国家</string>
+
+ <!-- Do not translate. Regex used by AutoFill. -->
+ <string name="autofill_zip_code_re">zip|postal|post code|pcode|^1z$<!-- de-DE -->|postleitzahl<!-- es -->|cp<!-- fr-FR -->|cdp<!-- it-IT -->|cap<!-- ja-JP -->|郵便番号<!-- pt-BR, pt-PT -->|codigo|codpos|cep<!-- ru -->|Почтовый.?Индекс<!--zh-CN -->|邮政编码|邮编<!-- zh-TW -->|郵遞區號</string>
+
+ <!-- Do not translate. Regex used by AutoFill. -->
+ <string name="autofill_zip_4_re">zip|^-$|post2<!-- pt-BR, pt-PT -->|codpos2</string>
+
+ <!-- Do not translate. Regex used by AutoFill. -->
+ <string name="autofill_city_re">city|town<!-- de-DE -->|ort|stadt<!-- en-AU -->|suburb<!-- es -->|ciudad|provincia|localidad|poblacion<!-- fr-FR -->|ville|commune<!-- it-IT -->|localita<!-- ja-JP -->|市区町村<!-- pt-BR, pt-PT -->|cidade<!-- ru -->|Город<!-- zh-CN -->|市<!-- zh-TW -->|分區</string>
+
+ <!-- Do not translate. Regex used by AutoFill. -->
+ <string name="autofill_state_re">state|county|region|province<!-- de-DE -->|land<!-- en-UK -->|county|principality<!-- ja-JP -->|都道府県<!-- pt-BR, pt-PT -->|estado|provincia<!-- ru -->|область<!-- zh-CN -->|省<!-- zh-TW -->|地區</string>
+
+ <!-- Do not translate. Regex used by AutoFill. -->
+ <string name="autofill_address_type_same_as_re">same as</string>
+
+ <!-- Do not translate. Regex used by AutoFill. -->
+ <string name="autofill_address_type_use_my_re">use my</string>
+
+ <!-- Do not translate. Regex used by AutoFill. -->
+ <string name="autofill_billing_designator_re">bill</string>
+
+ <!-- Do not translate. Regex used by AutoFill. -->
+ <string name="autofill_shipping_designator_re">ship</string>
+
+ <!-- Do not translate. Regex used by AutoFill. -->
+ <string name="autofill_email_re">e.?mail<!-- ja-JP -->|メールアドレス<!-- ru -->|Электронной.?Почты<!-- zh-CN -->|邮件|邮箱<!-- zh-TW -->|電郵地址</string>
+
+ <!-- Do not translate. Regex used by AutoFill. -->
+ <string name="autofill_username_re">user.?name|user.?id<!-- de-DE -->|vollständiger.?name<!-- zh-CN -->|用户名</string>
+
+ <!-- Do not translate. Regex used by AutoFill. -->
+ <string name="autofill_name_re">^name|full.?name|your.?name|customer.?name|firstandlastname<!-- es -->|nombre.*y.*apellidos<!-- fr-FR -->|^nom<!-- ja-JP -->|お名前|氏名<!-- pt-BR, pt-PT -->|^nome<!-- zh-CN -->|姓名</string>
+
+ <!-- Do not translate. Regex used by AutoFill. -->
+ <string name="autofill_name_specific_re">^name<!-- fr-FR -->|^nom<!-- pt-BR, pt-PT -->|^nome</string>
+
+ <!-- Do not translate. Regex used by AutoFill. -->
+
+ <string name="autofill_first_name_re">irst.*name|initials|fname|first$<!-- de-DE -->|vorname<!-- es -->|nombre<!-- fr-FR -->|forename|prénom|prenom<!-- ja-JP -->|名<!-- pt-BR, pt-PT -->|nome<!-- ru -->|Имя</string>
+
+ <!-- Do not translate. Regex used by AutoFill. -->
+ <string name="autofill_middle_initial_re">middle.*initial|m\\.i\\.|mi$</string>
+
+ <!-- Do not translate. Regex used by AutoFill. -->
+ <string name="autofill_middle_name_re">middle.*name|mname|middle$<!-- es -->|apellido.?materno|lastlastname</string>
+
+ <!-- Do not translate. Regex used by AutoFill. -->
+ <string name="autofill_last_name_re">last.*name|lname|surname|last$<!-- de-DE -->|nachname<!-- es -->|apellidos<!-- fr-FR -->|famille|^nom<!-- it-IT -->|cognome<!-- ja-JP -->|姓<!-- pt-BR, pt-PT -->|morada|apelidos|surename|sobrenome<!-- ru -->|Фамилия</string>
+
+ <!-- Do not translate. Regex used by AutoFill. -->
+ <string name="autofill_phone_re">phone<!-- de-DE -->|telefonnummer<!-- es -->|telefono|teléfono<!-- fr-FR -->|telfixe<!-- ja-JP -->|電話<!-- pt-BR, pt-PT -->|telefone|telemovel<!-- ru -->|телефон<!-- zh-CN -->|电话</string>
+
+ <!-- Do not translate. Regex used by AutoFill. -->
+ <string name="autofill_area_code_re">area code</string>
+
+ <!-- Do not translate. Regex used by AutoFill. -->
+ <string name="autofill_phone_prefix_re">^-$|\\)$|prefix<!-- fr-FR -->|preselection<!-- pt-BR, pt-PT -->|ddd</string>
+
+ <!-- Do not translate. Regex used by AutoFill. -->
+ <string name="autofill_phone_suffix_re">^-$|suffix</string>
+
+ <!-- Do not translate. Regex used by AutoFill. -->
+ <string name="autofill_phone_extension_re">ext<!-- pt-BR, pt-PT -->|ramal</string>
+
+ <!-- Do not translate. Regex used by AutoFill. -->
+ <string name="autofill_name_on_card_re">card.?holder|name.?on.?card|ccname|owner<!-- de-DE -->|karteninhaber<!-- es -->|nombre.*tarjeta<!-- fr-FR -->|nom.*carte<!-- it-IT -->|nome.*cart<!-- ja-JP -->|名前<!-- ru -->|Имя.*карты<!-- zh-CN -->|信用卡开户名|开户名|持卡人姓名<!-- zh-TW -->|持卡人姓名</string>
+
+ <!-- Do not translate. Regex used by AutoFill. -->
+ <string name="autofill_name_on_card_contextual_re">name</string>
+
+ <!-- Do not translate. Regex used by AutoFill. -->
+ <string name="autofill_card_cvc_re">verification|card identification|cvn|security code|cvv code|cvc</string>
+
+ <!-- Do not translate. Regex used by AutoFill. -->
+ <string name="autofill_card_number_re">number|card.?#|card.?no|ccnum<!-- de-DE -->|nummer<!-- es -->|credito|numero|número<!-- fr-FR -->|numéro<!-- ja-JP -->|カード番号<!-- ru -->|Номер.*карты<!-- zh-CN -->|信用卡号|信用卡号码<!-- zh-TW -->|信用卡卡號</string>
+
+ <!-- Do not translate. Regex used by AutoFill. -->
+ <string name="autofill_expiration_month_re">expir|exp.*month|exp.*date|ccmonth<!-- de-DE -->|gueltig|gültig|monat<!-- es -->|fecha<!-- fr-FR -->|date.*exp<!-- it-IT -->|scadenza<!-- ja-JP -->|有効期限<!-- pt-BR, pt-PT -->|validade<!-- ru -->|Срок действия карты<!-- zh-CN -->|月</string>
+
+ <!-- Do not translate. Regex used by AutoFill. -->
+ <string name="autofill_expiration_date_re">exp|^/|year<!-- de-DE -->|ablaufdatum|gueltig|gültig|yahr<!-- es -->|fecha<!-- it-IT -->|scadenza<!-- ja-JP -->|有効期限<!-- pt-BR, pt-PT -->|validade<!-- ru -->|Срок действия карты<!-- zh-CN -->|年|有效期</string>
+
+ <!-- Do not translate. Regex used by AutoFill. -->
+ <string name="autofill_card_ignored_re">^card</string>
+
<!-- Title of an application permission, listed so the user can choose whether
they want to allow the application to do this. -->
<string name="permlab_readHistoryBookmarks">read Browser\'s history and bookmarks</string>
@@ -2193,6 +2302,8 @@
<string name="clearDefaultHintMsg">Clear default in Home Settings &gt; Applications &gt; Manage applications.</string>
<!-- Default title for the activity chooser, when one is not given. Android allows multiple activities to perform an action. for example, there may be many ringtone pickers installed. A dialog is shown to the user allowing him to pick which activity should be used. This is the title. -->
<string name="chooseActivity">Select an action</string>
+ <!-- title for the USB activity chooser. -->
+ <string name="chooseUsbActivity">Select an application for the USB device</string>
<!-- Text to display when there are no activities found to display in the
activity chooser. See the "Select an action" title. -->
<string name="noApplications">No applications can perform this action.</string>
diff --git a/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/ConnectivityManagerTestActivity.java b/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/ConnectivityManagerTestActivity.java
index 7756135..e138200 100644
--- a/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/ConnectivityManagerTestActivity.java
+++ b/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/ConnectivityManagerTestActivity.java
@@ -21,30 +21,34 @@ import android.content.Context;
import android.content.BroadcastReceiver;
import android.content.Intent;
import android.content.IntentFilter;
+import android.net.ConnectivityManager;
+import android.net.NetworkInfo;
+import android.net.NetworkInfo.State;
+import android.net.wifi.WifiConfiguration;
+import android.net.wifi.WifiManager;
+import android.net.wifi.WifiInfo;
+import android.net.wifi.ScanResult;
+import android.net.wifi.WifiConfiguration.KeyMgmt;
import android.os.Bundle;
+import android.os.Handler;
import android.os.IPowerManager;
+import android.os.Message;
import android.os.PowerManager;
import android.os.ServiceManager;
import android.os.SystemClock;
import android.provider.Settings;
import android.util.Log;
import android.view.KeyEvent;
+import android.widget.LinearLayout;
+
+import com.android.internal.util.AsyncChannel;
import java.io.IOException;
import java.io.InputStream;
import java.net.UnknownHostException;
import java.util.ArrayList;
import java.util.List;
-import android.widget.LinearLayout;
-import android.net.ConnectivityManager;
-import android.net.NetworkInfo;
-import android.net.NetworkInfo.State;
-import android.net.wifi.WifiConfiguration;
-import android.net.wifi.WifiManager;
-import android.net.wifi.WifiInfo;
-import android.net.wifi.ScanResult;
-import android.net.wifi.WifiConfiguration.KeyMgmt;
/**
* An activity registered with connectivity manager broadcast
@@ -180,6 +184,24 @@ public class ConnectivityManagerTestActivity extends Activity {
}
}
+ private class WifiServiceHandler extends Handler {
+ @Override
+ public void handleMessage(Message msg) {
+ switch (msg.what) {
+ case AsyncChannel.CMD_CHANNEL_HALF_CONNECTED:
+ if (msg.arg1 == AsyncChannel.STATUS_SUCCESSFUL) {
+ //AsyncChannel in msg.obj
+ } else {
+ log("Failed to establish AsyncChannel connection");
+ }
+ break;
+ default:
+ //Ignore
+ break;
+ }
+ }
+ }
+
public ConnectivityManagerTestActivity() {
mState = State.UNKNOWN;
scanResultAvailable = false;
@@ -216,6 +238,8 @@ public class ConnectivityManagerTestActivity extends Activity {
mCM = (ConnectivityManager)getSystemService(Context.CONNECTIVITY_SERVICE);
// Get an instance of WifiManager
mWifiManager =(WifiManager)getSystemService(Context.WIFI_SERVICE);
+ mWifiManager.asyncConnect(this, new WifiServiceHandler());
+
initializeNetworkStates();
if (mWifiManager.isWifiEnabled()) {
diff --git a/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/functional/WifiConnectionTest.java b/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/functional/WifiConnectionTest.java
index 9c72102..fe79e6c 100644
--- a/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/functional/WifiConnectionTest.java
+++ b/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/functional/WifiConnectionTest.java
@@ -34,12 +34,15 @@ import android.net.ConnectivityManager;
import android.net.DhcpInfo;
import android.net.NetworkInfo;
import android.net.NetworkInfo.State;
+import android.os.Handler;
+import android.os.Message;
import android.provider.Settings;
-
import android.test.suitebuilder.annotation.LargeTest;
import android.test.ActivityInstrumentationTestCase2;
import android.util.Log;
+import com.android.internal.util.AsyncChannel;
+
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
@@ -75,6 +78,7 @@ public class WifiConnectionTest
enabledNetworks = getEnabledNetworks(mWifiManager.getConfiguredNetworks());
mAct = getActivity();
+ mWifiManager.asyncConnect(mAct, new WifiServiceHandler());
networks = mAct.loadNetworkConfigurations();
if (DEBUG) {
printNetworkConfigurations();
@@ -89,6 +93,24 @@ public class WifiConnectionTest
assertTrue("wpa_supplicant is not started ", mAct.mWifiManager.pingSupplicant());
}
+ private class WifiServiceHandler extends Handler {
+ @Override
+ public void handleMessage(Message msg) {
+ switch (msg.what) {
+ case AsyncChannel.CMD_CHANNEL_HALF_CONNECTED:
+ if (msg.arg1 == AsyncChannel.STATUS_SUCCESSFUL) {
+ //AsyncChannel in msg.obj
+ } else {
+ log("Failed to establish AsyncChannel connection");
+ }
+ break;
+ default:
+ //Ignore
+ break;
+ }
+ }
+ }
+
private void printNetworkConfigurations() {
log("==== print network configurations parsed from XML file ====");
log("number of access points: " + networks.size());
diff --git a/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/stress/WifiApStress.java b/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/stress/WifiApStress.java
index 1374e7f..41104fe 100644
--- a/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/stress/WifiApStress.java
+++ b/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/stress/WifiApStress.java
@@ -108,15 +108,6 @@ public class WifiApStress
fail("thread in sleep is interrupted");
}
assertTrue("no uplink data connection after Wi-Fi tethering", mAct.pingTest(null));
- // Wait for 5 minutes, and verify the data connection again.
- // bug id: 3400027
- try {
- Thread.sleep(5 * 60 * 1000);
- } catch (Exception e) {
- fail("thread in sleep is interrupted");
- }
- // Verify the uplink data connection
- assertTrue("no uplink data connection", mAct.pingTest(null));
// Disable soft AP
assertTrue(mAct.mWifiManager.setWifiApEnabled(config, false));
// Wait for 30 seconds until Wi-Fi tethering is stopped
diff --git a/core/tests/coretests/AndroidManifest.xml b/core/tests/coretests/AndroidManifest.xml
index 01734f2..4be6995 100644
--- a/core/tests/coretests/AndroidManifest.xml
+++ b/core/tests/coretests/AndroidManifest.xml
@@ -44,6 +44,7 @@
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.BLUETOOTH" />
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
+ <uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" />
<uses-permission android:name="android.permission.BROADCAST_STICKY" />
<uses-permission android:name="android.permission.CHANGE_WIFI_STATE" />
<uses-permission android:name="android.permission.CLEAR_APP_CACHE" />
diff --git a/core/tests/coretests/src/android/accounts/AccountManagerServiceTest.java b/core/tests/coretests/src/android/accounts/AccountManagerServiceTest.java
index 887b032..6efc61a 100644
--- a/core/tests/coretests/src/android/accounts/AccountManagerServiceTest.java
+++ b/core/tests/coretests/src/android/accounts/AccountManagerServiceTest.java
@@ -96,7 +96,7 @@ public class AccountManagerServiceTest extends AndroidTestCase {
assertEquals(a21, accounts[1]);
assertEquals(a31, accounts[2]);
- mAms.removeAccount(a21);
+ mAms.removeAccountInternal(a21);
accounts = mAms.getAccounts("type1" );
Arrays.sort(accounts, new AccountSorter());
diff --git a/core/tests/coretests/src/android/bluetooth/BluetoothStressTest.java b/core/tests/coretests/src/android/bluetooth/BluetoothStressTest.java
index 96b028a..5dedd4a 100644
--- a/core/tests/coretests/src/android/bluetooth/BluetoothStressTest.java
+++ b/core/tests/coretests/src/android/bluetooth/BluetoothStressTest.java
@@ -250,8 +250,8 @@ public class BluetoothStressTest extends InstrumentationTestCase {
for (int i = 0; i < iterations; i++) {
mTestUtils.writeOutput("connectInput iteration " + (i + 1) + " of " + iterations);
- mTestUtils.connectInput(adapter, device);
- mTestUtils.disconnectInput(adapter, device);
+ mTestUtils.connectProfile(adapter, device, BluetoothProfile.INPUT_DEVICE);
+ mTestUtils.disconnectProfile(adapter, device, BluetoothProfile.INPUT_DEVICE);
}
mTestUtils.unpair(adapter, device);
@@ -316,4 +316,34 @@ public class BluetoothStressTest extends InstrumentationTestCase {
mTestUtils.disablePan(adapter);
mTestUtils.disable(adapter);
}
+
+ /**
+ * Stress test for verifying that AudioManager can open and close SCO connections.
+ * <p>
+ * In this test, a HSP connection is opened with an external headset and the SCO connection is
+ * repeatibly opened and closed.
+ */
+ public void testStartStopSco() {
+ int iterations = BluetoothTestRunner.sStartStopScoIterations;
+ if (iterations == 0) {
+ return;
+ }
+
+ BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
+ BluetoothDevice device = adapter.getRemoteDevice(BluetoothTestRunner.sHeadsetAddress);
+ mTestUtils.enable(adapter);
+ mTestUtils.pair(adapter, device, BluetoothTestRunner.sPairPasskey,
+ BluetoothTestRunner.sPairPin);
+ mTestUtils.connectProfile(adapter, device, BluetoothProfile.HEADSET);
+
+ for (int i = 0; i < iterations; i++) {
+ mTestUtils.writeOutput("startStopSco iteration " + (i + 1) + " of " + iterations);
+ mTestUtils.startSco(adapter, device);
+ mTestUtils.stopSco(adapter, device);
+ }
+
+ mTestUtils.disconnectProfile(adapter, device, BluetoothProfile.HEADSET);
+ mTestUtils.unpair(adapter, device);
+ mTestUtils.disable(adapter);
+ }
}
diff --git a/core/tests/coretests/src/android/bluetooth/BluetoothTestRunner.java b/core/tests/coretests/src/android/bluetooth/BluetoothTestRunner.java
index cede05a..1febc5c 100644
--- a/core/tests/coretests/src/android/bluetooth/BluetoothTestRunner.java
+++ b/core/tests/coretests/src/android/bluetooth/BluetoothTestRunner.java
@@ -39,6 +39,7 @@ import android.util.Log;
* [-e connect_headset_iterations <iterations>] \
* [-e connect_input_iterations <iterations>] \
* [-e connect_pan_iterations <iterations>] \
+ * [-e start_stop_sco_iterations <iterations>] \
* [-e pair_address <address>] \
* [-e headset_address <address>] \
* [-e a2dp_address <address>] \
@@ -62,6 +63,7 @@ public class BluetoothTestRunner extends InstrumentationTestRunner {
public static int sConnectA2dpIterations = 100;
public static int sConnectInputIterations = 100;
public static int sConnectPanIterations = 100;
+ public static int sStartStopScoIterations = 100;
public static String sPairAddress = "";
public static String sHeadsetAddress = "";
@@ -167,6 +169,14 @@ public class BluetoothTestRunner extends InstrumentationTestRunner {
}
}
+ val = arguments.getString("start_stop_sco_iterations");
+ if (val != null) {
+ try {
+ sStartStopScoIterations = Integer.parseInt(val);
+ } catch (NumberFormatException e) {
+ // Invalid argument, fall back to default value
+ }
+ }
val = arguments.getString("pair_address");
if (val != null) {
sPairAddress = val;
@@ -214,6 +224,7 @@ public class BluetoothTestRunner extends InstrumentationTestRunner {
Log.i(TAG, String.format("connect_headset_iterations=%d", sConnectHeadsetIterations));
Log.i(TAG, String.format("connect_input_iterations=%d", sConnectInputIterations));
Log.i(TAG, String.format("connect_pan_iterations=%d", sConnectPanIterations));
+ Log.i(TAG, String.format("start_stop_sco_iterations=%d", sStartStopScoIterations));
Log.i(TAG, String.format("pair_address=%s", sPairAddress));
Log.i(TAG, String.format("a2dp_address=%s", sA2dpAddress));
Log.i(TAG, String.format("headset_address=%s", sHeadsetAddress));
diff --git a/core/tests/coretests/src/android/bluetooth/BluetoothTestUtils.java b/core/tests/coretests/src/android/bluetooth/BluetoothTestUtils.java
index effed76..1741119 100644
--- a/core/tests/coretests/src/android/bluetooth/BluetoothTestUtils.java
+++ b/core/tests/coretests/src/android/bluetooth/BluetoothTestUtils.java
@@ -16,10 +16,13 @@
package android.bluetooth;
+import android.bluetooth.BluetoothPan;
+import android.bluetooth.BluetoothProfile;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
+import android.media.AudioManager;
import android.os.Environment;
import android.util.Log;
@@ -65,6 +68,11 @@ public class BluetoothTestUtils extends Assert {
private static final int CONNECT_PROXY_TIMEOUT = 5000;
/**
+ * Timeout to start or stop a SCO channel in ms.
+ */
+ private static final int START_STOP_SCO_TIMEOUT = 10000;
+
+ /**
* Time between polls in ms.
*/
private static final int POLL_TIME = 100;
@@ -238,6 +246,9 @@ public class BluetoothTestUtils extends Assert {
case BluetoothProfile.HEADSET:
mConnectionAction = BluetoothHeadset.ACTION_CONNECTION_STATE_CHANGED;
break;
+ case BluetoothProfile.INPUT_DEVICE:
+ mConnectionAction = BluetoothInputDevice.ACTION_CONNECTION_STATE_CHANGED;
+ break;
default:
mConnectionAction = null;
}
@@ -270,40 +281,43 @@ public class BluetoothTestUtils extends Assert {
}
}
- private class ConnectInputReceiver extends FlagReceiver {
+ private class ConnectPanReceiver extends FlagReceiver {
private static final int STATE_DISCONNECTED_FLAG = 1;
private static final int STATE_CONNECTING_FLAG = 1 << 1;
private static final int STATE_CONNECTED_FLAG = 1 << 2;
private static final int STATE_DISCONNECTING_FLAG = 1 << 3;
private BluetoothDevice mDevice;
+ private int mRole;
- public ConnectInputReceiver(BluetoothDevice device, int expectedFlags) {
- super(expectedFlags);
+ public ConnectPanReceiver(BluetoothDevice device, int role, int expectedFlags) {
+ super (expectedFlags);
mDevice = device;
+ mRole = role;
}
@Override
public void onReceive(Context context, Intent intent) {
- if (!mDevice.equals(intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE))) {
+ if (!mDevice.equals(intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE))
+ || mRole != intent.getIntExtra(BluetoothPan.EXTRA_LOCAL_ROLE, -1)) {
return;
}
- if (BluetoothInputDevice.ACTION_INPUT_DEVICE_STATE_CHANGED.equals(intent.getAction())) {
- int state = intent.getIntExtra(BluetoothInputDevice.EXTRA_INPUT_DEVICE_STATE, -1);
+ if (BluetoothPan.ACTION_CONNECTION_STATE_CHANGED.equals(intent.getAction())) {
+ int state = intent.getIntExtra(BluetoothPan.EXTRA_STATE, -1);
assertNotSame(-1, state);
switch (state) {
- case BluetoothInputDevice.STATE_DISCONNECTED:
+ case BluetoothPan.STATE_DISCONNECTED:
setFiredFlag(STATE_DISCONNECTED_FLAG);
break;
- case BluetoothInputDevice.STATE_CONNECTING:
+ case BluetoothPan.STATE_CONNECTING:
setFiredFlag(STATE_CONNECTING_FLAG);
break;
- case BluetoothInputDevice.STATE_CONNECTED:
+ case BluetoothPan.STATE_CONNECTED:
setFiredFlag(STATE_CONNECTED_FLAG);
break;
- case BluetoothInputDevice.STATE_DISCONNECTING:
+ case BluetoothPan.STATE_DISCONNECTING:
setFiredFlag(STATE_DISCONNECTING_FLAG);
break;
}
@@ -311,44 +325,26 @@ public class BluetoothTestUtils extends Assert {
}
}
- private class ConnectPanReceiver extends FlagReceiver {
- private static final int STATE_DISCONNECTED_FLAG = 1;
- private static final int STATE_CONNECTING_FLAG = 1 << 1;
- private static final int STATE_CONNECTED_FLAG = 1 << 2;
- private static final int STATE_DISCONNECTING_FLAG = 1 << 3;
-
- private BluetoothDevice mDevice;
- private int mRole;
+ private class StartStopScoReceiver extends FlagReceiver {
+ private static final int STATE_CONNECTED_FLAG = 1;
+ private static final int STATE_DISCONNECTED_FLAG = 1 << 1;
- public ConnectPanReceiver(BluetoothDevice device, int role, int expectedFlags) {
- super (expectedFlags);
-
- mDevice = device;
- mRole = role;
+ public StartStopScoReceiver(int expectedFlags) {
+ super(expectedFlags);
}
@Override
public void onReceive(Context context, Intent intent) {
- if (!mDevice.equals(intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE))
- || mRole != intent.getIntExtra(BluetoothPan.EXTRA_LOCAL_ROLE, -1)) {
- return;
- }
-
- if (BluetoothPan.ACTION_PAN_STATE_CHANGED.equals(intent.getAction())) {
- int state = intent.getIntExtra(BluetoothPan.EXTRA_PAN_STATE, -1);
- assertNotSame(-1, state);
- switch (state) {
- case BluetoothPan.STATE_DISCONNECTED:
- setFiredFlag(STATE_DISCONNECTED_FLAG);
- break;
- case BluetoothPan.STATE_CONNECTING:
- setFiredFlag(STATE_CONNECTING_FLAG);
- break;
- case BluetoothPan.STATE_CONNECTED:
+ if (AudioManager.ACTION_SCO_AUDIO_STATE_CHANGED.equals(intent.getAction())) {
+ int state = intent.getIntExtra(AudioManager.EXTRA_SCO_AUDIO_STATE,
+ AudioManager.SCO_AUDIO_STATE_ERROR);
+ assertNotSame(AudioManager.SCO_AUDIO_STATE_ERROR, state);
+ switch(state) {
+ case AudioManager.SCO_AUDIO_STATE_CONNECTED:
setFiredFlag(STATE_CONNECTED_FLAG);
break;
- case BluetoothPan.STATE_DISCONNECTING:
- setFiredFlag(STATE_DISCONNECTING_FLAG);
+ case AudioManager.SCO_AUDIO_STATE_DISCONNECTED:
+ setFiredFlag(STATE_DISCONNECTED_FLAG);
break;
}
}
@@ -366,6 +362,12 @@ public class BluetoothTestUtils extends Assert {
case BluetoothProfile.HEADSET:
mHeadset = (BluetoothHeadset) proxy;
break;
+ case BluetoothProfile.INPUT_DEVICE:
+ mInput = (BluetoothInputDevice) proxy;
+ break;
+ case BluetoothProfile.PAN:
+ mPan = (BluetoothPan) proxy;
+ break;
}
}
}
@@ -379,6 +381,12 @@ public class BluetoothTestUtils extends Assert {
case BluetoothProfile.HEADSET:
mHeadset = null;
break;
+ case BluetoothProfile.INPUT_DEVICE:
+ mInput = null;
+ break;
+ case BluetoothProfile.PAN:
+ mPan = null;
+ break;
}
}
}
@@ -393,6 +401,8 @@ public class BluetoothTestUtils extends Assert {
private Context mContext;
private BluetoothA2dp mA2dp;
private BluetoothHeadset mHeadset;
+ private BluetoothInputDevice mInput;
+ private BluetoothPan mPan;
/**
* Creates a utility instance for testing Bluetooth.
@@ -737,13 +747,13 @@ public class BluetoothTestUtils extends Assert {
* @param adapter The BT adapter.
*/
public void enablePan(BluetoothAdapter adapter) {
- BluetoothPan pan = new BluetoothPan(mContext);
- assertNotNull(pan);
+ if (mPan == null) mPan = (BluetoothPan) connectProxy(adapter, BluetoothProfile.PAN);
+ assertNotNull(mPan);
long start = System.currentTimeMillis();
- pan.setBluetoothTethering(true);
+ mPan.setBluetoothTethering(true);
long stop = System.currentTimeMillis();
- assertTrue(pan.isTetheringOn());
+ assertTrue(mPan.isTetheringOn());
writeOutput(String.format("enablePan() completed in %d ms", (stop - start)));
}
@@ -755,13 +765,13 @@ public class BluetoothTestUtils extends Assert {
* @param adapter The BT adapter.
*/
public void disablePan(BluetoothAdapter adapter) {
- BluetoothPan pan = new BluetoothPan(mContext);
- assertNotNull(pan);
+ if (mPan == null) mPan = (BluetoothPan) connectProxy(adapter, BluetoothProfile.PAN);
+ assertNotNull(mPan);
long start = System.currentTimeMillis();
- pan.setBluetoothTethering(false);
+ mPan.setBluetoothTethering(false);
long stop = System.currentTimeMillis();
- assertFalse(pan.isTetheringOn());
+ assertFalse(mPan.isTetheringOn());
writeOutput(String.format("disablePan() completed in %d ms", (stop - start)));
}
@@ -1078,142 +1088,6 @@ public class BluetoothTestUtils extends Assert {
}
/**
- * Connects the local device with a remote HID device and checks to make sure that the profile
- * is connected and that the correct actions were broadcast.
- *
- * @param adapter The BT adapter.
- * @param device The remote device.
- */
- public void connectInput(BluetoothAdapter adapter, BluetoothDevice device) {
- int mask = (ConnectInputReceiver.STATE_CONNECTING_FLAG
- | ConnectInputReceiver.STATE_CONNECTED_FLAG);
- long start = -1;
-
- if (!adapter.isEnabled()) {
- fail(String.format("connectInput() bluetooth not enabled: device=%s", device));
- }
-
- if (!adapter.getBondedDevices().contains(device)) {
- fail(String.format("connectInput() device not paired: device=%s", device));
- }
-
- BluetoothInputDevice inputDevice = new BluetoothInputDevice(mContext);
- assertNotNull(inputDevice);
- ConnectInputReceiver receiver = getConnectInputReceiver(device, mask);
-
- int state = inputDevice.getInputDeviceState(device);
- switch (state) {
- case BluetoothInputDevice.STATE_CONNECTED:
- removeReceiver(receiver);
- return;
- case BluetoothInputDevice.STATE_CONNECTING:
- mask = 0; // Don't check for received intents since we might have missed them.
- break;
- case BluetoothInputDevice.STATE_DISCONNECTED:
- case BluetoothInputDevice.STATE_DISCONNECTING:
- start = System.currentTimeMillis();
- assertTrue(inputDevice.connectInputDevice(device));
- break;
- default:
- removeReceiver(receiver);
- fail(String.format("connectInput() invalid state: device=%s, state=%d", device,
- state));
- }
-
- long s = System.currentTimeMillis();
- while (System.currentTimeMillis() - s < CONNECT_DISCONNECT_PROFILE_TIMEOUT) {
- state = inputDevice.getInputDeviceState(device);
- if (state == BluetoothInputDevice.STATE_CONNECTED
- && (receiver.getFiredFlags() & mask) == mask) {
- long finish = receiver.getCompletedTime();
- if (start != -1 && finish != -1) {
- writeOutput(String.format("connectInput() completed in %d ms: device=%s",
- (finish - start), device));
- } else {
- writeOutput(String.format("connectInput() completed: device=%s", device));
- }
- removeReceiver(receiver);
- return;
- }
- sleep(POLL_TIME);
- }
-
- int firedFlags = receiver.getFiredFlags();
- removeReceiver(receiver);
- fail(String.format("connectInput() timeout: device=%s, state=%d (expected %d), "
- + "flags=0x%x (expected 0x%s)", device, state, BluetoothInputDevice.STATE_CONNECTED,
- firedFlags, mask));
- }
-
- /**
- * Disconnects the local device with a remote HID device and checks to make sure that the
- * profile is connected and that the correct actions were broadcast.
- *
- * @param adapter The BT adapter.
- * @param device The remote device.
- */
- public void disconnectInput(BluetoothAdapter adapter, BluetoothDevice device) {
- int mask = (ConnectInputReceiver.STATE_DISCONNECTING_FLAG
- | ConnectInputReceiver.STATE_DISCONNECTED_FLAG);
- long start = -1;
-
- if (!adapter.isEnabled()) {
- fail(String.format("disconnectInput() bluetooth not enabled: device=%s", device));
- }
-
- if (!adapter.getBondedDevices().contains(device)) {
- fail(String.format("disconnectInput() device not paired: device=%s", device));
- }
-
- BluetoothInputDevice inputDevice = new BluetoothInputDevice(mContext);
- assertNotNull(inputDevice);
- ConnectInputReceiver receiver = getConnectInputReceiver(device, mask);
-
- int state = inputDevice.getInputDeviceState(device);
- switch (state) {
- case BluetoothInputDevice.STATE_CONNECTED:
- case BluetoothInputDevice.STATE_CONNECTING:
- start = System.currentTimeMillis();
- assertTrue(inputDevice.disconnectInputDevice(device));
- break;
- case BluetoothInputDevice.STATE_DISCONNECTED:
- removeReceiver(receiver);
- return;
- case BluetoothInputDevice.STATE_DISCONNECTING:
- mask = 0; // Don't check for received intents since we might have missed them.
- break;
- default:
- removeReceiver(receiver);
- fail(String.format("disconnectInput() invalid state: device=%s, state=%d", device,
- state));
- }
-
- long s = System.currentTimeMillis();
- while (System.currentTimeMillis() - s < CONNECT_DISCONNECT_PROFILE_TIMEOUT) {
- state = inputDevice.getInputDeviceState(device);
- if (state == BluetoothInputDevice.STATE_DISCONNECTED
- && (receiver.getFiredFlags() & mask) == mask) {
- long finish = receiver.getCompletedTime();
- if (start != -1 && finish != -1) {
- writeOutput(String.format("disconnectInput() completed in %d ms: device=%s",
- (finish - start), device));
- } else {
- writeOutput(String.format("disconnectInput() completed: device=%s", device));
- }
- removeReceiver(receiver);
- return;
- }
- sleep(POLL_TIME);
- }
-
- int firedFlags = receiver.getFiredFlags();
- removeReceiver(receiver);
- fail(String.format("disconnectInput() timeout: device=%s, state=%d (expected %d), "
- + "flags=0x%x (expected 0x%s)", device, state,
- BluetoothInputDevice.STATE_DISCONNECTED, firedFlags, mask));
- }
-
- /**
* Connects the PANU to a remote NAP and checks to make sure that the PANU is connected and that
* the correct actions were broadcast.
*
@@ -1269,11 +1143,11 @@ public class BluetoothTestUtils extends Assert {
fail(String.format("%s device not paired: device=%s", methodName, device));
}
- BluetoothPan pan = new BluetoothPan(mContext);
- assertNotNull(pan);
+ if (mPan == null) mPan = (BluetoothPan) connectProxy(adapter, BluetoothProfile.PAN);
+ assertNotNull(mPan);
ConnectPanReceiver receiver = getConnectPanReceiver(device, role, mask);
- int state = pan.getPanDeviceState(device);
+ int state = mPan.getConnectionState(device);
switch (state) {
case BluetoothPan.STATE_CONNECTED:
removeReceiver(receiver);
@@ -1286,7 +1160,7 @@ public class BluetoothTestUtils extends Assert {
start = System.currentTimeMillis();
if (role == BluetoothPan.LOCAL_PANU_ROLE) {
Log.i("BT", "connect to pan");
- assertTrue(pan.connect(device));
+ assertTrue(mPan.connect(device));
}
break;
default:
@@ -1297,7 +1171,7 @@ public class BluetoothTestUtils extends Assert {
long s = System.currentTimeMillis();
while (System.currentTimeMillis() - s < CONNECT_DISCONNECT_PROFILE_TIMEOUT) {
- state = pan.getPanDeviceState(device);
+ state = mPan.getConnectionState(device);
if (state == BluetoothPan.STATE_CONNECTED
&& (receiver.getFiredFlags() & mask) == mask) {
long finish = receiver.getCompletedTime();
@@ -1376,23 +1250,23 @@ public class BluetoothTestUtils extends Assert {
fail(String.format("%s device not paired: device=%s", methodName, device));
}
- BluetoothPan pan = new BluetoothPan(mContext);
- assertNotNull(pan);
+ if (mPan == null) mPan = (BluetoothPan) connectProxy(adapter, BluetoothProfile.PAN);
+ assertNotNull(mPan);
ConnectPanReceiver receiver = getConnectPanReceiver(device, role, mask);
- int state = pan.getPanDeviceState(device);
+ int state = mPan.getConnectionState(device);
switch (state) {
- case BluetoothInputDevice.STATE_CONNECTED:
- case BluetoothInputDevice.STATE_CONNECTING:
+ case BluetoothPan.STATE_CONNECTED:
+ case BluetoothPan.STATE_CONNECTING:
start = System.currentTimeMillis();
if (role == BluetoothPan.LOCAL_PANU_ROLE) {
- assertTrue(pan.disconnect(device));
+ assertTrue(mPan.disconnect(device));
}
break;
- case BluetoothInputDevice.STATE_DISCONNECTED:
+ case BluetoothPan.STATE_DISCONNECTED:
removeReceiver(receiver);
return;
- case BluetoothInputDevice.STATE_DISCONNECTING:
+ case BluetoothPan.STATE_DISCONNECTING:
mask = 0; // Don't check for received intents since we might have missed them.
break;
default:
@@ -1403,7 +1277,7 @@ public class BluetoothTestUtils extends Assert {
long s = System.currentTimeMillis();
while (System.currentTimeMillis() - s < CONNECT_DISCONNECT_PROFILE_TIMEOUT) {
- state = pan.getPanDeviceState(device);
+ state = mPan.getConnectionState(device);
if (state == BluetoothInputDevice.STATE_DISCONNECTED
&& (receiver.getFiredFlags() & mask) == mask) {
long finish = receiver.getCompletedTime();
@@ -1427,6 +1301,103 @@ public class BluetoothTestUtils extends Assert {
}
/**
+ * Opens a SCO channel using {@link android.media.AudioManager#startBluetoothSco()} and checks
+ * to make sure that the channel is opened and that the correct actions were broadcast.
+ *
+ * @param adapter The BT adapter.
+ * @param device The remote device.
+ */
+ public void startSco(BluetoothAdapter adapter, BluetoothDevice device) {
+ startStopSco(adapter, device, true);
+ }
+
+ /**
+ * Closes a SCO channel using {@link android.media.AudioManager#stopBluetoothSco()} and checks
+ * to make sure that the channel is closed and that the correct actions were broadcast.
+ *
+ * @param adapter The BT adapter.
+ * @param device The remote device.
+ */
+ public void stopSco(BluetoothAdapter adapter, BluetoothDevice device) {
+ startStopSco(adapter, device, false);
+ }
+ /**
+ * Helper method for {@link #startSco(BluetoothAdapter, BluetoothDevice)} and
+ * {@link #stopSco(BluetoothAdapter, BluetoothDevice)}.
+ *
+ * @param adapter The BT adapter.
+ * @param device The remote device.
+ * @param isStart Whether the SCO channel should be opened.
+ */
+ private void startStopSco(BluetoothAdapter adapter, BluetoothDevice device, boolean isStart) {
+ long start = -1;
+ int mask;
+ String methodName;
+
+ if (isStart) {
+ methodName = "startSco()";
+ mask = StartStopScoReceiver.STATE_CONNECTED_FLAG;
+ } else {
+ methodName = "stopSco()";
+ mask = StartStopScoReceiver.STATE_DISCONNECTED_FLAG;
+ }
+
+ if (!adapter.isEnabled()) {
+ fail(String.format("%s bluetooth not enabled: device=%s, start=%b", methodName, device,
+ isStart));
+ }
+
+ if (!adapter.getBondedDevices().contains(device)) {
+ fail(String.format("%s device not paired: device=%s, start=%b", methodName, device,
+ isStart));
+ }
+
+ AudioManager manager = (AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE);
+ assertNotNull(manager);
+
+ if (!manager.isBluetoothScoAvailableOffCall()) {
+ fail(String.format("%s device does not support SCO: device=%s, start=%b", methodName,
+ device, isStart));
+ }
+
+ boolean isScoOn = manager.isBluetoothScoOn();
+ if (isStart == isScoOn) {
+ return;
+ }
+
+ StartStopScoReceiver receiver = getStartStopScoReceiver(mask);
+ start = System.currentTimeMillis();
+ if (isStart) {
+ manager.startBluetoothSco();
+ } else {
+ manager.stopBluetoothSco();
+ }
+
+ long s = System.currentTimeMillis();
+ while (System.currentTimeMillis() - s < START_STOP_SCO_TIMEOUT) {
+ isScoOn = manager.isBluetoothScoOn();
+ if ((isStart == isScoOn) &&
+ (receiver.getFiredFlags() & mask) == mask) {
+ long finish = receiver.getCompletedTime();
+ if (start != -1 && finish != -1) {
+ writeOutput(String.format("%s completed in %d ms", methodName,
+ (finish - start)));
+ } else {
+ writeOutput(String.format("%s completed", methodName));
+ }
+ removeReceiver(receiver);
+ return;
+ }
+ sleep(POLL_TIME);
+ }
+
+ int firedFlags = receiver.getFiredFlags();
+ removeReceiver(receiver);
+ fail(String.format("%s timeout: start=%b (expected %b), flags=0x%x (expected 0x%x)",
+ methodName, isScoOn, isStart, firedFlags, mask));
+ }
+
+ /**
* Writes a string to the logcat and a file if a file has been specified in the constructor.
*
* @param s The string to be written.
@@ -1478,25 +1449,25 @@ public class BluetoothTestUtils extends Assert {
int expectedFlags) {
String[] actions = {
BluetoothA2dp.ACTION_CONNECTION_STATE_CHANGED,
- BluetoothHeadset.ACTION_CONNECTION_STATE_CHANGED};
+ BluetoothHeadset.ACTION_CONNECTION_STATE_CHANGED,
+ BluetoothInputDevice.ACTION_CONNECTION_STATE_CHANGED};
ConnectProfileReceiver receiver = new ConnectProfileReceiver(device, profile,
expectedFlags);
addReceiver(receiver, actions);
return receiver;
}
- private ConnectInputReceiver getConnectInputReceiver(BluetoothDevice device,
+ private ConnectPanReceiver getConnectPanReceiver(BluetoothDevice device, int role,
int expectedFlags) {
- String[] actions = {BluetoothInputDevice.ACTION_INPUT_DEVICE_STATE_CHANGED};
- ConnectInputReceiver receiver = new ConnectInputReceiver(device, expectedFlags);
+ String[] actions = {BluetoothPan.ACTION_CONNECTION_STATE_CHANGED};
+ ConnectPanReceiver receiver = new ConnectPanReceiver(device, role, expectedFlags);
addReceiver(receiver, actions);
return receiver;
}
- private ConnectPanReceiver getConnectPanReceiver(BluetoothDevice device, int role,
- int expectedFlags) {
- String[] actions = {BluetoothPan.ACTION_PAN_STATE_CHANGED};
- ConnectPanReceiver receiver = new ConnectPanReceiver(device, role, expectedFlags);
+ private StartStopScoReceiver getStartStopScoReceiver(int expectedFlags) {
+ String[] actions = {AudioManager.ACTION_SCO_AUDIO_STATE_CHANGED};
+ StartStopScoReceiver receiver = new StartStopScoReceiver(expectedFlags);
addReceiver(receiver, actions);
return receiver;
}
@@ -1511,15 +1482,25 @@ public class BluetoothTestUtils extends Assert {
long s = System.currentTimeMillis();
switch (profile) {
case BluetoothProfile.A2DP:
- while (mA2dp != null && System.currentTimeMillis() - s < CONNECT_PROXY_TIMEOUT) {
+ while (mA2dp == null && System.currentTimeMillis() - s < CONNECT_PROXY_TIMEOUT) {
sleep(POLL_TIME);
}
return mA2dp;
case BluetoothProfile.HEADSET:
- while (mHeadset != null && System.currentTimeMillis() - s < CONNECT_PROXY_TIMEOUT) {
+ while (mHeadset == null && System.currentTimeMillis() - s < CONNECT_PROXY_TIMEOUT) {
sleep(POLL_TIME);
}
return mHeadset;
+ case BluetoothProfile.INPUT_DEVICE:
+ while (mInput == null && System.currentTimeMillis() - s < CONNECT_PROXY_TIMEOUT) {
+ sleep(POLL_TIME);
+ }
+ return mInput;
+ case BluetoothProfile.PAN:
+ while (mPan == null && System.currentTimeMillis() - s < CONNECT_PROXY_TIMEOUT) {
+ sleep(POLL_TIME);
+ }
+ return mPan;
default:
return null;
}
diff --git a/core/tests/coretests/src/android/content/pm/PackageManagerTests.java b/core/tests/coretests/src/android/content/pm/PackageManagerTests.java
index 7af64e4..5d28ef7 100755
--- a/core/tests/coretests/src/android/content/pm/PackageManagerTests.java
+++ b/core/tests/coretests/src/android/content/pm/PackageManagerTests.java
@@ -769,9 +769,9 @@ public class PackageManagerTests extends AndroidTestCase {
return doneFlag;
}
- public void packageDeleted(boolean succeeded) throws RemoteException {
+ public void packageDeleted(String packageName, int returnCode) throws RemoteException {
synchronized(this) {
- this.succeeded = succeeded;
+ this.succeeded = returnCode == PackageManager.DELETE_SUCCEEDED;
doneFlag = true;
notifyAll();
}
diff --git a/core/tests/coretests/src/android/util/LruCacheTest.java b/core/tests/coretests/src/android/util/LruCacheTest.java
index cf252e6..7e46e26 100644
--- a/core/tests/coretests/src/android/util/LruCacheTest.java
+++ b/core/tests/coretests/src/android/util/LruCacheTest.java
@@ -18,6 +18,7 @@ package android.util;
import java.util.ArrayList;
import java.util.Arrays;
+import java.util.Collections;
import java.util.List;
import java.util.Map;
import junit.framework.TestCase;
@@ -166,22 +167,16 @@ public final class LruCacheTest extends TestCase {
}
public void testEntryEvictedWhenFull() {
- List<String> expectedEvictionLog = new ArrayList<String>();
- final List<String> evictionLog = new ArrayList<String>();
- LruCache<String, String> cache = new LruCache<String, String>(3) {
- @Override protected void entryEvicted(String key, String value) {
- evictionLog.add(key + "=" + value);
- }
- };
+ List<String> log = new ArrayList<String>();
+ LruCache<String, String> cache = newRemovalLogCache(log);
cache.put("a", "A");
cache.put("b", "B");
cache.put("c", "C");
- assertEquals(expectedEvictionLog, evictionLog);
+ assertEquals(Collections.<String>emptyList(), log);
cache.put("d", "D");
- expectedEvictionLog.add("a=A");
- assertEquals(expectedEvictionLog, evictionLog);
+ assertEquals(Arrays.asList("a=A"), log);
}
/**
@@ -309,19 +304,14 @@ public final class LruCacheTest extends TestCase {
}
public void testEvictAll() {
- final List<String> evictionLog = new ArrayList<String>();
- LruCache<String, String> cache = new LruCache<String, String>(10) {
- @Override protected void entryEvicted(String key, String value) {
- evictionLog.add(key + "=" + value);
- }
- };
-
+ List<String> log = new ArrayList<String>();
+ LruCache<String, String> cache = newRemovalLogCache(log);
cache.put("a", "A");
cache.put("b", "B");
cache.put("c", "C");
cache.evictAll();
assertEquals(0, cache.size());
- assertEquals(Arrays.asList("a=A", "b=B", "c=C"), evictionLog);
+ assertEquals(Arrays.asList("a=A", "b=B", "c=C"), log);
}
public void testEvictAllEvictsSizeZeroElements() {
@@ -337,16 +327,6 @@ public final class LruCacheTest extends TestCase {
assertSnapshot(cache);
}
- public void testRemoveDoesNotCallEntryEvicted() {
- LruCache<String, String> cache = new LruCache<String, String>(10) {
- @Override protected void entryEvicted(String key, String value) {
- fail();
- }
- };
- cache.put("a", "A");
- assertEquals("A", cache.remove("a"));
- }
-
public void testRemoveWithCustomSizes() {
LruCache<String, String> cache = new LruCache<String, String>(10) {
@Override protected int sizeOf(String key, String value) {
@@ -376,6 +356,99 @@ public final class LruCacheTest extends TestCase {
}
}
+ public void testRemoveCallsEntryRemoved() {
+ List<String> log = new ArrayList<String>();
+ LruCache<String, String> cache = newRemovalLogCache(log);
+ cache.put("a", "A");
+ cache.remove("a");
+ assertEquals(Arrays.asList("a=A>null"), log);
+ }
+
+ public void testPutCallsEntryRemoved() {
+ List<String> log = new ArrayList<String>();
+ LruCache<String, String> cache = newRemovalLogCache(log);
+ cache.put("a", "A");
+ cache.put("a", "A2");
+ assertEquals(Arrays.asList("a=A>A2"), log);
+ }
+
+ public void testEntryRemovedIsCalledWithoutSynchronization() {
+ LruCache<String, String> cache = new LruCache<String, String>(3) {
+ @Override protected void entryRemoved(
+ boolean evicted, String key, String oldValue, String newValue) {
+ assertFalse(Thread.holdsLock(this));
+ }
+ };
+
+ cache.put("a", "A");
+ cache.put("a", "A2"); // replaced
+ cache.put("b", "B");
+ cache.put("c", "C");
+ cache.put("d", "D"); // single eviction
+ cache.remove("a"); // removed
+ cache.evictAll(); // multiple eviction
+ }
+
+ public void testCreateIsCalledWithoutSynchronization() {
+ LruCache<String, String> cache = new LruCache<String, String>(3) {
+ @Override protected String create(String key) {
+ assertFalse(Thread.holdsLock(this));
+ return null;
+ }
+ };
+
+ cache.get("a");
+ }
+
+ /**
+ * Test what happens when a value is added to the map while create is
+ * working. The map value should be returned by get(), and the created value
+ * should be released with entryRemoved().
+ */
+ public void testCreateWithConcurrentPut() {
+ final List<String> log = new ArrayList<String>();
+ LruCache<String, String> cache = new LruCache<String, String>(3) {
+ @Override protected String create(String key) {
+ put(key, "B");
+ return "A";
+ }
+ @Override protected void entryRemoved(
+ boolean evicted, String key, String oldValue, String newValue) {
+ log.add(key + "=" + oldValue + ">" + newValue);
+ }
+ };
+
+ assertEquals("B", cache.get("a"));
+ assertEquals(Arrays.asList("a=A>B"), log);
+ }
+
+ /**
+ * Test what happens when two creates happen concurrently. The result from
+ * the first create to return is returned by both gets. The other created
+ * values should be released with entryRemove().
+ */
+ public void testCreateWithConcurrentCreate() {
+ final List<String> log = new ArrayList<String>();
+ LruCache<String, Integer> cache = new LruCache<String, Integer>(3) {
+ int callCount = 0;
+ @Override protected Integer create(String key) {
+ if (callCount++ == 0) {
+ assertEquals(2, get(key).intValue());
+ return 1;
+ } else {
+ return 2;
+ }
+ }
+ @Override protected void entryRemoved(
+ boolean evicted, String key, Integer oldValue, Integer newValue) {
+ log.add(key + "=" + oldValue + ">" + newValue);
+ }
+ };
+
+ assertEquals(2, cache.get("a").intValue());
+ assertEquals(Arrays.asList("a=1>2"), log);
+ }
+
private LruCache<String, String> newCreatingCache() {
return new LruCache<String, String>(3) {
@Override protected String create(String key) {
@@ -384,6 +457,18 @@ public final class LruCacheTest extends TestCase {
};
}
+ private LruCache<String, String> newRemovalLogCache(final List<String> log) {
+ return new LruCache<String, String>(3) {
+ @Override protected void entryRemoved(
+ boolean evicted, String key, String oldValue, String newValue) {
+ String message = evicted
+ ? (key + "=" + oldValue)
+ : (key + "=" + oldValue + ">" + newValue);
+ log.add(message);
+ }
+ };
+ }
+
private void assertHit(LruCache<String, String> cache, String key, String value) {
assertEquals(value, cache.get(key));
expectedHitCount++;