summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--cmds/locksettings/src/com/android/commands/locksettings/LockSettingsCmd.java8
-rw-r--r--core/java/android/app/ActivityManager.java7
-rw-r--r--core/java/android/content/pm/LauncherActivityInfo.java10
-rw-r--r--core/java/android/hardware/radio/RadioModule.java234
-rw-r--r--core/java/android/os/FileUtils.java10
-rw-r--r--core/java/android/provider/AlarmClock.java22
-rw-r--r--core/java/android/service/euicc/EuiccService.java4
-rw-r--r--core/java/android/widget/PopupWindow.java33
-rw-r--r--core/java/com/android/internal/backup/LocalTransport.java181
-rw-r--r--core/jni/Android.bp3
-rw-r--r--core/jni/AndroidRuntime.cpp2
-rw-r--r--core/jni/android/graphics/ColorFilter.cpp11
-rw-r--r--core/jni/android_hardware_Radio.cpp969
-rw-r--r--core/res/res/layout-land/time_picker_material.xml2
-rw-r--r--graphics/java/android/graphics/ColorFilter.java46
-rw-r--r--libs/androidfw/ResourceTypes.cpp3
-rw-r--r--libs/hwui/tests/unit/SkiaBehaviorTests.cpp2
-rw-r--r--media/jni/soundpool/SoundPoolThread.cpp29
-rw-r--r--media/jni/soundpool/SoundPoolThread.h1
-rw-r--r--packages/MtpDocumentsProvider/res/values-af/strings.xml25
-rw-r--r--packages/MtpDocumentsProvider/res/values-am/strings.xml25
-rw-r--r--packages/MtpDocumentsProvider/res/values-ar/strings.xml25
-rw-r--r--packages/MtpDocumentsProvider/res/values-az/strings.xml25
-rw-r--r--packages/MtpDocumentsProvider/res/values-b+sr+Latn/strings.xml25
-rw-r--r--packages/MtpDocumentsProvider/res/values-be/strings.xml25
-rw-r--r--packages/MtpDocumentsProvider/res/values-bg/strings.xml25
-rw-r--r--packages/MtpDocumentsProvider/res/values-bn/strings.xml25
-rw-r--r--packages/MtpDocumentsProvider/res/values-bs/strings.xml25
-rw-r--r--packages/MtpDocumentsProvider/res/values-ca/strings.xml25
-rw-r--r--packages/MtpDocumentsProvider/res/values-cs/strings.xml25
-rw-r--r--packages/MtpDocumentsProvider/res/values-da/strings.xml25
-rw-r--r--packages/MtpDocumentsProvider/res/values-de/strings.xml25
-rw-r--r--packages/MtpDocumentsProvider/res/values-el/strings.xml25
-rw-r--r--packages/MtpDocumentsProvider/res/values-en-rAU/strings.xml25
-rw-r--r--packages/MtpDocumentsProvider/res/values-en-rGB/strings.xml25
-rw-r--r--packages/MtpDocumentsProvider/res/values-en-rIN/strings.xml25
-rw-r--r--packages/MtpDocumentsProvider/res/values-es-rUS/strings.xml25
-rw-r--r--packages/MtpDocumentsProvider/res/values-es/strings.xml25
-rw-r--r--packages/MtpDocumentsProvider/res/values-et/strings.xml25
-rw-r--r--packages/MtpDocumentsProvider/res/values-eu/strings.xml25
-rw-r--r--packages/MtpDocumentsProvider/res/values-fa/strings.xml25
-rw-r--r--packages/MtpDocumentsProvider/res/values-fi/strings.xml25
-rw-r--r--packages/MtpDocumentsProvider/res/values-fr-rCA/strings.xml25
-rw-r--r--packages/MtpDocumentsProvider/res/values-fr/strings.xml25
-rw-r--r--packages/MtpDocumentsProvider/res/values-gl/strings.xml25
-rw-r--r--packages/MtpDocumentsProvider/res/values-gu/strings.xml25
-rw-r--r--packages/MtpDocumentsProvider/res/values-hi/strings.xml25
-rw-r--r--packages/MtpDocumentsProvider/res/values-hr/strings.xml25
-rw-r--r--packages/MtpDocumentsProvider/res/values-hu/strings.xml25
-rw-r--r--packages/MtpDocumentsProvider/res/values-hy/strings.xml25
-rw-r--r--packages/MtpDocumentsProvider/res/values-in/strings.xml25
-rw-r--r--packages/MtpDocumentsProvider/res/values-is/strings.xml25
-rw-r--r--packages/MtpDocumentsProvider/res/values-it/strings.xml25
-rw-r--r--packages/MtpDocumentsProvider/res/values-iw/strings.xml25
-rw-r--r--packages/MtpDocumentsProvider/res/values-ja/strings.xml25
-rw-r--r--packages/MtpDocumentsProvider/res/values-ka/strings.xml25
-rw-r--r--packages/MtpDocumentsProvider/res/values-kk/strings.xml25
-rw-r--r--packages/MtpDocumentsProvider/res/values-km/strings.xml25
-rw-r--r--packages/MtpDocumentsProvider/res/values-kn/strings.xml25
-rw-r--r--packages/MtpDocumentsProvider/res/values-ko/strings.xml25
-rw-r--r--packages/MtpDocumentsProvider/res/values-ky/strings.xml25
-rw-r--r--packages/MtpDocumentsProvider/res/values-lo/strings.xml25
-rw-r--r--packages/MtpDocumentsProvider/res/values-lt/strings.xml25
-rw-r--r--packages/MtpDocumentsProvider/res/values-lv/strings.xml25
-rw-r--r--packages/MtpDocumentsProvider/res/values-mk/strings.xml25
-rw-r--r--packages/MtpDocumentsProvider/res/values-ml/strings.xml25
-rw-r--r--packages/MtpDocumentsProvider/res/values-mn/strings.xml25
-rw-r--r--packages/MtpDocumentsProvider/res/values-mr/strings.xml25
-rw-r--r--packages/MtpDocumentsProvider/res/values-ms/strings.xml25
-rw-r--r--packages/MtpDocumentsProvider/res/values-my/strings.xml25
-rw-r--r--packages/MtpDocumentsProvider/res/values-nb/strings.xml25
-rw-r--r--packages/MtpDocumentsProvider/res/values-ne/strings.xml25
-rw-r--r--packages/MtpDocumentsProvider/res/values-nl/strings.xml25
-rw-r--r--packages/MtpDocumentsProvider/res/values-pa/strings.xml25
-rw-r--r--packages/MtpDocumentsProvider/res/values-pl/strings.xml25
-rw-r--r--packages/MtpDocumentsProvider/res/values-pt-rBR/strings.xml25
-rw-r--r--packages/MtpDocumentsProvider/res/values-pt-rPT/strings.xml25
-rw-r--r--packages/MtpDocumentsProvider/res/values-pt/strings.xml25
-rw-r--r--packages/MtpDocumentsProvider/res/values-ro/strings.xml25
-rw-r--r--packages/MtpDocumentsProvider/res/values-ru/strings.xml25
-rw-r--r--packages/MtpDocumentsProvider/res/values-si/strings.xml25
-rw-r--r--packages/MtpDocumentsProvider/res/values-sk/strings.xml25
-rw-r--r--packages/MtpDocumentsProvider/res/values-sl/strings.xml25
-rw-r--r--packages/MtpDocumentsProvider/res/values-sq/strings.xml25
-rw-r--r--packages/MtpDocumentsProvider/res/values-sr/strings.xml25
-rw-r--r--packages/MtpDocumentsProvider/res/values-sv/strings.xml25
-rw-r--r--packages/MtpDocumentsProvider/res/values-sw/strings.xml25
-rw-r--r--packages/MtpDocumentsProvider/res/values-ta/strings.xml25
-rw-r--r--packages/MtpDocumentsProvider/res/values-te/strings.xml25
-rw-r--r--packages/MtpDocumentsProvider/res/values-th/strings.xml25
-rw-r--r--packages/MtpDocumentsProvider/res/values-tl/strings.xml25
-rw-r--r--packages/MtpDocumentsProvider/res/values-tr/strings.xml25
-rw-r--r--packages/MtpDocumentsProvider/res/values-uk/strings.xml25
-rw-r--r--packages/MtpDocumentsProvider/res/values-ur/strings.xml25
-rw-r--r--packages/MtpDocumentsProvider/res/values-uz/strings.xml25
-rw-r--r--packages/MtpDocumentsProvider/res/values-vi/strings.xml25
-rw-r--r--packages/MtpDocumentsProvider/res/values-zh-rCN/strings.xml25
-rw-r--r--packages/MtpDocumentsProvider/res/values-zh-rHK/strings.xml25
-rw-r--r--packages/MtpDocumentsProvider/res/values-zh-rTW/strings.xml25
-rw-r--r--packages/MtpDocumentsProvider/res/values-zu/strings.xml25
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/core/AbstractPreferenceController.java12
-rwxr-xr-xpackages/SettingsLib/src/com/android/settingslib/graph/BatteryMeterDrawableBase.java45
-rw-r--r--packages/SettingsLib/tests/integ/src/com/android/settingslib/graph/BatteryMeterDrawableBaseTest.java33
-rw-r--r--packages/Shell/res/layout/dialog_bugreport_info.xml14
-rw-r--r--packages/SystemUI/colorextraction/src/com/google/android/colorextraction/types/Tonal.java11
-rw-r--r--packages/SystemUI/src/com/android/keyguard/PasswordTextView.java4
-rw-r--r--packages/SystemUI/src/com/android/systemui/RoundedCorners.java6
-rw-r--r--packages/SystemUI/src/com/android/systemui/SystemUIApplication.java15
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/QSAnimator.java3
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/QSFragment.java5
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/tiles/BatterySaverTile.java46
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonView.java3
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java4
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerSignalTest.java73
-rw-r--r--proto/src/metrics_constants.proto6
-rw-r--r--services/core/java/com/android/server/am/ActivityStarter.java55
-rw-r--r--services/core/java/com/android/server/content/ContentService.java9
-rw-r--r--services/core/java/com/android/server/content/SyncJobService.java16
-rw-r--r--services/core/java/com/android/server/content/SyncLogger.java252
-rw-r--r--services/core/java/com/android/server/content/SyncManager.java114
-rw-r--r--services/core/java/com/android/server/content/SyncOperation.java13
-rw-r--r--services/core/java/com/android/server/locksettings/LockSettingsService.java74
-rw-r--r--services/core/java/com/android/server/locksettings/LockSettingsShellCommand.java9
-rw-r--r--services/core/java/com/android/server/notification/NotificationManagerService.java82
-rw-r--r--services/core/java/com/android/server/pm/PackageManagerService.java5
-rw-r--r--services/core/java/com/android/server/timezone/FileDescriptorHelper.java30
-rw-r--r--services/core/java/com/android/server/timezone/RulesManagerService.java91
-rw-r--r--services/core/java/com/android/server/timezone/RulesManagerServiceHelperImpl.java12
-rw-r--r--services/devicepolicy/java/com/android/server/devicepolicy/NetworkLoggingHandler.java83
-rw-r--r--services/tests/notification/src/com/android/server/notification/NotificationManagerServiceTest.java46
-rw-r--r--services/tests/servicestests/src/com/android/server/timezone/RulesManagerServiceTest.java122
-rw-r--r--services/usb/java/com/android/server/usb/UsbDebuggingManager.java14
-rw-r--r--services/usb/java/com/android/server/usb/UsbDeviceManager.java122
-rw-r--r--services/usb/java/com/android/server/usb/UsbHostManager.java35
-rw-r--r--services/usb/java/com/android/server/usb/UsbPortManager.java32
-rw-r--r--services/usb/java/com/android/server/usb/UsbProfileGroupSettingsManager.java51
-rw-r--r--services/usb/java/com/android/server/usb/UsbService.java30
-rw-r--r--services/usb/java/com/android/server/usb/UsbSettingsManager.java1
-rw-r--r--services/usb/java/com/android/server/usb/UsbUserSettingsManager.java5
-rw-r--r--telephony/java/android/telephony/euicc/EuiccManager.java6
-rw-r--r--telephony/java/com/android/internal/telephony/euicc/IEuiccController.aidl5
-rw-r--r--test-runner/src/android/test/ClassPathPackageInfo.java79
-rw-r--r--test-runner/src/android/test/ClassPathPackageInfoSource.java193
-rw-r--r--test-runner/src/android/test/PackageInfoSources.java38
-rw-r--r--test-runner/src/android/test/suitebuilder/TestGrouping.java7
-rw-r--r--test-runner/tests/Android.mk2
146 files changed, 3372 insertions, 2143 deletions
diff --git a/cmds/locksettings/src/com/android/commands/locksettings/LockSettingsCmd.java b/cmds/locksettings/src/com/android/commands/locksettings/LockSettingsCmd.java
index 1e426d62e4e0..b9fedd365925 100644
--- a/cmds/locksettings/src/com/android/commands/locksettings/LockSettingsCmd.java
+++ b/cmds/locksettings/src/com/android/commands/locksettings/LockSettingsCmd.java
@@ -33,6 +33,10 @@ public final class LockSettingsCmd extends BaseCommand {
" locksettings set-pin [--old OLD_CREDENTIAL] NEW_PIN\n" +
" locksettings set-password [--old OLD_CREDENTIAL] NEW_PASSWORD\n" +
" locksettings clear [--old OLD_CREDENTIAL]\n" +
+ " locksettings verify [--old OLD_CREDENTIAL]\n" +
+ "\n" +
+ "flags: \n" +
+ " --user USER_ID: specify the user, default value is current user\n" +
"\n" +
"locksettings set-pattern: sets a pattern\n" +
" A pattern is specified by a non-separated list of numbers that index the cell\n" +
@@ -44,7 +48,9 @@ public final class LockSettingsCmd extends BaseCommand {
"\n" +
"locksettings set-password: sets a password\n" +
"\n" +
- "locksettings clear: clears the unlock credential\n";
+ "locksettings clear: clears the unlock credential\n" +
+ "\n" +
+ "locksettings verify: verifies the credential and unlocks the user\n";
public static void main(String[] args) {
(new LockSettingsCmd()).run(args);
diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java
index 199e856e7a22..06dbe8218450 100644
--- a/core/java/android/app/ActivityManager.java
+++ b/core/java/android/app/ActivityManager.java
@@ -360,6 +360,13 @@ public class ActivityManager {
FIRST_START_NON_FATAL_ERROR_CODE + 1;
/**
+ * Result for IActivityManaqer.startActivity: a new activity start was aborted. Never returned
+ * externally.
+ * @hide
+ */
+ public static final int START_ABORTED = FIRST_START_NON_FATAL_ERROR_CODE + 2;
+
+ /**
* Flag for IActivityManaqer.startActivity: do special start mode where
* a new activity is launched only if it is needed.
* @hide
diff --git a/core/java/android/content/pm/LauncherActivityInfo.java b/core/java/android/content/pm/LauncherActivityInfo.java
index 358787e66428..e9c958857d5c 100644
--- a/core/java/android/content/pm/LauncherActivityInfo.java
+++ b/core/java/android/content/pm/LauncherActivityInfo.java
@@ -20,12 +20,10 @@ import android.content.ComponentName;
import android.content.Context;
import android.content.pm.PackageManager.NameNotFoundException;
import android.content.res.Resources;
-import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.os.UserHandle;
import android.os.UserManager;
import android.util.DisplayMetrics;
-import android.util.Log;
/**
* A representation of an activity that can belong to this user or a managed
@@ -173,12 +171,6 @@ public class LauncherActivityInfo {
public Drawable getBadgedIcon(int density) {
Drawable originalIcon = getIcon(density);
- if (originalIcon instanceof BitmapDrawable) {
- // TODO: Go through LauncherAppsService
- return mPm.getUserBadgedIcon(originalIcon, mUser);
- } else {
- Log.e(TAG, "Unable to create badged icon for " + mActivityInfo);
- }
- return originalIcon;
+ return mPm.getUserBadgedIcon(originalIcon, mUser);
}
}
diff --git a/core/java/android/hardware/radio/RadioModule.java b/core/java/android/hardware/radio/RadioModule.java
deleted file mode 100644
index c0df0f386b09..000000000000
--- a/core/java/android/hardware/radio/RadioModule.java
+++ /dev/null
@@ -1,234 +0,0 @@
-/*
- * Copyright (C) 2015 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.radio;
-
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.annotation.SystemApi;
-import android.content.Context;
-import android.content.Intent;
-import android.os.Handler;
-import android.os.Looper;
-import android.os.Message;
-import java.lang.ref.WeakReference;
-import java.util.List;
-import java.util.UUID;
-
-/**
- * A RadioModule implements the RadioTuner interface for a broadcast radio tuner physically
- * present on the device and exposed by the radio HAL.
- *
- * @hide
- */
-public class RadioModule extends RadioTuner {
- private long mNativeContext = 0;
- private int mId;
- private NativeEventHandlerDelegate mEventHandlerDelegate;
-
- RadioModule(int moduleId, RadioManager.BandConfig config, boolean withAudio,
- RadioTuner.Callback callback, Handler handler) {
- mId = moduleId;
- mEventHandlerDelegate = new NativeEventHandlerDelegate(callback, handler);
- native_setup(new WeakReference<RadioModule>(this), config, withAudio);
- }
- private native void native_setup(Object module_this,
- RadioManager.BandConfig config, boolean withAudio);
-
- @Override
- protected void finalize() {
- native_finalize();
- }
- private native void native_finalize();
-
- boolean initCheck() {
- return mNativeContext != 0;
- }
-
- // RadioTuner implementation
- public native void close();
-
- public native int setConfiguration(RadioManager.BandConfig config);
-
- public native int getConfiguration(RadioManager.BandConfig[] config);
-
- public native int setMute(boolean mute);
-
- public native boolean getMute();
-
- public native int step(int direction, boolean skipSubChannel);
-
- public native int scan(int direction, boolean skipSubChannel);
-
- public native int tune(int channel, int subChannel);
-
- public native int cancel();
-
- public native int getProgramInformation(RadioManager.ProgramInfo[] info);
-
- public native boolean startBackgroundScan();
-
- public native @NonNull List<RadioManager.ProgramInfo> getProgramList(@Nullable String filter);
-
- public native boolean isAnalogForced();
-
- public native void setAnalogForced(boolean isForced);
-
- public native boolean isAntennaConnected();
-
- public native boolean hasControl();
-
-
- /* keep in sync with radio_event_type_t in system/core/include/system/radio.h */
- static final int EVENT_HW_FAILURE = 0;
- static final int EVENT_CONFIG = 1;
- static final int EVENT_ANTENNA = 2;
- static final int EVENT_TUNED = 3;
- static final int EVENT_METADATA = 4;
- static final int EVENT_TA = 5;
- static final int EVENT_AF_SWITCH = 6;
- static final int EVENT_EA = 7;
- static final int EVENT_CONTROL = 100;
- static final int EVENT_SERVER_DIED = 101;
-
- private class NativeEventHandlerDelegate {
- private final Handler mHandler;
-
- NativeEventHandlerDelegate(final RadioTuner.Callback callback,
- Handler handler) {
- // find the looper for our new event handler
- Looper looper;
- if (handler != null) {
- looper = handler.getLooper();
- } else {
- looper = Looper.getMainLooper();
- }
-
- // construct the event handler with this looper
- if (looper != null) {
- // implement the event handler delegate
- mHandler = new Handler(looper) {
- @Override
- public void handleMessage(Message msg) {
- switch (msg.what) {
- case EVENT_HW_FAILURE:
- if (callback != null) {
- callback.onError(RadioTuner.ERROR_HARDWARE_FAILURE);
- }
- break;
- case EVENT_CONFIG: {
- RadioManager.BandConfig config = (RadioManager.BandConfig)msg.obj;
- switch(msg.arg1) {
- case RadioManager.STATUS_OK:
- if (callback != null) {
- callback.onConfigurationChanged(config);
- }
- break;
- default:
- if (callback != null) {
- callback.onError(RadioTuner.ERROR_CONFIG);
- }
- break;
- }
- } break;
- case EVENT_ANTENNA:
- if (callback != null) {
- callback.onAntennaState(msg.arg2 == 1);
- }
- break;
- case EVENT_AF_SWITCH:
- case EVENT_TUNED: {
- RadioManager.ProgramInfo info = (RadioManager.ProgramInfo)msg.obj;
- switch (msg.arg1) {
- case RadioManager.STATUS_OK:
- if (callback != null) {
- callback.onProgramInfoChanged(info);
- }
- break;
- case RadioManager.STATUS_TIMED_OUT:
- if (callback != null) {
- callback.onError(RadioTuner.ERROR_SCAN_TIMEOUT);
- }
- break;
- case RadioManager.STATUS_INVALID_OPERATION:
- default:
- if (callback != null) {
- callback.onError(RadioTuner.ERROR_CANCELLED);
- }
- break;
- }
- } break;
- case EVENT_METADATA: {
- RadioMetadata metadata = (RadioMetadata)msg.obj;
- if (callback != null) {
- callback.onMetadataChanged(metadata);
- }
- } break;
- case EVENT_TA:
- if (callback != null) {
- callback.onTrafficAnnouncement(msg.arg2 == 1);
- }
- break;
- case EVENT_EA:
- if (callback != null) {
- callback.onEmergencyAnnouncement(msg.arg2 == 1);
- }
- case EVENT_CONTROL:
- if (callback != null) {
- callback.onControlChanged(msg.arg2 == 1);
- }
- break;
- case EVENT_SERVER_DIED:
- if (callback != null) {
- callback.onError(RadioTuner.ERROR_SERVER_DIED);
- }
- break;
- default:
- // Should not happen
- break;
- }
- }
- };
- } else {
- mHandler = null;
- }
- }
-
- Handler handler() {
- return mHandler;
- }
- }
-
-
- @SuppressWarnings("unused")
- private static void postEventFromNative(Object module_ref,
- int what, int arg1, int arg2, Object obj) {
- RadioModule module = (RadioModule)((WeakReference)module_ref).get();
- if (module == null) {
- return;
- }
-
- NativeEventHandlerDelegate delegate = module.mEventHandlerDelegate;
- if (delegate != null) {
- Handler handler = delegate.handler();
- if (handler != null) {
- Message m = handler.obtainMessage(what, arg1, arg2, obj);
- handler.sendMessage(m);
- }
- }
- }
-}
-
diff --git a/core/java/android/os/FileUtils.java b/core/java/android/os/FileUtils.java
index 50b4f8c7facf..56d6e0a62f94 100644
--- a/core/java/android/os/FileUtils.java
+++ b/core/java/android/os/FileUtils.java
@@ -369,11 +369,11 @@ public class FileUtils {
* constraints remain.
*
* @param minCount Always keep at least this many files.
- * @param minAge Always keep files younger than this age.
+ * @param minAgeMs Always keep files younger than this age, in milliseconds.
* @return if any files were deleted.
*/
- public static boolean deleteOlderFiles(File dir, int minCount, long minAge) {
- if (minCount < 0 || minAge < 0) {
+ public static boolean deleteOlderFiles(File dir, int minCount, long minAgeMs) {
+ if (minCount < 0 || minAgeMs < 0) {
throw new IllegalArgumentException("Constraints must be positive or 0");
}
@@ -393,9 +393,9 @@ public class FileUtils {
for (int i = minCount; i < files.length; i++) {
final File file = files[i];
- // Keep files newer than minAge
+ // Keep files newer than minAgeMs
final long age = System.currentTimeMillis() - file.lastModified();
- if (age > minAge) {
+ if (age > minAgeMs) {
if (file.delete()) {
Log.d(TAG, "Deleted old file " + file);
deleted = true;
diff --git a/core/java/android/provider/AlarmClock.java b/core/java/android/provider/AlarmClock.java
index d921ed409d6c..f9030124cc63 100644
--- a/core/java/android/provider/AlarmClock.java
+++ b/core/java/android/provider/AlarmClock.java
@@ -82,7 +82,8 @@ public final class AlarmClock {
* If neither of the above are given then:
* <ul>
* <li>If exactly one active alarm exists, it is dismissed.
- * <li>If more than one active alarm exists, the user is prompted to choose the alarm to dismiss.
+ * <li>If more than one active alarm exists, the user is prompted to choose the alarm to
+ * dismiss.
* </ul>
* </p><p>
* If the extra {@link #EXTRA_ALARM_SEARCH_MODE} is used, and the search results contain two or
@@ -104,8 +105,7 @@ public final class AlarmClock {
* @see #EXTRA_ALARM_SEARCH_MODE
*/
@SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
- public static final String ACTION_DISMISS_ALARM =
- "android.intent.action.DISMISS_ALARM";
+ public static final String ACTION_DISMISS_ALARM = "android.intent.action.DISMISS_ALARM";
/**
* Activity Action: Snooze a currently ringing alarm.
@@ -124,8 +124,7 @@ public final class AlarmClock {
* @see #EXTRA_ALARM_SNOOZE_DURATION
*/
@SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
- public static final String ACTION_SNOOZE_ALARM =
- "android.intent.action.SNOOZE_ALARM";
+ public static final String ACTION_SNOOZE_ALARM = "android.intent.action.SNOOZE_ALARM";
/**
* Activity Action: Set a timer.
@@ -155,6 +154,16 @@ public final class AlarmClock {
public static final String ACTION_SET_TIMER = "android.intent.action.SET_TIMER";
/**
+ * Activity Action: Dismiss timers.
+ * <p>
+ * Dismiss all currently expired timers. If there are no expired timers, then this is a no-op.
+ * </p>
+ * @hide
+ */
+ @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
+ public static final String ACTION_DISMISS_TIMER = "android.intent.action.DISMISS_TIMER";
+
+ /**
* Activity Action: Show the timers.
* <p>
* This action opens the timers page.
@@ -200,8 +209,7 @@ public final class AlarmClock {
* @see #ALARM_SEARCH_MODE_LABEL
* @see #ACTION_DISMISS_ALARM
*/
- public static final String EXTRA_ALARM_SEARCH_MODE =
- "android.intent.extra.alarm.SEARCH_MODE";
+ public static final String EXTRA_ALARM_SEARCH_MODE = "android.intent.extra.alarm.SEARCH_MODE";
/**
* Search for the alarm that is most closely matched by the search parameters
diff --git a/core/java/android/service/euicc/EuiccService.java b/core/java/android/service/euicc/EuiccService.java
index 875f286e1a6b..26f85288699a 100644
--- a/core/java/android/service/euicc/EuiccService.java
+++ b/core/java/android/service/euicc/EuiccService.java
@@ -97,6 +97,10 @@ public abstract class EuiccService extends Service {
public static final String ACTION_RESOLVE_NO_PRIVILEGES =
"android.service.euicc.action.RESOLVE_NO_PRIVILEGES";
+ /** Intent extra set for resolution requests containing the package name of the calling app. */
+ public static final String EXTRA_RESOLUTION_CALLING_PACKAGE =
+ "android.service.euicc.extra.RESOLUTION_CALLING_PACKAGE";
+
/** Result code for a successful operation. */
public static final int RESULT_OK = 0;
/** Result code indicating that an active SIM must be deactivated to perform the operation. */
diff --git a/core/java/android/widget/PopupWindow.java b/core/java/android/widget/PopupWindow.java
index f6653fbfc08c..bf25915df211 100644
--- a/core/java/android/widget/PopupWindow.java
+++ b/core/java/android/widget/PopupWindow.java
@@ -208,9 +208,6 @@ public class PopupWindow {
private int mGravity = Gravity.NO_GRAVITY;
- // Title provided to accessibility services
- private CharSequence mAccessibilityTitle;
-
private static final int[] ABOVE_ANCHOR_STATE_SET = new int[] {
com.android.internal.R.attr.state_above_anchor
};
@@ -1134,31 +1131,6 @@ public class PopupWindow {
return mIsShowing;
}
- /**
- * Set the title for this window to be reported to accessibility services. If no title is set,
- * a generic default will be reported.
- *
- * @param accessibilityTitle The new title, or {@code null} to specify that the default should
- * be used.
- * @hide
- */
- public void setAccessibilityTitle(@Nullable CharSequence accessibilityTitle) {
- mAccessibilityTitle = accessibilityTitle;
- }
-
- /**
- * Get the title for this window to be reported to accessibility services.
- *
- * @return The current title.
- * @hide
- */
- public @NonNull CharSequence getAccessibilityTitle() {
- if (mAccessibilityTitle == null) {
- mAccessibilityTitle = mContext.getString(R.string.popup_window_default_title);
- }
- return mAccessibilityTitle;
- }
-
/** @hide */
protected final void setShowing(boolean isShowing) {
mIsShowing = isShowing;
@@ -1362,6 +1334,10 @@ public class PopupWindow {
+ "calling setContentView() before attempting to show the popup.");
}
+ if (p.accessibilityTitle == null) {
+ p.accessibilityTitle = mContext.getString(R.string.popup_window_default_title);
+ }
+
// The old decor view may be transitioning out. Make sure it finishes
// and cleans up before we try to create another one.
if (mDecorView != null) {
@@ -1524,7 +1500,6 @@ public class PopupWindow {
// Used for debugging.
p.setTitle("PopupWindow:" + Integer.toHexString(hashCode()));
- p.accessibilityTitle = getAccessibilityTitle();
return p;
}
diff --git a/core/java/com/android/internal/backup/LocalTransport.java b/core/java/com/android/internal/backup/LocalTransport.java
index f76b702a1ccc..543bd0c4913d 100644
--- a/core/java/com/android/internal/backup/LocalTransport.java
+++ b/core/java/com/android/internal/backup/LocalTransport.java
@@ -30,6 +30,7 @@ import android.os.ParcelFileDescriptor;
import android.system.ErrnoException;
import android.system.Os;
import android.system.StructStat;
+import android.util.ArrayMap;
import android.util.Log;
import com.android.org.bouncycastle.util.encoders.Base64;
@@ -44,7 +45,6 @@ import java.io.FileOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
-import static android.system.OsConstants.SEEK_CUR;
/**
* Backup transport for stashing stuff into a known location on disk, and
@@ -70,9 +70,8 @@ public class LocalTransport extends BackupTransport {
// The currently-active restore set always has the same (nonzero!) token
private static final long CURRENT_SET_TOKEN = 1;
- // Full backup size quota is set to reasonable value.
+ // Size quotas at reasonable values, similar to the current cloud-storage limits
private static final long FULL_BACKUP_SIZE_QUOTA = 25 * 1024 * 1024;
-
private static final long KEY_VALUE_BACKUP_SIZE_QUOTA = 5 * 1024 * 1024;
private Context mContext;
@@ -157,6 +156,17 @@ public class LocalTransport extends BackupTransport {
return TRANSPORT_OK;
}
+ // Encapsulation of a single k/v element change
+ private class KVOperation {
+ final String key; // Element filename, not the raw key, for efficiency
+ final byte[] value; // null when this is a deletion operation
+
+ KVOperation(String k, byte[] v) {
+ key = k;
+ value = v;
+ }
+ }
+
@Override
public int performBackup(PackageInfo packageInfo, ParcelFileDescriptor data) {
if (DEBUG) {
@@ -175,62 +185,135 @@ public class LocalTransport extends BackupTransport {
// Each 'record' in the restore set is kept in its own file, named by
// the record key. Wind through the data file, extracting individual
- // record operations and building a set of all the updates to apply
+ // record operations and building a list of all the updates to apply
// in this update.
- BackupDataInput changeSet = new BackupDataInput(data.getFileDescriptor());
+ final ArrayList<KVOperation> changeOps;
try {
- int bufSize = 512;
- byte[] buf = new byte[bufSize];
- while (changeSet.readNextHeader()) {
- String key = changeSet.getKey();
- String base64Key = new String(Base64.encode(key.getBytes()));
- File entityFile = new File(packageDir, base64Key);
+ changeOps = parseBackupStream(data);
+ } catch (IOException e) {
+ // oops, something went wrong. abort the operation and return error.
+ Log.v(TAG, "Exception reading backup input", e);
+ return TRANSPORT_ERROR;
+ }
- int dataSize = changeSet.getDataSize();
+ // Okay, now we've parsed out the delta's individual operations. We need to measure
+ // the effect against what we already have in the datastore to detect quota overrun.
+ // So, we first need to tally up the current in-datastore size per key.
+ final ArrayMap<String, Integer> datastore = new ArrayMap<>();
+ int totalSize = parseKeySizes(packageDir, datastore);
- if (DEBUG) Log.v(TAG, "Got change set key=" + key + " size=" + dataSize
- + " key64=" + base64Key);
+ // ... and now figure out the datastore size that will result from applying the
+ // sequence of delta operations
+ if (DEBUG) {
+ if (changeOps.size() > 0) {
+ Log.v(TAG, "Calculating delta size impact");
+ } else {
+ Log.v(TAG, "No operations in backup stream, so no size change");
+ }
+ }
+ int updatedSize = totalSize;
+ for (KVOperation op : changeOps) {
+ // Deduct the size of the key we're about to replace, if any
+ final Integer curSize = datastore.get(op.key);
+ if (curSize != null) {
+ updatedSize -= curSize.intValue();
+ if (DEBUG && op.value == null) {
+ Log.v(TAG, " delete " + op.key + ", updated total " + updatedSize);
+ }
+ }
- if (dataSize >= 0) {
- if (entityFile.exists()) {
- entityFile.delete();
- }
- FileOutputStream entity = new FileOutputStream(entityFile);
+ // And add back the size of the value we're about to store, if any
+ if (op.value != null) {
+ updatedSize += op.value.length;
+ if (DEBUG) {
+ Log.v(TAG, ((curSize == null) ? " new " : " replace ")
+ + op.key + ", updated total " + updatedSize);
+ }
+ }
+ }
- if (dataSize > bufSize) {
- bufSize = dataSize;
- buf = new byte[bufSize];
- }
- changeSet.readEntityData(buf, 0, dataSize);
- if (DEBUG) {
- try {
- long cur = Os.lseek(data.getFileDescriptor(), 0, SEEK_CUR);
- Log.v(TAG, " read entity data; new pos=" + cur);
- }
- catch (ErrnoException e) {
- Log.w(TAG, "Unable to stat input file in performBackup() on "
- + packageInfo.packageName);
- }
- }
+ // If our final size is over quota, report the failure
+ if (updatedSize > KEY_VALUE_BACKUP_SIZE_QUOTA) {
+ if (DEBUG) {
+ Log.i(TAG, "New datastore size " + updatedSize
+ + " exceeds quota " + KEY_VALUE_BACKUP_SIZE_QUOTA);
+ }
+ return TRANSPORT_QUOTA_EXCEEDED;
+ }
- try {
- entity.write(buf, 0, dataSize);
- } catch (IOException e) {
- Log.e(TAG, "Unable to update key file " + entityFile.getAbsolutePath());
- return TRANSPORT_ERROR;
- } finally {
- entity.close();
- }
- } else {
- entityFile.delete();
+ // No problem with storage size, so go ahead and apply the delta operations
+ // (in the order that the app provided them)
+ for (KVOperation op : changeOps) {
+ File element = new File(packageDir, op.key);
+
+ // this is either a deletion or a rewrite-from-zero, so we can just remove
+ // the existing file and proceed in either case.
+ element.delete();
+
+ // if this wasn't a deletion, put the new data in place
+ if (op.value != null) {
+ try (FileOutputStream out = new FileOutputStream(element)) {
+ out.write(op.value, 0, op.value.length);
+ } catch (IOException e) {
+ Log.e(TAG, "Unable to update key file " + element);
+ return TRANSPORT_ERROR;
}
}
- return TRANSPORT_OK;
- } catch (IOException e) {
- // oops, something went wrong. abort the operation and return error.
- Log.v(TAG, "Exception reading backup input:", e);
- return TRANSPORT_ERROR;
}
+ return TRANSPORT_OK;
+ }
+
+ // Parses a backup stream into individual key/value operations
+ private ArrayList<KVOperation> parseBackupStream(ParcelFileDescriptor data)
+ throws IOException {
+ ArrayList<KVOperation> changeOps = new ArrayList<>();
+ BackupDataInput changeSet = new BackupDataInput(data.getFileDescriptor());
+ while (changeSet.readNextHeader()) {
+ String key = changeSet.getKey();
+ String base64Key = new String(Base64.encode(key.getBytes()));
+ int dataSize = changeSet.getDataSize();
+ if (DEBUG) {
+ Log.v(TAG, " Delta operation key " + key + " size " + dataSize
+ + " key64 " + base64Key);
+ }
+
+ byte[] buf = (dataSize >= 0) ? new byte[dataSize] : null;
+ if (dataSize >= 0) {
+ changeSet.readEntityData(buf, 0, dataSize);
+ }
+ changeOps.add(new KVOperation(base64Key, buf));
+ }
+ return changeOps;
+ }
+
+ // Reads the given datastore directory, building a table of the value size of each
+ // keyed element, and returning the summed total.
+ private int parseKeySizes(File packageDir, ArrayMap<String, Integer> datastore) {
+ int totalSize = 0;
+ final String[] elements = packageDir.list();
+ if (elements != null) {
+ if (DEBUG) {
+ Log.v(TAG, "Existing datastore contents:");
+ }
+ for (String file : elements) {
+ File element = new File(packageDir, file);
+ String key = file; // filename
+ int size = (int) element.length();
+ totalSize += size;
+ if (DEBUG) {
+ Log.v(TAG, " key " + key + " size " + size);
+ }
+ datastore.put(key, size);
+ }
+ if (DEBUG) {
+ Log.v(TAG, " TOTAL: " + totalSize);
+ }
+ } else {
+ if (DEBUG) {
+ Log.v(TAG, "No existing data for this package");
+ }
+ }
+ return totalSize;
}
// Deletes the contents but not the given directory
diff --git a/core/jni/Android.bp b/core/jni/Android.bp
index c5279e10d93f..51851690c08d 100644
--- a/core/jni/Android.bp
+++ b/core/jni/Android.bp
@@ -162,7 +162,6 @@ cc_library_shared {
"android_hardware_camera2_DngCreator.cpp",
"android_hardware_display_DisplayViewport.cpp",
"android_hardware_HardwareBuffer.cpp",
- "android_hardware_Radio.cpp",
"android_hardware_SensorManager.cpp",
"android_hardware_SerialPort.cpp",
"android_hardware_SoundTrigger.cpp",
@@ -258,12 +257,10 @@ cc_library_shared {
"libpdfium",
"libimg_utils",
"libnetd_client",
- "libradio",
"libsoundtrigger",
"libminikin",
"libprocessgroup",
"libnativebridge",
- "libradio_metadata",
"libnativeloader",
"libmemunreachable",
"libhidlbase",
diff --git a/core/jni/AndroidRuntime.cpp b/core/jni/AndroidRuntime.cpp
index 659f47debaf1..92bc16055931 100644
--- a/core/jni/AndroidRuntime.cpp
+++ b/core/jni/AndroidRuntime.cpp
@@ -88,7 +88,6 @@ extern int register_android_hardware_camera2_legacy_LegacyCameraDevice(JNIEnv *e
extern int register_android_hardware_camera2_legacy_PerfMeasurement(JNIEnv *env);
extern int register_android_hardware_camera2_DngCreator(JNIEnv *env);
extern int register_android_hardware_HardwareBuffer(JNIEnv *env);
-extern int register_android_hardware_Radio(JNIEnv *env);
extern int register_android_hardware_SensorManager(JNIEnv *env);
extern int register_android_hardware_SerialPort(JNIEnv *env);
extern int register_android_hardware_SoundTrigger(JNIEnv *env);
@@ -1402,7 +1401,6 @@ static const RegJNIRec gRegJNI[] = {
REG_JNI(register_android_hardware_camera2_legacy_PerfMeasurement),
REG_JNI(register_android_hardware_camera2_DngCreator),
REG_JNI(register_android_hardware_HardwareBuffer),
- REG_JNI(register_android_hardware_Radio),
REG_JNI(register_android_hardware_SensorManager),
REG_JNI(register_android_hardware_SerialPort),
REG_JNI(register_android_hardware_SoundTrigger),
diff --git a/core/jni/android/graphics/ColorFilter.cpp b/core/jni/android/graphics/ColorFilter.cpp
index 5553a3ed22c5..4b6578bdff7f 100644
--- a/core/jni/android/graphics/ColorFilter.cpp
+++ b/core/jni/android/graphics/ColorFilter.cpp
@@ -30,9 +30,12 @@ using namespace uirenderer;
class SkColorFilterGlue {
public:
- static void SafeUnref(JNIEnv* env, jobject clazz, jlong skFilterHandle) {
- SkColorFilter* filter = reinterpret_cast<SkColorFilter *>(skFilterHandle);
- SkSafeUnref(filter);
+ static void SafeUnref(SkShader* shader) {
+ SkSafeUnref(shader);
+ }
+
+ static jlong GetNativeFinalizer(JNIEnv*, jobject) {
+ return static_cast<jlong>(reinterpret_cast<uintptr_t>(&SafeUnref));
}
static jlong CreatePorterDuffFilter(JNIEnv* env, jobject, jint srcColor, jint modeHandle) {
@@ -57,7 +60,7 @@ public:
};
static const JNINativeMethod colorfilter_methods[] = {
- {"nSafeUnref", "(J)V", (void*) SkColorFilterGlue::SafeUnref}
+ {"nativeGetFinalizer", "()J", (void*) SkColorFilterGlue::GetNativeFinalizer }
};
static const JNINativeMethod porterduff_methods[] = {
diff --git a/core/jni/android_hardware_Radio.cpp b/core/jni/android_hardware_Radio.cpp
deleted file mode 100644
index 8b9be68bf712..000000000000
--- a/core/jni/android_hardware_Radio.cpp
+++ /dev/null
@@ -1,969 +0,0 @@
-/*
-**
-** Copyright 2015, 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_NDEBUG 1
-#define LOG_TAG "Radio-JNI"
-#include <utils/Log.h>
-
-#include "jni.h"
-#include "JNIHelp.h"
-#include "core_jni_helpers.h"
-#include <system/radio.h>
-#include <system/RadioMetadataWrapper.h>
-#include <radio/RadioCallback.h>
-#include <radio/Radio.h>
-#include <utils/RefBase.h>
-#include <utils/Vector.h>
-#include <binder/IMemory.h>
-#include <binder/MemoryDealer.h>
-
-using namespace android;
-
-static jclass gArrayListClass;
-static struct {
- jmethodID add;
-} gArrayListMethods;
-
-static const char* const kRadioManagerClassPathName = "android/hardware/radio/RadioManager";
-static jclass gRadioManagerClass;
-
-static const char* const kRadioModuleClassPathName = "android/hardware/radio/RadioModule";
-static jclass gRadioModuleClass;
-static struct {
- jfieldID mNativeContext;
- jfieldID mId;
-} gModuleFields;
-static jmethodID gPostEventFromNative;
-
-static const char* const kModulePropertiesClassPathName =
- "android/hardware/radio/RadioManager$ModuleProperties";
-static jclass gModulePropertiesClass;
-static jmethodID gModulePropertiesCstor;
-
-
-static const char* const kRadioBandDescriptorClassPathName =
- "android/hardware/radio/RadioManager$BandDescriptor";
-static jclass gRadioBandDescriptorClass;
-static struct {
- jfieldID mRegion;
- jfieldID mType;
- jfieldID mLowerLimit;
- jfieldID mUpperLimit;
- jfieldID mSpacing;
-} gRadioBandDescriptorFields;
-
-static const char* const kRadioFmBandDescriptorClassPathName =
- "android/hardware/radio/RadioManager$FmBandDescriptor";
-static jclass gRadioFmBandDescriptorClass;
-static jmethodID gRadioFmBandDescriptorCstor;
-
-static const char* const kRadioAmBandDescriptorClassPathName =
- "android/hardware/radio/RadioManager$AmBandDescriptor";
-static jclass gRadioAmBandDescriptorClass;
-static jmethodID gRadioAmBandDescriptorCstor;
-
-static const char* const kRadioBandConfigClassPathName =
- "android/hardware/radio/RadioManager$BandConfig";
-static jclass gRadioBandConfigClass;
-static struct {
- jfieldID mDescriptor;
-} gRadioBandConfigFields;
-
-
-static const char* const kRadioFmBandConfigClassPathName =
- "android/hardware/radio/RadioManager$FmBandConfig";
-static jclass gRadioFmBandConfigClass;
-static jmethodID gRadioFmBandConfigCstor;
-static struct {
- jfieldID mStereo;
- jfieldID mRds;
- jfieldID mTa;
- jfieldID mAf;
- jfieldID mEa;
-} gRadioFmBandConfigFields;
-
-static const char* const kRadioAmBandConfigClassPathName =
- "android/hardware/radio/RadioManager$AmBandConfig";
-static jclass gRadioAmBandConfigClass;
-static jmethodID gRadioAmBandConfigCstor;
-static struct {
- jfieldID mStereo;
-} gRadioAmBandConfigFields;
-
-
-static const char* const kRadioProgramInfoClassPathName =
- "android/hardware/radio/RadioManager$ProgramInfo";
-static jclass gRadioProgramInfoClass;
-static jmethodID gRadioProgramInfoCstor;
-
-static const char* const kRadioMetadataClassPathName =
- "android/hardware/radio/RadioMetadata";
-static jclass gRadioMetadataClass;
-static jmethodID gRadioMetadataCstor;
-static struct {
- jmethodID putIntFromNative;
- jmethodID putStringFromNative;
- jmethodID putBitmapFromNative;
- jmethodID putClockFromNative;
-} gRadioMetadataMethods;
-
-static Mutex gLock;
-
-enum {
- RADIO_STATUS_OK = 0,
- RADIO_STATUS_ERROR = INT_MIN,
- RADIO_PERMISSION_DENIED = -1,
- RADIO_STATUS_NO_INIT = -19,
- RADIO_STATUS_BAD_VALUE = -22,
- RADIO_STATUS_DEAD_OBJECT = -32,
- RADIO_STATUS_INVALID_OPERATION = -38,
- RADIO_STATUS_TIMED_OUT = -110,
-};
-
-
-// ----------------------------------------------------------------------------
-
-static sp<Radio> getRadio(JNIEnv* env, jobject thiz)
-{
- Mutex::Autolock l(gLock);
- Radio* const radio = (Radio*)env->GetLongField(thiz, gModuleFields.mNativeContext);
- return sp<Radio>(radio);
-}
-
-static sp<Radio> setRadio(JNIEnv* env, jobject thiz, const sp<Radio>& module)
-{
- Mutex::Autolock l(gLock);
- sp<Radio> old = (Radio*)env->GetLongField(thiz, gModuleFields.mNativeContext);
- if (module.get()) {
- module->incStrong((void*)setRadio);
- }
- if (old != 0) {
- old->decStrong((void*)setRadio);
- }
- env->SetLongField(thiz, gModuleFields.mNativeContext, (jlong)module.get());
- return old;
-}
-
-static jint convertBandDescriptorFromNative(JNIEnv *env,
- jobject *jBandDescriptor,
- const radio_band_config_t *nBandconfig)
-{
- ALOGV("%s type %d region %d", __FUNCTION__, nBandconfig->band.type, nBandconfig->region);
-
- if (nBandconfig->band.type == RADIO_BAND_FM ||
- nBandconfig->band.type == RADIO_BAND_FM_HD) {
- *jBandDescriptor = env->NewObject(gRadioFmBandDescriptorClass, gRadioFmBandDescriptorCstor,
- nBandconfig->region, nBandconfig->band.type,
- nBandconfig->band.lower_limit, nBandconfig->band.upper_limit,
- nBandconfig->band.spacings[0],
- nBandconfig->band.fm.stereo,
- nBandconfig->band.fm.rds != RADIO_RDS_NONE,
- nBandconfig->band.fm.ta,
- nBandconfig->band.fm.af,
- nBandconfig->band.fm.ea);
- } else if (nBandconfig->band.type == RADIO_BAND_AM) {
- *jBandDescriptor = env->NewObject(gRadioAmBandDescriptorClass, gRadioAmBandDescriptorCstor,
- nBandconfig->region, nBandconfig->band.type,
- nBandconfig->band.lower_limit, nBandconfig->band.upper_limit,
- nBandconfig->band.spacings[0],
- nBandconfig->band.am.stereo);
- } else {
- ALOGE("%s unknown band type %d", __FUNCTION__, nBandconfig->band.type);
- return (jint)RADIO_STATUS_BAD_VALUE;
- }
-
- if (*jBandDescriptor == NULL) {
- return (jint)RADIO_STATUS_NO_INIT;
- }
-
- return (jint)RADIO_STATUS_OK;
-}
-
-static jint convertBandConfigFromNative(JNIEnv *env,
- jobject *jBandConfig,
- const radio_band_config_t *nBandconfig)
-{
- ALOGV("%s type %d region %d", __FUNCTION__, nBandconfig->band.type, nBandconfig->region);
-
- if (nBandconfig->band.type == RADIO_BAND_FM ||
- nBandconfig->band.type == RADIO_BAND_FM_HD) {
- *jBandConfig = env->NewObject(gRadioFmBandConfigClass, gRadioFmBandConfigCstor,
- nBandconfig->region, nBandconfig->band.type,
- nBandconfig->band.lower_limit, nBandconfig->band.upper_limit,
- nBandconfig->band.spacings[0],
- nBandconfig->band.fm.stereo,
- nBandconfig->band.fm.rds != RADIO_RDS_NONE,
- nBandconfig->band.fm.ta,
- nBandconfig->band.fm.af,
- nBandconfig->band.fm.ea);
- } else if (nBandconfig->band.type == RADIO_BAND_AM) {
- *jBandConfig = env->NewObject(gRadioAmBandConfigClass, gRadioAmBandConfigCstor,
- nBandconfig->region, nBandconfig->band.type,
- nBandconfig->band.lower_limit, nBandconfig->band.upper_limit,
- nBandconfig->band.spacings[0],
- nBandconfig->band.am.stereo);
- } else {
- ALOGE("%s unknown band type %d", __FUNCTION__, nBandconfig->band.type);
- return (jint)RADIO_STATUS_BAD_VALUE;
- }
-
- if (*jBandConfig == NULL) {
- return (jint)RADIO_STATUS_NO_INIT;
- }
-
- return (jint)RADIO_STATUS_OK;
-}
-
-static jint convertMetadataFromNative(JNIEnv *env,
- jobject *jMetadata,
- const radio_metadata_t *nMetadata)
-{
- ALOGV("%s", __FUNCTION__);
- int count = radio_metadata_get_count(nMetadata);
- if (count <= 0) {
- return (jint)count;
- }
- *jMetadata = env->NewObject(gRadioMetadataClass, gRadioMetadataCstor);
-
- jint jCount = 0;
- jint jStatus = 0;
- for (unsigned int i = 0; i < (unsigned int)count; i++) {
- radio_metadata_key_t key;
- radio_metadata_type_t type;
- void *value;
- size_t size;
- if (radio_metadata_get_at_index(nMetadata, i , &key, &type, &value, &size) != 0) {
- continue;
- }
- switch (type) {
- case RADIO_METADATA_TYPE_INT: {
- ALOGV("%s RADIO_METADATA_TYPE_INT %d", __FUNCTION__, key);
- int32_t val = *(int32_t *)value;
- jStatus = env->CallIntMethod(*jMetadata,
- gRadioMetadataMethods.putIntFromNative,
- key, (jint)val);
- if (jStatus == 0) {
- jCount++;
- }
- } break;
- case RADIO_METADATA_TYPE_TEXT: {
- ALOGV("%s RADIO_METADATA_TYPE_TEXT %d", __FUNCTION__, key);
- jstring jText = env->NewStringUTF((char *)value);
- jStatus = env->CallIntMethod(*jMetadata,
- gRadioMetadataMethods.putStringFromNative,
- key, jText);
- if (jStatus == 0) {
- jCount++;
- }
- env->DeleteLocalRef(jText);
- } break;
- case RADIO_METADATA_TYPE_RAW: {
- ALOGV("%s RADIO_METADATA_TYPE_RAW %d size %zu", __FUNCTION__, key, size);
- if (size == 0) {
- break;
- }
- jbyteArray jData = env->NewByteArray(size);
- if (jData == NULL) {
- break;
- }
- env->SetByteArrayRegion(jData, 0, size, (jbyte *)value);
- jStatus = env->CallIntMethod(*jMetadata,
- gRadioMetadataMethods.putBitmapFromNative,
- key, jData);
- if (jStatus == 0) {
- jCount++;
- }
- env->DeleteLocalRef(jData);
- } break;
- case RADIO_METADATA_TYPE_CLOCK: {
- ALOGV("%s RADIO_METADATA_TYPE_CLOCK %d", __FUNCTION__, key);
- radio_metadata_clock_t *clock = (radio_metadata_clock_t *) value;
- jStatus =
- env->CallIntMethod(*jMetadata,
- gRadioMetadataMethods.putClockFromNative,
- key, (jint) clock->utc_seconds_since_epoch,
- (jint) clock->timezone_offset_in_minutes);
- if (jStatus == 0) {
- jCount++;
- }
- } break;
- }
- }
- return jCount;
-}
-
-static jint convertProgramInfoFromNative(JNIEnv *env,
- jobject *jProgramInfo,
- const radio_program_info_t *nProgramInfo)
-{
- ALOGV("%s", __FUNCTION__);
- int jStatus;
- jobject jMetadata = NULL;
-
- if (nProgramInfo == nullptr || nProgramInfo->metadata == nullptr) {
- return (jint)RADIO_STATUS_BAD_VALUE;
- }
-
- jStatus = convertMetadataFromNative(env, &jMetadata, nProgramInfo->metadata);
- if (jStatus < 0) {
- return jStatus;
- }
-
- ALOGV("%s channel %d tuned %d", __FUNCTION__, nProgramInfo->channel, nProgramInfo->tuned);
-
- int flags = 0; // TODO(b/32621193): pass from the HAL
- jstring jVendorExension = env->NewStringUTF(""); // TODO(b/32621193): pass from the HAL
- *jProgramInfo = env->NewObject(gRadioProgramInfoClass, gRadioProgramInfoCstor,
- nProgramInfo->channel, nProgramInfo->sub_channel,
- nProgramInfo->tuned, nProgramInfo->stereo,
- nProgramInfo->digital, nProgramInfo->signal_strength,
- jMetadata, flags, jVendorExension);
-
- env->DeleteLocalRef(jMetadata);
- env->DeleteLocalRef(jVendorExension);
- return (jint)RADIO_STATUS_OK;
-}
-
-
-static jint convertBandConfigToNative(JNIEnv *env,
- radio_band_config_t *nBandconfig,
- jobject jBandConfig)
-{
- ALOGV("%s", __FUNCTION__);
-
- jobject jDescriptor = env->GetObjectField(jBandConfig, gRadioBandConfigFields.mDescriptor);
-
- if (jDescriptor == NULL) {
- return (jint)RADIO_STATUS_NO_INIT;
- }
-
- nBandconfig->region =
- (radio_region_t)env->GetIntField(jDescriptor, gRadioBandDescriptorFields.mRegion);
- nBandconfig->band.type =
- (radio_band_t)env->GetIntField(jDescriptor, gRadioBandDescriptorFields.mType);
- nBandconfig->band.lower_limit =
- env->GetIntField(jDescriptor, gRadioBandDescriptorFields.mLowerLimit);
- nBandconfig->band.upper_limit =
- env->GetIntField(jDescriptor, gRadioBandDescriptorFields.mUpperLimit);
- nBandconfig->band.num_spacings = 1;
- nBandconfig->band.spacings[0] =
- env->GetIntField(jDescriptor, gRadioBandDescriptorFields.mSpacing);
-
- if (env->IsInstanceOf(jBandConfig, gRadioFmBandConfigClass)) {
- nBandconfig->band.fm.deemphasis = radio_demephasis_for_region(nBandconfig->region);
- nBandconfig->band.fm.stereo =
- env->GetBooleanField(jBandConfig, gRadioFmBandConfigFields.mStereo);
- nBandconfig->band.fm.rds =
- radio_rds_for_region(env->GetBooleanField(jBandConfig,
- gRadioFmBandConfigFields.mRds),
- nBandconfig->region);
- nBandconfig->band.fm.ta = env->GetBooleanField(jBandConfig, gRadioFmBandConfigFields.mTa);
- nBandconfig->band.fm.af = env->GetBooleanField(jBandConfig, gRadioFmBandConfigFields.mAf);
- nBandconfig->band.fm.ea = env->GetBooleanField(jBandConfig, gRadioFmBandConfigFields.mEa);
- } else if (env->IsInstanceOf(jBandConfig, gRadioAmBandConfigClass)) {
- nBandconfig->band.am.stereo =
- env->GetBooleanField(jBandConfig, gRadioAmBandConfigFields.mStereo);
- } else {
- return (jint)RADIO_STATUS_BAD_VALUE;
- }
-
- return (jint)RADIO_STATUS_OK;
-}
-
-static jint
-android_hardware_Radio_listModules(JNIEnv *env, jobject clazz,
- jobject jModules)
-{
- ALOGV("%s", __FUNCTION__);
-
- if (jModules == NULL) {
- ALOGE("listModules NULL ArrayList");
- return RADIO_STATUS_BAD_VALUE;
- }
- if (!env->IsInstanceOf(jModules, gArrayListClass)) {
- ALOGE("listModules not an arraylist");
- return RADIO_STATUS_BAD_VALUE;
- }
-
- unsigned int numModules = 0;
- radio_properties_t *nModules = NULL;
-
- status_t status = Radio::listModules(nModules, &numModules);
- if (status != NO_ERROR || numModules == 0) {
- return (jint)status;
- }
-
- nModules = (radio_properties_t *)calloc(numModules, sizeof(radio_properties_t));
-
- status = Radio::listModules(nModules, &numModules);
- ALOGV("%s Radio::listModules status %d numModules %d", __FUNCTION__, status, numModules);
-
- if (status != NO_ERROR) {
- numModules = 0;
- }
-
- for (size_t i = 0; i < numModules; i++) {
- if (nModules[i].num_bands == 0) {
- continue;
- }
- ALOGV("%s module %zu id %d implementor %s product %s",
- __FUNCTION__, i, nModules[i].handle, nModules[i].implementor,
- nModules[i].product);
-
-
- jobjectArray jBands = env->NewObjectArray(nModules[i].num_bands,
- gRadioBandDescriptorClass, NULL);
-
- for (size_t j = 0; j < nModules[i].num_bands; j++) {
- jobject jBandDescriptor;
- int jStatus =
- convertBandDescriptorFromNative(env, &jBandDescriptor, &nModules[i].bands[j]);
- if (jStatus != RADIO_STATUS_OK) {
- continue;
- }
- env->SetObjectArrayElement(jBands, j, jBandDescriptor);
- env->DeleteLocalRef(jBandDescriptor);
- }
-
- if (env->GetArrayLength(jBands) == 0) {
- continue;
- }
- jstring jImplementor = env->NewStringUTF(nModules[i].implementor);
- jstring jProduct = env->NewStringUTF(nModules[i].product);
- jstring jVersion = env->NewStringUTF(nModules[i].version);
- jstring jSerial = env->NewStringUTF(nModules[i].serial);
- bool isBgscanSupported = false; // TODO(b/32621193): pass from the HAL
- jstring jVendorExension = env->NewStringUTF(""); // TODO(b/32621193): pass from the HAL
- jobject jModule = env->NewObject(gModulePropertiesClass, gModulePropertiesCstor,
- nModules[i].handle, nullptr, nModules[i].class_id,
- jImplementor, jProduct, jVersion, jSerial,
- nModules[i].num_tuners,
- nModules[i].num_audio_sources,
- nModules[i].supports_capture,
- jBands, isBgscanSupported, jVendorExension);
-
- env->DeleteLocalRef(jImplementor);
- env->DeleteLocalRef(jProduct);
- env->DeleteLocalRef(jVersion);
- env->DeleteLocalRef(jSerial);
- env->DeleteLocalRef(jBands);
- env->DeleteLocalRef(jVendorExension);
- if (jModule == NULL) {
- continue;
- }
- env->CallBooleanMethod(jModules, gArrayListMethods.add, jModule);
- }
-
- free(nModules);
- return (jint) status;
-}
-
-// ----------------------------------------------------------------------------
-
-class JNIRadioCallback: public RadioCallback
-{
-public:
- JNIRadioCallback(JNIEnv* env, jobject thiz, jobject weak_thiz);
- ~JNIRadioCallback();
-
- virtual void onEvent(struct radio_event *event);
-
-private:
- jclass mClass; // Reference to Radio class
- jobject mObject; // Weak ref to Radio Java object to call on
-};
-
-JNIRadioCallback::JNIRadioCallback(JNIEnv* env, jobject thiz, jobject weak_thiz)
-{
-
- // Hold onto the RadioModule class for use in calling the static method
- // that posts events to the application thread.
- jclass clazz = env->GetObjectClass(thiz);
- if (clazz == NULL) {
- ALOGE("Can't find class %s", kRadioModuleClassPathName);
- return;
- }
- mClass = (jclass)env->NewGlobalRef(clazz);
-
- // We use a weak reference so the RadioModule object can be garbage collected.
- // The reference is only used as a proxy for callbacks.
- mObject = env->NewGlobalRef(weak_thiz);
-}
-
-JNIRadioCallback::~JNIRadioCallback()
-{
- // remove global references
- JNIEnv *env = AndroidRuntime::getJNIEnv();
- if (env == NULL) {
- return;
- }
- env->DeleteGlobalRef(mObject);
- env->DeleteGlobalRef(mClass);
-}
-
-void JNIRadioCallback::onEvent(struct radio_event *event)
-{
- JNIEnv *env = AndroidRuntime::getJNIEnv();
- if (env == NULL) {
- return;
- }
-
- ALOGV("%s", __FUNCTION__);
-
- jobject jObj = NULL;
- jint jArg2 = 0;
- jint jStatus = RADIO_STATUS_OK;
- switch (event->type) {
- case RADIO_EVENT_CONFIG:
- jStatus = convertBandConfigFromNative(env, &jObj, &event->config);
- break;
- case RADIO_EVENT_TUNED:
- case RADIO_EVENT_AF_SWITCH:
- ALOGV("%s RADIO_EVENT_TUNED channel %d", __FUNCTION__, event->info.channel);
- jStatus = convertProgramInfoFromNative(env, &jObj, &event->info);
- break;
- case RADIO_EVENT_METADATA:
- jStatus = convertMetadataFromNative(env, &jObj, event->metadata);
- if (jStatus >= 0) {
- jStatus = RADIO_STATUS_OK;
- }
- break;
- case RADIO_EVENT_ANTENNA:
- case RADIO_EVENT_TA:
- case RADIO_EVENT_EA:
- case RADIO_EVENT_CONTROL:
- jArg2 = event->on ? 1 : 0;
- break;
- }
-
- if (jStatus != RADIO_STATUS_OK) {
- return;
- }
- env->CallStaticVoidMethod(mClass, gPostEventFromNative, mObject,
- event->type, event->status, jArg2, jObj);
-
- env->DeleteLocalRef(jObj);
- if (env->ExceptionCheck()) {
- ALOGW("An exception occurred while notifying an event.");
- env->ExceptionClear();
- }
-}
-
-// ----------------------------------------------------------------------------
-
-static void
-android_hardware_Radio_setup(JNIEnv *env, jobject thiz,
- jobject weak_this, jobject jConfig, jboolean withAudio)
-{
- ALOGV("%s", __FUNCTION__);
-
- setRadio(env, thiz, 0);
-
- sp<JNIRadioCallback> callback = new JNIRadioCallback(env, thiz, weak_this);
-
- radio_handle_t handle = (radio_handle_t)env->GetIntField(thiz, gModuleFields.mId);
-
- struct radio_band_config nConfig;
- struct radio_band_config *configPtr = NULL;
- if (jConfig != NULL) {
- jint jStatus = convertBandConfigToNative(env, &nConfig, jConfig);
- if (jStatus != RADIO_STATUS_OK) {
- return;
- }
- configPtr = &nConfig;
- }
- sp<Radio> module = Radio::attach(handle, configPtr, (bool)withAudio, callback);
- if (module == 0) {
- return;
- }
-
- setRadio(env, thiz, module);
-}
-
-static void
-android_hardware_Radio_close(JNIEnv *env, jobject thiz)
-{
- ALOGV("%s", __FUNCTION__);
- sp<Radio> module = setRadio(env, thiz, 0);
- ALOGV("detach module %p", module.get());
- if (module != 0) {
- ALOGV("detach module->detach()");
- module->detach();
- }
-}
-
-static void
-android_hardware_Radio_finalize(JNIEnv *env, jobject thiz)
-{
- ALOGV("%s", __FUNCTION__);
- sp<Radio> module = getRadio(env, thiz);
- if (module != 0) {
- ALOGW("Radio finalized without being detached");
- }
- android_hardware_Radio_close(env, thiz);
-}
-
-static jint
-android_hardware_Radio_setConfiguration(JNIEnv *env, jobject thiz, jobject jConfig)
-{
- ALOGV("%s", __FUNCTION__);
- sp<Radio> module = getRadio(env, thiz);
- if (module == NULL) {
- return RADIO_STATUS_NO_INIT;
- }
-
- if (!env->IsInstanceOf(jConfig, gRadioFmBandConfigClass) &&
- !env->IsInstanceOf(jConfig, gRadioAmBandConfigClass)) {
- return RADIO_STATUS_BAD_VALUE;
- }
-
- struct radio_band_config nConfig;
- jint jStatus = convertBandConfigToNative(env, &nConfig, jConfig);
- if (jStatus != RADIO_STATUS_OK) {
- return jStatus;
- }
-
- status_t status = module->setConfiguration(&nConfig);
- return (jint)status;
-}
-
-static jint
-android_hardware_Radio_getConfiguration(JNIEnv *env, jobject thiz, jobjectArray jConfigs)
-{
- ALOGV("%s", __FUNCTION__);
- sp<Radio> module = getRadio(env, thiz);
- if (module == NULL) {
- return RADIO_STATUS_NO_INIT;
- }
- if (env->GetArrayLength(jConfigs) != 1) {
- return (jint)RADIO_STATUS_BAD_VALUE;
- }
-
- struct radio_band_config nConfig;
-
- status_t status = module->getConfiguration(&nConfig);
- if (status != NO_ERROR) {
- return (jint)status;
- }
- jobject jConfig;
- int jStatus = convertBandConfigFromNative(env, &jConfig, &nConfig);
- if (jStatus != RADIO_STATUS_OK) {
- return jStatus;
- }
- env->SetObjectArrayElement(jConfigs, 0, jConfig);
- env->DeleteLocalRef(jConfig);
- return RADIO_STATUS_OK;
-}
-
-static jint
-android_hardware_Radio_setMute(JNIEnv *env, jobject thiz, jboolean mute)
-{
- ALOGV("%s", __FUNCTION__);
- sp<Radio> module = getRadio(env, thiz);
- if (module == NULL) {
- return RADIO_STATUS_NO_INIT;
- }
- status_t status = module->setMute((bool)mute);
- return (jint)status;
-}
-
-static jboolean
-android_hardware_Radio_getMute(JNIEnv *env, jobject thiz)
-{
- ALOGV("%s", __FUNCTION__);
- sp<Radio> module = getRadio(env, thiz);
- if (module == NULL) {
- return true;
- }
- bool mute = true;
- status_t status = module->getMute(&mute);
- if (status != NO_ERROR) {
- return true;
- }
- return (jboolean)mute;
-}
-
-static jint
-android_hardware_Radio_step(JNIEnv *env, jobject thiz, jint direction, jboolean skipSubChannel)
-{
- ALOGV("%s", __FUNCTION__);
- sp<Radio> module = getRadio(env, thiz);
- if (module == NULL) {
- return RADIO_STATUS_NO_INIT;
- }
- status_t status = module->step((radio_direction_t)direction, (bool)skipSubChannel);
- return (jint)status;
-}
-
-static jint
-android_hardware_Radio_scan(JNIEnv *env, jobject thiz, jint direction, jboolean skipSubChannel)
-{
- ALOGV("%s", __FUNCTION__);
- sp<Radio> module = getRadio(env, thiz);
- if (module == NULL) {
- return RADIO_STATUS_NO_INIT;
- }
- status_t status = module->scan((radio_direction_t)direction, (bool)skipSubChannel);
- return (jint)status;
-}
-
-static jint
-android_hardware_Radio_tune(JNIEnv *env, jobject thiz, jint channel, jint subChannel)
-{
- ALOGV("%s", __FUNCTION__);
- sp<Radio> module = getRadio(env, thiz);
- if (module == NULL) {
- return RADIO_STATUS_NO_INIT;
- }
- status_t status = module->tune((uint32_t)channel, (uint32_t)subChannel);
- return (jint)status;
-}
-
-static jint
-android_hardware_Radio_cancel(JNIEnv *env, jobject thiz)
-{
- ALOGV("%s", __FUNCTION__);
- sp<Radio> module = getRadio(env, thiz);
- if (module == NULL) {
- return RADIO_STATUS_NO_INIT;
- }
- status_t status = module->cancel();
- return (jint)status;
-}
-
-static jint
-android_hardware_Radio_getProgramInformation(JNIEnv *env, jobject thiz, jobjectArray jInfos)
-{
- ALOGV("%s", __FUNCTION__);
- sp<Radio> module = getRadio(env, thiz);
- if (module == NULL) {
- return RADIO_STATUS_NO_INIT;
- }
- if (env->GetArrayLength(jInfos) != 1) {
- return (jint)RADIO_STATUS_BAD_VALUE;
- }
-
- struct radio_program_info nInfo;
- RadioMetadataWrapper metadataWrapper(&nInfo.metadata);
- jobject jInfo = NULL;
- int jStatus;
-
- jStatus = (int)module->getProgramInformation(&nInfo);
- if (jStatus != RADIO_STATUS_OK) {
- goto exit;
- }
- jStatus = convertProgramInfoFromNative(env, &jInfo, &nInfo);
- if (jStatus != RADIO_STATUS_OK) {
- goto exit;
- }
- env->SetObjectArrayElement(jInfos, 0, jInfo);
-
-exit:
- if (jInfo != NULL) {
- env->DeleteLocalRef(jInfo);
- }
- return jStatus;
-}
-
-static jboolean
-android_hardware_Radio_isAntennaConnected(JNIEnv *env, jobject thiz)
-{
- ALOGV("%s", __FUNCTION__);
- sp<Radio> module = getRadio(env, thiz);
- if (module == NULL) {
- return false;
- }
-
- struct radio_band_config nConfig;
-
- status_t status = module->getConfiguration(&nConfig);
- if (status != NO_ERROR) {
- return false;
- }
-
- return (jboolean)nConfig.band.antenna_connected;
-}
-
-
-static jboolean
-android_hardware_Radio_hasControl(JNIEnv *env, jobject thiz)
-{
- ALOGV("%s", __FUNCTION__);
- sp<Radio> module = getRadio(env, thiz);
- if (module == NULL) {
- return false;
- }
-
- bool hasControl;
- status_t status = module->hasControl(&hasControl);
- if (status != NO_ERROR) {
- return false;
- }
-
- return (jboolean)hasControl;
-}
-
-
-static JNINativeMethod gMethods[] = {
- {"nativeListModules",
- "(Ljava/util/List;)I",
- (void *)android_hardware_Radio_listModules},
-};
-
-static JNINativeMethod gModuleMethods[] = {
- {"native_setup",
- "(Ljava/lang/Object;Landroid/hardware/radio/RadioManager$BandConfig;Z)V",
- (void *)android_hardware_Radio_setup},
- {"native_finalize",
- "()V",
- (void *)android_hardware_Radio_finalize},
- {"close",
- "()V",
- (void *)android_hardware_Radio_close},
- {"setConfiguration",
- "(Landroid/hardware/radio/RadioManager$BandConfig;)I",
- (void *)android_hardware_Radio_setConfiguration},
- {"getConfiguration",
- "([Landroid/hardware/radio/RadioManager$BandConfig;)I",
- (void *)android_hardware_Radio_getConfiguration},
- {"setMute",
- "(Z)I",
- (void *)android_hardware_Radio_setMute},
- {"getMute",
- "()Z",
- (void *)android_hardware_Radio_getMute},
- {"step",
- "(IZ)I",
- (void *)android_hardware_Radio_step},
- {"scan",
- "(IZ)I",
- (void *)android_hardware_Radio_scan},
- {"tune",
- "(II)I",
- (void *)android_hardware_Radio_tune},
- {"cancel",
- "()I",
- (void *)android_hardware_Radio_cancel},
- {"getProgramInformation",
- "([Landroid/hardware/radio/RadioManager$ProgramInfo;)I",
- (void *)android_hardware_Radio_getProgramInformation},
- {"isAntennaConnected",
- "()Z",
- (void *)android_hardware_Radio_isAntennaConnected},
- {"hasControl",
- "()Z",
- (void *)android_hardware_Radio_hasControl},
-};
-
-int register_android_hardware_Radio(JNIEnv *env)
-{
- jclass arrayListClass = FindClassOrDie(env, "java/util/ArrayList");
- gArrayListClass = MakeGlobalRefOrDie(env, arrayListClass);
- gArrayListMethods.add = GetMethodIDOrDie(env, arrayListClass, "add", "(Ljava/lang/Object;)Z");
-
- jclass lClass = FindClassOrDie(env, kRadioManagerClassPathName);
- gRadioManagerClass = MakeGlobalRefOrDie(env, lClass);
-
- jclass moduleClass = FindClassOrDie(env, kRadioModuleClassPathName);
- gRadioModuleClass = MakeGlobalRefOrDie(env, moduleClass);
- gPostEventFromNative = GetStaticMethodIDOrDie(env, moduleClass, "postEventFromNative",
- "(Ljava/lang/Object;IIILjava/lang/Object;)V");
- gModuleFields.mNativeContext = GetFieldIDOrDie(env, moduleClass, "mNativeContext", "J");
- gModuleFields.mId = GetFieldIDOrDie(env, moduleClass, "mId", "I");
-
- jclass modulePropertiesClass = FindClassOrDie(env, kModulePropertiesClassPathName);
- gModulePropertiesClass = MakeGlobalRefOrDie(env, modulePropertiesClass);
- gModulePropertiesCstor = GetMethodIDOrDie(env, modulePropertiesClass, "<init>",
- "(ILjava/lang/String;ILjava/lang/String;Ljava/lang/String;Ljava/lang/String;"
- "Ljava/lang/String;IIZ[Landroid/hardware/radio/RadioManager$BandDescriptor;Z"
- "Ljava/lang/String;)V");
-
- jclass bandDescriptorClass = FindClassOrDie(env, kRadioBandDescriptorClassPathName);
- gRadioBandDescriptorClass = MakeGlobalRefOrDie(env, bandDescriptorClass);
- gRadioBandDescriptorFields.mRegion = GetFieldIDOrDie(env, bandDescriptorClass, "mRegion", "I");
- gRadioBandDescriptorFields.mType = GetFieldIDOrDie(env, bandDescriptorClass, "mType", "I");
- gRadioBandDescriptorFields.mLowerLimit =
- GetFieldIDOrDie(env, bandDescriptorClass, "mLowerLimit", "I");
- gRadioBandDescriptorFields.mUpperLimit =
- GetFieldIDOrDie(env, bandDescriptorClass, "mUpperLimit", "I");
- gRadioBandDescriptorFields.mSpacing =
- GetFieldIDOrDie(env, bandDescriptorClass, "mSpacing", "I");
-
- jclass fmBandDescriptorClass = FindClassOrDie(env, kRadioFmBandDescriptorClassPathName);
- gRadioFmBandDescriptorClass = MakeGlobalRefOrDie(env, fmBandDescriptorClass);
- gRadioFmBandDescriptorCstor = GetMethodIDOrDie(env, fmBandDescriptorClass, "<init>",
- "(IIIIIZZZZZ)V");
-
- jclass amBandDescriptorClass = FindClassOrDie(env, kRadioAmBandDescriptorClassPathName);
- gRadioAmBandDescriptorClass = MakeGlobalRefOrDie(env, amBandDescriptorClass);
- gRadioAmBandDescriptorCstor = GetMethodIDOrDie(env, amBandDescriptorClass, "<init>",
- "(IIIIIZ)V");
-
- jclass bandConfigClass = FindClassOrDie(env, kRadioBandConfigClassPathName);
- gRadioBandConfigClass = MakeGlobalRefOrDie(env, bandConfigClass);
- gRadioBandConfigFields.mDescriptor =
- GetFieldIDOrDie(env, bandConfigClass, "mDescriptor",
- "Landroid/hardware/radio/RadioManager$BandDescriptor;");
-
- jclass fmBandConfigClass = FindClassOrDie(env, kRadioFmBandConfigClassPathName);
- gRadioFmBandConfigClass = MakeGlobalRefOrDie(env, fmBandConfigClass);
- gRadioFmBandConfigCstor = GetMethodIDOrDie(env, fmBandConfigClass, "<init>",
- "(IIIIIZZZZZ)V");
- gRadioFmBandConfigFields.mStereo = GetFieldIDOrDie(env, fmBandConfigClass, "mStereo", "Z");
- gRadioFmBandConfigFields.mRds = GetFieldIDOrDie(env, fmBandConfigClass, "mRds", "Z");
- gRadioFmBandConfigFields.mTa = GetFieldIDOrDie(env, fmBandConfigClass, "mTa", "Z");
- gRadioFmBandConfigFields.mAf = GetFieldIDOrDie(env, fmBandConfigClass, "mAf", "Z");
- gRadioFmBandConfigFields.mEa =
- GetFieldIDOrDie(env, fmBandConfigClass, "mEa", "Z");
-
-
- jclass amBandConfigClass = FindClassOrDie(env, kRadioAmBandConfigClassPathName);
- gRadioAmBandConfigClass = MakeGlobalRefOrDie(env, amBandConfigClass);
- gRadioAmBandConfigCstor = GetMethodIDOrDie(env, amBandConfigClass, "<init>",
- "(IIIIIZ)V");
- gRadioAmBandConfigFields.mStereo = GetFieldIDOrDie(env, amBandConfigClass, "mStereo", "Z");
-
- jclass programInfoClass = FindClassOrDie(env, kRadioProgramInfoClassPathName);
- gRadioProgramInfoClass = MakeGlobalRefOrDie(env, programInfoClass);
- gRadioProgramInfoCstor = GetMethodIDOrDie(env, programInfoClass, "<init>",
- "(IIZZZILandroid/hardware/radio/RadioMetadata;ILjava/lang/String;)V");
-
- jclass metadataClass = FindClassOrDie(env, kRadioMetadataClassPathName);
- gRadioMetadataClass = MakeGlobalRefOrDie(env, metadataClass);
- gRadioMetadataCstor = GetMethodIDOrDie(env, metadataClass, "<init>", "()V");
- gRadioMetadataMethods.putIntFromNative = GetMethodIDOrDie(env, metadataClass,
- "putIntFromNative",
- "(II)I");
- gRadioMetadataMethods.putStringFromNative = GetMethodIDOrDie(env, metadataClass,
- "putStringFromNative",
- "(ILjava/lang/String;)I");
- gRadioMetadataMethods.putBitmapFromNative = GetMethodIDOrDie(env, metadataClass,
- "putBitmapFromNative",
- "(I[B)I");
- gRadioMetadataMethods.putClockFromNative = GetMethodIDOrDie(env, metadataClass,
- "putClockFromNative",
- "(IJI)I");
-
-
- RegisterMethodsOrDie(env, kRadioManagerClassPathName, gMethods, NELEM(gMethods));
-
- int ret = RegisterMethodsOrDie(env, kRadioModuleClassPathName, gModuleMethods, NELEM(gModuleMethods));
-
- ALOGV("%s DONE", __FUNCTION__);
-
- return ret;
-}
diff --git a/core/res/res/layout-land/time_picker_material.xml b/core/res/res/layout-land/time_picker_material.xml
index 863efef5c661..d83ccb23f64f 100644
--- a/core/res/res/layout-land/time_picker_material.xml
+++ b/core/res/res/layout-land/time_picker_material.xml
@@ -17,6 +17,7 @@
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layoutDirection="ltr"
android:layout_width="match_parent"
android:layout_height="wrap_content">
@@ -30,6 +31,7 @@
<LinearLayout
android:id="@+id/time_layout"
+ android:layoutDirection="ltr"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:paddingTop="@dimen/timepicker_radial_picker_top_margin"
diff --git a/graphics/java/android/graphics/ColorFilter.java b/graphics/java/android/graphics/ColorFilter.java
index 0ca3729dcc0e..b24b9885d1b0 100644
--- a/graphics/java/android/graphics/ColorFilter.java
+++ b/graphics/java/android/graphics/ColorFilter.java
@@ -14,19 +14,22 @@
* limitations under the License.
*/
-// This file was generated from the C++ include file: SkColorFilter.h
-// Any changes made to this file will be discarded by the build.
-// To change this file, either edit the include, or device/tools/gluemaker/main.cpp,
-// or one of the auxilary file specifications in device/tools/gluemaker.
-
package android.graphics;
+import libcore.util.NativeAllocationRegistry;
+
/**
* A color filter can be used with a {@link Paint} to modify the color of
* each pixel drawn with that paint. This is an abstract class that should
* never be used directly.
*/
public class ColorFilter {
+
+ private static class NoImagePreloadHolder {
+ public static final NativeAllocationRegistry sRegistry = new NativeAllocationRegistry(
+ ColorFilter.class.getClassLoader(), nativeGetFinalizer(), 50);
+ }
+
/**
* @deprecated Use subclass constructors directly instead.
*/
@@ -34,9 +37,11 @@ public class ColorFilter {
public ColorFilter() {}
/**
- * Holds the pointer to the native SkColorFilter instance.
+ * Current native SkColorFilter instance.
*/
private long mNativeInstance;
+ // Runnable to do immediate destruction
+ private Runnable mCleaner;
long createNativeInstance() {
return 0;
@@ -44,35 +49,28 @@ public class ColorFilter {
void discardNativeInstance() {
if (mNativeInstance != 0) {
- nSafeUnref(mNativeInstance);
+ mCleaner.run();
+ mCleaner = null;
mNativeInstance = 0;
}
}
- @Override
- protected void finalize() throws Throwable {
- try {
- if (mNativeInstance != 0) {
- nSafeUnref(mNativeInstance);
- }
- mNativeInstance = -1;
- } finally {
- super.finalize();
- }
- }
-
/** @hide */
public long getNativeInstance() {
- if (mNativeInstance == -1) {
- throw new IllegalStateException("attempting to use a finalized ColorFilter");
- }
-
if (mNativeInstance == 0) {
mNativeInstance = createNativeInstance();
+
+ if (mNativeInstance != 0) {
+ // Note: we must check for null here, since it's possible for createNativeInstance()
+ // to return nullptr if the native SkColorFilter would be a no-op at draw time.
+ // See native implementations of subclass create methods for more info.
+ mCleaner = NoImagePreloadHolder.sRegistry.registerNativeAllocation(
+ this, mNativeInstance);
+ }
}
return mNativeInstance;
}
- static native void nSafeUnref(long native_instance);
+ private static native long nativeGetFinalizer();
}
diff --git a/libs/androidfw/ResourceTypes.cpp b/libs/androidfw/ResourceTypes.cpp
index bab8883ef64f..0782269d7de1 100644
--- a/libs/androidfw/ResourceTypes.cpp
+++ b/libs/androidfw/ResourceTypes.cpp
@@ -3313,13 +3313,14 @@ struct ResTable::PackageGroup
clearBagCache();
const size_t numTypes = types.size();
for (size_t i = 0; i < numTypes; i++) {
- const TypeList& typeList = types[i];
+ TypeList& typeList = types.editItemAt(i);
const size_t numInnerTypes = typeList.size();
for (size_t j = 0; j < numInnerTypes; j++) {
if (typeList[j]->package->owner == owner) {
delete typeList[j];
}
}
+ typeList.clear();
}
const size_t N = packages.size();
diff --git a/libs/hwui/tests/unit/SkiaBehaviorTests.cpp b/libs/hwui/tests/unit/SkiaBehaviorTests.cpp
index a3d5079c6ce9..85b12ba79a8c 100644
--- a/libs/hwui/tests/unit/SkiaBehaviorTests.cpp
+++ b/libs/hwui/tests/unit/SkiaBehaviorTests.cpp
@@ -51,8 +51,6 @@ TEST(SkiaBehavior, CreateBitmapShader1x1) {
SkShader::TileMode xy[2];
ASSERT_TRUE(s->isABitmap(&bitmap, nullptr, xy))
<< "1x1 bitmap shader must query as bitmap shader";
- EXPECT_EQ(SkShader::kClamp_TileMode, xy[0]);
- EXPECT_EQ(SkShader::kRepeat_TileMode, xy[1]);
EXPECT_EQ(origBitmap.pixelRef(), bitmap.pixelRef());
}
diff --git a/media/jni/soundpool/SoundPoolThread.cpp b/media/jni/soundpool/SoundPoolThread.cpp
index 3d988773ff04..ba3b482935dd 100644
--- a/media/jni/soundpool/SoundPoolThread.cpp
+++ b/media/jni/soundpool/SoundPoolThread.cpp
@@ -20,8 +20,6 @@
#include "SoundPoolThread.h"
-static const int kMaxWorkers = 3;
-
namespace android {
void SoundPoolThread::write(SoundPoolMsg msg) {
@@ -33,21 +31,14 @@ void SoundPoolThread::write(SoundPoolMsg msg) {
// if thread is quitting, don't add to queue
if (mRunning) {
mMsgQueue.push(msg);
- if (mNumWorkers < kMaxWorkers) {
- if (createThreadEtc(beginThread, this, "SoundPoolThread")) {
- mNumWorkers++;
- ALOGV("created worker thread");
- }
- }
+ mCondition.signal();
}
}
const SoundPoolMsg SoundPoolThread::read() {
Mutex::Autolock lock(&mLock);
- if (mMsgQueue.size() == 0) {
- mNumWorkers--;
- mCondition.signal();
- return SoundPoolMsg(SoundPoolMsg::KILL, 0);
+ while (mMsgQueue.size() == 0) {
+ mCondition.wait(mLock);
}
SoundPoolMsg msg = mMsgQueue[0];
mMsgQueue.removeAt(0);
@@ -60,20 +51,20 @@ void SoundPoolThread::quit() {
if (mRunning) {
mRunning = false;
mMsgQueue.clear();
- mCondition.broadcast(); // wake up any blocked writers
- while (mNumWorkers > 0) {
- mCondition.wait(mLock);
- }
+ mMsgQueue.push(SoundPoolMsg(SoundPoolMsg::KILL, 0));
+ mCondition.signal();
+ mCondition.wait(mLock);
}
ALOGV("return from quit");
}
SoundPoolThread::SoundPoolThread(SoundPool* soundPool) :
- mSoundPool(soundPool),
- mNumWorkers(0),
- mRunning(true)
+ mSoundPool(soundPool)
{
mMsgQueue.setCapacity(maxMessages);
+ if (createThreadEtc(beginThread, this, "SoundPoolThread")) {
+ mRunning = true;
+ }
}
SoundPoolThread::~SoundPoolThread()
diff --git a/media/jni/soundpool/SoundPoolThread.h b/media/jni/soundpool/SoundPoolThread.h
index 5d7bf0c07803..7b3e1dda0a23 100644
--- a/media/jni/soundpool/SoundPoolThread.h
+++ b/media/jni/soundpool/SoundPoolThread.h
@@ -58,7 +58,6 @@ private:
Condition mCondition;
Vector<SoundPoolMsg> mMsgQueue;
SoundPool* mSoundPool;
- int32_t mNumWorkers;
bool mRunning;
};
diff --git a/packages/MtpDocumentsProvider/res/values-af/strings.xml b/packages/MtpDocumentsProvider/res/values-af/strings.xml
new file mode 100644
index 000000000000..c2c8761146f3
--- /dev/null
+++ b/packages/MtpDocumentsProvider/res/values-af/strings.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2015 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="app_label" msgid="6271216747302322594">"MTP-gasheer"</string>
+ <string name="downloads_app_label" msgid="7120690641874849726">"Aflaaie"</string>
+ <string name="root_name" msgid="5819495383921089536">"<xliff:g id="DEVICE_MODEL">%1$s</xliff:g> <xliff:g id="STORAGE_NAME">%2$s</xliff:g>"</string>
+ <string name="accessing_notification_title" msgid="3030133609230917944">"Toegang tot lêers word tans van <xliff:g id="DEVICE_MODEL">%1$s</xliff:g> af verkry"</string>
+ <string name="error_busy_device" msgid="3997316850357386589">"Die ander toestel is besig. Jy kan nie lêers oordra voordat dit beskikbaar is nie."</string>
+ <string name="error_locked_device" msgid="7557872102188356147">"Geen lêers is gevind nie. Die ander toestel is dalk gesluit. Indien wel, ontsluit dit en probeer weer."</string>
+</resources>
diff --git a/packages/MtpDocumentsProvider/res/values-am/strings.xml b/packages/MtpDocumentsProvider/res/values-am/strings.xml
new file mode 100644
index 000000000000..7b721c86cec0
--- /dev/null
+++ b/packages/MtpDocumentsProvider/res/values-am/strings.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2015 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="app_label" msgid="6271216747302322594">"የMTP አስተናጋጅ"</string>
+ <string name="downloads_app_label" msgid="7120690641874849726">"የወረዱ"</string>
+ <string name="root_name" msgid="5819495383921089536">"<xliff:g id="DEVICE_MODEL">%1$s</xliff:g> <xliff:g id="STORAGE_NAME">%2$s</xliff:g>"</string>
+ <string name="accessing_notification_title" msgid="3030133609230917944">"ፋይሎችን ከ<xliff:g id="DEVICE_MODEL">%1$s</xliff:g> በመድረስ ላይ"</string>
+ <string name="error_busy_device" msgid="3997316850357386589">"ሌላኛው መሣሪያ ሥራ በዝቶበታል። እስከሚገኝ ድረስ ፋይሎችን ማስተላለፍ አይችሉም።"</string>
+ <string name="error_locked_device" msgid="7557872102188356147">"ምንም ፋይሎች አልተገኙም። ሌላኛው መሣሪያ ተቆልፎ ሊሆን ይችላል። ተቆልፎ ከሆነ ይክፈቱት እና እንደገና ይሞክሩ።"</string>
+</resources>
diff --git a/packages/MtpDocumentsProvider/res/values-ar/strings.xml b/packages/MtpDocumentsProvider/res/values-ar/strings.xml
new file mode 100644
index 000000000000..284a8602ce6a
--- /dev/null
+++ b/packages/MtpDocumentsProvider/res/values-ar/strings.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2015 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="app_label" msgid="6271216747302322594">"‏مضيف بروتوكول نقل الوسائط (MTP)"</string>
+ <string name="downloads_app_label" msgid="7120690641874849726">"التنزيلات"</string>
+ <string name="root_name" msgid="5819495383921089536">"<xliff:g id="DEVICE_MODEL">%1$s</xliff:g> <xliff:g id="STORAGE_NAME">%2$s</xliff:g>"</string>
+ <string name="accessing_notification_title" msgid="3030133609230917944">"جارٍ الوصول إلى الملفات من <xliff:g id="DEVICE_MODEL">%1$s</xliff:g>"</string>
+ <string name="error_busy_device" msgid="3997316850357386589">"الجهاز الآخر مشغول، ولا يمكنك نقل الملفات إلا بعد أن يصبح متاحًا."</string>
+ <string name="error_locked_device" msgid="7557872102188356147">"لم يتم العثور على ملفات، وربما يكون الجهاز الآخر في وضع القفل. إذا كان الأمر كذلك، فعليك إلغاء قفله وإعادة المحاولة."</string>
+</resources>
diff --git a/packages/MtpDocumentsProvider/res/values-az/strings.xml b/packages/MtpDocumentsProvider/res/values-az/strings.xml
new file mode 100644
index 000000000000..e8ed1242f13c
--- /dev/null
+++ b/packages/MtpDocumentsProvider/res/values-az/strings.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2015 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="app_label" msgid="6271216747302322594">"MTP Host"</string>
+ <string name="downloads_app_label" msgid="7120690641874849726">"Endirmələr"</string>
+ <string name="root_name" msgid="5819495383921089536">"<xliff:g id="DEVICE_MODEL">%1$s</xliff:g> <xliff:g id="STORAGE_NAME">%2$s</xliff:g>"</string>
+ <string name="accessing_notification_title" msgid="3030133609230917944">"Fayllara <xliff:g id="DEVICE_MODEL">%1$s</xliff:g> cihazından daxil olunur"</string>
+ <string name="error_busy_device" msgid="3997316850357386589">"Digər cihaz məşğuldur. Əlçatan olmayana kimi fayl köçürə bilməzsiniz."</string>
+ <string name="error_locked_device" msgid="7557872102188356147">"Fayl tapılmadı. Digər cihaz kilidlənmiş ola bilər. Elədirsə, kiliddən çıxarın və yenidən cəhd edin."</string>
+</resources>
diff --git a/packages/MtpDocumentsProvider/res/values-b+sr+Latn/strings.xml b/packages/MtpDocumentsProvider/res/values-b+sr+Latn/strings.xml
new file mode 100644
index 000000000000..bc9009969a16
--- /dev/null
+++ b/packages/MtpDocumentsProvider/res/values-b+sr+Latn/strings.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2015 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="app_label" msgid="6271216747302322594">"MTP host"</string>
+ <string name="downloads_app_label" msgid="7120690641874849726">"Preuzimanja"</string>
+ <string name="root_name" msgid="5819495383921089536">"<xliff:g id="DEVICE_MODEL">%1$s</xliff:g> <xliff:g id="STORAGE_NAME">%2$s</xliff:g>"</string>
+ <string name="accessing_notification_title" msgid="3030133609230917944">"Pristup datotekama sa uređaja <xliff:g id="DEVICE_MODEL">%1$s</xliff:g>"</string>
+ <string name="error_busy_device" msgid="3997316850357386589">"Drugi uređaj je zauzet. Datoteke možete da prenesete tek kad on postane dostupan."</string>
+ <string name="error_locked_device" msgid="7557872102188356147">"Nije pronađena nijedna datoteka. Drugi uređaj je možda zaključan. Ako jeste, otključajte ga i pokušajte ponovo."</string>
+</resources>
diff --git a/packages/MtpDocumentsProvider/res/values-be/strings.xml b/packages/MtpDocumentsProvider/res/values-be/strings.xml
new file mode 100644
index 000000000000..f6263acb0150
--- /dev/null
+++ b/packages/MtpDocumentsProvider/res/values-be/strings.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2015 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="app_label" msgid="6271216747302322594">"Вузел MTP"</string>
+ <string name="downloads_app_label" msgid="7120690641874849726">"Спампоўкі"</string>
+ <string name="root_name" msgid="5819495383921089536">"<xliff:g id="DEVICE_MODEL">%1$s</xliff:g> <xliff:g id="STORAGE_NAME">%2$s</xliff:g>"</string>
+ <string name="accessing_notification_title" msgid="3030133609230917944">"Доступ да файлаў з <xliff:g id="DEVICE_MODEL">%1$s</xliff:g>"</string>
+ <string name="error_busy_device" msgid="3997316850357386589">"Іншая прылада занята. Вы не можаце перадаць файлы, пакуль яна не стане даступнай."</string>
+ <string name="error_locked_device" msgid="7557872102188356147">"Файлы не знойдзены. Іншая прылада можа быць заблакіравана. Калі гэта так, разблакіруйце яе і паўтарыце спробу."</string>
+</resources>
diff --git a/packages/MtpDocumentsProvider/res/values-bg/strings.xml b/packages/MtpDocumentsProvider/res/values-bg/strings.xml
new file mode 100644
index 000000000000..52d311971fc1
--- /dev/null
+++ b/packages/MtpDocumentsProvider/res/values-bg/strings.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2015 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="app_label" msgid="6271216747302322594">"MTP хост"</string>
+ <string name="downloads_app_label" msgid="7120690641874849726">"Изтегляния"</string>
+ <string name="root_name" msgid="5819495383921089536">"<xliff:g id="STORAGE_NAME">%2$s</xliff:g> на <xliff:g id="DEVICE_MODEL">%1$s</xliff:g>"</string>
+ <string name="accessing_notification_title" msgid="3030133609230917944">"От <xliff:g id="DEVICE_MODEL">%1$s</xliff:g> се осъществява достъп до файловете"</string>
+ <string name="error_busy_device" msgid="3997316850357386589">"Другото устройство е заето. Не можете да прехвърляте файлове, докато то не се освободи."</string>
+ <string name="error_locked_device" msgid="7557872102188356147">"Няма намерени файлове. Другото устройство може да е заключено. Ако е така, отключете го и опитайте отново."</string>
+</resources>
diff --git a/packages/MtpDocumentsProvider/res/values-bn/strings.xml b/packages/MtpDocumentsProvider/res/values-bn/strings.xml
new file mode 100644
index 000000000000..7fad89e89d60
--- /dev/null
+++ b/packages/MtpDocumentsProvider/res/values-bn/strings.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2015 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="app_label" msgid="6271216747302322594">"MTP হোস্ট"</string>
+ <string name="downloads_app_label" msgid="7120690641874849726">"ডাউনলোডগুলি"</string>
+ <string name="root_name" msgid="5819495383921089536">"<xliff:g id="DEVICE_MODEL">%1$s</xliff:g> <xliff:g id="STORAGE_NAME">%2$s</xliff:g>"</string>
+ <string name="accessing_notification_title" msgid="3030133609230917944">"<xliff:g id="DEVICE_MODEL">%1$s</xliff:g> থেকে ফাইলগুলিকে অ্যাক্সেস করা হচ্ছে"</string>
+ <string name="error_busy_device" msgid="3997316850357386589">"অন্য ডিভাইসটি ব্যস্ত আছে৷ এটি উপলব্ধ না হওয়া পর্যন্ত আপনি ফাইলগুলিকে স্থানান্তর করতে পারবেন না৷"</string>
+ <string name="error_locked_device" msgid="7557872102188356147">"কোনো ফাইল পাওয়া যায়নি৷ অন্য ডিভাইসটি লক থাকতে পারে৷ যদি তাই হয়, তাহলে এটিকে আনলক করে আবার চেষ্টা করুন৷"</string>
+</resources>
diff --git a/packages/MtpDocumentsProvider/res/values-bs/strings.xml b/packages/MtpDocumentsProvider/res/values-bs/strings.xml
new file mode 100644
index 000000000000..33323f81f81a
--- /dev/null
+++ b/packages/MtpDocumentsProvider/res/values-bs/strings.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2015 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="app_label" msgid="6271216747302322594">"MTP Host"</string>
+ <string name="downloads_app_label" msgid="7120690641874849726">"Preuzimanja"</string>
+ <string name="root_name" msgid="5819495383921089536">"<xliff:g id="DEVICE_MODEL">%1$s</xliff:g> <xliff:g id="STORAGE_NAME">%2$s</xliff:g>"</string>
+ <string name="accessing_notification_title" msgid="3030133609230917944">"Pristupanje datotekama iz uređaja <xliff:g id="DEVICE_MODEL">%1$s</xliff:g>"</string>
+ <string name="error_busy_device" msgid="3997316850357386589">"Drugi uređaj je zauzet. Nećete moći prenositi fajlove dok ne bude dostupan."</string>
+ <string name="error_locked_device" msgid="7557872102188356147">"Fajlovi nisu pronađeni. Moguće je da je drugi uređaj zaključan. Ako jeste, otključajte ga i pokušajte ponovo."</string>
+</resources>
diff --git a/packages/MtpDocumentsProvider/res/values-ca/strings.xml b/packages/MtpDocumentsProvider/res/values-ca/strings.xml
new file mode 100644
index 000000000000..b2aa59966ac4
--- /dev/null
+++ b/packages/MtpDocumentsProvider/res/values-ca/strings.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2015 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="app_label" msgid="6271216747302322594">"Amfitrió MTP"</string>
+ <string name="downloads_app_label" msgid="7120690641874849726">"Baixades"</string>
+ <string name="root_name" msgid="5819495383921089536">"<xliff:g id="STORAGE_NAME">%2$s</xliff:g> de <xliff:g id="DEVICE_MODEL">%1$s</xliff:g>"</string>
+ <string name="accessing_notification_title" msgid="3030133609230917944">"S\'està accedint als fitxers del dispositiu <xliff:g id="DEVICE_MODEL">%1$s</xliff:g>"</string>
+ <string name="error_busy_device" msgid="3997316850357386589">"L\'altre dispositiu està ocupat. No pots transferir fitxers fins que estigui disponible."</string>
+ <string name="error_locked_device" msgid="7557872102188356147">"No s\'han trobat fitxers. És possible que l\'altre dispositiu estigui bloquejat. Si és així, desbloqueja\'l i torna-ho a provar."</string>
+</resources>
diff --git a/packages/MtpDocumentsProvider/res/values-cs/strings.xml b/packages/MtpDocumentsProvider/res/values-cs/strings.xml
new file mode 100644
index 000000000000..2156e8c52f7e
--- /dev/null
+++ b/packages/MtpDocumentsProvider/res/values-cs/strings.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2015 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="app_label" msgid="6271216747302322594">"Hostitel MTP"</string>
+ <string name="downloads_app_label" msgid="7120690641874849726">"Stahování"</string>
+ <string name="root_name" msgid="5819495383921089536">"<xliff:g id="DEVICE_MODEL">%1$s</xliff:g> – <xliff:g id="STORAGE_NAME">%2$s</xliff:g>"</string>
+ <string name="accessing_notification_title" msgid="3030133609230917944">"Používání souborů ze zařízení <xliff:g id="DEVICE_MODEL">%1$s</xliff:g>"</string>
+ <string name="error_busy_device" msgid="3997316850357386589">"Druhé zařízení je zaneprázdněné. Dokud nebude dostupné, soubory nelze přenést."</string>
+ <string name="error_locked_device" msgid="7557872102188356147">"Nebyly nalezeny žádné soubory. Druhé zařízení je možná uzamčené. Pokud ano, odemkněte jej a zkuste to znovu."</string>
+</resources>
diff --git a/packages/MtpDocumentsProvider/res/values-da/strings.xml b/packages/MtpDocumentsProvider/res/values-da/strings.xml
new file mode 100644
index 000000000000..b82c5e8b0af8
--- /dev/null
+++ b/packages/MtpDocumentsProvider/res/values-da/strings.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2015 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="app_label" msgid="6271216747302322594">"MTP-host"</string>
+ <string name="downloads_app_label" msgid="7120690641874849726">"Downloads"</string>
+ <string name="root_name" msgid="5819495383921089536">"<xliff:g id="DEVICE_MODEL">%1$s</xliff:g> <xliff:g id="STORAGE_NAME">%2$s</xliff:g>"</string>
+ <string name="accessing_notification_title" msgid="3030133609230917944">"Adgang til filer fra <xliff:g id="DEVICE_MODEL">%1$s</xliff:g>"</string>
+ <string name="error_busy_device" msgid="3997316850357386589">"Den anden enhed er optaget. Du kan ikke overføre filer, før den er tilgængelig."</string>
+ <string name="error_locked_device" msgid="7557872102188356147">"Der blev ikke fundet nogen filer. Den anden enhed er muligvis låst. Hvis dette er tilfældet, skal du låse den op og prøve igen."</string>
+</resources>
diff --git a/packages/MtpDocumentsProvider/res/values-de/strings.xml b/packages/MtpDocumentsProvider/res/values-de/strings.xml
new file mode 100644
index 000000000000..9a71c769aaed
--- /dev/null
+++ b/packages/MtpDocumentsProvider/res/values-de/strings.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2015 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="app_label" msgid="6271216747302322594">"MTP-Host"</string>
+ <string name="downloads_app_label" msgid="7120690641874849726">"Downloads"</string>
+ <string name="root_name" msgid="5819495383921089536">"<xliff:g id="STORAGE_NAME">%2$s</xliff:g> von <xliff:g id="DEVICE_MODEL">%1$s</xliff:g>"</string>
+ <string name="accessing_notification_title" msgid="3030133609230917944">"Zugriff auf Dateien von <xliff:g id="DEVICE_MODEL">%1$s</xliff:g>"</string>
+ <string name="error_busy_device" msgid="3997316850357386589">"Das andere Gerät ist nicht verfügbar. Du kannst die Dateien übertragen, sobald das Gerät wieder verfügbar ist."</string>
+ <string name="error_locked_device" msgid="7557872102188356147">"Keine Dateien gefunden. Das andere Gerät ist möglicherweise gesperrt. Entsperre es in diesem Fall und versuche es noch einmal."</string>
+</resources>
diff --git a/packages/MtpDocumentsProvider/res/values-el/strings.xml b/packages/MtpDocumentsProvider/res/values-el/strings.xml
new file mode 100644
index 000000000000..562d2952988a
--- /dev/null
+++ b/packages/MtpDocumentsProvider/res/values-el/strings.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2015 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="app_label" msgid="6271216747302322594">"Κεντρικός υπολογιστής MTP"</string>
+ <string name="downloads_app_label" msgid="7120690641874849726">"Λήψεις"</string>
+ <string name="root_name" msgid="5819495383921089536">"<xliff:g id="DEVICE_MODEL">%1$s</xliff:g> <xliff:g id="STORAGE_NAME">%2$s</xliff:g>"</string>
+ <string name="accessing_notification_title" msgid="3030133609230917944">"Πρόσβαση στα αρχεία από τη συσκευή <xliff:g id="DEVICE_MODEL">%1$s</xliff:g>"</string>
+ <string name="error_busy_device" msgid="3997316850357386589">"Η άλλη συσκευή είναι απασχολημένη. Δεν μπορείτε να μεταφέρετε αρχεία μέχρι να γίνει διαθέσιμη."</string>
+ <string name="error_locked_device" msgid="7557872102188356147">"Δεν βρέθηκαν αρχεία. Η άλλη συσκευή ενδέχεται να είναι κλειδωμένη. Εάν ισχύει αυτό, ξεκλειδώστε την και δοκιμάστε ξανά."</string>
+</resources>
diff --git a/packages/MtpDocumentsProvider/res/values-en-rAU/strings.xml b/packages/MtpDocumentsProvider/res/values-en-rAU/strings.xml
new file mode 100644
index 000000000000..5f2167e8273a
--- /dev/null
+++ b/packages/MtpDocumentsProvider/res/values-en-rAU/strings.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2015 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="app_label" msgid="6271216747302322594">"MTP Host"</string>
+ <string name="downloads_app_label" msgid="7120690641874849726">"Downloads"</string>
+ <string name="root_name" msgid="5819495383921089536">"<xliff:g id="DEVICE_MODEL">%1$s</xliff:g> <xliff:g id="STORAGE_NAME">%2$s</xliff:g>"</string>
+ <string name="accessing_notification_title" msgid="3030133609230917944">"Accessing files from <xliff:g id="DEVICE_MODEL">%1$s</xliff:g>"</string>
+ <string name="error_busy_device" msgid="3997316850357386589">"The other device is busy. You can\'t transfer files until it\'s available."</string>
+ <string name="error_locked_device" msgid="7557872102188356147">"No files found. The other device may be locked. If so, unlock it and try again."</string>
+</resources>
diff --git a/packages/MtpDocumentsProvider/res/values-en-rGB/strings.xml b/packages/MtpDocumentsProvider/res/values-en-rGB/strings.xml
new file mode 100644
index 000000000000..5f2167e8273a
--- /dev/null
+++ b/packages/MtpDocumentsProvider/res/values-en-rGB/strings.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2015 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="app_label" msgid="6271216747302322594">"MTP Host"</string>
+ <string name="downloads_app_label" msgid="7120690641874849726">"Downloads"</string>
+ <string name="root_name" msgid="5819495383921089536">"<xliff:g id="DEVICE_MODEL">%1$s</xliff:g> <xliff:g id="STORAGE_NAME">%2$s</xliff:g>"</string>
+ <string name="accessing_notification_title" msgid="3030133609230917944">"Accessing files from <xliff:g id="DEVICE_MODEL">%1$s</xliff:g>"</string>
+ <string name="error_busy_device" msgid="3997316850357386589">"The other device is busy. You can\'t transfer files until it\'s available."</string>
+ <string name="error_locked_device" msgid="7557872102188356147">"No files found. The other device may be locked. If so, unlock it and try again."</string>
+</resources>
diff --git a/packages/MtpDocumentsProvider/res/values-en-rIN/strings.xml b/packages/MtpDocumentsProvider/res/values-en-rIN/strings.xml
new file mode 100644
index 000000000000..5f2167e8273a
--- /dev/null
+++ b/packages/MtpDocumentsProvider/res/values-en-rIN/strings.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2015 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="app_label" msgid="6271216747302322594">"MTP Host"</string>
+ <string name="downloads_app_label" msgid="7120690641874849726">"Downloads"</string>
+ <string name="root_name" msgid="5819495383921089536">"<xliff:g id="DEVICE_MODEL">%1$s</xliff:g> <xliff:g id="STORAGE_NAME">%2$s</xliff:g>"</string>
+ <string name="accessing_notification_title" msgid="3030133609230917944">"Accessing files from <xliff:g id="DEVICE_MODEL">%1$s</xliff:g>"</string>
+ <string name="error_busy_device" msgid="3997316850357386589">"The other device is busy. You can\'t transfer files until it\'s available."</string>
+ <string name="error_locked_device" msgid="7557872102188356147">"No files found. The other device may be locked. If so, unlock it and try again."</string>
+</resources>
diff --git a/packages/MtpDocumentsProvider/res/values-es-rUS/strings.xml b/packages/MtpDocumentsProvider/res/values-es-rUS/strings.xml
new file mode 100644
index 000000000000..740d224d7136
--- /dev/null
+++ b/packages/MtpDocumentsProvider/res/values-es-rUS/strings.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2015 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="app_label" msgid="6271216747302322594">"Host MTP"</string>
+ <string name="downloads_app_label" msgid="7120690641874849726">"Descargas"</string>
+ <string name="root_name" msgid="5819495383921089536">"<xliff:g id="DEVICE_MODEL">%1$s</xliff:g> <xliff:g id="STORAGE_NAME">%2$s</xliff:g>"</string>
+ <string name="accessing_notification_title" msgid="3030133609230917944">"Accediendo a los archivos de <xliff:g id="DEVICE_MODEL">%1$s</xliff:g>"</string>
+ <string name="error_busy_device" msgid="3997316850357386589">"El otro dispositivo está ocupado. No podrás transferir archivos hasta que esté disponible."</string>
+ <string name="error_locked_device" msgid="7557872102188356147">"No se encontraron archivos. Es posible que el otro dispositivo esté bloqueado. Si es así, desbloquéalo y vuelve a intentarlo."</string>
+</resources>
diff --git a/packages/MtpDocumentsProvider/res/values-es/strings.xml b/packages/MtpDocumentsProvider/res/values-es/strings.xml
new file mode 100644
index 000000000000..d80a75ac07f7
--- /dev/null
+++ b/packages/MtpDocumentsProvider/res/values-es/strings.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2015 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="app_label" msgid="6271216747302322594">"Host de MTP"</string>
+ <string name="downloads_app_label" msgid="7120690641874849726">"Descargas"</string>
+ <string name="root_name" msgid="5819495383921089536">"<xliff:g id="STORAGE_NAME">%2$s</xliff:g> de <xliff:g id="DEVICE_MODEL">%1$s</xliff:g>"</string>
+ <string name="accessing_notification_title" msgid="3030133609230917944">"Accediendo a los archivos desde <xliff:g id="DEVICE_MODEL">%1$s</xliff:g>"</string>
+ <string name="error_busy_device" msgid="3997316850357386589">"El otro dispositivo está ocupado. No se pueden transferir archivos hasta que esté disponible."</string>
+ <string name="error_locked_device" msgid="7557872102188356147">"No se ha encontrado ningún archivo. Es posible que el otro dispositivo esté bloqueado. Si es así, desbloquéalo y vuelve a intentarlo."</string>
+</resources>
diff --git a/packages/MtpDocumentsProvider/res/values-et/strings.xml b/packages/MtpDocumentsProvider/res/values-et/strings.xml
new file mode 100644
index 000000000000..7568777e15f7
--- /dev/null
+++ b/packages/MtpDocumentsProvider/res/values-et/strings.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2015 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="app_label" msgid="6271216747302322594">"MTP host"</string>
+ <string name="downloads_app_label" msgid="7120690641874849726">"Allalaadimised"</string>
+ <string name="root_name" msgid="5819495383921089536">"<xliff:g id="DEVICE_MODEL">%1$s</xliff:g>, <xliff:g id="STORAGE_NAME">%2$s</xliff:g>"</string>
+ <string name="accessing_notification_title" msgid="3030133609230917944">"Juurdepääsemine failidele seadmest <xliff:g id="DEVICE_MODEL">%1$s</xliff:g>"</string>
+ <string name="error_busy_device" msgid="3997316850357386589">"Teine seade on hõivatud. Te ei saa faile üle viia enne, kui see seade on saadaval."</string>
+ <string name="error_locked_device" msgid="7557872102188356147">"Faile ei leitud. Teine seade võib olla lukustatud. Kui see on nii, avage see ja proovige uuesti."</string>
+</resources>
diff --git a/packages/MtpDocumentsProvider/res/values-eu/strings.xml b/packages/MtpDocumentsProvider/res/values-eu/strings.xml
new file mode 100644
index 000000000000..dc9d463b98eb
--- /dev/null
+++ b/packages/MtpDocumentsProvider/res/values-eu/strings.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2015 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="app_label" msgid="6271216747302322594">"MTP ostalaria"</string>
+ <string name="downloads_app_label" msgid="7120690641874849726">"Deskargak"</string>
+ <string name="root_name" msgid="5819495383921089536">"<xliff:g id="DEVICE_MODEL">%1$s</xliff:g> <xliff:g id="STORAGE_NAME">%2$s</xliff:g>"</string>
+ <string name="accessing_notification_title" msgid="3030133609230917944">"<xliff:g id="DEVICE_MODEL">%1$s</xliff:g> gailuko fitxategiak atzitzen"</string>
+ <string name="error_busy_device" msgid="3997316850357386589">"Beste gailua lanpetuta dago. Erabilgarri egon arte ezingo duzu transferitu fitxategirik."</string>
+ <string name="error_locked_device" msgid="7557872102188356147">"Ez da aurkitu fitxategirik. Baliteke beste gailua blokeatuta egotea. Hala bada, desblokea ezazu eta saiatu berriro."</string>
+</resources>
diff --git a/packages/MtpDocumentsProvider/res/values-fa/strings.xml b/packages/MtpDocumentsProvider/res/values-fa/strings.xml
new file mode 100644
index 000000000000..9ac58c7ad3f1
--- /dev/null
+++ b/packages/MtpDocumentsProvider/res/values-fa/strings.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2015 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="app_label" msgid="6271216747302322594">"‏میزبان MTP"</string>
+ <string name="downloads_app_label" msgid="7120690641874849726">"بارگیری‌ها"</string>
+ <string name="root_name" msgid="5819495383921089536">"<xliff:g id="DEVICE_MODEL">%1$s</xliff:g> <xliff:g id="STORAGE_NAME">%2$s</xliff:g>"</string>
+ <string name="accessing_notification_title" msgid="3030133609230917944">"دسترسی به فایل‌ها از <xliff:g id="DEVICE_MODEL">%1$s</xliff:g>"</string>
+ <string name="error_busy_device" msgid="3997316850357386589">"دستگاه دیگر مشغول است. تا زمانی که این دستگاه دردسترس قرار نگیرد نمی‌توانید فایل‌ها را منتقل کنید."</string>
+ <string name="error_locked_device" msgid="7557872102188356147">"فایلی پیدا نشد. دستگاه دیگر ممکن است قفل باشد. اگر این‌طور است، قفل آن را باز کنید و دوباره تلاش کنید."</string>
+</resources>
diff --git a/packages/MtpDocumentsProvider/res/values-fi/strings.xml b/packages/MtpDocumentsProvider/res/values-fi/strings.xml
new file mode 100644
index 000000000000..0a61d08a566e
--- /dev/null
+++ b/packages/MtpDocumentsProvider/res/values-fi/strings.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2015 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="app_label" msgid="6271216747302322594">"MTP-isäntä"</string>
+ <string name="downloads_app_label" msgid="7120690641874849726">"Lataukset"</string>
+ <string name="root_name" msgid="5819495383921089536">"<xliff:g id="DEVICE_MODEL">%1$s</xliff:g> <xliff:g id="STORAGE_NAME">%2$s</xliff:g>"</string>
+ <string name="accessing_notification_title" msgid="3030133609230917944">"Käytetään laitteen <xliff:g id="DEVICE_MODEL">%1$s</xliff:g> tiedostoja"</string>
+ <string name="error_busy_device" msgid="3997316850357386589">"Toinen laite on varattu. Et voi siirtää tiedostoja, ennen kuin se on käytettävissä."</string>
+ <string name="error_locked_device" msgid="7557872102188356147">"Tiedostoja ei löytynyt. Toinen laite voi olla lukittu. Jos näin on, avaa se ja yritä uudelleen."</string>
+</resources>
diff --git a/packages/MtpDocumentsProvider/res/values-fr-rCA/strings.xml b/packages/MtpDocumentsProvider/res/values-fr-rCA/strings.xml
new file mode 100644
index 000000000000..281760ecb620
--- /dev/null
+++ b/packages/MtpDocumentsProvider/res/values-fr-rCA/strings.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2015 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="app_label" msgid="6271216747302322594">"Hôte MTP"</string>
+ <string name="downloads_app_label" msgid="7120690641874849726">"Téléchargements"</string>
+ <string name="root_name" msgid="5819495383921089536">"<xliff:g id="DEVICE_MODEL">%1$s</xliff:g> <xliff:g id="STORAGE_NAME">%2$s</xliff:g>"</string>
+ <string name="accessing_notification_title" msgid="3030133609230917944">"Accès aux fichiers à partir de l\'appareil <xliff:g id="DEVICE_MODEL">%1$s</xliff:g>"</string>
+ <string name="error_busy_device" msgid="3997316850357386589">"L\'autre appareil est occupé. Vous devez attendre qu\'il soit disponible pour transférer des fichiers."</string>
+ <string name="error_locked_device" msgid="7557872102188356147">"Aucun fichier trouvé. L\'autre appareil est peut-être verrouillé. Si c\'est le cas, déverrouillez-le, puis réessayez."</string>
+</resources>
diff --git a/packages/MtpDocumentsProvider/res/values-fr/strings.xml b/packages/MtpDocumentsProvider/res/values-fr/strings.xml
new file mode 100644
index 000000000000..96c713b61af4
--- /dev/null
+++ b/packages/MtpDocumentsProvider/res/values-fr/strings.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2015 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="app_label" msgid="6271216747302322594">"Hôte MTP"</string>
+ <string name="downloads_app_label" msgid="7120690641874849726">"Téléchargements"</string>
+ <string name="root_name" msgid="5819495383921089536">"<xliff:g id="STORAGE_NAME">%2$s</xliff:g> – <xliff:g id="DEVICE_MODEL">%1$s</xliff:g>"</string>
+ <string name="accessing_notification_title" msgid="3030133609230917944">"Accès aux fichiers depuis le <xliff:g id="DEVICE_MODEL">%1$s</xliff:g>…"</string>
+ <string name="error_busy_device" msgid="3997316850357386589">"L\'autre appareil est occupé. Vous devez attendre qu\'il soit disponible pour transférer des fichiers."</string>
+ <string name="error_locked_device" msgid="7557872102188356147">"Aucun fichier trouvé. L\'autre appareil est peut-être verrouillé. Si tel est le cas, déverrouillez-le, puis réessayez."</string>
+</resources>
diff --git a/packages/MtpDocumentsProvider/res/values-gl/strings.xml b/packages/MtpDocumentsProvider/res/values-gl/strings.xml
new file mode 100644
index 000000000000..7e61c7cedff9
--- /dev/null
+++ b/packages/MtpDocumentsProvider/res/values-gl/strings.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2015 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="app_label" msgid="6271216747302322594">"Host MTP"</string>
+ <string name="downloads_app_label" msgid="7120690641874849726">"Descargas"</string>
+ <string name="root_name" msgid="5819495383921089536">"<xliff:g id="STORAGE_NAME">%2$s</xliff:g> de <xliff:g id="DEVICE_MODEL">%1$s</xliff:g>"</string>
+ <string name="accessing_notification_title" msgid="3030133609230917944">"Accedendo aos ficheiros do dispositivo <xliff:g id="DEVICE_MODEL">%1$s</xliff:g>"</string>
+ <string name="error_busy_device" msgid="3997316850357386589">"O outro dispositivo está ocupado. Non podes transferir ficheiros ata que estea dispoñible."</string>
+ <string name="error_locked_device" msgid="7557872102188356147">"Non se atopou ningún ficheiro. Se o outro dispositivo está bloqueado, desbloquéao e téntao de novo."</string>
+</resources>
diff --git a/packages/MtpDocumentsProvider/res/values-gu/strings.xml b/packages/MtpDocumentsProvider/res/values-gu/strings.xml
new file mode 100644
index 000000000000..40ec38ddcda9
--- /dev/null
+++ b/packages/MtpDocumentsProvider/res/values-gu/strings.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2015 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="app_label" msgid="6271216747302322594">"MTP હોસ્ટ"</string>
+ <string name="downloads_app_label" msgid="7120690641874849726">"ડાઉનલોડ્સ"</string>
+ <string name="root_name" msgid="5819495383921089536">"<xliff:g id="DEVICE_MODEL">%1$s</xliff:g> <xliff:g id="STORAGE_NAME">%2$s</xliff:g>"</string>
+ <string name="accessing_notification_title" msgid="3030133609230917944">"<xliff:g id="DEVICE_MODEL">%1$s</xliff:g> ની ફાઇલોને ઍક્સેસ કરી રહ્યાં છે"</string>
+ <string name="error_busy_device" msgid="3997316850357386589">"અન્ય ઉપકરણ વ્યસ્ત છે. તે ઉપલબ્ધ ન થાય ત્યાં સુધી તમે ફાઇલોને સ્થાનાંતરિત કરી શકતાં નથી."</string>
+ <string name="error_locked_device" msgid="7557872102188356147">"કોઈ ફાઇલો મળી નહીં. અન્ય ઉપકરણ લૉક કરેલ હોઈ શકે છે. જો આમ હોય, તો તેને અનલૉક કરો અને ફરી પ્રયાસ કરો."</string>
+</resources>
diff --git a/packages/MtpDocumentsProvider/res/values-hi/strings.xml b/packages/MtpDocumentsProvider/res/values-hi/strings.xml
new file mode 100644
index 000000000000..1cf1c03780e8
--- /dev/null
+++ b/packages/MtpDocumentsProvider/res/values-hi/strings.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2015 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="app_label" msgid="6271216747302322594">"MTP होस्ट"</string>
+ <string name="downloads_app_label" msgid="7120690641874849726">"डाउनलोड"</string>
+ <string name="root_name" msgid="5819495383921089536">"<xliff:g id="DEVICE_MODEL">%1$s</xliff:g> <xliff:g id="STORAGE_NAME">%2$s</xliff:g>"</string>
+ <string name="accessing_notification_title" msgid="3030133609230917944">"<xliff:g id="DEVICE_MODEL">%1$s</xliff:g> से फ़ाइलें एक्सेस कर रहा है"</string>
+ <string name="error_busy_device" msgid="3997316850357386589">"दूसरा डिवाइस व्यस्त है. आप उसके उपलब्ध हो जाने तक फ़ाइलें स्थानांतरित नहीं कर सकते हैं."</string>
+ <string name="error_locked_device" msgid="7557872102188356147">"कोई फ़ाइल नहीं मिली. हो सकता है कि दूसरा डिवाइस लॉक हो. यदि ऐसा है, तो उसे अनलॉक करें और पुन: प्रयास करें."</string>
+</resources>
diff --git a/packages/MtpDocumentsProvider/res/values-hr/strings.xml b/packages/MtpDocumentsProvider/res/values-hr/strings.xml
new file mode 100644
index 000000000000..63fc5c768113
--- /dev/null
+++ b/packages/MtpDocumentsProvider/res/values-hr/strings.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2015 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="app_label" msgid="6271216747302322594">"MTP host"</string>
+ <string name="downloads_app_label" msgid="7120690641874849726">"Preuzimanja"</string>
+ <string name="root_name" msgid="5819495383921089536">"<xliff:g id="DEVICE_MODEL">%1$s</xliff:g><xliff:g id="STORAGE_NAME">%2$s</xliff:g>"</string>
+ <string name="accessing_notification_title" msgid="3030133609230917944">"Pristupanje datotekama s uređaja <xliff:g id="DEVICE_MODEL">%1$s</xliff:g>"</string>
+ <string name="error_busy_device" msgid="3997316850357386589">"Drugi je uređaj zauzet. Datoteke ćete moći prenijeti kada postane dostupan."</string>
+ <string name="error_locked_device" msgid="7557872102188356147">"Datoteke nisu pronađene. Drugi je uređaj možda zaključan. U tom ga slučaju otključajte i pokušajte ponovo."</string>
+</resources>
diff --git a/packages/MtpDocumentsProvider/res/values-hu/strings.xml b/packages/MtpDocumentsProvider/res/values-hu/strings.xml
new file mode 100644
index 000000000000..e5b822c14271
--- /dev/null
+++ b/packages/MtpDocumentsProvider/res/values-hu/strings.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2015 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="app_label" msgid="6271216747302322594">"MTP Host"</string>
+ <string name="downloads_app_label" msgid="7120690641874849726">"Letöltések"</string>
+ <string name="root_name" msgid="5819495383921089536">"<xliff:g id="DEVICE_MODEL">%1$s</xliff:g> <xliff:g id="STORAGE_NAME">%2$s</xliff:g>"</string>
+ <string name="accessing_notification_title" msgid="3030133609230917944">"Hozzáférés a fájlokhoz a következő eszközről: <xliff:g id="DEVICE_MODEL">%1$s</xliff:g>"</string>
+ <string name="error_busy_device" msgid="3997316850357386589">"A másik eszköz elfoglalt. Nem vihetők át fájlok addig, amíg rendelkezésre nem áll."</string>
+ <string name="error_locked_device" msgid="7557872102188356147">"Nem található fájl. Lehet, hogy a másik eszköz zárolva van. Ha igen, oldja fel, és próbálkozzon újra."</string>
+</resources>
diff --git a/packages/MtpDocumentsProvider/res/values-hy/strings.xml b/packages/MtpDocumentsProvider/res/values-hy/strings.xml
new file mode 100644
index 000000000000..3a6bfb50de44
--- /dev/null
+++ b/packages/MtpDocumentsProvider/res/values-hy/strings.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2015 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="app_label" msgid="6271216747302322594">"MTP խնամորդ"</string>
+ <string name="downloads_app_label" msgid="7120690641874849726">"Ներբեռնումներ"</string>
+ <string name="root_name" msgid="5819495383921089536">"<xliff:g id="DEVICE_MODEL">%1$s</xliff:g> <xliff:g id="STORAGE_NAME">%2$s</xliff:g>"</string>
+ <string name="accessing_notification_title" msgid="3030133609230917944">"Մուտք է գործում ֆայլեր <xliff:g id="DEVICE_MODEL">%1$s</xliff:g> սարքից"</string>
+ <string name="error_busy_device" msgid="3997316850357386589">"Մյուս սարքը զբաղված է: Ֆայլերը կարող եք փոխանցել միայն երբ այն հասանելի է:"</string>
+ <string name="error_locked_device" msgid="7557872102188356147">"Ֆայլեր չեն գտնվել: Հնարավոր է, որ մյուս սարքը կողպված է: Եթե դա այդպես է, ապակողպեք այն և փորձեք նորից:"</string>
+</resources>
diff --git a/packages/MtpDocumentsProvider/res/values-in/strings.xml b/packages/MtpDocumentsProvider/res/values-in/strings.xml
new file mode 100644
index 000000000000..6f65337a1d61
--- /dev/null
+++ b/packages/MtpDocumentsProvider/res/values-in/strings.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2015 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="app_label" msgid="6271216747302322594">"Host MTP"</string>
+ <string name="downloads_app_label" msgid="7120690641874849726">"Download"</string>
+ <string name="root_name" msgid="5819495383921089536">"<xliff:g id="DEVICE_MODEL">%1$s</xliff:g> <xliff:g id="STORAGE_NAME">%2$s</xliff:g>"</string>
+ <string name="accessing_notification_title" msgid="3030133609230917944">"Mengakses file dari <xliff:g id="DEVICE_MODEL">%1$s</xliff:g>"</string>
+ <string name="error_busy_device" msgid="3997316850357386589">"Perangkat lainnya sedang sibuk. Anda dapat mentransfer file jika telah tersedia."</string>
+ <string name="error_locked_device" msgid="7557872102188356147">"File tidak ditemukan. Perangkat lainnya mungkin terkunci. Jika begitu, buka kuncinya dan coba lagi."</string>
+</resources>
diff --git a/packages/MtpDocumentsProvider/res/values-is/strings.xml b/packages/MtpDocumentsProvider/res/values-is/strings.xml
new file mode 100644
index 000000000000..9388f7e76efa
--- /dev/null
+++ b/packages/MtpDocumentsProvider/res/values-is/strings.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2015 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="app_label" msgid="6271216747302322594">"MTP-hýsill"</string>
+ <string name="downloads_app_label" msgid="7120690641874849726">"Niðurhal"</string>
+ <string name="root_name" msgid="5819495383921089536">"<xliff:g id="DEVICE_MODEL">%1$s</xliff:g> <xliff:g id="STORAGE_NAME">%2$s</xliff:g>"</string>
+ <string name="accessing_notification_title" msgid="3030133609230917944">"Fær aðgang að skrám frá <xliff:g id="DEVICE_MODEL">%1$s</xliff:g>"</string>
+ <string name="error_busy_device" msgid="3997316850357386589">"Hitt tækið er upptekið. Þú getur ekki fært skrár fyrr en það er tiltækt."</string>
+ <string name="error_locked_device" msgid="7557872102188356147">"Engar skrár fundust. Hitt tækið gæti verið læst. Ef svo er skaltu opna það og reyna aftur."</string>
+</resources>
diff --git a/packages/MtpDocumentsProvider/res/values-it/strings.xml b/packages/MtpDocumentsProvider/res/values-it/strings.xml
new file mode 100644
index 000000000000..a41699f55282
--- /dev/null
+++ b/packages/MtpDocumentsProvider/res/values-it/strings.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2015 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="app_label" msgid="6271216747302322594">"Host MTP"</string>
+ <string name="downloads_app_label" msgid="7120690641874849726">"Download"</string>
+ <string name="root_name" msgid="5819495383921089536">"<xliff:g id="STORAGE_NAME">%2$s</xliff:g> di <xliff:g id="DEVICE_MODEL">%1$s</xliff:g>"</string>
+ <string name="accessing_notification_title" msgid="3030133609230917944">"Accesso ai file da <xliff:g id="DEVICE_MODEL">%1$s</xliff:g>"</string>
+ <string name="error_busy_device" msgid="3997316850357386589">"L\'altro dispositivo è occupato. I file non possono essere trasferiti fino a quando non sarà disponibile."</string>
+ <string name="error_locked_device" msgid="7557872102188356147">"Nessun file trovato. L\'altro dispositivo potrebbe essere bloccato. In questo caso, sbloccalo e riprova."</string>
+</resources>
diff --git a/packages/MtpDocumentsProvider/res/values-iw/strings.xml b/packages/MtpDocumentsProvider/res/values-iw/strings.xml
new file mode 100644
index 000000000000..62dfe7dd4ebb
--- /dev/null
+++ b/packages/MtpDocumentsProvider/res/values-iw/strings.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2015 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="app_label" msgid="6271216747302322594">"‏מארח פרוטוקול העברת מדיה (MTP)"</string>
+ <string name="downloads_app_label" msgid="7120690641874849726">"הורדות"</string>
+ <string name="root_name" msgid="5819495383921089536">"<xliff:g id="DEVICE_MODEL">%1$s</xliff:g> <xliff:g id="STORAGE_NAME">%2$s</xliff:g>"</string>
+ <string name="accessing_notification_title" msgid="3030133609230917944">"גישה לקבצים מ-<xliff:g id="DEVICE_MODEL">%1$s</xliff:g>"</string>
+ <string name="error_busy_device" msgid="3997316850357386589">"המכשיר השני לא פנוי. ניתן יהיה להעביר קבצים רק לאחר שהוא יהיה זמין."</string>
+ <string name="error_locked_device" msgid="7557872102188356147">"לא נמצאו קבצים. ייתכן שהמכשיר השני נעול. אם כן, פתח אותו ונסה שוב."</string>
+</resources>
diff --git a/packages/MtpDocumentsProvider/res/values-ja/strings.xml b/packages/MtpDocumentsProvider/res/values-ja/strings.xml
new file mode 100644
index 000000000000..4ae59f5d9037
--- /dev/null
+++ b/packages/MtpDocumentsProvider/res/values-ja/strings.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2015 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="app_label" msgid="6271216747302322594">"MTP ホスト"</string>
+ <string name="downloads_app_label" msgid="7120690641874849726">"ダウンロード"</string>
+ <string name="root_name" msgid="5819495383921089536">"<xliff:g id="DEVICE_MODEL">%1$s</xliff:g> <xliff:g id="STORAGE_NAME">%2$s</xliff:g>"</string>
+ <string name="accessing_notification_title" msgid="3030133609230917944">"<xliff:g id="DEVICE_MODEL">%1$s</xliff:g> からファイルにアクセスしています"</string>
+ <string name="error_busy_device" msgid="3997316850357386589">"接続先の端末は使用中のため、利用できるようになるまでファイルを転送できません。"</string>
+ <string name="error_locked_device" msgid="7557872102188356147">"ファイルが見つかりません。接続先の端末がロックされている可能性があります。その場合は、ロックを解除してからもう一度お試しください。"</string>
+</resources>
diff --git a/packages/MtpDocumentsProvider/res/values-ka/strings.xml b/packages/MtpDocumentsProvider/res/values-ka/strings.xml
new file mode 100644
index 000000000000..33812dfbf3df
--- /dev/null
+++ b/packages/MtpDocumentsProvider/res/values-ka/strings.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2015 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="app_label" msgid="6271216747302322594">"MTP ჰოსტი"</string>
+ <string name="downloads_app_label" msgid="7120690641874849726">"ჩამოტვირთვები"</string>
+ <string name="root_name" msgid="5819495383921089536">"<xliff:g id="DEVICE_MODEL">%1$s</xliff:g> <xliff:g id="STORAGE_NAME">%2$s</xliff:g>"</string>
+ <string name="accessing_notification_title" msgid="3030133609230917944">"მიმდინარეობს <xliff:g id="DEVICE_MODEL">%1$s</xliff:g>-ზე არსებულ ფაილებზე წვდომა"</string>
+ <string name="error_busy_device" msgid="3997316850357386589">"სხვა მოწყობილობა დაკავებულია. ფაილების გადატანა ვერ მოხერხდება, სანამ ის ხელმისაწვდომი არ გახდება."</string>
+ <string name="error_locked_device" msgid="7557872102188356147">"ფაილები ვერ მოიძებნა. მეორე მოწყობილობა შეიძლება დაბლოკილი იყოს. ამ შემთხვევაში, განბლოკეთ ის და ცადეთ ხელახლა."</string>
+</resources>
diff --git a/packages/MtpDocumentsProvider/res/values-kk/strings.xml b/packages/MtpDocumentsProvider/res/values-kk/strings.xml
new file mode 100644
index 000000000000..a6dea5b97b03
--- /dev/null
+++ b/packages/MtpDocumentsProvider/res/values-kk/strings.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2015 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="app_label" msgid="6271216747302322594">"MTP хосты"</string>
+ <string name="downloads_app_label" msgid="7120690641874849726">"Жүктеп алынғандар"</string>
+ <string name="root_name" msgid="5819495383921089536">"<xliff:g id="DEVICE_MODEL">%1$s</xliff:g> <xliff:g id="STORAGE_NAME">%2$s</xliff:g>"</string>
+ <string name="accessing_notification_title" msgid="3030133609230917944">"Файлдарға <xliff:g id="DEVICE_MODEL">%1$s</xliff:g> құрылғысынан кіру"</string>
+ <string name="error_busy_device" msgid="3997316850357386589">"Екінші құрылғы бос емес. Ол босамайынша, файлдар тасымалданбайды."</string>
+ <string name="error_locked_device" msgid="7557872102188356147">"Ешқандай файл табылмады. Екінші құрылғы құлыптаулы болуы мүмкін. Құлыптаулы болса, құлпын ашып, қайталап көріңіз."</string>
+</resources>
diff --git a/packages/MtpDocumentsProvider/res/values-km/strings.xml b/packages/MtpDocumentsProvider/res/values-km/strings.xml
new file mode 100644
index 000000000000..baffa95c426b
--- /dev/null
+++ b/packages/MtpDocumentsProvider/res/values-km/strings.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2015 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="app_label" msgid="6271216747302322594">"ម៉ាស៊ីន MTP"</string>
+ <string name="downloads_app_label" msgid="7120690641874849726">"ដោយឡូត"</string>
+ <string name="root_name" msgid="5819495383921089536">"<xliff:g id="DEVICE_MODEL">%1$s</xliff:g> <xliff:g id="STORAGE_NAME">%2$s</xliff:g>"</string>
+ <string name="accessing_notification_title" msgid="3030133609230917944">"កំពុងចូលដំណើរការពី <xliff:g id="DEVICE_MODEL">%1$s</xliff:g>"</string>
+ <string name="error_busy_device" msgid="3997316850357386589">"ឧបករណ៍ផ្សេងទៀតកំពុងជាប់រវល់។ អ្នកមិនផ្ទេរឯកសារបានទេ រហូតទាល់តែវាអាចប្រើបាន។"</string>
+ <string name="error_locked_device" msgid="7557872102188356147">"រកមិនឃើញឯកសារទេ។ ឧបករណ៍ផ្សេងទៀតប្រហែលជាត្រូវបានចាក់សោ។ ប្រសិនបើវាត្រូវបានចាក់សោមែន សូមដោះសោ ហើយព្យាយាមម្តងទៀត។"</string>
+</resources>
diff --git a/packages/MtpDocumentsProvider/res/values-kn/strings.xml b/packages/MtpDocumentsProvider/res/values-kn/strings.xml
new file mode 100644
index 000000000000..3f16c142aba1
--- /dev/null
+++ b/packages/MtpDocumentsProvider/res/values-kn/strings.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2015 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="app_label" msgid="6271216747302322594">"MTP ಹೋಸ್ಟ್"</string>
+ <string name="downloads_app_label" msgid="7120690641874849726">"ಡೌನ್‌ಲೋಡ್‌ಗಳು"</string>
+ <string name="root_name" msgid="5819495383921089536">"<xliff:g id="DEVICE_MODEL">%1$s</xliff:g> <xliff:g id="STORAGE_NAME">%2$s</xliff:g>"</string>
+ <string name="accessing_notification_title" msgid="3030133609230917944">"<xliff:g id="DEVICE_MODEL">%1$s</xliff:g> ನಿಂದ ಫೈಲ್‌ಗಳನ್ನು ಪ್ರವೇಶಿಸಲಾಗುತ್ತಿದೆ"</string>
+ <string name="error_busy_device" msgid="3997316850357386589">"ಬೇರೆಯ ಸಾಧನವು ಕಾರ್ಯನಿರತವಾಗಿದೆ. ಇದು ಲಭ್ಯವಾಗುವವರೆಗೆ ಫೈಲ್‌ಗಳನ್ನು ನಿಮಗೆ ವರ್ಗಾಯಿಸಲು ಸಾಧ್ಯವಾಗುವುದಿಲ್ಲ."</string>
+ <string name="error_locked_device" msgid="7557872102188356147">"ಯಾವುದೇ ಫೈಲ್‌ಗಳು ಕಂಡುಬಂದಿಲ್ಲ. ಬೇರೆಯ ಸಾಧನವು ಲಾಕ್ ಆಗಿರಬಹುದು. ಹಾಗಾದಲ್ಲಿ, ಇದನ್ನು ಅನ್‌ಲಾಕ್ ಮಾಡಿ ಹಾಗೂ ಮತ್ತೆ ಪ್ರಯತ್ನಿಸಿ."</string>
+</resources>
diff --git a/packages/MtpDocumentsProvider/res/values-ko/strings.xml b/packages/MtpDocumentsProvider/res/values-ko/strings.xml
new file mode 100644
index 000000000000..bbe2fe6d78a4
--- /dev/null
+++ b/packages/MtpDocumentsProvider/res/values-ko/strings.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2015 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="app_label" msgid="6271216747302322594">"MTP 호스트"</string>
+ <string name="downloads_app_label" msgid="7120690641874849726">"다운로드"</string>
+ <string name="root_name" msgid="5819495383921089536">"<xliff:g id="DEVICE_MODEL">%1$s</xliff:g> <xliff:g id="STORAGE_NAME">%2$s</xliff:g>"</string>
+ <string name="accessing_notification_title" msgid="3030133609230917944">"<xliff:g id="DEVICE_MODEL">%1$s</xliff:g>에서 파일에 액세스 중"</string>
+ <string name="error_busy_device" msgid="3997316850357386589">"다른 기기가 사용 중입니다. 다른 기기를 사용할 수 있을 때까지 파일을 전송할 수 없습니다."</string>
+ <string name="error_locked_device" msgid="7557872102188356147">"파일이 없습니다. 다른 기기가 잠겨 있을 수 있습니다. 기기의 잠금을 해제하고 다시 시도하세요."</string>
+</resources>
diff --git a/packages/MtpDocumentsProvider/res/values-ky/strings.xml b/packages/MtpDocumentsProvider/res/values-ky/strings.xml
new file mode 100644
index 000000000000..e60a494a9919
--- /dev/null
+++ b/packages/MtpDocumentsProvider/res/values-ky/strings.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2015 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="app_label" msgid="6271216747302322594">"MTP хосту"</string>
+ <string name="downloads_app_label" msgid="7120690641874849726">"Жүктөлүп алынган нерселер"</string>
+ <string name="root_name" msgid="5819495383921089536">"<xliff:g id="DEVICE_MODEL">%1$s</xliff:g> <xliff:g id="STORAGE_NAME">%2$s</xliff:g>"</string>
+ <string name="accessing_notification_title" msgid="3030133609230917944">"<xliff:g id="DEVICE_MODEL">%1$s</xliff:g> түзмөгүндөгү файлдар колдонулууда"</string>
+ <string name="error_busy_device" msgid="3997316850357386589">"Берки түзмөк бош эмес. Ал бошомоюнча файлдарды өткөрө албайсыз."</string>
+ <string name="error_locked_device" msgid="7557872102188356147">"Бир дагы файл табылган жок. Берки түзмөк кулпуланып турат окшойт. Кулпусун ачып, кайра аракет кылып көрүңүз."</string>
+</resources>
diff --git a/packages/MtpDocumentsProvider/res/values-lo/strings.xml b/packages/MtpDocumentsProvider/res/values-lo/strings.xml
new file mode 100644
index 000000000000..bcc0ee6b7ff3
--- /dev/null
+++ b/packages/MtpDocumentsProvider/res/values-lo/strings.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2015 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="app_label" msgid="6271216747302322594">"ໂຮສ MTP"</string>
+ <string name="downloads_app_label" msgid="7120690641874849726">"ການດາວໂຫລດ"</string>
+ <string name="root_name" msgid="5819495383921089536">"<xliff:g id="DEVICE_MODEL">%1$s</xliff:g> <xliff:g id="STORAGE_NAME">%2$s</xliff:g>"</string>
+ <string name="accessing_notification_title" msgid="3030133609230917944">"ກຳລັງເຂົ້າເຖິງໄຟລ໌ຈາກ <xliff:g id="DEVICE_MODEL">%1$s</xliff:g>"</string>
+ <string name="error_busy_device" msgid="3997316850357386589">"ອຸປະກອນອື່ນບໍ່ຫວ່າງເທື່ອ. ທ່ານບໍ່ສາມາດໂອນຍ້າຍໄຟລ໌ໄດ້ຈົນກວ່າມັນຈະຫວ່າງ."</string>
+ <string name="error_locked_device" msgid="7557872102188356147">"ບໍ່ພົບໄຟລ໌. ອຸປະກອນອີກເຄື່ອງອາດຖືກລັອກໄວ້ຢູ່. ຫາກມັນຖືກລັອກໄວ້, ໃຫ້ປົດລັອກມັນກ່ອນແລ້ວລອງໃໝ່ອີກຄັ້ງ."</string>
+</resources>
diff --git a/packages/MtpDocumentsProvider/res/values-lt/strings.xml b/packages/MtpDocumentsProvider/res/values-lt/strings.xml
new file mode 100644
index 000000000000..8bff3a8fe78a
--- /dev/null
+++ b/packages/MtpDocumentsProvider/res/values-lt/strings.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2015 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="app_label" msgid="6271216747302322594">"MPP priegloba"</string>
+ <string name="downloads_app_label" msgid="7120690641874849726">"Atsisiuntimai"</string>
+ <string name="root_name" msgid="5819495383921089536">"„<xliff:g id="DEVICE_MODEL">%1$s</xliff:g>“ <xliff:g id="STORAGE_NAME">%2$s</xliff:g>"</string>
+ <string name="accessing_notification_title" msgid="3030133609230917944">"Pasiekiami failai iš „<xliff:g id="DEVICE_MODEL">%1$s</xliff:g>“"</string>
+ <string name="error_busy_device" msgid="3997316850357386589">"Kitas įrenginys yra užsiėmęs. Failus galėsite perkelti tik tada, kai jis bus pasiekiamas."</string>
+ <string name="error_locked_device" msgid="7557872102188356147">"Nerasta failų. Gali būti, kad kitas įrenginys yra užrakintas. Jei taip yra, atrakinkite jį ir bandykite dar kartą."</string>
+</resources>
diff --git a/packages/MtpDocumentsProvider/res/values-lv/strings.xml b/packages/MtpDocumentsProvider/res/values-lv/strings.xml
new file mode 100644
index 000000000000..5e96338afaa0
--- /dev/null
+++ b/packages/MtpDocumentsProvider/res/values-lv/strings.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2015 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="app_label" msgid="6271216747302322594">"MTP saimniekdators"</string>
+ <string name="downloads_app_label" msgid="7120690641874849726">"Lejupielādes"</string>
+ <string name="root_name" msgid="5819495383921089536">"<xliff:g id="DEVICE_MODEL">%1$s</xliff:g> <xliff:g id="STORAGE_NAME">%2$s</xliff:g>"</string>
+ <string name="accessing_notification_title" msgid="3030133609230917944">"Piekļuve failiem no: <xliff:g id="DEVICE_MODEL">%1$s</xliff:g>"</string>
+ <string name="error_busy_device" msgid="3997316850357386589">"Otra ierīce ir aizņemta. Varēsiet pārsūtīt failus tikai tad, kad tā būs pieejama."</string>
+ <string name="error_locked_device" msgid="7557872102188356147">"Neviens fails netika atrasts. Iespējams, otra ierīce ir bloķēta. Ja tā ir, atbloķējiet ierīci un mēģiniet vēlreiz."</string>
+</resources>
diff --git a/packages/MtpDocumentsProvider/res/values-mk/strings.xml b/packages/MtpDocumentsProvider/res/values-mk/strings.xml
new file mode 100644
index 000000000000..6028b716ec9e
--- /dev/null
+++ b/packages/MtpDocumentsProvider/res/values-mk/strings.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2015 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="app_label" msgid="6271216747302322594">"MTP-хост"</string>
+ <string name="downloads_app_label" msgid="7120690641874849726">"Преземања"</string>
+ <string name="root_name" msgid="5819495383921089536">"<xliff:g id="DEVICE_MODEL">%1$s</xliff:g> <xliff:g id="STORAGE_NAME">%2$s</xliff:g>"</string>
+ <string name="accessing_notification_title" msgid="3030133609230917944">"Се пристапува до датотеки од <xliff:g id="DEVICE_MODEL">%1$s</xliff:g>"</string>
+ <string name="error_busy_device" msgid="3997316850357386589">"Другиот уред е зафатен. Не може да се пренесуваат датотеки сѐ додека не стане достапен."</string>
+ <string name="error_locked_device" msgid="7557872102188356147">"Не се најдени датотеки. Другиот уред можеби е заклучен. Ако е така, отклучете го и обидете се повторно."</string>
+</resources>
diff --git a/packages/MtpDocumentsProvider/res/values-ml/strings.xml b/packages/MtpDocumentsProvider/res/values-ml/strings.xml
new file mode 100644
index 000000000000..49eb847b1173
--- /dev/null
+++ b/packages/MtpDocumentsProvider/res/values-ml/strings.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2015 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="app_label" msgid="6271216747302322594">"MTP ഹോസ്റ്റ്"</string>
+ <string name="downloads_app_label" msgid="7120690641874849726">"ഡൗണ്‍ലോഡുകൾ"</string>
+ <string name="root_name" msgid="5819495383921089536">"<xliff:g id="DEVICE_MODEL">%1$s</xliff:g> <xliff:g id="STORAGE_NAME">%2$s</xliff:g>"</string>
+ <string name="accessing_notification_title" msgid="3030133609230917944">"<xliff:g id="DEVICE_MODEL">%1$s</xliff:g> ഉപകരണത്തിൽ നിന്ന് ഫയലുകൾ ആക്സസ്സ് ചെയ്യുന്നു"</string>
+ <string name="error_busy_device" msgid="3997316850357386589">"രണ്ടാമത്തെ ഉപകരണം തിരക്കിലാണ്. അത് ലഭ്യമാകുന്നത് വരെ നിങ്ങൾക്ക് ഫയലുകൾ കൈമാറാൻ കഴിയില്ല."</string>
+ <string name="error_locked_device" msgid="7557872102188356147">"ഫയലുകളൊന്നും കണ്ടെത്തിയില്ല. രണ്ടാമത്തെ ഉപകരണം ലോക്കുചെയ്ത നിലയിലായിരിക്കാം. ആണെങ്കിൽ, അൺലോക്കുചെയ്ത് വീണ്ടും ശ്രമിക്കുക."</string>
+</resources>
diff --git a/packages/MtpDocumentsProvider/res/values-mn/strings.xml b/packages/MtpDocumentsProvider/res/values-mn/strings.xml
new file mode 100644
index 000000000000..43b8204e7599
--- /dev/null
+++ b/packages/MtpDocumentsProvider/res/values-mn/strings.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2015 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="app_label" msgid="6271216747302322594">"MTP Хост"</string>
+ <string name="downloads_app_label" msgid="7120690641874849726">"Таталт"</string>
+ <string name="root_name" msgid="5819495383921089536">"<xliff:g id="DEVICE_MODEL">%1$s</xliff:g> <xliff:g id="STORAGE_NAME">%2$s</xliff:g>"</string>
+ <string name="accessing_notification_title" msgid="3030133609230917944">"<xliff:g id="DEVICE_MODEL">%1$s</xliff:g>-с файлд хандаж байна"</string>
+ <string name="error_busy_device" msgid="3997316850357386589">"Нөгөө төхөөрөмж завгүй байна. Үүнийг боломжтой болох хүртэл файл шилжүүлэх боломжгүй."</string>
+ <string name="error_locked_device" msgid="7557872102188356147">"Файл олдсонгүй. Нөгөө төхөөрөмж түгжигдсэн байж болзошгүй. Ингэсэн тохиолдолд түгжээг нь тайлаад, дахин оролдоно уу."</string>
+</resources>
diff --git a/packages/MtpDocumentsProvider/res/values-mr/strings.xml b/packages/MtpDocumentsProvider/res/values-mr/strings.xml
new file mode 100644
index 000000000000..5b856dc4ec19
--- /dev/null
+++ b/packages/MtpDocumentsProvider/res/values-mr/strings.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2015 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="app_label" msgid="6271216747302322594">"MTP होस्ट"</string>
+ <string name="downloads_app_label" msgid="7120690641874849726">"डाउनलोड"</string>
+ <string name="root_name" msgid="5819495383921089536">"<xliff:g id="DEVICE_MODEL">%1$s</xliff:g> <xliff:g id="STORAGE_NAME">%2$s</xliff:g>"</string>
+ <string name="accessing_notification_title" msgid="3030133609230917944">"<xliff:g id="DEVICE_MODEL">%1$s</xliff:g> मधून फायलींंमध्ये प्रवेश करीत आहे"</string>
+ <string name="error_busy_device" msgid="3997316850357386589">"अन्य डिव्हाइस व्यस्त आहे. ते उपलब्‍ध होईपर्यंत आपण फायली हस्तांतरित करू शकत नाही."</string>
+ <string name="error_locked_device" msgid="7557872102188356147">"कोणत्याही फायली आढळल्या नाहीत. अन्य डिव्हाइस कदाचित बंद असू शकते. तसे असल्यास, ते अनलॉक करा आणि पुन्हा प्रयत्न करा."</string>
+</resources>
diff --git a/packages/MtpDocumentsProvider/res/values-ms/strings.xml b/packages/MtpDocumentsProvider/res/values-ms/strings.xml
new file mode 100644
index 000000000000..febec1d349af
--- /dev/null
+++ b/packages/MtpDocumentsProvider/res/values-ms/strings.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2015 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="app_label" msgid="6271216747302322594">"Hos MTP"</string>
+ <string name="downloads_app_label" msgid="7120690641874849726">"Muat turun"</string>
+ <string name="root_name" msgid="5819495383921089536">"<xliff:g id="DEVICE_MODEL">%1$s</xliff:g> <xliff:g id="STORAGE_NAME">%2$s</xliff:g>"</string>
+ <string name="accessing_notification_title" msgid="3030133609230917944">"Mengakses fail daripada <xliff:g id="DEVICE_MODEL">%1$s</xliff:g>"</string>
+ <string name="error_busy_device" msgid="3997316850357386589">"Peranti lain sedang sibuk. Anda tidak boleh memindahkan fail sehingga peranti itu tersedia."</string>
+ <string name="error_locked_device" msgid="7557872102188356147">"Tiada fail ditemui. Peranti lain itu mungkin dikunci. Jika benar, sila buka kuncinya dan cuba lagi."</string>
+</resources>
diff --git a/packages/MtpDocumentsProvider/res/values-my/strings.xml b/packages/MtpDocumentsProvider/res/values-my/strings.xml
new file mode 100644
index 000000000000..8b509fbf0167
--- /dev/null
+++ b/packages/MtpDocumentsProvider/res/values-my/strings.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2015 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="app_label" msgid="6271216747302322594">"MTP လက်ခံစက်"</string>
+ <string name="downloads_app_label" msgid="7120690641874849726">"ဒေါင်းလုဒ်များ"</string>
+ <string name="root_name" msgid="5819495383921089536">"<xliff:g id="DEVICE_MODEL">%1$s</xliff:g> <xliff:g id="STORAGE_NAME">%2$s</xliff:g>"</string>
+ <string name="accessing_notification_title" msgid="3030133609230917944">"<xliff:g id="DEVICE_MODEL">%1$s</xliff:g> မှ ဖိုင်များကို အသုံးပြုနေသည်"</string>
+ <string name="error_busy_device" msgid="3997316850357386589">"တခြားစက်ပစ္စည်းသည် မအားသေးပါ။ ၎င်းအဆင်သင့် မဖြစ်သေးသ၍ ဖိုင်များကို လွှဲပြောင်း၍ရမည် မဟုတ်ပါ။"</string>
+ <string name="error_locked_device" msgid="7557872102188356147">"မည်သည့်ဖိုင်မျှ မတွေ့ပါ။ ၎င်းစက်ပစ္စည်းကို လော့ခ်ချထားပုံရပါသည်။ သို့ဖြစ်လျှင် ၎င်းကိုလော့ခ်ဖြုတ်ပြီး ထပ်လုပ်ကြည့်ပါ။"</string>
+</resources>
diff --git a/packages/MtpDocumentsProvider/res/values-nb/strings.xml b/packages/MtpDocumentsProvider/res/values-nb/strings.xml
new file mode 100644
index 000000000000..40fabed73f40
--- /dev/null
+++ b/packages/MtpDocumentsProvider/res/values-nb/strings.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2015 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="app_label" msgid="6271216747302322594">"MTP-vert"</string>
+ <string name="downloads_app_label" msgid="7120690641874849726">"Nedlastinger"</string>
+ <string name="root_name" msgid="5819495383921089536">"<xliff:g id="STORAGE_NAME">%2$s</xliff:g> på <xliff:g id="DEVICE_MODEL">%1$s</xliff:g>"</string>
+ <string name="accessing_notification_title" msgid="3030133609230917944">"Bruker filer på <xliff:g id="DEVICE_MODEL">%1$s</xliff:g>"</string>
+ <string name="error_busy_device" msgid="3997316850357386589">"Den andre enheten er opptatt. Du kan ikke overføre filer før den er tilgjengelig."</string>
+ <string name="error_locked_device" msgid="7557872102188356147">"Ingen filer ble funnet. Den andre enheten kan være låst. I så fall må du låse den opp og prøve igjen."</string>
+</resources>
diff --git a/packages/MtpDocumentsProvider/res/values-ne/strings.xml b/packages/MtpDocumentsProvider/res/values-ne/strings.xml
new file mode 100644
index 000000000000..53c0954d296e
--- /dev/null
+++ b/packages/MtpDocumentsProvider/res/values-ne/strings.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2015 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="app_label" msgid="6271216747302322594">"MTP होस्ट"</string>
+ <string name="downloads_app_label" msgid="7120690641874849726">"डाउनलोडहरू"</string>
+ <string name="root_name" msgid="5819495383921089536">"<xliff:g id="DEVICE_MODEL">%1$s</xliff:g> <xliff:g id="STORAGE_NAME">%2$s</xliff:g>"</string>
+ <string name="accessing_notification_title" msgid="3030133609230917944">"<xliff:g id="DEVICE_MODEL">%1$s</xliff:g> बाट फाइलहरूमाथि पहुँच राख्दै"</string>
+ <string name="error_busy_device" msgid="3997316850357386589">"अर्को यन्त्र व्यस्त छ। त्यो यन्त्र उपलब्ध नभएसम्म तपाईं फाइल स्थानान्तरण गर्न सक्नुहुन्न।"</string>
+ <string name="error_locked_device" msgid="7557872102188356147">"कुनै फाइल भेट्टिएन। अर्को यन्त्र लक गरिएको हुन सक्छ। यदि त्यसो हो भने त्यसलाई अनलक गरेर फेरि प्रयास गर्नुहोस्।"</string>
+</resources>
diff --git a/packages/MtpDocumentsProvider/res/values-nl/strings.xml b/packages/MtpDocumentsProvider/res/values-nl/strings.xml
new file mode 100644
index 000000000000..b1a01b2cd8a9
--- /dev/null
+++ b/packages/MtpDocumentsProvider/res/values-nl/strings.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2015 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="app_label" msgid="6271216747302322594">"MTP-host"</string>
+ <string name="downloads_app_label" msgid="7120690641874849726">"Downloads"</string>
+ <string name="root_name" msgid="5819495383921089536">"<xliff:g id="DEVICE_MODEL">%1$s</xliff:g> <xliff:g id="STORAGE_NAME">%2$s</xliff:g>"</string>
+ <string name="accessing_notification_title" msgid="3030133609230917944">"Bestanden openen op <xliff:g id="DEVICE_MODEL">%1$s</xliff:g>"</string>
+ <string name="error_busy_device" msgid="3997316850357386589">"Het andere apparaat wordt gebruikt. Je moet wachten tot het beschikbaar is om bestanden te kunnen overzetten."</string>
+ <string name="error_locked_device" msgid="7557872102188356147">"Geen bestanden gevonden. Het kan zijn dat het andere apparaat is vergrendeld. Als dat het geval is, ontgrendel je het en probeer je het opnieuw."</string>
+</resources>
diff --git a/packages/MtpDocumentsProvider/res/values-pa/strings.xml b/packages/MtpDocumentsProvider/res/values-pa/strings.xml
new file mode 100644
index 000000000000..ab8ba1592ba7
--- /dev/null
+++ b/packages/MtpDocumentsProvider/res/values-pa/strings.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2015 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="app_label" msgid="6271216747302322594">"MTP ਹੋਸਟ"</string>
+ <string name="downloads_app_label" msgid="7120690641874849726">"ਡਾਊਨਲੋਡ"</string>
+ <string name="root_name" msgid="5819495383921089536">"<xliff:g id="DEVICE_MODEL">%1$s</xliff:g> <xliff:g id="STORAGE_NAME">%2$s</xliff:g>"</string>
+ <string name="accessing_notification_title" msgid="3030133609230917944">"<xliff:g id="DEVICE_MODEL">%1$s</xliff:g> ਦੀਆਂ ਫ਼ਾਈਲਾਂ \'ਤੇ ਪਹੁੰਚ ਕੀਤੀ ਜਾ ਰਹੀ ਹੈ"</string>
+ <string name="error_busy_device" msgid="3997316850357386589">"ਦੂਜੀ ਡੀਵਾਈਸ ਰੁਝੇਵੇਂ ਵਿੱਚ ਹੈ। ਉਸਦੇ ਉਪਲਬਧ ਹੋਣ ਤੱਕ ਤੁਸੀਂ ਫ਼ਾਈਲਾਂ ਦਾ ਤਬਾਦਲਾ ਨਹੀਂ ਕਰ ਸਕਦੇ।"</string>
+ <string name="error_locked_device" msgid="7557872102188356147">"ਕੋਈ ਫ਼ਾਈਲਾਂ ਨਹੀਂ ਮਿਲੀਆਂ। ਹੋ ਸਕਦਾ ਹੈ ਕਿ ਦੂਜੀ ਡੀਵਾਈਸ ਲੌਕ ਹੋਵੇ। ਜੇਕਰ ਇੰਝ ਹੈ, ਤਾਂ ਉਸਨੂੰ ਅਨਲੌਕ ਕਰੋ ਅਤੇ ਦੁਬਾਰਾ ਕੋਸ਼ਿਸ਼ ਕਰੋ।"</string>
+</resources>
diff --git a/packages/MtpDocumentsProvider/res/values-pl/strings.xml b/packages/MtpDocumentsProvider/res/values-pl/strings.xml
new file mode 100644
index 000000000000..69fa0f4473ca
--- /dev/null
+++ b/packages/MtpDocumentsProvider/res/values-pl/strings.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2015 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="app_label" msgid="6271216747302322594">"Host MTP"</string>
+ <string name="downloads_app_label" msgid="7120690641874849726">"Pobrane"</string>
+ <string name="root_name" msgid="5819495383921089536">"<xliff:g id="DEVICE_MODEL">%1$s</xliff:g> – <xliff:g id="STORAGE_NAME">%2$s</xliff:g>"</string>
+ <string name="accessing_notification_title" msgid="3030133609230917944">"Uzyskuję dostęp do plików na urządzeniu <xliff:g id="DEVICE_MODEL">%1$s</xliff:g>"</string>
+ <string name="error_busy_device" msgid="3997316850357386589">"Drugie urządzenie jest zajęte. Dopóki nie będzie dostępne, nie możesz przesłać plików."</string>
+ <string name="error_locked_device" msgid="7557872102188356147">"Nie znaleziono plików. Drugie urządzenie może być zablokowane. Jeśli tak jest, odblokuj je i spróbuj ponownie."</string>
+</resources>
diff --git a/packages/MtpDocumentsProvider/res/values-pt-rBR/strings.xml b/packages/MtpDocumentsProvider/res/values-pt-rBR/strings.xml
new file mode 100644
index 000000000000..03a14263f9c3
--- /dev/null
+++ b/packages/MtpDocumentsProvider/res/values-pt-rBR/strings.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2015 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="app_label" msgid="6271216747302322594">"Host do MTP"</string>
+ <string name="downloads_app_label" msgid="7120690641874849726">"Downloads"</string>
+ <string name="root_name" msgid="5819495383921089536">"<xliff:g id="STORAGE_NAME">%2$s</xliff:g> do <xliff:g id="DEVICE_MODEL">%1$s</xliff:g>"</string>
+ <string name="accessing_notification_title" msgid="3030133609230917944">"Acessando arquivos do <xliff:g id="DEVICE_MODEL">%1$s</xliff:g>"</string>
+ <string name="error_busy_device" msgid="3997316850357386589">"O outro dispositivo está ocupado. Não é possível transferir arquivos até que ele esteja disponível."</string>
+ <string name="error_locked_device" msgid="7557872102188356147">"Nenhum arquivo encontrado. É possível que o outro dispositivo esteja bloqueado. Se for o caso, desbloqueie-o e tente novamente."</string>
+</resources>
diff --git a/packages/MtpDocumentsProvider/res/values-pt-rPT/strings.xml b/packages/MtpDocumentsProvider/res/values-pt-rPT/strings.xml
new file mode 100644
index 000000000000..05d32d40fa27
--- /dev/null
+++ b/packages/MtpDocumentsProvider/res/values-pt-rPT/strings.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2015 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="app_label" msgid="6271216747302322594">"Anfitrião MTP"</string>
+ <string name="downloads_app_label" msgid="7120690641874849726">"Transferências"</string>
+ <string name="root_name" msgid="5819495383921089536">"<xliff:g id="DEVICE_MODEL">%1$s</xliff:g> <xliff:g id="STORAGE_NAME">%2$s</xliff:g>"</string>
+ <string name="accessing_notification_title" msgid="3030133609230917944">"Aceder a ficheiros do <xliff:g id="DEVICE_MODEL">%1$s</xliff:g>"</string>
+ <string name="error_busy_device" msgid="3997316850357386589">"O outro dispositivo está ocupado. Não pode transferir os ficheiros enquanto não estiver disponível."</string>
+ <string name="error_locked_device" msgid="7557872102188356147">"Nenhum ficheiro encontrado. O outro dispositivo pode estar bloqueado. Se assim for, desbloqueie e tente novamente."</string>
+</resources>
diff --git a/packages/MtpDocumentsProvider/res/values-pt/strings.xml b/packages/MtpDocumentsProvider/res/values-pt/strings.xml
new file mode 100644
index 000000000000..03a14263f9c3
--- /dev/null
+++ b/packages/MtpDocumentsProvider/res/values-pt/strings.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2015 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="app_label" msgid="6271216747302322594">"Host do MTP"</string>
+ <string name="downloads_app_label" msgid="7120690641874849726">"Downloads"</string>
+ <string name="root_name" msgid="5819495383921089536">"<xliff:g id="STORAGE_NAME">%2$s</xliff:g> do <xliff:g id="DEVICE_MODEL">%1$s</xliff:g>"</string>
+ <string name="accessing_notification_title" msgid="3030133609230917944">"Acessando arquivos do <xliff:g id="DEVICE_MODEL">%1$s</xliff:g>"</string>
+ <string name="error_busy_device" msgid="3997316850357386589">"O outro dispositivo está ocupado. Não é possível transferir arquivos até que ele esteja disponível."</string>
+ <string name="error_locked_device" msgid="7557872102188356147">"Nenhum arquivo encontrado. É possível que o outro dispositivo esteja bloqueado. Se for o caso, desbloqueie-o e tente novamente."</string>
+</resources>
diff --git a/packages/MtpDocumentsProvider/res/values-ro/strings.xml b/packages/MtpDocumentsProvider/res/values-ro/strings.xml
new file mode 100644
index 000000000000..21ebc57836b4
--- /dev/null
+++ b/packages/MtpDocumentsProvider/res/values-ro/strings.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2015 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="app_label" msgid="6271216747302322594">"Gazdă MTP"</string>
+ <string name="downloads_app_label" msgid="7120690641874849726">"Descărcări"</string>
+ <string name="root_name" msgid="5819495383921089536">"<xliff:g id="DEVICE_MODEL">%1$s</xliff:g> <xliff:g id="STORAGE_NAME">%2$s</xliff:g>"</string>
+ <string name="accessing_notification_title" msgid="3030133609230917944">"Se accesează fișierele de pe <xliff:g id="DEVICE_MODEL">%1$s</xliff:g>"</string>
+ <string name="error_busy_device" msgid="3997316850357386589">"Celălalt dispozitiv este ocupat. Nu puteți să transferați fișiere înainte să fie disponibil."</string>
+ <string name="error_locked_device" msgid="7557872102188356147">"Nu s-au găsit fișiere. Este posibil ca celălalt dispozitiv să fie blocat. În acest caz, deblocați-l și încercați din nou."</string>
+</resources>
diff --git a/packages/MtpDocumentsProvider/res/values-ru/strings.xml b/packages/MtpDocumentsProvider/res/values-ru/strings.xml
new file mode 100644
index 000000000000..717f12f5403f
--- /dev/null
+++ b/packages/MtpDocumentsProvider/res/values-ru/strings.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2015 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="app_label" msgid="6271216747302322594">"MTP-хост"</string>
+ <string name="downloads_app_label" msgid="7120690641874849726">"Загрузки"</string>
+ <string name="root_name" msgid="5819495383921089536">"<xliff:g id="STORAGE_NAME">%2$s</xliff:g> <xliff:g id="DEVICE_MODEL">%1$s</xliff:g>"</string>
+ <string name="accessing_notification_title" msgid="3030133609230917944">"Доступ к файлам на устройстве <xliff:g id="DEVICE_MODEL">%1$s</xliff:g>…"</string>
+ <string name="error_busy_device" msgid="3997316850357386589">"Другое устройство занято. Вы сможете передать файлы, когда оно будет доступно."</string>
+ <string name="error_locked_device" msgid="7557872102188356147">"Файлы не найдены. Если другое устройство заблокировано, разблокируйте его и повторите попытку."</string>
+</resources>
diff --git a/packages/MtpDocumentsProvider/res/values-si/strings.xml b/packages/MtpDocumentsProvider/res/values-si/strings.xml
new file mode 100644
index 000000000000..7a096b0a356a
--- /dev/null
+++ b/packages/MtpDocumentsProvider/res/values-si/strings.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2015 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="app_label" msgid="6271216747302322594">"MTP සංග්‍රාහක"</string>
+ <string name="downloads_app_label" msgid="7120690641874849726">"බාගැනීම්"</string>
+ <string name="root_name" msgid="5819495383921089536">"<xliff:g id="DEVICE_MODEL">%1$s</xliff:g> <xliff:g id="STORAGE_NAME">%2$s</xliff:g>"</string>
+ <string name="accessing_notification_title" msgid="3030133609230917944">"<xliff:g id="DEVICE_MODEL">%1$s</xliff:g> වෙතින් ගොනු වෙත පිවිසීම"</string>
+ <string name="error_busy_device" msgid="3997316850357386589">"අනෙක් උපාංගය කාර්ය බහුලය. එය ලබා ගත හැකි වන තෙක් ඔබට ගොනු මාරු කළ නොහැකිය."</string>
+ <string name="error_locked_device" msgid="7557872102188356147">"ගොනු හමු නොවීය. අනෙක් උපාංගය අගුලු දමා තිබිය හැකිය. එසේ නම්, එය අගුලු හැර නැවත උත්සාහ කරන්න."</string>
+</resources>
diff --git a/packages/MtpDocumentsProvider/res/values-sk/strings.xml b/packages/MtpDocumentsProvider/res/values-sk/strings.xml
new file mode 100644
index 000000000000..365e1b7ba0ae
--- /dev/null
+++ b/packages/MtpDocumentsProvider/res/values-sk/strings.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2015 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="app_label" msgid="6271216747302322594">"Hostiteľ MTP"</string>
+ <string name="downloads_app_label" msgid="7120690641874849726">"Stiahnuté súbory"</string>
+ <string name="root_name" msgid="5819495383921089536">"<xliff:g id="DEVICE_MODEL">%1$s</xliff:g> <xliff:g id="STORAGE_NAME">%2$s</xliff:g>"</string>
+ <string name="accessing_notification_title" msgid="3030133609230917944">"Prístup k súborom zo zariadenia <xliff:g id="DEVICE_MODEL">%1$s</xliff:g>"</string>
+ <string name="error_busy_device" msgid="3997316850357386589">"Druhé zariadenie je zaneprázdnené. Súbory bude možné preniesť, keď bude k dispozícii."</string>
+ <string name="error_locked_device" msgid="7557872102188356147">"Nenašli sa žiadne súbory. Druhé zariadenie môže byť uzamknuté. Ak je to tak, odomknite ho a skúste to znova."</string>
+</resources>
diff --git a/packages/MtpDocumentsProvider/res/values-sl/strings.xml b/packages/MtpDocumentsProvider/res/values-sl/strings.xml
new file mode 100644
index 000000000000..60945d64fe8f
--- /dev/null
+++ b/packages/MtpDocumentsProvider/res/values-sl/strings.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2015 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="app_label" msgid="6271216747302322594">"Gostitelj MTP"</string>
+ <string name="downloads_app_label" msgid="7120690641874849726">"Prenosi"</string>
+ <string name="root_name" msgid="5819495383921089536">"<xliff:g id="DEVICE_MODEL">%1$s</xliff:g> <xliff:g id="STORAGE_NAME">%2$s</xliff:g>"</string>
+ <string name="accessing_notification_title" msgid="3030133609230917944">"Dostopanje do datotek iz naprave <xliff:g id="DEVICE_MODEL">%1$s</xliff:g>"</string>
+ <string name="error_busy_device" msgid="3997316850357386589">"Druga naprava ni na voljo. Dokler ne bo na voljo, ne bo mogoče prenašati datotek."</string>
+ <string name="error_locked_device" msgid="7557872102188356147">"Ni datotek. Druga naprava je morda zaklenjena. Če je zaklenjena, jo odklenite in poskusite znova."</string>
+</resources>
diff --git a/packages/MtpDocumentsProvider/res/values-sq/strings.xml b/packages/MtpDocumentsProvider/res/values-sq/strings.xml
new file mode 100644
index 000000000000..d92f29f6db60
--- /dev/null
+++ b/packages/MtpDocumentsProvider/res/values-sq/strings.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2015 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="app_label" msgid="6271216747302322594">"Pritësi i protokollit MTP"</string>
+ <string name="downloads_app_label" msgid="7120690641874849726">"Shkarkimet"</string>
+ <string name="root_name" msgid="5819495383921089536">"<xliff:g id="DEVICE_MODEL">%1$s</xliff:g> <xliff:g id="STORAGE_NAME">%2$s</xliff:g>"</string>
+ <string name="accessing_notification_title" msgid="3030133609230917944">"Po qaset te skedarët nga <xliff:g id="DEVICE_MODEL">%1$s</xliff:g>"</string>
+ <string name="error_busy_device" msgid="3997316850357386589">"Pajisja tjetër është e zënë. Nuk mund të transferosh skedarë deri sa të jetë në dispozicion."</string>
+ <string name="error_locked_device" msgid="7557872102188356147">"Nuk u gjet asnjë skedar. Pajisja tjetër mund të jetë e kyçur. Nëse po, shkyçe dhe provo përsëri."</string>
+</resources>
diff --git a/packages/MtpDocumentsProvider/res/values-sr/strings.xml b/packages/MtpDocumentsProvider/res/values-sr/strings.xml
new file mode 100644
index 000000000000..d91c5c4354ce
--- /dev/null
+++ b/packages/MtpDocumentsProvider/res/values-sr/strings.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2015 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="app_label" msgid="6271216747302322594">"MTP хост"</string>
+ <string name="downloads_app_label" msgid="7120690641874849726">"Преузимања"</string>
+ <string name="root_name" msgid="5819495383921089536">"<xliff:g id="DEVICE_MODEL">%1$s</xliff:g> <xliff:g id="STORAGE_NAME">%2$s</xliff:g>"</string>
+ <string name="accessing_notification_title" msgid="3030133609230917944">"Приступ датотекама са уређаја <xliff:g id="DEVICE_MODEL">%1$s</xliff:g>"</string>
+ <string name="error_busy_device" msgid="3997316850357386589">"Други уређај је заузет. Датотеке можете да пренесете тек кад он постане доступан."</string>
+ <string name="error_locked_device" msgid="7557872102188356147">"Није пронађена ниједна датотека. Други уређај је можда закључан. Ако јесте, откључајте га и покушајте поново."</string>
+</resources>
diff --git a/packages/MtpDocumentsProvider/res/values-sv/strings.xml b/packages/MtpDocumentsProvider/res/values-sv/strings.xml
new file mode 100644
index 000000000000..26818eb220ce
--- /dev/null
+++ b/packages/MtpDocumentsProvider/res/values-sv/strings.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2015 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="app_label" msgid="6271216747302322594">"MTP-värd"</string>
+ <string name="downloads_app_label" msgid="7120690641874849726">"Nedladdningar"</string>
+ <string name="root_name" msgid="5819495383921089536">"<xliff:g id="DEVICE_MODEL">%1$s</xliff:g> <xliff:g id="STORAGE_NAME">%2$s</xliff:g>"</string>
+ <string name="accessing_notification_title" msgid="3030133609230917944">"Åtkomst till filer från <xliff:g id="DEVICE_MODEL">%1$s</xliff:g>"</string>
+ <string name="error_busy_device" msgid="3997316850357386589">"Den andra enheten är upptagen. Du kan inte överföra filer förrän den är tillgänglig."</string>
+ <string name="error_locked_device" msgid="7557872102188356147">"Inga filer hittades. Den andra enheten kan vara låst. Om den är det låser du upp den och försöker igen."</string>
+</resources>
diff --git a/packages/MtpDocumentsProvider/res/values-sw/strings.xml b/packages/MtpDocumentsProvider/res/values-sw/strings.xml
new file mode 100644
index 000000000000..de3ed54b367f
--- /dev/null
+++ b/packages/MtpDocumentsProvider/res/values-sw/strings.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2015 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="app_label" msgid="6271216747302322594">"Seva pangishi ya MTP"</string>
+ <string name="downloads_app_label" msgid="7120690641874849726">"Vipakuliwa"</string>
+ <string name="root_name" msgid="5819495383921089536">"<xliff:g id="DEVICE_MODEL">%1$s</xliff:g> <xliff:g id="STORAGE_NAME">%2$s</xliff:g>"</string>
+ <string name="accessing_notification_title" msgid="3030133609230917944">"Inafikia faili kwenye <xliff:g id="DEVICE_MODEL">%1$s</xliff:g>"</string>
+ <string name="error_busy_device" msgid="3997316850357386589">"Kifaa hicho kingine kinatumika. Huwezi kuhamisha faili hadi kipatikane."</string>
+ <string name="error_locked_device" msgid="7557872102188356147">"Hakuna faili zilizopatikana. Huenda kifaa hicho kingine kimefungwa. Ikiwa kimefungwa, kifungue na ujaribu tena."</string>
+</resources>
diff --git a/packages/MtpDocumentsProvider/res/values-ta/strings.xml b/packages/MtpDocumentsProvider/res/values-ta/strings.xml
new file mode 100644
index 000000000000..c6e6e6204e2f
--- /dev/null
+++ b/packages/MtpDocumentsProvider/res/values-ta/strings.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2015 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="app_label" msgid="6271216747302322594">"MTP ஹோஸ்ட்"</string>
+ <string name="downloads_app_label" msgid="7120690641874849726">"இறக்கங்கள்"</string>
+ <string name="root_name" msgid="5819495383921089536">"<xliff:g id="DEVICE_MODEL">%1$s</xliff:g> <xliff:g id="STORAGE_NAME">%2$s</xliff:g>"</string>
+ <string name="accessing_notification_title" msgid="3030133609230917944">"<xliff:g id="DEVICE_MODEL">%1$s</xliff:g> இலிருந்து கோப்புகளை அணுகுகிறது"</string>
+ <string name="error_busy_device" msgid="3997316850357386589">"பிற சாதனம் பணிமிகுதியில் உள்ளதால், அந்தப் பணி முடியும் வரை கோப்புகளை இடமாற்ற முடியாது."</string>
+ <string name="error_locked_device" msgid="7557872102188356147">"கோப்புகள் இல்லை. பிற சாதனம் பூட்டப்பட்டிருக்கக்கூடும் என்பதால் முதலில் அதைத் திறந்து, மீண்டும் முயலவும்."</string>
+</resources>
diff --git a/packages/MtpDocumentsProvider/res/values-te/strings.xml b/packages/MtpDocumentsProvider/res/values-te/strings.xml
new file mode 100644
index 000000000000..7add85835da7
--- /dev/null
+++ b/packages/MtpDocumentsProvider/res/values-te/strings.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2015 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="app_label" msgid="6271216747302322594">"MTP హోస్ట్"</string>
+ <string name="downloads_app_label" msgid="7120690641874849726">"డౌన్‌లోడ్‌లు"</string>
+ <string name="root_name" msgid="5819495383921089536">"<xliff:g id="DEVICE_MODEL">%1$s</xliff:g> <xliff:g id="STORAGE_NAME">%2$s</xliff:g>"</string>
+ <string name="accessing_notification_title" msgid="3030133609230917944">"<xliff:g id="DEVICE_MODEL">%1$s</xliff:g> నుండి ఫైల్‌లను ప్రాప్యత చేస్తోంది"</string>
+ <string name="error_busy_device" msgid="3997316850357386589">"ఇతర పరికరం బిజీగా ఉంది. అది అందుబాటులోకి వచ్చే వరకు మీరు ఫైల్‌లను బదిలీ చేయలేరు."</string>
+ <string name="error_locked_device" msgid="7557872102188356147">"ఫైల్‍లు ఏవీ కనుగొనబడలేదు. ఇతర పరికరం లాక్ చేయబడి ఉండవచ్చు. అలా జరిగి ఉంటే, దాన్ని అన్‌లాక్ చేసి, ఆపై మళ్లీ ప్రయత్నించండి."</string>
+</resources>
diff --git a/packages/MtpDocumentsProvider/res/values-th/strings.xml b/packages/MtpDocumentsProvider/res/values-th/strings.xml
new file mode 100644
index 000000000000..d2b62fe516e1
--- /dev/null
+++ b/packages/MtpDocumentsProvider/res/values-th/strings.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2015 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="app_label" msgid="6271216747302322594">"โฮสต์ MTP"</string>
+ <string name="downloads_app_label" msgid="7120690641874849726">"ดาวน์โหลด"</string>
+ <string name="root_name" msgid="5819495383921089536">"<xliff:g id="DEVICE_MODEL">%1$s</xliff:g> <xliff:g id="STORAGE_NAME">%2$s</xliff:g>"</string>
+ <string name="accessing_notification_title" msgid="3030133609230917944">"กำลังเข้าถึงไฟล์จาก <xliff:g id="DEVICE_MODEL">%1$s</xliff:g>"</string>
+ <string name="error_busy_device" msgid="3997316850357386589">"อุปกรณ์อีกเครื่องหนึ่งไม่ว่าง คุณไม่สามารถโอนไฟล์จนกว่าอุปกรณ์จะสามารถใช้ได้"</string>
+ <string name="error_locked_device" msgid="7557872102188356147">"ไม่พบไฟล์ อุปกรณ์อีกเครื่องหนึ่งอาจล็อกอยู่ หากเป็นเช่นนั้น ให้ปลดล็อกและลองอีกครั้ง"</string>
+</resources>
diff --git a/packages/MtpDocumentsProvider/res/values-tl/strings.xml b/packages/MtpDocumentsProvider/res/values-tl/strings.xml
new file mode 100644
index 000000000000..68b2eba38ea3
--- /dev/null
+++ b/packages/MtpDocumentsProvider/res/values-tl/strings.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2015 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="app_label" msgid="6271216747302322594">"Host ng MTP"</string>
+ <string name="downloads_app_label" msgid="7120690641874849726">"Mga Download"</string>
+ <string name="root_name" msgid="5819495383921089536">"<xliff:g id="DEVICE_MODEL">%1$s</xliff:g> <xliff:g id="STORAGE_NAME">%2$s</xliff:g>"</string>
+ <string name="accessing_notification_title" msgid="3030133609230917944">"Nag-a-access ng mga file mula sa <xliff:g id="DEVICE_MODEL">%1$s</xliff:g>"</string>
+ <string name="error_busy_device" msgid="3997316850357386589">"Abala ang kabilang device. Hindi ka makakapaglipat ng mga file hanggang sa maging available ito."</string>
+ <string name="error_locked_device" msgid="7557872102188356147">"Walang natagpuang mga file. Maaaring naka-lock ang kabilang device. Kung gayon, i-unlock ito at subukang muli."</string>
+</resources>
diff --git a/packages/MtpDocumentsProvider/res/values-tr/strings.xml b/packages/MtpDocumentsProvider/res/values-tr/strings.xml
new file mode 100644
index 000000000000..14250ef527c7
--- /dev/null
+++ b/packages/MtpDocumentsProvider/res/values-tr/strings.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2015 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="app_label" msgid="6271216747302322594">"MTP Ana Makinesi"</string>
+ <string name="downloads_app_label" msgid="7120690641874849726">"İndirilenler"</string>
+ <string name="root_name" msgid="5819495383921089536">"<xliff:g id="DEVICE_MODEL">%1$s</xliff:g> <xliff:g id="STORAGE_NAME">%2$s</xliff:g>"</string>
+ <string name="accessing_notification_title" msgid="3030133609230917944">"<xliff:g id="DEVICE_MODEL">%1$s</xliff:g> cihazdaki dosyalara erişiliyor"</string>
+ <string name="error_busy_device" msgid="3997316850357386589">"Diğer cihaz meşgul. Cihaz kullanılabilir duruma gelene kadar dosyaları aktaramazsınız."</string>
+ <string name="error_locked_device" msgid="7557872102188356147">"Hiçbir dosya bulunamadı. Diğer cihaz kilitli olabilir. Kilitliyse, kilidini açıp tekrar deneyin."</string>
+</resources>
diff --git a/packages/MtpDocumentsProvider/res/values-uk/strings.xml b/packages/MtpDocumentsProvider/res/values-uk/strings.xml
new file mode 100644
index 000000000000..8589f8c594b6
--- /dev/null
+++ b/packages/MtpDocumentsProvider/res/values-uk/strings.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2015 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="app_label" msgid="6271216747302322594">"Хост MTP"</string>
+ <string name="downloads_app_label" msgid="7120690641874849726">"Завантаження"</string>
+ <string name="root_name" msgid="5819495383921089536">"<xliff:g id="DEVICE_MODEL">%1$s</xliff:g> <xliff:g id="STORAGE_NAME">%2$s</xliff:g>"</string>
+ <string name="accessing_notification_title" msgid="3030133609230917944">"Відкриваються файли з пристрою <xliff:g id="DEVICE_MODEL">%1$s</xliff:g>"</string>
+ <string name="error_busy_device" msgid="3997316850357386589">"Інший пристрій зайнятий. Щоб передавати файли, він має бути доступним."</string>
+ <string name="error_locked_device" msgid="7557872102188356147">"Не вдалося знайти файли. Можливо, інший пристрій заблоковано. У такому разі розблокуйте його та повторіть спробу."</string>
+</resources>
diff --git a/packages/MtpDocumentsProvider/res/values-ur/strings.xml b/packages/MtpDocumentsProvider/res/values-ur/strings.xml
new file mode 100644
index 000000000000..17578ae51b9f
--- /dev/null
+++ b/packages/MtpDocumentsProvider/res/values-ur/strings.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2015 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="app_label" msgid="6271216747302322594">"‏MTP میزبان"</string>
+ <string name="downloads_app_label" msgid="7120690641874849726">"ڈاؤن لوڈز"</string>
+ <string name="root_name" msgid="5819495383921089536">"<xliff:g id="DEVICE_MODEL">%1$s</xliff:g> <xliff:g id="STORAGE_NAME">%2$s</xliff:g>"</string>
+ <string name="accessing_notification_title" msgid="3030133609230917944">"<xliff:g id="DEVICE_MODEL">%1$s</xliff:g> سے فائلوں کی رسائی ہو رہی ہے"</string>
+ <string name="error_busy_device" msgid="3997316850357386589">"دوسرا آلہ مصروف ہے۔ اس کے دستیاب ہونے تک آپ فائلیں منتقل نہیں کر سکتے۔"</string>
+ <string name="error_locked_device" msgid="7557872102188356147">"کوئی فائلیں نہیں ملیں۔ ہو سکتا ہے دوسرا آلہ مقفل ہو۔ اگر ایسا ہے تو اسے غیر مقفل کریں اور دوبارہ کوشش کریں۔"</string>
+</resources>
diff --git a/packages/MtpDocumentsProvider/res/values-uz/strings.xml b/packages/MtpDocumentsProvider/res/values-uz/strings.xml
new file mode 100644
index 000000000000..c511172076c0
--- /dev/null
+++ b/packages/MtpDocumentsProvider/res/values-uz/strings.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2015 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="app_label" msgid="6271216747302322594">"MTP Host"</string>
+ <string name="downloads_app_label" msgid="7120690641874849726">"Yuklanmalar"</string>
+ <string name="root_name" msgid="5819495383921089536">"<xliff:g id="DEVICE_MODEL">%1$s</xliff:g><xliff:g id="STORAGE_NAME">%2$s</xliff:g>"</string>
+ <string name="accessing_notification_title" msgid="3030133609230917944">"<xliff:g id="DEVICE_MODEL">%1$s</xliff:g> qurilmasidan fayllar o‘qilmoqda"</string>
+ <string name="error_busy_device" msgid="3997316850357386589">"Ulangan qurilma band. U bo‘shamaguncha fayllarni o‘tkazib bo‘lmaydi."</string>
+ <string name="error_locked_device" msgid="7557872102188356147">"Hech qanday fayl topilmadi. Ulangan qurilma qulflangan bo‘lishi mumkin. Agar shunday bo‘lsa, uni qulfdan chiqaring va qayta urinib ko‘ring."</string>
+</resources>
diff --git a/packages/MtpDocumentsProvider/res/values-vi/strings.xml b/packages/MtpDocumentsProvider/res/values-vi/strings.xml
new file mode 100644
index 000000000000..0eb63106d85e
--- /dev/null
+++ b/packages/MtpDocumentsProvider/res/values-vi/strings.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2015 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="app_label" msgid="6271216747302322594">"Máy chủ MTP"</string>
+ <string name="downloads_app_label" msgid="7120690641874849726">"Tải xuống"</string>
+ <string name="root_name" msgid="5819495383921089536">"<xliff:g id="DEVICE_MODEL">%1$s</xliff:g> <xliff:g id="STORAGE_NAME">%2$s</xliff:g>"</string>
+ <string name="accessing_notification_title" msgid="3030133609230917944">"Đang truy cập tệp từ <xliff:g id="DEVICE_MODEL">%1$s</xliff:g>"</string>
+ <string name="error_busy_device" msgid="3997316850357386589">"Thiết bị khác đang bận. Bạn không thể chuyển tệp cho đến khi thiết bị rảnh."</string>
+ <string name="error_locked_device" msgid="7557872102188356147">"Không tìm thấy tệp. Thiết bị khác có thể đã bị khóa. Nếu như vậy, hãy mở khóa thiết bị rồi thử lại."</string>
+</resources>
diff --git a/packages/MtpDocumentsProvider/res/values-zh-rCN/strings.xml b/packages/MtpDocumentsProvider/res/values-zh-rCN/strings.xml
new file mode 100644
index 000000000000..7f1f3942c911
--- /dev/null
+++ b/packages/MtpDocumentsProvider/res/values-zh-rCN/strings.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2015 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="app_label" msgid="6271216747302322594">"MTP 主机"</string>
+ <string name="downloads_app_label" msgid="7120690641874849726">"下载"</string>
+ <string name="root_name" msgid="5819495383921089536">"<xliff:g id="DEVICE_MODEL">%1$s</xliff:g> <xliff:g id="STORAGE_NAME">%2$s</xliff:g>"</string>
+ <string name="accessing_notification_title" msgid="3030133609230917944">"正在访问 <xliff:g id="DEVICE_MODEL">%1$s</xliff:g> 的文件"</string>
+ <string name="error_busy_device" msgid="3997316850357386589">"另一台设备正忙。您必须等到该设备可用时才能传输文件。"</string>
+ <string name="error_locked_device" msgid="7557872102188356147">"未找到任何文件。另一台设备可能处于锁定状态;如果是这样,请解锁该设备并重试。"</string>
+</resources>
diff --git a/packages/MtpDocumentsProvider/res/values-zh-rHK/strings.xml b/packages/MtpDocumentsProvider/res/values-zh-rHK/strings.xml
new file mode 100644
index 000000000000..be8c5482c13c
--- /dev/null
+++ b/packages/MtpDocumentsProvider/res/values-zh-rHK/strings.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2015 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="app_label" msgid="6271216747302322594">"媒體傳輸協定主機"</string>
+ <string name="downloads_app_label" msgid="7120690641874849726">"下載"</string>
+ <string name="root_name" msgid="5819495383921089536">"<xliff:g id="DEVICE_MODEL">%1$s</xliff:g> 的「<xliff:g id="STORAGE_NAME">%2$s</xliff:g>」"</string>
+ <string name="accessing_notification_title" msgid="3030133609230917944">"正在從 <xliff:g id="DEVICE_MODEL">%1$s</xliff:g> 存取檔案"</string>
+ <string name="error_busy_device" msgid="3997316850357386589">"另一部裝置目前處於忙碌狀態,要等到該裝置可用時才能轉移檔案。"</string>
+ <string name="error_locked_device" msgid="7557872102188356147">"找不到檔案。如果另一部裝置處於鎖定狀態,請解鎖該裝置,然後再試一次。"</string>
+</resources>
diff --git a/packages/MtpDocumentsProvider/res/values-zh-rTW/strings.xml b/packages/MtpDocumentsProvider/res/values-zh-rTW/strings.xml
new file mode 100644
index 000000000000..2fe3c06898e0
--- /dev/null
+++ b/packages/MtpDocumentsProvider/res/values-zh-rTW/strings.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2015 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="app_label" msgid="6271216747302322594">"媒體傳輸通訊協定主機"</string>
+ <string name="downloads_app_label" msgid="7120690641874849726">"下載"</string>
+ <string name="root_name" msgid="5819495383921089536">"<xliff:g id="DEVICE_MODEL">%1$s</xliff:g> <xliff:g id="STORAGE_NAME">%2$s</xliff:g>"</string>
+ <string name="accessing_notification_title" msgid="3030133609230917944">"正在從 <xliff:g id="DEVICE_MODEL">%1$s</xliff:g> 存取檔案"</string>
+ <string name="error_busy_device" msgid="3997316850357386589">"另一個裝置忙碌中。必須等到該裝置可用時才能轉移檔案。"</string>
+ <string name="error_locked_device" msgid="7557872102188356147">"找不到任何檔案。如果另一個裝置處於鎖定狀態,請將該裝置解鎖後再試一次。"</string>
+</resources>
diff --git a/packages/MtpDocumentsProvider/res/values-zu/strings.xml b/packages/MtpDocumentsProvider/res/values-zu/strings.xml
new file mode 100644
index 000000000000..f3f720676b22
--- /dev/null
+++ b/packages/MtpDocumentsProvider/res/values-zu/strings.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2015 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="app_label" msgid="6271216747302322594">"Ukusingatha kwe-MTP"</string>
+ <string name="downloads_app_label" msgid="7120690641874849726">"Okulandiwe"</string>
+ <string name="root_name" msgid="5819495383921089536">"<xliff:g id="DEVICE_MODEL">%1$s</xliff:g> <xliff:g id="STORAGE_NAME">%2$s</xliff:g>"</string>
+ <string name="accessing_notification_title" msgid="3030133609230917944">"Ifinyelela kumafayela kusukela ku-<xliff:g id="DEVICE_MODEL">%1$s</xliff:g>"</string>
+ <string name="error_busy_device" msgid="3997316850357386589">"Enye idivayisi imatasatasa. Awukwazi ukudlulisela amafayela ize itholakale."</string>
+ <string name="error_locked_device" msgid="7557872102188356147">"Awekho amafayela atholiwe. Enye idivayisi kungenzeka ikhiyiwe. Uma kunjalo, yivule uphinde uzame futhi."</string>
+</resources>
diff --git a/packages/SettingsLib/src/com/android/settingslib/core/AbstractPreferenceController.java b/packages/SettingsLib/src/com/android/settingslib/core/AbstractPreferenceController.java
index fc1a3a902c73..38fe8790e4d0 100644
--- a/packages/SettingsLib/src/com/android/settingslib/core/AbstractPreferenceController.java
+++ b/packages/SettingsLib/src/com/android/settingslib/core/AbstractPreferenceController.java
@@ -4,7 +4,6 @@ import android.content.Context;
import android.support.v7.preference.Preference;
import android.support.v7.preference.PreferenceGroup;
import android.support.v7.preference.PreferenceScreen;
-import java.util.List;
/**
* A controller that manages event for preference.
@@ -40,17 +39,6 @@ public abstract class AbstractPreferenceController {
}
/**
- * Updates non-indexable keys for search provider.
- *
- * Called by SearchIndexProvider#getNonIndexableKeys
- */
- public void updateNonIndexableKeys(List<String> keys) {
- if (!isAvailable()) {
- keys.add(getPreferenceKey());
- }
- }
-
- /**
* Returns true if preference is available (should be displayed)
*/
public abstract boolean isAvailable();
diff --git a/packages/SettingsLib/src/com/android/settingslib/graph/BatteryMeterDrawableBase.java b/packages/SettingsLib/src/com/android/settingslib/graph/BatteryMeterDrawableBase.java
index 1bb141706736..924a82f0b1f4 100755
--- a/packages/SettingsLib/src/com/android/settingslib/graph/BatteryMeterDrawableBase.java
+++ b/packages/SettingsLib/src/com/android/settingslib/graph/BatteryMeterDrawableBase.java
@@ -28,6 +28,7 @@ import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.Path.Direction;
import android.graphics.Path.FillType;
+import android.graphics.Rect;
import android.graphics.RectF;
import android.graphics.Typeface;
import android.graphics.drawable.Drawable;
@@ -82,6 +83,7 @@ public class BatteryMeterDrawableBase extends Drawable {
private final float[] mPlusPoints;
private final Path mPlusPath = new Path();
+ private final Rect mPadding = new Rect();
private final RectF mFrame = new RectF();
private final RectF mButtonFrame = new RectF();
private final RectF mBoltFrame = new RectF();
@@ -219,12 +221,40 @@ public class BatteryMeterDrawableBase extends Drawable {
@Override
public void setBounds(int left, int top, int right, int bottom) {
super.setBounds(left, top, right, bottom);
- mHeight = bottom - top;
- mWidth = right - left;
+ updateSize();
+ }
+
+ private void updateSize() {
+ final Rect bounds = getBounds();
+
+ mHeight = (bounds.bottom - mPadding.bottom) - (bounds.top + mPadding.top);
+ mWidth = (bounds.right - mPadding.right) - (bounds.left + mPadding.left);
mWarningTextPaint.setTextSize(mHeight * 0.75f);
mWarningTextHeight = -mWarningTextPaint.getFontMetrics().ascent;
}
+ @Override
+ public boolean getPadding(Rect padding) {
+ if (mPadding.left == 0
+ && mPadding.top == 0
+ && mPadding.right == 0
+ && mPadding.bottom == 0) {
+ return super.getPadding(padding);
+ }
+
+ padding.set(mPadding);
+ return true;
+ }
+
+ public void setPadding(int left, int top, int right, int bottom) {
+ mPadding.left = left;
+ mPadding.top = top;
+ mPadding.right = right;
+ mPadding.bottom = bottom;
+
+ updateSize();
+ }
+
private int getColorForLevel(int percent) {
// If we are in power save mode, always use the normal color.
if (mPowerSaveEnabled) {
@@ -255,6 +285,10 @@ public class BatteryMeterDrawableBase extends Drawable {
invalidateSelf();
}
+ protected int batteryColorForLevel(int level) {
+ return mCharging ? mChargeColor : getColorForLevel(level);
+ }
+
@Override
public void draw(Canvas c) {
final int level = mLevel;
@@ -264,11 +298,10 @@ public class BatteryMeterDrawableBase extends Drawable {
float drawFrac = (float) level / 100f;
final int height = mHeight;
final int width = (int) (ASPECT_RATIO * mHeight);
- int px = (mWidth - width) / 2;
-
+ final int px = (mWidth - width) / 2;
final int buttonHeight = Math.round(height * mButtonHeightFraction);
- mFrame.set(0, 0, width, height);
+ mFrame.set(mPadding.left, mPadding.top, width + mPadding.left, height + mPadding.top);
mFrame.offset(px, 0);
// button-frame: area above the battery body
@@ -282,7 +315,7 @@ public class BatteryMeterDrawableBase extends Drawable {
mFrame.top += buttonHeight;
// set the battery charging color
- mBatteryPaint.setColor(mCharging ? mChargeColor : getColorForLevel(level));
+ mBatteryPaint.setColor(batteryColorForLevel(level));
if (level >= FULL) {
drawFrac = 1f;
diff --git a/packages/SettingsLib/tests/integ/src/com/android/settingslib/graph/BatteryMeterDrawableBaseTest.java b/packages/SettingsLib/tests/integ/src/com/android/settingslib/graph/BatteryMeterDrawableBaseTest.java
index 83667ea00629..aa92fa40a91b 100644
--- a/packages/SettingsLib/tests/integ/src/com/android/settingslib/graph/BatteryMeterDrawableBaseTest.java
+++ b/packages/SettingsLib/tests/integ/src/com/android/settingslib/graph/BatteryMeterDrawableBaseTest.java
@@ -3,6 +3,7 @@ package com.android.settingslib.graph;
import android.content.Context;
import android.content.res.Resources;
import android.graphics.Canvas;
+import android.graphics.Rect;
import android.support.test.InstrumentationRegistry;
import android.support.test.filters.SmallTest;
import android.support.test.runner.AndroidJUnit4;
@@ -68,4 +69,36 @@ public class BatteryMeterDrawableBaseTest {
}
}
}
+
+ @Test
+ public void testPadding_returnsCorrectValues() {
+ // different pads on each side to differentiate
+ final int left = 1;
+ final int top = 2;
+ final int right = 3;
+ final int bottom = 4;
+
+ final Rect expected = new Rect(left, top, right, bottom);
+ final Rect padding = new Rect();
+
+ mBatteryDrawable.setPadding(left, top, right, bottom);
+
+ assertThat(mBatteryDrawable.getPadding(padding)).isEqualTo(true);
+ assertThat(padding).isEqualTo(expected);
+ }
+
+ @Test
+ public void testPadding_falseIfUnsetOrZero() {
+ final Rect padding = new Rect();
+ assertThat(mBatteryDrawable.getPadding(padding)).isEqualTo(false);
+ assertThat(isRectZero(padding)).isEqualTo(true);
+
+ mBatteryDrawable.setPadding(0, 0, 0, 0);
+ assertThat(mBatteryDrawable.getPadding(padding)).isEqualTo(false);
+ assertThat(isRectZero(padding)).isEqualTo(true);
+ }
+
+ private boolean isRectZero(Rect r) {
+ return r.left == 0 && r.top == 0 && r.right == 0 && r.bottom == 0;
+ }
}
diff --git a/packages/Shell/res/layout/dialog_bugreport_info.xml b/packages/Shell/res/layout/dialog_bugreport_info.xml
index bb3084f5c10a..4bd871103193 100644
--- a/packages/Shell/res/layout/dialog_bugreport_info.xml
+++ b/packages/Shell/res/layout/dialog_bugreport_info.xml
@@ -19,39 +19,51 @@
android:paddingTop="15dp"
android:paddingStart="24dp"
android:paddingEnd="24dp"
- android:focusableInTouchMode="true"
+ android:focusableInTouchMode="false"
+ android:focusable="false"
+ android:importantForAutofill="noExcludeDescendants"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<TextView
+ android:focusableInTouchMode="false"
+ android:focusable="false"
android:inputType="textNoSuggestions"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/bugreport_info_name"/>
<EditText
android:id="@+id/name"
+ android:nextFocusDown="@+id/title"
android:maxLength="30"
android:singleLine="true"
android:inputType="textNoSuggestions"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
<TextView
+ android:focusableInTouchMode="false"
+ android:focusable="false"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/bugreport_info_title"/>
<EditText
android:id="@+id/title"
+ android:nextFocusUp="@+id/name"
+ android:nextFocusDown="@+id/description"
android:maxLength="80"
android:singleLine="true"
android:inputType="textAutoCorrect|textCapSentences"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
<TextView
+ android:focusableInTouchMode="false"
+ android:focusable="false"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:editable="false"
android:text="@string/bugreport_info_description"/>
<EditText
android:id="@+id/description"
+ android:nextFocusUp="@+id/title"
android:singleLine="false"
android:inputType="textMultiLine|textAutoCorrect|textCapSentences"
android:layout_width="match_parent"
diff --git a/packages/SystemUI/colorextraction/src/com/google/android/colorextraction/types/Tonal.java b/packages/SystemUI/colorextraction/src/com/google/android/colorextraction/types/Tonal.java
index d9719f356f14..f59c4a56bf3b 100644
--- a/packages/SystemUI/colorextraction/src/com/google/android/colorextraction/types/Tonal.java
+++ b/packages/SystemUI/colorextraction/src/com/google/android/colorextraction/types/Tonal.java
@@ -29,6 +29,7 @@ import android.util.Range;
import com.google.android.colorextraction.ColorExtractor.GradientColors;
+import java.util.Arrays;
import java.util.List;
/**
@@ -311,6 +312,12 @@ public class Tonal implements ExtractionType {
final float maxHue;
TonalPalette(float[] h, float[] s, float[] l) {
+ if (h.length != s.length || s.length != l.length) {
+ throw new IllegalArgumentException("All arrays should have the same size. h: "
+ + Arrays.toString(h) + " s: " + Arrays.toString(s) + " l: "
+ + Arrays.toString(l));
+ }
+
this.h = h;
this.s = s;
this.l = l;
@@ -388,7 +395,7 @@ public class Tonal implements ExtractionType {
new float[] {0.70f, 0.72f, 0.69f, 0.6703296703296703f, 0.728813559322034f,
0.5657142857142856f, 0.5076923076923077f, 0.3944223107569721f,
0.6206896551724138f, 0.8931297709923666f, 1f, 1f, 1f},
- new float[] {0.05f, 0.08f, 0.1784313725490196f, 0.23137254901960785f,
+ new float[] {0.05f, 0.08f, 0.14f, 0.1784313725490196f, 0.23137254901960785f,
0.3431372549019608f, 0.38235294117647056f, 0.49215686274509807f,
0.6588235294117647f, 0.7431372549019608f, 0.8176470588235294f,
0.8784313725490196f, 0.9294117647058824f}
@@ -442,7 +449,7 @@ public class Tonal implements ExtractionType {
0.8285256410256411f, 0.821522309711286f, 0.8083333333333333f,
0.8046594982078853f, 0.8005822416302766f, 0.7842377260981912f,
0.7771084337349398f, 0.7747747747747749f},
- new float[] {1f, 1f, 1f, 1f, 1f, 1f, 1f, 1f,
+ new float[] {1f, 1f, 1f, 1f, 1f, 1f, 1f, 1f, 1f,
0.737142857142857f, 0.6434108527131781f, 0.46835443037974644f},
new float[] {0.05f, 0.08f, 0.12745098039215685f, 0.15490196078431373f,
0.20392156862745098f, 0.24901960784313726f, 0.3137254901960784f,
diff --git a/packages/SystemUI/src/com/android/keyguard/PasswordTextView.java b/packages/SystemUI/src/com/android/keyguard/PasswordTextView.java
index d8bebabf0c5e..12f75bb2d56c 100644
--- a/packages/SystemUI/src/com/android/keyguard/PasswordTextView.java
+++ b/packages/SystemUI/src/com/android/keyguard/PasswordTextView.java
@@ -29,10 +29,8 @@ import android.graphics.Rect;
import android.graphics.Typeface;
import android.os.PowerManager;
import android.os.SystemClock;
-import android.os.UserHandle;
import android.provider.Settings;
import android.text.InputType;
-import android.text.TextUtils;
import android.util.AttributeSet;
import android.view.Gravity;
import android.view.View;
@@ -252,9 +250,9 @@ public class PasswordTextView extends View {
mText = mText.substring(0, length - 1);
CharState charState = mTextChars.get(length - 1);
charState.startRemoveAnimation(0, 0);
+ sendAccessibilityEventTypeViewTextChanged(textbefore, textbefore.length() - 1, 1, 0);
}
userActivity();
- sendAccessibilityEventTypeViewTextChanged(textbefore, textbefore.length() - 1, 1, 0);
}
public String getText() {
diff --git a/packages/SystemUI/src/com/android/systemui/RoundedCorners.java b/packages/SystemUI/src/com/android/systemui/RoundedCorners.java
index 14e15ec5716d..5ea18f22fbc9 100644
--- a/packages/SystemUI/src/com/android/systemui/RoundedCorners.java
+++ b/packages/SystemUI/src/com/android/systemui/RoundedCorners.java
@@ -98,9 +98,13 @@ public class RoundedCorners extends SystemUI implements Tunable {
TunablePadding.addTunablePadding(statusBar.findViewById(R.id.keyguard_header), PADDING,
padding, FLAG_END);
- FragmentHostManager.get(sb.getNavigationBarWindow()).addTagListener(
+ View navigationBarWindow = sb.getNavigationBarWindow();
+ // Not all devices have on screen navigation bars.
+ if (navigationBarWindow != null) {
+ FragmentHostManager.get(navigationBarWindow).addTagListener(
NavigationBarFragment.TAG,
new TunablePaddingTagListener(padding, 0));
+ }
FragmentHostManager fragmentHostManager = FragmentHostManager.get(statusBar);
fragmentHostManager.addTagListener(CollapsedStatusBarFragment.TAG,
diff --git a/packages/SystemUI/src/com/android/systemui/SystemUIApplication.java b/packages/SystemUI/src/com/android/systemui/SystemUIApplication.java
index 4a459974fcb6..9034c3fd926e 100644
--- a/packages/SystemUI/src/com/android/systemui/SystemUIApplication.java
+++ b/packages/SystemUI/src/com/android/systemui/SystemUIApplication.java
@@ -26,8 +26,10 @@ import android.content.pm.ApplicationInfo;
import android.content.res.Configuration;
import android.os.Process;
import android.os.SystemProperties;
+import android.os.Trace;
import android.os.UserHandle;
import android.util.ArraySet;
+import android.util.BootTimingsTraceLog;
import android.util.Log;
import com.android.systemui.fragments.FragmentService;
@@ -190,11 +192,17 @@ public class SystemUIApplication extends Application implements SysUiServiceProv
Log.v(TAG, "Starting SystemUI services for user " +
Process.myUserHandle().getIdentifier() + ".");
+ BootTimingsTraceLog log = new BootTimingsTraceLog("SystemUIBootTiming",
+ Trace.TRACE_TAG_APP);
+ log.traceBegin("StartServices");
final int N = services.length;
for (int i = 0; i < N; i++) {
Class<?> cl = services[i];
if (DEBUG) Log.d(TAG, "loading: " + cl);
+ log.traceBegin("StartServices" + cl.getSimpleName());
+ long ti = System.currentTimeMillis();
try {
+
Object newService = SystemUIFactory.getInstance().createInstance(cl);
mServices[i] = (SystemUI) ((newService == null) ? cl.newInstance() : newService);
} catch (IllegalAccessException ex) {
@@ -207,11 +215,18 @@ public class SystemUIApplication extends Application implements SysUiServiceProv
mServices[i].mComponents = mComponents;
if (DEBUG) Log.d(TAG, "running: " + mServices[i]);
mServices[i].start();
+ log.traceEnd();
+ // Warn if initialization of component takes too long
+ ti = System.currentTimeMillis() - ti;
+ if (ti > 1000) {
+ Log.w(TAG, "Initialization of " + cl.getName() + " took " + ti + " ms");
+ }
if (mBootCompleted) {
mServices[i].onBootCompleted();
}
}
+ log.traceEnd();
Dependency.get(PluginManager.class).addPluginListener(
new PluginListener<OverlayPlugin>() {
private ArraySet<OverlayPlugin> mOverlays;
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSAnimator.java b/packages/SystemUI/src/com/android/systemui/qs/QSAnimator.java
index 6b507645e4d0..8f1880039857 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSAnimator.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSAnimator.java
@@ -161,7 +161,8 @@ public class QSAnimator implements Callback, PageListener, Listener, OnLayoutCha
QSTileLayout tileLayout = mQsPanel.getTileLayout();
mAllViews.add((View) tileLayout);
- int heightDiff = mQsPanel.getBottom() - mQs.getHeader().getBottom()
+ int height = mQs.getView() != null ? mQs.getView().getMeasuredHeight() : 0;
+ int heightDiff = height - mQs.getHeader().getBottom()
+ mQs.getHeader().getPaddingBottom();
firstPageBuilder.addFloat(tileLayout, "translationY", heightDiff, 0);
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java b/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java
index 90275c50b54a..bb3672511c48 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java
@@ -253,7 +253,8 @@ public class QSFragment extends Fragment implements QS {
}
mHeader.setExpansion(mKeyguardShowing ? 1 : expansion);
mFooter.setExpansion(mKeyguardShowing ? 1 : expansion);
- int heightDiff = mQSPanel.getBottom() - mHeader.getBottom() + mHeader.getPaddingBottom();
+ int heightDiff = mQSPanel.getBottom() - mHeader.getBottom() + mHeader.getPaddingBottom()
+ + mFooter.getHeight();
mQSPanel.setTranslationY(translationScaleY * heightDiff);
mQSDetail.setFullyExpanded(expansion == 1);
@@ -262,7 +263,7 @@ public class QSFragment extends Fragment implements QS {
}
// Set bounds on the QS panel so it doesn't run over the header.
- mQsBounds.top = (int) (mQSPanel.getHeight() * (1 - expansion));
+ mQsBounds.top = (int) -mQSPanel.getTranslationY();
mQsBounds.right = mQSPanel.getWidth();
mQsBounds.bottom = mQSPanel.getHeight();
mQSPanel.setClipBounds(mQsBounds);
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/BatterySaverTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/BatterySaverTile.java
index 918c00c2337f..089d07a567dd 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/BatterySaverTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/BatterySaverTile.java
@@ -15,10 +15,13 @@
*/
package com.android.systemui.qs.tiles;
+import android.content.Context;
import android.content.Intent;
+import android.graphics.drawable.Drawable;
import android.service.quicksettings.Tile;
import android.widget.Switch;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
+import com.android.settingslib.graph.BatteryMeterDrawableBase;
import com.android.systemui.Dependency;
import com.android.systemui.R;
import com.android.systemui.plugins.qs.QSTile.BooleanState;
@@ -79,7 +82,9 @@ public class BatterySaverTile extends QSTileImpl<BooleanState> implements
protected void handleUpdateState(BooleanState state, Object arg) {
state.state = mCharging ? Tile.STATE_UNAVAILABLE
: mPowerSave ? Tile.STATE_ACTIVE : Tile.STATE_INACTIVE;
- state.icon = ResourceIcon.get(R.drawable.ic_qs_battery_saver);
+ BatterySaverIcon bsi = new BatterySaverIcon();
+ bsi.mState = state.state;
+ state.icon = bsi;
state.label = mContext.getString(R.string.battery_detail_switch_title);
state.contentDescription = state.label;
state.value = mPowerSave;
@@ -99,4 +104,41 @@ public class BatterySaverTile extends QSTileImpl<BooleanState> implements
mPowerSave = isPowerSave;
refreshState(null);
}
-} \ No newline at end of file
+
+ public static class BatterySaverIcon extends Icon {
+ private int mState;
+
+ @Override
+ public Drawable getDrawable(Context context) {
+ BatterySaverDrawable b = new BatterySaverDrawable(context, 0);
+ b.mState = mState;
+ final int pad = context.getResources()
+ .getDimensionPixelSize(R.dimen.qs_tile_divider_height);
+ b.setPadding(pad, pad, pad, pad);
+ return b;
+ }
+ }
+
+ private static class BatterySaverDrawable extends BatteryMeterDrawableBase {
+ private int mState;
+ private static final int MAX_BATTERY = 100;
+
+ BatterySaverDrawable(Context context, int frameColor) {
+ super(context, frameColor);
+ // Show as full so it's always uniform color
+ super.setBatteryLevel(MAX_BATTERY);
+ setPowerSave(true);
+ setCharging(false);
+ }
+
+ @Override
+ protected int batteryColorForLevel(int level) {
+ return QSTileImpl.getColorForState(mContext, mState);
+ }
+
+ @Override
+ public void setBatteryLevel(int val) {
+ // Don't change the actual level, otherwise this won't draw correctly
+ }
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonView.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonView.java
index d77796144282..2d3e0b6829ca 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonView.java
@@ -226,6 +226,9 @@ public class KeyButtonView extends ImageView implements ButtonInterface {
case MotionEvent.ACTION_UP:
final boolean doIt = isPressed() && !mLongClicked;
setPressed(false);
+ // Always send a release ourselves because it doesn't seem to be sent elsewhere
+ // and it feels weird to sometimes get a release haptic and other times not.
+ performHapticFeedback(HapticFeedbackConstants.VIRTUAL_KEY_RELEASE);
if (mCode != 0) {
if (doIt) {
sendEvent(KeyEvent.ACTION_UP, 0);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java
index bd7fee0f7f52..b6c76551c48b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java
@@ -341,6 +341,10 @@ public class MobileSignalController extends SignalController<
}
private boolean isRoaming() {
+ // During a carrier change, roaming indications need to be supressed.
+ if (isCarrierNetworkChangeActive()) {
+ return false;
+ }
if (isCdma()) {
final int iconMode = mServiceState.getCdmaEriIconMode();
return mServiceState.getCdmaEriIconIndex() != EriInfo.ROAMING_INDICATOR_OFF
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerSignalTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerSignalTest.java
index be3802bd68ed..cba9f77df2ff 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerSignalTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerSignalTest.java
@@ -494,6 +494,79 @@ public class NetworkControllerSignalTest extends NetworkControllerBaseTest {
DEFAULT_ICON /* typeIcon */);
}
+ @Test
+ public void testCarrierNetworkChange_roamingBeforeNetworkChange() {
+ int strength = SignalStrength.SIGNAL_STRENGTH_GREAT;
+
+ setupDefaultSignal();
+ setLevel(strength);
+ setGsmRoaming(true);
+
+ // Verify baseline
+ verifyLastMobileDataIndicators(true /* visible */,
+ strength /* strengthIcon */,
+ DEFAULT_ICON /* typeIcon */,
+ true /* roaming */);
+
+ // API call is made
+ setCarrierNetworkChange(true /* enabled */);
+
+ // Carrier network change is true, show special indicator, no roaming.
+ verifyLastMobileDataIndicators(true /* visible */,
+ SignalDrawable.getCarrierChangeState(SignalStrength.NUM_SIGNAL_STRENGTH_BINS),
+ 0 /* typeIcon */,
+ false /* roaming */);
+
+ // Revert back
+ setCarrierNetworkChange(false /* enabled */);
+
+ // Verify back in previous state
+ verifyLastMobileDataIndicators(true /* visible */,
+ strength /* strengthIcon */,
+ DEFAULT_ICON /* typeIcon */,
+ true /* roaming */);
+ }
+
+ @Test
+ public void testCarrierNetworkChange_roamingAfterNetworkChange() {
+ int strength = SignalStrength.SIGNAL_STRENGTH_GREAT;
+
+ setupDefaultSignal();
+ setLevel(strength);
+
+ // Verify baseline
+ verifyLastMobileDataIndicators(true /* visible */,
+ strength /* strengthIcon */,
+ DEFAULT_ICON /* typeIcon */,
+ false /* roaming */);
+
+ // API call is made
+ setCarrierNetworkChange(true /* enabled */);
+
+ // Carrier network change is true, show special indicator, no roaming.
+ verifyLastMobileDataIndicators(true /* visible */,
+ SignalDrawable.getCarrierChangeState(SignalStrength.NUM_SIGNAL_STRENGTH_BINS),
+ 0 /* typeIcon */,
+ false /* roaming */);
+
+ setGsmRoaming(true);
+
+ // Roaming should not show.
+ verifyLastMobileDataIndicators(true /* visible */,
+ SignalDrawable.getCarrierChangeState(SignalStrength.NUM_SIGNAL_STRENGTH_BINS),
+ 0 /* typeIcon */,
+ false /* roaming */);
+
+ // Revert back
+ setCarrierNetworkChange(false /* enabled */);
+
+ // Verify back in previous state
+ verifyLastMobileDataIndicators(true /* visible */,
+ strength /* strengthIcon */,
+ DEFAULT_ICON /* typeIcon */,
+ true /* roaming */);
+ }
+
private void verifyEmergencyOnly(boolean isEmergencyOnly) {
ArgumentCaptor<Boolean> emergencyOnly = ArgumentCaptor.forClass(Boolean.class);
Mockito.verify(mCallbackHandler, Mockito.atLeastOnce()).setEmergencyCallsOnly(
diff --git a/proto/src/metrics_constants.proto b/proto/src/metrics_constants.proto
index 2edcd71721ca..39ee6cf4a234 100644
--- a/proto/src/metrics_constants.proto
+++ b/proto/src/metrics_constants.proto
@@ -3546,7 +3546,7 @@ message MetricsEvent {
STORAGE_FILES = 841;
// FIELD - Rank of the clicked Settings search result
- FIELD_SETTINGS_SERACH_RESULT_RANK = 842;
+ FIELD_SETTINGS_SEARCH_RESULT_RANK = 842;
// OPEN: Settings > Apps > Default Apps > Assist > Default assist
DEFAULT_ASSIST_PICKER = 843;
@@ -4039,10 +4039,10 @@ message MetricsEvent {
ACTION_SETTINGS_UPDATE_DEFAULT_APP = 1000;
// FIELD - Query length when Settings search result is clicked
- FIELD_SETTINGS_SERACH_QUERY_LENGTH = 1001;
+ FIELD_SETTINGS_SEARCH_QUERY_LENGTH = 1001;
// FIELD - Number of results when Settings search result is clicked
- FIELD_SETTINGS_SERACH_RESULT_COUNT = 1002;
+ FIELD_SETTINGS_SEARCH_RESULT_COUNT = 1002;
// OPEN: Settings > Display > Ambient Display
// CATEGORY: SETTINGS
diff --git a/services/core/java/com/android/server/am/ActivityStarter.java b/services/core/java/com/android/server/am/ActivityStarter.java
index 902353e8a3f1..a31c33e4ab91 100644
--- a/services/core/java/com/android/server/am/ActivityStarter.java
+++ b/services/core/java/com/android/server/am/ActivityStarter.java
@@ -17,6 +17,7 @@
package com.android.server.am;
import static android.app.Activity.RESULT_CANCELED;
+import static android.app.ActivityManager.START_ABORTED;
import static android.app.ActivityManager.START_CANCELED;
import static android.app.ActivityManager.START_CLASS_NOT_FOUND;
import static android.app.ActivityManager.START_DELIVERED_TO_TOP;
@@ -117,7 +118,6 @@ import android.os.UserManager;
import android.service.voice.IVoiceInteractionSession;
import android.text.TextUtils;
import android.util.EventLog;
-import android.util.Printer;
import android.util.Slog;
import com.android.internal.app.HeavyWeightSwitcherActivity;
@@ -130,7 +130,6 @@ import java.io.PrintWriter;
import java.text.DateFormat;
import java.util.ArrayList;
import java.util.Date;
-import java.util.List;
/**
* Controller for interpreting how and then launching activities.
@@ -248,34 +247,6 @@ class ActivityStarter {
mUsingVr2dDisplay = false;
}
- // TODO(b/38121026): Remove once issue has been resolved.
- private class ActivityInfoAssignment {
- final ActivityInfo info;
- final String description;
- final long timestamp;
-
- public ActivityInfoAssignment(ActivityInfo info, String description) {
- timestamp = System.currentTimeMillis();
- this.info = info;
- this.description = description;
- }
-
- void dump(PrintWriter pw, String prefix) {
- pw.println(prefix + " " + timestamp + ":" + description + ":" + describeInfo());
- }
-
- private String describeInfo() {
- return "ActivityInfo[obj:" + info + " userId:"
- + (info != null ? UserHandle.getUserId(info.applicationInfo.uid) : 0) + "]";
- }
- }
-
- private List<ActivityInfoAssignment> mLastStartActivityInfoAssignments = new ArrayList<>();
-
- private void addActivityInfoAssignment(ActivityInfo info, String description) {
- mLastStartActivityInfoAssignments.add(new ActivityInfoAssignment(info, description));
- }
-
ActivityStarter(ActivityManagerService service, ActivityStackSupervisor supervisor) {
mService = service;
mSupervisor = supervisor;
@@ -283,8 +254,6 @@ class ActivityStarter {
mUsingVr2dDisplay = false;
}
-
-
int startActivityLocked(IApplicationThread caller, Intent intent, Intent ephemeralIntent,
String resolvedType, ActivityInfo aInfo, ResolveInfo rInfo,
IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor,
@@ -293,8 +262,6 @@ class ActivityStarter {
ActivityOptions options, boolean ignoreTargetSecurity, boolean componentSpecified,
ActivityRecord[] outActivity, ActivityStackSupervisor.ActivityContainer container,
TaskRecord inTask, String reason) {
- mLastStartActivityInfoAssignments.clear();
- addActivityInfoAssignment(aInfo, "startActivityLocked::initial");
if (TextUtils.isEmpty(reason)) {
throw new IllegalArgumentException("Need to specify a reason.");
@@ -313,7 +280,9 @@ class ActivityStarter {
// mLastStartActivityRecord[0] is set in the call to startActivity above.
outActivity[0] = mLastStartActivityRecord[0];
}
- return mLastStartActivityResult;
+
+ // Aborted results are treated as successes externally, but we must track them internally.
+ return mLastStartActivityResult != START_ABORTED ? mLastStartActivityResult : START_SUCCESS;
}
/** DO NOT call this method directly. Use {@link #startActivityLocked} instead. */
@@ -486,7 +455,6 @@ class ActivityStarter {
intent = mInterceptor.mIntent;
rInfo = mInterceptor.mRInfo;
aInfo = mInterceptor.mAInfo;
- addActivityInfoAssignment(aInfo, "startActivity::mInterceptor.mAInfo");
resolvedType = mInterceptor.mResolvedType;
inTask = mInterceptor.mInTask;
callingPid = mInterceptor.mCallingPid;
@@ -500,7 +468,7 @@ class ActivityStarter {
// We pretend to the caller that it was really started, but
// they will just get a cancel result.
ActivityOptions.abort(options);
- return START_SUCCESS;
+ return START_ABORTED;
}
// If permissions need a review before any of the app components can run, we
@@ -533,7 +501,6 @@ class ActivityStarter {
rInfo = mSupervisor.resolveIntent(intent, resolvedType, userId);
aInfo = mSupervisor.resolveActivity(intent, rInfo, startFlags,
null /*profilerInfo*/);
- addActivityInfoAssignment(aInfo, "startActivity::isPermissionReviewRequired");
if (DEBUG_PERMISSIONS_REVIEW) {
Slog.i(TAG, "START u" + userId + " {" + intent.toShortString(true, true,
@@ -558,14 +525,12 @@ class ActivityStarter {
callingPid = realCallingPid;
aInfo = mSupervisor.resolveActivity(intent, rInfo, startFlags, null /*profilerInfo*/);
- addActivityInfoAssignment(aInfo, "startActivity::auxiliaryInfo != null");
}
ActivityRecord r = new ActivityRecord(mService, callerApp, callingPid, callingUid,
callingPackage, intent, resolvedType, aInfo, mService.getGlobalConfiguration(),
resultRecord, resultWho, requestCode, componentSpecified, voiceSession != null,
mSupervisor, container, options, sourceRecord);
- addActivityInfoAssignment(aInfo, "startActivity:: value used to create new activity");
if (outActivity != null) {
outActivity[0] = r;
}
@@ -2366,16 +2331,6 @@ class ActivityStarter {
pw.println(prefix + "mStartActivity:");
mStartActivity.dump(pw, prefix + " ");
}
-
- if (!mLastStartActivityInfoAssignments.isEmpty()) {
- pw.println(prefix + "mLastStartActivityInfoAssignments:");
- for (ActivityInfoAssignment assignment : mLastStartActivityInfoAssignments) {
- assignment.dump(pw, prefix);
- /*pw.println(prefix + prefix + assignment.description + "@" + p
- + ":" + assignment.info);*/
- }
- }
-
if (mIntent != null) {
pw.println(prefix + "mIntent=" + mIntent);
}
diff --git a/services/core/java/com/android/server/content/ContentService.java b/services/core/java/com/android/server/content/ContentService.java
index 13054a643e52..468cb2990b67 100644
--- a/services/core/java/com/android/server/content/ContentService.java
+++ b/services/core/java/com/android/server/content/ContentService.java
@@ -60,6 +60,7 @@ import android.util.SparseArray;
import android.util.SparseIntArray;
import com.android.internal.annotations.GuardedBy;
+import com.android.internal.util.ArrayUtils;
import com.android.internal.util.DumpUtils;
import com.android.internal.util.IndentingPrintWriter;
import com.android.server.LocalServices;
@@ -166,6 +167,8 @@ public final class ContentService extends IContentService.Stub {
if (!DumpUtils.checkDumpAndUsageStatsPermission(mContext, TAG, pw_)) return;
final IndentingPrintWriter pw = new IndentingPrintWriter(pw_, " ");
+ final boolean dumpAll = ArrayUtils.contains(args, "-a");
+
// This makes it so that future permission checks will be in the context of this
// process rather than the caller's process. We will restore this before returning.
final long identityToken = clearCallingIdentity();
@@ -173,7 +176,7 @@ public final class ContentService extends IContentService.Stub {
if (mSyncManager == null) {
pw.println("No SyncManager created! (Disk full?)");
} else {
- mSyncManager.dump(fd, pw);
+ mSyncManager.dump(fd, pw, dumpAll);
}
pw.println();
pw.println("Observer tree:");
@@ -603,7 +606,7 @@ public final class ContentService extends IContentService.Stub {
SyncStorageEngine.EndPoint info;
info = new SyncStorageEngine.EndPoint(account, authority, userId);
syncManager.clearScheduledSyncOperations(info);
- syncManager.cancelActiveSync(info, null /* all syncs for this adapter */);
+ syncManager.cancelActiveSync(info, null /* all syncs for this adapter */, "API");
}
} finally {
restoreCallingIdentity(identityToken);
@@ -631,7 +634,7 @@ public final class ContentService extends IContentService.Stub {
}
// Cancel active syncs and clear pending syncs from the queue.
syncManager.cancelScheduledSyncOperation(info, extras);
- syncManager.cancelActiveSync(info, extras);
+ syncManager.cancelActiveSync(info, extras, "API");
} finally {
restoreCallingIdentity(identityToken);
}
diff --git a/services/core/java/com/android/server/content/SyncJobService.java b/services/core/java/com/android/server/content/SyncJobService.java
index a621d7376b7f..1f02ebfc4972 100644
--- a/services/core/java/com/android/server/content/SyncJobService.java
+++ b/services/core/java/com/android/server/content/SyncJobService.java
@@ -34,6 +34,8 @@ public class SyncJobService extends JobService {
private Messenger mMessenger;
private SparseArray<JobParameters> jobParamsMap = new SparseArray<JobParameters>();
+ private final SyncLogger mLogger = SyncLogger.getInstance();
+
/**
* This service is started by the SyncManager which passes a messenger object to
* communicate back with it. It never stops while the device is running.
@@ -63,6 +65,9 @@ public class SyncJobService extends JobService {
@Override
public boolean onStartJob(JobParameters params) {
+
+ mLogger.purgeOldLogs();
+
boolean isLoggable = Log.isLoggable(TAG, Log.VERBOSE);
synchronized (jobParamsMap) {
jobParamsMap.put(params.getJobId(), params);
@@ -70,6 +75,9 @@ public class SyncJobService extends JobService {
Message m = Message.obtain();
m.what = SyncManager.SyncHandler.MESSAGE_START_SYNC;
SyncOperation op = SyncOperation.maybeCreateFromJobExtras(params.getExtras());
+
+ mLogger.log("onStopJob() jobid=", params.getJobId(), " op=", op);
+
if (op == null) {
Slog.e(TAG, "Got invalid job " + params.getJobId());
return false;
@@ -88,7 +96,7 @@ public class SyncJobService extends JobService {
Slog.v(TAG, "onStopJob called " + params.getJobId() + ", reason: "
+ params.getStopReason());
}
-
+ mLogger.log("onStopJob() ", mLogger.jobParametersToString(params));
synchronized (jobParamsMap) {
jobParamsMap.remove(params.getJobId());
}
@@ -108,9 +116,13 @@ public class SyncJobService extends JobService {
return false;
}
- public void callJobFinished(int jobId, boolean needsReschedule) {
+ public void callJobFinished(int jobId, boolean needsReschedule, String why) {
synchronized (jobParamsMap) {
JobParameters params = jobParamsMap.get(jobId);
+ mLogger.log("callJobFinished()",
+ " needsReschedule=", needsReschedule,
+ " ", mLogger.jobParametersToString(params),
+ " why=", why);
if (params != null) {
jobFinished(params, needsReschedule);
jobParamsMap.remove(jobId);
diff --git a/services/core/java/com/android/server/content/SyncLogger.java b/services/core/java/com/android/server/content/SyncLogger.java
new file mode 100644
index 000000000000..db794643b4df
--- /dev/null
+++ b/services/core/java/com/android/server/content/SyncLogger.java
@@ -0,0 +1,252 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.server.content;
+
+import android.app.job.JobParameters;
+import android.os.Build;
+import android.os.Environment;
+import android.os.FileUtils;
+import android.os.SystemProperties;
+import android.text.format.DateUtils;
+import android.util.Slog;
+
+import com.android.internal.annotations.GuardedBy;
+
+import libcore.io.IoUtils;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileReader;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.io.Reader;
+import java.io.Writer;
+import java.text.SimpleDateFormat;
+import java.util.Arrays;
+import java.util.Date;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * Implements a rotating file logger for the sync manager, which is enabled only on userdebug/eng
+ * builds (unless debug.synclog is set to 1).
+ *
+ * Note this class could be used for other purposes too, but in general we don't want various
+ * system components to log to files, so it's put in a local package here.
+ */
+public class SyncLogger {
+ private static final String TAG = "SyncLogger";
+
+ private static SyncLogger sInstance;
+
+ SyncLogger() {
+ }
+
+ /**
+ * @return the singleton instance.
+ */
+ public static synchronized SyncLogger getInstance() {
+ if (sInstance == null) {
+ final boolean enable = "1".equals(SystemProperties.get("debug.synclog",
+ Build.IS_DEBUGGABLE ? "1" : "0"));
+ if (enable) {
+ sInstance = new RotatingFileLogger();
+ } else {
+ sInstance = new SyncLogger();
+ }
+ }
+ return sInstance;
+ }
+
+ /**
+ * Write strings to the log file.
+ */
+ public void log(Object... message) {
+ }
+
+ /**
+ * Remove old log files.
+ */
+ public void purgeOldLogs() {
+ // The default implementation is no-op.
+ }
+
+ public String jobParametersToString(JobParameters params) {
+ // The default implementation is no-op.
+ return "";
+ }
+
+ /**
+ * Dump all existing log files into a given writer.
+ */
+ public void dumpAll(PrintWriter pw) {
+ }
+
+ /**
+ * Actual implementation which is only used on userdebug/eng builds (by default).
+ */
+ private static class RotatingFileLogger extends SyncLogger {
+ private final Object mLock = new Object();
+
+ private final long mKeepAgeMs = TimeUnit.DAYS.toMillis(7);
+
+ private static final SimpleDateFormat sTimestampFormat
+ = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS");
+
+ private static final SimpleDateFormat sFilenameDateFormat
+ = new SimpleDateFormat("yyyy-MM-dd");
+
+ @GuardedBy("mLock")
+ private final Date mCachedDate = new Date();
+
+ @GuardedBy("mLock")
+ private final StringBuilder mStringBuilder = new StringBuilder();
+
+ private final File mLogPath;
+
+ @GuardedBy("mLock")
+ private long mCurrentLogFileDayTimestamp;
+
+ @GuardedBy("mLock")
+ private Writer mLogWriter;
+
+ @GuardedBy("mLock")
+ private boolean mErrorShown;
+
+ RotatingFileLogger() {
+ mLogPath = new File(Environment.getDataSystemDirectory(), "syncmanager-log");
+ }
+
+ private void handleException(String message, Exception e) {
+ if (!mErrorShown) {
+ Slog.e(TAG, message, e);
+ mErrorShown = true;
+ }
+ }
+
+ @Override
+ public void log(Object... message) {
+ if (message == null) {
+ return;
+ }
+ synchronized (mLock) {
+ final long now = System.currentTimeMillis();
+ openLogLocked(now);
+ if (mLogWriter == null) {
+ return; // Couldn't open log file?
+ }
+
+ mStringBuilder.setLength(0);
+ mCachedDate.setTime(now);
+ mStringBuilder.append(sTimestampFormat.format(mCachedDate));
+ mStringBuilder.append(' ');
+
+ mStringBuilder.append(android.os.Process.myTid());
+ mStringBuilder.append(' ');
+
+ for (Object o : message) {
+ mStringBuilder.append(o);
+ }
+ mStringBuilder.append('\n');
+
+ try {
+ mLogWriter.append(mStringBuilder);
+ mLogWriter.flush();
+ } catch (IOException e) {
+ handleException("Failed to write log", e);
+ }
+ }
+ }
+
+ private void openLogLocked(long now) {
+ // If we already have a log file opened and the date has't changed, just use it.
+ final long day = now % DateUtils.DAY_IN_MILLIS;
+ if ((mLogWriter != null) && (day == mCurrentLogFileDayTimestamp)) {
+ return;
+ }
+
+ // Otherwise create a new log file.
+ closeCurrentLogLocked();
+
+ mCurrentLogFileDayTimestamp = day;
+
+ mCachedDate.setTime(now);
+ final String filename = "synclog-" + sFilenameDateFormat.format(mCachedDate) + ".log";
+ final File file = new File(mLogPath, filename);
+
+ file.getParentFile().mkdirs();
+
+ try {
+ mLogWriter = new FileWriter(file, /* append= */ true);
+ } catch (IOException e) {
+ handleException("Failed to open log file: " + file, e);
+ }
+ }
+
+ private void closeCurrentLogLocked() {
+ IoUtils.closeQuietly(mLogWriter);
+ mLogWriter = null;
+ }
+
+ @Override
+ public void purgeOldLogs() {
+ synchronized (mLock) {
+ FileUtils.deleteOlderFiles(mLogPath, /* keepCount= */ 1, mKeepAgeMs);
+ }
+ }
+
+ @Override
+ public String jobParametersToString(JobParameters params) {
+ if (params == null) {
+ return "job:null";
+ } else {
+ return "job:#" + params.getJobId() + ":"
+ + SyncOperation.maybeCreateFromJobExtras(params.getExtras());
+ }
+ }
+
+ @Override
+ public void dumpAll(PrintWriter pw) {
+ synchronized (mLock) {
+ final String[] files = mLogPath.list();
+ if (files == null || (files.length == 0)) {
+ return;
+ }
+ Arrays.sort(files);
+
+ for (String file : files) {
+ dumpFile(pw, new File(mLogPath, file));
+ }
+ }
+ }
+
+ private void dumpFile(PrintWriter pw, File file) {
+ Slog.w(TAG, "Dumping " + file);
+ final char[] buffer = new char[32 * 1024];
+
+ try (Reader in = new BufferedReader(new FileReader(file))) {
+ int read;
+ while ((read = in.read(buffer)) >= 0) {
+ if (read > 0) {
+ pw.write(buffer, 0, read);
+ }
+ }
+ } catch (IOException e) {
+ }
+ }
+ }
+}
diff --git a/services/core/java/com/android/server/content/SyncManager.java b/services/core/java/com/android/server/content/SyncManager.java
index e3e26583b686..35591420af50 100644
--- a/services/core/java/com/android/server/content/SyncManager.java
+++ b/services/core/java/com/android/server/content/SyncManager.java
@@ -241,6 +241,8 @@ public class SyncManager {
private final Random mRand;
+ private final SyncLogger mLogger;
+
private boolean isJobIdInUseLockedH(int jobId, List<JobInfo> pendingJobs) {
for (JobInfo job: pendingJobs) {
if (job.getId() == jobId) {
@@ -289,13 +291,15 @@ public class SyncManager {
mStorageIsLow = true;
cancelActiveSync(
SyncStorageEngine.EndPoint.USER_ALL_PROVIDER_ALL_ACCOUNTS_ALL,
- null /* any sync */);
+ null /* any sync */,
+ "storage low");
} else if (Intent.ACTION_DEVICE_STORAGE_OK.equals(action)) {
if (Log.isLoggable(TAG, Log.VERBOSE)) {
Slog.v(TAG, "Internal storage is ok.");
}
mStorageIsLow = false;
- rescheduleSyncs(EndPoint.USER_ALL_PROVIDER_ALL_ACCOUNTS_ALL);
+ rescheduleSyncs(EndPoint.USER_ALL_PROVIDER_ALL_ACCOUNTS_ALL,
+ "storage ok");
}
}
};
@@ -378,15 +382,16 @@ public class SyncManager {
if (Log.isLoggable(TAG, Log.VERBOSE)) {
Slog.v(TAG, "Reconnection detected: clearing all backoffs");
}
+ // Note the location of this code was wrong from nyc to oc; fixed in DR.
+ clearAllBackoffs("network reconnect");
}
- clearAllBackoffs();
}
}
};
- private void clearAllBackoffs() {
+ private void clearAllBackoffs(String why) {
mSyncStorageEngine.clearAllBackoffsLocked();
- rescheduleSyncs(EndPoint.USER_ALL_PROVIDER_ALL_ACCOUNTS_ALL);
+ rescheduleSyncs(EndPoint.USER_ALL_PROVIDER_ALL_ACCOUNTS_ALL, why);
}
private boolean readDataConnectionState() {
@@ -502,6 +507,8 @@ public class SyncManager {
// and creating threads and so on; it may fail if the disk is full.
mContext = context;
+ mLogger = SyncLogger.getInstance();
+
SyncStorageEngine.init(context);
mSyncStorageEngine = SyncStorageEngine.getSingleton();
mSyncStorageEngine.setOnSyncRequestListener(new OnSyncRequestListener() {
@@ -1145,8 +1152,12 @@ public class SyncManager {
mSyncHandler.sendMessage(msg);
}
- private void sendCancelSyncsMessage(final SyncStorageEngine.EndPoint info, Bundle extras) {
+ private void sendCancelSyncsMessage(final SyncStorageEngine.EndPoint info, Bundle extras,
+ String why) {
if (Log.isLoggable(TAG, Log.VERBOSE)) Slog.v(TAG, "sending MESSAGE_CANCEL");
+
+ mLogger.log("sendCancelSyncsMessage() ep=", info, " why=", why);
+
Message msg = mSyncHandler.obtainMessage();
msg.what = SyncHandler.MESSAGE_CANCEL;
msg.setData(extras);
@@ -1227,7 +1238,7 @@ public class SyncManager {
}
}
- private void clearBackoffSetting(EndPoint target) {
+ private void clearBackoffSetting(EndPoint target, String why) {
Pair<Long, Long> backoff = mSyncStorageEngine.getBackoff(target);
if (backoff != null && backoff.first == SyncStorageEngine.NOT_IN_BACKOFF_MODE &&
backoff.second == SyncStorageEngine.NOT_IN_BACKOFF_MODE) {
@@ -1240,7 +1251,7 @@ public class SyncManager {
SyncStorageEngine.NOT_IN_BACKOFF_MODE,
SyncStorageEngine.NOT_IN_BACKOFF_MODE);
- rescheduleSyncs(target);
+ rescheduleSyncs(target, why);
}
private void increaseBackoffSetting(EndPoint target) {
@@ -1281,14 +1292,16 @@ public class SyncManager {
Slog.v(TAG, "Backoff until: " + backoff + ", delayTime: " + newDelayInMs);
}
mSyncStorageEngine.setBackoff(target, backoff, newDelayInMs);
- rescheduleSyncs(target);
+ rescheduleSyncs(target, "increaseBackoffSetting");
}
/**
* Reschedule all scheduled syncs for this EndPoint. The syncs will be scheduled according
* to current backoff and delayUntil values of this EndPoint.
*/
- private void rescheduleSyncs(EndPoint target) {
+ private void rescheduleSyncs(EndPoint target, String why) {
+ mLogger.log("rescheduleSyncs() ep=", target, " why=", why);
+
List<SyncOperation> ops = getAllPendingSyncs();
int count = 0;
for (SyncOperation op: ops) {
@@ -1316,7 +1329,7 @@ public class SyncManager {
if (Log.isLoggable(TAG, Log.VERBOSE)) {
Slog.v(TAG, "Delay Until time set to " + newDelayUntilTime + " for " + target);
}
- rescheduleSyncs(target);
+ rescheduleSyncs(target, "delayUntil newDelayUntilTime: " + newDelayUntilTime);
}
private boolean isAdapterDelayed(EndPoint target) {
@@ -1338,8 +1351,8 @@ public class SyncManager {
* have null account/provider info to specify all accounts/providers.
* @param extras if non-null, specifies the exact sync to remove.
*/
- public void cancelActiveSync(SyncStorageEngine.EndPoint info, Bundle extras) {
- sendCancelSyncsMessage(info, extras);
+ public void cancelActiveSync(SyncStorageEngine.EndPoint info, Bundle extras, String why) {
+ sendCancelSyncsMessage(info, extras, why);
}
/**
@@ -1599,7 +1612,8 @@ public class SyncManager {
null /* any account */,
null /* any authority */,
userId),
- null /* any sync. */
+ null /* any sync. */,
+ "onUserStopped"
);
}
@@ -1759,10 +1773,15 @@ public class SyncManager {
}
}
- protected void dump(FileDescriptor fd, PrintWriter pw) {
+ protected void dump(FileDescriptor fd, PrintWriter pw, boolean dumpAll) {
final IndentingPrintWriter ipw = new IndentingPrintWriter(pw, " ");
dumpSyncState(ipw);
dumpSyncAdapters(ipw);
+
+ if (dumpAll) {
+ ipw.println("Detailed Sync History");
+ mLogger.dumpAll(pw);
+ }
}
static String formatTime(long time) {
@@ -2644,7 +2663,7 @@ public class SyncManager {
Log.d(TAG, "handleSyncHandlerMessage: MESSAGE_CANCEL: "
+ endpoint + " bundle: " + extras);
}
- cancelActiveSyncH(endpoint, extras);
+ cancelActiveSyncH(endpoint, extras, "MESSAGE_CANCEL");
break;
case SyncHandler.MESSAGE_SYNC_FINISHED:
@@ -2660,7 +2679,8 @@ public class SyncManager {
Slog.v(TAG, "syncFinished" + payload.activeSyncContext.mSyncOperation);
}
mSyncJobService.callJobFinished(
- payload.activeSyncContext.mSyncOperation.jobId, false);
+ payload.activeSyncContext.mSyncOperation.jobId, false,
+ "sync finished");
runSyncFinishedOrCanceledH(payload.syncResult,
payload.activeSyncContext);
break;
@@ -2704,7 +2724,8 @@ public class SyncManager {
SyncResult syncResult = new SyncResult();
syncResult.stats.numIoExceptions++;
mSyncJobService.callJobFinished(
- currentSyncContext.mSyncOperation.jobId, false);
+ currentSyncContext.mSyncOperation.jobId, false,
+ "service disconnected");
runSyncFinishedOrCanceledH(syncResult, currentSyncContext);
}
break;
@@ -2722,7 +2743,8 @@ public class SyncManager {
"Detected sync making no progress for %s. cancelling.",
monitoredSyncContext));
mSyncJobService.callJobFinished(
- monitoredSyncContext.mSyncOperation.jobId, false);
+ monitoredSyncContext.mSyncOperation.jobId, false,
+ "no network activity");
runSyncFinishedOrCanceledH(
null /* cancel => no result */, monitoredSyncContext);
} else {
@@ -2754,8 +2776,10 @@ public class SyncManager {
* delay. This is equivalent to a failure. If this is a periodic sync, a delayed one-off
* sync will be scheduled.
*/
- private void deferSyncH(SyncOperation op, long delay) {
- mSyncJobService.callJobFinished(op.jobId, false);
+ private void deferSyncH(SyncOperation op, long delay, String why) {
+ mLogger.log("deferSyncH() ", (op.isPeriodic ? "periodic " : ""),
+ "sync. op=", op, " delay=", delay, " why=", why);
+ mSyncJobService.callJobFinished(op.jobId, false, why);
if (op.isPeriodic) {
scheduleSyncOperationH(op.createOneTimeSyncOperation(), delay);
} else {
@@ -2779,10 +2803,10 @@ public class SyncManager {
/**
* Cancel an active sync and reschedule it on the JobScheduler with some delay.
*/
- private void deferActiveSyncH(ActiveSyncContext asc) {
+ private void deferActiveSyncH(ActiveSyncContext asc, String why) {
SyncOperation op = asc.mSyncOperation;
runSyncFinishedOrCanceledH(null, asc);
- deferSyncH(op, SYNC_DELAY_ON_CONFLICT);
+ deferSyncH(op, SYNC_DELAY_ON_CONFLICT, why);
}
private void startSyncH(SyncOperation op) {
@@ -2790,7 +2814,7 @@ public class SyncManager {
if (isLoggable) Slog.v(TAG, op.toString());
if (mStorageIsLow) {
- deferSyncH(op, SYNC_DELAY_ON_LOW_STORAGE);
+ deferSyncH(op, SYNC_DELAY_ON_LOW_STORAGE, "storage low");
return;
}
@@ -2800,7 +2824,8 @@ public class SyncManager {
List<SyncOperation> ops = getAllPendingSyncs();
for (SyncOperation syncOperation: ops) {
if (syncOperation.sourcePeriodicId == op.jobId) {
- mSyncJobService.callJobFinished(op.jobId, false);
+ mSyncJobService.callJobFinished(op.jobId, false,
+ "periodic sync, pending");
return;
}
}
@@ -2808,13 +2833,14 @@ public class SyncManager {
// executing according to some backoff criteria.
for (ActiveSyncContext asc: mActiveSyncContexts) {
if (asc.mSyncOperation.sourcePeriodicId == op.jobId) {
- mSyncJobService.callJobFinished(op.jobId, false);
+ mSyncJobService.callJobFinished(op.jobId, false,
+ "periodic sync, already running");
return;
}
}
// Check for adapter delays.
if (isAdapterDelayed(op.target)) {
- deferSyncH(op, 0 /* No minimum delay */);
+ deferSyncH(op, 0 /* No minimum delay */, "backing off");
return;
}
}
@@ -2828,13 +2854,13 @@ public class SyncManager {
if (isLoggable) {
Slog.v(TAG, "Rescheduling sync due to conflict " + op.toString());
}
- deferSyncH(op, SYNC_DELAY_ON_CONFLICT);
+ deferSyncH(op, SYNC_DELAY_ON_CONFLICT, "delay on conflict");
return;
} else {
if (isLoggable) {
Slog.v(TAG, "Pushing back running sync due to a higher priority sync");
}
- deferActiveSyncH(asc);
+ deferActiveSyncH(asc, "preempted");
break;
}
}
@@ -2844,12 +2870,13 @@ public class SyncManager {
switch (syncOpState) {
case SYNC_OP_STATE_INVALID_NO_ACCOUNT_ACCESS:
case SYNC_OP_STATE_INVALID: {
- mSyncJobService.callJobFinished(op.jobId, false);
+ mSyncJobService.callJobFinished(op.jobId, false,
+ "invalid op state: " + syncOpState);
} return;
}
if (!dispatchSyncOperation(op)) {
- mSyncJobService.callJobFinished(op.jobId, false);
+ mSyncJobService.callJobFinished(op.jobId, false, "dispatchSyncOperation() failed");
}
setAuthorityPendingState(op.target);
@@ -3019,7 +3046,8 @@ public class SyncManager {
if (op.sourcePeriodicId == syncOperation.jobId || op.jobId == syncOperation.jobId) {
ActiveSyncContext asc = findActiveSyncContextH(syncOperation.jobId);
if (asc != null) {
- mSyncJobService.callJobFinished(syncOperation.jobId, false);
+ mSyncJobService.callJobFinished(syncOperation.jobId, false,
+ "removePeriodicSyncInternalH");
runSyncFinishedOrCanceledH(null, asc);
}
getJobScheduler().cancel(op.jobId);
@@ -3131,6 +3159,8 @@ public class SyncManager {
final RegisteredServicesCache.ServiceInfo<SyncAdapterType> syncAdapterInfo;
syncAdapterInfo = mSyncAdapters.getServiceInfo(syncAdapterType, info.userId);
if (syncAdapterInfo == null) {
+ mLogger.log("dispatchSyncOperation() failed: no sync adapter info for ",
+ syncAdapterType);
Log.d(TAG, "can't find a sync adapter for " + syncAdapterType
+ ", removing settings for it");
mSyncStorageEngine.removeAuthority(info);
@@ -3151,6 +3181,8 @@ public class SyncManager {
postMonitorSyncProgressMessage(activeSyncContext);
if (!activeSyncContext.bindToSyncAdapter(targetComponent, info.userId)) {
+ mLogger.log("dispatchSyncOperation() failed: bind failed. target: ",
+ targetComponent);
Slog.e(TAG, "Bind attempt failed - target: " + targetComponent);
closeActiveSyncContext(activeSyncContext);
return false;
@@ -3166,16 +3198,25 @@ public class SyncManager {
activeSyncContext.mIsLinkedToDeath = true;
syncAdapter.linkToDeath(activeSyncContext, 0);
+ mLogger.log("Sync start: account=" + syncOperation.target.account,
+ " authority=", syncOperation.target.provider,
+ " reason=", SyncOperation.reasonToString(null, syncOperation.reason),
+ " extras=", SyncOperation.extrasToString(syncOperation.extras));
+
activeSyncContext.mSyncAdapter = ISyncAdapter.Stub.asInterface(syncAdapter);
activeSyncContext.mSyncAdapter
.startSync(activeSyncContext, syncOperation.target.provider,
syncOperation.target.account, syncOperation.extras);
+
+ mLogger.log("Sync finish");
} catch (RemoteException remoteExc) {
+ mLogger.log("Sync failed with RemoteException: ", remoteExc.toString());
Log.d(TAG, "maybeStartNextSync: caught a RemoteException, rescheduling", remoteExc);
closeActiveSyncContext(activeSyncContext);
increaseBackoffSetting(syncOperation.target);
scheduleSyncOperationH(syncOperation);
} catch (RuntimeException exc) {
+ mLogger.log("Sync failed with RuntimeException: ", exc.toString());
closeActiveSyncContext(activeSyncContext);
Slog.e(TAG, "Caught RuntimeException while starting the sync " + syncOperation, exc);
}
@@ -3186,7 +3227,8 @@ public class SyncManager {
* @param info Can have null fields to indicate all the active syncs for that field.
* @param extras Can be null to indicate <strong>all</strong> syncs for the given endpoint.
*/
- private void cancelActiveSyncH(SyncStorageEngine.EndPoint info, Bundle extras) {
+ private void cancelActiveSyncH(SyncStorageEngine.EndPoint info, Bundle extras,
+ String why) {
ArrayList<ActiveSyncContext> activeSyncs =
new ArrayList<ActiveSyncContext>(mActiveSyncContexts);
for (ActiveSyncContext activeSyncContext : activeSyncs) {
@@ -3202,7 +3244,8 @@ public class SyncManager {
false /* no config settings */)) {
continue;
}
- mSyncJobService.callJobFinished(activeSyncContext.mSyncOperation.jobId, false);
+ mSyncJobService.callJobFinished(activeSyncContext.mSyncOperation.jobId, false,
+ why);
runSyncFinishedOrCanceledH(null /* cancel => no result */, activeSyncContext);
}
}
@@ -3250,6 +3293,7 @@ public class SyncManager {
// potentially rescheduling all pending jobs to respect new backoff values.
getJobScheduler().cancel(syncOperation.jobId);
}
+ mLogger.log("runSyncFinishedOrCanceledH() op=", syncOperation, " result=", syncResult);
if (syncResult != null) {
if (isLoggable) {
@@ -3262,7 +3306,7 @@ public class SyncManager {
// TODO: set these correctly when the SyncResult is extended to include it
downstreamActivity = 0;
upstreamActivity = 0;
- clearBackoffSetting(syncOperation.target);
+ clearBackoffSetting(syncOperation.target, "sync success");
// If the operation completes successfully and it was scheduled due to
// a periodic operation failing, we reschedule the periodic operation to
diff --git a/services/core/java/com/android/server/content/SyncOperation.java b/services/core/java/com/android/server/content/SyncOperation.java
index b46426cc4a05..7d2cc0035847 100644
--- a/services/core/java/com/android/server/content/SyncOperation.java
+++ b/services/core/java/com/android/server/content/SyncOperation.java
@@ -237,6 +237,9 @@ public class SyncOperation {
* contain a valid sync operation.
*/
static SyncOperation maybeCreateFromJobExtras(PersistableBundle jobExtras) {
+ if (jobExtras == null) {
+ return null;
+ }
String accountName, accountType;
String provider;
int userId, owningUid;
@@ -445,6 +448,10 @@ public class SyncOperation {
}
static void extrasToStringBuilder(Bundle bundle, StringBuilder sb) {
+ if (bundle == null) {
+ sb.append("null");
+ return;
+ }
sb.append("[");
for (String key : bundle.keySet()) {
sb.append(key).append("=").append(bundle.get(key)).append(" ");
@@ -452,6 +459,12 @@ public class SyncOperation {
sb.append("]");
}
+ static String extrasToString(Bundle bundle) {
+ final StringBuilder sb = new StringBuilder();
+ extrasToStringBuilder(bundle, sb);
+ return sb.toString();
+ }
+
String wakeLockName() {
if (wakeLockName != null) {
return wakeLockName;
diff --git a/services/core/java/com/android/server/locksettings/LockSettingsService.java b/services/core/java/com/android/server/locksettings/LockSettingsService.java
index fe2c5bd87df4..c1e820c9b787 100644
--- a/services/core/java/com/android/server/locksettings/LockSettingsService.java
+++ b/services/core/java/com/android/server/locksettings/LockSettingsService.java
@@ -142,6 +142,7 @@ public class LockSettingsService extends ILockSettings.Stub {
private static final int SYNTHETIC_PASSWORD_ENABLED_BY_DEFAULT = 1;
// Order of holding lock: mSeparateChallengeLock -> mSpManager -> this
+ // Do not call into ActivityManager while holding mSpManager lock.
private final Object mSeparateChallengeLock = new Object();
private final DeviceProvisionedObserver mDeviceProvisionedObserver =
@@ -1434,16 +1435,14 @@ public class LockSettingsService extends ILockSettings.Stub {
Slog.e(TAG, "FRP credential can only be verified prior to provisioning.");
return VerifyCredentialResponse.ERROR;
}
- synchronized (mSpManager) {
- if (isSyntheticPasswordBasedCredentialLocked(userId)) {
- VerifyCredentialResponse response = spBasedDoVerifyCredentialLocked(credential,
- credentialType, hasChallenge, challenge, userId, progressCallback);
- if (response.getResponseCode() == VerifyCredentialResponse.RESPONSE_OK) {
- mStrongAuth.reportSuccessfulStrongAuthUnlock(userId);
- }
- return response;
- }
+ VerifyCredentialResponse response = null;
+ response = spBasedDoVerifyCredential(credential, credentialType, hasChallenge, challenge,
+ userId, progressCallback);
+ // The user employs synthetic password based credential.
+ if (response != null) {
+ return response;
}
+
final CredentialHash storedHash;
if (userId == USER_FRP) {
PersistentData data = mStorage.readPersistentDataBlock();
@@ -1472,7 +1471,7 @@ public class LockSettingsService extends ILockSettings.Stub {
credentialToVerify = credential;
}
- VerifyCredentialResponse response = verifyCredential(userId, storedHash, credentialToVerify,
+ response = verifyCredential(userId, storedHash, credentialToVerify,
hasChallenge, challenge, progressCallback);
if (response.getResponseCode() == VerifyCredentialResponse.RESPONSE_OK) {
@@ -1995,33 +1994,46 @@ public class LockSettingsService extends ILockSettings.Stub {
setLong(SYNTHETIC_PASSWORD_ENABLED_KEY, 1, UserHandle.USER_SYSTEM);
}
- private VerifyCredentialResponse spBasedDoVerifyCredentialLocked(String userCredential, int
+ private VerifyCredentialResponse spBasedDoVerifyCredential(String userCredential, int
credentialType, boolean hasChallenge, long challenge, int userId,
ICheckCredentialProgressCallback progressCallback) throws RemoteException {
- if (DEBUG) Slog.d(TAG, "spBasedDoVerifyCredentialLocked: user=" + userId);
+ if (DEBUG) Slog.d(TAG, "spBasedDoVerifyCredential: user=" + userId);
if (credentialType == LockPatternUtils.CREDENTIAL_TYPE_NONE) {
userCredential = null;
}
- if (userId == USER_FRP) {
- return mSpManager.verifyFrpCredential(getGateKeeperService(),
- userCredential, credentialType, progressCallback);
- }
- long handle = getSyntheticPasswordHandleLocked(userId);
- AuthenticationResult authResult = mSpManager.unwrapPasswordBasedSyntheticPassword(
- getGateKeeperService(), handle, userCredential, userId);
+ final AuthenticationResult authResult;
+ VerifyCredentialResponse response;
+ synchronized (mSpManager) {
+ if (!isSyntheticPasswordBasedCredentialLocked(userId)) {
+ return null;
+ }
+ if (userId == USER_FRP) {
+ return mSpManager.verifyFrpCredential(getGateKeeperService(),
+ userCredential, credentialType, progressCallback);
+ }
- VerifyCredentialResponse response = authResult.gkResponse;
- if (response.getResponseCode() == VerifyCredentialResponse.RESPONSE_OK) {
+ long handle = getSyntheticPasswordHandleLocked(userId);
+ authResult = mSpManager.unwrapPasswordBasedSyntheticPassword(
+ getGateKeeperService(), handle, userCredential, userId);
+
+ response = authResult.gkResponse;
// credential has matched
- // perform verifyChallenge with synthetic password which generates the real auth
- // token for the current user
- response = mSpManager.verifyChallenge(getGateKeeperService(), authResult.authToken,
- challenge, userId);
- if (response.getResponseCode() != VerifyCredentialResponse.RESPONSE_OK) {
- Slog.wtf(TAG, "verifyChallenge with SP failed.");
- return VerifyCredentialResponse.ERROR;
+ if (response.getResponseCode() == VerifyCredentialResponse.RESPONSE_OK) {
+ // perform verifyChallenge with synthetic password which generates the real GK auth
+ // token and response for the current user
+ response = mSpManager.verifyChallenge(getGateKeeperService(), authResult.authToken,
+ challenge, userId);
+ if (response.getResponseCode() != VerifyCredentialResponse.RESPONSE_OK) {
+ // This shouldn't really happen: the unwrapping of SP succeeds, but SP doesn't
+ // match the recorded GK password handle.
+ Slog.wtf(TAG, "verifyChallenge with SP failed.");
+ return VerifyCredentialResponse.ERROR;
+ }
}
+ }
+
+ if (response.getResponseCode() == VerifyCredentialResponse.RESPONSE_OK) {
if (progressCallback != null) {
progressCallback.onCredentialVerified();
}
@@ -2032,12 +2044,14 @@ public class LockSettingsService extends ILockSettings.Stub {
Slog.i(TAG, "Unlocking user " + userId + " with secret only, length " + secret.length);
unlockUser(userId, null, secret);
+ activateEscrowTokens(authResult.authToken, userId);
+
if (isManagedProfileWithSeparatedLock(userId)) {
TrustManager trustManager =
(TrustManager) mContext.getSystemService(Context.TRUST_SERVICE);
trustManager.setDeviceLockedForUser(userId, false);
}
- activateEscrowTokens(authResult.authToken, userId);
+ mStrongAuth.reportSuccessfulStrongAuthUnlock(userId);
} else if (response.getResponseCode() == VerifyCredentialResponse.RESPONSE_RETRY) {
if (response.getTimeout() > 0) {
requireStrongAuth(STRONG_AUTH_REQUIRED_AFTER_LOCKOUT, userId);
@@ -2184,8 +2198,8 @@ public class LockSettingsService extends ILockSettings.Stub {
private void activateEscrowTokens(AuthenticationToken auth, int userId) throws RemoteException {
if (DEBUG) Slog.d(TAG, "activateEscrowTokens: user=" + userId);
- disableEscrowTokenOnNonManagedDevicesIfNeeded(userId);
synchronized (mSpManager) {
+ disableEscrowTokenOnNonManagedDevicesIfNeeded(userId);
for (long handle : mSpManager.getPendingTokensForUser(userId)) {
Slog.i(TAG, String.format("activateEscrowTokens: %x %d ", handle, userId));
mSpManager.activateTokenBasedSyntheticPassword(handle, auth, userId);
diff --git a/services/core/java/com/android/server/locksettings/LockSettingsShellCommand.java b/services/core/java/com/android/server/locksettings/LockSettingsShellCommand.java
index d730c56ae2ca..67ead6f45d7a 100644
--- a/services/core/java/com/android/server/locksettings/LockSettingsShellCommand.java
+++ b/services/core/java/com/android/server/locksettings/LockSettingsShellCommand.java
@@ -36,6 +36,7 @@ class LockSettingsShellCommand extends ShellCommand {
private static final String COMMAND_CLEAR = "clear";
private static final String COMMAND_SP = "sp";
private static final String COMMAND_SET_DISABLED = "set-disabled";
+ private static final String COMMAND_VERIFY = "verify";
private int mCurrentUserId;
private final LockPatternUtils mLockPatternUtils;
@@ -76,6 +77,9 @@ class LockSettingsShellCommand extends ShellCommand {
case COMMAND_SET_DISABLED:
runSetDisabled();
break;
+ case COMMAND_VERIFY:
+ runVerify();
+ break;
default:
getErrPrintWriter().println("Unknown command: " + cmd);
break;
@@ -88,6 +92,11 @@ class LockSettingsShellCommand extends ShellCommand {
}
}
+ private void runVerify() {
+ // The command is only run if the credential is correct.
+ getOutPrintWriter().println("Lock credential verified successfully");
+ }
+
@Override
public void onHelp() {
}
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index fbe6d302dd64..48b4c5724b5f 100644
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -1136,7 +1136,7 @@ public class NotificationManagerService extends SystemService {
NotificationAssistants notificationAssistants, ConditionProviders conditionProviders,
ICompanionDeviceManager companionManager, SnoozeHelper snoozeHelper,
NotificationUsageStats usageStats, AtomicFile policyFile,
- ActivityManager activityManager) {
+ ActivityManager activityManager, GroupHelper groupHelper) {
Resources resources = getContext().getResources();
mMaxPackageEnqueueRate = Settings.Global.getFloat(getContext().getContentResolver(),
Settings.Global.MAX_NOTIFICATION_ENQUEUE_RATE,
@@ -1193,35 +1193,7 @@ public class NotificationManagerService extends SystemService {
}
});
mSnoozeHelper = snoozeHelper;
- mGroupHelper = new GroupHelper(new GroupHelper.Callback() {
- @Override
- public void addAutoGroup(String key) {
- synchronized (mNotificationLock) {
- addAutogroupKeyLocked(key);
- }
- mRankingHandler.requestSort(false);
- }
-
- @Override
- public void removeAutoGroup(String key) {
- synchronized (mNotificationLock) {
- removeAutogroupKeyLocked(key);
- }
- mRankingHandler.requestSort(false);
- }
-
- @Override
- public void addAutoGroupSummary(int userId, String pkg, String triggeringKey) {
- createAutoGroupSummary(userId, pkg, triggeringKey);
- }
-
- @Override
- public void removeAutoGroupSummary(int userId, String pkg) {
- synchronized (mNotificationLock) {
- clearAutogroupSummaryLocked(userId, pkg);
- }
- }
- });
+ mGroupHelper = groupHelper;
// This is a ManagedServices object that keeps track of the listeners.
mListeners = notificationListeners;
@@ -1337,11 +1309,44 @@ public class NotificationManagerService extends SystemService {
new ConditionProviders(getContext(), mUserProfiles, AppGlobals.getPackageManager()),
null, snoozeHelper, new NotificationUsageStats(getContext()),
new AtomicFile(new File(systemDir, "notification_policy.xml")),
- (ActivityManager) getContext().getSystemService(Context.ACTIVITY_SERVICE));
+ (ActivityManager) getContext().getSystemService(Context.ACTIVITY_SERVICE),
+ getGroupHelper());
publishBinderService(Context.NOTIFICATION_SERVICE, mService);
publishLocalService(NotificationManagerInternal.class, mInternalService);
}
+ private GroupHelper getGroupHelper() {
+ return new GroupHelper(new GroupHelper.Callback() {
+ @Override
+ public void addAutoGroup(String key) {
+ synchronized (mNotificationLock) {
+ addAutogroupKeyLocked(key);
+ }
+ mRankingHandler.requestSort(false);
+ }
+
+ @Override
+ public void removeAutoGroup(String key) {
+ synchronized (mNotificationLock) {
+ removeAutogroupKeyLocked(key);
+ }
+ mRankingHandler.requestSort(false);
+ }
+
+ @Override
+ public void addAutoGroupSummary(int userId, String pkg, String triggeringKey) {
+ createAutoGroupSummary(userId, pkg, triggeringKey);
+ }
+
+ @Override
+ public void removeAutoGroupSummary(int userId, String pkg) {
+ synchronized (mNotificationLock) {
+ clearAutogroupSummaryLocked(userId, pkg);
+ }
+ }
+ });
+ }
+
private void sendRegisteredOnlyBroadcast(String action) {
getContext().sendBroadcastAsUser(new Intent(action)
.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY), UserHandle.ALL, null);
@@ -3323,7 +3328,6 @@ public class NotificationManagerService extends SystemService {
(r.mOriginalFlags & ~Notification.FLAG_FOREGROUND_SERVICE);
mRankingHelper.sort(mNotificationList);
mListeners.notifyPostedLocked(sbn, sbn /* oldSbn */);
- mGroupHelper.onNotificationPosted(sbn);
}
};
@@ -3740,12 +3744,14 @@ public class NotificationManagerService extends SystemService {
if (notification.getSmallIcon() != null) {
StatusBarNotification oldSbn = (old != null) ? old.sbn : null;
mListeners.notifyPostedLocked(n, oldSbn);
- mHandler.post(new Runnable() {
- @Override
- public void run() {
- mGroupHelper.onNotificationPosted(n);
- }
- });
+ if (oldSbn == null || !Objects.equals(oldSbn.getGroup(), n.getGroup())) {
+ mHandler.post(new Runnable() {
+ @Override
+ public void run() {
+ mGroupHelper.onNotificationPosted(n);
+ }
+ });
+ }
} else {
Slog.e(TAG, "Not posting notification without small icon: " + notification);
if (old != null && !old.isCanceled) {
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 0af3fffb2e3f..e59b9e383d13 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -7209,12 +7209,15 @@ public class PackageManagerService extends IPackageManager.Stub
// load resources from the correct package
installerInfo.resolvePackageName = info.getComponentInfo().packageName;
resolveInfos.set(i, installerInfo);
+ continue;
}
- continue;
}
// caller is a full app, don't need to apply any other filtering
if (ephemeralPkgName == null) {
continue;
+ } else if (ephemeralPkgName.equals(info.activityInfo.packageName)) {
+ // caller is same app; don't need to apply any other filtering
+ continue;
}
// allow activities that have been explicitly exposed to ephemeral apps
if (!isEphemeralApp
diff --git a/services/core/java/com/android/server/timezone/FileDescriptorHelper.java b/services/core/java/com/android/server/timezone/FileDescriptorHelper.java
deleted file mode 100644
index c3b1101000b5..000000000000
--- a/services/core/java/com/android/server/timezone/FileDescriptorHelper.java
+++ /dev/null
@@ -1,30 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server.timezone;
-
-import android.os.ParcelFileDescriptor;
-
-import java.io.IOException;
-
-/**
- * An easy-to-mock interface around use of {@link ParcelFileDescriptor} for use by
- * {@link RulesManagerService}.
- */
-interface FileDescriptorHelper {
-
- byte[] readFully(ParcelFileDescriptor parcelFileDescriptor) throws IOException;
-}
diff --git a/services/core/java/com/android/server/timezone/RulesManagerService.java b/services/core/java/com/android/server/timezone/RulesManagerService.java
index 58bdeb9d11ec..804a8b79310e 100644
--- a/services/core/java/com/android/server/timezone/RulesManagerService.java
+++ b/services/core/java/com/android/server/timezone/RulesManagerService.java
@@ -20,8 +20,8 @@ import com.android.internal.annotations.VisibleForTesting;
import com.android.server.SystemService;
import com.android.timezone.distro.DistroException;
import com.android.timezone.distro.DistroVersion;
-import com.android.timezone.distro.TimeZoneDistro;
import com.android.timezone.distro.StagedDistroOperation;
+import com.android.timezone.distro.TimeZoneDistro;
import android.app.timezone.Callback;
import android.app.timezone.DistroFormatVersion;
@@ -36,7 +36,9 @@ import android.os.RemoteException;
import android.util.Slog;
import java.io.File;
+import java.io.FileInputStream;
import java.io.IOException;
+import java.io.InputStream;
import java.util.Arrays;
import java.util.concurrent.Executor;
import java.util.concurrent.atomic.AtomicBoolean;
@@ -83,26 +85,22 @@ public final class RulesManagerService extends IRulesManager.Stub {
private final PackageTracker mPackageTracker;
private final Executor mExecutor;
private final TimeZoneDistroInstaller mInstaller;
- private final FileDescriptorHelper mFileDescriptorHelper;
private static RulesManagerService create(Context context) {
RulesManagerServiceHelperImpl helper = new RulesManagerServiceHelperImpl(context);
return new RulesManagerService(
helper /* permissionHelper */,
helper /* executor */,
- helper /* fileDescriptorHelper */,
PackageTracker.create(context),
new TimeZoneDistroInstaller(TAG, SYSTEM_TZ_DATA_FILE, TZ_DATA_DIR));
}
// A constructor that can be used by tests to supply mocked / faked dependencies.
RulesManagerService(PermissionHelper permissionHelper,
- Executor executor,
- FileDescriptorHelper fileDescriptorHelper, PackageTracker packageTracker,
+ Executor executor, PackageTracker packageTracker,
TimeZoneDistroInstaller timeZoneDistroInstaller) {
mPermissionHelper = permissionHelper;
mExecutor = executor;
- mFileDescriptorHelper = fileDescriptorHelper;
mPackageTracker = packageTracker;
mInstaller = timeZoneDistroInstaller;
}
@@ -177,55 +175,78 @@ public final class RulesManagerService extends IRulesManager.Stub {
}
@Override
- public int requestInstall(
- ParcelFileDescriptor timeZoneDistro, byte[] checkTokenBytes, ICallback callback) {
- mPermissionHelper.enforceCallerHasPermission(REQUIRED_UPDATER_PERMISSION);
+ public int requestInstall(ParcelFileDescriptor distroParcelFileDescriptor,
+ byte[] checkTokenBytes, ICallback callback) {
- CheckToken checkToken = null;
- if (checkTokenBytes != null) {
- checkToken = createCheckTokenOrThrow(checkTokenBytes);
- }
- synchronized (this) {
- if (timeZoneDistro == null) {
- throw new NullPointerException("timeZoneDistro == null");
- }
- if (callback == null) {
- throw new NullPointerException("observer == null");
- }
- if (mOperationInProgress.get()) {
- return RulesManager.ERROR_OPERATION_IN_PROGRESS;
+ boolean closeParcelFileDescriptorOnExit = true;
+ try {
+ mPermissionHelper.enforceCallerHasPermission(REQUIRED_UPDATER_PERMISSION);
+
+ CheckToken checkToken = null;
+ if (checkTokenBytes != null) {
+ checkToken = createCheckTokenOrThrow(checkTokenBytes);
}
- mOperationInProgress.set(true);
- // Execute the install asynchronously.
- mExecutor.execute(new InstallRunnable(timeZoneDistro, checkToken, callback));
+ synchronized (this) {
+ if (distroParcelFileDescriptor == null) {
+ throw new NullPointerException("distroParcelFileDescriptor == null");
+ }
+ if (callback == null) {
+ throw new NullPointerException("observer == null");
+ }
+ if (mOperationInProgress.get()) {
+ return RulesManager.ERROR_OPERATION_IN_PROGRESS;
+ }
+ mOperationInProgress.set(true);
- return RulesManager.SUCCESS;
+ // Execute the install asynchronously.
+ mExecutor.execute(
+ new InstallRunnable(distroParcelFileDescriptor, checkToken, callback));
+
+ // The InstallRunnable now owns the ParcelFileDescriptor, so it will close it after
+ // it executes (and we do not have to).
+ closeParcelFileDescriptorOnExit = false;
+
+ return RulesManager.SUCCESS;
+ }
+ } finally {
+ // We should close() the local ParcelFileDescriptor we were passed if it hasn't been
+ // passed to another thread to handle.
+ if (distroParcelFileDescriptor != null && closeParcelFileDescriptorOnExit) {
+ try {
+ distroParcelFileDescriptor.close();
+ } catch (IOException e) {
+ Slog.w(TAG, "Failed to close distroParcelFileDescriptor", e);
+ }
+ }
}
}
private class InstallRunnable implements Runnable {
- private final ParcelFileDescriptor mTimeZoneDistro;
+ private final ParcelFileDescriptor mDistroParcelFileDescriptor;
private final CheckToken mCheckToken;
private final ICallback mCallback;
- InstallRunnable(
- ParcelFileDescriptor timeZoneDistro, CheckToken checkToken, ICallback callback) {
- mTimeZoneDistro = timeZoneDistro;
+ InstallRunnable(ParcelFileDescriptor distroParcelFileDescriptor, CheckToken checkToken,
+ ICallback callback) {
+ mDistroParcelFileDescriptor = distroParcelFileDescriptor;
mCheckToken = checkToken;
mCallback = callback;
}
@Override
public void run() {
+ boolean success = false;
// Adopt the ParcelFileDescriptor into this try-with-resources so it is closed
// when we are done.
- boolean success = false;
- try {
- byte[] distroBytes =
- RulesManagerService.this.mFileDescriptorHelper.readFully(mTimeZoneDistro);
- TimeZoneDistro distro = new TimeZoneDistro(distroBytes);
+ try (ParcelFileDescriptor pfd = mDistroParcelFileDescriptor) {
+ // The ParcelFileDescriptor owns the underlying FileDescriptor and we'll close
+ // it at the end of the try-with-resources.
+ final boolean isFdOwner = false;
+ InputStream is = new FileInputStream(pfd.getFileDescriptor(), isFdOwner);
+
+ TimeZoneDistro distro = new TimeZoneDistro(is);
int installerResult = mInstaller.stageInstallWithErrorCode(distro);
int resultCode = mapInstallerResultToApiCode(installerResult);
sendFinishedStatus(mCallback, resultCode);
diff --git a/services/core/java/com/android/server/timezone/RulesManagerServiceHelperImpl.java b/services/core/java/com/android/server/timezone/RulesManagerServiceHelperImpl.java
index 15a571d6750c..482d8e2c8014 100644
--- a/services/core/java/com/android/server/timezone/RulesManagerServiceHelperImpl.java
+++ b/services/core/java/com/android/server/timezone/RulesManagerServiceHelperImpl.java
@@ -27,8 +27,7 @@ import libcore.io.Streams;
/**
* A single class that implements multiple helper interfaces for use by {@link RulesManagerService}.
*/
-final class RulesManagerServiceHelperImpl
- implements PermissionHelper, Executor, FileDescriptorHelper {
+final class RulesManagerServiceHelperImpl implements PermissionHelper, Executor {
private final Context mContext;
@@ -47,13 +46,4 @@ final class RulesManagerServiceHelperImpl
// TODO Is there a better way?
new Thread(runnable).start();
}
-
- @Override
- public byte[] readFully(ParcelFileDescriptor parcelFileDescriptor) throws IOException {
- try (ParcelFileDescriptor pfd = parcelFileDescriptor) {
- // Read bytes
- FileInputStream in = new FileInputStream(pfd.getFileDescriptor(), false /* isOwner */);
- return Streams.readFully(in);
- }
- }
}
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/NetworkLoggingHandler.java b/services/devicepolicy/java/com/android/server/devicepolicy/NetworkLoggingHandler.java
index 70c7e586d3fe..608635491849 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/NetworkLoggingHandler.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/NetworkLoggingHandler.java
@@ -25,8 +25,8 @@ import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.os.SystemClock;
-import android.util.Log;
import android.util.LongSparseArray;
+import android.util.Slog;
import com.android.internal.annotations.GuardedBy;
@@ -60,16 +60,21 @@ final class NetworkLoggingHandler extends Handler {
/** Delay after which older batches get discarded after a retrieval. */
private static final long RETRIEVED_BATCH_DISCARD_DELAY_MS = 5 * 60 * 1000; // 5m
+ /** Do not call into mDpm with locks held */
private final DevicePolicyManagerService mDpm;
private final AlarmManager mAlarmManager;
private final OnAlarmListener mBatchTimeoutAlarmListener = new OnAlarmListener() {
@Override
public void onAlarm() {
- Log.d(TAG, "Received a batch finalization timeout alarm, finalizing "
+ Slog.d(TAG, "Received a batch finalization timeout alarm, finalizing "
+ mNetworkEvents.size() + " pending events.");
+ Bundle notificationExtras = null;
synchronized (NetworkLoggingHandler.this) {
- finalizeBatchAndNotifyDeviceOwnerLocked();
+ notificationExtras = finalizeBatchAndBuildDeviceOwnerMessageLocked();
+ }
+ if (notificationExtras != null) {
+ notifyDeviceOwner(notificationExtras);
}
}
};
@@ -110,17 +115,21 @@ final class NetworkLoggingHandler extends Handler {
case LOG_NETWORK_EVENT_MSG: {
final NetworkEvent networkEvent = msg.getData().getParcelable(NETWORK_EVENT_KEY);
if (networkEvent != null) {
+ Bundle notificationExtras = null;
synchronized (NetworkLoggingHandler.this) {
mNetworkEvents.add(networkEvent);
if (mNetworkEvents.size() >= MAX_EVENTS_PER_BATCH) {
- finalizeBatchAndNotifyDeviceOwnerLocked();
+ notificationExtras = finalizeBatchAndBuildDeviceOwnerMessageLocked();
}
}
+ if (notificationExtras != null) {
+ notifyDeviceOwner(notificationExtras);
+ }
}
break;
}
default: {
- Log.d(TAG, "NetworkLoggingHandler received an unknown of message.");
+ Slog.d(TAG, "NetworkLoggingHandler received an unknown of message.");
break;
}
}
@@ -133,40 +142,48 @@ final class NetworkLoggingHandler extends Handler {
mAlarmManager.setWindow(AlarmManager.ELAPSED_REALTIME_WAKEUP, when,
BATCH_FINALIZATION_TIMEOUT_ALARM_INTERVAL_MS, NETWORK_LOGGING_TIMEOUT_ALARM_TAG,
mBatchTimeoutAlarmListener, this);
- Log.d(TAG, "Scheduled a new batch finalization alarm " + BATCH_FINALIZATION_TIMEOUT_MS
+ Slog.d(TAG, "Scheduled a new batch finalization alarm " + BATCH_FINALIZATION_TIMEOUT_MS
+ "ms from now.");
}
synchronized void pause() {
- Log.d(TAG, "Paused network logging");
+ Slog.d(TAG, "Paused network logging");
mPaused = true;
}
- synchronized void resume() {
- if (!mPaused) {
- Log.d(TAG, "Attempted to resume network logging, but logging is not paused.");
- return;
- }
+ void resume() {
+ Bundle notificationExtras = null;
+ synchronized (this) {
+ if (!mPaused) {
+ Slog.d(TAG, "Attempted to resume network logging, but logging is not paused.");
+ return;
+ }
- Log.d(TAG, "Resumed network logging. Current batch=" + mCurrentBatchToken
- + ", LastRetrievedBatch=" + mLastRetrievedBatchToken);
- mPaused = false;
+ Slog.d(TAG, "Resumed network logging. Current batch=" + mCurrentBatchToken
+ + ", LastRetrievedBatch=" + mLastRetrievedBatchToken);
+ mPaused = false;
- // If there is a batch ready that the device owner hasn't been notified about, do it now.
- if (mBatches.size() > 0 && mLastRetrievedBatchToken != mCurrentBatchToken) {
- scheduleBatchFinalization();
- notifyDeviceOwnerLocked();
+ // If there is a batch ready that the device owner hasn't been notified about, do it now.
+ if (mBatches.size() > 0 && mLastRetrievedBatchToken != mCurrentBatchToken) {
+ scheduleBatchFinalization();
+ notificationExtras = buildDeviceOwnerMessageLocked();
+ }
+ }
+ if (notificationExtras != null) {
+ notifyDeviceOwner(notificationExtras);
}
}
synchronized void discardLogs() {
mBatches.clear();
mNetworkEvents = new ArrayList<>();
- Log.d(TAG, "Discarded all network logs");
+ Slog.d(TAG, "Discarded all network logs");
}
@GuardedBy("this")
- private void finalizeBatchAndNotifyDeviceOwnerLocked() {
+ /** @returns extras if a message should be sent to the device owner */
+ private Bundle finalizeBatchAndBuildDeviceOwnerMessageLocked() {
+ Bundle notificationExtras = null;
if (mNetworkEvents.size() > 0) {
// Finalize the batch and start a new one from scratch.
if (mBatches.size() >= MAX_BATCHES) {
@@ -177,27 +194,39 @@ final class NetworkLoggingHandler extends Handler {
mBatches.append(mCurrentBatchToken, mNetworkEvents);
mNetworkEvents = new ArrayList<>();
if (!mPaused) {
- notifyDeviceOwnerLocked();
+ notificationExtras = buildDeviceOwnerMessageLocked();
}
} else {
// Don't notify the DO, since there are no events; DPC can still retrieve
// the last full batch if not paused.
- Log.d(TAG, "Was about to finalize the batch, but there were no events to send to"
+ Slog.d(TAG, "Was about to finalize the batch, but there were no events to send to"
+ " the DPC, the batchToken of last available batch: " + mCurrentBatchToken);
}
// Regardless of whether the batch was non-empty schedule a new finalization after timeout.
scheduleBatchFinalization();
+ return notificationExtras;
}
- /** Sends a notification to the DO. Should only be called when there is a batch available. */
@GuardedBy("this")
- private void notifyDeviceOwnerLocked() {
+ /** Build extras notification to the DO. Should only be called when there
+ is a batch available. */
+ private Bundle buildDeviceOwnerMessageLocked() {
final Bundle extras = new Bundle();
final int lastBatchSize = mBatches.valueAt(mBatches.size() - 1).size();
extras.putLong(DeviceAdminReceiver.EXTRA_NETWORK_LOGS_TOKEN, mCurrentBatchToken);
extras.putInt(DeviceAdminReceiver.EXTRA_NETWORK_LOGS_COUNT, lastBatchSize);
- Log.d(TAG, "Sending network logging batch broadcast to device owner, batchToken: "
- + mCurrentBatchToken);
+ return extras;
+ }
+
+ /** Sends a notification to the DO. Should not hold locks as DevicePolicyManagerService may
+ call into NetworkLoggingHandler. */
+ private void notifyDeviceOwner(Bundle extras) {
+ Slog.d(TAG, "Sending network logging batch broadcast to device owner, batchToken: "
+ + extras.getLong(DeviceAdminReceiver.EXTRA_NETWORK_LOGS_TOKEN, -1));
+ if (Thread.holdsLock(this)) {
+ Slog.wtfStack(TAG, "Shouldn't be called with NetworkLoggingHandler lock held");
+ return;
+ }
mDpm.sendDeviceOwnerCommand(DeviceAdminReceiver.ACTION_NETWORK_LOGS_AVAILABLE, extras);
}
diff --git a/services/tests/notification/src/com/android/server/notification/NotificationManagerServiceTest.java b/services/tests/notification/src/com/android/server/notification/NotificationManagerServiceTest.java
index d475d6459c72..8ff46394db14 100644
--- a/services/tests/notification/src/com/android/server/notification/NotificationManagerServiceTest.java
+++ b/services/tests/notification/src/com/android/server/notification/NotificationManagerServiceTest.java
@@ -118,6 +118,7 @@ public class NotificationManagerServiceTest extends NotificationTestCase {
private ManagedServices.ManagedServiceInfo mListener;
@Mock private ICompanionDeviceManager mCompanionMgr;
@Mock SnoozeHelper mSnoozeHelper;
+ @Mock GroupHelper mGroupHelper;
// Use a Testable subclass so we can simulate calls from the system without failing.
private static class TestableNotificationManagerService extends NotificationManagerService {
@@ -175,7 +176,7 @@ public class NotificationManagerServiceTest extends NotificationTestCase {
mNotificationManagerService.init(mTestableLooper.getLooper(), mPackageManager,
mPackageManagerClient, mockLightsManager, mNotificationListeners,
mNotificationAssistants, mConditionProviders, mCompanionMgr,
- mSnoozeHelper, mUsageStats, mPolicyFile, mActivityManager);
+ mSnoozeHelper, mUsageStats, mPolicyFile, mActivityManager, mGroupHelper);
} catch (SecurityException e) {
if (!e.getMessage().contains("Permission Denial: not allowed to send broadcast")) {
throw e;
@@ -1086,4 +1087,47 @@ public class NotificationManagerServiceTest extends NotificationTestCase {
verify(mNotificationAssistants, never()).setPackageOrComponentEnabled(
any(), anyInt(), anyBoolean(), anyBoolean());
}
+
+ @Test
+ public void testOnlyAutogroupIfGroupChanged_noPriorNoti_autogroups() throws Exception {
+ NotificationRecord r = generateNotificationRecord(mTestNotificationChannel, 0, null, false);
+ mNotificationManagerService.addEnqueuedNotification(r);
+ NotificationManagerService.PostNotificationRunnable runnable =
+ mNotificationManagerService.new PostNotificationRunnable(r.getKey());
+ runnable.run();
+ waitForIdle();
+
+ verify(mGroupHelper, times(1)).onNotificationPosted(any());
+ }
+
+ @Test
+ public void testOnlyAutogroupIfGroupChanged_groupChanged_autogroups()
+ throws Exception {
+ NotificationRecord r = generateNotificationRecord(mTestNotificationChannel, 0, "group", false);
+ mNotificationManagerService.addNotification(r);
+
+ r = generateNotificationRecord(mTestNotificationChannel, 0, null, false);
+ mNotificationManagerService.addEnqueuedNotification(r);
+ NotificationManagerService.PostNotificationRunnable runnable =
+ mNotificationManagerService.new PostNotificationRunnable(r.getKey());
+ runnable.run();
+ waitForIdle();
+
+ verify(mGroupHelper, times(1)).onNotificationPosted(any());
+ }
+
+ @Test
+ public void testOnlyAutogroupIfGroupChanged_noGroupChanged_autogroups()
+ throws Exception {
+ NotificationRecord r = generateNotificationRecord(mTestNotificationChannel, 0, "group", false);
+ mNotificationManagerService.addNotification(r);
+ mNotificationManagerService.addEnqueuedNotification(r);
+
+ NotificationManagerService.PostNotificationRunnable runnable =
+ mNotificationManagerService.new PostNotificationRunnable(r.getKey());
+ runnable.run();
+ waitForIdle();
+
+ verify(mGroupHelper, never()).onNotificationPosted(any());
+ }
}
diff --git a/services/tests/servicestests/src/com/android/server/timezone/RulesManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/timezone/RulesManagerServiceTest.java
index c3a6f07548c8..3b76d5e05e0e 100644
--- a/services/tests/servicestests/src/com/android/server/timezone/RulesManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/timezone/RulesManagerServiceTest.java
@@ -30,6 +30,8 @@ import android.app.timezone.RulesManager;
import android.app.timezone.RulesState;
import android.os.ParcelFileDescriptor;
+import java.io.File;
+import java.io.FileOutputStream;
import java.io.IOException;
import java.util.concurrent.Executor;
import javax.annotation.Nullable;
@@ -61,7 +63,6 @@ public class RulesManagerServiceTest {
private FakeExecutor mFakeExecutor;
private PermissionHelper mMockPermissionHelper;
- private FileDescriptorHelper mMockFileDescriptorHelper;
private PackageTracker mMockPackageTracker;
private TimeZoneDistroInstaller mMockTimeZoneDistroInstaller;
@@ -69,7 +70,6 @@ public class RulesManagerServiceTest {
public void setUp() {
mFakeExecutor = new FakeExecutor();
- mMockFileDescriptorHelper = mock(FileDescriptorHelper.class);
mMockPackageTracker = mock(PackageTracker.class);
mMockPermissionHelper = mock(PermissionHelper.class);
mMockTimeZoneDistroInstaller = mock(TimeZoneDistroInstaller.class);
@@ -77,7 +77,6 @@ public class RulesManagerServiceTest {
mRulesManagerService = new RulesManagerService(
mMockPermissionHelper,
mFakeExecutor,
- mMockFileDescriptorHelper,
mMockPackageTracker,
mMockTimeZoneDistroInstaller);
}
@@ -273,9 +272,8 @@ public class RulesManagerServiceTest {
revision);
configureInstalledDistroVersion(installedDistroVersion);
- byte[] expectedContent = createArbitraryBytes(1000);
- ParcelFileDescriptor parcelFileDescriptor = createFakeParcelFileDescriptor();
- configureParcelFileDescriptorReadSuccess(parcelFileDescriptor, expectedContent);
+ ParcelFileDescriptor parcelFileDescriptor =
+ createParcelFileDescriptor(createArbitraryBytes(1000));
// Start an async operation so there is one in progress. The mFakeExecutor won't actually
// execute it.
@@ -298,24 +296,27 @@ public class RulesManagerServiceTest {
public void requestInstall_operationInProgress() throws Exception {
configureCallerHasPermission();
- byte[] expectedContent = createArbitraryBytes(1000);
- ParcelFileDescriptor parcelFileDescriptor = createFakeParcelFileDescriptor();
- configureParcelFileDescriptorReadSuccess(parcelFileDescriptor, expectedContent);
+ ParcelFileDescriptor parcelFileDescriptor1 =
+ createParcelFileDescriptor(createArbitraryBytes(1000));
byte[] tokenBytes = createArbitraryTokenBytes();
ICallback callback = new StubbedCallback();
// First request should succeed.
assertEquals(RulesManager.SUCCESS,
- mRulesManagerService.requestInstall(parcelFileDescriptor, tokenBytes, callback));
+ mRulesManagerService.requestInstall(parcelFileDescriptor1, tokenBytes, callback));
// Something async should be enqueued. Clear it but do not execute it so we can detect the
// second request does nothing.
mFakeExecutor.getAndResetLastCommand();
// Second request should fail.
+ ParcelFileDescriptor parcelFileDescriptor2 =
+ createParcelFileDescriptor(createArbitraryBytes(1000));
assertEquals(RulesManager.ERROR_OPERATION_IN_PROGRESS,
- mRulesManagerService.requestInstall(parcelFileDescriptor, tokenBytes, callback));
+ mRulesManagerService.requestInstall(parcelFileDescriptor2, tokenBytes, callback));
+
+ assertClosed(parcelFileDescriptor2);
// Assert nothing async was enqueued.
mFakeExecutor.assertNothingQueued();
@@ -327,9 +328,8 @@ public class RulesManagerServiceTest {
public void requestInstall_badToken() throws Exception {
configureCallerHasPermission();
- byte[] expectedContent = createArbitraryBytes(1000);
- ParcelFileDescriptor parcelFileDescriptor = createFakeParcelFileDescriptor();
- configureParcelFileDescriptorReadSuccess(parcelFileDescriptor, expectedContent);
+ ParcelFileDescriptor parcelFileDescriptor =
+ createParcelFileDescriptor(createArbitraryBytes(1000));
byte[] badTokenBytes = new byte[2];
ICallback callback = new StubbedCallback();
@@ -340,6 +340,8 @@ public class RulesManagerServiceTest {
} catch (IllegalArgumentException expected) {
}
+ assertClosed(parcelFileDescriptor);
+
// Assert nothing async was enqueued.
mFakeExecutor.assertNothingQueued();
verifyNoInstallerCallsMade();
@@ -369,7 +371,8 @@ public class RulesManagerServiceTest {
public void requestInstall_nullCallback() throws Exception {
configureCallerHasPermission();
- ParcelFileDescriptor parcelFileDescriptor = createFakeParcelFileDescriptor();
+ ParcelFileDescriptor parcelFileDescriptor =
+ createParcelFileDescriptor(createArbitraryBytes(1000));
byte[] tokenBytes = createArbitraryTokenBytes();
ICallback callback = null;
@@ -378,6 +381,8 @@ public class RulesManagerServiceTest {
fail();
} catch (NullPointerException expected) {}
+ assertClosed(parcelFileDescriptor);
+
// Assert nothing async was enqueued.
mFakeExecutor.assertNothingQueued();
verifyNoInstallerCallsMade();
@@ -388,9 +393,8 @@ public class RulesManagerServiceTest {
public void requestInstall_asyncSuccess() throws Exception {
configureCallerHasPermission();
- ParcelFileDescriptor parcelFileDescriptor = createFakeParcelFileDescriptor();
- byte[] expectedContent = createArbitraryBytes(1000);
- configureParcelFileDescriptorReadSuccess(parcelFileDescriptor, expectedContent);
+ ParcelFileDescriptor parcelFileDescriptor =
+ createParcelFileDescriptor(createArbitraryBytes(1000));
CheckToken token = createArbitraryToken();
byte[] tokenBytes = token.toByteArray();
@@ -406,14 +410,14 @@ public class RulesManagerServiceTest {
verifyNoInstallerCallsMade();
verifyNoPackageTrackerCallsMade();
- TimeZoneDistro expectedDistro = new TimeZoneDistro(expectedContent);
-
// Set up the installer.
configureStageInstallExpectation(TimeZoneDistroInstaller.INSTALL_SUCCESS);
// Simulate the async execution.
mFakeExecutor.simulateAsyncExecutionOfLastCommand();
+ assertClosed(parcelFileDescriptor);
+
// Verify the expected calls were made to other components.
verifyStageInstallCalled();
verifyPackageTrackerCalled(token, true /* success */);
@@ -426,9 +430,8 @@ public class RulesManagerServiceTest {
public void requestInstall_nullTokenBytes() throws Exception {
configureCallerHasPermission();
- ParcelFileDescriptor parcelFileDescriptor = createFakeParcelFileDescriptor();
- byte[] expectedContent = createArbitraryBytes(1000);
- configureParcelFileDescriptorReadSuccess(parcelFileDescriptor, expectedContent);
+ ParcelFileDescriptor parcelFileDescriptor =
+ createParcelFileDescriptor(createArbitraryBytes(1000));
TestCallback callback = new TestCallback();
@@ -447,6 +450,8 @@ public class RulesManagerServiceTest {
// Simulate the async execution.
mFakeExecutor.simulateAsyncExecutionOfLastCommand();
+ assertClosed(parcelFileDescriptor);
+
// Verify the expected calls were made to other components.
verifyStageInstallCalled();
verifyPackageTrackerCalled(null /* expectedToken */, true /* success */);
@@ -459,9 +464,8 @@ public class RulesManagerServiceTest {
public void requestInstall_asyncInstallFail() throws Exception {
configureCallerHasPermission();
- byte[] expectedContent = createArbitraryBytes(1000);
- ParcelFileDescriptor parcelFileDescriptor = createFakeParcelFileDescriptor();
- configureParcelFileDescriptorReadSuccess(parcelFileDescriptor, expectedContent);
+ ParcelFileDescriptor parcelFileDescriptor =
+ createParcelFileDescriptor(createArbitraryBytes(1000));
CheckToken token = createArbitraryToken();
byte[] tokenBytes = token.toByteArray();
@@ -482,6 +486,8 @@ public class RulesManagerServiceTest {
// Simulate the async execution.
mFakeExecutor.simulateAsyncExecutionOfLastCommand();
+ assertClosed(parcelFileDescriptor);
+
// Verify the expected calls were made to other components.
verifyStageInstallCalled();
@@ -494,38 +500,6 @@ public class RulesManagerServiceTest {
}
@Test
- public void requestInstall_asyncParcelFileDescriptorReadFail() throws Exception {
- configureCallerHasPermission();
-
- ParcelFileDescriptor parcelFileDescriptor = createFakeParcelFileDescriptor();
- configureParcelFileDescriptorReadFailure(parcelFileDescriptor);
-
- CheckToken token = createArbitraryToken();
- byte[] tokenBytes = token.toByteArray();
-
- TestCallback callback = new TestCallback();
-
- // Request the install.
- assertEquals(RulesManager.SUCCESS,
- mRulesManagerService.requestInstall(parcelFileDescriptor, tokenBytes, callback));
-
- // Simulate the async execution.
- mFakeExecutor.simulateAsyncExecutionOfLastCommand();
-
- // Verify nothing else happened.
- verifyNoInstallerCallsMade();
-
- // A failure to read the ParcelFileDescriptor is treated as a failure. It might be the
- // result of a file system error. This is a fairly arbitrary choice.
- verifyPackageTrackerCalled(token, false /* success */);
-
- verifyNoPackageTrackerCallsMade();
-
- // Check the callback was received.
- callback.assertResultReceived(Callback.ERROR_UNKNOWN_FAILURE);
- }
-
- @Test
public void requestUninstall_operationInProgress() throws Exception {
configureCallerHasPermission();
@@ -773,17 +747,6 @@ public class RulesManagerServiceTest {
.enforceCallerHasPermission(REQUIRED_UPDATER_PERMISSION);
}
- private void configureParcelFileDescriptorReadSuccess(ParcelFileDescriptor parcelFileDescriptor,
- byte[] content) throws Exception {
- when(mMockFileDescriptorHelper.readFully(parcelFileDescriptor)).thenReturn(content);
- }
-
- private void configureParcelFileDescriptorReadFailure(ParcelFileDescriptor parcelFileDescriptor)
- throws Exception {
- when(mMockFileDescriptorHelper.readFully(parcelFileDescriptor))
- .thenThrow(new IOException("Simulated failure"));
- }
-
private void configureStageInstallExpectation(int resultCode)
throws Exception {
when(mMockTimeZoneDistroInstaller.stageInstallWithErrorCode(any(TimeZoneDistro.class)))
@@ -827,10 +790,6 @@ public class RulesManagerServiceTest {
return new CheckToken(1, new PackageVersions(1, 1));
}
- private ParcelFileDescriptor createFakeParcelFileDescriptor() {
- return new ParcelFileDescriptor((ParcelFileDescriptor) null);
- }
-
private void configureDeviceSystemRulesVersion(String systemRulesVersion) throws Exception {
when(mMockTimeZoneDistroInstaller.getSystemRulesVersion()).thenReturn(systemRulesVersion);
}
@@ -870,6 +829,10 @@ public class RulesManagerServiceTest {
.thenThrow(new IOException("Simulated failure"));
}
+ private static void assertClosed(ParcelFileDescriptor parcelFileDescriptor) {
+ assertFalse(parcelFileDescriptor.getFileDescriptor().valid());
+ }
+
private static class FakeExecutor implements Executor {
private Runnable mLastCommand;
@@ -926,4 +889,17 @@ public class RulesManagerServiceTest {
fail("Unexpected call");
}
}
+
+ private static ParcelFileDescriptor createParcelFileDescriptor(byte[] bytes)
+ throws IOException {
+ File file = File.createTempFile("pfd", null);
+ try (FileOutputStream fos = new FileOutputStream(file)) {
+ fos.write(bytes);
+ }
+ ParcelFileDescriptor pfd =
+ ParcelFileDescriptor.open(file, ParcelFileDescriptor.MODE_READ_ONLY);
+ // This should now be safe to delete. The ParcelFileDescriptor has an open fd.
+ file.delete();
+ return pfd;
+ }
}
diff --git a/services/usb/java/com/android/server/usb/UsbDebuggingManager.java b/services/usb/java/com/android/server/usb/UsbDebuggingManager.java
index f6d9e9a1a4e4..703f1a1ca656 100644
--- a/services/usb/java/com/android/server/usb/UsbDebuggingManager.java
+++ b/services/usb/java/com/android/server/usb/UsbDebuggingManager.java
@@ -43,12 +43,10 @@ import com.android.internal.util.IndentingPrintWriter;
import com.android.server.FgThread;
import java.io.File;
-import java.io.FileDescriptor;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
-import java.io.PrintWriter;
import java.security.MessageDigest;
import java.util.Arrays;
@@ -56,10 +54,10 @@ public class UsbDebuggingManager {
private static final String TAG = "UsbDebuggingManager";
private static final boolean DEBUG = false;
- private final String ADBD_SOCKET = "adbd";
- private final String ADB_DIRECTORY = "misc/adb";
- private final String ADB_KEYS_FILE = "adb_keys";
- private final int BUFFER_SIZE = 4096;
+ private static final String ADBD_SOCKET = "adbd";
+ private static final String ADB_DIRECTORY = "misc/adb";
+ private static final String ADB_KEYS_FILE = "adb_keys";
+ private static final int BUFFER_SIZE = 4096;
private final Context mContext;
private final Handler mHandler;
@@ -346,7 +344,7 @@ public class UsbDebuggingManager {
}
/**
- * @returns true if the componentName led to an Activity that was started.
+ * @return true if the componentName led to an Activity that was started.
*/
private boolean startConfirmationActivity(ComponentName componentName, UserHandle userHandle,
String key, String fingerprints) {
@@ -365,7 +363,7 @@ public class UsbDebuggingManager {
}
/**
- * @returns true if the componentName led to a Service that was started.
+ * @return true if the componentName led to a Service that was started.
*/
private boolean startConfirmationService(ComponentName componentName, UserHandle userHandle,
String key, String fingerprints) {
diff --git a/services/usb/java/com/android/server/usb/UsbDeviceManager.java b/services/usb/java/com/android/server/usb/UsbDeviceManager.java
index 42272fddb95b..1a24d9571e72 100644
--- a/services/usb/java/com/android/server/usb/UsbDeviceManager.java
+++ b/services/usb/java/com/android/server/usb/UsbDeviceManager.java
@@ -92,14 +92,6 @@ public class UsbDeviceManager {
private static final String USB_CONFIG_PROPERTY = "sys.usb.config";
/**
- * The property which stores the current build type (user/userdebug/eng).
- */
- private static final String BUILD_TYPE_PROPERTY = "ro.build.type";
-
- private static final String BUILD_TYPE_USERDEBUG = "userdebug";
- private static final String BUILD_TYPE_ENG = "eng";
-
- /**
* The non-persistent property which stores the current USB actual state.
*/
private static final String USB_STATE_PROPERTY = "sys.usb.state";
@@ -179,7 +171,7 @@ public class UsbDeviceManager {
private static Set<Integer> sBlackListedInterfaces;
static {
- sBlackListedInterfaces = new HashSet<Integer>();
+ sBlackListedInterfaces = new HashSet<>();
sBlackListedInterfaces.add(UsbConstants.USB_CLASS_AUDIO);
sBlackListedInterfaces.add(UsbConstants.USB_CLASS_COMM);
sBlackListedInterfaces.add(UsbConstants.USB_CLASS_HID);
@@ -191,7 +183,7 @@ public class UsbDeviceManager {
sBlackListedInterfaces.add(UsbConstants.USB_CLASS_CONTENT_SEC);
sBlackListedInterfaces.add(UsbConstants.USB_CLASS_VIDEO);
sBlackListedInterfaces.add(UsbConstants.USB_CLASS_WIRELESS_CONTROLLER);
- };
+ }
private class AdbSettingsObserver extends ContentObserver {
public AdbSettingsObserver() {
@@ -225,44 +217,6 @@ public class UsbDeviceManager {
}
};
- private final BroadcastReceiver mPortReceiver = new BroadcastReceiver() {
- @Override
- public void onReceive(Context context, Intent intent) {
- UsbPort port = intent.getParcelableExtra(UsbManager.EXTRA_PORT);
- UsbPortStatus status = intent.getParcelableExtra(UsbManager.EXTRA_PORT_STATUS);
- mHandler.updateHostState(port, status);
- }
- };
-
- private final BroadcastReceiver mChargingReceiver = new BroadcastReceiver() {
- @Override
- public void onReceive(Context context, Intent intent) {
- int chargePlug = intent.getIntExtra(BatteryManager.EXTRA_PLUGGED, -1);
- boolean usbCharging = chargePlug == BatteryManager.BATTERY_PLUGGED_USB;
- mHandler.sendMessage(MSG_UPDATE_CHARGING_STATE, usbCharging);
- }
- };
-
- private final BroadcastReceiver mHostReceiver = new BroadcastReceiver() {
- @Override
- public void onReceive(Context context, Intent intent) {
- Iterator devices = ((UsbManager) context.getSystemService(Context.USB_SERVICE))
- .getDeviceList().entrySet().iterator();
- if (intent.getAction().equals(UsbManager.ACTION_USB_DEVICE_ATTACHED)) {
- mHandler.sendMessage(MSG_UPDATE_HOST_STATE, devices, true);
- } else {
- mHandler.sendMessage(MSG_UPDATE_HOST_STATE, devices, false);
- }
- }
- };
-
- private final BroadcastReceiver mLanguageChangedReceiver = new BroadcastReceiver() {
- @Override
- public void onReceive(Context context, Intent intent) {
- mHandler.sendEmptyMessage(MSG_LOCALE_CHANGED);
- }
- };
-
public UsbDeviceManager(Context context, UsbAlsaManager alsaManager,
UsbSettingsManager settingsManager) {
mContext = context;
@@ -287,17 +241,56 @@ public class UsbDeviceManager {
if (secureAdbEnabled && !dataEncrypted) {
mDebuggingManager = new UsbDebuggingManager(context);
}
- mContext.registerReceiver(mPortReceiver,
+
+ BroadcastReceiver portReceiver = new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ UsbPort port = intent.getParcelableExtra(UsbManager.EXTRA_PORT);
+ UsbPortStatus status = intent.getParcelableExtra(UsbManager.EXTRA_PORT_STATUS);
+ mHandler.updateHostState(port, status);
+ }
+ };
+
+ BroadcastReceiver chargingReceiver = new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ int chargePlug = intent.getIntExtra(BatteryManager.EXTRA_PLUGGED, -1);
+ boolean usbCharging = chargePlug == BatteryManager.BATTERY_PLUGGED_USB;
+ mHandler.sendMessage(MSG_UPDATE_CHARGING_STATE, usbCharging);
+ }
+ };
+
+ BroadcastReceiver hostReceiver = new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ Iterator devices = ((UsbManager) context.getSystemService(Context.USB_SERVICE))
+ .getDeviceList().entrySet().iterator();
+ if (intent.getAction().equals(UsbManager.ACTION_USB_DEVICE_ATTACHED)) {
+ mHandler.sendMessage(MSG_UPDATE_HOST_STATE, devices, true);
+ } else {
+ mHandler.sendMessage(MSG_UPDATE_HOST_STATE, devices, false);
+ }
+ }
+ };
+
+ BroadcastReceiver languageChangedReceiver = new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ mHandler.sendEmptyMessage(MSG_LOCALE_CHANGED);
+ }
+ };
+
+ mContext.registerReceiver(portReceiver,
new IntentFilter(UsbManager.ACTION_USB_PORT_CHANGED));
- mContext.registerReceiver(mChargingReceiver,
+ mContext.registerReceiver(chargingReceiver,
new IntentFilter(Intent.ACTION_BATTERY_CHANGED));
IntentFilter filter =
new IntentFilter(UsbManager.ACTION_USB_DEVICE_ATTACHED);
filter.addAction(UsbManager.ACTION_USB_DEVICE_DETACHED);
- mContext.registerReceiver(mHostReceiver, filter);
+ mContext.registerReceiver(hostReceiver, filter);
- mContext.registerReceiver(mLanguageChangedReceiver,
+ mContext.registerReceiver(languageChangedReceiver,
new IntentFilter(Intent.ACTION_LOCALE_CHANGED));
}
@@ -326,7 +319,7 @@ public class UsbDeviceManager {
// We do not show the USB notification if the primary volume supports mass storage.
// The legacy mass storage UI will be used instead.
- boolean massStorageSupported = false;
+ boolean massStorageSupported;
final StorageManager storageManager = StorageManager.from(mContext);
final StorageVolume primary = storageManager.getPrimaryVolume();
massStorageSupported = primary != null && primary.allowMassStorage();
@@ -454,7 +447,7 @@ public class UsbDeviceManager {
SystemProperties.get(USB_STATE_PROPERTY));
}
- /**
+ /*
* Use the normal bootmode persistent prop to maintain state of adb across
* all boot modes.
*/
@@ -462,7 +455,7 @@ public class UsbDeviceManager {
SystemProperties.get(USB_PERSISTENT_CONFIG_PROPERTY),
UsbManager.USB_FUNCTION_ADB);
- /**
+ /*
* Previous versions can set persist config to mtp/ptp but it does not
* get reset on OTA. Reset the property here instead.
*/
@@ -652,10 +645,7 @@ public class UsbDeviceManager {
private boolean isNormalBoot() {
String bootMode = SystemProperties.get(BOOT_MODE_PROPERTY, "unknown");
- if (bootMode.equals(NORMAL_BOOT) || bootMode.equals("unknown")) {
- return true;
- }
- return false;
+ return bootMode.equals(NORMAL_BOOT) || bootMode.equals("unknown");
}
private boolean trySetEnabledFunctions(String functions, boolean forceRestart) {
@@ -1311,25 +1301,21 @@ public class UsbDeviceManager {
String[] items = config.split(":");
if (items.length == 3 || items.length == 4) {
if (mOemModeMap == null) {
- mOemModeMap = new HashMap<String, HashMap<String,
- Pair<String, String>>>();
+ mOemModeMap = new HashMap<>();
}
HashMap<String, Pair<String, String>> overrideMap
= mOemModeMap.get(items[0]);
if (overrideMap == null) {
- overrideMap = new HashMap<String,
- Pair<String, String>>();
+ overrideMap = new HashMap<>();
mOemModeMap.put(items[0], overrideMap);
}
// Favoring the first combination if duplicate exists
if (!overrideMap.containsKey(items[1])) {
if (items.length == 3) {
- overrideMap.put(items[1],
- new Pair<String, String>(items[2], ""));
+ overrideMap.put(items[1], new Pair<>(items[2], ""));
} else {
- overrideMap.put(items[1],
- new Pair<String, String>(items[2], items[3]));
+ overrideMap.put(items[1], new Pair<>(items[2], items[3]));
}
}
}
@@ -1390,7 +1376,7 @@ public class UsbDeviceManager {
String bootMode = SystemProperties.get(BOOT_MODE_PROPERTY, "unknown");
String persistProp = USB_PERSISTENT_CONFIG_PROPERTY;
if (!(bootMode.equals(NORMAL_BOOT) || bootMode.equals("unknown"))) {
- if (functions == true) {
+ if (functions) {
persistProp = "persist.sys.usb." + bootMode + ".func";
} else {
persistProp = "persist.sys.usb." + bootMode + ".config";
diff --git a/services/usb/java/com/android/server/usb/UsbHostManager.java b/services/usb/java/com/android/server/usb/UsbHostManager.java
index af78c05ae399..737b572d9f29 100644
--- a/services/usb/java/com/android/server/usb/UsbHostManager.java
+++ b/services/usb/java/com/android/server/usb/UsbHostManager.java
@@ -16,7 +16,6 @@
package com.android.server.usb;
-import android.annotation.NonNull;
import android.annotation.Nullable;
import android.content.ComponentName;
import android.content.Context;
@@ -44,13 +43,11 @@ public class UsbHostManager {
private static final boolean DEBUG = false;
// contains all connected USB devices
- private final HashMap<String, UsbDevice> mDevices = new HashMap<String, UsbDevice>();
-
+ private final HashMap<String, UsbDevice> mDevices = new HashMap<>();
// USB busses to exclude from USB host support
private final String[] mHostBlacklist;
- private final Context mContext;
private final Object mLock = new Object();
private UsbDevice mNewDevice;
@@ -71,7 +68,6 @@ public class UsbHostManager {
public UsbHostManager(Context context, UsbAlsaManager alsaManager,
UsbSettingsManager settingsManager) {
- mContext = context;
mHostBlacklist = context.getResources().getStringArray(
com.android.internal.R.array.config_usbHostBlacklist);
mUsbAlsaManager = alsaManager;
@@ -119,17 +115,14 @@ public class UsbHostManager {
}
/* returns true if the USB device should not be accessible by applications */
- private boolean isBlackListed(int clazz, int subClass, int protocol) {
+ private boolean isBlackListed(int clazz, int subClass) {
// blacklist hubs
if (clazz == UsbConstants.USB_CLASS_HUB) return true;
// blacklist HID boot devices (mouse and keyboard)
- if (clazz == UsbConstants.USB_CLASS_HID &&
- subClass == UsbConstants.USB_INTERFACE_SUBCLASS_BOOT) {
- return true;
- }
+ return clazz == UsbConstants.USB_CLASS_HID
+ && subClass == UsbConstants.USB_INTERFACE_SUBCLASS_BOOT;
- return false;
}
/* Called from JNI in monitorUsbHostBus() to report new USB devices
@@ -137,6 +130,7 @@ public class UsbHostManager {
interfaces and endpoints, and finally call endUsbDeviceAdded after all descriptors
have been processed
*/
+ @SuppressWarnings("unused")
private boolean beginUsbDeviceAdded(String deviceName, int vendorID, int productID,
int deviceClass, int deviceSubclass, int deviceProtocol,
String manufacturerName, String productName, int version, String serialNumber) {
@@ -161,7 +155,7 @@ public class UsbHostManager {
// such test until endUsbDeviceAdded() when we have that info.
if (isBlackListed(deviceName) ||
- isBlackListed(deviceClass, deviceSubclass, deviceProtocol)) {
+ isBlackListed(deviceClass, deviceSubclass)) {
return false;
}
@@ -183,9 +177,9 @@ public class UsbHostManager {
deviceClass, deviceSubclass, deviceProtocol,
manufacturerName, productName, versionString, serialNumber);
- mNewConfigurations = new ArrayList<UsbConfiguration>();
- mNewInterfaces = new ArrayList<UsbInterface>();
- mNewEndpoints = new ArrayList<UsbEndpoint>();
+ mNewConfigurations = new ArrayList<>();
+ mNewInterfaces = new ArrayList<>();
+ mNewEndpoints = new ArrayList<>();
}
return true;
@@ -194,6 +188,7 @@ public class UsbHostManager {
/* Called from JNI in monitorUsbHostBus() to report new USB configuration for the device
currently being added. Returns true if successful, false in case of error.
*/
+ @SuppressWarnings("unused")
private void addUsbConfiguration(int id, String name, int attributes, int maxPower) {
if (mNewConfiguration != null) {
mNewConfiguration.setInterfaces(
@@ -208,6 +203,7 @@ public class UsbHostManager {
/* Called from JNI in monitorUsbHostBus() to report new USB interface for the device
currently being added. Returns true if successful, false in case of error.
*/
+ @SuppressWarnings("unused")
private void addUsbInterface(int id, String name, int altSetting,
int Class, int subClass, int protocol) {
if (mNewInterface != null) {
@@ -223,11 +219,13 @@ public class UsbHostManager {
/* Called from JNI in monitorUsbHostBus() to report new USB endpoint for the device
currently being added. Returns true if successful, false in case of error.
*/
+ @SuppressWarnings("unused")
private void addUsbEndpoint(int address, int attributes, int maxPacketSize, int interval) {
mNewEndpoints.add(new UsbEndpoint(address, attributes, maxPacketSize, interval));
}
/* Called from JNI in monitorUsbHostBus() to finish adding a new device */
+ @SuppressWarnings("unused")
private void endUsbDeviceAdded() {
if (DEBUG) {
Slog.d(TAG, "usb:UsbHostManager.endUsbDeviceAdded()");
@@ -273,6 +271,7 @@ public class UsbHostManager {
}
/* Called from JNI in monitorUsbHostBus to report USB device removal */
+ @SuppressWarnings("unused")
private void usbDeviceRemoved(String deviceName) {
synchronized (mLock) {
UsbDevice device = mDevices.remove(deviceName);
@@ -288,11 +287,7 @@ public class UsbHostManager {
synchronized (mLock) {
// Create a thread to call into native code to wait for USB host events.
// This thread will call us back on usbDeviceAdded and usbDeviceRemoved.
- Runnable runnable = new Runnable() {
- public void run() {
- monitorUsbHostBus();
- }
- };
+ Runnable runnable = this::monitorUsbHostBus;
new Thread(null, runnable, "UsbService host thread").start();
}
}
diff --git a/services/usb/java/com/android/server/usb/UsbPortManager.java b/services/usb/java/com/android/server/usb/UsbPortManager.java
index 7e2496c4f0f3..e28513a29a3a 100644
--- a/services/usb/java/com/android/server/usb/UsbPortManager.java
+++ b/services/usb/java/com/android/server/usb/UsbPortManager.java
@@ -87,9 +87,6 @@ public class UsbPortManager {
// Mostly due a command sent by the remote Usb device.
private HALCallback mHALCallback = new HALCallback(null, this);
- // Notification object used to listen to the start of the usb daemon.
- private final ServiceNotification mServiceNotification = new ServiceNotification();
-
// Cookie sent for usb hal death notification.
private static final int USB_HAL_DEATH_COOKIE = 1000;
@@ -107,18 +104,20 @@ public class UsbPortManager {
// Ports may temporarily have different dispositions as they are added or removed
// but the class invariant is that this list will only contain ports with DISPOSITION_READY
// except while updatePortsLocked() is in progress.
- private final ArrayMap<String, PortInfo> mPorts = new ArrayMap<String, PortInfo>();
+ private final ArrayMap<String, PortInfo> mPorts = new ArrayMap<>();
// List of all simulated ports, indexed by id.
private final ArrayMap<String, RawPortInfo> mSimulatedPorts =
- new ArrayMap<String, RawPortInfo>();
+ new ArrayMap<>();
public UsbPortManager(Context context) {
mContext = context;
try {
+ ServiceNotification serviceNotification = new ServiceNotification();
+
boolean ret = IServiceManager.getService()
.registerForNotifications("android.hardware.usb@1.0::IUsb",
- "", mServiceNotification);
+ "", serviceNotification);
if (!ret) {
logAndPrint(Log.ERROR, null,
"Failed to register service start notification");
@@ -258,7 +257,6 @@ public class UsbPortManager {
logAndPrintException(pw, "Failed to set the USB port mode: "
+ "portId=" + portId
+ ", newMode=" + UsbPort.modeToString(newRole.role), e);
- return;
}
} else {
// Change power and data role independently as needed.
@@ -289,7 +287,6 @@ public class UsbPortManager {
+ ", newDataRole=" + UsbPort.dataRoleToString(newRole
.role),
e);
- return;
}
}
}
@@ -415,10 +412,6 @@ public class UsbPortManager {
public IndentingPrintWriter pw;
public UsbPortManager portManager;
- HALCallback() {
- super();
- }
-
HALCallback(IndentingPrintWriter pw, UsbPortManager portManager) {
this.pw = pw;
this.portManager = portManager;
@@ -434,7 +427,7 @@ public class UsbPortManager {
return;
}
- ArrayList<RawPortInfo> newPortInfo = new ArrayList<RawPortInfo>();
+ ArrayList<RawPortInfo> newPortInfo = new ArrayList<>();
for (PortStatus current : currentPortStatus) {
RawPortInfo temp = new RawPortInfo(current.portName,
@@ -452,7 +445,6 @@ public class UsbPortManager {
message.what = MSG_UPDATE_PORTS;
message.setData(bundle);
portManager.mHandler.sendMessage(message);
- return;
}
@@ -467,7 +459,7 @@ public class UsbPortManager {
return;
}
- ArrayList<RawPortInfo> newPortInfo = new ArrayList<RawPortInfo>();
+ ArrayList<RawPortInfo> newPortInfo = new ArrayList<>();
for (PortStatus_1_1 current : currentPortStatus) {
RawPortInfo temp = new RawPortInfo(current.status.portName,
@@ -485,7 +477,6 @@ public class UsbPortManager {
message.what = MSG_UPDATE_PORTS;
message.setData(bundle);
portManager.mHandler.sendMessage(message);
- return;
}
public void notifyRoleSwitchStatus(String portName, PortRole role, int retval) {
@@ -495,7 +486,7 @@ public class UsbPortManager {
logAndPrint(Log.ERROR, pw, portName + " role switch failed");
}
}
- };
+ }
final class DeathRecipient implements HwBinder.DeathRecipient {
public IndentingPrintWriter pw;
@@ -701,12 +692,7 @@ public class UsbPortManager {
// Guard against possible reentrance by posting the broadcast from the handler
// instead of from within the critical section.
- mHandler.post(new Runnable() {
- @Override
- public void run() {
- mContext.sendBroadcastAsUser(intent, UserHandle.ALL);
- }
- });
+ mHandler.post(() -> mContext.sendBroadcastAsUser(intent, UserHandle.ALL));
}
private static void logAndPrint(int priority, IndentingPrintWriter pw, String msg) {
diff --git a/services/usb/java/com/android/server/usb/UsbProfileGroupSettingsManager.java b/services/usb/java/com/android/server/usb/UsbProfileGroupSettingsManager.java
index 840ae221df30..ebb5a62ce7ec 100644
--- a/services/usb/java/com/android/server/usb/UsbProfileGroupSettingsManager.java
+++ b/services/usb/java/com/android/server/usb/UsbProfileGroupSettingsManager.java
@@ -225,7 +225,7 @@ class UsbProfileGroupSettingsManager {
} else if ("serial-number".equals(name)) {
serialNumber = value;
} else {
- int intValue = -1;
+ int intValue;
int radix = 10;
if (value != null && value.length() > 2 && value.charAt(0) == '0' &&
(value.charAt(1) == 'x' || value.charAt(1) == 'X')) {
@@ -388,9 +388,9 @@ class UsbProfileGroupSettingsManager {
(filter.mSerialNumber != null &&
mSerialNumber != null &&
!mSerialNumber.equals(filter.mSerialNumber))) {
- return(false);
+ return false;
}
- return(true);
+ return true;
}
if (obj instanceof UsbDevice) {
UsbDevice device = (UsbDevice)obj;
@@ -415,7 +415,7 @@ class UsbProfileGroupSettingsManager {
!mProductName.equals(device.getProductName())) ||
(device.getSerialNumber() != null &&
!mSerialNumber.equals(device.getSerialNumber()))) {
- return(false);
+ return false;
}
return true;
}
@@ -501,8 +501,7 @@ class UsbProfileGroupSettingsManager {
public boolean matches(UsbAccessory acc) {
if (mManufacturer != null && !acc.getManufacturer().equals(mManufacturer)) return false;
if (mModel != null && !acc.getModel().equals(mModel)) return false;
- if (mVersion != null && !acc.getVersion().equals(mVersion)) return false;
- return true;
+ return !(mVersion != null && !acc.getVersion().equals(mVersion));
}
/**
@@ -517,8 +516,7 @@ class UsbProfileGroupSettingsManager {
return false;
}
if (mModel != null && !Objects.equals(accessory.mModel, mModel)) return false;
- if (mVersion != null && !Objects.equals(accessory.mVersion, mVersion)) return false;
- return true;
+ return !(mVersion != null && !Objects.equals(accessory.mVersion, mVersion));
}
@Override
@@ -624,13 +622,8 @@ class UsbProfileGroupSettingsManager {
mPackageMonitor.register(context, null, UserHandle.ALL, true);
mMtpNotificationManager = new MtpNotificationManager(
parentUserContext,
- new MtpNotificationManager.OnOpenInAppListener() {
- @Override
- public void onOpenInApp(UsbDevice device) {
- resolveActivity(createDeviceAttachedIntent(device),
- device, false /* showMtpNotification */);
- }
- });
+ device -> resolveActivity(createDeviceAttachedIntent(device),
+ device, false /* showMtpNotification */));
}
/**
@@ -727,9 +720,7 @@ class UsbProfileGroupSettingsManager {
XmlUtils.nextElement(parser);
}
}
- } catch (IOException e) {
- Log.wtf(TAG, "Failed to read single-user settings", e);
- } catch (XmlPullParserException e) {
+ } catch (IOException | XmlPullParserException e) {
Log.wtf(TAG, "Failed to read single-user settings", e);
} finally {
IoUtils.closeQuietly(fis);
@@ -1015,8 +1006,8 @@ class UsbProfileGroupSettingsManager {
}
}
- private final ArrayList<ResolveInfo> getDeviceMatchesLocked(UsbDevice device, Intent intent) {
- ArrayList<ResolveInfo> matches = new ArrayList<ResolveInfo>();
+ private ArrayList<ResolveInfo> getDeviceMatchesLocked(UsbDevice device, Intent intent) {
+ ArrayList<ResolveInfo> matches = new ArrayList<>();
List<ResolveInfo> resolveInfos = queryIntentActivitiesForAllProfiles(intent);
int count = resolveInfos.size();
for (int i = 0; i < count; i++) {
@@ -1029,9 +1020,9 @@ class UsbProfileGroupSettingsManager {
return removeForwardIntentIfNotNeeded(preferHighPriority(matches));
}
- private final ArrayList<ResolveInfo> getAccessoryMatchesLocked(
+ private ArrayList<ResolveInfo> getAccessoryMatchesLocked(
UsbAccessory accessory, Intent intent) {
- ArrayList<ResolveInfo> matches = new ArrayList<ResolveInfo>();
+ ArrayList<ResolveInfo> matches = new ArrayList<>();
List<ResolveInfo> resolveInfos = queryIntentActivitiesForAllProfiles(intent);
int count = resolveInfos.size();
for (int i = 0; i < count; i++) {
@@ -1402,7 +1393,7 @@ class UsbProfileGroupSettingsManager {
void setDevicePackage(@NonNull UsbDevice device, @Nullable String packageName,
@NonNull UserHandle user) {
DeviceFilter filter = new DeviceFilter(device);
- boolean changed = false;
+ boolean changed;
synchronized (mLock) {
if (packageName == null) {
changed = (mDevicePreferenceMap.remove(filter) != null);
@@ -1430,7 +1421,7 @@ class UsbProfileGroupSettingsManager {
void setAccessoryPackage(@NonNull UsbAccessory accessory, @Nullable String packageName,
@NonNull UserHandle user) {
AccessoryFilter filter = new AccessoryFilter(accessory);
- boolean changed = false;
+ boolean changed;
synchronized (mLock) {
if (packageName == null) {
changed = (mAccessoryPreferenceMap.remove(filter) != null);
@@ -1460,8 +1451,7 @@ class UsbProfileGroupSettingsManager {
UserPackage userPackage = new UserPackage(packageName, user);
synchronized (mLock) {
if (mDevicePreferenceMap.values().contains(userPackage)) return true;
- if (mAccessoryPreferenceMap.values().contains(userPackage)) return true;
- return false;
+ return mAccessoryPreferenceMap.values().contains(userPackage);
}
}
@@ -1493,9 +1483,9 @@ class UsbProfileGroupSettingsManager {
synchronized (mLock) {
if (mDevicePreferenceMap.containsValue(userPackage)) {
// make a copy of the key set to avoid ConcurrentModificationException
- Object[] keys = mDevicePreferenceMap.keySet().toArray();
+ DeviceFilter[] keys = mDevicePreferenceMap.keySet().toArray(new DeviceFilter[0]);
for (int i = 0; i < keys.length; i++) {
- Object key = keys[i];
+ DeviceFilter key = keys[i];
if (userPackage.equals(mDevicePreferenceMap.get(key))) {
mDevicePreferenceMap.remove(key);
cleared = true;
@@ -1504,9 +1494,10 @@ class UsbProfileGroupSettingsManager {
}
if (mAccessoryPreferenceMap.containsValue(userPackage)) {
// make a copy of the key set to avoid ConcurrentModificationException
- Object[] keys = mAccessoryPreferenceMap.keySet().toArray();
+ AccessoryFilter[] keys =
+ mAccessoryPreferenceMap.keySet().toArray(new AccessoryFilter[0]);
for (int i = 0; i < keys.length; i++) {
- Object key = keys[i];
+ AccessoryFilter key = keys[i];
if (userPackage.equals(mAccessoryPreferenceMap.get(key))) {
mAccessoryPreferenceMap.remove(key);
cleared = true;
diff --git a/services/usb/java/com/android/server/usb/UsbService.java b/services/usb/java/com/android/server/usb/UsbService.java
index 61e1e8f28c59..e4fcea77fa44 100644
--- a/services/usb/java/com/android/server/usb/UsbService.java
+++ b/services/usb/java/com/android/server/usb/UsbService.java
@@ -134,25 +134,25 @@ public class UsbService extends IUsbManager.Stub {
onSwitchUser(UserHandle.USER_SYSTEM);
+ BroadcastReceiver receiver = new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ final String action = intent.getAction();
+ if (DevicePolicyManager.ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED
+ .equals(action)) {
+ if (mDeviceManager != null) {
+ mDeviceManager.updateUserRestrictions();
+ }
+ }
+ }
+ };
+
final IntentFilter filter = new IntentFilter();
filter.setPriority(IntentFilter.SYSTEM_HIGH_PRIORITY);
filter.addAction(DevicePolicyManager.ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED);
- mContext.registerReceiver(mReceiver, filter, null, null);
+ mContext.registerReceiver(receiver, filter, null, null);
}
- private BroadcastReceiver mReceiver = new BroadcastReceiver() {
- @Override
- public void onReceive(Context context, Intent intent) {
- final String action = intent.getAction();
- if (DevicePolicyManager.ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED
- .equals(action)) {
- if (mDeviceManager != null) {
- mDeviceManager.updateUserRestrictions();
- }
- }
- }
- };
-
/**
* Set new {@link #mCurrentUserId} and propagate it to other modules.
*
@@ -681,7 +681,7 @@ public class UsbService extends IUsbManager.Stub {
}
}
- private static final String removeLastChar(String value) {
+ private static String removeLastChar(String value) {
return value.substring(0, value.length() - 1);
}
}
diff --git a/services/usb/java/com/android/server/usb/UsbSettingsManager.java b/services/usb/java/com/android/server/usb/UsbSettingsManager.java
index 7a55be43ffd5..c7e5998db70d 100644
--- a/services/usb/java/com/android/server/usb/UsbSettingsManager.java
+++ b/services/usb/java/com/android/server/usb/UsbSettingsManager.java
@@ -28,6 +28,7 @@ import android.os.UserHandle;
import android.os.UserManager;
import android.util.Slog;
import android.util.SparseArray;
+
import com.android.internal.annotations.GuardedBy;
import com.android.internal.util.IndentingPrintWriter;
diff --git a/services/usb/java/com/android/server/usb/UsbUserSettingsManager.java b/services/usb/java/com/android/server/usb/UsbUserSettingsManager.java
index 4a34ece9524e..96c5211cecf4 100644
--- a/services/usb/java/com/android/server/usb/UsbUserSettingsManager.java
+++ b/services/usb/java/com/android/server/usb/UsbUserSettingsManager.java
@@ -32,6 +32,7 @@ import android.os.Process;
import android.os.UserHandle;
import android.util.Slog;
import android.util.SparseBooleanArray;
+
import com.android.internal.util.IndentingPrintWriter;
import java.util.HashMap;
@@ -48,10 +49,10 @@ class UsbUserSettingsManager {
// Temporary mapping USB device name to list of UIDs with permissions for the device
private final HashMap<String, SparseBooleanArray> mDevicePermissionMap =
- new HashMap<String, SparseBooleanArray>();
+ new HashMap<>();
// Temporary mapping UsbAccessory to list of UIDs with permissions for the accessory
private final HashMap<UsbAccessory, SparseBooleanArray> mAccessoryPermissionMap =
- new HashMap<UsbAccessory, SparseBooleanArray>();
+ new HashMap<>();
private final Object mLock = new Object();
diff --git a/telephony/java/android/telephony/euicc/EuiccManager.java b/telephony/java/android/telephony/euicc/EuiccManager.java
index 11770fb06c95..f22a6327c80f 100644
--- a/telephony/java/android/telephony/euicc/EuiccManager.java
+++ b/telephony/java/android/telephony/euicc/EuiccManager.java
@@ -320,7 +320,8 @@ public class EuiccManager {
return;
}
try {
- mController.getDownloadableSubscriptionMetadata(subscription, callbackIntent);
+ mController.getDownloadableSubscriptionMetadata(
+ subscription, mContext.getOpPackageName(), callbackIntent);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -349,7 +350,8 @@ public class EuiccManager {
return;
}
try {
- mController.getDefaultDownloadableSubscriptionList(callbackIntent);
+ mController.getDefaultDownloadableSubscriptionList(
+ mContext.getOpPackageName(), callbackIntent);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
diff --git a/telephony/java/com/android/internal/telephony/euicc/IEuiccController.aidl b/telephony/java/com/android/internal/telephony/euicc/IEuiccController.aidl
index 725b89bcf351..fa43631cee9e 100644
--- a/telephony/java/com/android/internal/telephony/euicc/IEuiccController.aidl
+++ b/telephony/java/com/android/internal/telephony/euicc/IEuiccController.aidl
@@ -26,8 +26,9 @@ import android.telephony.euicc.EuiccInfo;
interface IEuiccController {
oneway void continueOperation(in Intent resolutionIntent, in Bundle resolutionExtras);
oneway void getDownloadableSubscriptionMetadata(in DownloadableSubscription subscription,
- in PendingIntent callbackIntent);
- oneway void getDefaultDownloadableSubscriptionList(in PendingIntent callbackIntent);
+ String callingPackage, in PendingIntent callbackIntent);
+ oneway void getDefaultDownloadableSubscriptionList(
+ String callingPackage, in PendingIntent callbackIntent);
String getEid();
oneway void downloadSubscription(in DownloadableSubscription subscription,
boolean switchAfterDownload, String callingPackage, in PendingIntent callbackIntent);
diff --git a/test-runner/src/android/test/ClassPathPackageInfo.java b/test-runner/src/android/test/ClassPathPackageInfo.java
deleted file mode 100644
index 2cf76afa1d94..000000000000
--- a/test-runner/src/android/test/ClassPathPackageInfo.java
+++ /dev/null
@@ -1,79 +0,0 @@
-/*
- * Copyright (C) 2008 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.test;
-
-import java.util.Collections;
-import java.util.HashSet;
-import java.util.Set;
-
-/**
- * The Package object doesn't allow you to iterate over the contained
- * classes and subpackages of that package. This is a version that does.
- *
- * {@hide} Not needed for 1.0 SDK.
- */
-@Deprecated
-public class ClassPathPackageInfo {
-
- private final ClassPathPackageInfoSource source;
- private final String packageName;
- private final Set<String> subpackageNames;
- private final Set<Class<?>> topLevelClasses;
-
- ClassPathPackageInfo(ClassPathPackageInfoSource source, String packageName,
- Set<String> subpackageNames, Set<Class<?>> topLevelClasses) {
- this.source = source;
- this.packageName = packageName;
- this.subpackageNames = Collections.unmodifiableSet(subpackageNames);
- this.topLevelClasses = Collections.unmodifiableSet(topLevelClasses);
- }
-
- public Set<ClassPathPackageInfo> getSubpackages() {
- Set<ClassPathPackageInfo> info = new HashSet<>();
- for (String name : subpackageNames) {
- info.add(source.getPackageInfo(name));
- }
- return info;
- }
-
- public Set<Class<?>> getTopLevelClassesRecursive() {
- Set<Class<?>> set = new HashSet<>();
- addTopLevelClassesTo(set);
- return set;
- }
-
- private void addTopLevelClassesTo(Set<Class<?>> set) {
- set.addAll(topLevelClasses);
- for (ClassPathPackageInfo info : getSubpackages()) {
- info.addTopLevelClassesTo(set);
- }
- }
-
- @Override
- public boolean equals(Object obj) {
- if (obj instanceof ClassPathPackageInfo) {
- ClassPathPackageInfo that = (ClassPathPackageInfo) obj;
- return (this.packageName).equals(that.packageName);
- }
- return false;
- }
-
- @Override
- public int hashCode() {
- return packageName.hashCode();
- }
-}
diff --git a/test-runner/src/android/test/ClassPathPackageInfoSource.java b/test-runner/src/android/test/ClassPathPackageInfoSource.java
index 9bcc25adf8d3..755b540cbbb8 100644
--- a/test-runner/src/android/test/ClassPathPackageInfoSource.java
+++ b/test-runner/src/android/test/ClassPathPackageInfoSource.java
@@ -21,15 +21,12 @@ import dalvik.system.DexFile;
import java.io.File;
import java.io.IOException;
+import java.util.Collections;
import java.util.Enumeration;
-import java.util.HashMap;
import java.util.HashSet;
-import java.util.Map;
import java.util.Set;
import java.util.TreeSet;
import java.util.regex.Pattern;
-import java.util.zip.ZipEntry;
-import java.util.zip.ZipFile;
/**
* Generate {@link ClassPathPackageInfo}s by scanning apk paths.
@@ -39,11 +36,13 @@ import java.util.zip.ZipFile;
@Deprecated
public class ClassPathPackageInfoSource {
- private static final String CLASS_EXTENSION = ".class";
-
private static final ClassLoader CLASS_LOADER
= ClassPathPackageInfoSource.class.getClassLoader();
+ private static String[] apkPaths;
+
+ private static ClassPathPackageInfoSource classPathSource;
+
private final SimpleCache<String, ClassPathPackageInfo> cache =
new SimpleCache<String, ClassPathPackageInfo>() {
@Override
@@ -54,23 +53,28 @@ public class ClassPathPackageInfoSource {
// The class path of the running application
private final String[] classPath;
- private static String[] apkPaths;
- // A cache of jar file contents
- private final Map<File, Set<String>> jarFiles = new HashMap<>();
- private ClassLoader classLoader;
+ private final ClassLoader classLoader;
- ClassPathPackageInfoSource() {
+ private ClassPathPackageInfoSource(ClassLoader classLoader) {
+ this.classLoader = classLoader;
classPath = getClassPath();
}
-
- public static void setApkPaths(String[] apkPaths) {
+ static void setApkPaths(String[] apkPaths) {
ClassPathPackageInfoSource.apkPaths = apkPaths;
}
- public ClassPathPackageInfo getPackageInfo(String pkgName) {
- return cache.get(pkgName);
+ public static ClassPathPackageInfoSource forClassPath(ClassLoader classLoader) {
+ if (classPathSource == null) {
+ classPathSource = new ClassPathPackageInfoSource(classLoader);
+ }
+ return classPathSource;
+ }
+
+ public Set<Class<?>> getTopLevelClassesRecursive(String packageName) {
+ ClassPathPackageInfo packageInfo = cache.get(packageName);
+ return packageInfo.getTopLevelClassesRecursive();
}
private ClassPathPackageInfo createPackageInfo(String packageName) {
@@ -96,7 +100,7 @@ public class ClassPathPackageInfoSource {
+ "'. Message: " + e.getMessage(), e);
}
}
- return new ClassPathPackageInfo(this, packageName, subpackageNames,
+ return new ClassPathPackageInfo(packageName, subpackageNames,
topLevelClasses);
}
@@ -107,9 +111,6 @@ public class ClassPathPackageInfoSource {
*/
private void findClasses(String packageName, Set<String> classNames,
Set<String> subpackageNames) {
- String packagePrefix = packageName + '.';
- String pathPrefix = packagePrefix.replace('.', '/');
-
for (String entryName : classPath) {
File classPathEntry = new File(entryName);
@@ -150,58 +151,6 @@ public class ClassPathPackageInfoSource {
/**
* Finds all classes and sub packages that are below the packageName and
- * add them to the respective sets. Searches the package in a class directory.
- */
- private void findClassesInDirectory(File classDir,
- String packagePrefix, String pathPrefix, Set<String> classNames,
- Set<String> subpackageNames)
- throws IOException {
- File directory = new File(classDir, pathPrefix);
-
- if (directory.exists()) {
- for (File f : directory.listFiles()) {
- String name = f.getName();
- if (name.endsWith(CLASS_EXTENSION) && isToplevelClass(name)) {
- classNames.add(packagePrefix + getClassName(name));
- } else if (f.isDirectory()) {
- subpackageNames.add(packagePrefix + name);
- }
- }
- }
- }
-
- /**
- * Finds all classes and sub packages that are below the packageName and
- * add them to the respective sets. Searches the package in a single jar file.
- */
- private void findClassesInJar(File jarFile, String pathPrefix,
- Set<String> classNames, Set<String> subpackageNames)
- throws IOException {
- Set<String> entryNames = getJarEntries(jarFile);
- // check if the Jar contains the package.
- if (!entryNames.contains(pathPrefix)) {
- return;
- }
- int prefixLength = pathPrefix.length();
- for (String entryName : entryNames) {
- if (entryName.startsWith(pathPrefix)) {
- if (entryName.endsWith(CLASS_EXTENSION)) {
- // check if the class is in the package itself or in one of its
- // subpackages.
- int index = entryName.indexOf('/', prefixLength);
- if (index >= 0) {
- String p = entryName.substring(0, index).replace('/', '.');
- subpackageNames.add(p);
- } else if (isToplevelClass(entryName)) {
- classNames.add(getClassName(entryName).replace('/', '.'));
- }
- }
- }
- }
- }
-
- /**
- * Finds all classes and sub packages that are below the packageName and
* add them to the respective sets. Searches the package in a single apk file.
*/
private void findClassesInApk(String apkPath, String packageName,
@@ -242,47 +191,6 @@ public class ClassPathPackageInfoSource {
}
/**
- * Gets the class and package entries from a Jar.
- */
- private Set<String> getJarEntries(File jarFile)
- throws IOException {
- Set<String> entryNames = jarFiles.get(jarFile);
- if (entryNames == null) {
- entryNames = new HashSet<>();
- ZipFile zipFile = new ZipFile(jarFile);
- Enumeration<? extends ZipEntry> entries = zipFile.entries();
- while (entries.hasMoreElements()) {
- String entryName = entries.nextElement().getName();
- if (entryName.endsWith(CLASS_EXTENSION)) {
- // add the entry name of the class
- entryNames.add(entryName);
-
- // add the entry name of the classes package, i.e. the entry name of
- // the directory that the class is in. Used to quickly skip jar files
- // if they do not contain a certain package.
- //
- // Also add parent packages so that a JAR that contains
- // pkg1/pkg2/Foo.class will be marked as containing pkg1/ in addition
- // to pkg1/pkg2/ and pkg1/pkg2/Foo.class. We're still interested in
- // JAR files that contains subpackages of a given package, even if
- // an intermediate package contains no direct classes.
- //
- // Classes in the default package will cause a single package named
- // "" to be added instead.
- int lastIndex = entryName.lastIndexOf('/');
- do {
- String packageName = entryName.substring(0, lastIndex + 1);
- entryNames.add(packageName);
- lastIndex = entryName.lastIndexOf('/', lastIndex - 1);
- } while (lastIndex > 0);
- }
- }
- jarFiles.put(jarFile, entryNames);
- }
- return entryNames;
- }
-
- /**
* Checks if a given file name represents a toplevel class.
*/
private static boolean isToplevelClass(String fileName) {
@@ -290,14 +198,6 @@ public class ClassPathPackageInfoSource {
}
/**
- * Given the absolute path of a class file, return the class name.
- */
- private static String getClassName(String className) {
- int classNameEnd = className.length() - CLASS_EXTENSION.length();
- return className.substring(0, classNameEnd);
- }
-
- /**
* Gets the class path from the System Property "java.class.path" and splits
* it up into the individual elements.
*/
@@ -307,7 +207,56 @@ public class ClassPathPackageInfoSource {
return classPath.split(Pattern.quote(separator));
}
- public void setClassLoader(ClassLoader classLoader) {
- this.classLoader = classLoader;
+ /**
+ * The Package object doesn't allow you to iterate over the contained
+ * classes and subpackages of that package. This is a version that does.
+ */
+ private class ClassPathPackageInfo {
+
+ private final String packageName;
+ private final Set<String> subpackageNames;
+ private final Set<Class<?>> topLevelClasses;
+
+ private ClassPathPackageInfo(String packageName,
+ Set<String> subpackageNames, Set<Class<?>> topLevelClasses) {
+ this.packageName = packageName;
+ this.subpackageNames = Collections.unmodifiableSet(subpackageNames);
+ this.topLevelClasses = Collections.unmodifiableSet(topLevelClasses);
+ }
+
+ private Set<ClassPathPackageInfo> getSubpackages() {
+ Set<ClassPathPackageInfo> info = new HashSet<>();
+ for (String name : subpackageNames) {
+ info.add(cache.get(name));
+ }
+ return info;
+ }
+
+ private Set<Class<?>> getTopLevelClassesRecursive() {
+ Set<Class<?>> set = new HashSet<>();
+ addTopLevelClassesTo(set);
+ return set;
+ }
+
+ private void addTopLevelClassesTo(Set<Class<?>> set) {
+ set.addAll(topLevelClasses);
+ for (ClassPathPackageInfo info : getSubpackages()) {
+ info.addTopLevelClassesTo(set);
+ }
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (obj instanceof ClassPathPackageInfo) {
+ ClassPathPackageInfo that = (ClassPathPackageInfo) obj;
+ return (this.packageName).equals(that.packageName);
+ }
+ return false;
+ }
+
+ @Override
+ public int hashCode() {
+ return packageName.hashCode();
+ }
}
}
diff --git a/test-runner/src/android/test/PackageInfoSources.java b/test-runner/src/android/test/PackageInfoSources.java
deleted file mode 100644
index 205f86b04d5f..000000000000
--- a/test-runner/src/android/test/PackageInfoSources.java
+++ /dev/null
@@ -1,38 +0,0 @@
-/*
- * Copyright (C) 2008 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.test;
-
-/**
- * {@hide} Not needed for SDK.
- */
-@Deprecated
-public class PackageInfoSources {
-
- private static ClassPathPackageInfoSource classPathSource;
-
- private PackageInfoSources() {
- }
-
- public static ClassPathPackageInfoSource forClassPath(ClassLoader classLoader) {
- if (classPathSource == null) {
- classPathSource = new ClassPathPackageInfoSource();
- classPathSource.setClassLoader(classLoader);
- }
- return classPathSource;
- }
-
-}
diff --git a/test-runner/src/android/test/suitebuilder/TestGrouping.java b/test-runner/src/android/test/suitebuilder/TestGrouping.java
index 307afb55e47a..030bc426ac19 100644
--- a/test-runner/src/android/test/suitebuilder/TestGrouping.java
+++ b/test-runner/src/android/test/suitebuilder/TestGrouping.java
@@ -16,9 +16,7 @@
package android.test.suitebuilder;
-import android.test.ClassPathPackageInfo;
import android.test.ClassPathPackageInfoSource;
-import android.test.PackageInfoSources;
import android.util.Log;
import com.android.internal.util.Predicate;
import junit.framework.TestCase;
@@ -131,10 +129,9 @@ class TestGrouping {
}
private List<Class<? extends TestCase>> testCaseClassesInPackage(String packageName) {
- ClassPathPackageInfoSource source = PackageInfoSources.forClassPath(classLoader);
- ClassPathPackageInfo packageInfo = source.getPackageInfo(packageName);
+ ClassPathPackageInfoSource source = ClassPathPackageInfoSource.forClassPath(classLoader);
- return selectTestClasses(packageInfo.getTopLevelClassesRecursive());
+ return selectTestClasses(source.getTopLevelClassesRecursive(packageName));
}
@SuppressWarnings("unchecked")
diff --git a/test-runner/tests/Android.mk b/test-runner/tests/Android.mk
index cc9b01d18fa6..7ee047e47058 100644
--- a/test-runner/tests/Android.mk
+++ b/test-runner/tests/Android.mk
@@ -18,7 +18,7 @@ include $(CLEAR_VARS)
# We only want this apk build for tests.
#
# Run the tests using the following commands:
-# adb -r install ${ANDROID_PRODUCT_OUT}/data/app/FrameworkTestRunnerTests/FrameworkTestRunnerTests.apk
+# adb install -r ${ANDROID_PRODUCT_OUT}/data/app/FrameworkTestRunnerTests/FrameworkTestRunnerTests.apk
# adb shell am instrument \
-e notAnnotation android.test.suitebuilder.examples.error.RunAsPartOfSeparateTest \
-w com.android.frameworks.testrunner.tests/android.test.InstrumentationTestRunner