diff options
243 files changed, 5141 insertions, 1427 deletions
diff --git a/core/java/android/hardware/camera2/DngCreator.java b/core/java/android/hardware/camera2/DngCreator.java index 45fa15e043e5..1a51acd6c5ec 100644 --- a/core/java/android/hardware/camera2/DngCreator.java +++ b/core/java/android/hardware/camera2/DngCreator.java @@ -119,8 +119,14 @@ public final class DngCreator implements AutoCloseable { captureTime = timestamp / 1000000 + timeOffset; } + // Create this fresh each time since the time zone may change while a long-running application + // is active. + final DateFormat dateTimeStampFormat = + new SimpleDateFormat(TIFF_DATETIME_FORMAT); + dateTimeStampFormat.setTimeZone(TimeZone.getDefault()); + // Format for metadata - String formattedCaptureTime = sDateTimeStampFormat.format(captureTime); + String formattedCaptureTime = dateTimeStampFormat.format(captureTime); nativeInit(characteristics.getNativeCopy(), metadata.getNativeCopy(), formattedCaptureTime); @@ -467,13 +473,10 @@ public final class DngCreator implements AutoCloseable { private static final String GPS_DATE_FORMAT_STR = "yyyy:MM:dd"; private static final String TIFF_DATETIME_FORMAT = "yyyy:MM:dd HH:mm:ss"; private static final DateFormat sExifGPSDateStamp = new SimpleDateFormat(GPS_DATE_FORMAT_STR); - private static final DateFormat sDateTimeStampFormat = - new SimpleDateFormat(TIFF_DATETIME_FORMAT); private final Calendar mGPSTimeStampCalendar = Calendar .getInstance(TimeZone.getTimeZone("UTC")); static { - sDateTimeStampFormat.setTimeZone(TimeZone.getDefault()); sExifGPSDateStamp.setTimeZone(TimeZone.getTimeZone("UTC")); } diff --git a/core/java/android/hardware/usb/UsbDeviceConnection.java b/core/java/android/hardware/usb/UsbDeviceConnection.java index f7bf1e43a010..160e261de530 100644 --- a/core/java/android/hardware/usb/UsbDeviceConnection.java +++ b/core/java/android/hardware/usb/UsbDeviceConnection.java @@ -24,7 +24,7 @@ import android.os.ParcelFileDescriptor; import dalvik.system.CloseGuard; import java.io.FileDescriptor; - +import java.nio.ByteBuffer; /** * This class is used for sending and receiving data and control messages to a USB device. @@ -257,13 +257,20 @@ public class UsbDeviceConnection { /** * Waits for the result of a {@link android.hardware.usb.UsbRequest#queue} operation - * Note that this may return requests queued on multiple - * {@link android.hardware.usb.UsbEndpoint}s. - * When multiple endpoints are in use, {@link android.hardware.usb.UsbRequest#getEndpoint} and - * {@link android.hardware.usb.UsbRequest#getClientData} can be useful in determining - * how to process the result of this function. + * <p>Note that this may return requests queued on multiple + * {@link android.hardware.usb.UsbEndpoint}s. When multiple endpoints are in use, + * {@link android.hardware.usb.UsbRequest#getEndpoint} and {@link + * android.hardware.usb.UsbRequest#getClientData} can be useful in determining how to process + * the result of this function.</p> + * <p>Position and array offset of the request's buffer are ignored and assumed to be 0. The + * position will be set to the number of bytes read/written.</p> * * @return a completed USB request, or null if an error occurred + * + * @throws IllegalArgumentException if the number of bytes read or written is more than the + * limit of the request's buffer. The number of bytes is + * determined by the {@code length} parameter of + * {@link UsbRequest#queue(ByteBuffer, int)} */ public UsbRequest requestWait() { UsbRequest request = native_request_wait(); diff --git a/core/java/android/hardware/usb/UsbRequest.java b/core/java/android/hardware/usb/UsbRequest.java index b531e5fb3db3..9f7592f880e6 100644 --- a/core/java/android/hardware/usb/UsbRequest.java +++ b/core/java/android/hardware/usb/UsbRequest.java @@ -17,6 +17,7 @@ package android.hardware.usb; import android.util.Log; +import com.android.internal.util.Preconditions; import dalvik.system.CloseGuard; import java.nio.ByteBuffer; @@ -66,7 +67,7 @@ public class UsbRequest { */ public boolean initialize(UsbDeviceConnection connection, UsbEndpoint endpoint) { mEndpoint = endpoint; - mConnection = connection; + mConnection = Preconditions.checkNotNull(connection); boolean wasInitialized = native_init(connection, endpoint.getAddress(), endpoint.getAttributes(), endpoint.getMaxPacketSize(), endpoint.getInterval()); @@ -137,15 +138,16 @@ public class UsbRequest { /** * Queues the request to send or receive data on its endpoint. - * For OUT endpoints, the given buffer data will be sent on the endpoint. - * For IN endpoints, the endpoint will attempt to read the given number of bytes - * into the specified buffer. - * If the queueing operation is successful, we return true and the result will be - * returned via {@link android.hardware.usb.UsbDeviceConnection#requestWait} + * <p>For OUT endpoints, the given buffer data will be sent on the endpoint. For IN endpoints, + * the endpoint will attempt to read the given number of bytes into the specified buffer. If the + * queueing operation is successful, we return true and the result will be returned via {@link + * android.hardware.usb.UsbDeviceConnection#requestWait}</p> + * + * @param buffer the buffer containing the bytes to write, or location to store the results of a + * read. Position and array offset will be ignored and assumed to be 0. Limit and + * capacity will be ignored. + * @param length number of bytes to read or write. * - * @param buffer the buffer containing the bytes to write, or location to store - * the results of a read - * @param length number of bytes to read or write * @return true if the queueing operation succeeded */ public boolean queue(ByteBuffer buffer, int length) { @@ -155,6 +157,9 @@ public class UsbRequest { mBuffer = buffer; mLength = length; + // Note: On a buffer slice we lost the capacity information about the underlying buffer, + // hence we cannot check if the access would be a data leak/memory corruption. + boolean result; if (buffer.isDirect()) { result = native_queue_direct(buffer, length, out); diff --git a/core/java/android/net/metrics/ValidationProbeEvent.java b/core/java/android/net/metrics/ValidationProbeEvent.java index 331cf0cdd4ad..1a31b56f1ffb 100644 --- a/core/java/android/net/metrics/ValidationProbeEvent.java +++ b/core/java/android/net/metrics/ValidationProbeEvent.java @@ -34,10 +34,12 @@ import java.lang.annotation.RetentionPolicy; @SystemApi public final class ValidationProbeEvent implements Parcelable { - public static final int PROBE_DNS = 0; - public static final int PROBE_HTTP = 1; - public static final int PROBE_HTTPS = 2; - public static final int PROBE_PAC = 3; + public static final int PROBE_DNS = 0; + public static final int PROBE_HTTP = 1; + public static final int PROBE_HTTPS = 2; + public static final int PROBE_PAC = 3; + /** {@hide} */ + public static final int PROBE_FALLBACK = 4; public static final int DNS_FAILURE = 0; public static final int DNS_SUCCESS = 1; @@ -57,7 +59,7 @@ public final class ValidationProbeEvent implements Parcelable { public final @ProbeType int probeType; public final @ReturnCode int returnCode; - /** @hide */ + /** {@hide} */ public ValidationProbeEvent( int netId, long durationMs, @ProbeType int probeType, @ReturnCode int returnCode) { this.netId = netId; diff --git a/core/java/android/os/AsyncTask.java b/core/java/android/os/AsyncTask.java index 9a4b599f0e9b..fea64ec5ee1e 100644 --- a/core/java/android/os/AsyncTask.java +++ b/core/java/android/os/AsyncTask.java @@ -304,6 +304,9 @@ public abstract class AsyncTask<Params, Progress, Result> { //noinspection unchecked result = doInBackground(mParams); Binder.flushPendingCommands(); + } catch (Throwable tr) { + mCancelled.set(true); + throw tr; } finally { postResult(result); } diff --git a/core/java/android/os/HwBlob.java b/core/java/android/os/HwBlob.java index 153c6e634ecb..88226f0a1665 100644 --- a/core/java/android/os/HwBlob.java +++ b/core/java/android/os/HwBlob.java @@ -16,6 +16,8 @@ package android.os; +import android.annotation.NonNull; + import libcore.util.NativeAllocationRegistry; /** @hide */ @@ -54,6 +56,69 @@ public class HwBlob { public native final long handle(); + public static Boolean[] wrapArray(@NonNull boolean[] array) { + final int n = array.length; + Boolean[] wrappedArray = new Boolean[n]; + for (int i = 0; i < n; ++i) { + wrappedArray[i] = array[i]; + } + return wrappedArray; + } + + public static Long[] wrapArray(@NonNull long[] array) { + final int n = array.length; + Long[] wrappedArray = new Long[n]; + for (int i = 0; i < n; ++i) { + wrappedArray[i] = array[i]; + } + return wrappedArray; + } + + public static Byte[] wrapArray(@NonNull byte[] array) { + final int n = array.length; + Byte[] wrappedArray = new Byte[n]; + for (int i = 0; i < n; ++i) { + wrappedArray[i] = array[i]; + } + return wrappedArray; + } + + public static Short[] wrapArray(@NonNull short[] array) { + final int n = array.length; + Short[] wrappedArray = new Short[n]; + for (int i = 0; i < n; ++i) { + wrappedArray[i] = array[i]; + } + return wrappedArray; + } + + public static Integer[] wrapArray(@NonNull int[] array) { + final int n = array.length; + Integer[] wrappedArray = new Integer[n]; + for (int i = 0; i < n; ++i) { + wrappedArray[i] = array[i]; + } + return wrappedArray; + } + + public static Float[] wrapArray(@NonNull float[] array) { + final int n = array.length; + Float[] wrappedArray = new Float[n]; + for (int i = 0; i < n; ++i) { + wrappedArray[i] = array[i]; + } + return wrappedArray; + } + + public static Double[] wrapArray(@NonNull double[] array) { + final int n = array.length; + Double[] wrappedArray = new Double[n]; + for (int i = 0; i < n; ++i) { + wrappedArray[i] = array[i]; + } + return wrappedArray; + } + // Returns address of the "freeFunction". private static native final long native_init(); diff --git a/core/java/android/os/RecoverySystem.java b/core/java/android/os/RecoverySystem.java index 90bd11fe83bc..0b3abaaf33e8 100644 --- a/core/java/android/os/RecoverySystem.java +++ b/core/java/android/os/RecoverySystem.java @@ -93,6 +93,14 @@ public class RecoverySystem { */ public static final File UNCRYPT_PACKAGE_FILE = new File(RECOVERY_DIR, "uncrypt_file"); + /** + * UNCRYPT_STATUS_FILE stores the time cost (and error code in the case of a failure) + * of uncrypt. + * + * @hide + */ + public static final File UNCRYPT_STATUS_FILE = new File(RECOVERY_DIR, "uncrypt_status"); + // Length limits for reading files. private static final int LOG_FILE_MAX_LENGTH = 64 * 1024; diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java index e62440aef04e..f8b93611d766 100755 --- a/core/java/android/provider/Settings.java +++ b/core/java/android/provider/Settings.java @@ -8067,12 +8067,37 @@ public final class Settings { /** * The server used for captive portal detection upon a new conection. A * 204 response code from the server is used for validation. + * TODO: remove this deprecated symbol. * * @hide */ public static final String CAPTIVE_PORTAL_SERVER = "captive_portal_server"; /** + * The URL used for HTTPS captive portal detection upon a new connection. + * A 204 response code from the server is used for validation. + * + * @hide + */ + public static final String CAPTIVE_PORTAL_HTTPS_URL = "captive_portal_https_url"; + + /** + * The URL used for HTTP captive portal detection upon a new connection. + * A 204 response code from the server is used for validation. + * + * @hide + */ + public static final String CAPTIVE_PORTAL_HTTP_URL = "captive_portal_http_url"; + + /** + * The URL used for fallback HTTP captive portal detection when previous HTTP + * and HTTPS captive portal detection attemps did not return a conclusive answer. + * + * @hide + */ + public static final String CAPTIVE_PORTAL_FALLBACK_URL = "captive_portal_fallback_url"; + + /** * Whether to use HTTPS for network validation. This is enabled by default and the setting * needs to be set to 0 to disable it. This setting is a misnomer because captive portals * don't actually use HTTPS, but it's consistent with the other settings. @@ -8082,6 +8107,14 @@ public final class Settings { public static final String CAPTIVE_PORTAL_USE_HTTPS = "captive_portal_use_https"; /** + * Which User-Agent string to use in the header of the captive portal detection probes. + * The User-Agent field is unset when this setting has no value (HttpUrlConnection default). + * + * @hide + */ + public static final String CAPTIVE_PORTAL_USER_AGENT = "captive_portal_user_agent"; + + /** * Whether network service discovery is enabled. * * @hide @@ -8792,7 +8825,7 @@ public final class Settings { public static final String WFC_IMS_ENABLED = "wfc_ims_enabled"; /** - * WFC Mode. + * WFC mode on home/non-roaming network. * <p> * Type: int - 2=Wi-Fi preferred, 1=Cellular preferred, 0=Wi-Fi only * @@ -8801,6 +8834,15 @@ public final class Settings { public static final String WFC_IMS_MODE = "wfc_ims_mode"; /** + * WFC mode on roaming network. + * <p> + * Type: int - see {@link WFC_IMS_MODE} for values + * + * @hide + */ + public static final String WFC_IMS_ROAMING_MODE = "wfc_ims_roaming_mode"; + + /** * Whether WFC roaming is enabled * <p> * Type: int (0 for false, 1 for true) diff --git a/core/res/res/values-af/strings.xml b/core/res/res/values-af/strings.xml index f58852009ecd..34244ab1863d 100644 --- a/core/res/res/values-af/strings.xml +++ b/core/res/res/values-af/strings.xml @@ -1330,7 +1330,8 @@ <string name="storage_usb_drive_label" msgid="4501418548927759953">"<xliff:g id="MANUFACTURER">%s</xliff:g>-USB-datastokkie"</string> <string name="storage_usb" msgid="3017954059538517278">"USB-berging"</string> <string name="extract_edit_menu_button" msgid="8940478730496610137">"Redigeer"</string> - <string name="data_usage_warning_title" msgid="1955638862122232342">"Dataverbruik-waarskuwing"</string> + <!-- no translation found for data_usage_warning_title (3620440638180218181) --> + <skip /> <string name="data_usage_warning_body" msgid="6660692274311972007">"Tik om gebruik en instellings te bekyk."</string> <string name="data_usage_3g_limit_title" msgid="4361523876818447683">"2G-3G-datalimiet bereik"</string> <string name="data_usage_4g_limit_title" msgid="4609566827219442376">"4G-datalimiet bereik"</string> diff --git a/core/res/res/values-am/strings.xml b/core/res/res/values-am/strings.xml index ac2e76b03078..b3cd896307bb 100644 --- a/core/res/res/values-am/strings.xml +++ b/core/res/res/values-am/strings.xml @@ -1330,7 +1330,8 @@ <string name="storage_usb_drive_label" msgid="4501418548927759953">"የ<xliff:g id="MANUFACTURER">%s</xliff:g> ዩኤስቢ አንጻፊ"</string> <string name="storage_usb" msgid="3017954059538517278">"የUSB ማከማቻ"</string> <string name="extract_edit_menu_button" msgid="8940478730496610137">"አርትዕ"</string> - <string name="data_usage_warning_title" msgid="1955638862122232342">"የውሂብ አጠቃቀም ማስጠንቀቂየ"</string> + <!-- no translation found for data_usage_warning_title (3620440638180218181) --> + <skip /> <string name="data_usage_warning_body" msgid="6660692274311972007">"አጠቃቀምን እና ቅንብሮችን ለማየት መታ ያድርጉ።"</string> <string name="data_usage_3g_limit_title" msgid="4361523876818447683">"የ2ጂ-3ጂ ውሂብ ገደብ ላይ ተደርሷል"</string> <string name="data_usage_4g_limit_title" msgid="4609566827219442376">"የ4ጂ ውሂብ ገደብ ላይ ተደርሷል"</string> diff --git a/core/res/res/values-ar/strings.xml b/core/res/res/values-ar/strings.xml index 380561266dbc..717e9da989dd 100644 --- a/core/res/res/values-ar/strings.xml +++ b/core/res/res/values-ar/strings.xml @@ -1434,7 +1434,8 @@ <string name="storage_usb_drive_label" msgid="4501418548927759953">"محرك أقراص USB من <xliff:g id="MANUFACTURER">%s</xliff:g>"</string> <string name="storage_usb" msgid="3017954059538517278">"وحدة تخزين USB"</string> <string name="extract_edit_menu_button" msgid="8940478730496610137">"تعديل"</string> - <string name="data_usage_warning_title" msgid="1955638862122232342">"تحذير استخدام البيانات"</string> + <!-- no translation found for data_usage_warning_title (3620440638180218181) --> + <skip /> <string name="data_usage_warning_body" msgid="6660692274311972007">"انقر لعرض الاستخدام والإعدادات."</string> <string name="data_usage_3g_limit_title" msgid="4361523876818447683">"تم بلوغ حد بيانات اتصال 2G-3G"</string> <string name="data_usage_4g_limit_title" msgid="4609566827219442376">"تم بلوغ حد بيانات اتصال 4G"</string> diff --git a/core/res/res/values-az-rAZ/strings.xml b/core/res/res/values-az-rAZ/strings.xml index d3ee4a4cb6c8..5ff1373331ee 100644 --- a/core/res/res/values-az-rAZ/strings.xml +++ b/core/res/res/values-az-rAZ/strings.xml @@ -1330,7 +1330,8 @@ <string name="storage_usb_drive_label" msgid="4501418548927759953">"<xliff:g id="MANUFACTURER">%s</xliff:g> USB drayv"</string> <string name="storage_usb" msgid="3017954059538517278">"USB yaddaş"</string> <string name="extract_edit_menu_button" msgid="8940478730496610137">"Düzəliş edin"</string> - <string name="data_usage_warning_title" msgid="1955638862122232342">"Data istifadə xəbərdarlığı"</string> + <!-- no translation found for data_usage_warning_title (3620440638180218181) --> + <skip /> <string name="data_usage_warning_body" msgid="6660692274311972007">"İstifadə və ayarları görmək üçün tıklayın."</string> <string name="data_usage_3g_limit_title" msgid="4361523876818447683">"2G-3G data limitinə çatdı"</string> <string name="data_usage_4g_limit_title" msgid="4609566827219442376">"4G data limitinə çatdı"</string> diff --git a/core/res/res/values-b+sr+Latn/strings.xml b/core/res/res/values-b+sr+Latn/strings.xml index 72671f136004..a351d5cb01fc 100644 --- a/core/res/res/values-b+sr+Latn/strings.xml +++ b/core/res/res/values-b+sr+Latn/strings.xml @@ -1356,7 +1356,8 @@ <string name="storage_usb_drive_label" msgid="4501418548927759953">"<xliff:g id="MANUFACTURER">%s</xliff:g> USB disk"</string> <string name="storage_usb" msgid="3017954059538517278">"USB memorija"</string> <string name="extract_edit_menu_button" msgid="8940478730496610137">"Izmeni"</string> - <string name="data_usage_warning_title" msgid="1955638862122232342">"Upozorenje o potrošnji podataka"</string> + <!-- no translation found for data_usage_warning_title (3620440638180218181) --> + <skip /> <string name="data_usage_warning_body" msgid="6660692274311972007">"Dodirnite za potrošnju i podešavanja."</string> <string name="data_usage_3g_limit_title" msgid="4361523876818447683">"Nema više 2G-3G podataka"</string> <string name="data_usage_4g_limit_title" msgid="4609566827219442376">"Nema više 4G podataka"</string> diff --git a/core/res/res/values-be-rBY/strings.xml b/core/res/res/values-be-rBY/strings.xml index 3f2e07c41090..13a9cdcef2fd 100644 --- a/core/res/res/values-be-rBY/strings.xml +++ b/core/res/res/values-be-rBY/strings.xml @@ -1382,7 +1382,8 @@ <string name="storage_usb_drive_label" msgid="4501418548927759953">"USB-дыск <xliff:g id="MANUFACTURER">%s</xliff:g>"</string> <string name="storage_usb" msgid="3017954059538517278">"USB-назапашвальнік"</string> <string name="extract_edit_menu_button" msgid="8940478730496610137">"Рэдагаваць"</string> - <string name="data_usage_warning_title" msgid="1955638862122232342">"Папярэджанне выкарыстання дадзеных"</string> + <!-- no translation found for data_usage_warning_title (3620440638180218181) --> + <skip /> <string name="data_usage_warning_body" msgid="6660692274311972007">"Прагляд выкарыстання і налад."</string> <string name="data_usage_3g_limit_title" msgid="4361523876818447683">"Дасягнуты ліміт трафіку 2G-3G"</string> <string name="data_usage_4g_limit_title" msgid="4609566827219442376">"Дасягнуты ліміт трафіку 4G"</string> diff --git a/core/res/res/values-bg/strings.xml b/core/res/res/values-bg/strings.xml index e7ac345e0100..95e89aff9b64 100644 --- a/core/res/res/values-bg/strings.xml +++ b/core/res/res/values-bg/strings.xml @@ -1330,7 +1330,8 @@ <string name="storage_usb_drive_label" msgid="4501418548927759953">"USB устройство от <xliff:g id="MANUFACTURER">%s</xliff:g>"</string> <string name="storage_usb" msgid="3017954059538517278">"USB хранилище"</string> <string name="extract_edit_menu_button" msgid="8940478730496610137">"Редактиране"</string> - <string name="data_usage_warning_title" msgid="1955638862122232342">"Предупрежд. за ползване на данни"</string> + <!-- no translation found for data_usage_warning_title (3620440638180218181) --> + <skip /> <string name="data_usage_warning_body" msgid="6660692274311972007">"Пренос и настройки: Докоснете за преглед."</string> <string name="data_usage_3g_limit_title" msgid="4361523876818447683">"Достигнат лимит за 2G/3G данните"</string> <string name="data_usage_4g_limit_title" msgid="4609566827219442376">"Достигнат лимит за 4G данните"</string> diff --git a/core/res/res/values-bn-rBD/strings.xml b/core/res/res/values-bn-rBD/strings.xml index b69a123160e6..25f3367dfbe3 100644 --- a/core/res/res/values-bn-rBD/strings.xml +++ b/core/res/res/values-bn-rBD/strings.xml @@ -1330,7 +1330,8 @@ <string name="storage_usb_drive_label" msgid="4501418548927759953">"<xliff:g id="MANUFACTURER">%s</xliff:g> USB ড্রাইভ"</string> <string name="storage_usb" msgid="3017954059538517278">"USB সঞ্চয়স্থান"</string> <string name="extract_edit_menu_button" msgid="8940478730496610137">"সম্পাদনা করুন"</string> - <string name="data_usage_warning_title" msgid="1955638862122232342">"ডেটা ব্যবহারের সতর্কতা"</string> + <!-- no translation found for data_usage_warning_title (3620440638180218181) --> + <skip /> <string name="data_usage_warning_body" msgid="6660692274311972007">"ব্যবহার এবং সেটিংস দেখতে আলতো চাপুন৷"</string> <string name="data_usage_3g_limit_title" msgid="4361523876818447683">"2G-3G ডেটা সীমা ছাড়িয়েছে"</string> <string name="data_usage_4g_limit_title" msgid="4609566827219442376">"4G ডেটা সীমা ছাড়িয়েছে"</string> diff --git a/core/res/res/values-bs-rBA/strings.xml b/core/res/res/values-bs-rBA/strings.xml index 019ff1d60709..e786ff9b3aee 100644 --- a/core/res/res/values-bs-rBA/strings.xml +++ b/core/res/res/values-bs-rBA/strings.xml @@ -1358,7 +1358,8 @@ <string name="storage_usb_drive_label" msgid="4501418548927759953">"<xliff:g id="MANUFACTURER">%s</xliff:g> USB disk"</string> <string name="storage_usb" msgid="3017954059538517278">"USB pohrana"</string> <string name="extract_edit_menu_button" msgid="8940478730496610137">"Uredi"</string> - <string name="data_usage_warning_title" msgid="1955638862122232342">"Upozorenje za prijenos podataka"</string> + <!-- no translation found for data_usage_warning_title (3620440638180218181) --> + <skip /> <string name="data_usage_warning_body" msgid="6660692274311972007">"Dodirnite za prikaz upotrebe i postavki."</string> <string name="data_usage_3g_limit_title" msgid="4361523876818447683">"Dostignut limit za 2G-3G podatke"</string> <string name="data_usage_4g_limit_title" msgid="4609566827219442376">"Dostignut limit za 4G podatke"</string> diff --git a/core/res/res/values-ca/strings.xml b/core/res/res/values-ca/strings.xml index 8926fce19563..ac0b6d39b508 100644 --- a/core/res/res/values-ca/strings.xml +++ b/core/res/res/values-ca/strings.xml @@ -1330,7 +1330,8 @@ <string name="storage_usb_drive_label" msgid="4501418548927759953">"Unitat USB de: <xliff:g id="MANUFACTURER">%s</xliff:g>"</string> <string name="storage_usb" msgid="3017954059538517278">"Emmagatzematge USB"</string> <string name="extract_edit_menu_button" msgid="8940478730496610137">"Edita"</string> - <string name="data_usage_warning_title" msgid="1955638862122232342">"Advertiment d\'ús de dades"</string> + <!-- no translation found for data_usage_warning_title (3620440638180218181) --> + <skip /> <string name="data_usage_warning_body" msgid="6660692274311972007">"Toca per veure l\'ús i la configuració."</string> <string name="data_usage_3g_limit_title" msgid="4361523876818447683">"Límit de dades 2G-3G assolit"</string> <string name="data_usage_4g_limit_title" msgid="4609566827219442376">"Límit de dades 4G assolit"</string> diff --git a/core/res/res/values-cs/strings.xml b/core/res/res/values-cs/strings.xml index a9ff27d17c3c..4370d9f635d9 100644 --- a/core/res/res/values-cs/strings.xml +++ b/core/res/res/values-cs/strings.xml @@ -1382,7 +1382,8 @@ <string name="storage_usb_drive_label" msgid="4501418548927759953">"Jednotka USB <xliff:g id="MANUFACTURER">%s</xliff:g>"</string> <string name="storage_usb" msgid="3017954059538517278">"Úložiště USB"</string> <string name="extract_edit_menu_button" msgid="8940478730496610137">"Upravit"</string> - <string name="data_usage_warning_title" msgid="1955638862122232342">"Upozornění na využití dat"</string> + <!-- no translation found for data_usage_warning_title (3620440638180218181) --> + <skip /> <string name="data_usage_warning_body" msgid="6660692274311972007">"Klepnutím zobrazíte nastavení."</string> <string name="data_usage_3g_limit_title" msgid="4361523876818447683">"Dosáhli jste limitu dat 2G–3G"</string> <string name="data_usage_4g_limit_title" msgid="4609566827219442376">"Dosáhli jste limitu dat 4G"</string> diff --git a/core/res/res/values-da/strings.xml b/core/res/res/values-da/strings.xml index 487432b13132..1688cbe9a343 100644 --- a/core/res/res/values-da/strings.xml +++ b/core/res/res/values-da/strings.xml @@ -1330,7 +1330,8 @@ <string name="storage_usb_drive_label" msgid="4501418548927759953">"USB-drev fra <xliff:g id="MANUFACTURER">%s</xliff:g>"</string> <string name="storage_usb" msgid="3017954059538517278">"USB-lager"</string> <string name="extract_edit_menu_button" msgid="8940478730496610137">"Rediger"</string> - <string name="data_usage_warning_title" msgid="1955638862122232342">"Advarsel om dataforbrug"</string> + <!-- no translation found for data_usage_warning_title (3620440638180218181) --> + <skip /> <string name="data_usage_warning_body" msgid="6660692274311972007">"Tryk for at se forbrug og indstillinger."</string> <string name="data_usage_3g_limit_title" msgid="4361523876818447683">"Grænsen for 2G-3G-data er nået"</string> <string name="data_usage_4g_limit_title" msgid="4609566827219442376">"Grænsen for 4G-data er nået"</string> diff --git a/core/res/res/values-de/strings.xml b/core/res/res/values-de/strings.xml index 6b0525322410..d13777bd0577 100644 --- a/core/res/res/values-de/strings.xml +++ b/core/res/res/values-de/strings.xml @@ -1330,7 +1330,8 @@ <string name="storage_usb_drive_label" msgid="4501418548927759953">"USB-Speichergerät von <xliff:g id="MANUFACTURER">%s</xliff:g>"</string> <string name="storage_usb" msgid="3017954059538517278">"USB-Speicher"</string> <string name="extract_edit_menu_button" msgid="8940478730496610137">"Bearbeiten"</string> - <string name="data_usage_warning_title" msgid="1955638862122232342">"Warnung zum Datenverbrauch"</string> + <!-- no translation found for data_usage_warning_title (3620440638180218181) --> + <skip /> <string name="data_usage_warning_body" msgid="6660692274311972007">"Für Nutzung und Einstellungen tippen."</string> <string name="data_usage_3g_limit_title" msgid="4361523876818447683">"2G-/3G-Datenlimit erreicht"</string> <string name="data_usage_4g_limit_title" msgid="4609566827219442376">"4G-Datenlimit erreicht"</string> diff --git a/core/res/res/values-el/strings.xml b/core/res/res/values-el/strings.xml index a6ee8c2b8f3e..8f63a7355029 100644 --- a/core/res/res/values-el/strings.xml +++ b/core/res/res/values-el/strings.xml @@ -1330,7 +1330,8 @@ <string name="storage_usb_drive_label" msgid="4501418548927759953">"Μονάδα USB <xliff:g id="MANUFACTURER">%s</xliff:g>"</string> <string name="storage_usb" msgid="3017954059538517278">"Αποθηκευτικός χώρος USB"</string> <string name="extract_edit_menu_button" msgid="8940478730496610137">"Επεξεργασία"</string> - <string name="data_usage_warning_title" msgid="1955638862122232342">"Προειδοποίηση χρήσης δεδομένων"</string> + <!-- no translation found for data_usage_warning_title (3620440638180218181) --> + <skip /> <string name="data_usage_warning_body" msgid="6660692274311972007">"Πατήστε για προβολή χρήσης/ρυθμ."</string> <string name="data_usage_3g_limit_title" msgid="4361523876818447683">"Συμπλ. το όριο δεδομένων 2G-3G"</string> <string name="data_usage_4g_limit_title" msgid="4609566827219442376">"Συμπλ. το όριο δεδομένων 4G"</string> diff --git a/core/res/res/values-en-rAU/strings.xml b/core/res/res/values-en-rAU/strings.xml index 6342966f1ffc..348a7de5629e 100644 --- a/core/res/res/values-en-rAU/strings.xml +++ b/core/res/res/values-en-rAU/strings.xml @@ -1330,7 +1330,8 @@ <string name="storage_usb_drive_label" msgid="4501418548927759953">"<xliff:g id="MANUFACTURER">%s</xliff:g> USB drive"</string> <string name="storage_usb" msgid="3017954059538517278">"USB storage"</string> <string name="extract_edit_menu_button" msgid="8940478730496610137">"Edit"</string> - <string name="data_usage_warning_title" msgid="1955638862122232342">"Data usage warning"</string> + <!-- no translation found for data_usage_warning_title (3620440638180218181) --> + <skip /> <string name="data_usage_warning_body" msgid="6660692274311972007">"Tap to view usage and settings."</string> <string name="data_usage_3g_limit_title" msgid="4361523876818447683">"2G-3G data limit reached"</string> <string name="data_usage_4g_limit_title" msgid="4609566827219442376">"4G data limit reached"</string> diff --git a/core/res/res/values-en-rGB/strings.xml b/core/res/res/values-en-rGB/strings.xml index 6342966f1ffc..348a7de5629e 100644 --- a/core/res/res/values-en-rGB/strings.xml +++ b/core/res/res/values-en-rGB/strings.xml @@ -1330,7 +1330,8 @@ <string name="storage_usb_drive_label" msgid="4501418548927759953">"<xliff:g id="MANUFACTURER">%s</xliff:g> USB drive"</string> <string name="storage_usb" msgid="3017954059538517278">"USB storage"</string> <string name="extract_edit_menu_button" msgid="8940478730496610137">"Edit"</string> - <string name="data_usage_warning_title" msgid="1955638862122232342">"Data usage warning"</string> + <!-- no translation found for data_usage_warning_title (3620440638180218181) --> + <skip /> <string name="data_usage_warning_body" msgid="6660692274311972007">"Tap to view usage and settings."</string> <string name="data_usage_3g_limit_title" msgid="4361523876818447683">"2G-3G data limit reached"</string> <string name="data_usage_4g_limit_title" msgid="4609566827219442376">"4G data limit reached"</string> diff --git a/core/res/res/values-en-rIN/strings.xml b/core/res/res/values-en-rIN/strings.xml index 6342966f1ffc..348a7de5629e 100644 --- a/core/res/res/values-en-rIN/strings.xml +++ b/core/res/res/values-en-rIN/strings.xml @@ -1330,7 +1330,8 @@ <string name="storage_usb_drive_label" msgid="4501418548927759953">"<xliff:g id="MANUFACTURER">%s</xliff:g> USB drive"</string> <string name="storage_usb" msgid="3017954059538517278">"USB storage"</string> <string name="extract_edit_menu_button" msgid="8940478730496610137">"Edit"</string> - <string name="data_usage_warning_title" msgid="1955638862122232342">"Data usage warning"</string> + <!-- no translation found for data_usage_warning_title (3620440638180218181) --> + <skip /> <string name="data_usage_warning_body" msgid="6660692274311972007">"Tap to view usage and settings."</string> <string name="data_usage_3g_limit_title" msgid="4361523876818447683">"2G-3G data limit reached"</string> <string name="data_usage_4g_limit_title" msgid="4609566827219442376">"4G data limit reached"</string> diff --git a/core/res/res/values-es-rUS/strings.xml b/core/res/res/values-es-rUS/strings.xml index 0ba371fe0872..39746e0de81f 100644 --- a/core/res/res/values-es-rUS/strings.xml +++ b/core/res/res/values-es-rUS/strings.xml @@ -1330,7 +1330,8 @@ <string name="storage_usb_drive_label" msgid="4501418548927759953">"Unidad USB de <xliff:g id="MANUFACTURER">%s</xliff:g>"</string> <string name="storage_usb" msgid="3017954059538517278">"Almacenamiento USB"</string> <string name="extract_edit_menu_button" msgid="8940478730496610137">"Editar"</string> - <string name="data_usage_warning_title" msgid="1955638862122232342">"Advertencia de uso de datos"</string> + <!-- no translation found for data_usage_warning_title (3620440638180218181) --> + <skip /> <string name="data_usage_warning_body" msgid="6660692274311972007">"Presiona para uso y opciones."</string> <string name="data_usage_3g_limit_title" msgid="4361523876818447683">"Límite de datos 2G-3G alcanzado"</string> <string name="data_usage_4g_limit_title" msgid="4609566827219442376">"Límite de datos 4G alcanzado"</string> diff --git a/core/res/res/values-es/strings.xml b/core/res/res/values-es/strings.xml index d60fa8342929..117205f6c4e7 100644 --- a/core/res/res/values-es/strings.xml +++ b/core/res/res/values-es/strings.xml @@ -1330,7 +1330,8 @@ <string name="storage_usb_drive_label" msgid="4501418548927759953">"Unidad USB <xliff:g id="MANUFACTURER">%s</xliff:g>"</string> <string name="storage_usb" msgid="3017954059538517278">"Almacenamiento USB"</string> <string name="extract_edit_menu_button" msgid="8940478730496610137">"Editar"</string> - <string name="data_usage_warning_title" msgid="1955638862122232342">"Advertencia de uso de datos"</string> + <!-- no translation found for data_usage_warning_title (3620440638180218181) --> + <skip /> <string name="data_usage_warning_body" msgid="6660692274311972007">"Toca para ver uso y ajustes."</string> <string name="data_usage_3g_limit_title" msgid="4361523876818447683">"Límite de datos 2G-3G alcanzado"</string> <string name="data_usage_4g_limit_title" msgid="4609566827219442376">"Límite de datos 4G alcanzado"</string> diff --git a/core/res/res/values-et-rEE/strings.xml b/core/res/res/values-et-rEE/strings.xml index 15fa79fca1da..2fadecbd075c 100644 --- a/core/res/res/values-et-rEE/strings.xml +++ b/core/res/res/values-et-rEE/strings.xml @@ -1330,7 +1330,8 @@ <string name="storage_usb_drive_label" msgid="4501418548927759953">"Tootja <xliff:g id="MANUFACTURER">%s</xliff:g> USB-ketas"</string> <string name="storage_usb" msgid="3017954059538517278">"USB-mäluseade"</string> <string name="extract_edit_menu_button" msgid="8940478730496610137">"Muuda"</string> - <string name="data_usage_warning_title" msgid="1955638862122232342">"Andmete kasutamise hoiatus"</string> + <!-- no translation found for data_usage_warning_title (3620440638180218181) --> + <skip /> <string name="data_usage_warning_body" msgid="6660692274311972007">"Puudutage kasutuse/seadete vaat."</string> <string name="data_usage_3g_limit_title" msgid="4361523876818447683">"2G-, 3G-andmeside limiit on täis"</string> <string name="data_usage_4g_limit_title" msgid="4609566827219442376">"4G-andmeside limiit on täis"</string> diff --git a/core/res/res/values-eu-rES/strings.xml b/core/res/res/values-eu-rES/strings.xml index 47e64c3dda8d..61799870313f 100644 --- a/core/res/res/values-eu-rES/strings.xml +++ b/core/res/res/values-eu-rES/strings.xml @@ -1330,7 +1330,8 @@ <string name="storage_usb_drive_label" msgid="4501418548927759953">"<xliff:g id="MANUFACTURER">%s</xliff:g> USB unitatea"</string> <string name="storage_usb" msgid="3017954059538517278">"USB memoria"</string> <string name="extract_edit_menu_button" msgid="8940478730496610137">"Editatu"</string> - <string name="data_usage_warning_title" msgid="1955638862122232342">"Datuen erabilerari buruzko abisua"</string> + <!-- no translation found for data_usage_warning_title (3620440638180218181) --> + <skip /> <string name="data_usage_warning_body" msgid="6660692274311972007">"Sakatu erabilera eta ezarpenak ikusteko."</string> <string name="data_usage_3g_limit_title" msgid="4361523876818447683">"2-3 GB-ko mugara iritsi zara"</string> <string name="data_usage_4g_limit_title" msgid="4609566827219442376">"4 GB-ko mugara iritsi zara"</string> diff --git a/core/res/res/values-fa/strings.xml b/core/res/res/values-fa/strings.xml index 95c0db716b91..fd2bf8125859 100644 --- a/core/res/res/values-fa/strings.xml +++ b/core/res/res/values-fa/strings.xml @@ -1330,7 +1330,8 @@ <string name="storage_usb_drive_label" msgid="4501418548927759953">"درایو USB <xliff:g id="MANUFACTURER">%s</xliff:g>"</string> <string name="storage_usb" msgid="3017954059538517278">"حافظهٔ USB"</string> <string name="extract_edit_menu_button" msgid="8940478730496610137">"ویرایش"</string> - <string name="data_usage_warning_title" msgid="1955638862122232342">"هشدار میزان استفاده از داده"</string> + <!-- no translation found for data_usage_warning_title (3620440638180218181) --> + <skip /> <string name="data_usage_warning_body" msgid="6660692274311972007">"برای مشاهده مصرف و تنظیمات ضربه بزنید."</string> <string name="data_usage_3g_limit_title" msgid="4361523876818447683">"به حد مجاز مصرف داده 2G-3G رسید"</string> <string name="data_usage_4g_limit_title" msgid="4609566827219442376">"به حد مجاز مصرف داده 4G رسید"</string> diff --git a/core/res/res/values-fi/strings.xml b/core/res/res/values-fi/strings.xml index e11b2ca719a7..3ea7e66bfc61 100644 --- a/core/res/res/values-fi/strings.xml +++ b/core/res/res/values-fi/strings.xml @@ -1330,7 +1330,8 @@ <string name="storage_usb_drive_label" msgid="4501418548927759953">"USB-asema: <xliff:g id="MANUFACTURER">%s</xliff:g>"</string> <string name="storage_usb" msgid="3017954059538517278">"USB-tallennustila"</string> <string name="extract_edit_menu_button" msgid="8940478730496610137">"Muokkaa"</string> - <string name="data_usage_warning_title" msgid="1955638862122232342">"Tiedonsiirtovaroitus"</string> + <!-- no translation found for data_usage_warning_title (3620440638180218181) --> + <skip /> <string name="data_usage_warning_body" msgid="6660692274311972007">"Käyttö & asetukset napauttamalla"</string> <string name="data_usage_3g_limit_title" msgid="4361523876818447683">"2G-3G-tietojen raja saavutettu"</string> <string name="data_usage_4g_limit_title" msgid="4609566827219442376">"4G-tietojen raja saavutettu"</string> diff --git a/core/res/res/values-fr-rCA/strings.xml b/core/res/res/values-fr-rCA/strings.xml index c1e1808ed304..8b74244b4088 100644 --- a/core/res/res/values-fr-rCA/strings.xml +++ b/core/res/res/values-fr-rCA/strings.xml @@ -1330,7 +1330,8 @@ <string name="storage_usb_drive_label" msgid="4501418548927759953">"Clé USB <xliff:g id="MANUFACTURER">%s</xliff:g>"</string> <string name="storage_usb" msgid="3017954059538517278">"Mémoire de stockage USB"</string> <string name="extract_edit_menu_button" msgid="8940478730496610137">"Modifier"</string> - <string name="data_usage_warning_title" msgid="1955638862122232342">"Avertissement utilisation données"</string> + <!-- no translation found for data_usage_warning_title (3620440638180218181) --> + <skip /> <string name="data_usage_warning_body" msgid="6660692274311972007">"Touch. pour aff. util. et param."</string> <string name="data_usage_3g_limit_title" msgid="4361523876818447683">"Limite de données 2G-3G atteinte"</string> <string name="data_usage_4g_limit_title" msgid="4609566827219442376">"Limite de données 4G atteinte"</string> diff --git a/core/res/res/values-fr/strings.xml b/core/res/res/values-fr/strings.xml index 850301f9794d..8c8c6833c407 100644 --- a/core/res/res/values-fr/strings.xml +++ b/core/res/res/values-fr/strings.xml @@ -1330,7 +1330,8 @@ <string name="storage_usb_drive_label" msgid="4501418548927759953">"Clé USB <xliff:g id="MANUFACTURER">%s</xliff:g>"</string> <string name="storage_usb" msgid="3017954059538517278">"Mémoire de stockage USB"</string> <string name="extract_edit_menu_button" msgid="8940478730496610137">"Modifier"</string> - <string name="data_usage_warning_title" msgid="1955638862122232342">"Avertissement utilisation données"</string> + <!-- no translation found for data_usage_warning_title (3620440638180218181) --> + <skip /> <string name="data_usage_warning_body" msgid="6660692274311972007">"Appuyez pour conso/paramètres."</string> <string name="data_usage_3g_limit_title" msgid="4361523876818447683">"Limite de données 2G-3G atteinte"</string> <string name="data_usage_4g_limit_title" msgid="4609566827219442376">"Limite de données 4G atteinte"</string> diff --git a/core/res/res/values-gl-rES/strings.xml b/core/res/res/values-gl-rES/strings.xml index 8a37cffdd908..f842df2c85a3 100644 --- a/core/res/res/values-gl-rES/strings.xml +++ b/core/res/res/values-gl-rES/strings.xml @@ -1330,7 +1330,8 @@ <string name="storage_usb_drive_label" msgid="4501418548927759953">"Unidade USB de <xliff:g id="MANUFACTURER">%s</xliff:g>"</string> <string name="storage_usb" msgid="3017954059538517278">"almacenamento USB"</string> <string name="extract_edit_menu_button" msgid="8940478730496610137">"Editar"</string> - <string name="data_usage_warning_title" msgid="1955638862122232342">"Aviso de uso de datos"</string> + <!-- no translation found for data_usage_warning_title (3620440638180218181) --> + <skip /> <string name="data_usage_warning_body" msgid="6660692274311972007">"Toca para uso e configuración."</string> <string name="data_usage_3g_limit_title" msgid="4361523876818447683">"Límite de datos de 2G-3G acadado"</string> <string name="data_usage_4g_limit_title" msgid="4609566827219442376">"Límite de datos de 4G acadado"</string> diff --git a/core/res/res/values-gu-rIN/strings.xml b/core/res/res/values-gu-rIN/strings.xml index 2cd3da8ed45c..45038b0a6cf6 100644 --- a/core/res/res/values-gu-rIN/strings.xml +++ b/core/res/res/values-gu-rIN/strings.xml @@ -1330,7 +1330,8 @@ <string name="storage_usb_drive_label" msgid="4501418548927759953">"<xliff:g id="MANUFACTURER">%s</xliff:g> USB ડ્રાઇવ"</string> <string name="storage_usb" msgid="3017954059538517278">"USB સંગ્રહ"</string> <string name="extract_edit_menu_button" msgid="8940478730496610137">"સંપાદિત કરો"</string> - <string name="data_usage_warning_title" msgid="1955638862122232342">"ડેટા વપરાશ ચેતવણી"</string> + <!-- no translation found for data_usage_warning_title (3620440638180218181) --> + <skip /> <string name="data_usage_warning_body" msgid="6660692274311972007">"વપરાશ અને સેટિંગ્સ જોવા ટૅપ કરો."</string> <string name="data_usage_3g_limit_title" msgid="4361523876818447683">"2G-3G ડેટા મર્યાદા પર પહોંચ્યાં"</string> <string name="data_usage_4g_limit_title" msgid="4609566827219442376">"4G ડેટા મર્યાદા સુધી પહોંચ્યાં"</string> diff --git a/core/res/res/values-hi/strings.xml b/core/res/res/values-hi/strings.xml index d87f747fe631..8a651bda5a6d 100644 --- a/core/res/res/values-hi/strings.xml +++ b/core/res/res/values-hi/strings.xml @@ -1330,7 +1330,8 @@ <string name="storage_usb_drive_label" msgid="4501418548927759953">"<xliff:g id="MANUFACTURER">%s</xliff:g> USB डिस्क"</string> <string name="storage_usb" msgid="3017954059538517278">"USB मेमोरी"</string> <string name="extract_edit_menu_button" msgid="8940478730496610137">"संपादित करें"</string> - <string name="data_usage_warning_title" msgid="1955638862122232342">"डेटा उपयोग की चेतावनी"</string> + <!-- no translation found for data_usage_warning_title (3620440638180218181) --> + <skip /> <string name="data_usage_warning_body" msgid="6660692274311972007">"उपयोग व सेटिंग देखने हेतु टैप करें."</string> <string name="data_usage_3g_limit_title" msgid="4361523876818447683">"2G-3G डेटा सीमा पूर्ण हो गई"</string> <string name="data_usage_4g_limit_title" msgid="4609566827219442376">"4G डेटा सीमा पूर्ण हो गई"</string> diff --git a/core/res/res/values-hr/strings.xml b/core/res/res/values-hr/strings.xml index ed55b3f79992..16a304fb3006 100644 --- a/core/res/res/values-hr/strings.xml +++ b/core/res/res/values-hr/strings.xml @@ -1356,7 +1356,8 @@ <string name="storage_usb_drive_label" msgid="4501418548927759953">"<xliff:g id="MANUFACTURER">%s</xliff:g> USB pogon"</string> <string name="storage_usb" msgid="3017954059538517278">"USB pohrana"</string> <string name="extract_edit_menu_button" msgid="8940478730496610137">"Uredi"</string> - <string name="data_usage_warning_title" msgid="1955638862122232342">"Upozorenje o upotrebi podataka"</string> + <!-- no translation found for data_usage_warning_title (3620440638180218181) --> + <skip /> <string name="data_usage_warning_body" msgid="6660692274311972007">"Dodirnite za upotrebu i postavke"</string> <string name="data_usage_3g_limit_title" msgid="4361523876818447683">"Dost. ogr. 2G–3G prijenosa pod."</string> <string name="data_usage_4g_limit_title" msgid="4609566827219442376">"Dost. ogr. 4G prijenosa podataka"</string> diff --git a/core/res/res/values-hu/strings.xml b/core/res/res/values-hu/strings.xml index f4ea98d67095..cbb72a7c06c1 100644 --- a/core/res/res/values-hu/strings.xml +++ b/core/res/res/values-hu/strings.xml @@ -1330,7 +1330,8 @@ <string name="storage_usb_drive_label" msgid="4501418548927759953">"<xliff:g id="MANUFACTURER">%s</xliff:g> USB-meghajtó"</string> <string name="storage_usb" msgid="3017954059538517278">"USB-tár"</string> <string name="extract_edit_menu_button" msgid="8940478730496610137">"Szerkesztés"</string> - <string name="data_usage_warning_title" msgid="1955638862122232342">"Adathasználati figyelmeztetés"</string> + <!-- no translation found for data_usage_warning_title (3620440638180218181) --> + <skip /> <string name="data_usage_warning_body" msgid="6660692274311972007">"Koppintson az adatokért."</string> <string name="data_usage_3g_limit_title" msgid="4361523876818447683">"2G-/3G-adatkorlát elérve"</string> <string name="data_usage_4g_limit_title" msgid="4609566827219442376">"4G-adatkorlát elérve"</string> diff --git a/core/res/res/values-hy-rAM/strings.xml b/core/res/res/values-hy-rAM/strings.xml index f43dfb3009f7..ae83552af2c9 100644 --- a/core/res/res/values-hy-rAM/strings.xml +++ b/core/res/res/values-hy-rAM/strings.xml @@ -251,17 +251,17 @@ <string name="permgrouplab_calendar" msgid="5863508437783683902">"Օրացույց"</string> <string name="permgroupdesc_calendar" msgid="3889615280211184106">"օգտագործել օրացույցը"</string> <string name="permgrouplab_sms" msgid="228308803364967808">"Կարճ հաղորդագրություն"</string> - <string name="permgroupdesc_sms" msgid="4656988620100940350">"ուղարկել և դիտել SMS հաղորդագրությունները"</string> + <string name="permgroupdesc_sms" msgid="4656988620100940350">"ուղարկել և դիտել SMS հաղորդ․-ները"</string> <string name="permgrouplab_storage" msgid="1971118770546336966">"Պահոց"</string> - <string name="permgroupdesc_storage" msgid="637758554581589203">"օգտագործել լուսանկարները, մեդիա ֆայլերը և ձեր սարքում պահվող այլ ֆայլերը"</string> + <string name="permgroupdesc_storage" msgid="637758554581589203">"օգտագործել լուսանկարները, մեդիա ֆայլերը և ձեր սարքում պահվող մյուս ֆայլերը"</string> <string name="permgrouplab_microphone" msgid="171539900250043464">"Բարձրախոս"</string> - <string name="permgroupdesc_microphone" msgid="4988812113943554584">"ձայնագրում"</string> + <string name="permgroupdesc_microphone" msgid="4988812113943554584">"ձայնագրել"</string> <string name="permgrouplab_camera" msgid="4820372495894586615">"Ֆոտոխցիկ"</string> - <string name="permgroupdesc_camera" msgid="3250611594678347720">"լուսանկարում և տեսագրում"</string> + <string name="permgroupdesc_camera" msgid="3250611594678347720">"լուսանկարել և տեսագրել"</string> <string name="permgrouplab_phone" msgid="5229115638567440675">"Հեռախոս"</string> - <string name="permgroupdesc_phone" msgid="6234224354060641055">"հեռախոսազանգերի կատարում և կառավարում"</string> + <string name="permgroupdesc_phone" msgid="6234224354060641055">"կատարել զանգեր և կառավարել զանգերը"</string> <string name="permgrouplab_sensors" msgid="416037179223226722">"Մարմնի սենսորներ"</string> - <string name="permgroupdesc_sensors" msgid="7147968539346634043">"օգտագործել ձեր հիմնական ֆիզիոլոգիական ցուցանիշների վերաբերյալ սենսորի տվյալները"</string> + <string name="permgroupdesc_sensors" msgid="7147968539346634043">"օգտագործել սենսորների տվյալները ձեր օրգանիզմի վիճակի մասին"</string> <string name="capability_title_canRetrieveWindowContent" msgid="3901717936930170320">"Առբերել պատուհանի բովանդակությունը"</string> <string name="capability_desc_canRetrieveWindowContent" msgid="3772225008605310672">"Ստուգեք պատուհանի բովանդակությունը, որի հետ փոխգործակցում եք:"</string> <string name="capability_title_canRequestTouchExploration" msgid="3108723364676667320">"Միացնել Հպման միջոցով հետազոտումը"</string> @@ -1330,7 +1330,8 @@ <string name="storage_usb_drive_label" msgid="4501418548927759953">"USB սարքավար <xliff:g id="MANUFACTURER">%s</xliff:g>-ից"</string> <string name="storage_usb" msgid="3017954059538517278">"USB կրիչ"</string> <string name="extract_edit_menu_button" msgid="8940478730496610137">"Խմբագրել"</string> - <string name="data_usage_warning_title" msgid="1955638862122232342">"Տվյալների օգտագործման նախազգուշացում"</string> + <!-- no translation found for data_usage_warning_title (3620440638180218181) --> + <skip /> <string name="data_usage_warning_body" msgid="6660692274311972007">"Հպեք և տեսեք օգտագործումը և կարգավորումները:"</string> <string name="data_usage_3g_limit_title" msgid="4361523876818447683">"2G-3G տվյալների սահմանաչափը սպառվել է"</string> <string name="data_usage_4g_limit_title" msgid="4609566827219442376">"4G տվյալների սահմանաչափը սպառվել է"</string> diff --git a/core/res/res/values-in/strings.xml b/core/res/res/values-in/strings.xml index 2cbb6fb5b8a1..b6f6c4de6483 100644 --- a/core/res/res/values-in/strings.xml +++ b/core/res/res/values-in/strings.xml @@ -1330,7 +1330,8 @@ <string name="storage_usb_drive_label" msgid="4501418548927759953">"Drive USB <xliff:g id="MANUFACTURER">%s</xliff:g>"</string> <string name="storage_usb" msgid="3017954059538517278">"Penyimpanan USB"</string> <string name="extract_edit_menu_button" msgid="8940478730496610137">"Edit"</string> - <string name="data_usage_warning_title" msgid="1955638862122232342">"Peringatan penggunaan data"</string> + <!-- no translation found for data_usage_warning_title (3620440638180218181) --> + <skip /> <string name="data_usage_warning_body" msgid="6660692274311972007">"Ketuk untuk lihat penggunaan & setelan."</string> <string name="data_usage_3g_limit_title" msgid="4361523876818447683">"Batas data 2G-3G terlampaui"</string> <string name="data_usage_4g_limit_title" msgid="4609566827219442376">"Batas data 4G terlampaui"</string> diff --git a/core/res/res/values-is-rIS/strings.xml b/core/res/res/values-is-rIS/strings.xml index ffd1e311fa5a..5cce18b6f705 100644 --- a/core/res/res/values-is-rIS/strings.xml +++ b/core/res/res/values-is-rIS/strings.xml @@ -1330,7 +1330,8 @@ <string name="storage_usb_drive_label" msgid="4501418548927759953">"USB-drif frá <xliff:g id="MANUFACTURER">%s</xliff:g>"</string> <string name="storage_usb" msgid="3017954059538517278">"USB-geymsla"</string> <string name="extract_edit_menu_button" msgid="8940478730496610137">"Breyta"</string> - <string name="data_usage_warning_title" msgid="1955638862122232342">"Viðvörun vegna gagnanotkunar"</string> + <!-- no translation found for data_usage_warning_title (3620440638180218181) --> + <skip /> <string name="data_usage_warning_body" msgid="6660692274311972007">"Ýttu fyrir uppl. og stillingar"</string> <string name="data_usage_3g_limit_title" msgid="4361523876818447683">"Gagnahámarki 2G og 3G náð"</string> <string name="data_usage_4g_limit_title" msgid="4609566827219442376">"Gagnahámarki 4G náð"</string> diff --git a/core/res/res/values-it/strings.xml b/core/res/res/values-it/strings.xml index e576d8daf4d9..13c17ce073f5 100644 --- a/core/res/res/values-it/strings.xml +++ b/core/res/res/values-it/strings.xml @@ -1330,7 +1330,8 @@ <string name="storage_usb_drive_label" msgid="4501418548927759953">"Unità USB <xliff:g id="MANUFACTURER">%s</xliff:g>"</string> <string name="storage_usb" msgid="3017954059538517278">"Archivio USB"</string> <string name="extract_edit_menu_button" msgid="8940478730496610137">"Modifica"</string> - <string name="data_usage_warning_title" msgid="1955638862122232342">"Avviso sull\'utilizzo dei dati"</string> + <!-- no translation found for data_usage_warning_title (3620440638180218181) --> + <skip /> <string name="data_usage_warning_body" msgid="6660692274311972007">"Tocca per uso e impostazioni."</string> <string name="data_usage_3g_limit_title" msgid="4361523876818447683">"Limite di dati 2G-3G raggiunto"</string> <string name="data_usage_4g_limit_title" msgid="4609566827219442376">"Limite di dati 4G raggiunto"</string> diff --git a/core/res/res/values-iw/strings.xml b/core/res/res/values-iw/strings.xml index c0c18718e257..87ec61a4ec50 100644 --- a/core/res/res/values-iw/strings.xml +++ b/core/res/res/values-iw/strings.xml @@ -1382,7 +1382,8 @@ <string name="storage_usb_drive_label" msgid="4501418548927759953">"כונן USB של <xliff:g id="MANUFACTURER">%s</xliff:g>"</string> <string name="storage_usb" msgid="3017954059538517278">"אחסון USB"</string> <string name="extract_edit_menu_button" msgid="8940478730496610137">"ערוך"</string> - <string name="data_usage_warning_title" msgid="1955638862122232342">"אזהרת שימוש בנתונים"</string> + <!-- no translation found for data_usage_warning_title (3620440638180218181) --> + <skip /> <string name="data_usage_warning_body" msgid="6660692274311972007">"הקש כדי להציג נתוני שימוש והגדרות."</string> <string name="data_usage_3g_limit_title" msgid="4361523876818447683">"הגעת למגבלת הנתונים של 2G-3G"</string> <string name="data_usage_4g_limit_title" msgid="4609566827219442376">"הגעת למגבלת הנתונים של 4G"</string> diff --git a/core/res/res/values-ja/strings.xml b/core/res/res/values-ja/strings.xml index 59247378445f..213c0641aabb 100644 --- a/core/res/res/values-ja/strings.xml +++ b/core/res/res/values-ja/strings.xml @@ -1330,7 +1330,8 @@ <string name="storage_usb_drive_label" msgid="4501418548927759953">"<xliff:g id="MANUFACTURER">%s</xliff:g>製USBドライブ"</string> <string name="storage_usb" msgid="3017954059538517278">"USBストレージ"</string> <string name="extract_edit_menu_button" msgid="8940478730496610137">"編集"</string> - <string name="data_usage_warning_title" msgid="1955638862122232342">"データ使用の警告"</string> + <!-- no translation found for data_usage_warning_title (3620440638180218181) --> + <skip /> <string name="data_usage_warning_body" msgid="6660692274311972007">"タップして使用状況と設定を表示します。"</string> <string name="data_usage_3g_limit_title" msgid="4361523876818447683">"2G~3Gデータの上限に達しました"</string> <string name="data_usage_4g_limit_title" msgid="4609566827219442376">"4Gデータの上限に達しました"</string> diff --git a/core/res/res/values-ka-rGE/strings.xml b/core/res/res/values-ka-rGE/strings.xml index b5635914fd45..315ff645dda8 100644 --- a/core/res/res/values-ka-rGE/strings.xml +++ b/core/res/res/values-ka-rGE/strings.xml @@ -1330,7 +1330,8 @@ <string name="storage_usb_drive_label" msgid="4501418548927759953">"<xliff:g id="MANUFACTURER">%s</xliff:g> USB დისკი"</string> <string name="storage_usb" msgid="3017954059538517278">"USB მეხსიერება"</string> <string name="extract_edit_menu_button" msgid="8940478730496610137">"რედაქტირება"</string> - <string name="data_usage_warning_title" msgid="1955638862122232342">"ინტერნეტის გამოყენების გაფრთხილება"</string> + <!-- no translation found for data_usage_warning_title (3620440638180218181) --> + <skip /> <string name="data_usage_warning_body" msgid="6660692274311972007">"შეეხეთ მოხმარებისა და პარამეტრების სანახავად."</string> <string name="data_usage_3g_limit_title" msgid="4361523876818447683">"2G-3G მონაცემთა ლიმიტი ამოიწურა"</string> <string name="data_usage_4g_limit_title" msgid="4609566827219442376">"4G მონაცემთა ლიმიტი ამოიწურა"</string> diff --git a/core/res/res/values-kk-rKZ/strings.xml b/core/res/res/values-kk-rKZ/strings.xml index e752abace139..525fbeeeea96 100644 --- a/core/res/res/values-kk-rKZ/strings.xml +++ b/core/res/res/values-kk-rKZ/strings.xml @@ -1330,7 +1330,8 @@ <string name="storage_usb_drive_label" msgid="4501418548927759953">"<xliff:g id="MANUFACTURER">%s</xliff:g> USB дискі"</string> <string name="storage_usb" msgid="3017954059538517278">"USB жады"</string> <string name="extract_edit_menu_button" msgid="8940478730496610137">"Өзгерту"</string> - <string name="data_usage_warning_title" msgid="1955638862122232342">"Дерекқор қолдануға қатысты ескерту"</string> + <!-- no translation found for data_usage_warning_title (3620440638180218181) --> + <skip /> <string name="data_usage_warning_body" msgid="6660692274311972007">"Трафик пен параметрлерді көру үшін түртіңіз."</string> <string name="data_usage_3g_limit_title" msgid="4361523876818447683">"2G-3G деректер шегіне жеттіңіз"</string> <string name="data_usage_4g_limit_title" msgid="4609566827219442376">"4G деректер шегіне жеттіңіз"</string> diff --git a/core/res/res/values-km-rKH/strings.xml b/core/res/res/values-km-rKH/strings.xml index 3fcf41c4e01b..014d8446991d 100644 --- a/core/res/res/values-km-rKH/strings.xml +++ b/core/res/res/values-km-rKH/strings.xml @@ -1332,7 +1332,8 @@ <string name="storage_usb_drive_label" msgid="4501418548927759953">"ឧបករណ៍ផ្ទុក USB <xliff:g id="MANUFACTURER">%s</xliff:g>"</string> <string name="storage_usb" msgid="3017954059538517278">"ឧបករណ៍ផ្ទុកយូអេសប៊ី"</string> <string name="extract_edit_menu_button" msgid="8940478730496610137">"កែសម្រួល"</string> - <string name="data_usage_warning_title" msgid="1955638862122232342">"ការព្រមានប្រើទិន្នន័យ"</string> + <!-- no translation found for data_usage_warning_title (3620440638180218181) --> + <skip /> <string name="data_usage_warning_body" msgid="6660692274311972007">"ប៉ះដើម្បីមើលការប្រើប្រាស់ និងការកំណត់"</string> <string name="data_usage_3g_limit_title" msgid="4361523876818447683">"បានដល់ដែនកំណត់ទិន្នន័យ 2G-3G"</string> <string name="data_usage_4g_limit_title" msgid="4609566827219442376">"បានដល់ដែនកំណត់ទិន្នន័យ 4G"</string> diff --git a/core/res/res/values-kn-rIN/strings.xml b/core/res/res/values-kn-rIN/strings.xml index cd3f94816399..ab60289fb29c 100644 --- a/core/res/res/values-kn-rIN/strings.xml +++ b/core/res/res/values-kn-rIN/strings.xml @@ -1330,7 +1330,8 @@ <string name="storage_usb_drive_label" msgid="4501418548927759953">"<xliff:g id="MANUFACTURER">%s</xliff:g> USB ಡ್ರೈವ್"</string> <string name="storage_usb" msgid="3017954059538517278">"USB ಸಂಗ್ರಹಣೆ"</string> <string name="extract_edit_menu_button" msgid="8940478730496610137">"ಎಡಿಟ್"</string> - <string name="data_usage_warning_title" msgid="1955638862122232342">"ಡೇಟಾ ಬಳಕೆಯ ಎಚ್ಚರಿಕೆ"</string> + <!-- no translation found for data_usage_warning_title (3620440638180218181) --> + <skip /> <string name="data_usage_warning_body" msgid="6660692274311972007">"ಬಳಕೆ ಮತ್ತು ಸೆಟ್ಟಿಂಗ್ಗಳನ್ನು ವೀಕ್ಷಿಸಲು ಟ್ಯಾಪ್ ಮಾಡಿ."</string> <string name="data_usage_3g_limit_title" msgid="4361523876818447683">"2G-3G ಡೇಟಾ ಮೀತಿಯನ್ನು ತಲುಪಿದೆ"</string> <string name="data_usage_4g_limit_title" msgid="4609566827219442376">"4G ಡೇಟಾ ಮೀತಿಯನ್ನು ತಲುಪಿದೆ"</string> diff --git a/core/res/res/values-ko/strings.xml b/core/res/res/values-ko/strings.xml index 8de15a8b3520..5d226a6bd822 100644 --- a/core/res/res/values-ko/strings.xml +++ b/core/res/res/values-ko/strings.xml @@ -1330,7 +1330,8 @@ <string name="storage_usb_drive_label" msgid="4501418548927759953">"<xliff:g id="MANUFACTURER">%s</xliff:g> USB 드라이브"</string> <string name="storage_usb" msgid="3017954059538517278">"USB 저장소"</string> <string name="extract_edit_menu_button" msgid="8940478730496610137">"수정"</string> - <string name="data_usage_warning_title" msgid="1955638862122232342">"데이터 사용 경고"</string> + <!-- no translation found for data_usage_warning_title (3620440638180218181) --> + <skip /> <string name="data_usage_warning_body" msgid="6660692274311972007">"사용량 및 설정을 보려면 탭하세요."</string> <string name="data_usage_3g_limit_title" msgid="4361523876818447683">"2G-3G 데이터 한도에 도달함"</string> <string name="data_usage_4g_limit_title" msgid="4609566827219442376">"4G 데이터 한도에 도달함"</string> diff --git a/core/res/res/values-ky-rKG/strings.xml b/core/res/res/values-ky-rKG/strings.xml index 2d155bf82218..99bba3a72e7c 100644 --- a/core/res/res/values-ky-rKG/strings.xml +++ b/core/res/res/values-ky-rKG/strings.xml @@ -1330,7 +1330,8 @@ <string name="storage_usb_drive_label" msgid="4501418548927759953">"<xliff:g id="MANUFACTURER">%s</xliff:g> USB түзмөгү"</string> <string name="storage_usb" msgid="3017954059538517278">"USB эстутуму"</string> <string name="extract_edit_menu_button" msgid="8940478730496610137">"Өзгөртүү"</string> - <string name="data_usage_warning_title" msgid="1955638862122232342">"Дайындарды колдонуу боюнча эскрт"</string> + <!-- no translation found for data_usage_warning_title (3620440638180218181) --> + <skip /> <string name="data_usage_warning_body" msgid="6660692274311972007">"Колдонулушун жана жөндөөлөрүн көрүү үчүн таптаңыз."</string> <string name="data_usage_3g_limit_title" msgid="4361523876818447683">"2G-3G дайындар чегине жетти"</string> <string name="data_usage_4g_limit_title" msgid="4609566827219442376">"4G дайындар чегине жетти"</string> diff --git a/core/res/res/values-lo-rLA/strings.xml b/core/res/res/values-lo-rLA/strings.xml index 0676d1508921..9762f264afed 100644 --- a/core/res/res/values-lo-rLA/strings.xml +++ b/core/res/res/values-lo-rLA/strings.xml @@ -1330,7 +1330,8 @@ <string name="storage_usb_drive_label" msgid="4501418548927759953">"<xliff:g id="MANUFACTURER">%s</xliff:g> USB ດຣ້າຍ"</string> <string name="storage_usb" msgid="3017954059538517278">"ບ່ອນຈັດເກັບຂໍ້ມູນ USB"</string> <string name="extract_edit_menu_button" msgid="8940478730496610137">"ແກ້ໄຂ"</string> - <string name="data_usage_warning_title" msgid="1955638862122232342">"ເຕືອນກ່ຽວກັບການນຳໃຊ້ຂໍ້ມູນ"</string> + <!-- no translation found for data_usage_warning_title (3620440638180218181) --> + <skip /> <string name="data_usage_warning_body" msgid="6660692274311972007">"ແຕະເພື່ອເບິ່ງການນຳໃຊ້ ແລະ ການຕັ້ງຄ່າ."</string> <string name="data_usage_3g_limit_title" msgid="4361523876818447683">"ໃຊ້ຂໍ້ມູນ 2G-3G ຮອດຈຳນວນທີ່ຈຳກັດແລ້ວ"</string> <string name="data_usage_4g_limit_title" msgid="4609566827219442376">"ໃຊ້ຂໍ້ມູນ 4G ຮອດຈຳນວນທີ່ຈຳກັດແລ້ວ"</string> diff --git a/core/res/res/values-lt/strings.xml b/core/res/res/values-lt/strings.xml index f43e6e814029..644606661b22 100644 --- a/core/res/res/values-lt/strings.xml +++ b/core/res/res/values-lt/strings.xml @@ -1382,7 +1382,8 @@ <string name="storage_usb_drive_label" msgid="4501418548927759953">"„<xliff:g id="MANUFACTURER">%s</xliff:g>“ atmintukas"</string> <string name="storage_usb" msgid="3017954059538517278">"USB atmintis"</string> <string name="extract_edit_menu_button" msgid="8940478730496610137">"Redaguoti"</string> - <string name="data_usage_warning_title" msgid="1955638862122232342">"Įspėjimas dėl duomenų naudojimo"</string> + <!-- no translation found for data_usage_warning_title (3620440638180218181) --> + <skip /> <string name="data_usage_warning_body" msgid="6660692274311972007">"Pal. ir perž. naud. i. bei nust."</string> <string name="data_usage_3g_limit_title" msgid="4361523876818447683">"Pasiektas 2G–3G duomenų apribojimas"</string> <string name="data_usage_4g_limit_title" msgid="4609566827219442376">"Pasiektas 4G duomenų apribojimas"</string> diff --git a/core/res/res/values-lv/strings.xml b/core/res/res/values-lv/strings.xml index 3aa408a391dc..b0e7af501b17 100644 --- a/core/res/res/values-lv/strings.xml +++ b/core/res/res/values-lv/strings.xml @@ -1356,7 +1356,8 @@ <string name="storage_usb_drive_label" msgid="4501418548927759953">"<xliff:g id="MANUFACTURER">%s</xliff:g> USB disks"</string> <string name="storage_usb" msgid="3017954059538517278">"USB atmiņa"</string> <string name="extract_edit_menu_button" msgid="8940478730496610137">"Rediģēt"</string> - <string name="data_usage_warning_title" msgid="1955638862122232342">"Datu izmantošanas brīdinājums"</string> + <!-- no translation found for data_usage_warning_title (3620440638180218181) --> + <skip /> <string name="data_usage_warning_body" msgid="6660692274311972007">"Piesk., lai sk. lietoj. un iest."</string> <string name="data_usage_3g_limit_title" msgid="4361523876818447683">"Sasniegts 2G-3G datu ierobež."</string> <string name="data_usage_4g_limit_title" msgid="4609566827219442376">"Sasniegts 4G datu ierobežojums"</string> diff --git a/core/res/res/values-mk-rMK/strings.xml b/core/res/res/values-mk-rMK/strings.xml index 437df10805c0..a47a48341627 100644 --- a/core/res/res/values-mk-rMK/strings.xml +++ b/core/res/res/values-mk-rMK/strings.xml @@ -1332,7 +1332,8 @@ <string name="storage_usb_drive_label" msgid="4501418548927759953">"<xliff:g id="MANUFACTURER">%s</xliff:g> УСБ-меморија"</string> <string name="storage_usb" msgid="3017954059538517278">"УСБ меморија"</string> <string name="extract_edit_menu_button" msgid="8940478730496610137">"Уреди"</string> - <string name="data_usage_warning_title" msgid="1955638862122232342">"Опомена за потрошен интернет"</string> + <!-- no translation found for data_usage_warning_title (3620440638180218181) --> + <skip /> <string name="data_usage_warning_body" msgid="6660692274311972007">"Допрете за употреба и поставки."</string> <string name="data_usage_3g_limit_title" msgid="4361523876818447683">"Постигна лимит за 2G-3G податоци"</string> <string name="data_usage_4g_limit_title" msgid="4609566827219442376">"Постигнат лимит за 4G податоци"</string> diff --git a/core/res/res/values-ml-rIN/strings.xml b/core/res/res/values-ml-rIN/strings.xml index 76d05c783b79..eaa8deb68d74 100644 --- a/core/res/res/values-ml-rIN/strings.xml +++ b/core/res/res/values-ml-rIN/strings.xml @@ -1330,7 +1330,8 @@ <string name="storage_usb_drive_label" msgid="4501418548927759953">"<xliff:g id="MANUFACTURER">%s</xliff:g> USB ഡ്രൈവ്"</string> <string name="storage_usb" msgid="3017954059538517278">"USB സ്റ്റോറേജ്"</string> <string name="extract_edit_menu_button" msgid="8940478730496610137">"എഡിറ്റുചെയ്യുക"</string> - <string name="data_usage_warning_title" msgid="1955638862122232342">"ഡാറ്റ ഉപയോഗ മുന്നറിയിപ്പ്"</string> + <!-- no translation found for data_usage_warning_title (3620440638180218181) --> + <skip /> <string name="data_usage_warning_body" msgid="6660692274311972007">"ഉപയോഗവും ക്രമീകരണവും കാണാൻ ടാപ്പുചെയ്യുക."</string> <string name="data_usage_3g_limit_title" msgid="4361523876818447683">"2G-3G ഡാറ്റ പരിധിയിലെത്തി"</string> <string name="data_usage_4g_limit_title" msgid="4609566827219442376">"4G ഡാറ്റ പരിധിയിലെത്തി"</string> diff --git a/core/res/res/values-mn-rMN/strings.xml b/core/res/res/values-mn-rMN/strings.xml index 074e5c3c643b..79dbc686d967 100644 --- a/core/res/res/values-mn-rMN/strings.xml +++ b/core/res/res/values-mn-rMN/strings.xml @@ -1330,7 +1330,8 @@ <string name="storage_usb_drive_label" msgid="4501418548927759953">"<xliff:g id="MANUFACTURER">%s</xliff:g> USB диск"</string> <string name="storage_usb" msgid="3017954059538517278">"USB сан"</string> <string name="extract_edit_menu_button" msgid="8940478730496610137">"Засах"</string> - <string name="data_usage_warning_title" msgid="1955638862122232342">"Дата хэрэглээний анхааруулга"</string> + <!-- no translation found for data_usage_warning_title (3620440638180218181) --> + <skip /> <string name="data_usage_warning_body" msgid="6660692274311972007">"Хэрэглээ, тохиргоог харах бол товш."</string> <string name="data_usage_3g_limit_title" msgid="4361523876818447683">"2G-3G дата хязгаарт хүрсэн"</string> <string name="data_usage_4g_limit_title" msgid="4609566827219442376">"4G дата хязгаарт хүрсэн"</string> diff --git a/core/res/res/values-mr-rIN/strings.xml b/core/res/res/values-mr-rIN/strings.xml index 1997714eefd5..fce64c424353 100644 --- a/core/res/res/values-mr-rIN/strings.xml +++ b/core/res/res/values-mr-rIN/strings.xml @@ -1330,7 +1330,8 @@ <string name="storage_usb_drive_label" msgid="4501418548927759953">"<xliff:g id="MANUFACTURER">%s</xliff:g> USB ड्राइव्ह"</string> <string name="storage_usb" msgid="3017954059538517278">"USB संचयन"</string> <string name="extract_edit_menu_button" msgid="8940478730496610137">"संपादित करा"</string> - <string name="data_usage_warning_title" msgid="1955638862122232342">"डेटा वापर चेतावणी"</string> + <!-- no translation found for data_usage_warning_title (3620440638180218181) --> + <skip /> <string name="data_usage_warning_body" msgid="6660692274311972007">"वापर आणि सेटिंग्ज पाहण्यासाठी टॅप करा."</string> <string name="data_usage_3g_limit_title" msgid="4361523876818447683">"2G-3G डेटा मर्यादा गाठली"</string> <string name="data_usage_4g_limit_title" msgid="4609566827219442376">"4G डेटा मर्यादा गाठली"</string> diff --git a/core/res/res/values-ms-rMY/strings.xml b/core/res/res/values-ms-rMY/strings.xml index 0846ede2b3d0..53181ce0fe49 100644 --- a/core/res/res/values-ms-rMY/strings.xml +++ b/core/res/res/values-ms-rMY/strings.xml @@ -1330,7 +1330,8 @@ <string name="storage_usb_drive_label" msgid="4501418548927759953">"Pemacu USB <xliff:g id="MANUFACTURER">%s</xliff:g>"</string> <string name="storage_usb" msgid="3017954059538517278">"Storan USB"</string> <string name="extract_edit_menu_button" msgid="8940478730496610137">"Edit"</string> - <string name="data_usage_warning_title" msgid="1955638862122232342">"Amaran penggunaan data"</string> + <!-- no translation found for data_usage_warning_title (3620440638180218181) --> + <skip /> <string name="data_usage_warning_body" msgid="6660692274311972007">"Ketik utk lihat p\'gunaan & ttpn."</string> <string name="data_usage_3g_limit_title" msgid="4361523876818447683">"Mencapai had data 2G-3G"</string> <string name="data_usage_4g_limit_title" msgid="4609566827219442376">"Mencapai had data 4G"</string> diff --git a/core/res/res/values-my-rMM/strings.xml b/core/res/res/values-my-rMM/strings.xml index 549bb69ede27..987d7642fdf3 100644 --- a/core/res/res/values-my-rMM/strings.xml +++ b/core/res/res/values-my-rMM/strings.xml @@ -1330,7 +1330,8 @@ <string name="storage_usb_drive_label" msgid="4501418548927759953">"<xliff:g id="MANUFACTURER">%s</xliff:g> USB ဒရိုက်ဗ်"</string> <string name="storage_usb" msgid="3017954059538517278">"USBဖြင့် သိမ်းဆည်း"</string> <string name="extract_edit_menu_button" msgid="8940478730496610137">"ပြင်ဆင်ရန်"</string> - <string name="data_usage_warning_title" msgid="1955638862122232342">"ဒေတာအသုံးပြုမှုသတိပေးချက်"</string> + <!-- no translation found for data_usage_warning_title (3620440638180218181) --> + <skip /> <string name="data_usage_warning_body" msgid="6660692274311972007">"အသုံးပြုမှုနှင့် ဆက်တင်များကိုကြည့်ရန် တို့ပါ။"</string> <string name="data_usage_3g_limit_title" msgid="4361523876818447683">"2G-3G ဒေတာ ကန့်သတ်ချက် ပြည့်မီသွားပြီ"</string> <string name="data_usage_4g_limit_title" msgid="4609566827219442376">"4G ဒေတာ ကန့်သတ်ချက် ပြည့်မီသွားပြီ"</string> diff --git a/core/res/res/values-nb/strings.xml b/core/res/res/values-nb/strings.xml index 33f1436c7158..c807c14877bd 100644 --- a/core/res/res/values-nb/strings.xml +++ b/core/res/res/values-nb/strings.xml @@ -1330,7 +1330,8 @@ <string name="storage_usb_drive_label" msgid="4501418548927759953">"<xliff:g id="MANUFACTURER">%s</xliff:g> USB-stasjon"</string> <string name="storage_usb" msgid="3017954059538517278">"USB-lagring"</string> <string name="extract_edit_menu_button" msgid="8940478730496610137">"Rediger"</string> - <string name="data_usage_warning_title" msgid="1955638862122232342">"Advarsel for høyt dataforbruk"</string> + <!-- no translation found for data_usage_warning_title (3620440638180218181) --> + <skip /> <string name="data_usage_warning_body" msgid="6660692274311972007">"Trykk for å se bruken og innstillingene."</string> <string name="data_usage_3g_limit_title" msgid="4361523876818447683">"Datagrensen for 2G-3G er nådd"</string> <string name="data_usage_4g_limit_title" msgid="4609566827219442376">"Datagrensen for 4G er nådd"</string> diff --git a/core/res/res/values-ne-rNP/strings.xml b/core/res/res/values-ne-rNP/strings.xml index d4ad51f55599..65d3b69e923c 100644 --- a/core/res/res/values-ne-rNP/strings.xml +++ b/core/res/res/values-ne-rNP/strings.xml @@ -257,7 +257,7 @@ <string name="permgrouplab_microphone" msgid="171539900250043464">"माइक्रोफोन"</string> <string name="permgroupdesc_microphone" msgid="4988812113943554584">"अडियो रेकर्ड गर्नुहोस्"</string> <string name="permgrouplab_camera" msgid="4820372495894586615">"क्यामेरा"</string> - <string name="permgroupdesc_camera" msgid="3250611594678347720">"तस्बिर खिच्नुहोस् तथा भिडियो रेकर्ड गर्नुहोस्"</string> + <string name="permgroupdesc_camera" msgid="3250611594678347720">"तस्बिर खिच्नुका साथै भिडियो रेकर्ड गर्नुहोस्"</string> <string name="permgrouplab_phone" msgid="5229115638567440675">"फोन"</string> <string name="permgroupdesc_phone" msgid="6234224354060641055">"फोन कलहरू गर्नुहोस् र व्यवस्थापन गर्नुहोस्"</string> <string name="permgrouplab_sensors" msgid="416037179223226722">"शारीरिक सेन्सर"</string> @@ -1336,7 +1336,8 @@ <string name="storage_usb_drive_label" msgid="4501418548927759953">"<xliff:g id="MANUFACTURER">%s</xliff:g> USB ड्राइभ"</string> <string name="storage_usb" msgid="3017954059538517278">"USB भण्डारण"</string> <string name="extract_edit_menu_button" msgid="8940478730496610137">"सम्पादन गर्नुहोस्"</string> - <string name="data_usage_warning_title" msgid="1955638862122232342">"डेटाको प्रयोग चेतावनी"</string> + <!-- no translation found for data_usage_warning_title (3620440638180218181) --> + <skip /> <string name="data_usage_warning_body" msgid="6660692274311972007">"प्रयोग र सेटिङहरू हेर्न ट्याप गर्नुहोस्।"</string> <string name="data_usage_3g_limit_title" msgid="4361523876818447683">"2G-3G डेटा सीमा पुग्यो"</string> <string name="data_usage_4g_limit_title" msgid="4609566827219442376">"4G डेटा सीमा पुग्यो"</string> diff --git a/core/res/res/values-nl/strings.xml b/core/res/res/values-nl/strings.xml index 33fcb8abcc20..69a407421aa1 100644 --- a/core/res/res/values-nl/strings.xml +++ b/core/res/res/values-nl/strings.xml @@ -1330,7 +1330,8 @@ <string name="storage_usb_drive_label" msgid="4501418548927759953">"<xliff:g id="MANUFACTURER">%s</xliff:g> USB-drive"</string> <string name="storage_usb" msgid="3017954059538517278">"USB-opslag"</string> <string name="extract_edit_menu_button" msgid="8940478730496610137">"Bewerken"</string> - <string name="data_usage_warning_title" msgid="1955638862122232342">"Waarschuwing v. gegevensgebruik"</string> + <!-- no translation found for data_usage_warning_title (3620440638180218181) --> + <skip /> <string name="data_usage_warning_body" msgid="6660692274311972007">"Tik voor gebruik en instellingen"</string> <string name="data_usage_3g_limit_title" msgid="4361523876818447683">"Gegevenslimiet van 2G-3G bereikt"</string> <string name="data_usage_4g_limit_title" msgid="4609566827219442376">"Gegevenslimiet van 4G bereikt"</string> diff --git a/core/res/res/values-pa-rIN/strings.xml b/core/res/res/values-pa-rIN/strings.xml index ae8a4b13cd03..ac80d5163f01 100644 --- a/core/res/res/values-pa-rIN/strings.xml +++ b/core/res/res/values-pa-rIN/strings.xml @@ -1330,7 +1330,8 @@ <string name="storage_usb_drive_label" msgid="4501418548927759953">"<xliff:g id="MANUFACTURER">%s</xliff:g> USB ਡ੍ਰਾਇਵ"</string> <string name="storage_usb" msgid="3017954059538517278">"USB ਸਟੋਰੇਜ"</string> <string name="extract_edit_menu_button" msgid="8940478730496610137">"ਸੰਪਾਦਿਤ ਕਰੋ"</string> - <string name="data_usage_warning_title" msgid="1955638862122232342">"ਡੈਟਾ ਉਪਯੋਗ ਚਿਤਾਵਨੀ"</string> + <!-- no translation found for data_usage_warning_title (3620440638180218181) --> + <skip /> <string name="data_usage_warning_body" msgid="6660692274311972007">"ਵਰਤੋਂ ਅਤੇ ਸੈਟਿੰਗਾਂ ਨੂੰ ਵੇਖਣ ਲਈ ਟੈਪ ਕਰੋ।"</string> <string name="data_usage_3g_limit_title" msgid="4361523876818447683">"2G-3G ਡੈਟਾ ਸੀਮਾ ਪੂਰੀ ਹੋ ਗਈ"</string> <string name="data_usage_4g_limit_title" msgid="4609566827219442376">"4G ਡੈਟਾ ਸੀਮਾ ਪੂਰੀ ਹੋਈ"</string> diff --git a/core/res/res/values-pl/strings.xml b/core/res/res/values-pl/strings.xml index 8a2dae5c0f40..86988460866c 100644 --- a/core/res/res/values-pl/strings.xml +++ b/core/res/res/values-pl/strings.xml @@ -1382,7 +1382,8 @@ <string name="storage_usb_drive_label" msgid="4501418548927759953">"Dysk USB (<xliff:g id="MANUFACTURER">%s</xliff:g>)"</string> <string name="storage_usb" msgid="3017954059538517278">"Nośnik USB"</string> <string name="extract_edit_menu_button" msgid="8940478730496610137">"Edytuj"</string> - <string name="data_usage_warning_title" msgid="1955638862122232342">"Ostrzeżenie o transmisji danych"</string> + <!-- no translation found for data_usage_warning_title (3620440638180218181) --> + <skip /> <string name="data_usage_warning_body" msgid="6660692274311972007">"Kliknij, by wyświetlić użycie i ustawienia."</string> <string name="data_usage_3g_limit_title" msgid="4361523876818447683">"Osiągnięto limit danych 2G/3G"</string> <string name="data_usage_4g_limit_title" msgid="4609566827219442376">"Osiągnięto limit danych 4G"</string> diff --git a/core/res/res/values-pt-rBR/strings.xml b/core/res/res/values-pt-rBR/strings.xml index 191a41af593d..74b75193d0db 100644 --- a/core/res/res/values-pt-rBR/strings.xml +++ b/core/res/res/values-pt-rBR/strings.xml @@ -1330,7 +1330,8 @@ <string name="storage_usb_drive_label" msgid="4501418548927759953">"Drive USB <xliff:g id="MANUFACTURER">%s</xliff:g>"</string> <string name="storage_usb" msgid="3017954059538517278">"Armazenamento USB"</string> <string name="extract_edit_menu_button" msgid="8940478730496610137">"Editar"</string> - <string name="data_usage_warning_title" msgid="1955638862122232342">"Aviso sobre uso de dados"</string> + <!-- no translation found for data_usage_warning_title (3620440638180218181) --> + <skip /> <string name="data_usage_warning_body" msgid="6660692274311972007">"Toque para ver uso e config."</string> <string name="data_usage_3g_limit_title" msgid="4361523876818447683">"Limite de dados 2G-3G atingido"</string> <string name="data_usage_4g_limit_title" msgid="4609566827219442376">"Limite de dados 4G atingido"</string> diff --git a/core/res/res/values-pt-rPT/strings.xml b/core/res/res/values-pt-rPT/strings.xml index 9db6a76d5dd9..58e4097427cd 100644 --- a/core/res/res/values-pt-rPT/strings.xml +++ b/core/res/res/values-pt-rPT/strings.xml @@ -1330,7 +1330,8 @@ <string name="storage_usb_drive_label" msgid="4501418548927759953">"Unidade USB <xliff:g id="MANUFACTURER">%s</xliff:g>"</string> <string name="storage_usb" msgid="3017954059538517278">"Armazenamento USB"</string> <string name="extract_edit_menu_button" msgid="8940478730496610137">"Editar"</string> - <string name="data_usage_warning_title" msgid="1955638862122232342">"Aviso de utilização de dados"</string> + <!-- no translation found for data_usage_warning_title (3620440638180218181) --> + <skip /> <string name="data_usage_warning_body" msgid="6660692274311972007">"Toque para ver a utilização e definições"</string> <string name="data_usage_3g_limit_title" msgid="4361523876818447683">"Limite de dados 2G/3G atingido"</string> <string name="data_usage_4g_limit_title" msgid="4609566827219442376">"Limite de dados 4G atingido"</string> diff --git a/core/res/res/values-pt/strings.xml b/core/res/res/values-pt/strings.xml index 191a41af593d..74b75193d0db 100644 --- a/core/res/res/values-pt/strings.xml +++ b/core/res/res/values-pt/strings.xml @@ -1330,7 +1330,8 @@ <string name="storage_usb_drive_label" msgid="4501418548927759953">"Drive USB <xliff:g id="MANUFACTURER">%s</xliff:g>"</string> <string name="storage_usb" msgid="3017954059538517278">"Armazenamento USB"</string> <string name="extract_edit_menu_button" msgid="8940478730496610137">"Editar"</string> - <string name="data_usage_warning_title" msgid="1955638862122232342">"Aviso sobre uso de dados"</string> + <!-- no translation found for data_usage_warning_title (3620440638180218181) --> + <skip /> <string name="data_usage_warning_body" msgid="6660692274311972007">"Toque para ver uso e config."</string> <string name="data_usage_3g_limit_title" msgid="4361523876818447683">"Limite de dados 2G-3G atingido"</string> <string name="data_usage_4g_limit_title" msgid="4609566827219442376">"Limite de dados 4G atingido"</string> diff --git a/core/res/res/values-ro/strings.xml b/core/res/res/values-ro/strings.xml index 197da9683029..50113632abef 100644 --- a/core/res/res/values-ro/strings.xml +++ b/core/res/res/values-ro/strings.xml @@ -1356,7 +1356,8 @@ <string name="storage_usb_drive_label" msgid="4501418548927759953">"Unitate USB <xliff:g id="MANUFACTURER">%s</xliff:g>"</string> <string name="storage_usb" msgid="3017954059538517278">"Dsipozitiv de stocare USB"</string> <string name="extract_edit_menu_button" msgid="8940478730496610137">"Editați"</string> - <string name="data_usage_warning_title" msgid="1955638862122232342">"Avertisment de utiliz. a datelor"</string> + <!-- no translation found for data_usage_warning_title (3620440638180218181) --> + <skip /> <string name="data_usage_warning_body" msgid="6660692274311972007">"Atingeți ca să vedeți utilizarea/setările."</string> <string name="data_usage_3g_limit_title" msgid="4361523876818447683">"Ați atins limita de date 2G-3G"</string> <string name="data_usage_4g_limit_title" msgid="4609566827219442376">"Ați atins limita de date 4G"</string> diff --git a/core/res/res/values-ru/strings.xml b/core/res/res/values-ru/strings.xml index 11f19b8d2c67..7850cd8dc5df 100644 --- a/core/res/res/values-ru/strings.xml +++ b/core/res/res/values-ru/strings.xml @@ -1382,7 +1382,8 @@ <string name="storage_usb_drive_label" msgid="4501418548927759953">"USB-накопитель <xliff:g id="MANUFACTURER">%s</xliff:g>"</string> <string name="storage_usb" msgid="3017954059538517278">"USB-накопитель"</string> <string name="extract_edit_menu_button" msgid="8940478730496610137">"Изменить"</string> - <string name="data_usage_warning_title" msgid="1955638862122232342">"Осталось мало трафика"</string> + <!-- no translation found for data_usage_warning_title (3620440638180218181) --> + <skip /> <string name="data_usage_warning_body" msgid="6660692274311972007">"Нажмите, чтобы проверить трафик и настройки."</string> <string name="data_usage_3g_limit_title" msgid="4361523876818447683">"Достигнут лимит трафика 2G/3G"</string> <string name="data_usage_4g_limit_title" msgid="4609566827219442376">"Достигнут лимит трафика 4G"</string> diff --git a/core/res/res/values-si-rLK/strings.xml b/core/res/res/values-si-rLK/strings.xml index 73e28dcd9b16..7cab897a5269 100644 --- a/core/res/res/values-si-rLK/strings.xml +++ b/core/res/res/values-si-rLK/strings.xml @@ -1332,7 +1332,8 @@ <string name="storage_usb_drive_label" msgid="4501418548927759953">"<xliff:g id="MANUFACTURER">%s</xliff:g> USB ධාවකය"</string> <string name="storage_usb" msgid="3017954059538517278">"USB ආචයනය"</string> <string name="extract_edit_menu_button" msgid="8940478730496610137">"සංස්කරණය කරන්න"</string> - <string name="data_usage_warning_title" msgid="1955638862122232342">"දත්ත භාවිතා අවවාදය"</string> + <!-- no translation found for data_usage_warning_title (3620440638180218181) --> + <skip /> <string name="data_usage_warning_body" msgid="6660692274311972007">"භාවිතය සහ සැකසීම් බැලීමට තට්ටු කරන්න."</string> <string name="data_usage_3g_limit_title" msgid="4361523876818447683">"2G-3G දත්ත සීමාවට ළඟාවී ඇත"</string> <string name="data_usage_4g_limit_title" msgid="4609566827219442376">"4G දත්ත සීමාවට ළඟාවී ඇත"</string> diff --git a/core/res/res/values-sk/strings.xml b/core/res/res/values-sk/strings.xml index 2aa140add7d8..26e275f96e68 100644 --- a/core/res/res/values-sk/strings.xml +++ b/core/res/res/values-sk/strings.xml @@ -1382,7 +1382,8 @@ <string name="storage_usb_drive_label" msgid="4501418548927759953">"Disk USB <xliff:g id="MANUFACTURER">%s</xliff:g>"</string> <string name="storage_usb" msgid="3017954059538517278">"Ukladací priestor USB"</string> <string name="extract_edit_menu_button" msgid="8940478730496610137">"Upraviť"</string> - <string name="data_usage_warning_title" msgid="1955638862122232342">"Upozornenie o využití dát"</string> + <!-- no translation found for data_usage_warning_title (3620440638180218181) --> + <skip /> <string name="data_usage_warning_body" msgid="6660692274311972007">"Klepnutím zobrazíte využitie a nastavenia."</string> <string name="data_usage_3g_limit_title" msgid="4361523876818447683">"Bol dosiahnutý limit 2G–3G"</string> <string name="data_usage_4g_limit_title" msgid="4609566827219442376">"Bol dosiahnutý limit 4G"</string> diff --git a/core/res/res/values-sl/strings.xml b/core/res/res/values-sl/strings.xml index d942c46e928c..7f49968d56fc 100644 --- a/core/res/res/values-sl/strings.xml +++ b/core/res/res/values-sl/strings.xml @@ -1382,7 +1382,8 @@ <string name="storage_usb_drive_label" msgid="4501418548927759953">"Pogon USB <xliff:g id="MANUFACTURER">%s</xliff:g>"</string> <string name="storage_usb" msgid="3017954059538517278">"Pomnilnik USB"</string> <string name="extract_edit_menu_button" msgid="8940478730496610137">"Uredi"</string> - <string name="data_usage_warning_title" msgid="1955638862122232342">"Opozorilo o uporabi podatkov"</string> + <!-- no translation found for data_usage_warning_title (3620440638180218181) --> + <skip /> <string name="data_usage_warning_body" msgid="6660692274311972007">"Dot. se za ogled upor. in nast."</string> <string name="data_usage_3g_limit_title" msgid="4361523876818447683">"Dosežena pod. omejitev za 2G/3G"</string> <string name="data_usage_4g_limit_title" msgid="4609566827219442376">"Dosežena pod. omejitev za 4G"</string> diff --git a/core/res/res/values-sq-rAL/strings.xml b/core/res/res/values-sq-rAL/strings.xml index 26637b4afe5b..c906f74e5a8f 100644 --- a/core/res/res/values-sq-rAL/strings.xml +++ b/core/res/res/values-sq-rAL/strings.xml @@ -1330,7 +1330,8 @@ <string name="storage_usb_drive_label" msgid="4501418548927759953">"USB-ja nga <xliff:g id="MANUFACTURER">%s</xliff:g>"</string> <string name="storage_usb" msgid="3017954059538517278">"Hapësira ruajtëse e USB-së"</string> <string name="extract_edit_menu_button" msgid="8940478730496610137">"Redakto"</string> - <string name="data_usage_warning_title" msgid="1955638862122232342">"Paralajmërim për përdorimin e të dhënave"</string> + <!-- no translation found for data_usage_warning_title (3620440638180218181) --> + <skip /> <string name="data_usage_warning_body" msgid="6660692274311972007">"Trokit për të parë përdorimin dhe cilësimet."</string> <string name="data_usage_3g_limit_title" msgid="4361523876818447683">"Kufiri i të dhënave 2G-3G u arrit"</string> <string name="data_usage_4g_limit_title" msgid="4609566827219442376">"Kufiri i të dhënave 4G u arrit"</string> diff --git a/core/res/res/values-sr/strings.xml b/core/res/res/values-sr/strings.xml index 162debe58771..f029dbb33674 100644 --- a/core/res/res/values-sr/strings.xml +++ b/core/res/res/values-sr/strings.xml @@ -1356,7 +1356,8 @@ <string name="storage_usb_drive_label" msgid="4501418548927759953">"<xliff:g id="MANUFACTURER">%s</xliff:g> USB диск"</string> <string name="storage_usb" msgid="3017954059538517278">"USB меморија"</string> <string name="extract_edit_menu_button" msgid="8940478730496610137">"Измени"</string> - <string name="data_usage_warning_title" msgid="1955638862122232342">"Упозорење о потрошњи података"</string> + <!-- no translation found for data_usage_warning_title (3620440638180218181) --> + <skip /> <string name="data_usage_warning_body" msgid="6660692274311972007">"Додирните за потрошњу и подешавања."</string> <string name="data_usage_3g_limit_title" msgid="4361523876818447683">"Нема више 2G-3G података"</string> <string name="data_usage_4g_limit_title" msgid="4609566827219442376">"Нема више 4G података"</string> diff --git a/core/res/res/values-sv/strings.xml b/core/res/res/values-sv/strings.xml index a0b6db357e5b..3f4f8362ccc5 100644 --- a/core/res/res/values-sv/strings.xml +++ b/core/res/res/values-sv/strings.xml @@ -1330,7 +1330,8 @@ <string name="storage_usb_drive_label" msgid="4501418548927759953">"USB-enhet (<xliff:g id="MANUFACTURER">%s</xliff:g>)"</string> <string name="storage_usb" msgid="3017954059538517278">"USB-lagring"</string> <string name="extract_edit_menu_button" msgid="8940478730496610137">"Redigera"</string> - <string name="data_usage_warning_title" msgid="1955638862122232342">"Varning angående dataanvändning"</string> + <!-- no translation found for data_usage_warning_title (3620440638180218181) --> + <skip /> <string name="data_usage_warning_body" msgid="6660692274311972007">"Visa användning och inställning."</string> <string name="data_usage_3g_limit_title" msgid="4361523876818447683">"Datagränsen för 2G-3G har uppnåtts"</string> <string name="data_usage_4g_limit_title" msgid="4609566827219442376">"Datagränsen för 4G har uppnåtts"</string> diff --git a/core/res/res/values-sw/strings.xml b/core/res/res/values-sw/strings.xml index 2f5c4f9df046..9cba3909248b 100644 --- a/core/res/res/values-sw/strings.xml +++ b/core/res/res/values-sw/strings.xml @@ -1328,7 +1328,8 @@ <string name="storage_usb_drive_label" msgid="4501418548927759953">"Hifadhi ya USB iliyotengenezwa na <xliff:g id="MANUFACTURER">%s</xliff:g>"</string> <string name="storage_usb" msgid="3017954059538517278">"Hifadhi ya USB"</string> <string name="extract_edit_menu_button" msgid="8940478730496610137">"Badilisha"</string> - <string name="data_usage_warning_title" msgid="1955638862122232342">"Onyo la matumizi ya data"</string> + <!-- no translation found for data_usage_warning_title (3620440638180218181) --> + <skip /> <string name="data_usage_warning_body" msgid="6660692274311972007">"Gonga ili uangalie matumizi na mipangilio."</string> <string name="data_usage_3g_limit_title" msgid="4361523876818447683">"Kikomo data ya 2G-3G kimefikiwa"</string> <string name="data_usage_4g_limit_title" msgid="4609566827219442376">"Kikomo cha data ya 4G kimefikiwa"</string> diff --git a/core/res/res/values-ta-rIN/strings.xml b/core/res/res/values-ta-rIN/strings.xml index 1cb406237506..e784a7648aef 100644 --- a/core/res/res/values-ta-rIN/strings.xml +++ b/core/res/res/values-ta-rIN/strings.xml @@ -1330,7 +1330,8 @@ <string name="storage_usb_drive_label" msgid="4501418548927759953">"<xliff:g id="MANUFACTURER">%s</xliff:g> USB டிரைவ்"</string> <string name="storage_usb" msgid="3017954059538517278">"USB சேமிப்பிடம்"</string> <string name="extract_edit_menu_button" msgid="8940478730496610137">"திருத்து"</string> - <string name="data_usage_warning_title" msgid="1955638862122232342">"தரவு பயன்பாட்டு எச்சரிக்கை"</string> + <!-- no translation found for data_usage_warning_title (3620440638180218181) --> + <skip /> <string name="data_usage_warning_body" msgid="6660692274311972007">"தரவு உபயோகம், அமைப்புகளைப் பார்க்க, தட்டவும்."</string> <string name="data_usage_3g_limit_title" msgid="4361523876818447683">"2G-3G தரவு வரம்பைக் கடந்தது"</string> <string name="data_usage_4g_limit_title" msgid="4609566827219442376">"4G தரவு வரம்பைக் கடந்தது"</string> diff --git a/core/res/res/values-te-rIN/strings.xml b/core/res/res/values-te-rIN/strings.xml index e9aa6ba621b3..21ed7c6fe84c 100644 --- a/core/res/res/values-te-rIN/strings.xml +++ b/core/res/res/values-te-rIN/strings.xml @@ -1330,7 +1330,8 @@ <string name="storage_usb_drive_label" msgid="4501418548927759953">"<xliff:g id="MANUFACTURER">%s</xliff:g> USB డ్రైవ్"</string> <string name="storage_usb" msgid="3017954059538517278">"USB నిల్వ"</string> <string name="extract_edit_menu_button" msgid="8940478730496610137">"సవరించు"</string> - <string name="data_usage_warning_title" msgid="1955638862122232342">"డేటా వినియోగం హెచ్చరిక"</string> + <!-- no translation found for data_usage_warning_title (3620440638180218181) --> + <skip /> <string name="data_usage_warning_body" msgid="6660692274311972007">"వినియోగం,సెట్టింగ్ల కోసం నొక్కండి"</string> <string name="data_usage_3g_limit_title" msgid="4361523876818447683">"2G-3G డేటా పరిమితిని చేరుకుంది"</string> <string name="data_usage_4g_limit_title" msgid="4609566827219442376">"4G డేటా పరిమితిని చేరుకుంది"</string> diff --git a/core/res/res/values-th/strings.xml b/core/res/res/values-th/strings.xml index f3445cb16c75..df9b18291d4b 100644 --- a/core/res/res/values-th/strings.xml +++ b/core/res/res/values-th/strings.xml @@ -1330,7 +1330,8 @@ <string name="storage_usb_drive_label" msgid="4501418548927759953">"ไดรฟ์ USB ของ <xliff:g id="MANUFACTURER">%s</xliff:g>"</string> <string name="storage_usb" msgid="3017954059538517278">"ที่เก็บข้อมูล USB"</string> <string name="extract_edit_menu_button" msgid="8940478730496610137">"แก้ไข"</string> - <string name="data_usage_warning_title" msgid="1955638862122232342">"คำเตือนการใช้ข้อมูล"</string> + <!-- no translation found for data_usage_warning_title (3620440638180218181) --> + <skip /> <string name="data_usage_warning_body" msgid="6660692274311972007">"แตะเพื่อดูการใช้งานและการตั้งค่า"</string> <string name="data_usage_3g_limit_title" msgid="4361523876818447683">"ถึงขีดจำกัดข้อมูล 2G-3G แล้ว"</string> <string name="data_usage_4g_limit_title" msgid="4609566827219442376">"ถึงขีดจำกัดข้อมูล 4G แล้ว"</string> diff --git a/core/res/res/values-tl/strings.xml b/core/res/res/values-tl/strings.xml index ef1a57dfafe3..fac6eebc22c1 100644 --- a/core/res/res/values-tl/strings.xml +++ b/core/res/res/values-tl/strings.xml @@ -1330,7 +1330,8 @@ <string name="storage_usb_drive_label" msgid="4501418548927759953">"<xliff:g id="MANUFACTURER">%s</xliff:g> USB drive"</string> <string name="storage_usb" msgid="3017954059538517278">"USB storage"</string> <string name="extract_edit_menu_button" msgid="8940478730496610137">"I-edit"</string> - <string name="data_usage_warning_title" msgid="1955638862122232342">"Babala sa paggamit ng data"</string> + <!-- no translation found for data_usage_warning_title (3620440638180218181) --> + <skip /> <string name="data_usage_warning_body" msgid="6660692274311972007">"I-tap tingnan paggamit/setting."</string> <string name="data_usage_3g_limit_title" msgid="4361523876818447683">"Naabot na ang limitasyon sa 2G-3G data"</string> <string name="data_usage_4g_limit_title" msgid="4609566827219442376">"Naabot na ang limitasyon sa 4G data"</string> diff --git a/core/res/res/values-tr/strings.xml b/core/res/res/values-tr/strings.xml index daefd3ddcca3..afd9e68e1567 100644 --- a/core/res/res/values-tr/strings.xml +++ b/core/res/res/values-tr/strings.xml @@ -1330,7 +1330,8 @@ <string name="storage_usb_drive_label" msgid="4501418548927759953">"<xliff:g id="MANUFACTURER">%s</xliff:g> USB sürücüsü"</string> <string name="storage_usb" msgid="3017954059538517278">"USB bellek"</string> <string name="extract_edit_menu_button" msgid="8940478730496610137">"Düzenle"</string> - <string name="data_usage_warning_title" msgid="1955638862122232342">"Veri kullanım uyarısı"</string> + <!-- no translation found for data_usage_warning_title (3620440638180218181) --> + <skip /> <string name="data_usage_warning_body" msgid="6660692274311972007">"Kul. ve ayar. gör. için dokunun."</string> <string name="data_usage_3g_limit_title" msgid="4361523876818447683">"2G-3G veri sınırına ulaşıldı"</string> <string name="data_usage_4g_limit_title" msgid="4609566827219442376">"4G veri sınırına ulaşıldı"</string> diff --git a/core/res/res/values-uk/strings.xml b/core/res/res/values-uk/strings.xml index 42ac19156595..0ce3396f28aa 100644 --- a/core/res/res/values-uk/strings.xml +++ b/core/res/res/values-uk/strings.xml @@ -1382,7 +1382,8 @@ <string name="storage_usb_drive_label" msgid="4501418548927759953">"Носій USB (<xliff:g id="MANUFACTURER">%s</xliff:g>)"</string> <string name="storage_usb" msgid="3017954059538517278">"Носій USB"</string> <string name="extract_edit_menu_button" msgid="8940478730496610137">"Редагувати"</string> - <string name="data_usage_warning_title" msgid="1955638862122232342">"Застереження про використ. даних"</string> + <!-- no translation found for data_usage_warning_title (3620440638180218181) --> + <skip /> <string name="data_usage_warning_body" msgid="6660692274311972007">"Переглянути дані та параметри."</string> <string name="data_usage_3g_limit_title" msgid="4361523876818447683">"Досягнуто ліміту даних 2G–3G"</string> <string name="data_usage_4g_limit_title" msgid="4609566827219442376">"Досягнуто ліміту даних 4G"</string> diff --git a/core/res/res/values-ur-rPK/strings.xml b/core/res/res/values-ur-rPK/strings.xml index e351ec074d3a..ebab740c1761 100644 --- a/core/res/res/values-ur-rPK/strings.xml +++ b/core/res/res/values-ur-rPK/strings.xml @@ -1330,7 +1330,8 @@ <string name="storage_usb_drive_label" msgid="4501418548927759953">"<xliff:g id="MANUFACTURER">%s</xliff:g> USB ڈرائیو"</string> <string name="storage_usb" msgid="3017954059538517278">"USB اسٹوریج"</string> <string name="extract_edit_menu_button" msgid="8940478730496610137">"ترمیم کریں"</string> - <string name="data_usage_warning_title" msgid="1955638862122232342">"ڈیٹا کے استعمال کی وارننگ"</string> + <!-- no translation found for data_usage_warning_title (3620440638180218181) --> + <skip /> <string name="data_usage_warning_body" msgid="6660692274311972007">"استعمال اور ترتیبات دیکھنے کیلئے تھپتھپائیں۔"</string> <string name="data_usage_3g_limit_title" msgid="4361523876818447683">"2G-3G ڈیٹا کی حد کو پہنچ گیا"</string> <string name="data_usage_4g_limit_title" msgid="4609566827219442376">"4G ڈیٹا کی حد کو پہنچ گیا"</string> diff --git a/core/res/res/values-uz-rUZ/strings.xml b/core/res/res/values-uz-rUZ/strings.xml index d75291b2f8fd..f97a7b825395 100644 --- a/core/res/res/values-uz-rUZ/strings.xml +++ b/core/res/res/values-uz-rUZ/strings.xml @@ -1330,7 +1330,8 @@ <string name="storage_usb_drive_label" msgid="4501418548927759953">"<xliff:g id="MANUFACTURER">%s</xliff:g> USB xotira qurilmasi"</string> <string name="storage_usb" msgid="3017954059538517278">"USB xotira"</string> <string name="extract_edit_menu_button" msgid="8940478730496610137">"Tahrirlash"</string> - <string name="data_usage_warning_title" msgid="1955638862122232342">"Trafik kam qoldi"</string> + <!-- no translation found for data_usage_warning_title (3620440638180218181) --> + <skip /> <string name="data_usage_warning_body" msgid="6660692274311972007">"Trafik sarfi va sozlamalarni ko‘rish uchun bosing."</string> <string name="data_usage_3g_limit_title" msgid="4361523876818447683">"2G-3G trafik chekloviga yetdi"</string> <string name="data_usage_4g_limit_title" msgid="4609566827219442376">"4G trafik chekloviga yetdi"</string> diff --git a/core/res/res/values-vi/strings.xml b/core/res/res/values-vi/strings.xml index 058999bffc01..66b87e7295c3 100644 --- a/core/res/res/values-vi/strings.xml +++ b/core/res/res/values-vi/strings.xml @@ -1330,7 +1330,8 @@ <string name="storage_usb_drive_label" msgid="4501418548927759953">"Ổ USB <xliff:g id="MANUFACTURER">%s</xliff:g>"</string> <string name="storage_usb" msgid="3017954059538517278">"Bộ lưu trữ USB"</string> <string name="extract_edit_menu_button" msgid="8940478730496610137">"Chỉnh sửa"</string> - <string name="data_usage_warning_title" msgid="1955638862122232342">"Cảnh báo sử dụng dữ liệu"</string> + <!-- no translation found for data_usage_warning_title (3620440638180218181) --> + <skip /> <string name="data_usage_warning_body" msgid="6660692274311972007">"Nhấn để xem sử dụng và cài đặt."</string> <string name="data_usage_3g_limit_title" msgid="4361523876818447683">"Đã đạt tới giới hạn dữ liệu 2G-3G"</string> <string name="data_usage_4g_limit_title" msgid="4609566827219442376">"Đã đạt tới giới hạn dữ liệu 4G"</string> diff --git a/core/res/res/values-zh-rCN/strings.xml b/core/res/res/values-zh-rCN/strings.xml index 5d7ddcb42f50..1bd10237dbf4 100644 --- a/core/res/res/values-zh-rCN/strings.xml +++ b/core/res/res/values-zh-rCN/strings.xml @@ -1330,7 +1330,8 @@ <string name="storage_usb_drive_label" msgid="4501418548927759953">"<xliff:g id="MANUFACTURER">%s</xliff:g> U 盘"</string> <string name="storage_usb" msgid="3017954059538517278">"USB存储器"</string> <string name="extract_edit_menu_button" msgid="8940478730496610137">"修改"</string> - <string name="data_usage_warning_title" msgid="1955638862122232342">"流量警告"</string> + <!-- no translation found for data_usage_warning_title (3620440638180218181) --> + <skip /> <string name="data_usage_warning_body" msgid="6660692274311972007">"点按即可查看使用情况和设置。"</string> <string name="data_usage_3g_limit_title" msgid="4361523876818447683">"已达到2G-3G流量上限"</string> <string name="data_usage_4g_limit_title" msgid="4609566827219442376">"已达到4G流量上限"</string> diff --git a/core/res/res/values-zh-rHK/strings.xml b/core/res/res/values-zh-rHK/strings.xml index 25a0276d5fc0..4329c8fcca2a 100644 --- a/core/res/res/values-zh-rHK/strings.xml +++ b/core/res/res/values-zh-rHK/strings.xml @@ -1330,7 +1330,8 @@ <string name="storage_usb_drive_label" msgid="4501418548927759953">"<xliff:g id="MANUFACTURER">%s</xliff:g> USB 驅動器"</string> <string name="storage_usb" msgid="3017954059538517278">"USB 儲存裝置"</string> <string name="extract_edit_menu_button" msgid="8940478730496610137">"編輯"</string> - <string name="data_usage_warning_title" msgid="1955638862122232342">"資料用量警告"</string> + <!-- no translation found for data_usage_warning_title (3620440638180218181) --> + <skip /> <string name="data_usage_warning_body" msgid="6660692274311972007">"輕按即可查看用量和設定。"</string> <string name="data_usage_3g_limit_title" msgid="4361523876818447683">"已達到 2G-3G 數據流量上限"</string> <string name="data_usage_4g_limit_title" msgid="4609566827219442376">"已達到 4G 數據流量上限"</string> diff --git a/core/res/res/values-zh-rTW/strings.xml b/core/res/res/values-zh-rTW/strings.xml index 3b1296ca023c..ec7a9a0807d1 100644 --- a/core/res/res/values-zh-rTW/strings.xml +++ b/core/res/res/values-zh-rTW/strings.xml @@ -1330,7 +1330,8 @@ <string name="storage_usb_drive_label" msgid="4501418548927759953">"<xliff:g id="MANUFACTURER">%s</xliff:g> USB 隨身碟"</string> <string name="storage_usb" msgid="3017954059538517278">"USB 儲存裝置"</string> <string name="extract_edit_menu_button" msgid="8940478730496610137">"編輯"</string> - <string name="data_usage_warning_title" msgid="1955638862122232342">"數據用量警告"</string> + <!-- no translation found for data_usage_warning_title (3620440638180218181) --> + <skip /> <string name="data_usage_warning_body" msgid="6660692274311972007">"輕觸即可查看用量和設定。"</string> <string name="data_usage_3g_limit_title" msgid="4361523876818447683">"已達到 2G-3G 數據流量上限"</string> <string name="data_usage_4g_limit_title" msgid="4609566827219442376">"已達到 4G 數據流量上限"</string> diff --git a/core/res/res/values-zu/strings.xml b/core/res/res/values-zu/strings.xml index b50e76ce80ed..3a1964838c51 100644 --- a/core/res/res/values-zu/strings.xml +++ b/core/res/res/values-zu/strings.xml @@ -1330,7 +1330,8 @@ <string name="storage_usb_drive_label" msgid="4501418548927759953">"<xliff:g id="MANUFACTURER">%s</xliff:g> idrayivu ye-USB"</string> <string name="storage_usb" msgid="3017954059538517278">"Isitoreji se-USB"</string> <string name="extract_edit_menu_button" msgid="8940478730496610137">"Hlela"</string> - <string name="data_usage_warning_title" msgid="1955638862122232342">"Isexwayiso sokusetshenziswa kwedatha"</string> + <!-- no translation found for data_usage_warning_title (3620440638180218181) --> + <skip /> <string name="data_usage_warning_body" msgid="6660692274311972007">"Thepha ukuze ubuke ukusetshenziswa nezilungiselelo."</string> <string name="data_usage_3g_limit_title" msgid="4361523876818447683">"2G-3G umkhawulo wedatha ufinyelelwe"</string> <string name="data_usage_4g_limit_title" msgid="4609566827219442376">"4G umkhawulo wedatha ufinyelelwe"</string> diff --git a/core/tests/coretests/src/android/print/BasePrintTest.java b/core/tests/coretests/src/android/print/BasePrintTest.java index 2c2ee8c2e52f..ca7b5e19fcd3 100644 --- a/core/tests/coretests/src/android/print/BasePrintTest.java +++ b/core/tests/coretests/src/android/print/BasePrintTest.java @@ -16,6 +16,9 @@ package android.print; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; +import static org.junit.Assume.assumeTrue; import static org.mockito.Matchers.any; import static org.mockito.Mockito.doAnswer; import static org.mockito.Mockito.doCallRealMethod; @@ -26,173 +29,102 @@ import android.annotation.NonNull; import android.app.Instrumentation; import android.content.Context; import android.content.pm.PackageManager; -import android.content.res.Configuration; -import android.content.res.Resources; import android.os.CancellationSignal; -import android.os.LocaleList; import android.os.ParcelFileDescriptor; import android.os.SystemClock; -import android.print.PrintAttributes; -import android.print.PrintDocumentAdapter; -import android.print.PrintManager; -import android.print.PrinterId; import android.print.mockservice.PrintServiceCallbacks; import android.print.mockservice.PrinterDiscoverySessionCallbacks; import android.print.mockservice.StubbablePrinterDiscoverySession; import android.printservice.CustomPrinterIconCallback; import android.printservice.PrintJob; import android.printservice.PrintService; -import android.test.InstrumentationTestCase; -import android.util.DisplayMetrics; - +import android.support.test.InstrumentationRegistry; +import android.support.test.uiautomator.UiDevice; +import android.support.test.rule.ActivityTestRule; + +import org.junit.After; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Rule; import org.mockito.stubbing.Answer; -import java.io.BufferedReader; import java.io.FileInputStream; import java.io.IOException; -import java.io.InputStreamReader; -import java.util.ArrayList; import java.util.List; -import java.util.Locale; import java.util.concurrent.TimeoutException; /** * This is the base class for print tests. */ -public abstract class BasePrintTest extends InstrumentationTestCase { +abstract class BasePrintTest { private static final long OPERATION_TIMEOUT = 30000; private static final String PM_CLEAR_SUCCESS_OUTPUT = "Success"; - private static final String COMMAND_LIST_ENABLED_IME_COMPONENTS = "ime list -s"; - private static final String COMMAND_PREFIX_ENABLE_IME = "ime enable "; - private static final String COMMAND_PREFIX_DISABLE_IME = "ime disable "; private static final int CURRENT_USER_ID = -2; // Mirrors UserHandle.USER_CURRENT - private PrintTestActivity mActivity; private android.print.PrintJob mPrintJob; - private LocaleList mOldLocale; - private CallCounter mStartCallCounter; private CallCounter mStartSessionCallCounter; - private String[] mEnabledImes; - - private String[] getEnabledImes() throws IOException { - List<String> imeList = new ArrayList<>(); - - ParcelFileDescriptor pfd = getInstrumentation().getUiAutomation() - .executeShellCommand(COMMAND_LIST_ENABLED_IME_COMPONENTS); - try (BufferedReader reader = new BufferedReader( - new InputStreamReader(new FileInputStream(pfd.getFileDescriptor())))) { - - String line; - while ((line = reader.readLine()) != null) { - imeList.add(line); - } - } - - String[] imeArray = new String[imeList.size()]; - imeList.toArray(imeArray); + private static Instrumentation sInstrumentation; + private static UiDevice sUiDevice; - return imeArray; - } + @Rule + public ActivityTestRule<PrintTestActivity> mActivityRule = + new ActivityTestRule<>(PrintTestActivity.class, false, true); - private void disableImes() throws Exception { - mEnabledImes = getEnabledImes(); - for (String ime : mEnabledImes) { - String disableImeCommand = COMMAND_PREFIX_DISABLE_IME + ime; - runShellCommand(getInstrumentation(), disableImeCommand); - } + /** + * Return the UI device + * + * @return the UI device + */ + public UiDevice getUiDevice() { + return sUiDevice; } - private void enableImes() throws Exception { - for (String ime : mEnabledImes) { - String enableImeCommand = COMMAND_PREFIX_ENABLE_IME + ime; - runShellCommand(getInstrumentation(), enableImeCommand); - } - mEnabledImes = null; + protected static Instrumentation getInstrumentation() { + return sInstrumentation; } - @Override - protected void runTest() throws Throwable { - // Do nothing if the device does not support printing. - if (supportsPrinting()) { - super.runTest(); - } - } + @BeforeClass + public static void setUpClass() throws Exception { + sInstrumentation = InstrumentationRegistry.getInstrumentation(); + assumeTrue(sInstrumentation.getContext().getPackageManager().hasSystemFeature( + PackageManager.FEATURE_PRINTING)); - @Override - public void setUp() throws Exception { - super.setUp(); - if (!supportsPrinting()) { - return; - } + sUiDevice = UiDevice.getInstance(sInstrumentation); // Make sure we start with a clean slate. clearPrintSpoolerData(); - disableImes(); // Workaround for dexmaker bug: https://code.google.com/p/dexmaker/issues/detail?id=2 // Dexmaker is used by mockito. System.setProperty("dexmaker.dexcache", getInstrumentation() .getTargetContext().getCacheDir().getPath()); + } - // Set to US locale. - Resources resources = getInstrumentation().getTargetContext().getResources(); - Configuration oldConfiguration = resources.getConfiguration(); - if (!oldConfiguration.getLocales().get(0).equals(Locale.US)) { - mOldLocale = oldConfiguration.getLocales(); - DisplayMetrics displayMetrics = resources.getDisplayMetrics(); - Configuration newConfiguration = new Configuration(oldConfiguration); - newConfiguration.setLocale(Locale.US); - resources.updateConfiguration(newConfiguration, displayMetrics); - } - + @Before + public void setUp() throws Exception { // Initialize the latches. mStartCallCounter = new CallCounter(); mStartSessionCallCounter = new CallCounter(); - - // Create the activity for the right locale. - createActivity(); } - @Override + @After public void tearDown() throws Exception { - if (!supportsPrinting()) { - return; - } - - // Done with the activity. - getActivity().finish(); - enableImes(); - - // Restore the locale if needed. - if (mOldLocale != null) { - Resources resources = getInstrumentation().getTargetContext().getResources(); - DisplayMetrics displayMetrics = resources.getDisplayMetrics(); - Configuration newConfiguration = new Configuration(resources.getConfiguration()); - newConfiguration.setLocales(mOldLocale); - mOldLocale = null; - resources.updateConfiguration(newConfiguration, displayMetrics); - } - - // Make sure the spooler is cleaned, this also un-approves all services - clearPrintSpoolerData(); - - super.tearDown(); + // Exit print spooler + getUiDevice().pressBack(); + getUiDevice().pressBack(); } protected android.print.PrintJob print(@NonNull final PrintDocumentAdapter adapter, final PrintAttributes attributes) { // Initiate printing as if coming from the app. - getInstrumentation().runOnMainSync(new Runnable() { - @Override - public void run() { - PrintManager printManager = (PrintManager) getActivity() - .getSystemService(Context.PRINT_SERVICE); - mPrintJob = printManager.print("Print job", adapter, attributes); - } + getInstrumentation().runOnMainSync(() -> { + PrintManager printManager = (PrintManager) getActivity() + .getSystemService(Context.PRINT_SERVICE); + mPrintJob = printManager.print("Print job", adapter, attributes); }); return mPrintJob; @@ -215,7 +147,7 @@ public abstract class BasePrintTest extends InstrumentationTestCase { waitForCallbackCallCount(mStartCallCounter, 1, "Did not get expected call to start."); } - private void waitForCallbackCallCount(CallCounter counter, int count, String message) { + private static void waitForCallbackCallCount(CallCounter counter, int count, String message) { try { counter.waitForCount(count, OPERATION_TIMEOUT); } catch (TimeoutException te) { @@ -224,12 +156,7 @@ public abstract class BasePrintTest extends InstrumentationTestCase { } protected PrintTestActivity getActivity() { - return mActivity; - } - - protected void createActivity() { - mActivity = launchActivity(getInstrumentation().getTargetContext().getPackageName(), - PrintTestActivity.class, null); + return mActivityRule.getActivity(); } public static String runShellCommand(Instrumentation instrumentation, String cmd) @@ -238,7 +165,7 @@ public abstract class BasePrintTest extends InstrumentationTestCase { byte[] buf = new byte[512]; int bytesRead; FileInputStream fis = new ParcelFileDescriptor.AutoCloseInputStream(pfd); - StringBuffer stdout = new StringBuffer(); + StringBuilder stdout = new StringBuilder(); while ((bytesRead = fis.read(buf)) != -1) { stdout.append(new String(buf, 0, bytesRead)); } @@ -246,7 +173,7 @@ public abstract class BasePrintTest extends InstrumentationTestCase { return stdout.toString(); } - protected void clearPrintSpoolerData() throws Exception { + protected static void clearPrintSpoolerData() throws Exception { assertTrue("failed to clear print spooler data", runShellCommand(getInstrumentation(), String.format( "pm clear --user %d %s", CURRENT_USER_ID, @@ -319,7 +246,7 @@ public abstract class BasePrintTest extends InstrumentationTestCase { return service; } - protected final class CallCounter { + private static final class CallCounter { private final Object mLock = new Object(); private int mCallCount; @@ -331,7 +258,7 @@ public abstract class BasePrintTest extends InstrumentationTestCase { } } - public int getCallCount() { + int getCallCount() { synchronized (mLock) { return mCallCount; } @@ -355,9 +282,4 @@ public abstract class BasePrintTest extends InstrumentationTestCase { } } } - - protected boolean supportsPrinting() { - return getInstrumentation().getContext().getPackageManager() - .hasSystemFeature(PackageManager.FEATURE_PRINTING); - } } diff --git a/core/tests/coretests/src/android/print/IPrintManagerParametersTest.java b/core/tests/coretests/src/android/print/IPrintManagerParametersTest.java index d491ec4111fb..75be426e94e1 100644 --- a/core/tests/coretests/src/android/print/IPrintManagerParametersTest.java +++ b/core/tests/coretests/src/android/print/IPrintManagerParametersTest.java @@ -38,17 +38,22 @@ import android.print.mockservice.PrintServiceCallbacks; import android.print.mockservice.PrinterDiscoverySessionCallbacks; import android.print.mockservice.StubbablePrinterDiscoverySession; -import android.test.suitebuilder.annotation.LargeTest; -import android.test.suitebuilder.annotation.MediumTest; -import org.mockito.invocation.InvocationOnMock; -import org.mockito.stubbing.Answer; +import android.support.test.filters.LargeTest; +import android.support.test.filters.MediumTest; +import android.support.test.runner.AndroidJUnit4; +import org.junit.Test; +import org.junit.runner.RunWith; import java.util.ArrayList; import java.util.List; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + /** * tests feeding all possible parameters to the IPrintManager Binder. */ +@RunWith(AndroidJUnit4.class) public class IPrintManagerParametersTest extends BasePrintTest { private final int BAD_APP_ID = 0xffffffff; @@ -58,9 +63,7 @@ public class IPrintManagerParametersTest extends BasePrintTest { private final PrintJobId mBadPrintJobId; private PrintJob mGoodPrintJob; - private PrinterId mBadPrinterId; private PrinterId mGoodPrinterId; - private ComponentName mGoodComponentName; private ComponentName mBadComponentName; private IPrintManager mIPrintManager; @@ -93,6 +96,7 @@ public class IPrintManagerParametersTest extends BasePrintTest { public void onLayout(PrintAttributes oldAttributes, PrintAttributes newAttributes, CancellationSignal cancellationSignal, LayoutResultCallback callback, Bundle extras) { + callback.onLayoutFailed("not implemented"); } @Override @@ -109,54 +113,46 @@ public class IPrintManagerParametersTest extends BasePrintTest { */ private PrintServiceCallbacks createMockCallbacks() { return createMockPrintServiceCallbacks( - new Answer<PrinterDiscoverySessionCallbacks>() { - @Override - public PrinterDiscoverySessionCallbacks answer(InvocationOnMock invocation) { - return createMockPrinterDiscoverySessionCallbacks(new Answer<Void>() { - @Override - public Void answer(InvocationOnMock invocation) { - // Get the session. - StubbablePrinterDiscoverySession session = - ((PrinterDiscoverySessionCallbacks) invocation - .getMock()).getSession(); - - if (session.getPrinters().isEmpty()) { - final String PRINTER_NAME = "good printer"; - List<PrinterInfo> printers = new ArrayList<>(); - - // Add the printer. - mGoodPrinterId = session.getService() - .generatePrinterId(PRINTER_NAME); - - PrinterCapabilitiesInfo capabilities = - new PrinterCapabilitiesInfo.Builder(mGoodPrinterId) - .setMinMargins( - new Margins(200, 200, 200, 200)) - .addMediaSize(MediaSize.ISO_A4, true) - .addResolution(new Resolution("300x300", - "300x300", 300, 300), - true) - .setColorModes( - PrintAttributes.COLOR_MODE_COLOR, - PrintAttributes.COLOR_MODE_COLOR) - .build(); - - PrinterInfo printer = new PrinterInfo.Builder( - mGoodPrinterId, - PRINTER_NAME, - PrinterInfo.STATUS_IDLE) - .setCapabilities(capabilities) - .build(); - printers.add(printer); - - session.addPrinters(printers); - } - onPrinterDiscoverySessionStartCalled(); - return null; - } - }, null, null, null, null, null, null); + invocation -> createMockPrinterDiscoverySessionCallbacks(invocation1 -> { + // Get the session. + StubbablePrinterDiscoverySession session = + ((PrinterDiscoverySessionCallbacks) invocation1 + .getMock()).getSession(); + + if (session.getPrinters().isEmpty()) { + final String PRINTER_NAME = "good printer"; + List<PrinterInfo> printers = new ArrayList<>(); + + // Add the printer. + mGoodPrinterId = session.getService() + .generatePrinterId(PRINTER_NAME); + + PrinterCapabilitiesInfo capabilities = + new PrinterCapabilitiesInfo.Builder(mGoodPrinterId) + .setMinMargins( + new Margins(200, 200, 200, 200)) + .addMediaSize(MediaSize.ISO_A4, true) + .addResolution(new Resolution("300x300", + "300x300", 300, 300), + true) + .setColorModes( + PrintAttributes.COLOR_MODE_COLOR, + PrintAttributes.COLOR_MODE_COLOR) + .build(); + + PrinterInfo printer = new PrinterInfo.Builder( + mGoodPrinterId, + PRINTER_NAME, + PrinterInfo.STATUS_IDLE) + .setCapabilities(capabilities) + .build(); + printers.add(printer); + + session.addPrinters(printers); } - }, + onPrinterDiscoverySessionStartCalled(); + return null; + }, null, null, null, null, null, null), null, null); } @@ -214,20 +210,23 @@ public class IPrintManagerParametersTest extends BasePrintTest { waitForPrinterDiscoverySessionStartCallbackCalled(); } + /** + * Return a printer Id that is not from any print service + * + * @return The bad printer id. + */ + private PrinterId getBadPrinterId() { + return new PrinterId(getActivity().getComponentName(), "dummy printer"); + } + @Override public void setUp() throws Exception { super.setUp(); MockPrintService.setCallbacks(createMockCallbacks()); - mGoodComponentName = getActivity().getComponentName(); - mIPrintManager = IPrintManager.Stub .asInterface(ServiceManager.getService(Context.PRINT_SERVICE)); - - // Generate dummy printerId which is a valid PrinterId object, but does not correspond to a - // printer - mBadPrinterId = new PrinterId(mGoodComponentName, "dummy printer"); } /** @@ -268,6 +267,7 @@ public class IPrintManagerParametersTest extends BasePrintTest { * test IPrintManager.getPrintJobInfo */ @LargeTest + @Test public void testGetPrintJobInfo() throws Exception { startPrinting(); @@ -276,12 +276,9 @@ public class IPrintManagerParametersTest extends BasePrintTest { assertEquals(null, mIPrintManager.getPrintJobInfo(mBadPrintJobId, mAppId, mUserId)); assertEquals(null, mIPrintManager.getPrintJobInfo(null, mAppId, mUserId)); - assertException(new Invokable() { - @Override - public void run() throws Exception { - mIPrintManager.getPrintJobInfo(mGoodPrintJob.getId(), BAD_APP_ID, mUserId); - } - }, SecurityException.class); + assertException( + () -> mIPrintManager.getPrintJobInfo(mGoodPrintJob.getId(), BAD_APP_ID, mUserId), + SecurityException.class); // Cannot test bad user Id as these tests are allowed to call across users } @@ -290,6 +287,7 @@ public class IPrintManagerParametersTest extends BasePrintTest { * test IPrintManager.getPrintJobInfos */ @LargeTest + @Test public void testGetPrintJobInfos() throws Exception { startPrinting(); @@ -304,12 +302,8 @@ public class IPrintManagerParametersTest extends BasePrintTest { } assertTrue(foundPrintJob); - assertException(new Invokable() { - @Override - public void run() throws Exception { - mIPrintManager.getPrintJobInfos(BAD_APP_ID, mUserId); - } - }, SecurityException.class); + assertException(() -> mIPrintManager.getPrintJobInfos(BAD_APP_ID, mUserId), + SecurityException.class); // Cannot test bad user Id as these tests are allowed to call across users } @@ -318,6 +312,7 @@ public class IPrintManagerParametersTest extends BasePrintTest { * test IPrintManager.print */ @LargeTest + @Test public void testPrint() throws Exception { final String name = "dummy print job"; @@ -326,44 +321,23 @@ public class IPrintManagerParametersTest extends BasePrintTest { startPrinting(); - assertException(new Invokable() { - @Override - public void run() throws Exception { - mIPrintManager.print(null, adapter, null, mGoodComponentName.getPackageName(), - mAppId, mUserId); - } - }, IllegalArgumentException.class); + assertException(() -> mIPrintManager.print(null, adapter, null, + getActivity().getPackageName(), mAppId, mUserId), + IllegalArgumentException.class); - assertException(new Invokable() { - @Override - public void run() throws Exception { - mIPrintManager.print(name, null, null, mGoodComponentName.getPackageName(), - mAppId, mUserId); - } - }, NullPointerException.class); + assertException(() -> mIPrintManager.print(name, null, null, + getActivity().getPackageName(), mAppId, mUserId), + NullPointerException.class); - assertException(new Invokable() { - @Override - public void run() throws Exception { - mIPrintManager.print(name, adapter, null, null, mAppId, mUserId); - } - }, IllegalArgumentException.class); + assertException(() -> mIPrintManager.print(name, adapter, null, null, mAppId, mUserId), + IllegalArgumentException.class); - assertException(new Invokable() { - @Override - public void run() throws Exception { - mIPrintManager.print(name, adapter, null, mBadComponentName.getPackageName(), - mAppId, mUserId); - } - }, IllegalArgumentException.class); + assertException(() -> mIPrintManager.print(name, adapter, null, + mBadComponentName.getPackageName(), mAppId, mUserId), + IllegalArgumentException.class); - assertException(new Invokable() { - @Override - public void run() throws Exception { - mIPrintManager.print(name, adapter, null, mGoodComponentName.getPackageName(), - BAD_APP_ID, mUserId); - } - }, SecurityException.class); + assertException(() -> mIPrintManager.print(name, adapter, null, + getActivity().getPackageName(), BAD_APP_ID, mUserId), SecurityException.class); // Cannot test bad user Id as these tests are allowed to call across users } @@ -372,6 +346,7 @@ public class IPrintManagerParametersTest extends BasePrintTest { * test IPrintManager.cancelPrintJob */ @LargeTest + @Test public void testCancelPrintJob() throws Exception { startPrinting(); @@ -379,12 +354,9 @@ public class IPrintManagerParametersTest extends BasePrintTest { mIPrintManager.cancelPrintJob(mBadPrintJobId, mAppId, mUserId); mIPrintManager.cancelPrintJob(null, mAppId, mUserId); - assertException(new Invokable() { - @Override - public void run() throws Exception { - mIPrintManager.cancelPrintJob(mGoodPrintJob.getId(), BAD_APP_ID, mUserId); - } - }, SecurityException.class); + assertException( + () -> mIPrintManager.cancelPrintJob(mGoodPrintJob.getId(), BAD_APP_ID, mUserId), + SecurityException.class); // Cannot test bad user Id as these tests are allowed to call across users @@ -396,6 +368,7 @@ public class IPrintManagerParametersTest extends BasePrintTest { * test IPrintManager.restartPrintJob */ @LargeTest + @Test public void testRestartPrintJob() throws Exception { startPrinting(); @@ -405,12 +378,9 @@ public class IPrintManagerParametersTest extends BasePrintTest { mIPrintManager.restartPrintJob(mBadPrintJobId, mAppId, mUserId); mIPrintManager.restartPrintJob(null, mAppId, mUserId); - assertException(new Invokable() { - @Override - public void run() throws Exception { - mIPrintManager.restartPrintJob(mGoodPrintJob.getId(), BAD_APP_ID, mUserId); - } - }, SecurityException.class); + assertException( + () -> mIPrintManager.restartPrintJob(mGoodPrintJob.getId(), BAD_APP_ID, mUserId), + SecurityException.class); // Cannot test bad user Id as these tests are allowed to call across users } @@ -419,24 +389,18 @@ public class IPrintManagerParametersTest extends BasePrintTest { * test IPrintManager.addPrintJobStateChangeListener */ @MediumTest + @Test public void testAddPrintJobStateChangeListener() throws Exception { final IPrintJobStateChangeListener listener = createMockIPrintJobStateChangeListener(); mIPrintManager.addPrintJobStateChangeListener(listener, mAppId, mUserId); - assertException(new Invokable() { - @Override - public void run() throws Exception { - mIPrintManager.addPrintJobStateChangeListener(null, mAppId, mUserId); - } - }, NullPointerException.class); + assertException(() -> mIPrintManager.addPrintJobStateChangeListener(null, mAppId, mUserId), + NullPointerException.class); - assertException(new Invokable() { - @Override - public void run() throws Exception { - mIPrintManager.addPrintJobStateChangeListener(listener, BAD_APP_ID, mUserId); - } - }, SecurityException.class); + assertException( + () -> mIPrintManager.addPrintJobStateChangeListener(listener, BAD_APP_ID, mUserId), + SecurityException.class); // Cannot test bad user Id as these tests are allowed to call across users } @@ -445,6 +409,7 @@ public class IPrintManagerParametersTest extends BasePrintTest { * test IPrintManager.removePrintJobStateChangeListener */ @MediumTest + @Test public void testRemovePrintJobStateChangeListener() throws Exception { final IPrintJobStateChangeListener listener = createMockIPrintJobStateChangeListener(); @@ -455,12 +420,8 @@ public class IPrintManagerParametersTest extends BasePrintTest { mIPrintManager.removePrintJobStateChangeListener(listener, mUserId); mIPrintManager.addPrintJobStateChangeListener(listener, mAppId, mUserId); - assertException(new Invokable() { - @Override - public void run() throws Exception { - mIPrintManager.removePrintJobStateChangeListener(null, mUserId); - } - }, NullPointerException.class); + assertException(() -> mIPrintManager.removePrintJobStateChangeListener(null, mUserId), + NullPointerException.class); // Cannot test bad user Id as these tests are allowed to call across users } @@ -469,17 +430,14 @@ public class IPrintManagerParametersTest extends BasePrintTest { * test IPrintManager.addPrintServicesChangeListener */ @MediumTest + @Test public void testAddPrintServicesChangeListener() throws Exception { final IPrintServicesChangeListener listener = createMockIPrintServicesChangeListener(); mIPrintManager.addPrintServicesChangeListener(listener, mUserId); - assertException(new Invokable() { - @Override - public void run() throws Exception { - mIPrintManager.addPrintServicesChangeListener(null, mUserId); - } - }, NullPointerException.class); + assertException(() -> mIPrintManager.addPrintServicesChangeListener(null, mUserId), + NullPointerException.class); // Cannot test bad user Id as these tests are allowed to call across users } @@ -488,6 +446,7 @@ public class IPrintManagerParametersTest extends BasePrintTest { * test IPrintManager.removePrintServicesChangeListener */ @MediumTest + @Test public void testRemovePrintServicesChangeListener() throws Exception { final IPrintServicesChangeListener listener = createMockIPrintServicesChangeListener(); @@ -498,12 +457,8 @@ public class IPrintManagerParametersTest extends BasePrintTest { mIPrintManager.removePrintServicesChangeListener(listener, mUserId); mIPrintManager.addPrintServicesChangeListener(listener, mUserId); - assertException(new Invokable() { - @Override - public void run() throws Exception { - mIPrintManager.removePrintServicesChangeListener(null, mUserId); - } - }, NullPointerException.class); + assertException(() -> mIPrintManager.removePrintServicesChangeListener(null, mUserId), + NullPointerException.class); // Cannot test bad user Id as these tests are allowed to call across users } @@ -512,6 +467,7 @@ public class IPrintManagerParametersTest extends BasePrintTest { * test IPrintManager.getPrintServices */ @MediumTest + @Test public void testGetPrintServices() throws Exception { List<PrintServiceInfo> printServices = mIPrintManager.getPrintServices( PrintManager.ALL_SERVICES, mUserId); @@ -520,12 +476,8 @@ public class IPrintManagerParametersTest extends BasePrintTest { printServices = mIPrintManager.getPrintServices(0, mUserId); assertEquals(printServices, null); - assertException(new Invokable() { - @Override - public void run() throws Exception { - mIPrintManager.getPrintServices(~PrintManager.ALL_SERVICES, mUserId); - } - }, IllegalArgumentException.class); + assertException(() -> mIPrintManager.getPrintServices(~PrintManager.ALL_SERVICES, mUserId), + IllegalArgumentException.class); // Cannot test bad user Id as these tests are allowed to call across users } @@ -534,38 +486,23 @@ public class IPrintManagerParametersTest extends BasePrintTest { * test IPrintManager.setPrintServiceEnabled */ @MediumTest + @Test public void testSetPrintServiceEnabled() throws Exception { final ComponentName printService = mIPrintManager.getPrintServices( PrintManager.ALL_SERVICES, mUserId).get(0).getComponentName(); - assertException(new Invokable() { - @Override - public void run() throws Exception { - mIPrintManager.setPrintServiceEnabled(printService, false, mUserId); - } - }, SecurityException.class); + assertException(() -> mIPrintManager.setPrintServiceEnabled(printService, false, mUserId), + SecurityException.class); - assertException(new Invokable() { - @Override - public void run() throws Exception { - mIPrintManager.setPrintServiceEnabled(printService, true, mUserId); - } - }, SecurityException.class); + assertException(() -> mIPrintManager.setPrintServiceEnabled(printService, true, mUserId), + SecurityException.class); - assertException(new Invokable() { - @Override - public void run() throws Exception { - mIPrintManager.setPrintServiceEnabled(new ComponentName("bad", "name"), true, - mUserId); - } - }, SecurityException.class); + assertException( + () -> mIPrintManager.setPrintServiceEnabled(new ComponentName("bad", "name"), true, + mUserId), SecurityException.class); - assertException(new Invokable() { - @Override - public void run() throws Exception { - mIPrintManager.setPrintServiceEnabled(null, true, mUserId); - } - }, SecurityException.class); + assertException(() -> mIPrintManager.setPrintServiceEnabled(null, true, mUserId), + SecurityException.class); // Cannot test bad user Id as these tests are allowed to call across users } @@ -574,18 +511,16 @@ public class IPrintManagerParametersTest extends BasePrintTest { * test IPrintManager.addPrintServiceRecommendationsChangeListener */ @MediumTest + @Test public void testAddPrintServiceRecommendationsChangeListener() throws Exception { final IRecommendationsChangeListener listener = createMockIPrintServiceRecommendationsChangeListener(); mIPrintManager.addPrintServiceRecommendationsChangeListener(listener, mUserId); - assertException(new Invokable() { - @Override - public void run() throws Exception { - mIPrintManager.addPrintServiceRecommendationsChangeListener(null, mUserId); - } - }, NullPointerException.class); + assertException( + () -> mIPrintManager.addPrintServiceRecommendationsChangeListener(null, mUserId), + NullPointerException.class); // Cannot test bad user Id as these tests are allowed to call across users } @@ -594,6 +529,7 @@ public class IPrintManagerParametersTest extends BasePrintTest { * test IPrintManager.removePrintServicesChangeListener */ @MediumTest + @Test public void testRemovePrintServiceRecommendationsChangeListener() throws Exception { final IRecommendationsChangeListener listener = createMockIPrintServiceRecommendationsChangeListener(); @@ -605,12 +541,9 @@ public class IPrintManagerParametersTest extends BasePrintTest { mIPrintManager.removePrintServiceRecommendationsChangeListener(listener, mUserId); mIPrintManager.addPrintServiceRecommendationsChangeListener(listener, mUserId); - assertException(new Invokable() { - @Override - public void run() throws Exception { - mIPrintManager.removePrintServiceRecommendationsChangeListener(null, mUserId); - } - }, NullPointerException.class); + assertException( + () -> mIPrintManager.removePrintServiceRecommendationsChangeListener(null, mUserId), + NullPointerException.class); // Cannot test bad user Id as these tests are allowed to call across users } @@ -619,6 +552,7 @@ public class IPrintManagerParametersTest extends BasePrintTest { * test IPrintManager.getPrintServiceRecommendations */ @MediumTest + @Test public void testGetPrintServiceRecommendations() throws Exception { mIPrintManager.getPrintServiceRecommendations(mUserId); @@ -629,18 +563,15 @@ public class IPrintManagerParametersTest extends BasePrintTest { * test IPrintManager.createPrinterDiscoverySession */ @MediumTest + @Test public void testCreatePrinterDiscoverySession() throws Exception { final IPrinterDiscoveryObserver listener = createMockIPrinterDiscoveryObserver(); mIPrintManager.createPrinterDiscoverySession(listener, mUserId); try { - assertException(new Invokable() { - @Override - public void run() throws Exception { - mIPrintManager.createPrinterDiscoverySession(null, mUserId); - } - }, NullPointerException.class); + assertException(() -> mIPrintManager.createPrinterDiscoverySession(null, mUserId), + NullPointerException.class); // Cannot test bad user Id as these tests are allowed to call across users } finally { @@ -655,6 +586,7 @@ public class IPrintManagerParametersTest extends BasePrintTest { * test IPrintManager.startPrinterDiscovery */ @LargeTest + @Test public void testStartPrinterDiscovery() throws Exception { startPrinting(); @@ -663,7 +595,7 @@ public class IPrintManagerParametersTest extends BasePrintTest { goodPrinters.add(mGoodPrinterId); final List<PrinterId> badPrinters = new ArrayList<>(); - badPrinters.add(mBadPrinterId); + badPrinters.add(getBadPrinterId()); final List<PrinterId> emptyPrinters = new ArrayList<>(); @@ -677,19 +609,11 @@ public class IPrintManagerParametersTest extends BasePrintTest { mIPrintManager.startPrinterDiscovery(listener, emptyPrinters, mUserId); mIPrintManager.startPrinterDiscovery(listener, null, mUserId); - assertException(new Invokable() { - @Override - public void run() throws Exception { - mIPrintManager.startPrinterDiscovery(listener, nullPrinters, mUserId); - } - }, NullPointerException.class); + assertException(() -> mIPrintManager.startPrinterDiscovery(listener, nullPrinters, mUserId), + NullPointerException.class); - assertException(new Invokable() { - @Override - public void run() throws Exception { - mIPrintManager.startPrinterDiscovery(null, goodPrinters, mUserId); - } - }, NullPointerException.class); + assertException(() -> mIPrintManager.startPrinterDiscovery(null, goodPrinters, mUserId), + NullPointerException.class); // Cannot test bad user Id as these tests are allowed to call across users } @@ -698,6 +622,7 @@ public class IPrintManagerParametersTest extends BasePrintTest { * test IPrintManager.stopPrinterDiscovery */ @MediumTest + @Test public void testStopPrinterDiscovery() throws Exception { final IPrinterDiscoveryObserver listener = createMockIPrinterDiscoveryObserver(); @@ -708,12 +633,8 @@ public class IPrintManagerParametersTest extends BasePrintTest { mIPrintManager.stopPrinterDiscovery(listener, mUserId); mIPrintManager.startPrinterDiscovery(listener, null, mUserId); - assertException(new Invokable() { - @Override - public void run() throws Exception { - mIPrintManager.stopPrinterDiscovery(null, mUserId); - } - }, NullPointerException.class); + assertException(() -> mIPrintManager.stopPrinterDiscovery(null, mUserId), + NullPointerException.class); // Cannot test bad user Id as these tests are allowed to call across users } @@ -722,6 +643,7 @@ public class IPrintManagerParametersTest extends BasePrintTest { * test IPrintManager.validatePrinters */ @LargeTest + @Test public void testValidatePrinters() throws Exception { startPrinting(); @@ -729,7 +651,7 @@ public class IPrintManagerParametersTest extends BasePrintTest { goodPrinters.add(mGoodPrinterId); final List<PrinterId> badPrinters = new ArrayList<>(); - badPrinters.add(mBadPrinterId); + badPrinters.add(getBadPrinterId()); final List<PrinterId> emptyPrinters = new ArrayList<>(); @@ -742,19 +664,11 @@ public class IPrintManagerParametersTest extends BasePrintTest { mIPrintManager.validatePrinters(badPrinters, mUserId); mIPrintManager.validatePrinters(emptyPrinters, mUserId); - assertException(new Invokable() { - @Override - public void run() throws Exception { - mIPrintManager.validatePrinters(null, mUserId); - } - }, NullPointerException.class); + assertException(() -> mIPrintManager.validatePrinters(null, mUserId), + NullPointerException.class); - assertException(new Invokable() { - @Override - public void run() throws Exception { - mIPrintManager.validatePrinters(nullPrinters, mUserId); - } - }, NullPointerException.class); + assertException(() -> mIPrintManager.validatePrinters(nullPrinters, mUserId), + NullPointerException.class); // Cannot test bad user Id as these tests are allowed to call across users } @@ -763,20 +677,17 @@ public class IPrintManagerParametersTest extends BasePrintTest { * test IPrintManager.startPrinterStateTracking */ @LargeTest + @Test public void testStartPrinterStateTracking() throws Exception { startPrinting(); mIPrintManager.startPrinterStateTracking(mGoodPrinterId, mUserId); // Bad printers do no cause exceptions - mIPrintManager.startPrinterStateTracking(mBadPrinterId, mUserId); + mIPrintManager.startPrinterStateTracking(getBadPrinterId(), mUserId); - assertException(new Invokable() { - @Override - public void run() throws Exception { - mIPrintManager.startPrinterStateTracking(null, mUserId); - } - }, NullPointerException.class); + assertException(() -> mIPrintManager.startPrinterStateTracking(null, mUserId), + NullPointerException.class); // Cannot test bad user Id as these tests are allowed to call across users } @@ -785,20 +696,17 @@ public class IPrintManagerParametersTest extends BasePrintTest { * test IPrintManager.getCustomPrinterIcon */ @LargeTest + @Test public void testGetCustomPrinterIcon() throws Exception { startPrinting(); mIPrintManager.getCustomPrinterIcon(mGoodPrinterId, mUserId); // Bad printers do no cause exceptions - mIPrintManager.getCustomPrinterIcon(mBadPrinterId, mUserId); + mIPrintManager.getCustomPrinterIcon(getBadPrinterId(), mUserId); - assertException(new Invokable() { - @Override - public void run() throws Exception { - mIPrintManager.getCustomPrinterIcon(null, mUserId); - } - }, NullPointerException.class); + assertException(() -> mIPrintManager.getCustomPrinterIcon(null, mUserId), + NullPointerException.class); // Cannot test bad user Id as these tests are allowed to call across users } @@ -807,6 +715,7 @@ public class IPrintManagerParametersTest extends BasePrintTest { * test IPrintManager.stopPrinterStateTracking */ @LargeTest + @Test public void testStopPrinterStateTracking() throws Exception { startPrinting(); @@ -817,15 +726,11 @@ public class IPrintManagerParametersTest extends BasePrintTest { mIPrintManager.stopPrinterStateTracking(mGoodPrinterId, mUserId); // Bad printers do no cause exceptions - mIPrintManager.startPrinterStateTracking(mBadPrinterId, mUserId); - mIPrintManager.stopPrinterStateTracking(mBadPrinterId, mUserId); + mIPrintManager.startPrinterStateTracking(getBadPrinterId(), mUserId); + mIPrintManager.stopPrinterStateTracking(getBadPrinterId(), mUserId); - assertException(new Invokable() { - @Override - public void run() throws Exception { - mIPrintManager.stopPrinterStateTracking(null, mUserId); - } - }, NullPointerException.class); + assertException(() -> mIPrintManager.stopPrinterStateTracking(null, mUserId), + NullPointerException.class); // Cannot test bad user Id as these tests are allowed to call across users } @@ -834,6 +739,7 @@ public class IPrintManagerParametersTest extends BasePrintTest { * test IPrintManager.destroyPrinterDiscoverySession */ @MediumTest + @Test public void testDestroyPrinterDiscoverySession() throws Exception { final IPrinterDiscoveryObserver listener = createMockIPrinterDiscoveryObserver(); @@ -843,12 +749,8 @@ public class IPrintManagerParametersTest extends BasePrintTest { // Destroying already destroyed session is a no-op mIPrintManager.destroyPrinterDiscoverySession(listener, mUserId); - assertException(new Invokable() { - @Override - public void run() throws Exception { - mIPrintManager.destroyPrinterDiscoverySession(null, mUserId); - } - }, NullPointerException.class); + assertException(() -> mIPrintManager.destroyPrinterDiscoverySession(null, mUserId), + NullPointerException.class); // Cannot test bad user Id as these tests are allowed to call across users } diff --git a/core/tests/coretests/src/android/print/PrintTestActivity.java b/core/tests/coretests/src/android/print/PrintTestActivity.java index 86074a62eab6..e9b001f3c821 100644 --- a/core/tests/coretests/src/android/print/PrintTestActivity.java +++ b/core/tests/coretests/src/android/print/PrintTestActivity.java @@ -21,7 +21,6 @@ import android.os.Bundle; import android.view.WindowManager; public class PrintTestActivity extends Activity { - @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); diff --git a/core/tests/coretests/src/android/print/mockservice/StubbablePrinterDiscoverySession.java b/core/tests/coretests/src/android/print/mockservice/StubbablePrinterDiscoverySession.java index e132d79cfd8b..f3a5373722cc 100644 --- a/core/tests/coretests/src/android/print/mockservice/StubbablePrinterDiscoverySession.java +++ b/core/tests/coretests/src/android/print/mockservice/StubbablePrinterDiscoverySession.java @@ -16,6 +16,7 @@ package android.print.mockservice; +import android.support.annotation.NonNull; import android.os.CancellationSignal; import android.print.PrinterId; import android.printservice.CustomPrinterIconCallback; @@ -42,7 +43,7 @@ public class StubbablePrinterDiscoverySession extends PrinterDiscoverySession { } @Override - public void onStartPrinterDiscovery(List<PrinterId> priorityList) { + public void onStartPrinterDiscovery(@NonNull List<PrinterId> priorityList) { if (mCallbacks != null) { mCallbacks.onStartPrinterDiscovery(priorityList); } @@ -56,29 +57,30 @@ public class StubbablePrinterDiscoverySession extends PrinterDiscoverySession { } @Override - public void onValidatePrinters(List<PrinterId> printerIds) { + public void onValidatePrinters(@NonNull List<PrinterId> printerIds) { if (mCallbacks != null) { mCallbacks.onValidatePrinters(printerIds); } } @Override - public void onStartPrinterStateTracking(PrinterId printerId) { + public void onStartPrinterStateTracking(@NonNull PrinterId printerId) { if (mCallbacks != null) { mCallbacks.onStartPrinterStateTracking(printerId); } } @Override - public void onRequestCustomPrinterIcon(PrinterId printerId, - CancellationSignal cancellationSignal, CustomPrinterIconCallback callback) { + public void onRequestCustomPrinterIcon(@NonNull PrinterId printerId, + @NonNull CancellationSignal cancellationSignal, + @NonNull CustomPrinterIconCallback callback) { if (mCallbacks != null) { mCallbacks.onRequestCustomPrinterIcon(printerId, cancellationSignal, callback); } } @Override - public void onStopPrinterStateTracking(PrinterId printerId) { + public void onStopPrinterStateTracking(@NonNull PrinterId printerId) { if (mCallbacks != null) { mCallbacks.onStopPrinterStateTracking(printerId); } diff --git a/docs/html/guide/topics/manifest/provider-element.jd b/docs/html/guide/topics/manifest/provider-element.jd index 1947849e56f8..0e729c36f37e 100644 --- a/docs/html/guide/topics/manifest/provider-element.jd +++ b/docs/html/guide/topics/manifest/provider-element.jd @@ -215,17 +215,15 @@ it can also be set as a raw string. </p></dd> <dt><a name="multi"></a>{@code android:multiprocess}</dt> -<dd>Whether or not an instance of the content provider can be created in -every client process — "{@code true}" if instances can run in multiple -processes, and "{@code false}" if not. The default value is "{@code false}". - -<p> -Normally, a content provider is instantiated in the process of the -application that defined it. However, if this flag is set to "{@code true}", -the system can create an instance in every process where there's a client -that wants to interact with it, thus avoiding the overhead of interprocess -communication. -</p></dd> +<dd>If the app runs in multiple processes, this attribute determines whether +multiple instances of the content provder are created. If <code>true</code>, +each of the app's processes has its own content provider object. If +<code>false</code>, the app's processes share only one content provider object. +The default value is <code>false</code>. + +<p>Setting this flag to <code>true</code> may improve performance by reducing +the overhead of interprocess communication, but it also increases the memory +footprint of each process.</p></dd> <dt><a name="nm"></a>{@code android:name}</dt> <dd>The name of the class that implements the content provider, a subclass of diff --git a/docs/html/guide/topics/ui/drag-drop.jd b/docs/html/guide/topics/ui/drag-drop.jd index 4a87cd4938cb..8e4297f8ce1b 100644 --- a/docs/html/guide/topics/ui/drag-drop.jd +++ b/docs/html/guide/topics/ui/drag-drop.jd @@ -321,7 +321,7 @@ DraggableDot.java</a> in <a href="{@docRoot}resources/samples/ApiDemos/index.htm <p> If the listener wants to continue receiving drag events for this operation, it must return boolean <code>true</code> to the system. - <\p> + </p> </td> </tr> <tr> diff --git a/docs/html/guide/topics/ui/multi-window.jd b/docs/html/guide/topics/ui/multi-window.jd index dede557ecc9a..bab582dd0b8c 100644 --- a/docs/html/guide/topics/ui/multi-window.jd +++ b/docs/html/guide/topics/ui/multi-window.jd @@ -215,7 +215,7 @@ android:resizeableActivity=["true" | "false"] Set this attribute in your manifest's <a href= "{@docRoot}guide/topics/manifest/activity-element"><code><activity></code></a> node to indicate whether the activity supports <a href= - "{@docRoot}training/tv/playback/picture-in-picture.jd">Picture-in-Picture</a> + "{@docRoot}training/tv/playback/picture-in-picture.html">Picture-in-Picture</a> display. This attribute is ignored if <code>android:resizeableActivity</code> is false. </p> diff --git a/docs/html/training/monitoring-device-state/battery-monitoring.jd b/docs/html/training/monitoring-device-state/battery-monitoring.jd index db75aaf1f899..bab9c9cf6baf 100644 --- a/docs/html/training/monitoring-device-state/battery-monitoring.jd +++ b/docs/html/training/monitoring-device-state/battery-monitoring.jd @@ -141,10 +141,11 @@ receiver. The receiver is triggered whenever the device battery becomes low or e condition by listening for {@link android.content.Intent#ACTION_BATTERY_LOW} and {@link android.content.Intent#ACTION_BATTERY_OKAY}.</p> -<pre><receiver android:name=".BatteryLevelReceiver"> -<intent-filter> - <action android:name="android.intent.action.ACTION_BATTERY_LOW"/> - <action android:name="android.intent.action.ACTION_BATTERY_OKAY"/> +<pre> +<receiver android:name=".BatteryLevelReceiver"> + <intent-filter> + <action android:name="android.intent.action.BATTERY_LOW"/> + <action android:name="android.intent.action.BATTERY_OKAY"/> </intent-filter> </receiver></pre> diff --git a/docs/html/wear/images/partners/mkors.png b/docs/html/wear/images/partners/mkors.png Binary files differnew file mode 100644 index 000000000000..2f1e8ec3aad4 --- /dev/null +++ b/docs/html/wear/images/partners/mkors.png diff --git a/docs/html/wear/images/partners/nixon.png b/docs/html/wear/images/partners/nixon.png Binary files differnew file mode 100644 index 000000000000..8674da27974d --- /dev/null +++ b/docs/html/wear/images/partners/nixon.png diff --git a/docs/html/wear/images/partners/polar.png b/docs/html/wear/images/partners/polar.png Binary files differnew file mode 100644 index 000000000000..2faeb063e1ff --- /dev/null +++ b/docs/html/wear/images/partners/polar.png diff --git a/docs/html/wear/index.jd b/docs/html/wear/index.jd index f9bdef5ce6ce..1eb08bec612c 100644 --- a/docs/html/wear/index.jd +++ b/docs/html/wear/index.jd @@ -267,6 +267,9 @@ nonavpage=true <div class="col-4"> <img src="/wear/images/partners/mips.png" alt="MIPS"> </div> + <div class="col-4"> + <img src="/wear/images/partners/mkors.png" alt=Michael Kors"> + </div> <div class="col-4"> <img src="/wear/images/partners/mobvoi.png" alt="Mobvoi"> </div> @@ -277,6 +280,12 @@ nonavpage=true <img src="/wear/images/partners/nb.png" alt="New Balance"> </div> <div class="col-4"> + <img src="/wear/images/partners/nixon.png" alt="Nixon"> + </div> + <div class="col-4"> + <img src="/wear/images/partners/polar.png" alt="Polar"> + </div> + <div class="col-4"> <img src="/wear/images/partners/qualcomm.png" alt="Qualcomm"> </div> <div class="col-4"> diff --git a/docs/html/wear/preview/_book.yaml b/docs/html/wear/preview/_book.yaml index a231fb5daa24..54d5442ec631 100644 --- a/docs/html/wear/preview/_book.yaml +++ b/docs/html/wear/preview/_book.yaml @@ -8,18 +8,24 @@ toc: - title: API Overview path: /wear/preview/api-overview.html section: - - title: Notification Improvements - path: /wear/preview/features/notifications.html - - title: Input Method Framework - path: /wear/preview/features/ime.html - title: Complications path: /wear/preview/features/complications.html - title: Navigation and Actions path: /wear/preview/features/ui-nav-actions.html + - title: Curved Layout + path: /wear/preview/features/wearable-recycler-view.html + - title: Notification Improvements + path: /wear/preview/features/notifications.html - title: Bridging for Notifications path: /wear/preview/features/bridger.html + - title: Input Method Framework + path: /wear/preview/features/ime.html - title: Wrist Gestures path: /wear/preview/features/gestures.html + - title: Standalone apps + path: /wear/preview/features/standalone-apps.html + - title: App Distribution + path: /wear/preview/features/app-distribution.html - title: Get Started path: /wear/preview/start.html diff --git a/docs/html/wear/preview/api-overview.jd b/docs/html/wear/preview/api-overview.jd index 0b3ac6bf4b2d..f4612a259958 100644 --- a/docs/html/wear/preview/api-overview.jd +++ b/docs/html/wear/preview/api-overview.jd @@ -13,15 +13,16 @@ page.image=images/cards/card-n-apis_2x.png <ol> <li><a href="#complications">Complications</a></li> <li><a href="#drawers">Navigation and Action Drawers</a></li> + <li><a href="#wrv">Curved Layout</a></li> </ol> </li> <li><a href="#notify">Notifications and Input</a> <ol> - <li><a href="#expanded">Expanded Notification</a></li> - <li><a href="#messaging">Messaging Style Notification</a></li> + <li><a href="#expanded">Expanded Notifications</a></li> + <li><a href="#messaging">Messaging Style Notifications</a></li> + <li><a href="#inline-action">Inline Action</a></li> <li><a href="#smart-replies">Smart Reply</a></li> - <li><a href="#content-action">Notification Content Action</a> <li><a href="#remote-input">Remote Input</a></li> <li><a href="#bridging">Bridging Mode</a></li> <li><a href="#imf">Input Method Framework</a></li> @@ -40,308 +41,447 @@ page.image=images/cards/card-n-apis_2x.png </div> </div> - - -<p> - The Android Wear Preview API is still in active development, but you can try - it now as part of the Wear 2.0 Developer Preview. The sections below - highlight some of the new features for Android Wear developers. -</p> - - -<h2 id="ui">User Interface Improvements</h2> - -<p> - The preview introduces powerful additions to the user interface, opening up - exciting possibilities to developers. A complication - is any feature in a watch face that displays more than hours and - minutes. With the Complications API, watch faces can display extra information - and separate apps can expose complication data. The navigation and action - drawers provide users with new ways to interact with apps. -</p> - - -<h3 id="complications">Complications</h3> -<img src="{@docRoot}wear/preview/images/complications-main-image.png" - height="320" style="float:right;margin:10px 0 0 40px" /> - -<p> - A <a href= - "https://en.wikipedia.org/wiki/Complication_(horology)">complication</a> is a - feature of a watch face that displays more than hours and minutes, such as a - battery indicator or a step counter. The Complications API thus helps watch face - developers create visual features and the data connections they - require. -</p> - -<p> - Watch faces that use this API can display extra information without needing - code for getting the underlying data. Data providers can supply data to any - watch face using the API. -</p> - -<p>For information about this API, -see <a href="{@docRoot}wear/preview/features/complications.html"> - Watch Face Complications</a>. -</p> - -<h3 id="drawers">Navigation and Action drawers</h3> - -<p>Wear 2.0 introduces two new widgets, navigation drawer and action drawer. These - widgets give your users new ways to interact with your app. The navigation drawer - appears at the top of the screen and allows users to navigate between app views. - The action drawer appears at the bottom of the screen and allows users to choose - from a list of actions associated with the current usage context. These drawers - are accessible to users when they edge swipe from the top or bottom of the - screen; they peek when users scroll in an opposite direction. -</p> - -<div class="cols"> - <div class="col-2of6"> - <img src="{@docRoot}wear/preview/images/nav_drawer.gif" - height="240" alt="" style="padding:.5em"> - </div> - <div class="col-2of6"> - <img src="{@docRoot}wear/preview/images/action_drawer.gif" - height="240" alt="" style="padding:.5em;"> - </div> -</div> - -<p> - To learn how to add these widgets to your app, see - <a href="{@docRoot}wear/preview/features/ui-nav-actions.html"> - Wear Navigation and Actions</a>. -</p> - - -<h2 id="notify">Notifications and Input</h2> - -<p>In Wear 2.0, we’ve redesigned the key experiences on the watch to be even more - intuitive and provide users new ways to respond to messages. Some of the highlights - are below; for a complete list of changes, see - <a href="{@docRoot}wear/preview/features/notifications.html">Notification Changes in Wear 2.0</a>. - - -<img src="{@docRoot}wear/preview/images/expanded_diagram.png" height="340" - style="float:left;margin:10px 20px 0 0" /> -<h3 id="expanded">Expanded notifications</h3> - -<p> - When a user taps on a notification that is bridged from the phone to the - watch or that lacks a - <a href="{@docRoot}reference/android/support/v4/app/NotificationCompat.Builder.html#setContentIntent(android.app.PendingIntent)"> - {@code contentIntent}</a>, the user will be taken to the expanded view of - that notification. When you <a href= - "{@docRoot}training/wearables/notifications/pages.html">specify additional - content pages</a> and actions for a notification, those are available to the - user within the expanded notification. Each expanded notification follows - <a href="https://google.com/design/spec-wear">Material Design for Android - Wear</a>, so the user gets an app-like experience. -</p> - - -<h3 id="messaging">Messaging Style notification</h3> -<p> If you have a chat messaging app, your notifications should use -{@code Notification.MessagingStyle}, which is new in Android 6.0. Wear 2.0 uses -the chat messages included in a -<a href="{@docRoot}preview/features/notification-updates.html#style">{@code MessagingStyle}</a> - notification -(see {@code addMessage()}) to provide a rich chat app-like experience in the -expanded notification. -</p> - - -<h3 id="smart-replies">Smart Reply</h3> - -<p>Android Wear 2.0 introduces support for Smart Reply in -<a href="{@docRoot}wear/preview/features/notifications.html#messaging">{@code MessagingStyle}</a> - notifications. Smart Reply provides the user with contextually relevant, - touchable choices in the expanded notification and in - <a href="{@docRoot}reference/android/app/RemoteInput.html">{@code RemoteInput}</a>. -</p> - -<p>By enabling Smart Reply for your {@code MessagingStyle} notifications, you provide -users a fast (single tap), discreet (no speaking aloud), and reliable way to respond - to chat messages they receive. - </p> - - -<img src="{@docRoot}wear/preview/images/remoteinput.png" height="350" - style="float:right;margin:10px 0 0 40px" /> - -<h3 id="remote-input">Remote Input</h3> - -<p>Wear 2.0 users can choose between various input options from -<a href="{@docRoot}reference/android/app/RemoteInput.html">Remote Input</a>. - These options include: -</p> -<ul> -<li>Dictation</li> -<li>Emoji</li> -<li>Canned responses</li> -<li>Smart Reply</i> -<li>Default IME </i> -</ul> - -<p> -For messaging notifications with Smart Reply, the system-generated Smart Reply - appears within <a href="{@docRoot}reference/android/app/RemoteInput.html">{@code RemoteInput}</a> - above the developer-provided list of canned responses. - You can also use the - <a href="{@docRoot}reference/android/app/RemoteInput.Builder.html#setChoices(java.lang.CharSequence[])">setChoices()</a> - method in the {@code RemoteInput} API to enable users to select from a list - of canned responses. -</p> - -<h3 id="bridging"> Bridging Mode </h3> -<p>By default, notifications are -<a href="{@docRoot}training/wearables/notifications/index.html"> -bridged</a> (shared) from an app on a companion phone -to the watch. Since a phone app and a standalone watch app may be sources of the - same notifications, the Android Wear 2.0 Preview includes a Bridging mode feature. - Developers can begin planning to change the behavior of notifications with the - following: -</p> - -<ul> -<li>Specifying in the standalone app's Android manifest file that notifications from - the corresponding phone app should not be bridged to the watch. </li> -<li>Setting a dismissal ID so notification dismissals (by users) are synced across -devices.</li> -</ul> - -<p>For an example of how to use this feature, see <a href="{@docRoot}wear/preview/features/bridger.html"> -Bridging Mode for Notifications</a>.</p> - -<h3 id="imf">Input Method Framework</h3> - -<p>Wear 2.0 extends the Android input method framework (IMF) to Android Wear. -This allows users to enter text on Wear using the system default IME or third party - IMEs. The Wear IME lets the user enter text via gesture typing as well as tapping - individual keys. The IMF APIs used for Wear devices are the same as other form - factors, though usage is slightly different due to limited screen real estate. -</p> - -<p>Wear provides user settings on the watch that let the user:</p> -<ul> -<li>Enable multiple IMEs from the list of installed IMEs.</li> -<li>Set a single default IME from the list of enabled IMEs.</li> -<li>Change languages for various IMEs.</li> -</ul> - -<p>To learn how to create an IME for Wear, see <a href="{@docRoot}wear/preview/features/ime.html"> -Input Method Framework</a>. -</p> - -<h3 id="wrist-gestures">Wrist Gestures</h3> - -<p> - Wrist gestures can enable quick, one-handed interactions with your app - when use of a touch screen is inconvenient. The following - <a href="https://support.google.com/androidwear/answer/6312406">wrist gestures</a> - are available for use by apps: -</p> - -<ul> - <li>Flick wrist out</li> - <li>Flick wrist in</li> -</ul> - -<p>For more information, see -<a href="{@docRoot}wear/preview/features/gestures.html"> - Wrist Gestures</a>. -</p> - -<h2 id="stand-alone">Standalone Devices</h2> - -<p>Standalone watches will enable Android Wear apps to work independently of phone - apps. This means your app can continue to offer full functionality even if the - paired phone is far away or turned off. </p> - -<h3 id="wear-apk">Wear-Specific APKs</h3> - -<p>For delivery to a watch, an Android Wear app is currently embedded in its corresponding -phone app. This delivery method can result in an increased download size for users, - regardless of whether they have an Android Wear device. -</p> - -<p>With standalone devices, the -<a href ="{@docRoot}google/play/publishing/multiple-apks.html">Multi-APK</a> - delivery method will be used. Developers will have the ability to release Android - Wear apps independently of the corresponding phone apps. Please stay tuned for - more information about this change. -</p> - -<h3 id="network">Network Access</h3> - -<p>Since Android Wear apps will work independently of phone apps, Android Wear's - network access will no longer require the - <a href="{@docRoot}training/wearables/data-layer/index.html"> - Wearable Data Layer API</a>. Android Wear apps will have the ability to make - their own network requests. Additionally, they will be able to directly use - Google Cloud Messaging. -</p> - -<p>No APIs for network access or GCM are specific to Android Wear; refer to the -existing documentation about -<a href="{@docRoot}training/basics/network-ops/connecting.html"> -Connecting to the Network</a> and -<a href="https://developers.google.com/cloud-messaging/">Cloud Messaging</a>. -</p> - -<p>We recommend using the following libraries:</p> -<ul> -<li><a href="{@docRoot}reference/android/app/job/JobScheduler.html"> -JobScheduler</a> for asynchronous jobs, including polling at regular intervals -</li> -<li>Multi-networking APIs if you need to connect to specific network types; see -the <a href="{@docRoot}about/versions/android-5.0.html#Wireless"> -Multiple Network Connections</a> -</li> -</ul> - -<p>You will still be able to use the -<a href="{@docRoot}training/wearables/data-layer/index.html"> - Wearable Data Layer API</a> to communicate with a phone app. - However, use of this API to connect to a network will be discouraged. - </p> - - -<h3 id="auth">Authentication</h3> - -<p>Since Android Wear apps will work independently of phone apps, Android Wear's - authentication capabilities will be more powerful; apps will have new ways to - authenticate.</p> - -<h4>Users can enter a username and password on a watch</h4> - -<p>Google Keyboard will be standard on Android Wear, allowing for direct text -entry. This feature will work as expected with standard -<a href="{@docRoot}reference/android/widget/EditText.html">EditText widgets</a>. -For passwords, the {@code textPassword} attribute will be used.</p> - -<h4>Utilizing Account Manager</h4> - -<p>Android Wear will include the -<a href="{@docRoot}reference/android/accounts/AccountManager.html"> -AccountManager</a>, which will be accessible for syncing and storing account -data, as it is on an Android phone.</p> - -<h4>Authentication tokens can be passed over the Wearable Data Layer</h4> - -<p>For Android-paired watches (only), a phone securely -transfers authentication credentials to a watch app via the -<a href="{@docRoot}training/wearables/data-layer/index.html"> -Wearable Data Layer API</a>. The credentials can be transferred as -messages or data items.</p> - -<p>If your watch app needs to determine if your phone app is installed, you can -advertise a capability on the phone app and retrieve the capability on the -watch. For more information, see the following sections of -<a href="{@docRoot}training/wearables/data-layer/messages.html"> -Sending and Receiving Messages</a>:</p> - -<ul> - <li>Advertise Capabilities</li> - <li>Retrieve the Nodes with the Required Capabilities</li> -</ul> + <p> + Wear 2.0 is still in active development, but you can try it as part of + the Wear 2.0 Developer Preview. The sections below highlight some of the + new features for developers. + </p> + + <h2 id="ui"> + User Interface Improvements + </h2> + + <p> + The preview introduces powerful additions to the user interface, opening + up exciting possibilities to developers. + </p> + + <h3 id="complications"> + Complications + </h3> + + <img src="{@docRoot}wear/preview/images/complications-main-image.png" + height="320" style="float:right;margin:10px 0 0 40px"> + <p> + A <a href= + "https://en.wikipedia.org/wiki/Complication_(horology)">complication</a> + is a feature of a watch face that displays more than hours and minutes, + such as a battery indicator or a step counter. The Complications API thus + helps watch face developers create visual features and the data + connections they require. + </p> + + <p> + Watch faces that use this API can display extra information without + needing code for getting the underlying data. Data providers can supply + data to any watch face using the API. + </p> + + <p> + For information about this API, see <a href= + "{@docRoot}wear/preview/features/complications.html">Watch Face + Complications</a>. + </p> + + <h3 id="drawers"> + Navigation and Action Drawers + </h3> + + <p> + Wear 2.0 introduces two new widgets, navigation drawer and action drawer. + These widgets give your users new ways to interact with your app. The + navigation drawer appears at the top of the screen and allows users to + navigate between app views. The action drawer appears at the bottom of + the screen and allows users to choose from a list of actions associated + with the current usage context. These drawers are accessible to users + when they edge swipe from the top or bottom of the screen; they peek when + users scroll in an opposite direction. + </p> + + <div class="cols"> + <div class="col-2of6"> + <img src="{@docRoot}wear/preview/images/nav_drawer.gif" height="240" + alt="" style="padding:.5em"> + </div> + + <div class="col-2of6"> + <img src="{@docRoot}wear/preview/images/action_drawer.gif" height="240" + alt="" style="padding:.5em;"> + </div> + </div> + + <p> + To learn how to add these widgets to your app, see <a href= + "{@docRoot}wear/preview/features/ui-nav-actions.html">Wear Navigation and + Actions</a>. + </p> + + <h3 id="wrv"> + Curved Layout + </h3> + + <p> + Wear 2.0 introduces the <code>WearableRecyclerView</code> class for + displaying and manipulating a vertical list of items, + optimized for round displays. + </p> + + <p> + The key features include the following: + </p> + + <ul> + <li>A curved layout on round devices + </li> + + <li>A circular scrolling gesture, which can be toggled on and off + </li> + </ul> + + <p> + To learn how to create a curved layout optimized for round devices, see + <a href= + "https://developer.android.com/wear/preview/features/wearable-recycler-view.html"> + Curved Layout</a>. + </p> + + <h2 id="notify"> + Notifications and Input + </h2> + + <p> + In Wear 2.0, we’ve redesigned the key experiences on the watch to be even + more intuitive and provide users new ways to respond to messages. Some of + the highlights are below; for a complete list of changes, see <a href= + "{@docRoot}wear/preview/features/notifications.html">Notification Changes + in Wear 2.0</a>. <img src= + "{@docRoot}wear/preview/images/expanded_diagram.png" height="340" style= + "float:left;margin:10px 20px 0 0"> + </p> + + <h3 id="expanded"> + Expanded Notifications + </h3> + + <p> + When a user taps on a notification that is bridged from the phone to the + watch or that lacks a <a href= + "{@docRoot}reference/android/support/v4/app/NotificationCompat.Builder.html#setContentIntent(android.app.PendingIntent)"> + {@code contentIntent}</a>, the user will be taken to the expanded view of + that notification. When you <a href= + "{@docRoot}training/wearables/notifications/pages.html">specify + additional content pages</a> and actions for a notification, those are + available to the user within the expanded notification. Each expanded + notification follows <a href= + "https://google.com/design/spec-wear">Material Design for Android + Wear</a>, so the user gets an app-like experience. + </p> + + <h3 id="messaging"> + Messaging Style Notifications + </h3> + + <p> + If you have a chat messaging app, your notifications should use {@code + Notification.MessagingStyle}, which is new in Android 6.0. Wear 2.0 uses + the chat messages included in a <a href= + "{@docRoot}preview/features/notification-updates.html#style">{@code + MessagingStyle}</a> notification (see {@code addMessage()}) to provide a + rich chat, app-like experience in the expanded notification. + </p> + + <h3 id="inline-action"> + Inline Action + </h3> + + <p> + Wear 2.0 enables you to add an inline action within the notification + stream so that users can quickly take an action on a notification. + Examples of good use cases for an inline action within a notification stream + include replying to a text message, stopping a fitness activity, or + archiving an email message. + </p> + + <p> + To learn how to add an inline action to your notification stream, see + <a href= + "https://developer.android.com/wear/preview/features/notifications.html#inline"> + Inline Action</a>. + </p> + + <h3 id="smart-replies"> + Smart Reply + </h3> + + <p> + Android Wear 2.0 introduces support for Smart Reply in <a href= + "{@docRoot}wear/preview/features/notifications.html#messaging">{@code + MessagingStyle}</a> notifications. Smart Reply provides the user with + contextually relevant, touchable choices in the expanded notification and + in <a href="{@docRoot}reference/android/app/RemoteInput.html">{@code + RemoteInput}</a>. + </p> + + <p> + By enabling Smart Reply for your {@code MessagingStyle} notifications, + you provide users a fast (single tap), discreet (no speaking aloud), and + reliable way to respond to chat messages they receive. + </p> + + <img src="{@docRoot}wear/preview/images/remoteinput.png" height="350" + style="float:right;margin:10px 0 0 40px"> + + <h3 id="remote-input"> + Remote Input + </h3> + + <p> + Wear 2.0 users can choose between various input options from <a href= + "{@docRoot}reference/android/app/RemoteInput.html">Remote Input</a>. + These options include: + </p> + + <ul> + <li>Dictation + </li> + + <li>Emoji + </li> + + <li>Canned responses + </li> + + <li>Smart Reply + </li> + + <li>Default IME + </li> + </ul> + + <p> + For messaging notifications with Smart Reply, the system-generated Smart + Reply appears within <a href= + "{@docRoot}reference/android/app/RemoteInput.html">{@code + RemoteInput}</a> above the developer-provided list of canned responses. + You can also use the <a href= + "{@docRoot}reference/android/app/RemoteInput.Builder.html#setChoices(java.lang.CharSequence[])"> + setChoices()</a> method in the {@code RemoteInput} API to enable users to + select from a list of canned responses. + </p> + + <h3 id="bridging"> + Bridging Mode + </h3> + + <p> + By default, notifications are <a href= + "{@docRoot}training/wearables/notifications/index.html">bridged</a> + (shared) from an app on a companion phone to the watch. Since a phone app + and a standalone watch app may be sources of the same notifications, the + Android Wear 2.0 Preview includes a Bridging mode feature. + </p> + + <p> + For information about this feature, see <a href= + "{@docRoot}wear/preview/features/bridger.html">Bridging Mode for + Notifications</a>. + </p> + + <h3 id="imf"> + Input Method Framework + </h3> + + <p> + Wear 2.0 extends the Android input method framework (IMF) to Android + Wear. This allows users to enter text on Wear using the system default + IME or third party IMEs. The Wear IME lets the user enter text via + gesture typing as well as tapping individual keys. The IMF APIs used for + Wear devices are the same as other form factors, though usage is slightly + different due to limited screen real estate. + </p> + + <p> + Wear provides user settings on the watch that let the user: + </p> + + <ul> + <li>Enable multiple IMEs from the list of installed IMEs. + </li> + + <li>Set a single default IME from the list of enabled IMEs. + </li> + + <li>Change languages for various IMEs. + </li> + </ul> + + <p> + To learn how to create an IME for Wear, see <a href= + "{@docRoot}wear/preview/features/ime.html">Input Method Framework</a>. + </p> + + <h3 id="wrist-gestures"> + Wrist Gestures + </h3> + + <p> + Wrist gestures can enable quick, one-handed interactions with your app + when use of a touch screen is inconvenient. The following <a href= + "https://support.google.com/androidwear/answer/6312406">wrist + gestures</a> are available for use by apps: + </p> + + <ul> + <li>Flick wrist out + </li> + + <li>Flick wrist in + </li> + </ul> + + <p> + For more information, see <a href= + "{@docRoot}wear/preview/features/gestures.html">Wrist Gestures</a>. + </p> + + <h2 id="stand-alone"> + Standalone Devices + </h2> + + <p> + Standalone watches enable Android Wear apps to work independently of + phone apps. This means your app can continue to offer full functionality + even if the paired phone is far away or turned off. + </p> + + <h3 id="wear-apk"> + Wear-Specific APKs + </h3> + + <p> + For delivery to a watch, an Android Wear app is currently embedded in its + corresponding phone app. This delivery method can result in an increased + download size for users, regardless of whether they have an Android Wear + device. + </p> + + <p> + For information about planning and building your standalone app + for Wear 2.0, see <a href= + "https://developer.android.com/wear/preview/features/standalone-apps.html"> + Standalone Apps</a>. + </p> + + <p> + For information about distributing your app, see <a href= + "https://developer.android.com/wear/preview/features/app-distribution.html"> + App Distribution</a>. + </p> + + <h3 id="network"> + Network Access + </h3> + + <p> + Since Android Wear apps will work independently of phone apps, Android + Wear's network access will no longer require the <a href= + "{@docRoot}training/wearables/data-layer/index.html">Wearable Data Layer + API</a>. Android Wear apps will have the ability to make their own + network requests. Additionally, they will be able to directly use Google + Cloud Messaging. For more information, see + <a href= + "https://developer.android.com/wear/preview/features/standalone-apps.html#network_access"> + Network Access and Cloud Messaging</a>. + </p> + + <p> + No APIs for network access or GCM are specific to Android Wear; refer to + the existing documentation about <a href= + "{@docRoot}training/basics/network-ops/connecting.html">Connecting to the + Network</a> and <a href= + "https://developers.google.com/cloud-messaging/">Cloud Messaging</a>. + </p> + + <p> + We recommend using the following libraries: + </p> + + <ul> + <li> + <a href= + "{@docRoot}reference/android/app/job/JobScheduler.html">JobScheduler</a> + for asynchronous jobs, including polling at regular intervals + </li> + + <li>Multi-networking APIs, to connect to specific network + types; see <a href= + "{@docRoot}about/versions/android-5.0.html#Wireless">Multiple Network + Connections</a> + </li> + </ul> + + <p> + The <a href= + "{@docRoot}training/wearables/data-layer/index.html">Wearable Data Layer + API</a> is available to communicate with a phone app. + However, use of this API to connect to a network will be discouraged. + </p> + + <h3 id="auth"> + Authentication + </h3> + + <p> + Since Android Wear apps will work independently of phone apps, Android + Wear's authentication capabilities will be more powerful; apps will have + new ways to authenticate. + </p> + + <h4> + Users can enter a username and password on a watch + </h4> + + <p> + Google Keyboard will be standard on Android Wear, allowing for direct + text entry. This feature will work as expected with standard <a href= + "{@docRoot}reference/android/widget/EditText.html">EditText widgets</a>. + For passwords, the {@code textPassword} attribute will be used. + </p> + + <h4> + Utilizing Account Manager + </h4> + + <p> + Android Wear will include the <a href= + "{@docRoot}reference/android/accounts/AccountManager.html">AccountManager</a>, + which will be accessible for syncing and storing account data, as it is + on an Android phone. + </p> + + <h4> + Authentication tokens can be passed over the Wearable Data Layer + </h4> + + <p> + For Android-paired watches (only), a phone securely transfers + authentication credentials to a watch app via the <a href= + "{@docRoot}training/wearables/data-layer/index.html">Wearable Data Layer + API</a>. The credentials can be transferred as messages or data items. + </p> + + <p> + If your watch app needs to determine if your phone app is installed, you + can advertise a capability on the phone app and retrieve the capability + on the watch. For more information, see the following sections of + <a href="{@docRoot}training/wearables/data-layer/messages.html">Sending + and Receiving Messages</a>: + </p> + + <ul> + <li>Advertise Capabilities + </li> + + <li>Retrieve the Nodes with the Required Capabilities + </li> + </ul> diff --git a/docs/html/wear/preview/behavior-changes.jd b/docs/html/wear/preview/behavior-changes.jd index 02146220dbdd..c93d337a0a8c 100644 --- a/docs/html/wear/preview/behavior-changes.jd +++ b/docs/html/wear/preview/behavior-changes.jd @@ -22,6 +22,8 @@ page.tags="preview", "developer preview" <ul> <li><a href="#activity-dismissal">Activity Dismissal</a></li> + <li><a href="#invalid-fields">Invalid Fields for a Complication Type</a></li> + <li><a href="#empty">Complication Types for Empty Data</a></li> </ul> </div> @@ -61,3 +63,44 @@ page.tags="preview", "developer preview" <a href="{@docRoot}wear/preview/features/ui-nav-actions.html">navigation drawers</a>. </p> + +<h2 id="invalid-fields">Invalid Fields for a Complication Type</h2> + +<p> + When a watch face uses the <a href="{@docRoot}wear/preview/features/complications.html"> + Complications API</a>, the watch face requests data from a chosen provider. + A <code>ComplicationData</code> object, which contains + complication types, is returned. +</p> + +<p> + A complication type determines the + kinds of data that a watch face can render. This section describes + a behavior change related to the <code>ComplicationData</code> object. +</p> + +<p> + Starting with + <a href="https://developer.android.com/wear/preview/support.html#dp3"> + Developer Preview 3</a>, when a watch face requests a field that is invalid + for a complication type, a default value for the field is returned. + For example, if a watch face tries to access a <code>Long text</code> + field in a <code>SHORT_TEXT</code> type, the default value for the + <code>Long text</code> field is returned. + In previous releases, such a request for an invalid field + (for a type) resulted in an exception. +</p> + +<h2 id="empty">Complication Types for Empty Data</h2> + +<p> + Starting with + <a href="https://developer.android.com/wear/preview/support.html#dp3"> + Developer Preview 3</a>, the complication types used for "empty" data are + changed. Apps that use the Complications API + may need to be updated to use + <code>TYPE_NO_DATA</code>. See the information + about <code>TYPE_NO_DATA</code> in the + <a href="{@docRoot}wear/preview/features/complications.html#types_and_fields"> + Types and fields</a> section. +</p> diff --git a/docs/html/wear/preview/downloads.jd b/docs/html/wear/preview/downloads.jd index 4bc401bae072..08ed233afc8c 100644 --- a/docs/html/wear/preview/downloads.jd +++ b/docs/html/wear/preview/downloads.jd @@ -171,7 +171,9 @@ This is the Android Wear SDK Preview License Agreement (the “License Agreement <li> <a href="#set_up_a_watch">Set Up a Watch</a> </li> - + <li> + <a href="#set_up_a_phone">Set Up a Phone</a> + </li> <li> <a href="#set_up_an_emulator">Set Up an Emulator</a> </li> @@ -180,7 +182,7 @@ This is the Android Wear SDK Preview License Agreement (the “License Agreement </div> <p> - You can run and test your app with the Android Wear 2.0 Developer Preview + You can run and test your app with the Android Wear 2.0 Preview in either of these ways: </p> @@ -237,6 +239,13 @@ This is the Android Wear SDK Preview License Agreement (the “License Agreement following tables and flash it to the corresponding device. </p> + <p class="caution"><strong>Caution:</strong> + After you flash an image to a watch, follow the steps for + <a href="#set_up_a_phone">setting up a phone</a> with the beta version of + the Android Wear companion app. To use a Wear 2.0 image on a watch, + you must have the beta companion app on a paired phone. + </p> + <p> To restore your device to its original state during the preview, you can flash the appropriate retail system image, below, to the device. @@ -266,9 +275,9 @@ This is the Android Wear SDK Preview License Agreement (the “License Agreement <td> Preview image for testing </td> - <td><a href="#top" onclick="onDownload(this)">nemo-nvd83h-factory-48ac950c.tgz</a><br> - MD5: dd351884cce9fb5bf1bdec0a8e5f56e3<br> - SHA-1: 48ac950c48faef96a7770e3c1acb56d23a28d859 + <td><a href="#top" onclick="onDownload(this)">nemo-nve68j-factory-302a33ea.tgz</a><br> + MD5: ddfccc3e050c7e2db8d657c82f7d6291<br> + SHA-1: 302a33eac348c401fcb165bad4b9aaa40c7beb2b </td> </tr> @@ -276,9 +285,9 @@ This is the Android Wear SDK Preview License Agreement (the “License Agreement <td> Non-preview image (for after testing) </td> - <td><a href="#top" onclick="onDownload(this)">nemo-mnc40x-factory-fa528bec.tgz</a><br> - MD5: 0b8ba3653d5a93cb854f4d7409d7b6c9<br> - SHA-1: fa528bec8aba3bf6c7d901ba63cd6ea0a08dbeb0 + <td><a href="#top" onclick="onDownload(this)">nemo-mfd18l-factory-3faf6f2d.tgz</a><br> + MD5: f3a0090c0e99da82ad095b5d2a9acc6d<br> + SHA-1: 3faf6f2d7f422a17a5f6c54cf5e1d2c5622689b0 </td> </tr> @@ -307,18 +316,18 @@ This is the Android Wear SDK Preview License Agreement (the “License Agreement <td> Preview image for testing </td> - <td><a href="#top" onclick="onDownload(this)">sturgeon-nvd83h-factory-cb5a11ab.tgz</a><br> - MD5: 38c1047992b1d28f6833d9f6c8470cdc<br> - SHA-1: cb5a11ab0260ea3ca7da5894e73e41f70357da6b + <td><a href="#top" onclick="onDownload(this)">sturgeon-nve68j-factory-6607cd31.tgz</a><br> + MD5: f78ac6ba8bb84038d163cc2d7ca85040<br> + SHA-1: 6607cd31858af1bfd50b905c68f7cf1f0b6e570e </td> </tr> <tr id="sturgeon-non-preview"> <td> Non-preview image (for after testing) </td> - <td><a href="#top" onclick="onDownload(this)">sturgeon-mec23l-factory-48003078.tgz</a><br> - MD5: 417b5cbddb29a2262bce133e283d2732<br> - SHA-1: 4800307843580f818557dd7c43d8ba2161e289b2 + <td><a href="#top" onclick="onDownload(this)">sturgeon-m6e69f-factory-e659286a.tgz</a><br> + MD5: 12ce6cb0b0e43b67ea46a886eae052ae<br> + SHA-1: e659286aa9004f4555a476ede4e8b690f56cfefd </td> </tr> </table> @@ -437,13 +446,14 @@ This is the Android Wear SDK Preview License Agreement (the “License Agreement <h4 id="set_up_watch"> - Set up the watch and begin testing + Set up the watch </h4> <p> After the <code>flash-all</code> script finishes, your watch reboots. - Pair the watch with a phone or tablet. The preview now is available - for testing on the watch. Before installing an app, perform the + Only pair the watch with a phone (so you can begin testing the preview) + by using the instructions in <a href="#set_up_a_phone">Set Up a Phone</a>. + Additionally, before installing an app, perform the following steps on the watch to re-secure the watch's bootloader: </p> @@ -483,7 +493,9 @@ This is the Android Wear SDK Preview License Agreement (the “License Agreement </ol> <p> - Your watch is ready for you to <a href= + After you follow the instructions in + <a href="#set_up_a_phone">Set Up a Phone</a>, + your watch will be ready for you to <a href= "{@docRoot}training/wearables/apps/creating.html#Install">install and run your app</a>: </p> @@ -539,6 +551,97 @@ This is the Android Wear SDK Preview License Agreement (the “License Agreement device reset and removes all user data on the device. </p> + <h2 id="set_up_a_phone"> + Set Up a Phone + </h2> + + <p> + On a phone, follow the instructions in this section to install the beta + version of the Android Wear companion app. The beta version cannot be run + on a phone at the same time as the non-beta version. Additionally, the + beta version is English-only. + </p> + + <p> + <p class="caution"><strong>Caution:</strong> If you have an existing + pairing of the phone to a Wear 1.x + watch, installation of the beta companion app will cause a loss of that + pairing. + </p> + + <h3 id="join-the-wear-2-0-preview-group"> + Join the Wear 2.0 preview group + </h3> + + <p> + To access the beta companion app, you must <a href= + "https://groups.google.com/forum/#!forum/android-wear-developer-preview">join + the preview group in Google Groups</a>. + </p> + + <h3> + Opt in for beta testing + </h3> + + <p> + On the <a href= + "https://play.google.com/apps/testing/com.google.android.wearable.app">Testing + Opt-in</a> page, select <strong>Become a Tester</strong>. + </p> + + <h3 id="download-and-install-the-beta-version-of-the-companion-app"> + Download and install the beta version of the companion app + </h3> + + <p> + On the Play Store on your phone, go to the <a href= + "https://play.google.com/store/apps/details?id=com.google.android.wearable.app"> + Android Wear app listing</a>. Tap <strong>Update</strong> to download and + install the beta version of the app. After installation, confirm that + <strong>Auto-update</strong> is selected for the app (see + the "Set up automatic updates for specific apps" section of <a href= + "https://support.google.com/googleplay/answer/113412">Update downloaded + apps</a>). Tap <strong>Open</strong> to start the app. + </p> + + <h3 id="pairing"> + Pair the phone to the watch + </h3> + + <p> + After you install the beta version of the companion app on a phone, + you can pair the phone to the watch: + </p> + + <ol> + <li>On the phone, select your device name from the list of devices. + A pairing code is displayed on the phone and on the watch. + Ensure that the codes match. + </li> + + <li>Tap <strong>Pair</strong> to + continue the pairing process. When the watch is connected to + the phone, a confirmation message is displayed. + On the phone, a screen is displayed that lists + the accounts on the phone. + </li> + + <li>Choose a Google account to add and sync to your watch. + </li> + + <li>Confirm the screen lock and enter the password to start the copying of + the account from the phone to the watch. + </li> + + <li>Follow the instructions in the wizard to finish the + pairing process. + </li> + </ol> + + <p> + You can begin testing your app with the preview. + </p> + <h2 id="set_up_an_emulator"> Set Up an Emulator </h2> @@ -564,11 +667,11 @@ This is the Android Wear SDK Preview License Agreement (the “License Agreement Click <strong>Next</strong>. </li> - <li>Select an <strong>N</strong> image to download. The images may be on + <li>Select a <strong>Nougat</strong> image to download. The images may be on the <strong>x86</strong> tab instead of the <strong>Recommended</strong> tab, until installed. For example, select the image with the - <strong>Release Name</strong> of N, the <strong>API Level</strong> of N, - and the <strong>Target</strong> of "Android 6.X (with Android Wear)". + <strong>Release Name</strong> of Nougat, the <strong>API Level</strong> of 24, + and the <strong>Target</strong> of "Android 7.0 (with Android Wear)". When the download and installation are complete, click <strong>Finish</strong> and then click <strong>Next</strong>. </li> diff --git a/docs/html/wear/preview/features/app-distribution.jd b/docs/html/wear/preview/features/app-distribution.jd new file mode 100644 index 000000000000..319efa6b6554 --- /dev/null +++ b/docs/html/wear/preview/features/app-distribution.jd @@ -0,0 +1,325 @@ +page.title=App Distribution +meta.keywords="wear-preview" +page.tags="wear-preview" +page.image=images/cards/card-n-sdk_2x.png +@jd:body + +<div id="qv-wrapper"> +<div id="qv"> + +<h2>In this document</h2> + + <ul> + <li><a href="#publish">Publish Your APKs</a></li> + <li><a href="#targeting">Setting Up Targeting for a Watch</a></li> + <li><a href="#console">Using the Play Developer Console</a></li> + </ul> + +</div> +</div> + + <p> + With Android Wear 2.0, a user can visit the Play Store on a watch and + download a Wear app directly to the watch. + </p> + + <p> + Generally, a Wear 2.0 app in the Play Store needs + a minimum and target API level of 24 or higher in + the Android manifest file. The minimum SDK level can be 23 + only if you are using the same APK + for Wear 1.0 and 2.0 (and thus have an embedded Wear 1.0 APK). + </p> + + <h2 id="publish"> + Publish Your APKs + </h2> + + <p> + To make your app appear in the on-watch Play Store, upload + the watch APK in the Play Developer Console just as you would any other + APK. If you only have a watch APK and no phone APK, no other steps + are required. + </p> + + <p> + If you have a phone APK in addition to a watch APK, you must use the + <a href="https://developer.android.com/google/play/publishing/multiple-apks.html">Multi-APK delivery method</a>. + </p> + + <p> + <a href= + "https://developer.android.com/training/permissions/requesting.html">Run-time + permissions</a> are required. + </p> + + <p> + Also see + <a href="{@docRoot}wear/preview/features/standalone-apps.html"> + Standalone Apps</a>. + </p> + + <h3> + Distribution to Wear 2.0 watches + </h3> + + <p> + If you only want your app to be distributed to Wear 2.0 watches, + it is unnecessary to embed the watch APK inside the the phone APK. + </p> + + <p> + If you want your app to + be distributed to Wear 1.0 watches, you need to embed the + watch APK inside the phone APK, as described directly below. + </p> + + <h3> + Distribution to Wear 1.0 and 2.0 watches + </h3> + + <p> + If you are already distributing your app to Wear 1.0 watches, + follow these steps: + </p> + + <ol> + <li>Provide a Wear 2.0 (standalone) version of your watch APK that can be made + available in the Play Store on Wear. + </li> + + <li>Continue embedding a Wear 1.0 APK in your phone APK, + for use by watches that do not have Wear 2.0. + </li> + </ol> + + <h3> + Specifying a version code + </h3> + + <p> + To ensure that a standalone APK acts as an upgrade to an embedded Wear APK, the + standalone Wear APK's <a href= + "https://developer.android.com/google/play/publishing/multiple-apks.html#VersionCodes"> + version code</a> generally should be higher than the embedded Wear APK's version code. + (A phone APK's version code scheme can be independent from that of a watch + APK, although they must be unique.) However, the version codes + of the standalone APK and the embedded Wear APK can be the same if + the APKs are equivalent. If the APKs are not equivalent, + but the version code is the same, then when a watch updates from Wear 1.0 + to 2.0, the watch may get the new APK only after waiting for a + longer-than-expected period of time. + </p> + + <p> + Note that it currently is not possible to create a single APK that works + on a phone and watch. + </p> + + <h3> + Support in the Gradle file + </h3> + + <p> + If you have a Wear app that is intended for both Wear 1.0 and Wear 2.0, + consider using <a href= + "https://developer.android.com/studio/build/build-variants.html#product-flavors"> + product flavors</a>. For example, + if you want to target both SDK version 23 and version 24, + update your Wear module's <code>build.gradle</code> file to include + the following if an existing embedded app has a minimum SDK version of 23: + </p> + +<pre> +android { + ... + defaultConfig + { + // This is the minSdkVersion of the Wear 1.0 embedded app + minSdkVersion 23 + ... + } + buildTypes {...} + productFlavors { + wear1 { + // Use the defaultConfig value + } + wear2 { + minSdkVersion 24 + } + } +</pre> + + <p> + Then update your phone module’s <code>build.gradle</code> file, replacing + <code>wearApp</code> as follows: + </p> + +<pre> +dependencies { + ... + wearApp project(path: ':wearable', configuration: 'wear1Release') +} +</pre> + + <p> + A <a href= + "https://developer.android.com/studio/build/build-variants.html#product-flavors"> + build variant</a> is a combination of the product flavor and build type. + In Android Studio, select the appropriate build variant when + debugging or publishing your app. For example, if <code>wear2</code> is a + product flavor, select <strong>wear2Release</strong> as the + release build variant. + </p> + + <p> + For purposes of code that is Wear 2.0-specific or Wear 1.0-specific, + consider <a href= + "https://developer.android.com/studio/build/build-variants.html#sourcesets"> + source sets for build variants</a>. + </p> + + + <h2 id="targeting"> + Setting Up Targeting for a Watch + </h2> + + <p> + In your Android Manifest file, you must specify the following feature + restriction: the <code>uses-feature</code> element is set to + <code>android.hardware.type.watch</code>. Do not set + the <code>required</code> attribute to <code>false</code>. + A single APK for Wear and non-Wear devices presently is not supported. + </p> + + <p> + Thus, if an APK has the following setting, Google Play provides the APK + to watches only: + </p> + +<pre> +<manifest package="com.example.standalone" + xmlns:android="http://schemas.android.com/apk/res/android"> + <uses-feature + android:name="android.hardware.type.watch" + ... +</manifest> +</pre> + + <p> + The <code>android.hardware.type.watch</code> setting above can be + combined with other criteria such as SDK version, screen resolution, and + CPU architecture. Thus, different Wear APKs can target different hardware + configurations. + </p> + + <h2 id="console"> + Using the Play Developer Console + </h2> + + <p> + Below is an introduction to <a href= + "https://support.google.com/googleplay/android-developer/answer/113469">uploading</a> + a standalone Wear APK to an application listing using the Play Developer + Console. + </p> + + <p> + If your app supports both Wear 1.0 and Wear 2.0, continue embedding the + Wear 1.0 APK (minimum SDK version of 20, 21, or 22, or 23) in the phone + APK and upload the phone APK. In addition, upload your standalone Wear + 2.0 APK (which has a minimum SDK version of 24). + </p> + + <p> + Also see <a href= + "https://developer.android.com/google/play/publishing/multiple-apks.html"> + Multiple APK Support</a> and <a href= + "https://developer.android.com/distribute/googleplay/developer-console.html#manage"> + Manage Your App</a>. + Before uploading an APK as described below, the APK + must be <a href= + "https://developer.android.com/studio/publish/app-signing.html#release-mode"> + signed</a>. + </p> + + <h3 id="uploading-apk"> + Uploading your APK + </h3> + + <p> + Go to the <a href="https://play.google.com/apps/publish">Play Developer + Console</a>, navigate to your application listing, and select + <strong>APK</strong> in the left-navigation panel. An APK screen similar to + the following is displayed: + </p> + <img src="../images/apk-tabs.png" width="" alt="alt_text"> + + <p> + You may need to use advanced mode for uploads, as follows: + </p> + + <ul> + <li>Advanced mode is unnecessary if you only have a Wear 2.0 app and no + phone app. Instead of advanced mode, use simple mode.</li> + + <li>Use advanced mode if you support Wear 1.0 or have a phone app.</li> + </ul> + + <p> + Therefore, on the above APK screen, to determine whether to click + the <strong>Switch to advanced mode</strong> + button, consider the following: + </p> + + <ul> + <li>If your app does not support Wear 1.0, and only has a watch APK, + upload it using simple mode. + </li> + + <li>If your app does not support Wear 1.0 and has both a watch APK and a + phone APK, click <strong>Switch to advanced mode</strong> + to upload the watch and phone APKs. + </li> + </ul> + + <p> + See <a href= + "https://developer.android.com/google/play/publishing/multiple-apks.html#SimpleAndAdvanced"> + Simple mode and advanced mode</a> for more information about toggling + between modes. + </p> + + <p> + Select the appropriate tab (<strong>Production</strong>, <strong>Beta + Testing</strong>, or <strong>Alpha Testing</strong>) for your upload. + Then click + the <strong>Upload New APK</strong> button and select your standalone + Wear APK for upload. + </p> + + <h3> + Reviewing and publishing + </h3> + + <p> + After you upload your standalone Wear APK and scroll down the resulting + page, the APK is shown in the <strong>Current APK</strong> table, with a + version number, in a similar way to the following: + </p> + <img src="../images/current-apk.png" width="" alt="alt_text"> + + <p> + Finally, in the <strong>Current APK</strong> table above, click the line + with the <strong>Version</strong> to review the APK. The <strong>APK + Details</strong> panel is displayed. You can verify, for example, that + the number in the <strong>Supported Android Devices</strong> line is far + fewer than the number would be for a typical phone APK: + </p> + <img src="../images/apk-details.png" width="" alt="alt_text"> + + <p> + When you are ready, <a href= + "https://support.google.com/googleplay/android-developer/answer/6334282">publish</a> + your app. + </p> diff --git a/docs/html/wear/preview/features/bridger.jd b/docs/html/wear/preview/features/bridger.jd index b7be093ed298..2d879caeccc2 100644 --- a/docs/html/wear/preview/features/bridger.jd +++ b/docs/html/wear/preview/features/bridger.jd @@ -6,19 +6,26 @@ page.tags="wear-preview" <div id="qv-wrapper"> <div id="qv"> - <ol> + <ul> <li> <a href= - "#preventing_bridging_with_the_bridging_mode_feature">Preventing - Bridging with the Bridging Mode Feature</a> + "#using-an-entry-in-the-manifest-file">Specifying a Bridging Configuration in the Manifest File</a> </li> <li> <a href= - "#using_a_dismissal_id_to_sync_notification_dismissals">Using a - Dismissal ID to Sync Notification Dismissals</a> + "#specifying-a-bridging-configuration-at-runtime">Specifying a Bridging Configuration at Runtime</a> </li> - </ol> + <li> + <a href= + "#existing-method-of-preventing-bridging">Existing Method of Preventing Bridging</a> + </li> + + <li> + <a href= + "#using_a_dismissal_id_to_sync_notification_dismissals">Using a Dismissal ID to Sync Notification Dismissals</a> + </li> + </ul> </div> </div> @@ -27,19 +34,20 @@ page.tags="wear-preview" "{@docRoot}training/wearables/notifications/index.html">are bridged (shared)</a> from an app on a companion phone to the watch. If you build a standalone watch app and have a companion phone app, they may duplicate - notifications. The Android Wear 2.0 Preview includes a Bridging mode - feature to handle this problem of repeated notifications. + notifications. The Android Wear 2.0 Preview includes + features to handle this problem of repeated notifications. </p> <p> - With the Android Wear 2.0 Preview, developers can change the - behavior of notifications with the following: + With the Android Wear 2.0 Preview, developers can change the behavior of + notifications with one or more of the following: </p> <ul> - <li>Specifying in the standalone app's Android manifest file that - notifications from the corresponding phone app should not be - bridged to the watch + <li>Specifying a bridging configuration in the manifest file + </li> + + <li>Specifying a bridging configuration at runtime </li> <li>Setting a dismissal ID so notification dismissals are synced across @@ -47,43 +55,201 @@ page.tags="wear-preview" </li> </ul> - <h2 id="preventing_bridging_with_the_bridging_mode_feature"> - Preventing Bridging with the Bridging Mode Feature + <h2 id="using-an-entry-in-the-manifest-file"> + Specifying a Bridging Configuration in the Manifest File </h2> <p> - To prevent bridging of notifications from a phone app, you can use an + An app's Android manifest file can indicate that notifications from the + corresponding phone app should not be bridged to the watch. Specifically, + to prevent bridging of notifications from a phone app, you can use a + <code><meta-data></code> entry in the manifest file of the watch app (e.g. the standalone watch app), as follows: </p> - <pre> +<pre> com.google.android.wearable.notificationBridgeMode - </pre> +</pre> <p> Setting that entry to <code>NO_BRIDGING</code> will prevent bridging: </p> - <pre> -<meta-data android:name="com.google.android.wearable.notificationBridgeMode" - android:value="NO_BRIDGING" /> +<pre> +<meta-data android:name="com.google.android.wearable.notificationBridgeMode" + android:value="NO_BRIDGING" /> </pre> + <p> - The default bridging behavior occurs if you do not include the entry or + The default bridging behavior occurs if you do not + include the <code><meta-data></code> entry or if you specify a value of <code>BRIDGING</code> instead of <code>NO_BRIDGING</code>. </p> - <h3 id="existing_method_of_preventing_bridging"> - Existing method of preventing bridging + <p> + For an existing app, if you are using + Google Cloud Messaging (GCM) or Firebase Cloud + Messaging (FCM) to send notification alerts to devices, + you may already have disabled bridging in case a phone is not + connected at the time of receiving an alert. + In this case, you may still want to dismiss the notification + across other devices when it is dismissed in a watch app. + </p> + + <p> + The bridging configuration that is set in the manifest takes effect as + soon as a watch app is installed. + </p> + + <h2 id="specifying-a-bridging-configuration-at-runtime"> + Specifying a Bridging Configuration at Runtime + </h2> + + <p> + This section describes how to specify a bridging configuration at runtime + using the <code>BridgingManager</code> class + <code>(android.support.wearable.notifications.BridgingManager)</code>. + </p> + + <p> + You can set a bridging mode, and optionally set tags for notifications + that are exempt from the bridging mode, using a + <code>BridgingManager</code> object. Specifically, create a + <code>BridgingConfig</code> object and set it as shown in this section, + optionally using the <code>setBridgingEnabled</code> method. If you + specify a bridging configuration at runtime, then if the + <code>setBridgingEnabled</code> method is not set, bridging is enabled by + default. + </p> + + <p> + Specifying a bridging configuration at runtime overrides a + bridging-related setting in the Android manifest file. + </p> + + <h3 id="disable-bridging-for-all-notifications"> + Disable bridging for all notifications + </h3> + + <p> + You can use the <code>setBridgingEnabled</code> method, as follows: + </p> + +<pre> +BridgingManager.setConfig(context, + new BridgingConfig.Builder(context) + .setBridgingEnabled(false) + .build()); +</pre> + <p> + If the above setter is not called, the bridging mode defaults to true. + Here is an example of setting tags without using the + <code>setBridgingEnabled</code> method, excluding notifications with a + tag of <code>foo</code> or <code>bar</code>: + </p> + +<pre> +BridgingManager.setConfig(context, + new BridgingConfig.Builder(context) + .addExcludedTag("foo") + .addExcludedTag("bar") + .build()); +</pre> + <h3 id="exempt-notifications-that-are-tagged"> + Exempt notifications that are tagged </h3> <p> + You can disable bridging for all notifications except those with certain + tags. + </p> + + <p> + For example, you can disable bridging, except for notifications tagged as + <code>foo</code> or <code>bar,</code> with the following: + </p> + +<pre> +BridgingManager.setConfig(context, + new BridgingConfig.Builder(context) + .setBridgingEnabled(false) + .addExcludedTag("foo") + .addExcludedTag("bar") + .build()); +</pre> + + <p> + As another example, you can disable bridging for all notifications except + for notifications tagged as <code>foo</code>, <code>bar</code> or + <code>baz</code>. + </p> + + <pre> +BridgingManager.setConfig(context, + new BridgingConfig.Builder(context) + .setBridgingEnabled(false) + .addExcludedTags(Arrays.asList("foo", "bar", "baz")) + .build()); +</pre> + <h3 id="enable-bridging-except-for-notifications-with-certain-tags"> + Enable bridging except for notifications with certain tags + </h3> + + <p> + You can enable bridging for all notifications except those with certain + tags. + </p> + + <p> + For example, you can enable bridging for all notifications, except for + notifications tagged as <code>foo</code> or <code>bar</code>, with the + following: + </p> + +<pre> +BridgingManager.setConfig(context, + new BridgingConfig.Builder(context) + .setBridgingEnabled(true) + .addExcludedTag("foo") + .addExcludedTag("bar") + .build()); +</pre> + + <h3 id="setting-a-bridge-tag"> + Setting a bridge tag + </h3> + + <p> + A bridge tag can be set on a notification by calling the + <code>setNotificationBridgeTag</code> method as follows: + </p> + +<pre> +BridgingManager.setNotificationBridgeTag(<NotificationCompat.Builder>, <String>); +</pre> + + <p> + For example: + </p> + +<pre> +NotificationCompat.Builder builder = new NotificationCompat.Builder(context) +<set other fields>; +BridgingManager.setNotificationBridgeTag(builder, "foo"); +Notification notification = builder.build(); +</pre> + + <h2 id="existing-method-of-preventing-bridging"> + Existing Method of Preventing Bridging + </h2> + + <p> An existing way to prevent bridging is with the <code>Notification.Builder</code> class; specify <code>true</code> in the <a href= - "{@docRoot}reference/android/app/Notification.Builder.html#setLocalOnly(boolean)"> + "http://developer.android.com/reference/android/app/Notification.Builder.html#setLocalOnly(boolean)"> setLocalOnly</a> method. </p> @@ -95,12 +261,6 @@ com.google.android.wearable.notificationBridgeMode the watch app may not be installed on all of them. </p> - <p> - Thus, if bridging should be prevented when the watch app - is installed, use the <a href= - "#preventing_bridging_with_the_bridging_mode_feature">Bridging mode - feature</a>. - </p> <h2 id="using_a_dismissal_id_to_sync_notification_dismissals"> Using a Dismissal ID to Sync Notification Dismissals @@ -110,7 +270,7 @@ com.google.android.wearable.notificationBridgeMode If you prevent bridging with the Bridging mode feature, dismissals (cancellations) of notifications are not synced across a user's devices. However, the following methods of the <a href= - "{@docRoot}reference/android/support/v4/app/NotificationCompat.WearableExtender.html"> + "http://developer.android.com/reference/android/support/v4/app/NotificationCompat.WearableExtender.html"> NotificationCompat.WearableExtender</a> class enable you to use dismissal IDs: </p> @@ -118,7 +278,7 @@ com.google.android.wearable.notificationBridgeMode <pre> public WearableExtender setDismissalId(String dismissalId) public String getDismissalId() - </pre> +</pre> <p> To enable a dismissal to be synced, use the <code>setDismissalId()</code> method. For each notification, pass a globally unique ID, as a string, @@ -135,12 +295,12 @@ public String getDismissalId() <pre> NotificationCompat.WearableExtender wearableExtender = -new NotificationCompat.WearableExtender().setDismissalId(“abc123”); +new NotificationCompat.WearableExtender().setDismissalId("abc123"); Notification notification = new NotificationCompat.Builder(context) <set other fields> .extend(wearableExtender) .build(); - </pre> +</pre> <p> Dismissal IDs work if a watch is paired to an Android phone, but not if a watch is paired to an iPhone. diff --git a/docs/html/wear/preview/features/complications.jd b/docs/html/wear/preview/features/complications.jd index 3334cb79b143..c8661188eb0a 100644 --- a/docs/html/wear/preview/features/complications.jd +++ b/docs/html/wear/preview/features/complications.jd @@ -13,6 +13,13 @@ page.image=/wear/preview/images/complications-main-image.png Complications to a Watch Face</a> </li> <li> + <a href="#permissions-for-complication-data">Permissions + for Complication Data</a> + </li> + <li> + <a href="#default-providers">Default Providers for Watch Faces</a> + </li> + <li> <a href="#exposing_data_to_complications">Exposing Data to Complications</a> </li> @@ -27,12 +34,14 @@ page.image=/wear/preview/images/complications-main-image.png <a href="#api_additions">API Additions</a> </li> </ol> + <h2>See Also</h2> <ol> <li><a class="external-link" href="https://github.com/googlesamples/android-WatchFace">Watch Face sample app with complications</a></li> </ol> + </div> </div> @@ -56,9 +65,12 @@ page.image=/wear/preview/images/complications-main-image.png </p> <p> - Along with reviewing this page, download the Android Wear 2.0 Preview - Reference (see the Complications API <a href= - "#api_additions">additions</a>) and review the Javadoc for complications. + You can review the Javadoc for complications by downloading + the Android Wear 2.0 Preview + Reference. Also see the <a href="#api_additions">API additions for + complications</a> and the + <a href="https://developer.android.com/wear/preview/behavior-changes.html"> + behavior changes</a> for Wear 2.0. </p> <p> @@ -117,8 +129,8 @@ page.image=/wear/preview/images/complications-main-image.png <code>WatchFaceService.Engine</code> class, with a list of watch face complication IDs. A watch face creates these IDs to uniquely identify slots on the watch face where complications can appear, and passes them - to the <code>createProviderChooserIntent</code> method (of the - <code>ProviderChooserIntent</code> class) to allow the user to decide + to the <code>createProviderChooserIntent</code> method + to allow the user to decide which complication should go in which slot. </p> @@ -186,6 +198,406 @@ page.image=/wear/preview/images/complications-main-image.png where possible. </p> + <h2 id="permissions-for-complication-data"> + Permissions for Complication Data + </h2> + + <p> + A watch face must have the following <a href= + "https://developer.android.com/training/permissions/requesting.html">permission</a> + to receive complication data and open the provider chooser: + </p> + +<pre> +com.google.android.wearable.permission.RECEIVE_COMPLICATION_DATA +</pre> + + <h3 id="opening-the-provider-chooser"> + Opening the provider chooser + </h3> + + <p> + A watch face that was not granted the above permission will be unable to + start the provider chooser. + </p> + + <p> + To make it easier to request the permission and start the chooser, the + <code>ComplicationHelperActivity</code> class is available in the + wearable support library. This class should be used instead of + <code>ProviderChooserIntent</code> to start the chooser in almost all + cases. + </p> + + <h4 id="requesting-the-necessary-permission"> + Requesting the necessary permission + </h4> + + <p> + To use <code>ComplicationHelperActivity</code>, add it to the watch face + in the <a href= + "https://developer.android.com/guide/topics/manifest/manifest-intro.html"> + manifest file</a>: + </p> + +<pre> +<activity android:name="android.support.wearable.complications.ComplicationHelperActivity"/> +</pre> + + <p> + To start the provider chooser, call the + <code>ComplicationHelperActivity.createProviderChooserHelperIntent</code> + method, to obtain an intent. + </p> + + <p> + The new intent can be used with either <code>startActivity</code> or + <code>startActivityForResult</code> to launch the chooser. + </p> + + <p> + Here is an example of using the new intent with + <code>startActivityForResult</code>: + </p> + + <pre> +startActivityForResult( + ComplicationHelperActivity.createProviderChooserHelperIntent( + getActivity(), + watchFace, + complicationId, + ComplicationData.TYPE_LARGE_IMAGE), + PROVIDER_CHOOSER_REQUEST_CODE); +</pre> + <p> + When the helper activity is started, the helper activity checks if the + permission was granted. If the permission was not granted, the helper + activity makes a runtime permission request. If the permission request is + accepted (or is unneeded), the provider chooser is shown. + </p> + + <p> + If <code>startActivityForResult</code> was used with the intent, the + result delivered back to the calling Activity will have a result code of + <code>RESULT_OK</code> if a provider was successfully set, or a result + code of <code>RESULT_CANCELLED</code> if no provider was set. + </p> + + <p> + In the case where a provider was set, + <code>ComplicationProviderInfo</code> for the chosen provider will be + included in the data intent of the result, as an extra with the key + <code>ProviderChooserIntent#EXTRA_PROVIDER_INFO</code>. + </p> + + <h3 id="receiving-complication-data"> + Receiving complication data + </h3> + + <p> + In general, watch faces need the above permission in order to receive + complication data, but there are some exceptions. Specifically, a watch + face can only receive data from a provider if one of the following is + true: + </p> + + <ul> + <li>The provider is a "safe" system provider, + </li> + + <li>The provider and watch face are from the same app, + </li> + + <li>The provider whitelists the watch face as a "safe" watch face, or + </li> + + <li>The watch face has the permission + </li> + </ul> + + <h4 id="lack-of-appropriate-permission"> + Lack of appropriate permission + </h4> + + <p> + If none of the above is true, then when <code>ComplicationData</code> + normally would be sent by a provider to a watch face, the system instead + sends data of the type <code>TYPE_NO_PERMISSION</code>. This type + includes an icon (an exclamation mark) and short text ("--") to allow it + to be rendered as if it were of the short text type or icon type, for + convenience. + </p> + + <p> + When a watch face receives data of <code>TYPE_NO_PERMISSION</code>, the + watch face should render this appropriately, so the user can see that + action is needed for the complication to work. If possible, a tap on a + complication in this state should launch a permission request. This can + be done using + <code>ComplicationHelperActivity.createPermissionRequestHelperIntent</code>, + if the helper activity was added to the watch face app. + </p> + + <p> + If a user accepts the permission request created by the helper activity, + updates are requested for all the active complications on the watch face + automatically, allowing the <code>TYPE_NO_PERMISSION</code> data to be + replaced by real data. + </p> + + <h4 id="safe-providers"> + Safe providers + </h4> + + <p> + Some system providers are considered "safe", because they only supply + information that the watch face already could obtain itself. + </p> + + <p> + These providers are listed in the new <code>SystemProviders</code> class + in the wearable support library. Whether a system provider is safe is + stated in the Javadoc (in the Android Wear 2.0 Preview Reference). Also + see <a href="#system-providers">System providers</a> for a list. + </p> + + <h4 id="provider-specified-safe-watch-faces"> + Provider-specified safe watch faces + </h4> + + <p> + Providers can specify certain watch faces as "safe" to receive their + data. This is intended to be used only when the watch face will attempt + to use the provider as a default (see below), + and the provider trusts the watch face app. + </p> + + <p> + To declare watch faces as safe, the provider adds metadata with a key of + <code>android.support.wearable.complications.SAFE_WATCH_FACES</code>. The + metadata value should be a comma-separated list (whitespace is ignored). + Entries in the list can be component names (of + <code>WatchFaceServices</code>, given as if + <code>ComponentName.flattenToString()</code> had been called), or they + can be package names (of apps, in which case every watch face within a + specified app is considered safe). + </p> + + <p> + For example: + </p> + +<pre> +<meta-data + android:name="android.support.wearable.complications.SAFE_WATCH_FACES" + android:value=" + com.app.watchface/com.app.watchface.MyWatchFaceService, + com.anotherapp.anotherwatchface/com.something.WatchFaceService, + com.something.text + "/> +</pre> + + <h2 id="default-providers"> + Default Providers for Watch Faces + </h2> + + <p> + Watch faces can specify default providers that are used until a user + selects a provider. + </p> + + <h3 id="setting-default-providers"> + Setting default providers + </h3> + + <p> + Set default providers using the + <code>setDefaultComplicationProvider</code> method in + <code>WatchFaceService.Engine</code>. This method may be called at any + time, but it does nothing if the user already chose a provider for the + given complication. + </p> + + <h3 id="safe-providers2"> + Safe providers + </h3> + + <p> + For most providers, the <code>RECEIVE_COMPLICATION_DATA</code> permission + must be granted to a watch face before data can flow to it. However, some + system providers are considered "safe", and do not require the watch face + to have the permission for data to be sent (see <a href= + "#safe-providers">Safe Providers</a> and <a href= + "#system-providers">System providers</a>). These providers may be + preferable to use as defaults, as they can supply data immediately. + </p> + + <p> + Alternatively, if a watch face has a partnership with a certain provider + and wishes to use it as a default, it can request that the provider list + it as a safe watch face (see <a href= + "#provider-specified-safe-watch-faces">Provider-specified safe watch + faces</a>). + </p> + + <h3 id="system-providers"> + System providers + </h3> + + <p> + The system includes providers that can be used as defaults. These are + listed in the <code>SystemProviders</code> class in the wearable support + library. + </p> + + <p> + The following table has details about providers that are considered safe: + </p> + + <table> + <tr> + <th> + Method name in the SystemProviders class + </th> + <th> + Safety + </th> + <th> + Can be the default + </th> + <th> + Notes + </th> + </tr> + + <tr> + <td> + <code>dateProvider()</code> + </td> + <td> + Yes + </td> + <td> + Yes + </td> + <td> + The standard system date provider. Tapping opens the standard Agenda + app. + </td> + </tr> + + <tr> + <td> + <code>currentTimeProvider()</code> + </td> + <td> + Yes + </td> + <td> + Yes + </td> + <td> + The standard system "time and date" provider. No tap action. + </td> + </tr> + + <tr> + <td> + <code>batteryProvider()</code> + </td> + <td> + Yes + </td> + <td> + Yes + </td> + <td> + The standard system battery provider. No tap action. + </td> + </tr> + + <tr> + <td> + <code>stepCountProvider()</code> + </td> + <td> + Yes + </td> + <td> + Yes + </td> + <td> + Shows a daily total of steps, as reported by + <code>readDailyTotal</code>. + </td> + </tr> + + <tr> + <td> + <code>unreadCountProvider()</code> + </td> + <td> + Yes + </td> + <td> + Yes + </td> + <td> + Shows the number of unread notifications in the stream. + </td> + </tr> + + <tr> + <td> + <code>worldClockProvider()</code> + </td> + <td> + Yes + </td> + <td> + Yes + </td> + <td> + Will default to London or New York. Can be tapped to change the time + zone. + </td> + </tr> + + <tr> + <td> + <code>appsProvider()</code> + </td> + <td> + Yes + </td> + <td> + Yes + </td> + <td> + Will show an "apps" icon at first, which can be tapped to choose an + app. + </td> + </tr> + + <tr> + <td> + <code>nextEventProvider()</code> + </td> + <td> + No + </td> + <td> + Yes (but not a safe provider) + </td> + <td> + The standard system "next event" provider. Tapping opens + the standard Agenda app. + </p> + </td> + </tr> + </table> + + <h2 id="exposing_data_to_complications"> Exposing Data to Complications </h2> @@ -203,6 +615,11 @@ page.image=/wear/preview/images/complications-main-image.png be used to send data back to the system. </p> + <p class="note"><strong>Note:</strong> When you provide data as a + complication data provider, the watch face receives the raw values + you send so it can draw them on the watch face. + </p> + <p> In your app's manifest, declare the service and add an intent filter for the following: @@ -210,7 +627,8 @@ page.image=/wear/preview/images/complications-main-image.png <pre> android.support.wearable.complications.ACTION_COMPLICATION_UPDATE_REQUEST -</pre> + </pre> + <p> The service's manifest entry should also include an <code>android:icon</code> attribute. The provided icon should be a @@ -227,6 +645,21 @@ android.support.wearable.complications.ACTION_COMPLICATION_UPDATE_REQUEST <a href="#api_additions">API Additions</a>). </p> + <p> + Additionally, a permission for provider services ensures that only the Android Wear system + can bind to provider services. Only the Android Wear system can have this + permission. + </p> + + <p> + Provider services should add the following to their service declarations + in the manifest: + </p> + +<pre> +android:permission="com.google.android.wearable.permission.BIND_COMPLICATION_PROVIDER" +</pre> + <h3 id="update_period"> Update period </h3> @@ -371,6 +804,11 @@ METADATA_KEY_PROVIDER_CONFIG_ACTION <p> The following table describes the types and fields of the <code>ComplicationData</code> object. + If a watch face requests a field that is invalid for a complication type, + a default value for the field is returned. + For example, if a watch face tries to access a <code>Long text</code> + field in a <code>SHORT_TEXT</code> type, the default value for the + <code>Long text</code> field is returned. </p> <table> @@ -489,56 +927,80 @@ METADATA_KEY_PROVIDER_CONFIG_ACTION </table> <p> - In addition, the following two types have no fields. These two types may - be sent for any complication slot and do not need to be included in a - list of supported types: + In addition, the types in the table below are for empty data and + may be sent for any complication slot. These types have no fields + and do not need to be included in a + list of supported types. These types enable watch + faces to differentiate among the following three cases: + </p> + + <ul> + <li>No provider was chosen + </li> + + <li>The user has selected "empty" for a slot + </li> + + <li>A provider has no data to send + </li> + </ul> + + <p> + Providers should not send <code>TYPE_EMPTY</code> in response to + update requests. Providers should send <code>TYPE_NO_DATA</code> instead. + </p> + + <p> + Details on the complication types for "empty" data are in the + following table: </p> <table> <tr> - <th style="width:175px"> - Type - </th> - <th style="width:175px"> - Required fields + <th>Complication type </th> - <th style="width:175px"> - Optional fields - </th> - <th> - Notes + <th>Description </th> </tr> <tr> <td> - NOT_CONFIGURED - </td> - <td> - None - </td> - <td> - None + <code>TYPE_NOT_CONFIGURED</code> </td> <td> - Sent when a provider has not yet been chosen for a complication. + Sent by the system when a complication is activated but the user has + not selected a provider, and no default was set. + <p> + Cannot be sent by providers. + </p> </td> </tr> <tr> <td> - EMPTY + <code>TYPE_EMPTY</code> </td> <td> - None + Sent by the system when a complication is activated and the user has + chosen "empty" instead of a provider, or when the watch face has + chosen no provider, and this type, as the default. + <p> + Cannot be sent by providers. + </p> </td> + </tr> + + <tr> <td> - None + <code>TYPE_NO_DATA</code> </td> <td> - Sent by a provider when there is no data to display in a - complication, or sent by the system when nothing should be shown in a - complication. + Sent by the system when a complication (that has a provider) is + activated, to clear the complication before actual data is received + from the provider. + <p> + Should be sent by providers if they have no actual data to send. + </p> </td> </tr> </table> @@ -700,8 +1162,8 @@ METADATA_KEY_PROVIDER_CONFIG_ACTION </h2> <p> - The Complications API includes new classes in the Wearable Support - Library. For more information, download the <a href= + The Complications API includes new classes in the wearable support + library. For more information, download the <a href= "{@docRoot}wear/preview/start.html#get_the_preview_reference_documentation"> Android Wear 2.0 Preview Reference</a>. </p> @@ -722,14 +1184,26 @@ METADATA_KEY_PROVIDER_CONFIG_ACTION </li> <li> - <code>ComplicationText</code> + <code>ComplicationHelperActivity</code> <ul> - <li>Used to supply text-based values in a - <code>ComplicationData</code> object + <li>Used to request the following permission: <br> +<code>com.google.android.wearable.permission.RECEIVE_COMPLICATION_DATA</code> </li> - <li>Includes options for time-dependent values, whose text value - depends on the current time + <li>Used instead of <code>ProviderChooserIntent</code> + to start the chooser in almost all cases + </li> + </ul> + </li> + + <li> + <code>ComplicationManager</code> + <ul> + <li>A wrapper for the complication manager service, for use by + providers + </li> + + <li>Allows providers to send complication data to the system </li> </ul> </li> @@ -747,13 +1221,14 @@ METADATA_KEY_PROVIDER_CONFIG_ACTION </li> <li> - <code>ComplicationManager</code> + <code>ComplicationText</code> <ul> - <li>A wrapper for the complication manager service, for use by - providers + <li>Used to supply text-based values in a + <code>ComplicationData</code> object </li> - <li>Allows providers to send complication data to the system + <li>Includes options for time-dependent values, whose text value + depends on the current time </li> </ul> </li> @@ -761,11 +1236,8 @@ METADATA_KEY_PROVIDER_CONFIG_ACTION <li> <code>ProviderChooserIntent</code> <ul> - <li>Non-instantiable utility class - </li> - - <li>Includes a method that a watch face can call for starting a - provider chooser (to allow a user to configure complications) + <li>Non-instantiable utility class that is not commonly used; use + <code>ComplicationHelperActivity</code> instead </li> </ul> </li> @@ -789,6 +1261,16 @@ METADATA_KEY_PROVIDER_CONFIG_ACTION </li> </ul> </li> + + <li> + <code>SystemProviders</code> + <ul> + <li>Lists system providers that are considered "safe", + because they only supply information that the watch face + already could obtain itself + </li> + </ul> + </li> </ul> <p> diff --git a/docs/html/wear/preview/features/notifications.jd b/docs/html/wear/preview/features/notifications.jd index dcc09709deb3..b546978a8b9c 100644 --- a/docs/html/wear/preview/features/notifications.jd +++ b/docs/html/wear/preview/features/notifications.jd @@ -1,6 +1,5 @@ page.title=Notification Changes in Android Wear 2.0 -meta.tags="wear", "wear-preview", "notifications" -page.tags="wear" +meta.tags="wear", "wear-preview", "notifications" page.tags="wear" page.image=/wear/preview/images/expanded_diagram.png @@ -12,6 +11,7 @@ page.image=/wear/preview/images/expanded_diagram.png <h2>This document includes</h2> <ol> <li><a href="#visual">Visual Updates</a></li> + <li><a href="#inline">Inline Action</a></li> <li><a href="#expanded">Expanded Notifications</a></li> <li><a href="#messaging">MessagingStyle</a></li> </ol> @@ -67,7 +67,8 @@ material design</a> visual changes. We recommended that you don't set color for bridged notifications. When Wear apps post local notifications, you can work around this by checking - <a href="{@docRoot}training/basics/supporting-devices/platforms.html#version-codes">the API level of the device</a> they're running on and using an appropriate color + <a href="{@docRoot}training/basics/supporting-devices/platforms.html#version-codes">the API level of the device</a> + they're running on and using an appropriate color for Wear 1.x and a different color for Wear 2.0. </li> @@ -77,6 +78,85 @@ material design</a> visual changes. you must update the text of your notification. </li> </ul> + +<h2 id="inline">Inline Action</h3> + +<img src="{@docRoot}wear/preview/images/inline_action.png" style="float:right;margin:10px 20px 0 0"> +<p> + Wear 2.0 now supports inline action, which allows users to take actions on a + notification from within the notification stream card. On Wear, the inline + action appears as an additional button displayed at the bottom of the notification. +</p> +<p> + Inline actions are optional but recommended for cases in which users are likely + to take an action on a notification after viewing the contents in the + notification stream card (without going to the + <a href= "{@docRoot}wear/preview/features/notifications.html#expanded">expanded notification</a>). + Examples of good use cases for inline action on a notification include: replying to a + text message, stopping a fitness activity, and archiving an email message. +</p> + +<p> + A notification can provide only one inline action. + To display the inline action as an additional button in the notification, set + the <a href="https://developer.android.com/reference/android/support/v4/app/NotificationCompat.Action.WearableExtender.html#setHintDisplayActionInline(boolean)">{@code setHintDisplayActionInline()}</a> + method to true. When a user taps the inline action, the system invokes + the intent that you specified in the notification action. +</p> + +<h3>Adding an inline action</h3> +<p> + The following code example shows how to create a notification with an inline + reply action: +</p> + +<ol> + <li>Create an instance of + <a href="https://developer.android.com/reference/android/support/v4/app/RemoteInput.Builder.html">{@code RemoteInput.Builder}</a></code> + that you can add to your notification action. This class's constructor accepts a + string that the system uses as the key for the text input. Later, your app + uses that key to retrieve the text of the input. + +<pre> +String[] choices = context.getResources().getStringArray(R.array.notification_reply_choices); + choices = WearUtil.addEmojisToCannedResponse(choices); + RemoteInput remoteInput = new RemoteInput.Builder(Intent.EXTRA_TEXT) + .setLabel(context.getString(R.string.notification_prompt_reply)) + .setChoices(choices) + .build(); +</pre> + + </li> + + <li> + Use the <a href="https://developer.android.com/reference/android/support/v4/app/NotificationCompat.Action.Builder.html#addRemoteInput(android.support.v4.app.RemoteInput)">{@code addRemoteInput()}</a> + method to attach the <ahref="https://developer.android.com/reference/android/support/v4/app/RemoteInput.html">{@code RemoteInput}</a> + object to an action. + +<pre> +NotificationCompat.Action.Builder actionBuilder = new NotificationCompat.Action.Builder( + R.drawable.ic_full_reply, R.string.notification_reply, replyPendingIntent); + actionBuilder.addRemoteInput(remoteInput); + actionBuilder.setAllowGeneratedReplies(true); +</pre> + </li> + + <li> + Add a hint to display the reply action inline, and use the + <a href="https://developer.android.com/reference/android/support/v4/app/NotificationCompat.WearableExtender.html#addAction(android.support.v4.app.NotificationCompat.Action)">{@code addAction}</a> + method to add this action to the notification. + +<pre> +// Android Wear 2.0 requires a hint to display the reply action inline. + Action.WearableExtender actionExtender = + new Action.WearableExtender() + .setHintLaunchesActivity(true) + .setHintDisplayActionInline(true); + wearableExtender.addAction(actionBuilder.extend(actionExtender).build()); +</pre> + </li> +</ol> + <h2 id="expanded">Expanded Notifications</h2> <p>Android Wear 2.0 introduces <i>expanded notifications</i>, which provide substantial additional content and actions for each notification. @@ -152,51 +232,52 @@ action in the notification unless a different action is specified using </p> <h2 id="messaging">MessagingStyle</h2> -<p>If you have a chat messaging app, your notifications should use -<a href="{@docRoot}preview/features/notification-updates.html#style">{@code Notification.MessagingStyle}</a>, - which is new in Android N. Wear 2.0 uses the chat messages included - in a <a href="{@docRoot}preview/features/notification-updates.html#style">{@code MessagingStyle}</a> notification - - (see <a href="{@docRoot}preview/features/notification-updates.html#style">{@code addMessage()}</a>) to provide - a rich chat app-like experience in the expanded notification. +<p> + If you have a chat messaging app, your notifications should use + <a href="https://developer.android.com/reference/android/support/v4/app/NotificationCompat.MessagingStyle.html">{@code NotificationCompat.MessagingStyle}</a>, + which is new in Android 7.0. Wear 2.0 uses the chat messages included in a + {@code MessagingStyle} notification + (see <a href="https://developer.android.com/reference/android/support/v4/app/NotificationCompat.MessagingStyle.html#addMessage(android.support.v4.app.NotificationCompat.MessagingStyle.Message)">{@code addMessage()}</a>) + to provide a rich chat app-like experience in the expanded notification. </p> -<p class="note">Note: <a href="{@docRoot}preview/features/notification-updates.html#style">{@code MessagingStyle}</a> +<p class="note">Note: <a href="https://developer.android.com/reference/android/support/v4/app/NotificationCompat.MessagingStyle.html">{@code MessagingStyle}</a> expanded notifications require that you have at least version 1.5.0.2861804 of the <a href="https://play.google.com/store/apps/details?id=com.google.android.wearable.app">Android Wear app</a> - on your paired Android phone. That version will be available within the next - few weeks in the Play Store. + on your paired Android phone. </p> <h3 id="smart-reply">Smart Reply</h3> <img src="{@docRoot}wear/preview/images/messaging_style.png" height="420" style="float:right;margin:10px 20px 0 0" /> -<p>Wear 2.0 also introduces <i>Smart Reply</i> -for <a href="{@docRoot}preview/features/notification-updates.html#style">{@code MessagingStyle}</a> notifications. +<p>Wear 2.0 also introduces <i>Smart Reply</i> for + <a href="https://developer.android.com/reference/android/support/v4/app/NotificationCompat.MessagingStyle.html">{@code MessagingStyle}</a> notifications. Smart Reply provides the user with contextually relevant, touchable choices in the expanded notification and in {@code RemoteInput}. These augment the fixed list of choices that the developer provides in - <a href="http://developer.android.com/reference/android/support/v4/app/RemoteInput.html">{@code RemoteInput}</a> - using the - <a href="{@docRoot}reference/android/support/v4/app/RemoteInput.Builder.html#setChoices(java.lang.CharSequence[])">{@code setChoices()}</a> method. + <a href="http://developer.android.com/reference/android/support/v4/app/RemoteInput.html">{@code RemoteInput}</a> + using the + <a href="{@docRoot}reference/android/support/v4/app/RemoteInput.Builder.html#setChoices(java.lang.CharSequence[])">{@code setChoices()}</a> method. </p> -<p>By enabling Smart Reply for your MessagingStyle notifications, - you provide users with a fast (single tap), discreet (no speaking aloud), and - reliable way to respond to chat messages. +<p> Smart Reply provides users with a fast (single tap), discreet (no speaking aloud), + private (messages received by a user never leave the watch), and reliable (no + internet connection needed) way to respond to chat messages. </p> -<p>Responses generated by Smart Reply are shown in addition to those set using the - <a href="{@docRoot}reference/android/support/v4/app/RemoteInput.Builder.html#setChoices(java.lang.CharSequence[])">{@code setChoices()}</a> method. +<p> + Smart Reply responses are generated by an entirely on-watch machine learning + model using the context provided by the MessagingStyle notification. No user + notification data is sent to Google servers to generate Smart Reply responses. </p> + <p>To enable Smart Reply for your notification action, you need to do the following: </p> <ol> - <li>Use <a href="{@docRoot}preview/features/notification-updates.html#style">{@code Notification.MessagingStyle}</a>. + <li>Use <a href="https://developer.android.com/reference/android/support/v4/app/NotificationCompat.MessagingStyle.html">{@code NotificationCompat.MessagingStyle}</a>. </li> - <li>Call the method {@code setAllowGeneratedReplies()} for the notification action. - For more information, see the downloadable - <a href="{@docRoot}preview/setup-sdk.html#docs-dl">API reference</a>. + <li>Call the method <a href="https://developer.android.com/reference/android/support/v4/app/NotificationCompat.Action.Builder.html#setAllowGeneratedReplies(boolean)">{@code setAllowGeneratedReplies(true)}</a> + for the notification action. </li> <li>Ensure that the notification action has a <a href="{@docRoot}reference/android/app/RemoteInput.html">{@code RemoteInput}</a> @@ -236,3 +317,29 @@ Notification noti = new NotificationCompat.Builder() // 3) add an action with RemoteInput .extend(new WearableExtender().addAction(action)).build(); </pre> + +<h3 id="images">Adding images to a MessagingStyle notification</h3> +<p> + You can add images to a notification message by setting the appropriate MIME + type and placing the URI to the image in {@code NotificationCompat.MessagingStyle.Message.} + <a href="https://developer.android.com/reference/android/support/v4/app/NotificationCompat.MessagingStyle.Message.html#setData(java.lang.String, android.net.Uri)">{@code setData()}</a> method. +</p> +<p> + Here is the code snippet to set data of type image in a notification: +</p> +<pre> +NotificationCompat.MessagingStyle.Message message = new Message("sticker", 1, "Jeff") + .setData("image/png", stickerUri); + + NotificationCompat notification = new NotificationCompat.Builder() + .setStyle(new NotificationComapt.MessagingStyle("Me") + .addMessage(message) + .build()); + +</pre> +<p> + In the above code snippet the variable <code>stickerUri </code>is a Uri that + points to a publicly-accessible location, as described <a + href="https://developer.android.com/reference/android/support/v4/app/NotificationCompat.MessagingStyle.Message.html">here + </a>. +</p>
\ No newline at end of file diff --git a/docs/html/wear/preview/features/standalone-apps.jd b/docs/html/wear/preview/features/standalone-apps.jd new file mode 100644 index 000000000000..5c1930dedf86 --- /dev/null +++ b/docs/html/wear/preview/features/standalone-apps.jd @@ -0,0 +1,499 @@ +page.title=Standalone Apps +meta.keywords="wear-preview" +page.tags="wear-preview" +page.image=images/cards/card-n-sdk_2x.png + +@jd:body + +<div id="qv-wrapper"> +<div id="qv"> + +<h2>In this document</h2> + + <ul> + <li><a href="#planning_apps">Planning Your Phone and Watch Apps</a></li> + <li><a href="#network_access">Network Access and Cloud Messaging</a></li> + <li><a href="#background_services">Using Background Services</a></li> + <li><a href="#fcm">Cloud Notifications Using FCM</a></li> + <li><a href="#fcm-phone">Notifications from a Companion Phone</a></li> + </ul> + +</div> +</div> + + <p> + In Android Wear 2.0, apps can work independently of a phone. Users can + complete more tasks on a watch, without access to an Android or iOS + phone. + </p> + + <h2 id="planning_apps"> + Planning Your Phone and Watch Apps + </h2> + + <p> + A watch APK targeting Wear 2.0 should not be embedded in a phone APK. + For more information, see + <a href="{@docRoot}wear/preview/features/app-distribution.html"> + App Distribution</a>. + </p> + + <p> + Generally, the minimum and target API level for a standalone app, and + for Wear 2.0, is level 24. The minimum SDK level can be 23 + only if you are using the same APK + for Wear 1.0 and 2.0 (and thus have an embedded Wear 1.0 APK). + </p> + + <p> + If you build a standalone Wear 2.0 APK and will continue to have a + Wear 1.0 APK, please do both of the following: + </p> + + <ul> + <li>Provide a standalone version of the Wear APK, and + </li> + + <li>Continue embedding a version of the Wear APK in your phone APK + </li> + </ul> + + <p> + <strong>Caution</strong>: For the Wear 2.0 Developer Preview, if you + publish an update to your production phone APK that has removed an embedded + Wear APK, production users who update the phone APK before installing + your standalone Wear APK will lose their existing Wear app and its data. + Therefore, it's important that you continue to embed + your watch APK into your phone APK. + </p> + + <p> + <a href= + "https://developer.android.com/training/articles/wear-permissions.html"> + Run-time permissions</a> are required for standalone apps. + </p> + + <h3> + Shared code and data storage + </h3> + + <p> + Code can be shared between a Wear app and a phone app. Optionally, code + that is specific to a form factor can be in a separate module. + </p> + + <p> + For example, common code for networking can be in a shared library. + </p> + + <p> + You can use standard Android storage APIs to store data locally. + For example, you can use + the <a href= + "https://developer.android.com/reference/android/content/SharedPreferences.html"> + SharedPreferences APIs</a>, SQLite, or internal storage (as you would in + the case of a phone). + </p> + + <h3> + Detecting your phone app or watch app + </h3> + + <p> + If a user of your watch app needs your phone app, your watch app can + detect if the phone app is available. Using the <a href= + "https://developers.google.com/android/reference/com/google/android/gms/wearable/CapabilityApi"> + CapabilityApi</a>, your phone app or watch app can advertise its presence + to a paired device. It can do so statically and dynamically. When an app + is on a node in a user's Wear network (i.e., on a phone, paired watch, or + in the cloud), the <code>CapabilityApi</code> enables another + app to detect if it is installed. For more information, see <a href= + "https://developer.android.com/training/wearables/data-layer/messages.html#AdvertiseCapabilities"> + Advertise capabilities</a>. + </p> + + <p> + If your phone app is unavailable, your can check if the Play Store is + available on the phone, as described below, before directing the user to + go to the Play Store (to install your phone app). + </p> + + <h4> + Checking for Play Store availability on a phone + </h4> + + <p> + iPhones and some Android phones lack the Play Store. A standalone Wear + app can check if the paired phone has the Play Store, before directing a + user to go there to install your phone app. The + <code>PlayStoreAvailability</code> class contains a + <code>getPlayStoreAvailabilityOnPhone()</code> method that enables your + Wear app to check if a companion phone has the Play Store. + </p> + + <p> + More information about the <code>PlayStoreAvailability</code> class is + available when you <a href= + "https://developer.android.com/wear/preview/start.html#get_the_preview_reference_documentation"> + download the Android Wear 2.0 Preview Reference</a>. Here is a snippet + that uses the <code>getPlayStoreAvailabilityOnPhone()</code> method to + determine if the paired phone has the Play Store: + </p> + +<pre> +int playStoreAvailabilityOnPhone = +PlayStoreAvailability.getPlayStoreAvailabilityOnPhone(context); +</pre> + + <p> + The value returned by the <code>getPlayStoreAvailabilityOnPhone()</code> + method is one of the following: + </p> + + <table> + <tr> + <th> + <strong>Return value</strong> + </th> + <th> + <strong>Description</strong> + </th> + </tr> + + <tr> + <td> + <code>PLAY_STORE_ON_PHONE_AVAILABLE</code> + </td> + <td> + The Play Store is available on the companion phone. + </td> + </tr> + + <tr> + <td> + <code>PLAY_STORE_ON_PHONE_UNAVAILABLE</code> + </td> + <td> + The Play Store is not available on the companion phone. + </td> + </tr> + + <tr> + <td> + <code>PLAY_STORE_ON_PHONE_ERROR_UNKNOWN</code> + </td> + <td> + An error occurred in the check for the Play Store; another check + should be made later. + </td> + </tr> + </table> + + <h2 id="network_access"> + Network Access and Cloud Messaging + </h2> + + <p> + Android Wear apps can make their own network requests. When a watch has a + Bluetooth connection to a phone, the watch's network traffic is proxied + through the phone. When a phone is unavailable, Wi-Fi and cellular + networks are used, depending on the hardware. The Wear platform handles + transitions between networks. A watch's network access thus does not + require the <a href= + "https://developer.android.com/training/wearables/data-layer/index.html"> + Wearable Data Layer API</a>. + </p> + + <p> + For sending notifications, apps can directly use Firebase Cloud Messaging + (FCM), which replaces Google Cloud Messaging, or continue to use GCM. + </p> + + <p> + No APIs for network access or FCM are specific to Android Wear. + Refer to the existing documentation about <a href= + "https://developer.android.com/training/basics/network-ops/connecting.html"> + connecting to a network</a> and <a href= + "https://developers.google.com/cloud-messaging/">cloud messaging</a>. + </p> + + <p> + You can use protocols such as HTTP, TCP, and UDP. However, + the <a href="https://developer.android.com/reference/android/webkit/package-summary.html"> + android.webkit</a> APIs are not available. Therefore, + use of cookies is available by reading and writing headers on + requests and responses, but the <a href= + "https://developer.androidcom/reference/android/webkit/CookieManager.html"> + CookieManager</a> class is not available. + </p> + + <p> + FCM works well with + <a href="https://developer.android.com/training/monitoring-device-state/doze-standby.html"> + Doze</a>. + </p> + + <p> + Additionally, we recommend using the following: + </p> + + <ul> + <li>The <a href= + "https://developer.android.com/reference/android/app/job/JobScheduler.html"> + JobScheduler</a> API for asynchronous jobs, including polling at + regular intervals (described below) + </li> + + <li>Multi-networking APIs if you need to connect to specific network + types; see <a href= + "https://developer.android.com/about/versions/android-5.0.html#Wireless"> + Multiple Network Connections</a> + </li> + </ul> + + <p> + For foreground use cases, we currently recommend that you make a + request for an unmetered network. Here is an example of using + the multi-networking APIs to request an unmetered network: + </p> + +<pre> +ConnectivityManager.NetworkCallback networkCallback = + new ConnectivityManager.NetworkCallback() { + @Override + public void onAvailable(Network network) { + // access network + } + }; +ConnectivityManager connectivityManager = + (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE); + +connectivityManager.requestNetwork(new NetworkRequest.Builder() + .addCapability(NET_CAPABILITY_NOT_METERED) + .build(), networkCallback); +</pre> + + <p> + We also recommend setting a timer for frontend scenarios + to prevent a user from potentially waiting for a long time. + When the network is no longer needed, or if the timer fires, + the network callback needs to be unregistered: + </p> + +<pre> +connectivityManager.unregisterNetworkCallback(networkCallback): +</pre> + + <p> + A Wear app can communicate with a phone app using the <a href= + "https://developer.android.com/training/wearables/data-layer/index.html">Wearable + Data Layer API</a>, but connecting to a network using that API is + discouraged. + </p> + + <h3 id="necessary_data"> + Obtaining only the necessary data + </h3> + + <p> + When obtaining data from the cloud, get only the necessary data. + Otherwise, you may introduce unnecessary latency, memory use, and battery + use. + </p> + + <p> + When a watch is connected over a Bluetooth LE connection, your app may + have access to a bandwidth of only 10 kilobytes per second. Therefore, + the following steps are recommended: + </p> + + <ul> + <li>Audit your network requests and responses for extra data that only is + for a phone app + </li> + + <li>Shrink large images before sending them over a network to a watch + </li> + </ul> + + <h2 id="background_services"> + Using Background Services + </h2> + + <p> + To ensure that background tasks are correctly executed, they must account + for <a href= + "https://developer.android.com/training/monitoring-device-state/doze-standby.html"> + Doze</a>. In Android 6.0, Doze and App Standby resulted in significant + improvements to battery life by allowing devices to enter deep sleep when + idle and stationary. + </p> + + <p> + Doze is <a href= + "https://developer.android.com/preview/behavior-changes.html#doze">enhanced</a> + in Android Nougat and Android Wear 2.0. When a screen turns off or enters + ambient mode for a long enough time, a subset of Doze can occur and + background tasks may be deferred for certain periods. Later, when a + device is stationary for an extended time, regular Doze occurs. + </p> + + <p> + You should schedule jobs with the <a href= + "https://developer.android.com/reference/android/app/job/JobScheduler.html"> + JobScheduler</a> API, which enables your app to register for Doze-safe + code execution. When scheduling jobs, you can select constraints such as + periodic execution and the need for connectivity or device charging. + It is important to configure jobs in a way that does not adversely + impact battery life. Jobs should use a + <a href="https://developer.android.com/reference/android/app/job/JobInfo.Builder.html"> + JobInfo.Builder</a> object to provide constraints and metadata, e.g. with + one or more of the following methods for a task: + </p> + + <ul> + <li>To schedule a task that requires networking, use + <code>setRequiredNetworkType(int networkType)</code>, specifying + <code>NETWORK_TYPE_ANY</code> or <code>NETWORK_TYPE_UNMETERED</code>; + note that <code>NETWORK_TYPE_UNMETERED</code> is for large data transfers + while <code>NETWORK_TYPE_ANY</code> is for small transfers + </li> + + <li>To schedule a task while charging, use + <code>setRequiresCharging(boolean requiresCharging)</code> + </li> + + <li>For specifying that a device is idle for a task, use + <code>setRequiresDeviceIdle(boolean requiresDeviceIdle)</code>; this + method can be useful for lower-priority background work or + synchronization, especially when used with + <code>setRequiresCharging</code> + </li> + </ul> + + <p> + Note that some low-bandwidth networks, such as Bluetooth LE, are + considered metered. + </p> + + <h3> + Scheduling with constraints + </h3> + + <p> + You can schedule a task that requires constraints. In the example below, + a <code>JobScheduler</code> object activates <code>MyJobService</code> + when the following constraints are met: + </p> + + <ul> + <li>Unmetered networking + </li> + + <li>Device charging + </li> + </ul> + + <p> + You can use the builder method <code>setExtras</code> to attach a bundle + of app-specific metadata to the job request. When your job executes, this + bundle is provided to your job service. Note the <code>MY_JOB_ID</code> + value passed to the <code>JobInfo.Builder</code> constructor. This + <code>MY_JOB_ID</code> value is an app-provided identifier. Subsequent + calls to cancel, and subsequent jobs created with that same value, will + update the existing job: + </p> + +<pre> +JobInfo jobInfo = new JobInfo.Builder(MY_JOB_ID, + new ComponentName(this, MyJobService.class)) + .setRequiredNetworkType(JobInfo.NETWORK_TYPE_UNMETERED) + .setRequiresCharging(true) + .setExtras(extras) + .build(); +((JobScheduler) getSystemService(JOB_SCHEDULER_SERVICE)) + .schedule(jobInfo); +</pre> + + <p> + Below is an implementation of <a href= + "https://developer.android.com/reference/android/app/job/JobService.html"> + JobService</a> to handle the job above. When the job executes, a + <code>JobParameters</code> object is passed into the + <code>onStartJob</code> method. The <code>JobParameters</code> object + enables you to get the job ID value along with any extras bundle provided + when scheduling the job. The <code>onStartJob</code> method is called on + the main application thread, and therefore any expensive logic should be + run from a separate thread. In the example, an <code>AsyncTask</code> is + used to run code in the background. When work is complete, you would call + the <code>jobFinished</code> method to notify <code>JobScheduler</code> + that the task is done: + </p> + +<pre> +public class MyJobService extends JobService { + @Override public boolean onStartJob(JobParameters params) { + new JobAsyncTask().execute(params); + return true; + } + + private class JobAsyncTask extends AsyncTask +</pre> + + <h2 id="fcm"> + Cloud Notifications Using FCM + </h2> + + <p> + FCM is the recommended way to send notifications to a watch. + </p> + + <p> + Provide for messages from FCM by collecting a registration token for a + device when your Wear app runs. Then include the token as part of the + destination when your server sends messages to the FCM REST endpoint. FCM + sends messages to the device identified by the token. + </p> + + <p> + An FCM message is in JSON format and can include one or both of the + following payloads: + </p> + + <ul> + <li> + <strong>Notification payload.</strong> When a notification payload is + received by a watch, the data is displayed to a user directly in the + notification stream. When the user taps the notification, your app is + launched. + </li> + + <li> + <strong>Data payload</strong>. The payload has a set of custom + key/value pairs. The payload and is delivered as data to your Wear app. + </li> + </ul> + + <p> + For more information and examples of payloads, see <a href= + "https://firebase.google.com/docs/cloud-messaging/concept-options">About + FCM Messages</a>. + </p> + + <h2 id="fcm-phone"> + Notifications from a Companion Phone + </h2> + + <p> + By default, notifications are bridged (shared) from a phone app to a + watch. If you have a standalone Wear app and a corresponding phone app, + duplicate notifications can occur. For example, the same notification + from FCM, received by both a phone and a watch, could be + displayed by both devices independently. + </p> + + <p> + For information about preventing duplicate notifications, see <a href= + "https://developer.android.com/wear/preview/features/bridger.html">Bridging + Mode for Notifications</a>. + </p> diff --git a/docs/html/wear/preview/features/wearable-recycler-view.jd b/docs/html/wear/preview/features/wearable-recycler-view.jd new file mode 100644 index 000000000000..f28a4722377e --- /dev/null +++ b/docs/html/wear/preview/features/wearable-recycler-view.jd @@ -0,0 +1,223 @@ + +page.title=Curved Layout +meta.tags="wear", "wear-preview", "RecyclerView" +page.tags="wear" + +@jd:body + + +<div id="qv-wrapper"> +<div id="qv"> + + <h2>In this document</h2> + <ol> + <li><a href="#creating">Creating a Curved Layout</a></li> + <li><a href="#adding">Adding a Circular Scrolling Gesture</a></li> + <li><a href="#aligning">Anchoring Children to the Curve</a></li> + </ol> + +</div> +</div> + + +<p> + Wear 2.0 introduces the {@code WearableRecyclerView} class for displaying + and manipulating a vertical list of items optimized for round displays. + {@code WearableRecyclerView} extends the existing + <a href="{@docRoot}reference/android/support/v7/widget/RecyclerView.html">{@code RecyclerView}</a> + class to provide a curved layout and a circular scrolling gesture in wearable apps. +</p> +<img src="https://android-dot-devsite.googleplex.com/wear/preview/images/wrv_new.png" + style="float:right;margin:10px 20px 0 0"> + +<p> + You can adapt to this interface in your wearable app by creating a new + {@code WearableRecyclerView} container. +</p> + +<p> + You should decide whether to use a {@code WearableRecyclerView}, based on + the kind of user experience you want to provide. We recommend using the + {@code WearableRecyclerView} for a simple, long list of items, such as an + application launcher, or a list contacts. Each item might have a short string + and an associated icon. Alternatively, each item might have only a string or + an icon. We do not recommend using a {@code WearableRecyclerView} for short + or complex lists. +</p> + +<p> + This document describes how to create a curved layout for your scrollable items + and properly align them along the curve. +</p> + + +<h2 id="creating">Creating a Curved Layout</h2> +<p>To create a curved layout for scrollable items in your wearable app: +</p> +<ul> + <li>Use {@code WearableRecyclerView} as your main container in the relevant + xml layout. + </li> + + <li>By default, {@code WearableRecyclerView} uses the {@code + DefaultOffsettingHelper} class to offset items in a curved layout on round + devices. If you wish to implement your own offsetting logic, you can extend the + abstract {@code WearableRecyclerView.OffsettingHelper} class and attach it to + the {@code WearableRecyclerView} using {@code + WearableRecyclerView.setOffsettingHelper} method. + + <pre> + CircularOffsettingHelper circularHelper = new CircularOffsettingHelper(); + mRecyclerView.setOffsettingHelper(circularHelper); + </pre> + + <pre> + public class CircularOffsettingHelper extends OffsettingHelper { + + @Override + public void updateChild(View child, WearableRecyclerView parent) { + int progress = child.getTop() / parent.getHeight(); + child.setTranslationX(-child.getHeight() * progress); + } + } + </pre> + + </li> + +</ul> + +<p class="note"> + <strong>Note:</strong> {@code DefaultOffsettingHelper} class + offsets the child items + along a predefined UX curve, but the operation can cut off part of the child + view if it is not scaled down accordingly. This is because the default curve + attempts to fit 5 items on the screen, regardless of their size. + If you do not wish to scale your items, you should consider additional padding. +</p> + +<h3>Examples</h3> +<p> + The following code example demonstrates how to add {@code WearableRecyclerView} + to a layout: +</p> +<pre> +<android.support.wearable.view.WearableRecyclerView + xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:tools="http://schemas.android.com/tools" + android:id="@+id/recycler_launcher_view" + android:layout_width="match_parent" + android:layout_height="match_parent" + android:scrollbars="vertical" /> + </pre> + + +<p> + To customize the appearance of the children while scrolling (for example, + scale the icons and text while the items scroll away from the center), extend + the {@code DefaultOffsettingHelper} and override the {@code updateChild } + method. It is important to call the {@code super.updateChild(child, parent)} to + offset the children along the curve. However, if for any particular child you do + not wish them to follow a curve, you can chose not to call the super method for + that particular child. +</p> + +<pre> + +public class MyOffsettingHelper extends DefaultOffsettingHelper { + + /** How much should we scale the icon at most. */ + private static final float MAX_ICON_PROGRESS = 0.65f; + + private float mProgressToCenter; + + public OffsettingHelper() {} + + @Override + + public void updateChild(View child, WearableRecyclerView parent) { + super.updateChild(child, parent); + + + // Figure out % progress from top to bottom + float centerOffset = ((float) child.getHeight() / 2.0f) / (float) mParentView.getHeight(); + float yRelativeToCenterOffset = (child.getY() / mParentView.getHeight()) + centerOffset; + + // Normalize for center + mProgressToCenter = Math.abs(0.5f - yRelativeToCenterOffset); + // Adjust to the maximum scale + mProgressToCenter = Math.min(mProgressToCenter, MAX_ICON_PROGRESS); + + child.setScaleX(1 - mProgressToCenter); + child.setScaleY(1 - mProgressToCenter); + } +} + + +</pre> + + +<h2 id="adding">Adding a Circular Scrolling Gesture</h2> + +<p> + By default, circular scrolling is disabled in the {@code + WearableRecyclerView}. If you want to enable circular scrolling gesture + in your child view, use the {@code WearavleRecyclerView}’s {@code + setCircularScrollingGestureEnabled()} method. You can also customize the + circular scrolling gesture by defining one or both of the following: +</p> + +<ul> + <li>How many degrees the user has to rotate by to scroll through one screen height. + This effectively influences the speed of the scolling - + {@code setScrollDegreesPerScreen} - the default value is set at 180 degrees. + </li> + + <li> + The width of a virtual ‘bezel’ near the the edge of the screen in which the + gesture will be recognized - {@code setBezelWidth} - the default value is set + at 1. This is expressed as a fraction of the radius of the view. +</ul> + + +<p>The following code snippet shows how to set these methods:</p> + +<pre> + setCircularScrollingGestureEnabled(true); + setBezelWidth(0.5f); + setScrollDegreesPerScreen(90); +</pre> + +<h2 id="aligning"> Anchoring Children to the Curve </h2> + +<p> + To ensure that the layout for WearableRecyclerView is adaptable to different + types of child views, the WearableRecyclerView class, by default, chooses the + middle left edge (X=0, Y=Half the child height) as the anchor coordinates for + the child item. Using the default anchor coordinates can result in offsetting + the child items from the left edge of the watch face. To customize the anchor + coordinates of your child view along the curve, you can overwrite the + {@code adjustAnchorOffsetXY()} method. You can calculate the X (horizontal) + and Y (vertical) offset of the child item, and set it using the + {@code adjustAnchorOffsetXY()} method to properly align items + along the curve. The coordinates should be with relation to the child view. +</p> + +<p><img src="{@docRoot}wear/preview/images/alignment.png"/></p> +<p><b>Figure 1</b>. Imaginary UX curve and anchor points on the curve.</p> + +<p> + The code snippet below, calculates the X offset for a child item in which the + width of the icon is same as the height of the child item. In this case, the + anchor coordinates for the child item are at the center of the icon. + +</p> +<img src="{@docRoot}wear/preview/images/center_align.png" style="float:left;margin:10px 20px 0 0"/> + +<pre> + @Override + protected void adjustAnchorOffsetXY(View child, float[] anchorOffsetXY) { + anchorOffsetXY[0] = child.getHeight() / 2.0f; + } +</pre> + + diff --git a/docs/html/wear/preview/images/alignment.png b/docs/html/wear/preview/images/alignment.png Binary files differnew file mode 100644 index 000000000000..525b3341789a --- /dev/null +++ b/docs/html/wear/preview/images/alignment.png diff --git a/docs/html/wear/preview/images/apk-details.png b/docs/html/wear/preview/images/apk-details.png Binary files differnew file mode 100644 index 000000000000..eb3b8591f53f --- /dev/null +++ b/docs/html/wear/preview/images/apk-details.png diff --git a/docs/html/wear/preview/images/apk-tabs.png b/docs/html/wear/preview/images/apk-tabs.png Binary files differnew file mode 100644 index 000000000000..949b98f75b7d --- /dev/null +++ b/docs/html/wear/preview/images/apk-tabs.png diff --git a/docs/html/wear/preview/images/center_align.png b/docs/html/wear/preview/images/center_align.png Binary files differnew file mode 100644 index 000000000000..ca88ad77bac4 --- /dev/null +++ b/docs/html/wear/preview/images/center_align.png diff --git a/docs/html/wear/preview/images/current-apk.png b/docs/html/wear/preview/images/current-apk.png Binary files differnew file mode 100644 index 000000000000..2545f925f608 --- /dev/null +++ b/docs/html/wear/preview/images/current-apk.png diff --git a/docs/html/wear/preview/images/inline_action.png b/docs/html/wear/preview/images/inline_action.png Binary files differnew file mode 100644 index 000000000000..7ecaafeb2544 --- /dev/null +++ b/docs/html/wear/preview/images/inline_action.png diff --git a/docs/html/wear/preview/images/wrv_new.png b/docs/html/wear/preview/images/wrv_new.png Binary files differnew file mode 100644 index 000000000000..c413c59a77c3 --- /dev/null +++ b/docs/html/wear/preview/images/wrv_new.png diff --git a/docs/html/wear/preview/program.jd b/docs/html/wear/preview/program.jd index e2bf92f80c6c..4f2fb5cecfb1 100644 --- a/docs/html/wear/preview/program.jd +++ b/docs/html/wear/preview/program.jd @@ -143,8 +143,9 @@ page.image=images/cards/card-n-sdk_2x.png <p> At milestone 4, you'll have access to the final Android Wear 2.0 APIs and SDK to develop with, as well as near-final system images to test - system behaviors and features. Android Wear 2.0 will use the Android N - API level at this time. You can begin final compatibility testing of your + system behaviors and features. Android Wear 2.0 will use the + Android 7.0 API level at this time. + You can begin final compatibility testing of your legacy apps and refine any new code that is using the Android Wear 2.0 APIs or features. </p> diff --git a/docs/html/wear/preview/start.jd b/docs/html/wear/preview/start.jd index 8fccdc82cd5a..c9720dceb842 100644 --- a/docs/html/wear/preview/start.jd +++ b/docs/html/wear/preview/start.jd @@ -29,7 +29,7 @@ page.image=images/cards/card-n-sdk_2x.png <p> If you want an environment for basic compatibility - testing of your app, you can use your current APK and a + testing, you can use your current APK and a supported watch or an emulator. You don't necessarily need to update your full development environment to do basic testing. To simply test your app's compatibility with a preview system image, see <a href= @@ -48,10 +48,8 @@ page.image=images/cards/card-n-sdk_2x.png </h2> <p> - 1. For compatibility with the <a href="{@docRoot}preview/overview.html">N - Developer Preview</a>, follow the <a href= - "{@docRoot}preview/setup-sdk.html">setup instructions</a> for installing - the latest version of Android Studio. + 1. For compatibility with Android 7.0, install the latest version of + <a href="https://developer.android.com/studio/index.html">Android Studio</a>. </p> <p> @@ -63,7 +61,7 @@ page.image=images/cards/card-n-sdk_2x.png <ul> <li>Under the <strong>SDK Platforms tab</strong>: <ul> - <li>Android N Preview + <li>Android 7.0 (Nougat) </li> </ul> </li> @@ -107,10 +105,10 @@ page.image=images/cards/card-n-sdk_2x.png <tr> <td> - <a href="http://storage.googleapis.com/androiddevelopers/shareables/wear-preview/wearable-support-preview-2-docs.zip">wearable-support-preview-2-docs.zip</a> + <a href="http://storage.googleapis.com/androiddevelopers/shareables/wear-preview/wearable-support-preview-3-docs.zip">wearable-support-preview-3-docs.zip</a> </td> - <td>MD5: afb770c9c5c0431bbcbdde186f1eae06<br> - SHA-1: 81d681e61cee01f222ea82e83297d23c4e55b8f3 + <td>MD5: 22bae00e473e39e320aae8ea09a001a5<br> + SHA-1: 474502cc7092bcf0bd671441b8654aa8d6c155ed </td> </tr> </table> @@ -163,7 +161,7 @@ page.image=images/cards/card-n-sdk_2x.png following, which requires that your the Google Repository <a href= "#install_android_studio_and_the_latest_packages">is the latest version</a>: - <code>compile 'com.google.android.support:wearable:2.0.0-alpha2'</code> + <code>compile 'com.google.android.support:wearable:2.0.0-alpha3'</code> </li> </ul> </li> @@ -190,12 +188,12 @@ page.image=images/cards/card-n-sdk_2x.png </li> <li>Optionally, select the <strong>Phone and Tablet</strong> option. If - you plan to use N Preview APIs in a phone app, then the Minimum SDK - option list, select <strong>API N: Android 6.x (N Preview)</strong>. + you plan to use Android 7.0 APIs in a phone app, then the Minimum SDK + option list, select <strong>API 24: Android 7.0 (Nougat)</strong>. </li> <li>Select the <strong>Wear</strong> option, and in the Minimum SDK - option list, select the latest available (<strong>N Preview</strong>) + option list, select the latest available (<strong>API Nougat</strong>) option. Click <strong>Next</strong> until you exit the Create New Project wizard. </li> @@ -215,7 +213,7 @@ page.image=images/cards/card-n-sdk_2x.png following, which requires that your the Google Repository <a href= "#install_android_studio_and_the_latest_packages">is the latest version</a>: - <code>compile 'com.google.android.support:wearable:2.0.0-alpha2'</code> + <code>compile 'com.google.android.support:wearable:2.0.0-alpha3'</code> </li> </ul> </li> diff --git a/docs/html/wear/preview/support.jd b/docs/html/wear/preview/support.jd index 78b4e4b854ac..7636d863aa8c 100644 --- a/docs/html/wear/preview/support.jd +++ b/docs/html/wear/preview/support.jd @@ -23,7 +23,9 @@ page.tags="preview", "developer preview" <ul> <li><a href="#general">General Advisories</a></li> + <li><a href="#platform-version">Platform API Version</a></li> <li><a href="#deprecations">Deprecations</a></li> + <li><a href="#dp3">Developer Preview 3</a></li> <li><a href="#dp2">Developer Preview 2</a></li> <li><a href="#dp1">Developer Preview 1</a></li> </ul> @@ -46,10 +48,25 @@ page.tags="preview", "developer preview" panics and crashes. </li> <li>Some apps <strong>may not function as expected</strong> on the new - platform version. This includes Google’s apps and other apps. + platform version. This includes Google's apps and other apps. </li> </ul> +<h2 id="platform-version"> + Platform API Version +</h2> + +<p> + The Android Platform API version is incremented to 24 to match Android 7.0. + You can update the following in your Android Wear 2.0 Preview project + to <strong>24</strong>: +</p> + +<ul> + <li><code>compileSdkVersion</code></li> + <li><code>targetSdkVersion</code></li> +</ul> + <h2 id="deprecations">Deprecations</h2> <p>The following fields are deprecated in the preview:</p> @@ -64,6 +81,275 @@ page.tags="preview", "developer preview" </li> </ul> +<h2 id="dp3">Developer Preview 3</h2> + +<div class="wrap"> + <div class="cols"> + <div class="col-6of12"> + <p><em>Date: September 2016<br /> + Builds: Wearable Support 2.0.0-alpha3, NVE68J<br/> + Emulator support: x86 & ARM (32-bit)<br/> + </em></p> + </div> + </div> +</div> + +<h3 id="new-in-fdp3"> + New in Preview 3 +</h3> + + <p> + For access to system images and the companion app for Preview 3, see + <a href="https://developer.android.com/wear/preview/downloads.html"> + Download and Test with a Device</a>. + </p> + + <h4> + Additions for standalone apps and the Play Store on Wear + </h4> + + <p> + For information about planning your Wear 2.0 app, see <a href= + "https://developer.android.com/wear/preview/features/standalone-apps.html"> + Standalone Apps</a>. + </p> + + <p> + Generally, the minimum and target SDK level for Wear 2.0, and for a + standalone APK, is level 24. The minimum SDK level can be 23 + only if you are using the same APK + for Wear 1.0 and 2.0 (and thus have an embedded Wear 1.0 APK). + </p> + + <p> + Run-time permissions are required. + </p> + + <p> + For information about distributing your Wear 2.0 app, see <a href= + "https://developer.android.com/wear/preview/features/app-distribution.html"> + App Distribution</a>. + </p> + + <h4 id="additions-to-the-complications-api"> + Complications API additions + </h4> + + <p> + For Preview 3, additions and changes have been made to the Complications + API. The <a href= + "https://developer.android.com/wear/preview/features/complications.html">documentation</a> + includes information about the following additions and changes: + </p> + + <ul> + <li>To receive complication data and open the provider chooser, a watch + face must have the <code>RECEIVE_COMPLICATION_DATA</code> permission. + </li> + + <li>To ease a request for the new permission and the starting of the + chooser, the <code>ComplicationHelperActivity</code> class is available + in the wearable support library. This class should be used instead of + <code>ProviderChooserIntent</code> to start the chooser in almost all + cases. + </li> + + <li>Watch faces can specify default providers that are used until a user + selects a provider. + </li> + + <li>The complication types used for "empty" data are changed. + </li> + + <li>A new permission was added to ensure that only the Android Wear + system can bind to provider services. + </li> + </ul> + + <p> + For changes related to the <code>ComplicationData</code> object, see + <a href= + "https://developer.android.com/wear/preview/behavior-changes.html">Behavior + Changes</a>. + </p> + + <h4 id="wearable-recycler-view-api"> + Curved Layout + </h4> + + <p> + For information about creating a curved layout using + the <code>WearableRecyclerView</code> API in your Wear 2.0 app, see + <a href="https://developer.android.com/wear/preview/features/wearable-recycler-view.html"> + Curved Layout</a>. + </p> + + <h4 id="notifications-features-fdp3"> + Notifications features + </h4> + + <p> + To learn about adding an inline action to a notification, + see <a href="https://developer.android.com/wear/preview/notifications.html#inline">Inline + Action</a>. + </p> + + <p> + To learn about adding images to a notification, see + <a href= + "https://developer.android.com/wear/preview/notifications.html#images">Adding + images to a notification</a>. + </p> + + <p> + For additions related to the bridging of notifications from a companion + app to a watch, see <a href= + "https://developer.android.com/wear/preview/features/bridger.html">Bridging + Mode for Notifications</a>. + </p> + + <h4 id="additions-for-smart-reply"> + Smart Reply additions + </h4> + + <p> + Smart Reply responses are generated by an entirely on-watch, + machine-learning model using the context provided by <a href= + "https://developer.android.com/wear/preview/features/notifications.html#messaging"> + MessagingStyle</a> notifications. Use the <a href= + "https://developer.android.com/reference/android/support/v4/app/NotificationCompat.Action.Builder.html#setAllowGeneratedReplies(boolean)"> + setAllowGeneratedReplies(boolean)</a> method to enable Smart Reply for + your <code>MessagingStyle</code> notification. + </p> + + <h3 id="known-issues-3"> + Known Issues + </h3> + + <h4 id="notifications"> + Notifications + </h4> + + <ul> + <li>The <code>MessagingStyle</code> <a href= + "https://developer.android.com/wear/preview/features/notifications.html#images"> + notifications with images</a> posted by standalone apps don't show + images in the notification (i.e., bridged notifications show images, + but standalone notifications don't). + </li> + + <li>This preview release does not include support for notification + groups. + </li> + + <li>With Wear 2.0, a watch can receive notifications directly from + Firebase Cloud Messaging (FCM), which replaces Google Cloud Messaging + (GCM). However, in Preview 3 of Wear 2.0, FCM does not function with + iOS-paired watches. + </li> + + <li>Smart Reply responses are only shown in <code>RemoteInput</code> when + <code>RemoteInput</code> is called from a <code>MessagingStyle</code> + expanded notification. Smart Reply responses are not shown in + <code>RemoteInput</code> when <code>RemoteInput</code> is called from an + <a href= + "https://developer.android.com/wear/preview/features/notifications.html#inline"> + inline action</a> within the stream—an action set with the <a href= + "https://developer.android.com/reference/android/support/v4/app/NotificationCompat.Action.WearableExtender.html#setHintDisplayActionInline(boolean)"> + setHintDisplayActionInline(true)</a> method. + </li> + </ul> + + <h4 id="companion-app"> + Companion app + </h4> + + <ul> + <li>The preview companion app is not compatible with Android 4.3 + (Jelly Bean MR2), which has an SDK build version code of: + <code>JELLY_BEAN_MR2</code></li> + </ul> + + <ul> + <li>In permission screens in the preview companion app: + If you deny a permission, you cannot + proceed. Instead of denying a permission, tap <strong>Skip</strong>. + </li> + </ul> + + + <h4 id="developer-console"> + Developer Console + </h4> + + <ul> + <li>If you set a minimum SDK version of 24, the Play Developer Console + states that there are few supported devices. + </li> + </ul> + + <h4 id="system-user-interface"> + System user interface and apps + </h4> + + <ul> + <li>Dismissing multiple notifications can cause an app to forcibly close. + </li> + + <li>The "Ok Google" detection and voice transcription may not work + reliably. + </li> + + <li>Google Fit is not available with Preview 3. + </li> + + <li>Syncing for embedded apps is not enabled for the preview. Therefore, + to test an app on a device, add it to the Play Store or side-load it + onto a watch. Some existing Wear apps, e.g. Google Maps, are only + using the embedded apps mechanism currently, and are therefore not + installable on the preview (and therefore do not appear on the watch). + </li> + + <li>In Play Store search results on the watch, + results other than apps sometimes appear. + </li> + + <li>Media controls/notifications are not bridged + to the watch from an Android KitKat phone. + </li> + </ul> + + <h4 id="devices"> + Devices + </h4> + + <ul> + <li>In Android Wear emulators, the Play Store app requires that an + account is synced to the device before the app can be opened. + </li> + + <li>On the Huawei Watch, selecting the language, followed by multiple + acknowledgement dialogues, results in a black screen. + </li> + + <li>On the LG Watch Urbane 2nd Edition, when answering a call from the + watch, the watch does not provide audio from the caller. + </li> + </ul> + + <h4 id="smart-reply"> + Smart Reply + </h4> + + <ul> + <li>Smart Reply is only available if your watch's system language is + English. + </li> + + <li>Smart Reply responses are not generated for all messages. + </li> + </ul> + <h2 id="dp2">Developer Preview 2</h2> <div class="wrap"> @@ -78,24 +364,9 @@ page.tags="preview", "developer preview" </div> <h3 id="new-in-fdp2"> - <strong>New in Preview 2</strong> + New in Preview 2 </h3> -<h4 id="platform-version-24"> - Platform API Version -</h4> - -<p> - The Android Platform API version is incremented to 24 to match Android Nougat. - You can update the following in your Android Wear 2.0 Preview project - to <strong>24</strong>: -</p> - -<ul> - <li><code>compileSdkVersion</code></li> - <li><code>targetSdkVersion</code></li> -</ul> - <h4 id="wearable-drawers"> Wearable drawers </h4> @@ -174,7 +445,7 @@ page.tags="preview", "developer preview" </p> <h3 id="known-issues-2"> - <strong>Known Issues</strong> + Known Issues </h3> <h4 id="notifications-2"> @@ -239,6 +510,10 @@ page.tags="preview", "developer preview" <li>Unable to turn off the Wi-Fi on a wearable. </li> + + <li>After music is played on a companion phone, + music card notifications are not mirrored to the watch. + </li> </ul> <h4 id="companion-app-2"> diff --git a/media/java/android/media/MediaRouter.java b/media/java/android/media/MediaRouter.java index 96ea8349627f..06dd3db9ab4f 100644 --- a/media/java/android/media/MediaRouter.java +++ b/media/java/android/media/MediaRouter.java @@ -219,12 +219,25 @@ public class MediaRouter { } if (mBluetoothA2dpRoute != null) { - if (mSelectedRoute == mDefaultAudioVideo || mSelectedRoute == null) { + final boolean a2dpEnabled = isBluetoothA2dpOn(); + if (mSelectedRoute == mBluetoothA2dpRoute && !a2dpEnabled) { + selectRouteStatic(ROUTE_TYPE_LIVE_AUDIO, mDefaultAudioVideo, false); + } else if ((mSelectedRoute == mDefaultAudioVideo || mSelectedRoute == null) && + a2dpEnabled) { selectRouteStatic(ROUTE_TYPE_LIVE_AUDIO, mBluetoothA2dpRoute, false); } } } + boolean isBluetoothA2dpOn() { + try { + return mAudioService.isBluetoothA2dpOn(); + } catch (RemoteException e) { + Log.e(TAG, "Error querying Bluetooth A2DP state", e); + return false; + } + } + void updateDiscoveryRequest() { // What are we looking for today? int routeTypes = 0; @@ -893,11 +906,6 @@ public class MediaRouter { static void selectRouteStatic(int types, @NonNull RouteInfo route, boolean explicit) { Log.v(TAG, "Selecting route: " + route); assert(route != null); - if (route == sStatic.mDefaultAudioVideo && sStatic.mBluetoothA2dpRoute != null) { - Log.i(TAG, "Change the route to a BT route: " + sStatic.mBluetoothA2dpRoute - + "\nDo not select the default route when a BT route is available."); - route = sStatic.mBluetoothA2dpRoute; - } final RouteInfo oldRoute = sStatic.mSelectedRoute; if (oldRoute == route) return; if (!route.matchesTypes(types)) { @@ -907,6 +915,16 @@ public class MediaRouter { return; } + final RouteInfo btRoute = sStatic.mBluetoothA2dpRoute; + if (btRoute != null && (types & ROUTE_TYPE_LIVE_AUDIO) != 0 && + (route == btRoute || route == sStatic.mDefaultAudioVideo)) { + try { + sStatic.mAudioService.setBluetoothA2dpOn(route == btRoute); + } catch (RemoteException e) { + Log.e(TAG, "Error changing Bluetooth A2DP state", e); + } + } + final WifiDisplay activeDisplay = sStatic.mDisplayService.getWifiDisplayStatus().getActiveDisplay(); final boolean oldRouteHasAddress = oldRoute != null && oldRoute.mDeviceAddress != null; @@ -946,7 +964,7 @@ public class MediaRouter { static void selectDefaultRouteStatic() { // TODO: Be smarter about the route types here; this selects for all valid. if (sStatic.mSelectedRoute != sStatic.mBluetoothA2dpRoute - && sStatic.mBluetoothA2dpRoute != null) { + && sStatic.mBluetoothA2dpRoute != null && sStatic.isBluetoothA2dpOn()) { selectRouteStatic(ROUTE_TYPE_ANY, sStatic.mBluetoothA2dpRoute, false); } else { selectRouteStatic(ROUTE_TYPE_ANY, sStatic.mDefaultAudioVideo, false); @@ -1278,7 +1296,12 @@ public class MediaRouter { selectedRoute == sStatic.mDefaultAudioVideo) { dispatchRouteVolumeChanged(selectedRoute); } else if (sStatic.mBluetoothA2dpRoute != null) { - dispatchRouteVolumeChanged(sStatic.mBluetoothA2dpRoute); + try { + dispatchRouteVolumeChanged(sStatic.mAudioService.isBluetoothA2dpOn() ? + sStatic.mBluetoothA2dpRoute : sStatic.mDefaultAudioVideo); + } catch (RemoteException e) { + Log.e(TAG, "Error checking Bluetooth A2DP state to report volume change", e); + } } else { dispatchRouteVolumeChanged(sStatic.mDefaultAudioVideo); } diff --git a/media/java/android/media/RingtoneManager.java b/media/java/android/media/RingtoneManager.java index af1410bf7965..3cb01de7513d 100644 --- a/media/java/android/media/RingtoneManager.java +++ b/media/java/android/media/RingtoneManager.java @@ -727,7 +727,9 @@ public class RingtoneManager { String setting = getSettingForType(type); if (setting == null) return; - ringtoneUri = ContentProvider.maybeAddUserId(ringtoneUri, context.getUserId()); + if(!isInternalRingtoneUri(ringtoneUri)) { + ringtoneUri = ContentProvider.maybeAddUserId(ringtoneUri, context.getUserId()); + } Settings.System.putStringForUser(resolver, setting, ringtoneUri != null ? ringtoneUri.toString() : null, context.getUserId()); @@ -744,6 +746,12 @@ public class RingtoneManager { } } + private static boolean isInternalRingtoneUri(Uri uri) { + Uri uriWithoutUserId = ContentProvider.getUriWithoutUserId(uri); + return uriWithoutUserId == null ? false : uriWithoutUserId.toString() + .startsWith(MediaStore.Audio.Media.INTERNAL_CONTENT_URI.toString()); + } + /** * Try opening the given ringtone locally first, but failover to * {@link IRingtonePlayer} if we can't access it directly. Typically happens diff --git a/packages/SettingsLib/res/values-ja/strings.xml b/packages/SettingsLib/res/values-ja/strings.xml index 812f53d28456..f657c1e21687 100644 --- a/packages/SettingsLib/res/values-ja/strings.xml +++ b/packages/SettingsLib/res/values-ja/strings.xml @@ -28,10 +28,8 @@ <string name="wifi_disabled_wifi_failure" msgid="3081668066612876581">"WiFi接続エラー"</string> <string name="wifi_disabled_password_failure" msgid="8659805351763133575">"認証に問題"</string> <string name="wifi_not_in_range" msgid="1136191511238508967">"圏外"</string> - <!-- no translation found for wifi_no_internet_no_reconnect (2211781637653149657) --> - <skip /> - <!-- no translation found for wifi_no_internet (5011955173375805204) --> - <skip /> + <string name="wifi_no_internet_no_reconnect" msgid="2211781637653149657">"インターネット アクセスを検出できないため、自動的に再接続されません。"</string> + <string name="wifi_no_internet" msgid="5011955173375805204">"インターネットに接続していません。"</string> <string name="saved_network" msgid="4352716707126620811">"<xliff:g id="NAME">%1$s</xliff:g>で保存"</string> <string name="connected_via_wfa" msgid="3805736726317410714">"Wi‑Fiアシスタント経由で接続"</string> <string name="connected_via_passpoint" msgid="2826205693803088747">"%1$s経由で接続"</string> diff --git a/packages/SystemUI/plugin/ExamplePlugin/AndroidManifest.xml b/packages/SystemUI/plugin/ExamplePlugin/AndroidManifest.xml index bd2c71c38f5a..ff89bbcb455f 100644 --- a/packages/SystemUI/plugin/ExamplePlugin/AndroidManifest.xml +++ b/packages/SystemUI/plugin/ExamplePlugin/AndroidManifest.xml @@ -21,7 +21,15 @@ <uses-permission android:name="com.android.systemui.permission.PLUGIN" /> <application> - <service android:name=".SampleOverlayPlugin"> + <activity android:name=".PluginSettings" + android:label="@string/plugin_label"> + <intent-filter> + <action android:name="com.android.systemui.action.PLUGIN_SETTINGS" /> + </intent-filter> + </activity> + + <service android:name=".SampleOverlayPlugin" + android:label="@string/plugin_label"> <intent-filter> <action android:name="com.android.systemui.action.PLUGIN_OVERLAY" /> </intent-filter> diff --git a/packages/SystemUI/plugin/ExamplePlugin/res/layout/plugin_settings.xml b/packages/SystemUI/plugin/ExamplePlugin/res/layout/plugin_settings.xml new file mode 100644 index 000000000000..eb90283f08d0 --- /dev/null +++ b/packages/SystemUI/plugin/ExamplePlugin/res/layout/plugin_settings.xml @@ -0,0 +1,24 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- +** Copyright 2016, The Android Open Source Project +** +** Licensed under the Apache License, Version 2.0 (the "License"); +** you may not use this file except in compliance with the License. +** You may obtain a copy of the License at +** +** http://www.apache.org/licenses/LICENSE-2.0 +** +** Unless required by applicable law or agreed to in writing, software +** distributed under the License is distributed on an "AS IS" BASIS, +** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +** See the License for the specific language governing permissions and +** limitations under the License. +--> + +<TextView + xmlns:android="http://schemas.android.com/apk/res/android" + android:layout_width="match_parent" + android:layout_height="match_parent" + android:textAppearance="?android:attr/textAppearanceLarge" + android:text="@string/plugin_settings_here" + android:gravity="center" /> diff --git a/packages/SystemUI/plugin/ExamplePlugin/res/values/strings.xml b/packages/SystemUI/plugin/ExamplePlugin/res/values/strings.xml new file mode 100644 index 000000000000..a0bfe849e5c6 --- /dev/null +++ b/packages/SystemUI/plugin/ExamplePlugin/res/values/strings.xml @@ -0,0 +1,24 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- +/** + * Copyright (c) 2016, 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:xliff="urn:oasis:names:tc:xliff:document:1.2"> + + <string name="plugin_settings_here" translatable="false">Plugin settings go here</string> + <string name="plugin_label" translatable="false">Overlay Plugin</string> + +</resources> diff --git a/packages/SystemUI/plugin/ExamplePlugin/src/com/android/systemui/plugin/testoverlayplugin/PluginSettings.java b/packages/SystemUI/plugin/ExamplePlugin/src/com/android/systemui/plugin/testoverlayplugin/PluginSettings.java new file mode 100644 index 000000000000..cf39075d958f --- /dev/null +++ b/packages/SystemUI/plugin/ExamplePlugin/src/com/android/systemui/plugin/testoverlayplugin/PluginSettings.java @@ -0,0 +1,32 @@ +/* + * Copyright (C) 2016 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the + * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +package com.android.systemui.plugin.testoverlayplugin; + +import android.annotation.Nullable; +import android.app.Activity; +import android.os.Bundle; + +/** + * DO NOT Reference Plugin interfaces here, this runs in the plugin APK's process + * and is only for modifying settings. + */ +public class PluginSettings extends Activity { + + @Override + public void onCreate(@Nullable Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.plugin_settings); + } +} diff --git a/packages/SystemUI/plugin/src/com/android/systemui/plugins/PluginInstanceManager.java b/packages/SystemUI/plugin/src/com/android/systemui/plugins/PluginInstanceManager.java index 2a7139c3a74c..495771a3c8ec 100644 --- a/packages/SystemUI/plugin/src/com/android/systemui/plugins/PluginInstanceManager.java +++ b/packages/SystemUI/plugin/src/com/android/systemui/plugins/PluginInstanceManager.java @@ -24,7 +24,6 @@ import android.content.pm.ApplicationInfo; import android.content.pm.PackageManager; import android.content.pm.ResolveInfo; import android.net.Uri; -import android.os.AsyncTask; import android.os.Build; import android.os.Handler; import android.os.Looper; @@ -163,6 +162,7 @@ public class PluginInstanceManager<T extends Plugin> extends BroadcastReceiver { switch (msg.what) { case PLUGIN_CONNECTED: if (DEBUG) Log.d(TAG, "onPluginConnected"); + PluginPrefs.setHasPlugins(mContext); PluginInfo<T> info = (PluginInfo<T>) msg.obj; info.mPlugin.onCreate(mContext, info.mPluginContext); mListener.onPluginConnected(info.mPlugin); diff --git a/packages/SystemUI/plugin/src/com/android/systemui/plugins/PluginManager.java b/packages/SystemUI/plugin/src/com/android/systemui/plugins/PluginManager.java index aa0b3c586747..4bf6494995bc 100644 --- a/packages/SystemUI/plugin/src/com/android/systemui/plugins/PluginManager.java +++ b/packages/SystemUI/plugin/src/com/android/systemui/plugins/PluginManager.java @@ -37,6 +37,7 @@ public class PluginManager { private final Context mContext; private final PluginInstanceManagerFactory mFactory; private final boolean isDebuggable; + private final PluginPrefs mPluginPrefs; private PluginManager(Context context) { this(context, new PluginInstanceManagerFactory(), Build.IS_DEBUGGABLE, @@ -51,6 +52,7 @@ public class PluginManager { mBackgroundThread = new HandlerThread("Plugins"); mBackgroundThread.start(); isDebuggable = debuggable; + mPluginPrefs = new PluginPrefs(mContext); PluginExceptionHandler uncaughtExceptionHandler = new PluginExceptionHandler( defaultHandler); @@ -68,6 +70,7 @@ public class PluginManager { // Never ever ever allow these on production builds, they are only for prototyping. return; } + mPluginPrefs.addAction(action); PluginInstanceManager p = mFactory.createPluginInstanceManager(mContext, action, listener, allowMultiple, mBackgroundThread.getLooper(), version); p.startListening(); diff --git a/packages/SystemUI/plugin/src/com/android/systemui/plugins/PluginPrefs.java b/packages/SystemUI/plugin/src/com/android/systemui/plugins/PluginPrefs.java new file mode 100644 index 000000000000..3671b3c1689f --- /dev/null +++ b/packages/SystemUI/plugin/src/com/android/systemui/plugins/PluginPrefs.java @@ -0,0 +1,61 @@ +/* + * Copyright (C) 2016 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the + * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +package com.android.systemui.plugins; + +import android.content.Context; +import android.content.SharedPreferences; +import android.util.ArraySet; + +import java.util.Set; + +/** + * Storage for all plugin actions in SharedPreferences. + * + * This allows the list of actions that the Tuner needs to search for to be generated + * instead of hard coded. + */ +public class PluginPrefs { + + private static final String PREFS = "plugin_prefs"; + + private static final String PLUGIN_ACTIONS = "actions"; + private static final String HAS_PLUGINS = "plugins"; + + private final Set<String> mPluginActions; + private final SharedPreferences mSharedPrefs; + + public PluginPrefs(Context context) { + mSharedPrefs = context.getSharedPreferences(PREFS, 0); + mPluginActions = new ArraySet<>(mSharedPrefs.getStringSet(PLUGIN_ACTIONS, null)); + } + + public Set<String> getPluginList() { + return mPluginActions; + } + + public synchronized void addAction(String action) { + if (mPluginActions.add(action)){ + mSharedPrefs.edit().putStringSet(PLUGIN_ACTIONS, mPluginActions).commit(); + } + } + + public static boolean hasPlugins(Context context) { + return context.getSharedPreferences(PREFS, 0).getBoolean(HAS_PLUGINS, false); + } + + public static void setHasPlugins(Context context) { + context.getSharedPreferences(PREFS, 0).edit().putBoolean(HAS_PLUGINS, true).commit(); + } +} diff --git a/packages/SystemUI/res/layout/tuner_widget_settings_switch.xml b/packages/SystemUI/res/layout/tuner_widget_settings_switch.xml new file mode 100644 index 000000000000..c89c02fd9171 --- /dev/null +++ b/packages/SystemUI/res/layout/tuner_widget_settings_switch.xml @@ -0,0 +1,47 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Copyright (C) 2016 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> + +<LinearLayout + xmlns:android="http://schemas.android.com/apk/res/android" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:orientation="horizontal" + android:gravity="center_vertical"> + + <ImageView + android:id="@+id/settings" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:src="@drawable/ic_settings" + android:tint="@android:color/black" + android:padding="12dp" + android:background="?android:attr/selectableItemBackgroundBorderless" /> + + <View + android:id="@+id/divider" + android:layout_width="1dp" + android:layout_height="30dp" + android:layout_marginEnd="8dp" + android:background="?android:attr/listDivider" /> + + <Switch + android:id="@android:id/switch_widget" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:focusable="false" + android:clickable="false" + android:background="@null" /> +</LinearLayout> diff --git a/packages/SystemUI/res/values-af/strings.xml b/packages/SystemUI/res/values-af/strings.xml index ec77d77871e9..9fc0b6ec19f8 100644 --- a/packages/SystemUI/res/values-af/strings.xml +++ b/packages/SystemUI/res/values-af/strings.xml @@ -237,7 +237,8 @@ <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"4G-data is laat wag"</string> <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"Sellulêre data is onderbreek"</string> <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"Data is onderbreek"</string> - <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"Omdat die gestelde dataperk bereik is, het die toestel datagebruik vir die res van hierdie siklus onderbreek.\n\nAs dit hervat word, kan dit tot heffings deur jou diensverskaffer lei."</string> + <!-- no translation found for data_usage_disabled_dialog (1841738975235283398) --> + <skip /> <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"Hervat"</string> <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Geen internetverbinding nie"</string> <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi gekoppel"</string> diff --git a/packages/SystemUI/res/values-am/strings.xml b/packages/SystemUI/res/values-am/strings.xml index 9e00b7a97d18..0e49ab969530 100644 --- a/packages/SystemUI/res/values-am/strings.xml +++ b/packages/SystemUI/res/values-am/strings.xml @@ -237,7 +237,8 @@ <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"4ጂ ውሂብ ላፍታ ቆሟል"</string> <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"የተንቀሳቃሽ ስልክ ውሂብ ላፍታ ቆሟል"</string> <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"ውሂብ ላፍታ ቆሟል"</string> - <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"የእርስዎ የተዋቀረው የውሂብ ገደብ ላይ ስለተደረሰ፣ የዚህን ዑደት አጠቃቀም ለማስታወስ መሣሪያው ላፍታ ቆሟል።\n\nከቆመበት ማስቀጠሉ ከእርስዎ የአገልግሎት አቅራቢ ክፍያን ሊያስጠይቅዎት ይችላል።"</string> + <!-- no translation found for data_usage_disabled_dialog (1841738975235283398) --> + <skip /> <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"ከቆመበት ቀጥል"</string> <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"ምንም በይነመረብ ተያያዥ የለም።"</string> <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi ተያይዟል"</string> diff --git a/packages/SystemUI/res/values-ar/strings.xml b/packages/SystemUI/res/values-ar/strings.xml index 93c46472923a..abd32b7b47fd 100644 --- a/packages/SystemUI/res/values-ar/strings.xml +++ b/packages/SystemUI/res/values-ar/strings.xml @@ -241,7 +241,8 @@ <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"تم إيقاف بيانات شبكة الجيل الرابع مؤقتًا"</string> <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"تم إيقاف بيانات شبكة الجوّال مؤقتًا"</string> <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"تم إيقاف البيانات مؤقتًا"</string> - <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"نظرًا لأنك بلغت الحد الأقصى المحدد للبيانات، فقد أوقف الجهاز استخدام البيانات مؤقتًا في بقية هذه الدورة.\n\nومن الممكن أن يؤدي الاستئناف إلى تحصيل رسوم من قِبل مشغِّل شبكة الجوّال."</string> + <!-- no translation found for data_usage_disabled_dialog (1841738975235283398) --> + <skip /> <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"استئناف"</string> <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"لا يوجد اتصال إنترنت"</string> <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi متصل"</string> diff --git a/packages/SystemUI/res/values-az-rAZ/strings.xml b/packages/SystemUI/res/values-az-rAZ/strings.xml index 109610823eb6..ca5479404425 100644 --- a/packages/SystemUI/res/values-az-rAZ/strings.xml +++ b/packages/SystemUI/res/values-az-rAZ/strings.xml @@ -237,7 +237,8 @@ <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"4G məlumatlarına fasilə verildi"</string> <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"Mobil məlumatlara fasilə verildi"</string> <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"Məlumatlara fasilə verildi"</string> - <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"Məlumatlar dəsti limitinizi keçdiyiniz üçün cihaz bu dövrənin qalan hissəsi üçün məlumatların istifadəsinə fasilə verib.\n\nDavam etmək operaturunuzdan xərclərə səbəb ola bilər."</string> + <!-- no translation found for data_usage_disabled_dialog (1841738975235283398) --> + <skip /> <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"Davam et"</string> <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"İnternet bağlantısı yoxdur"</string> <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi qoşulub"</string> diff --git a/packages/SystemUI/res/values-b+sr+Latn/strings.xml b/packages/SystemUI/res/values-b+sr+Latn/strings.xml index d184130eb4e4..d22928df1957 100644 --- a/packages/SystemUI/res/values-b+sr+Latn/strings.xml +++ b/packages/SystemUI/res/values-b+sr+Latn/strings.xml @@ -238,7 +238,8 @@ <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"4G podaci su pauzirani"</string> <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"Mobilni podaci su pauzirani"</string> <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"Podaci su pauzirani"</string> - <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"Zbog toga što ste dostigli podešeno ograničenje za podatke, uređaj je pauzirao korišćenje podataka tokom ostatka ovog ciklusa.\n\nAko nastavite, mobilni operater može da vam naplati dodatne troškove."</string> + <!-- no translation found for data_usage_disabled_dialog (1841738975235283398) --> + <skip /> <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"Nastavi"</string> <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Nema internet veze"</string> <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi je povezan"</string> diff --git a/packages/SystemUI/res/values-be-rBY/strings.xml b/packages/SystemUI/res/values-be-rBY/strings.xml index cc71580e0452..c215680d58d3 100644 --- a/packages/SystemUI/res/values-be-rBY/strings.xml +++ b/packages/SystemUI/res/values-be-rBY/strings.xml @@ -241,7 +241,8 @@ <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"Перадача даных 4G прыпынена"</string> <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"Мабільная перадача даных прыпынена"</string> <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"Перадача даных прыпынена"</string> - <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"Быў дасягнуты ліміт перадачы даных, таму прылада прыпыніла перадачу даных на астатнюю частку гэтага цыкла.\n\nУзнаўленне перадачы можа прывесці да спагнання платы вашым аператарам."</string> + <!-- no translation found for data_usage_disabled_dialog (1841738975235283398) --> + <skip /> <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"Узнавіць"</string> <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Няма падключэння да Iнтэрнэту"</string> <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi падключаны"</string> diff --git a/packages/SystemUI/res/values-bg/strings.xml b/packages/SystemUI/res/values-bg/strings.xml index 42ac038bcb08..c2a2a9241ee3 100644 --- a/packages/SystemUI/res/values-bg/strings.xml +++ b/packages/SystemUI/res/values-bg/strings.xml @@ -237,7 +237,8 @@ <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"Данните от 4G са поставени на пауза"</string> <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"Мобилните данни са поставени на пауза"</string> <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"Данните са поставени на пауза"</string> - <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"Тъй като зададеното от вас ограничение за данни бе достигнато, устройството постави преноса им на пауза за остатъка от този цикъл.\n\nВъзобновяването може да доведе до таксуване от оператора ви."</string> + <!-- no translation found for data_usage_disabled_dialog (1841738975235283398) --> + <skip /> <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"Възобновяване"</string> <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Няма връзка с интернет"</string> <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi: Има връзка"</string> diff --git a/packages/SystemUI/res/values-bn-rBD/strings.xml b/packages/SystemUI/res/values-bn-rBD/strings.xml index 1467eea320ae..5ed264e417c3 100644 --- a/packages/SystemUI/res/values-bn-rBD/strings.xml +++ b/packages/SystemUI/res/values-bn-rBD/strings.xml @@ -237,7 +237,8 @@ <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"4G ডেটা বিরতি দেওয়া হয়েছে"</string> <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"সেলুলার ডেটা বিরতি দেওয়া হয়েছে"</string> <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"ডেট বিরতি দেওয়া হয়েছে"</string> - <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"আপনার সেট ডেটার সীমা অবধি পৌঁছনোর কারনে ডিভাইস এই চক্রের অবশিষ্টাংশের জন্য ডেটা ব্যবহারে বিরতি দেওয়া হয়েছে৷ \n\nপুনরায় চালু করা হলে পরিষেবা প্রদানকারীর দ্বারা চার্জের করা হতে পারে৷"</string> + <!-- no translation found for data_usage_disabled_dialog (1841738975235283398) --> + <skip /> <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"পুনঃসূচনা করুন"</string> <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"কোনো ইন্টারনেট সংযোগ নেই"</string> <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"ওয়াই-ফাই সংযুক্ত হয়েছে"</string> diff --git a/packages/SystemUI/res/values-bs-rBA/strings.xml b/packages/SystemUI/res/values-bs-rBA/strings.xml index 349098a6655c..c621ecd3b0d5 100644 --- a/packages/SystemUI/res/values-bs-rBA/strings.xml +++ b/packages/SystemUI/res/values-bs-rBA/strings.xml @@ -238,7 +238,8 @@ <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"4G prijenos podataka je pauzirano"</string> <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"Mobilni podaci su pauzirani"</string> <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"Prijenos podataka je pauziran"</string> - <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"Dostigli ste postavljeno ograničenje prijenosa podataka pa je uređaj zaustavio prijenos podataka za preostali dio ovog ciklusa.\n\nAko nastavite, operater vam može naplatiti dodatne troškove."</string> + <!-- no translation found for data_usage_disabled_dialog (1841738975235283398) --> + <skip /> <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"Nastavi"</string> <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Nema internet veze"</string> <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi veza aktivna"</string> diff --git a/packages/SystemUI/res/values-ca/strings.xml b/packages/SystemUI/res/values-ca/strings.xml index b764bf63f3cd..882c8e34d6bd 100644 --- a/packages/SystemUI/res/values-ca/strings.xml +++ b/packages/SystemUI/res/values-ca/strings.xml @@ -237,7 +237,8 @@ <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"Les dades 4G estan aturades"</string> <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"Les dades mòbils estan aturades"</string> <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"Les dades estan aturades"</string> - <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"Com que has arribat al límit de dades establert, s\'ha aturat l\'ús de dades del dispositiu per a la resta d\'aquest cicle.\n\nSi el reprens, l\'operador de telefonia mòbil pot aplicar càrrecs."</string> + <!-- no translation found for data_usage_disabled_dialog (1841738975235283398) --> + <skip /> <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"Reprèn"</string> <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"No hi ha connexió a Internet"</string> <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi: connectada"</string> diff --git a/packages/SystemUI/res/values-cs/strings.xml b/packages/SystemUI/res/values-cs/strings.xml index a829fe79949a..216e763072df 100644 --- a/packages/SystemUI/res/values-cs/strings.xml +++ b/packages/SystemUI/res/values-cs/strings.xml @@ -241,7 +241,8 @@ <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"Data 4G jsou pozastavena"</string> <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"Mobilní data jsou pozastavena"</string> <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"Data jsou pozastavena"</string> - <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"Protože jste dosáhli nastaveného limitu dat, zařízení využití dat pro zbytek tohoto cyklu pozastavilo.\n\nObnovení může vést k poplatkům od operátora."</string> + <!-- no translation found for data_usage_disabled_dialog (1841738975235283398) --> + <skip /> <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"Pokračovat"</string> <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Žádné přip. k internetu"</string> <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi: připojeno"</string> diff --git a/packages/SystemUI/res/values-da/strings.xml b/packages/SystemUI/res/values-da/strings.xml index 64046e76d1af..77727bbd5ebe 100644 --- a/packages/SystemUI/res/values-da/strings.xml +++ b/packages/SystemUI/res/values-da/strings.xml @@ -237,7 +237,8 @@ <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"4G-data er sat på pause"</string> <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"Mobildata er sat på pause"</string> <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"Data er sat på pause"</string> - <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"Eftersom din fastsatte datagrænse blev nået, har enheden sat dataforbruget på pause i den resterende del af cyklussen.\n\nHvis du genaktiverer dataforbruget, kan det medføre gebyrer fra dit mobilselskab."</string> + <!-- no translation found for data_usage_disabled_dialog (1841738975235283398) --> + <skip /> <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"Genoptag"</string> <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Ingen internetforb."</string> <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi er forbundet"</string> diff --git a/packages/SystemUI/res/values-de/strings.xml b/packages/SystemUI/res/values-de/strings.xml index 134e41fd2685..5aa99a14b14a 100644 --- a/packages/SystemUI/res/values-de/strings.xml +++ b/packages/SystemUI/res/values-de/strings.xml @@ -239,7 +239,8 @@ <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"4G-Daten pausiert"</string> <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"Mobilfunkdaten pausiert"</string> <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"Daten pausiert"</string> - <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"Da dein festgelegtes Datenlimit erreicht wurde, hat das Gerät die Datennutzung für den Rest dieses Zeitraums pausiert.\n\nWenn du die Nutzung fortsetzt, entstehen möglicherweise Kosten bei deinem Mobilfunkanbieter."</string> + <!-- no translation found for data_usage_disabled_dialog (1841738975235283398) --> + <skip /> <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"Fortsetzen"</string> <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Keine Internetverbindung"</string> <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"WLAN verbunden"</string> diff --git a/packages/SystemUI/res/values-el/strings.xml b/packages/SystemUI/res/values-el/strings.xml index b1085431a9ec..4c5718b7ccb5 100644 --- a/packages/SystemUI/res/values-el/strings.xml +++ b/packages/SystemUI/res/values-el/strings.xml @@ -237,7 +237,8 @@ <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"Τα δεδομένα 4G τέθηκαν σε παύση"</string> <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"Τα δεδομένα κινητής τηλεφωνίας τέθηκαν σε παύση"</string> <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"Τα δεδομένα τέθηκαν σε παύση"</string> - <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"Επειδή συμπληρώθηκε το όριο των δεδομένων που ορίστηκε για τη συσκευή σας, η χρήση δεδομένων τέθηκε σε παύση για το υπόλοιπο αυτού του κύκλου.\n\nΗ εκ νέου ενεργοποίησή τους ενδέχεται να επιφέρει χρεώσεις από την εταιρεία κινητής τηλεφωνίας σας."</string> + <!-- no translation found for data_usage_disabled_dialog (1841738975235283398) --> + <skip /> <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"Συνέχιση"</string> <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Χωρ. σύνδ. στο Διαδ."</string> <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi συνδεδεμένο"</string> diff --git a/packages/SystemUI/res/values-en-rAU/strings.xml b/packages/SystemUI/res/values-en-rAU/strings.xml index 776e043089f9..d12b44887d2a 100644 --- a/packages/SystemUI/res/values-en-rAU/strings.xml +++ b/packages/SystemUI/res/values-en-rAU/strings.xml @@ -237,7 +237,8 @@ <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"4G data is paused"</string> <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"Mobile data is paused"</string> <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"Data is paused"</string> - <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"Because your set data limit was reached, the device has paused data usage for the remainder of this cycle.\n\nResuming may lead to charges from your operator."</string> + <!-- no translation found for data_usage_disabled_dialog (1841738975235283398) --> + <skip /> <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"Resume"</string> <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"No Internet connection"</string> <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi connected"</string> diff --git a/packages/SystemUI/res/values-en-rGB/strings.xml b/packages/SystemUI/res/values-en-rGB/strings.xml index 776e043089f9..d12b44887d2a 100644 --- a/packages/SystemUI/res/values-en-rGB/strings.xml +++ b/packages/SystemUI/res/values-en-rGB/strings.xml @@ -237,7 +237,8 @@ <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"4G data is paused"</string> <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"Mobile data is paused"</string> <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"Data is paused"</string> - <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"Because your set data limit was reached, the device has paused data usage for the remainder of this cycle.\n\nResuming may lead to charges from your operator."</string> + <!-- no translation found for data_usage_disabled_dialog (1841738975235283398) --> + <skip /> <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"Resume"</string> <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"No Internet connection"</string> <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi connected"</string> diff --git a/packages/SystemUI/res/values-en-rIN/strings.xml b/packages/SystemUI/res/values-en-rIN/strings.xml index 776e043089f9..d12b44887d2a 100644 --- a/packages/SystemUI/res/values-en-rIN/strings.xml +++ b/packages/SystemUI/res/values-en-rIN/strings.xml @@ -237,7 +237,8 @@ <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"4G data is paused"</string> <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"Mobile data is paused"</string> <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"Data is paused"</string> - <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"Because your set data limit was reached, the device has paused data usage for the remainder of this cycle.\n\nResuming may lead to charges from your operator."</string> + <!-- no translation found for data_usage_disabled_dialog (1841738975235283398) --> + <skip /> <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"Resume"</string> <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"No Internet connection"</string> <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi connected"</string> diff --git a/packages/SystemUI/res/values-es-rUS/strings.xml b/packages/SystemUI/res/values-es-rUS/strings.xml index abaeafee420c..45198cfff959 100644 --- a/packages/SystemUI/res/values-es-rUS/strings.xml +++ b/packages/SystemUI/res/values-es-rUS/strings.xml @@ -239,7 +239,8 @@ <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"Datos 4G pausados"</string> <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"Datos móviles pausados"</string> <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"Datos pausados"</string> - <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"Debido que se alcanzó el límite de datos establecido, el dispositivo pausó el uso de datos para el resto de este ciclo.\n\nLa reanudación podría tener como resultado cargos del proveedor."</string> + <!-- no translation found for data_usage_disabled_dialog (1841738975235283398) --> + <skip /> <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"Reanudar"</string> <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Sin conexión a Internet"</string> <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi conectado"</string> diff --git a/packages/SystemUI/res/values-es/strings.xml b/packages/SystemUI/res/values-es/strings.xml index bfb37b60b461..3d69e5ee3a9c 100644 --- a/packages/SystemUI/res/values-es/strings.xml +++ b/packages/SystemUI/res/values-es/strings.xml @@ -239,7 +239,8 @@ <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"Datos 4G pausados"</string> <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"Datos móviles pausados"</string> <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"Datos pausados"</string> - <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"Has alcanzado el límite de datos establecido, por lo que el dispositivo ha pausado el uso de datos para el resto de este ciclo.\n\nSi lo reanudas, el operador puede facturar cargos."</string> + <!-- no translation found for data_usage_disabled_dialog (1841738975235283398) --> + <skip /> <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"Reanudar"</string> <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Sin conexión a Internet"</string> <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Con conexión Wi-Fi"</string> diff --git a/packages/SystemUI/res/values-et-rEE/strings.xml b/packages/SystemUI/res/values-et-rEE/strings.xml index ac55422d325a..17cbc1378302 100644 --- a/packages/SystemUI/res/values-et-rEE/strings.xml +++ b/packages/SystemUI/res/values-et-rEE/strings.xml @@ -239,7 +239,8 @@ <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"4G andmekasutus on peatatud"</string> <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"Mobiilse andmeside kasutus on peatatud"</string> <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"Andmekasutus on peatatud"</string> - <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"Kuna jõudsite andmemahu määratud piirini, peatas seade andmekasutuse ülejäänud tsükliks.\n\nJätkamisel võivad lisanduda operaatoritasud."</string> + <!-- no translation found for data_usage_disabled_dialog (1841738975235283398) --> + <skip /> <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"Jätka"</string> <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Interneti-ühendus puudub"</string> <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"WiFi on ühendatud"</string> diff --git a/packages/SystemUI/res/values-eu-rES/strings.xml b/packages/SystemUI/res/values-eu-rES/strings.xml index e0912e5b2aee..5715c506e8e8 100644 --- a/packages/SystemUI/res/values-eu-rES/strings.xml +++ b/packages/SystemUI/res/values-eu-rES/strings.xml @@ -239,7 +239,8 @@ <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"4G datuen erabilera eten da"</string> <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"Sare mugikorreko datuen erabilera eten da"</string> <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"Datuen erabilera eten da"</string> - <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"Zehaztuta duzun datuen erabilera-mugara iritsi zarenez, gailuak datuen erabilera eten du zikloa amaitzen den arte.\n\nDatuak erabiltzen jarraitzen baduzu, gastu gehiago ordaindu beharko dizkiozu agian operadoreari."</string> + <!-- no translation found for data_usage_disabled_dialog (1841738975235283398) --> + <skip /> <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"Jarraitu erabiltzen"</string> <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Ez duzu Interneteko konexiorik"</string> <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi konektatuta"</string> diff --git a/packages/SystemUI/res/values-fa/strings.xml b/packages/SystemUI/res/values-fa/strings.xml index df8ba8cc102b..d92b4c03a2de 100644 --- a/packages/SystemUI/res/values-fa/strings.xml +++ b/packages/SystemUI/res/values-fa/strings.xml @@ -237,7 +237,8 @@ <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"داده 4G موقتاً متوقف شده است"</string> <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"داده شبکه همراه موقتاً متوقف شده است"</string> <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"داده موقتاً متوقف شده است"</string> - <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"چون به محدودیت داده تنظیم شده رسیدهاید، دستگاه مصرف داده را برای باقیمانده این دوره موقتاً متوقف کرده است.\n\nاگر ادامه دهید شاید موجب کسر هزینه از طرف شرکت مخابراتی شما شود."</string> + <!-- no translation found for data_usage_disabled_dialog (1841738975235283398) --> + <skip /> <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"از سرگیری"</string> <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"اتصال اینترنتی ندارید"</string> <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi متصل شد"</string> diff --git a/packages/SystemUI/res/values-fi/strings.xml b/packages/SystemUI/res/values-fi/strings.xml index d15747293242..7bb7dd68b07f 100644 --- a/packages/SystemUI/res/values-fi/strings.xml +++ b/packages/SystemUI/res/values-fi/strings.xml @@ -237,7 +237,8 @@ <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"4G-tiedonsiirto keskeytettiin"</string> <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"Mobiilitiedonsiirto keskeytettiin"</string> <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"Tiedonsiirto keskeytettiin"</string> - <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"Määrittämäsi tiedonsiirtorajoitus saavutettiin, ja laite keskeytti tiedonsiirron tämän kauden loppuajaksi.\n\nOperaattorisi voi veloittaa sinulta lisämaksun, jos jatkat tiedonsiirtoa."</string> + <!-- no translation found for data_usage_disabled_dialog (1841738975235283398) --> + <skip /> <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"Jatka"</string> <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Ei internetyhteyttä"</string> <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi yhdistetty"</string> diff --git a/packages/SystemUI/res/values-fr-rCA/strings.xml b/packages/SystemUI/res/values-fr-rCA/strings.xml index 465de963f491..b0215bd149e5 100644 --- a/packages/SystemUI/res/values-fr-rCA/strings.xml +++ b/packages/SystemUI/res/values-fr-rCA/strings.xml @@ -239,7 +239,8 @@ <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"Données 4G désactivées"</string> <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"Données cellulaires désactivées"</string> <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"Données désactivées"</string> - <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"Vous avez atteint le quota de données maximal. La consommation des données a donc été interrompue pour la fin de la période de facturation en cours.\n\nSi vous réactivez les données, votre fournisseur de services risque de vous facturer des frais supplémentaires."</string> + <!-- no translation found for data_usage_disabled_dialog (1841738975235283398) --> + <skip /> <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"Reprendre"</string> <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Aucune connexion Internet"</string> <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Connecté au Wi-Fi"</string> diff --git a/packages/SystemUI/res/values-fr/strings.xml b/packages/SystemUI/res/values-fr/strings.xml index 3ed8977aee9f..2a37637681cf 100644 --- a/packages/SystemUI/res/values-fr/strings.xml +++ b/packages/SystemUI/res/values-fr/strings.xml @@ -239,7 +239,8 @@ <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"Données 4G désactivées"</string> <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"Données mobiles désactivées"</string> <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"Données désactivées"</string> - <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"Vous avez atteint le quota de données maximal. La consommation des données a donc été interrompue pour la fin de la période de facturation en cours.\n\nSi vous réactivez les données, votre opérateur risque de vous facturer des frais supplémentaires."</string> + <!-- no translation found for data_usage_disabled_dialog (1841738975235283398) --> + <skip /> <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"Réactiver"</string> <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Aucune connexion Internet"</string> <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Connecté au Wi-Fi"</string> diff --git a/packages/SystemUI/res/values-gl-rES/strings.xml b/packages/SystemUI/res/values-gl-rES/strings.xml index dafe79d172fe..40c5ca7a0c1b 100644 --- a/packages/SystemUI/res/values-gl-rES/strings.xml +++ b/packages/SystemUI/res/values-gl-rES/strings.xml @@ -239,7 +239,8 @@ <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"Os datos 4G están en pausa"</string> <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"Os datos de móbiles están en pausa"</string> <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"Os datos están en pausa"</string> - <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"Como acadaches o límite de datos definido, o dispositivo puxo en pausa o uso de datos para o resto do ciclo.\n\nSe retomas o uso, poden aplicarse cargos do operador."</string> + <!-- no translation found for data_usage_disabled_dialog (1841738975235283398) --> + <skip /> <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"Retomar"</string> <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Sen Internet"</string> <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi conectada"</string> diff --git a/packages/SystemUI/res/values-gu-rIN/strings.xml b/packages/SystemUI/res/values-gu-rIN/strings.xml index b230bac7e554..5b3c9c2c0e14 100644 --- a/packages/SystemUI/res/values-gu-rIN/strings.xml +++ b/packages/SystemUI/res/values-gu-rIN/strings.xml @@ -237,7 +237,8 @@ <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"4G ડેટા થોભાવ્યો છે"</string> <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"સેલ્યુલર ડેટા થોભાવ્યો છે"</string> <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"ડેટા થોભાવ્યો છે"</string> - <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"તમે સેટ કરેલ ડેટા મર્યાદા સુધી પહોંચી ગયા હોવાથી, ઉપકરણે આ ચક્રના શેષ માટે ડેટા વપરાશ થોભાવ્યો છે.\n\nફરીથી શરૂ કરવું તમારા કેરીઅર તરફથી શુલ્ક તરફ દોરી શકે છે."</string> + <!-- no translation found for data_usage_disabled_dialog (1841738975235283398) --> + <skip /> <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"ફરી શરૂ કરો"</string> <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"કોઈ ઇન્ટરનેટ કનેક્શન નથી"</string> <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi કનેક્ટ કર્યું"</string> diff --git a/packages/SystemUI/res/values-hi/strings.xml b/packages/SystemUI/res/values-hi/strings.xml index c781403c0235..217a5f184b3e 100644 --- a/packages/SystemUI/res/values-hi/strings.xml +++ b/packages/SystemUI/res/values-hi/strings.xml @@ -237,7 +237,8 @@ <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"4G डेटा रोक दिया गया है"</string> <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"सेल्युलर डेटा रोक दिया गया है"</string> <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"डेटा रोक दिया गया है"</string> - <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"चूंकि आपके निर्धारित डेटा की सीमा, सीमा पर पहुंच गई थी, इसलिए डिवाइस ने इस चक्र के रिमाइंडर के लिए डेटा उपयोग को रोक दिया है.\n\nफिर से शुरू करने से आपके वाहक की ओर से शुल्क लगाया जाता है."</string> + <!-- no translation found for data_usage_disabled_dialog (1841738975235283398) --> + <skip /> <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"फिर से शुरू करें"</string> <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"कोई इंटरनेट कनेक्शन नहीं"</string> <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"वाई-फ़ाई कनेक्ट किया गया"</string> diff --git a/packages/SystemUI/res/values-hr/strings.xml b/packages/SystemUI/res/values-hr/strings.xml index 1de9f783a1d8..a9815d5fe4ee 100644 --- a/packages/SystemUI/res/values-hr/strings.xml +++ b/packages/SystemUI/res/values-hr/strings.xml @@ -238,7 +238,8 @@ <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"4G podaci pauzirani"</string> <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"Mobilni podaci pauzirani"</string> <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"Podaci su pauzirani"</string> - <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"Budući da je dosegnuto postavljeno ograničenje podataka, uređaj je pauzirao upotrebu podataka za preostali dio ovog ciklusa.\n\nMobilni operater može naplatiti daljnju upotrebu."</string> + <!-- no translation found for data_usage_disabled_dialog (1841738975235283398) --> + <skip /> <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"Nastavi"</string> <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Nema internetske veze"</string> <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi povezan"</string> diff --git a/packages/SystemUI/res/values-hu/strings.xml b/packages/SystemUI/res/values-hu/strings.xml index 6d699addfcb2..9fd4eb720145 100644 --- a/packages/SystemUI/res/values-hu/strings.xml +++ b/packages/SystemUI/res/values-hu/strings.xml @@ -237,7 +237,8 @@ <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"A 4G adatforgalom szünetel"</string> <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"A mobilhálózati adatforgalom szünetel"</string> <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"Az adatforgalom szünetel"</string> - <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"Mivel elérte a beállított adatkorlátot, az eszköz a ciklus fennmaradó részére felfüggesztette az adathasználatot.\n\nHa mégis használja az adatkapcsolatot, akkor szolgáltatója többletköltséget számíthat fel."</string> + <!-- no translation found for data_usage_disabled_dialog (1841738975235283398) --> + <skip /> <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"Folytatás"</string> <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Nincs internet"</string> <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi csatlakoztatva"</string> diff --git a/packages/SystemUI/res/values-hy-rAM/strings.xml b/packages/SystemUI/res/values-hy-rAM/strings.xml index e08ec4638247..236663de0081 100644 --- a/packages/SystemUI/res/values-hy-rAM/strings.xml +++ b/packages/SystemUI/res/values-hy-rAM/strings.xml @@ -237,7 +237,8 @@ <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"4Գ տվյալների օգտագործումը դադարեցված է"</string> <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"Բջջային տվյալների օգտագործումը դադարեցված է"</string> <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"Տվյալների օգտագործումը դադարեցված է"</string> - <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"Քանի որ ձեր սահմանված տվյալների սահմանաչափը սպառվել է, սարքն այլևս չի օգտագործի տվյալները այս ցիկլի մնացած ընթացքում:\n\nԵթե վերսկսեք, հնարավոր է կիրառվեն գանձումներ ձեր օպերատորի կողմից:"</string> + <!-- no translation found for data_usage_disabled_dialog (1841738975235283398) --> + <skip /> <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"Վերսկսել"</string> <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Ինտերնետ կապ չկա"</string> <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi-ը միացված է"</string> diff --git a/packages/SystemUI/res/values-in/strings.xml b/packages/SystemUI/res/values-in/strings.xml index de4b68d9237b..5e2600808305 100644 --- a/packages/SystemUI/res/values-in/strings.xml +++ b/packages/SystemUI/res/values-in/strings.xml @@ -237,7 +237,8 @@ <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"Data 4G dijeda"</string> <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"Data seluler dijeda"</string> <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"Data dijeda"</string> - <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"Karena batas data yang disetel telah tercapai, perangkat telah menjeda penggunaan data selama sisa waktu siklus ini.\n\nMelanjutkan dapat mengakibatkan tagihan dari operator."</string> + <!-- no translation found for data_usage_disabled_dialog (1841738975235283398) --> + <skip /> <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"Lanjutkan"</string> <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Tidak ada sambungan internet"</string> <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi tersambung"</string> diff --git a/packages/SystemUI/res/values-is-rIS/strings.xml b/packages/SystemUI/res/values-is-rIS/strings.xml index 9b1e13920ee3..02b59b613ba1 100644 --- a/packages/SystemUI/res/values-is-rIS/strings.xml +++ b/packages/SystemUI/res/values-is-rIS/strings.xml @@ -237,7 +237,8 @@ <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"Slökkt er á 4G-gögnum"</string> <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"Slökkt er á farsímagögnum"</string> <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"Slökkt er á gagnanotkun"</string> - <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"Þar sem gagnahámarkinu var náð hefur tækið slökkt á gagnanotkun það sem eftir er af þessu tímabili.\n\nEf þú heldur áfram kann það að leiða til kostnaðar frá símafyrirtækinu."</string> + <!-- no translation found for data_usage_disabled_dialog (1841738975235283398) --> + <skip /> <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"Halda áfram"</string> <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Engin nettenging"</string> <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi tengt"</string> diff --git a/packages/SystemUI/res/values-it/strings.xml b/packages/SystemUI/res/values-it/strings.xml index f207e43f1171..9d76477efb14 100644 --- a/packages/SystemUI/res/values-it/strings.xml +++ b/packages/SystemUI/res/values-it/strings.xml @@ -239,7 +239,8 @@ <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"Dati 4G sospesi"</string> <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"Dati cellulari sospesi"</string> <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"Dati sospesi"</string> - <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"Hai raggiunto il tuo limite di dati, pertanto sul dispositivo è stato sospeso l\'utilizzo di dati per la parte rimanente del ciclo.\n\nSe riprendi a utilizzare i dati, l\'operatore potrebbe addebitarti costi."</string> + <!-- no translation found for data_usage_disabled_dialog (1841738975235283398) --> + <skip /> <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"Riprendi"</string> <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Nessuna connessione"</string> <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi connesso"</string> diff --git a/packages/SystemUI/res/values-iw/strings.xml b/packages/SystemUI/res/values-iw/strings.xml index 6462ae5eb3ed..34294973455b 100644 --- a/packages/SystemUI/res/values-iw/strings.xml +++ b/packages/SystemUI/res/values-iw/strings.xml @@ -239,7 +239,8 @@ <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"השימוש בנתוני 4G מושהה"</string> <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"השימוש בנתונים סלולריים מושהה"</string> <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"השימוש בנתונים מושהה"</string> - <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"מכיוון שהגעת למגבלת הנתונים שהגדרת, המכשיר השהה את השימוש בנתונים עד סוף התקופה.\n\nאם תמשיך, אתה עשוי לקבל חיובים מהספק."</string> + <!-- no translation found for data_usage_disabled_dialog (1841738975235283398) --> + <skip /> <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"המשך"</string> <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"אין חיבור לאינטרנט"</string> <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi מחובר"</string> diff --git a/packages/SystemUI/res/values-ja/strings.xml b/packages/SystemUI/res/values-ja/strings.xml index fd59bc5b31db..bbd803353171 100644 --- a/packages/SystemUI/res/values-ja/strings.xml +++ b/packages/SystemUI/res/values-ja/strings.xml @@ -239,7 +239,8 @@ <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"4Gデータは一時停止中です"</string> <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"モバイルデータは一時停止中です"</string> <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"データの一時停止"</string> - <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"設定されたデータの上限に達したため、このサイクルの終了までこの端末でのデータの利用を一時停止しました。\n\n再開すると、携帯通信会社から課金される可能性があります。"</string> + <!-- no translation found for data_usage_disabled_dialog (1841738975235283398) --> + <skip /> <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"再開"</string> <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"インターネット未接続"</string> <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi接続済み"</string> diff --git a/packages/SystemUI/res/values-ka-rGE/strings.xml b/packages/SystemUI/res/values-ka-rGE/strings.xml index 28e37cad6a50..c00c54caf22a 100644 --- a/packages/SystemUI/res/values-ka-rGE/strings.xml +++ b/packages/SystemUI/res/values-ka-rGE/strings.xml @@ -237,7 +237,8 @@ <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"4G მონაცემები შეჩერებულია"</string> <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"ფიჭური მონაცემები შეჩერებულია"</string> <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"მონაცემები შეჩერებულია"</string> - <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"რადგან თქვენი მონაცემების ლიმიტი ამოწურულია, მოწყობილობამ შეაჭერა მონაცემების გამოყენება დარჩენილი ციკლისათვის. \n\n შეჯამაბ შეიძლება გამოიწვიოს თქვენს პროვაიდერთან დამატებითი ხარჯები."</string> + <!-- no translation found for data_usage_disabled_dialog (1841738975235283398) --> + <skip /> <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"გაგრძელება"</string> <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"ინტერნეტ კავშირი არ არის"</string> <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi დაკავშირებულია"</string> diff --git a/packages/SystemUI/res/values-kk-rKZ/strings.xml b/packages/SystemUI/res/values-kk-rKZ/strings.xml index ad25a1c89814..8051cd8d6dbe 100644 --- a/packages/SystemUI/res/values-kk-rKZ/strings.xml +++ b/packages/SystemUI/res/values-kk-rKZ/strings.xml @@ -237,7 +237,8 @@ <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"4G деректері кідіртілді"</string> <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"Ұялы деректер кідіртілді"</string> <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"Деректер кідіртілді"</string> - <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"Орнатылған деректер шегіне жеткендіктен, құрылғы осы циклдың қалған бөлігі бойы деректерді пайдалануды кідіртті.\n\nЖалғастыру оператор ақыларына әкелуі мүмкін."</string> + <!-- no translation found for data_usage_disabled_dialog (1841738975235283398) --> + <skip /> <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"Жалғастыру"</string> <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Интернет байланысы жоқ"</string> <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi қосулы"</string> diff --git a/packages/SystemUI/res/values-km-rKH/strings.xml b/packages/SystemUI/res/values-km-rKH/strings.xml index 76a8f59f215c..c0d002c4920e 100644 --- a/packages/SystemUI/res/values-km-rKH/strings.xml +++ b/packages/SystemUI/res/values-km-rKH/strings.xml @@ -237,7 +237,8 @@ <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"ទិន្នន័យ 4G ត្រូវបានផ្អាក"</string> <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"ទិន្នន័យចល័តត្រូវបានផ្អាក"</string> <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"ទិន្នន័យត្រូវបានផ្អាក"</string> - <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"ដោយសារទិន្នន័យរបស់អ្នកបានឈានដល់កំណត់ ឧបករណ៍នេះបានផ្អាកការប្រើប្រាស់ទិន្នន័យសម្រាប់ការរំលឹកនៃវគ្គនេះ។\n\nការបន្តប្រើប្រាស់អាចនាំឲ្យមានការគិតប្រាក់ពីក្រុមហ៊ុនផ្តល់សេវាកម្ម។"</string> + <!-- no translation found for data_usage_disabled_dialog (1841738975235283398) --> + <skip /> <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"បន្ត"</string> <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"គ្មានការតភ្ជាប់អ៊ីនធឺណិត"</string> <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"បានភ្ជាប់វ៉ាយហ្វាយ"</string> diff --git a/packages/SystemUI/res/values-kn-rIN/strings.xml b/packages/SystemUI/res/values-kn-rIN/strings.xml index 69e3bdb55f5b..e1c42d794680 100644 --- a/packages/SystemUI/res/values-kn-rIN/strings.xml +++ b/packages/SystemUI/res/values-kn-rIN/strings.xml @@ -237,7 +237,8 @@ <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"4G ಡೇಟಾ ವಿರಾಮಗೊಳಿಸಲಾಗಿದೆ"</string> <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"ಸೆಲ್ಯುಲಾರ್ ಡೇಟಾ ವಿರಾಮಗೊಳಿಸಲಾಗಿದೆ"</string> <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"ಡೇಟಾ ವಿರಾಮಗೊಳಿಸಲಾಗಿದೆ"</string> - <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"ಏಕೆಂದರೆ ನಿಮ್ಮ ಹೊಂದಾಣಿಕೆ ಡೇಟಾ ಮೀತಿಯನ್ನು ತಲುಪಿದೆ, ಈ ಆವರ್ತನೆಯ ಉಳಿದ ಭಾಗಕ್ಕೆ ಸಾಧನವು ಡೇಟಾ ಬಳಕೆಯನ್ನು ವಿರಾಮಗೊಳಿಸಿದೆ.\n\nಮುಂದುವರೆಯುವಿಕೆಯು ನಿಮ್ಮ ವಾಹಕದ ಶುಲ್ಕಗಳಿಗೆ ಕಾರಣವಾಗಬಹುದು."</string> + <!-- no translation found for data_usage_disabled_dialog (1841738975235283398) --> + <skip /> <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"ಮುಂದುವರಿಸು"</string> <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"ಇಂಟರ್ನೆಟ್ ಸಂಪರ್ಕವಿಲ್ಲ"</string> <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"ವೈ-ಫೈ ಸಂಪರ್ಕಗೊಂಡಿದೆ"</string> diff --git a/packages/SystemUI/res/values-ko/strings.xml b/packages/SystemUI/res/values-ko/strings.xml index d47741202a01..1c9721261c7c 100644 --- a/packages/SystemUI/res/values-ko/strings.xml +++ b/packages/SystemUI/res/values-ko/strings.xml @@ -239,7 +239,8 @@ <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"4G 데이터 사용 중지됨"</string> <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"모바일 데이터 사용 중지됨"</string> <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"데이터 사용 중지됨"</string> - <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"설정된 데이터 한도에 도달했기 때문에 기기에서 사이클의 나머지 기간 동안 데이터 사용을 일시 중지했습니다. \n\n데이터 사용을 재개하면 이동통신사 요금이 청구될 수 있습니다."</string> + <!-- no translation found for data_usage_disabled_dialog (1841738975235283398) --> + <skip /> <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"재개"</string> <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"인터넷에 연결되지 않음"</string> <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi 연결됨"</string> diff --git a/packages/SystemUI/res/values-ky-rKG/strings.xml b/packages/SystemUI/res/values-ky-rKG/strings.xml index b84bea2008b9..b17f523de29e 100644 --- a/packages/SystemUI/res/values-ky-rKG/strings.xml +++ b/packages/SystemUI/res/values-ky-rKG/strings.xml @@ -237,7 +237,8 @@ <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"4G дайындары тындырылды"</string> <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"Уюлдук дайындар тындырылды"</string> <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"Дайындар тындырылды"</string> - <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"Киргизиле турган дайындар белгиленген эң жогорку чекке жеткендиктен, ушул мерчимдин калган бөлүгүндө түзмөгүңүздө дайындардын колдонулушу тындырылды.\n\nУлантсаңыз, байланыш операторуңузга акы төлөп калышыңыз мүмкүн."</string> + <!-- no translation found for data_usage_disabled_dialog (1841738975235283398) --> + <skip /> <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"Улантуу"</string> <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Интернет байланыш жок"</string> <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi байланышта"</string> diff --git a/packages/SystemUI/res/values-lo-rLA/strings.xml b/packages/SystemUI/res/values-lo-rLA/strings.xml index f1be8b3daf63..0dc3d50a8eff 100644 --- a/packages/SystemUI/res/values-lo-rLA/strings.xml +++ b/packages/SystemUI/res/values-lo-rLA/strings.xml @@ -237,7 +237,8 @@ <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"ຂໍ້ມູນ 4G ຢຸດຊົ່ວຄາວແລ້ວ"</string> <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"ຂໍ້ມູນເຊວລູລາຢຸດຊົ່ວຄາວແລ້ວ"</string> <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"ຂໍ້ມູນຢຸດຊົ່ວຄາວແລ້ວ"</string> - <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"ເນື່ອງຈາກວ່າຮອດຂີດຈຳກັດຂໍ້ມູນທີ່ຕັ້ງໄວ້ຂອງທ່ານແລ້ວ, ອຸປະກອນຢຸດການນຳໃຊ້ຂໍ້ມູນສຳລັບສ່ວນທີ່ຍັງເຫຼືອຂອງຮອບວຽນນີ້.\n\nການເລີ່ມຕໍ່ອາດຈະນຳໄປສູ່ການປ່ຽນແປງຈາກຜູ້ໃຫ້ບໍລິການເຄືອຂ່າຍຂອງທ່ານ."</string> + <!-- no translation found for data_usage_disabled_dialog (1841738975235283398) --> + <skip /> <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"ເລີ່ມຕໍ່"</string> <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"ບໍ່ມີການເຊື່ອມຕໍ່ອິນເຕີເນັດ"</string> <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"ເຊື່ອມຕໍ່ Wi--Fi ແລ້ວ"</string> diff --git a/packages/SystemUI/res/values-lt/strings.xml b/packages/SystemUI/res/values-lt/strings.xml index 8a0f956b521f..dd2f198355c5 100644 --- a/packages/SystemUI/res/values-lt/strings.xml +++ b/packages/SystemUI/res/values-lt/strings.xml @@ -239,7 +239,8 @@ <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"4G duomenys pristabdyti"</string> <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"Korinio ryšio duomenys pristabdyti"</string> <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"Duomenys pristabdyti"</string> - <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"Kadangi buvo pasiektas nustatytas duomenų limitas, įrenginys pristabdė duomenų naudojimą likusį šio ciklo laikotarpį.\n\nAtnaujinus gali būti taikomi operatoriaus mokesčiai."</string> + <!-- no translation found for data_usage_disabled_dialog (1841738975235283398) --> + <skip /> <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"Atnaujinti"</string> <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Nėra interneto ryš."</string> <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Prisij. prie „Wi-Fi“"</string> diff --git a/packages/SystemUI/res/values-lv/strings.xml b/packages/SystemUI/res/values-lv/strings.xml index 76d0da4df8ea..42424978ba71 100644 --- a/packages/SystemUI/res/values-lv/strings.xml +++ b/packages/SystemUI/res/values-lv/strings.xml @@ -238,7 +238,8 @@ <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"4G datu lietojums ir apturēts"</string> <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"Mobilo datu lietojums ir apturēts"</string> <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"Datu lietojums ir apturēts"</string> - <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"Tika sasniegts iestatītais datu lietojuma ierobežojums, tādēļ ierīcē ir apturēts datu lietojums cikla atlikušajā periodā.\n\nJa atsāksiet lietot datus, iespējams, jūsu mobilo sakaru operators iekasēs maksu."</string> + <!-- no translation found for data_usage_disabled_dialog (1841738975235283398) --> + <skip /> <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"Atsākt"</string> <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Nav interneta sav."</string> <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Izv. sav. ar Wi-Fi"</string> diff --git a/packages/SystemUI/res/values-mk-rMK/strings.xml b/packages/SystemUI/res/values-mk-rMK/strings.xml index d7982c7f2467..4091bbe3e1e6 100644 --- a/packages/SystemUI/res/values-mk-rMK/strings.xml +++ b/packages/SystemUI/res/values-mk-rMK/strings.xml @@ -237,7 +237,8 @@ <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"Податоците 4G се паузирани"</string> <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"Мобилните податоци се паузирани"</string> <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"Податоците се паузирани"</string> - <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"Поради тоа што го достигнавте поставеното ограничување на податоци, уредот го паузираше користењето податоци до крајот на циклусот.\n\nОператорот може да ви наплати ако продолжите."</string> + <!-- no translation found for data_usage_disabled_dialog (1841738975235283398) --> + <skip /> <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"Продолжи"</string> <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Нема интернет"</string> <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Поврзано на Wi-Fi"</string> diff --git a/packages/SystemUI/res/values-ml-rIN/strings.xml b/packages/SystemUI/res/values-ml-rIN/strings.xml index 34aaa92ea172..6ae547e256aa 100644 --- a/packages/SystemUI/res/values-ml-rIN/strings.xml +++ b/packages/SystemUI/res/values-ml-rIN/strings.xml @@ -237,7 +237,8 @@ <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"4G ഡാറ്റ താൽക്കാലികമായി നിർത്തി"</string> <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"സെല്ലുലാർ ഡാറ്റ താൽക്കാലികമായി നിർത്തി"</string> <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"ഡാറ്റ താൽക്കാലികമായി നിർത്തി"</string> - <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"നിങ്ങൾ നേരത്തെ ക്രമീകരിച്ച ഡാറ്റ പരിധിയിലെത്തിയതിനാൽ, ഈ സൈക്കിളിന്റെ അവശേഷിക്കുന്ന ഡാറ്റ ഉപയോഗം, ഉപകരണം താൽക്കാലികമായി നിർത്തി.\n\nപുനരാരംഭിക്കുന്നത്, നിങ്ങളുടെ കാരിയറിൽ നിന്ന് നിരക്കുകൾക്ക് ഇടയാക്കാം."</string> + <!-- no translation found for data_usage_disabled_dialog (1841738975235283398) --> + <skip /> <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"പുനരാരംഭിക്കുക"</string> <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"ഇന്റർനെറ്റ് കണക്ഷൻ ഇല്ല"</string> <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"വൈഫൈ കണക്റ്റുചെയ്തു"</string> diff --git a/packages/SystemUI/res/values-mn-rMN/strings.xml b/packages/SystemUI/res/values-mn-rMN/strings.xml index 44f012527b48..95cbcaeccbdf 100644 --- a/packages/SystemUI/res/values-mn-rMN/strings.xml +++ b/packages/SystemUI/res/values-mn-rMN/strings.xml @@ -235,7 +235,8 @@ <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"4G дата-г түр зогсоосон байна"</string> <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"Гар утасны дата-г түр зогсоосон байна"</string> <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"Дата-г түр зогсоосон байна"</string> - <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"Таны багц дата эрхийн дээд хэмжээнд хүрсэн байгаа тул төхөөрөмж нь үлдсэн хэсэгт дата хэрэглээг түр зогсоосон байна.\n\nТа үйлдлийг үргэлжлүүлэхийг хүсвэл үйлчилгээ үзүүлж буй үүрэн холбооны газраас нэмж дата эрх авна уу."</string> + <!-- no translation found for data_usage_disabled_dialog (1841738975235283398) --> + <skip /> <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"Үргэлжлүүлэх"</string> <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Интернет холболт байхгүй"</string> <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi холбогдсон"</string> diff --git a/packages/SystemUI/res/values-mr-rIN/strings.xml b/packages/SystemUI/res/values-mr-rIN/strings.xml index eeb16c742516..830cda4b1a77 100644 --- a/packages/SystemUI/res/values-mr-rIN/strings.xml +++ b/packages/SystemUI/res/values-mr-rIN/strings.xml @@ -237,7 +237,8 @@ <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"4G डेटास विराम दिला आहे"</string> <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"सेल्युलर डेटास विराम दिला आहे"</string> <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"डेटास विराम दिला आहे"</string> - <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"आपली सेट केलेली डेटा मर्यादा गाठल्यामुळे, डिव्हाइसने या चक्राच्या उर्वरित डेटा वापरास विराम दिला आहे.\n\nपुन्हा सुरु करण्यामुळे आपल्या वाहकाकडून शुल्क आकारले जाऊ शकते."</string> + <!-- no translation found for data_usage_disabled_dialog (1841738975235283398) --> + <skip /> <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"पुन्हा सुरु करा"</string> <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"इंटरनेट कनेक्शन नाही"</string> <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"वाय-फाय कनेक्ट केले"</string> diff --git a/packages/SystemUI/res/values-ms-rMY/strings.xml b/packages/SystemUI/res/values-ms-rMY/strings.xml index 45215b4f9839..82de7a33986b 100644 --- a/packages/SystemUI/res/values-ms-rMY/strings.xml +++ b/packages/SystemUI/res/values-ms-rMY/strings.xml @@ -237,7 +237,8 @@ <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"Data 4G dijeda"</string> <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"Data selular dijeda"</string> <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"Data dijeda"</string> - <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"Oleh kerana had data tetap anda telah dicapai, peranti telah menjeda penggunaan data bagi baki kitaran ini.\n\nMenyambung semula boleh menyebabkan anda dikenakan bayaran daripada pembawa anda."</string> + <!-- no translation found for data_usage_disabled_dialog (1841738975235283398) --> + <skip /> <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"Sambung semula"</string> <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Tiada smbg Internet"</string> <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi disambungkan"</string> diff --git a/packages/SystemUI/res/values-my-rMM/strings.xml b/packages/SystemUI/res/values-my-rMM/strings.xml index 31efa644754d..3899b00c7279 100644 --- a/packages/SystemUI/res/values-my-rMM/strings.xml +++ b/packages/SystemUI/res/values-my-rMM/strings.xml @@ -237,7 +237,8 @@ <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"4G data ခေတ္တရပ်တန့်သည်"</string> <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"cellular data ခေတ္တရပ်တန့်သည်"</string> <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"ဒေတာ ခေတ္တရပ်တန့်သည်"</string> - <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"သင့် ဒေတာ အသုံးပြုမှု သတ်မှတ်ထားချက်သို့ ရောက်ရှိသောကြောင့်၊ ဤကာလအတွက် ကျန်ရှိသည့် ဒေတာအသုံးပြုမှုအား စက်ပစ္စည်းမှ ရပ်တန့်ထားသည်။\n\nဆက်လက်သွားပါက သင့်ဖုန်းဝန်ဆောင်မှုမှ သင့်အား ကုန်ကျစရိတ်တောင်းခံလိမ့်မည်။"</string> + <!-- no translation found for data_usage_disabled_dialog (1841738975235283398) --> + <skip /> <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"ပြန်ဆက်လုပ်ရန်"</string> <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"အင်တာနက်မရှိ"</string> <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"ကြိုးမဲ့ဆက်သွယ်မှု"</string> diff --git a/packages/SystemUI/res/values-nb/strings.xml b/packages/SystemUI/res/values-nb/strings.xml index 9d13ebf86ed4..0a4e0452ae46 100644 --- a/packages/SystemUI/res/values-nb/strings.xml +++ b/packages/SystemUI/res/values-nb/strings.xml @@ -237,7 +237,8 @@ <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"4G-data er satt på pause"</string> <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"Mobildata er satt på pause"</string> <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"Data er satt på pause"</string> - <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"Fordi den angitte datagrensen ble nådd, har enheten satt databruk på pause for resten av denne syklusen. \n\nHvis du gjenopptar bruken, kan det føre til avgifter fra operatøren din."</string> + <!-- no translation found for data_usage_disabled_dialog (1841738975235283398) --> + <skip /> <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"Gjenoppta"</string> <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Ingen Internett-forbindelse"</string> <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi tilkoblet"</string> diff --git a/packages/SystemUI/res/values-ne-rNP/strings.xml b/packages/SystemUI/res/values-ne-rNP/strings.xml index 0a37810008ee..47d326c60f31 100644 --- a/packages/SystemUI/res/values-ne-rNP/strings.xml +++ b/packages/SystemUI/res/values-ne-rNP/strings.xml @@ -237,7 +237,8 @@ <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"4G डेटा रोकिएको छ"</string> <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"सेल्यूलर डेटा रोकिएको छ"</string> <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"डेटा रोकिएको छ"</string> - <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"तपाईंले सेट गर्नुभएको डेटाको सीमा पुगेकाले, यन्त्रले यस चक्रको बाँकी भागका लागि डेटाको प्रयोग रोकेको छ।\n\nपुन: सुरू गर्दा तपाईंको क्यारियरले शुल्कहरू लिन सक्छ।"</string> + <!-- no translation found for data_usage_disabled_dialog (1841738975235283398) --> + <skip /> <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"पुनः सुरु गर्नुहोस्"</string> <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"इन्टरनेट जडान छैन"</string> <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi जडित"</string> diff --git a/packages/SystemUI/res/values-nl/strings.xml b/packages/SystemUI/res/values-nl/strings.xml index ef55b3c18596..49319d166243 100644 --- a/packages/SystemUI/res/values-nl/strings.xml +++ b/packages/SystemUI/res/values-nl/strings.xml @@ -237,7 +237,8 @@ <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"4G-data zijn onderbroken"</string> <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"Mobiele gegevens zijn onderbroken"</string> <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"Gegevens zijn onderbroken"</string> - <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"Omdat de ingestelde gegevenslimiet is bereikt, heeft het apparaat het gegevensverbruik onderbroken voor de rest van deze cyclus.\n\nAls u het gegevensverbruik hervat, kan je provider kosten in rekening brengen."</string> + <!-- no translation found for data_usage_disabled_dialog (1841738975235283398) --> + <skip /> <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"Hervatten"</string> <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Geen internetverbinding"</string> <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Verbonden via wifi"</string> diff --git a/packages/SystemUI/res/values-pa-rIN/strings.xml b/packages/SystemUI/res/values-pa-rIN/strings.xml index 635e96e056bb..082ff3a2b256 100644 --- a/packages/SystemUI/res/values-pa-rIN/strings.xml +++ b/packages/SystemUI/res/values-pa-rIN/strings.xml @@ -237,7 +237,8 @@ <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"4G ਡੈਟਾ ਰੁਕ ਗਿਆ ਹੈ"</string> <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"ਸੈਲਿਊਲਰ ਡੈਟਾ ਰੁਕ ਗਿਆ ਹੈ"</string> <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"ਡੈਟਾ ਰੁਕ ਗਿਆ ਹੈ"</string> - <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"ਕਿਉਂਕਿ ਤੁਹਾਡੀ ਸੈਟ ਡੈਟਾ ਸੀਮਾ ਪੂਰੀ ਹੋ ਗਈ ਸੀ, ਡੀਵਾਈਸ ਨੇ ਇਸ ਬਾਕੀ ਚੱਕਰ ਲਈ ਡੈਟਾ ਉਪਯੋਗ ਰੋਕ ਦਿੱਤਾ ਹੈ।\n\nਇਸਨੂੰ ਦੁਬਾਰਾ ਸ਼ੁਰੂ ਕਰਨ ਨਾਲ ਤੁਹਾਡੇ ਕੈਰੀਅਰ ਵੱਲੋਂ ਖ਼ਰਚੇ ਪਾਏ ਜਾ ਸਕਦੇ ਹਨ।"</string> + <!-- no translation found for data_usage_disabled_dialog (1841738975235283398) --> + <skip /> <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"ਦੁਬਾਰਾ ਸ਼ੁਰੂ ਕਰੋ"</string> <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"ਕੋਈ ਇੰਟਰਨੈਟ ਕਨੈਕਸ਼ਨ ਨਹੀਂ"</string> <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi ਕਨੈਕਟ ਕੀਤਾ"</string> diff --git a/packages/SystemUI/res/values-pl/strings.xml b/packages/SystemUI/res/values-pl/strings.xml index 5d3fd99e7241..52bce7ce8648 100644 --- a/packages/SystemUI/res/values-pl/strings.xml +++ b/packages/SystemUI/res/values-pl/strings.xml @@ -239,7 +239,8 @@ <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"Transmisja danych 4G została wstrzymana"</string> <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"Komórkowa transmisja danych została wstrzymana"</string> <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"Transmisja danych została wstrzymana"</string> - <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"Ponieważ został osiągnięty ustawiony przez Ciebie limit danych, urządzenie wstrzymało użycie danych na pozostałą część tego cyklu.\n\nWznowienie może spowodować naliczenie opłat przez operatora."</string> + <!-- no translation found for data_usage_disabled_dialog (1841738975235283398) --> + <skip /> <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"Wznów"</string> <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Brak internetu"</string> <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi: połączono"</string> diff --git a/packages/SystemUI/res/values-pt-rBR/strings.xml b/packages/SystemUI/res/values-pt-rBR/strings.xml index 298fc3cb93c5..5ecf074c1359 100644 --- a/packages/SystemUI/res/values-pt-rBR/strings.xml +++ b/packages/SystemUI/res/values-pt-rBR/strings.xml @@ -239,7 +239,8 @@ <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"Os dados 4G foram pausados"</string> <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"Os dados da rede celular foram pausados"</string> <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"Os dados foram pausados"</string> - <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"Como seu limite de dados definido foi atingido, o dispositivo pausou o uso de dados para o restante deste ciclo.\n\nA retomada pode gerar cobranças por parte da sua operadora."</string> + <!-- no translation found for data_usage_disabled_dialog (1841738975235283398) --> + <skip /> <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"Retomar"</string> <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Sem conexão à Internet"</string> <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi conectado"</string> diff --git a/packages/SystemUI/res/values-pt-rPT/strings.xml b/packages/SystemUI/res/values-pt-rPT/strings.xml index 33176b6a464b..c1e662c159d7 100644 --- a/packages/SystemUI/res/values-pt-rPT/strings.xml +++ b/packages/SystemUI/res/values-pt-rPT/strings.xml @@ -237,7 +237,8 @@ <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"Dados 4G em pausa"</string> <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"Dados de redes móveis em pausa"</string> <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"Dados em pausa"</string> - <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"Uma vez que foi atingido o limite de dados definido, foi interrompida a utilização de dados no seu dispositivo durante o tempo restante deste ciclo.\n\nSe retomar a utilização, o seu operador pode efetuar cobranças."</string> + <!-- no translation found for data_usage_disabled_dialog (1841738975235283398) --> + <skip /> <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"Retomar"</string> <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Sem ligação internet"</string> <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi ligado"</string> diff --git a/packages/SystemUI/res/values-pt/strings.xml b/packages/SystemUI/res/values-pt/strings.xml index 298fc3cb93c5..5ecf074c1359 100644 --- a/packages/SystemUI/res/values-pt/strings.xml +++ b/packages/SystemUI/res/values-pt/strings.xml @@ -239,7 +239,8 @@ <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"Os dados 4G foram pausados"</string> <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"Os dados da rede celular foram pausados"</string> <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"Os dados foram pausados"</string> - <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"Como seu limite de dados definido foi atingido, o dispositivo pausou o uso de dados para o restante deste ciclo.\n\nA retomada pode gerar cobranças por parte da sua operadora."</string> + <!-- no translation found for data_usage_disabled_dialog (1841738975235283398) --> + <skip /> <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"Retomar"</string> <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Sem conexão à Internet"</string> <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi conectado"</string> diff --git a/packages/SystemUI/res/values-ro/strings.xml b/packages/SystemUI/res/values-ro/strings.xml index 9d6b7d902350..bedb7d0d1ff2 100644 --- a/packages/SystemUI/res/values-ro/strings.xml +++ b/packages/SystemUI/res/values-ro/strings.xml @@ -240,7 +240,8 @@ <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"Conexiunea de date 4G este întreruptă"</string> <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"Conexiunea de date mobile este întreruptă"</string> <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"Conexiunea de date este întreruptă"</string> - <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"Deoarece limita setată pentru date a fost atinsă, dispozitivul a întrerupt utilizarea datelor pentru restul acestui ciclu.\n\nReluarea utilizării de date poate genera aplicarea de taxe de către operator."</string> + <!-- no translation found for data_usage_disabled_dialog (1841738975235283398) --> + <skip /> <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"Reluați"</string> <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Fără conex. internet"</string> <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi conectat"</string> diff --git a/packages/SystemUI/res/values-ru/strings.xml b/packages/SystemUI/res/values-ru/strings.xml index 9ac4155f757c..a1551042ed80 100644 --- a/packages/SystemUI/res/values-ru/strings.xml +++ b/packages/SystemUI/res/values-ru/strings.xml @@ -241,7 +241,8 @@ <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"Передача данных 4G приостановлена"</string> <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"Передача мобильных данных приостановлена"</string> <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"Передача данных приостановлена"</string> - <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"Передача данных выключена до конца цикла, поскольку достигнут установленный вами лимит.\n\nЕсли вы возобновите ее, оператор может взимать плату за дополнительный расход трафика."</string> + <!-- no translation found for data_usage_disabled_dialog (1841738975235283398) --> + <skip /> <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"Возобновить"</string> <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Нет интернет-подключения"</string> <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi подключено"</string> diff --git a/packages/SystemUI/res/values-si-rLK/strings.xml b/packages/SystemUI/res/values-si-rLK/strings.xml index 95cac9e32a04..567d9e9dc424 100644 --- a/packages/SystemUI/res/values-si-rLK/strings.xml +++ b/packages/SystemUI/res/values-si-rLK/strings.xml @@ -237,7 +237,8 @@ <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"4G දත්ත විරාම කර ඇත"</string> <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"සෙලියුලර් දත්ත විරාම කර ඇත"</string> <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"දත්ත විරාම කර ඇත"</string> - <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"ඔබ සකසා ඇති දත්ත සීමාවට ළඟා වූ නිසා, උපාංගය මගින් මෙම චක්රයේ ඉතිරිය සඳහා දත්ත භාවිතය විරාම කර ඇත. \n\nනැවත පටන් ගැනීමෙන් ඔබගේ වාහකයෙන් අය කිරීම් වලට පොළඹවනු ඇත."</string> + <!-- no translation found for data_usage_disabled_dialog (1841738975235283398) --> + <skip /> <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"නැවත පටන්ගන්න"</string> <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"අන්තර්ජාල සම්බන්ධතාවයක් නැත"</string> <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi සම්බන්ධිතයි"</string> diff --git a/packages/SystemUI/res/values-sk/strings.xml b/packages/SystemUI/res/values-sk/strings.xml index 9c534c56e1f3..527a1fc3b546 100644 --- a/packages/SystemUI/res/values-sk/strings.xml +++ b/packages/SystemUI/res/values-sk/strings.xml @@ -241,7 +241,8 @@ <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"Dátové prenosy 4G sú pozastavené"</string> <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"Mobilné dáta sú pozastavené"</string> <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"Dáta sú pozastavené"</string> - <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"Keďže ste dosiahli nastavený limit pre mobilné dáta, na zariadení bola pre zvyšok tohto cyklu pozastavená spotreba dát.\n\nJej opätovné spustenie môže mať za následok účtovanie poplatkov vaším operátorom."</string> + <!-- no translation found for data_usage_disabled_dialog (1841738975235283398) --> + <skip /> <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"Znova spustiť"</string> <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Bez prip. na Internet"</string> <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi: pripojené"</string> diff --git a/packages/SystemUI/res/values-sl/strings.xml b/packages/SystemUI/res/values-sl/strings.xml index d930a72d78be..3134962f48ad 100644 --- a/packages/SystemUI/res/values-sl/strings.xml +++ b/packages/SystemUI/res/values-sl/strings.xml @@ -241,7 +241,8 @@ <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"Prenos podatkov v omrežju 4G je zaustavljen"</string> <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"Prenos mobilnih podatkov je zaustavljen"</string> <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"Prenos podatkov je zaustavljen"</string> - <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"Dosegli ste nastavljeno omejitev količine prenesenih podatkov, zato je naprava zaustavila porabo podatkov za preostanek cikla.\n\nČe nadaljujete s porabo, boste morda morali plačati stroške operaterju."</string> + <!-- no translation found for data_usage_disabled_dialog (1841738975235283398) --> + <skip /> <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"Nadaljuj"</string> <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Ni internetne povez."</string> <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi povezan"</string> diff --git a/packages/SystemUI/res/values-sq-rAL/strings.xml b/packages/SystemUI/res/values-sq-rAL/strings.xml index 7c11eb970e19..afa7694af5d6 100644 --- a/packages/SystemUI/res/values-sq-rAL/strings.xml +++ b/packages/SystemUI/res/values-sq-rAL/strings.xml @@ -237,7 +237,8 @@ <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"Të dhënat 4G janë ndërprerë"</string> <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"Të dhënat celulare janë ndërprerë"</string> <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"Të dhënat janë ndërprerë"</string> - <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"Pajisja jote ka ndërprerë përdorimin e të dhënave për pjesën e mbetur të ciklit sepse është arritur kufiri i caktuar i të dhënave.\n\nVazhdimi mund të sjellë tarifa nga operatori celular."</string> + <!-- no translation found for data_usage_disabled_dialog (1841738975235283398) --> + <skip /> <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"Rifillo"</string> <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Nuk ka lidhje interneti"</string> <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi është i lidhur"</string> diff --git a/packages/SystemUI/res/values-sr/strings.xml b/packages/SystemUI/res/values-sr/strings.xml index 30c14680b1bc..06fabeedecf4 100644 --- a/packages/SystemUI/res/values-sr/strings.xml +++ b/packages/SystemUI/res/values-sr/strings.xml @@ -238,7 +238,8 @@ <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"4G подаци су паузирани"</string> <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"Мобилни подаци су паузирани"</string> <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"Подаци су паузирани"</string> - <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"Због тога што сте достигли подешено ограничење за податке, уређај је паузирао коришћење података током остатка овог циклуса.\n\nАко наставите, мобилни оператер може да вам наплати додатне трошкове."</string> + <!-- no translation found for data_usage_disabled_dialog (1841738975235283398) --> + <skip /> <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"Настави"</string> <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Нема интернет везе"</string> <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi је повезан"</string> diff --git a/packages/SystemUI/res/values-sv/strings.xml b/packages/SystemUI/res/values-sv/strings.xml index b574e90b30c9..8b110c513ffd 100644 --- a/packages/SystemUI/res/values-sv/strings.xml +++ b/packages/SystemUI/res/values-sv/strings.xml @@ -237,7 +237,8 @@ <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"4G-data har pausats"</string> <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"Mobildata har pausats"</string> <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"Dataanvändningen har pausats"</string> - <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"Eftersom du har nått den angivna datagränsen har dataanvändningen pausats under resten av perioden.\n\nOm du återupptar dataanvändningen kan avgifter från operatören tillkomma."</string> + <!-- no translation found for data_usage_disabled_dialog (1841738975235283398) --> + <skip /> <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"Återuppta"</string> <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Ingen anslutning"</string> <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi-ansluten"</string> diff --git a/packages/SystemUI/res/values-sw/strings.xml b/packages/SystemUI/res/values-sw/strings.xml index 4e9d628d7554..be91af39bcd8 100644 --- a/packages/SystemUI/res/values-sw/strings.xml +++ b/packages/SystemUI/res/values-sw/strings.xml @@ -237,7 +237,8 @@ <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"Data ya 4G imesitishwa"</string> <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"Data ya simu ya mkononi imesitishwa"</string> <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"Data imesitishwa"</string> - <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"Kwa sababu ulifikia kiwango cha juu cha data kilichowekwa, kifaa kimesitisha matumizi ya data katika awamu hii iliyosalia.\n\n Kuendelea kunaweza kusababisha malipo kwa mtoa huduma wako."</string> + <!-- no translation found for data_usage_disabled_dialog (1841738975235283398) --> + <skip /> <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"Endelea"</string> <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Hakuna muunganisho wa mtandao"</string> <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Mtandao-hewa umeunganishwa"</string> diff --git a/packages/SystemUI/res/values-ta-rIN/strings.xml b/packages/SystemUI/res/values-ta-rIN/strings.xml index a2ed16f6929f..799d628e05f4 100644 --- a/packages/SystemUI/res/values-ta-rIN/strings.xml +++ b/packages/SystemUI/res/values-ta-rIN/strings.xml @@ -237,7 +237,8 @@ <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"4G டேட்டா இடைநிறுத்தப்பட்டது"</string> <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"செல்லுலார் தரவு இடைநிறுத்தப்பட்டது"</string> <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"தரவு இடைநிறுத்தப்பட்டது"</string> - <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"அமைக்கப்பட்ட தரவின் வரம்பை அடைந்துவிட்டதால், இந்தச் சுழற்சியின் மீதமுள்ள நாட்களுக்கான தரவுப் பயன்பாட்டைச் சாதனம் இடைநிறுத்தியுள்ளது.\n\nமீண்டும் தொடங்குவது, மொபைல் நிறுவனக் கட்டணங்களுக்கு உட்படுத்தலாம்."</string> + <!-- no translation found for data_usage_disabled_dialog (1841738975235283398) --> + <skip /> <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"மீண்டும் தொடங்கு"</string> <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"இணைய இணைப்பு இல்லை"</string> <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"வைஃபை இணைக்கப்பட்டது"</string> diff --git a/packages/SystemUI/res/values-te-rIN/strings.xml b/packages/SystemUI/res/values-te-rIN/strings.xml index fdb509265a09..f6e3ee23f399 100644 --- a/packages/SystemUI/res/values-te-rIN/strings.xml +++ b/packages/SystemUI/res/values-te-rIN/strings.xml @@ -237,7 +237,8 @@ <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"4G డేటా పాజ్ చేయబడింది"</string> <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"సెల్యులార్ డేటా పాజ్ చేయబడింది"</string> <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"డేటా పాజ్ చేయబడింది"</string> - <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"మీ సెట్ చేయబడిన డేటా పరిమితిని చేరుకున్నందున పరికరం ఈ సైకిల్లో మిగిలిన భాగానికి డేటా వినియోగాన్ని పాజ్ చేసింది.\n\nపునఃప్రారంభించడం వలన మీ క్యారియర్ ఛార్జీలు విధించవచ్చు."</string> + <!-- no translation found for data_usage_disabled_dialog (1841738975235283398) --> + <skip /> <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"పునఃప్రారంభించు"</string> <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"ఇంటర్నెట్ కనెక్షన్ లేదు"</string> <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi కనెక్ట్ చేయబడింది"</string> diff --git a/packages/SystemUI/res/values-th/strings.xml b/packages/SystemUI/res/values-th/strings.xml index 678937a9b1ec..0482e3bc92e6 100644 --- a/packages/SystemUI/res/values-th/strings.xml +++ b/packages/SystemUI/res/values-th/strings.xml @@ -237,7 +237,8 @@ <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"หยุดการใช้ข้อมูล 4G ชั่วคราวแล้ว"</string> <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"หยุดการใช้ข้อมูลมือถือชั่วคราวแล้ว"</string> <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"หยุดการใช้ข้อมูลชั่วคราวแล้ว"</string> - <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"เนื่องจากใช้งานข้อมูลถึงขีดจำกัดที่กำหนดไว้แล้ว อุปกรณ์จึงหยุดการใช้งานข้อมูลไว้ชั่วคราวตลอดระยะเวลาที่เหลือของรอบนี้\n\nการทำให้กลับมาทำงานอีกครั้งอาจทำให้เกิดค่าใช้จ่ายจากผู้ให้บริการ"</string> + <!-- no translation found for data_usage_disabled_dialog (1841738975235283398) --> + <skip /> <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"ทำต่อ"</string> <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"ไม่มีอินเทอร์เน็ต"</string> <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"เชื่อมต่อ WiFi แล้ว"</string> diff --git a/packages/SystemUI/res/values-tl/strings.xml b/packages/SystemUI/res/values-tl/strings.xml index 50c7e5c153c4..9b104f5391ad 100644 --- a/packages/SystemUI/res/values-tl/strings.xml +++ b/packages/SystemUI/res/values-tl/strings.xml @@ -237,7 +237,8 @@ <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"Naka-pause ang 4G data"</string> <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"Naka-pause ang cellular data"</string> <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"Naka-pause ang data"</string> - <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"Dahil naabot ang iyong nakatakdang limitasyon sa data, na-pause ng device ang paggamit ng data para sa nalalabing bahagi ng cycle na ito.\n\nMaaaring makakuha ng mga singilin mula sa iyong carrier ang pagpapatuloy."</string> + <!-- no translation found for data_usage_disabled_dialog (1841738975235283398) --> + <skip /> <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"Ipagpatuloy"</string> <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Walang koneksyon sa Internet"</string> <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"nakakonekta ang Wi-Fi"</string> diff --git a/packages/SystemUI/res/values-tr/strings.xml b/packages/SystemUI/res/values-tr/strings.xml index 575d011b905f..e655cd637bf7 100644 --- a/packages/SystemUI/res/values-tr/strings.xml +++ b/packages/SystemUI/res/values-tr/strings.xml @@ -237,7 +237,8 @@ <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"4G veri kullanımı duraklatıldı"</string> <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"Hücresel veri kullanımı duraklatıldı"</string> <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"Veri kullanımı duraklatıldı"</string> - <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"Ayarlanmış olan veri sınırınıza ulaşıldığından, bu dönemin kalan süresi için cihazda veri kullanımı duraklatıldı.\n\nVeri kullanımını devam ettirmek, operatörünüzün sizden ödeme almasına neden olabilir."</string> + <!-- no translation found for data_usage_disabled_dialog (1841738975235283398) --> + <skip /> <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"Devam ettir"</string> <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"İnternet bağlantısı yok"</string> <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Kablosuz bağlandı"</string> diff --git a/packages/SystemUI/res/values-uk/strings.xml b/packages/SystemUI/res/values-uk/strings.xml index 4d4162c5e45d..eccc4a27aa1b 100644 --- a/packages/SystemUI/res/values-uk/strings.xml +++ b/packages/SystemUI/res/values-uk/strings.xml @@ -241,7 +241,8 @@ <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"Передавання даних 4G призупинено"</string> <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"Передавання мобільних даних призупинено"</string> <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"Передавання даних призупинено"</string> - <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"Пристрій призупинив передавання даних до кінця цього циклу, оскільки ваш ліміт перевищено.\n\nЯкщо ви відновите передавання даних, оператор може стягувати додаткову плату."</string> + <!-- no translation found for data_usage_disabled_dialog (1841738975235283398) --> + <skip /> <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"Відновити"</string> <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Немає з’єднання"</string> <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi під’єднано"</string> diff --git a/packages/SystemUI/res/values-ur-rPK/strings.xml b/packages/SystemUI/res/values-ur-rPK/strings.xml index 6a3e4db4b911..dc177d125c23 100644 --- a/packages/SystemUI/res/values-ur-rPK/strings.xml +++ b/packages/SystemUI/res/values-ur-rPK/strings.xml @@ -237,7 +237,8 @@ <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"4G ڈیٹا موقوف کر دیا گیا"</string> <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"سیلولر ڈیٹا موقوف کر دیا گیا"</string> <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"ڈیٹا موقوف کر دیا گیا"</string> - <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"چونکہ آپ کی سیٹ کردہ ڈیٹا کی حد تک پہنچ گیا، لہذا آلہ نے اس سائیکل کے بقیہ حصے کیلئے ڈیٹا کے استعمال کو موقوف کر دیا ہے۔\n\nدوبارہ شروع کرنے سے آپ کے کیریئر سے چارجز لگ سکتے ہیں۔"</string> + <!-- no translation found for data_usage_disabled_dialog (1841738975235283398) --> + <skip /> <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"دوبارہ شروع کریں"</string> <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"کوئی انٹرنیٹ کنکشن نہیں"</string> <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi مربوط ہے"</string> diff --git a/packages/SystemUI/res/values-uz-rUZ/strings.xml b/packages/SystemUI/res/values-uz-rUZ/strings.xml index f7bae9be7402..32fb3030d587 100644 --- a/packages/SystemUI/res/values-uz-rUZ/strings.xml +++ b/packages/SystemUI/res/values-uz-rUZ/strings.xml @@ -239,7 +239,8 @@ <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"4G internet to‘xtatib qo‘yildi"</string> <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"Mobil internetdan foydalanish to‘xtatib qo‘yildi"</string> <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"Internetdan foydalanish to‘xtatib qo‘yildi"</string> - <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"Siz o‘rnatgan mobil internet chekloviga yetgani bois joriy hisob-kitob davrining qolgan muddati uchun mobil internetdan foydalanish vaqtinchalik to‘xtatib qo‘yildi.\n\nAgar internetdan foydalanishni davom ettirsangiz, buning uchun uyali aloqa operatoringiz ortiqcha haq talab qilishi mumkin."</string> + <!-- no translation found for data_usage_disabled_dialog (1841738975235283398) --> + <skip /> <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"Davom etish"</string> <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Internetga ulanmagan"</string> <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi ulandi"</string> diff --git a/packages/SystemUI/res/values-vi/strings.xml b/packages/SystemUI/res/values-vi/strings.xml index df6fdb931955..41467968e137 100644 --- a/packages/SystemUI/res/values-vi/strings.xml +++ b/packages/SystemUI/res/values-vi/strings.xml @@ -237,7 +237,8 @@ <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"Đã tạm dừng dữ liệu 4G"</string> <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"Đã tạm dừng dữ liệu di động"</string> <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"Đã tạm dừng dữ liệu"</string> - <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"Vì bạn đã đạt tới giới hạn dữ liệu thiết lập nên thiết bị đã tạm dừng sử dụng dữ liệu cho phần còn lại của chu kỳ này.\n\nTiếp tục có thể dẫn tới nhà cung cấp dịch vụ của bạn sẽ tính phí."</string> + <!-- no translation found for data_usage_disabled_dialog (1841738975235283398) --> + <skip /> <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"Tiếp tục"</string> <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Ko có k.nối Internet"</string> <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Đã kết nối Wi-Fi"</string> diff --git a/packages/SystemUI/res/values-zh-rCN/strings.xml b/packages/SystemUI/res/values-zh-rCN/strings.xml index 7bda7a0f10bd..30f624545465 100644 --- a/packages/SystemUI/res/values-zh-rCN/strings.xml +++ b/packages/SystemUI/res/values-zh-rCN/strings.xml @@ -237,7 +237,8 @@ <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"4G 数据网络已暂停使用"</string> <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"移动数据网络已暂停使用"</string> <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"数据网络已暂停使用"</string> - <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"由于使用的数据流量已达到您所设置的上限,因此您的设备已暂停在此周期的剩余时间内使用数据流量。\n\n如果恢复数据流量使用,您的运营商可能会向您收取相应费用。"</string> + <!-- no translation found for data_usage_disabled_dialog (1841738975235283398) --> + <skip /> <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"恢复"</string> <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"未连接互联网"</string> <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"已连接到WLAN网络"</string> diff --git a/packages/SystemUI/res/values-zh-rHK/strings.xml b/packages/SystemUI/res/values-zh-rHK/strings.xml index 9dbf41f2956d..f00a30bf8f2b 100644 --- a/packages/SystemUI/res/values-zh-rHK/strings.xml +++ b/packages/SystemUI/res/values-zh-rHK/strings.xml @@ -239,7 +239,8 @@ <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"已暫停 4G 數據"</string> <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"已暫停流動數據"</string> <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"已暫停使用數據"</string> - <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"由於您已達到設定的數據用量上限,裝置已暫停使用數據,直到週期結束。\n\n如恢復使用數據,流動網絡供應商可能會向您收取費用。"</string> + <!-- no translation found for data_usage_disabled_dialog (1841738975235283398) --> + <skip /> <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"恢復"</string> <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"沒有互聯網連線"</string> <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi 已連線"</string> diff --git a/packages/SystemUI/res/values-zh-rTW/strings.xml b/packages/SystemUI/res/values-zh-rTW/strings.xml index b06103738e8b..34d12ffb67a9 100644 --- a/packages/SystemUI/res/values-zh-rTW/strings.xml +++ b/packages/SystemUI/res/values-zh-rTW/strings.xml @@ -237,7 +237,8 @@ <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"已暫停 4G 數據連線"</string> <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"已暫停行動數據連線"</string> <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"已暫停數據連線"</string> - <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"由於數據用量已達設定上限,裝置在這個週期的剩餘時間將暫停使用數據連線。\n\n如果恢復使用,行動通訊業者可能會向您收取額外的連線費用。"</string> + <!-- no translation found for data_usage_disabled_dialog (1841738975235283398) --> + <skip /> <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"恢復連線"</string> <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"沒有網際網路連線"</string> <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi 已連線"</string> diff --git a/packages/SystemUI/res/values-zu/strings.xml b/packages/SystemUI/res/values-zu/strings.xml index f97e71a25c3a..1b2794e1d42b 100644 --- a/packages/SystemUI/res/values-zu/strings.xml +++ b/packages/SystemUI/res/values-zu/strings.xml @@ -237,7 +237,8 @@ <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"4G idatha imisiwe"</string> <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"Idatha yeselula imisiwe"</string> <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"Idatha imisiwe"</string> - <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"Ngoba umkhawulo wakho wedatha osethiwe ufinyelelwe, idivayisi imise kancane ukusetshenziswa kwedatha ngesikhumbuzi salo mjikelezo.\n\nUkuqhuba futhi kungaholela kuzindleko kusuka kwinkampani yakho yenethiwekhi."</string> + <!-- no translation found for data_usage_disabled_dialog (1841738975235283398) --> + <skip /> <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"Qalisa kabusha"</string> <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Alukho uxhumano lwe-Inthanethi"</string> <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"I-Wi-Fi ixhunyiwe"</string> diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml index 562fb7f62b83..3f485c3bad8b 100644 --- a/packages/SystemUI/res/values/strings.xml +++ b/packages/SystemUI/res/values/strings.xml @@ -1667,4 +1667,8 @@ <!-- accessibility label for paging indicator in quick settings [CHAR LIMITi=NONE] --> <string name="accessibility_quick_settings_page">Page <xliff:g name="current_page" example="1">%1$d</xliff:g> of <xliff:g name="num_pages" example="2">%2$d</xliff:g></string> + <!-- Plugin control section of the tuner. Non-translatable since it should + not appear on production builds ever. --> + <string name="plugins" translatable="false">Plugins</string> + </resources> diff --git a/packages/SystemUI/res/xml/tuner_prefs.xml b/packages/SystemUI/res/xml/tuner_prefs.xml index b46e862471f3..211f8e8183e8 100644 --- a/packages/SystemUI/res/xml/tuner_prefs.xml +++ b/packages/SystemUI/res/xml/tuner_prefs.xml @@ -133,6 +133,11 @@ android:title="@string/other" android:fragment="com.android.systemui.tuner.OtherPrefs" /> + <Preference + android:key="plugins" + android:title="@string/plugins" + android:fragment="com.android.systemui.tuner.PluginFragment" /> + <!-- Warning, this goes last. --> <Preference android:summary="@string/tuner_persistent_warning" diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java index 78e56c04ce9b..58d57f68d699 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java @@ -116,6 +116,8 @@ public class NotificationContentView extends FrameLayout { private boolean mForceSelectNextLayout = true; private PendingIntent mPreviousExpandedRemoteInputIntent; private PendingIntent mPreviousHeadsUpRemoteInputIntent; + private RemoteInputView mCachedExpandedRemoteInput; + private RemoteInputView mCachedHeadsUpRemoteInput; private int mContentHeightAtAnimationStart = UNDEFINED; private boolean mFocusOnVisibilityChange; @@ -298,6 +300,9 @@ public class NotificationContentView extends FrameLayout { mExpandedRemoteInput.onNotificationUpdateOrReset(); if (mExpandedRemoteInput.isActive()) { mPreviousExpandedRemoteInputIntent = mExpandedRemoteInput.getPendingIntent(); + mCachedExpandedRemoteInput = mExpandedRemoteInput; + mExpandedRemoteInput.dispatchStartTemporaryDetach(); + ((ViewGroup)mExpandedRemoteInput.getParent()).removeView(mExpandedRemoteInput); } } if (mExpandedChild != null) { @@ -310,6 +315,9 @@ public class NotificationContentView extends FrameLayout { mHeadsUpRemoteInput.onNotificationUpdateOrReset(); if (mHeadsUpRemoteInput.isActive()) { mPreviousHeadsUpRemoteInputIntent = mHeadsUpRemoteInput.getPendingIntent(); + mCachedHeadsUpRemoteInput = mHeadsUpRemoteInput; + mHeadsUpRemoteInput.dispatchStartTemporaryDetach(); + ((ViewGroup)mHeadsUpRemoteInput.getParent()).removeView(mHeadsUpRemoteInput); } } if (mHeadsUpChild != null) { @@ -963,22 +971,35 @@ public class NotificationContentView extends FrameLayout { View bigContentView = mExpandedChild; if (bigContentView != null) { mExpandedRemoteInput = applyRemoteInput(bigContentView, entry, hasRemoteInput, - mPreviousExpandedRemoteInputIntent); + mPreviousExpandedRemoteInputIntent, mCachedExpandedRemoteInput); } else { mExpandedRemoteInput = null; } + if (mCachedExpandedRemoteInput != null + && mCachedExpandedRemoteInput != mExpandedRemoteInput) { + // We had a cached remote input but didn't reuse it. Clean up required. + mCachedExpandedRemoteInput.dispatchFinishTemporaryDetach(); + } + mCachedExpandedRemoteInput = null; View headsUpContentView = mHeadsUpChild; if (headsUpContentView != null) { mHeadsUpRemoteInput = applyRemoteInput(headsUpContentView, entry, hasRemoteInput, - mPreviousHeadsUpRemoteInputIntent); + mPreviousHeadsUpRemoteInputIntent, mCachedHeadsUpRemoteInput); } else { mHeadsUpRemoteInput = null; } + if (mCachedHeadsUpRemoteInput != null + && mCachedHeadsUpRemoteInput != mHeadsUpRemoteInput) { + // We had a cached remote input but didn't reuse it. Clean up required. + mCachedHeadsUpRemoteInput.dispatchFinishTemporaryDetach(); + } + mCachedHeadsUpRemoteInput = null; } private RemoteInputView applyRemoteInput(View view, NotificationData.Entry entry, - boolean hasRemoteInput, PendingIntent existingPendingIntent) { + boolean hasRemoteInput, PendingIntent existingPendingIntent, + RemoteInputView cachedView) { View actionContainerCandidate = view.findViewById( com.android.internal.R.id.actions_container); if (actionContainerCandidate instanceof FrameLayout) { @@ -991,15 +1012,22 @@ public class NotificationContentView extends FrameLayout { if (existing == null && hasRemoteInput) { ViewGroup actionContainer = (FrameLayout) actionContainerCandidate; - RemoteInputView riv = RemoteInputView.inflate( - mContext, actionContainer, entry, mRemoteInputController); - - riv.setVisibility(View.INVISIBLE); - actionContainer.addView(riv, new LayoutParams( - ViewGroup.LayoutParams.MATCH_PARENT, - ViewGroup.LayoutParams.MATCH_PARENT) - ); - existing = riv; + if (cachedView == null) { + RemoteInputView riv = RemoteInputView.inflate( + mContext, actionContainer, entry, mRemoteInputController); + + riv.setVisibility(View.INVISIBLE); + actionContainer.addView(riv, new LayoutParams( + ViewGroup.LayoutParams.MATCH_PARENT, + ViewGroup.LayoutParams.MATCH_PARENT) + ); + existing = riv; + } else { + actionContainer.addView(cachedView); + cachedView.dispatchFinishTemporaryDetach(); + cachedView.requestFocus(); + existing = cachedView; + } } if (hasRemoteInput) { int color = entry.notification.getNotification().color; diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/RemoteInputController.java b/packages/SystemUI/src/com/android/systemui/statusbar/RemoteInputController.java index 6cbaceaa00ff..66cc15d7cc8f 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/RemoteInputController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/RemoteInputController.java @@ -21,7 +21,9 @@ import com.android.systemui.statusbar.phone.StatusBarWindowManager; import com.android.systemui.statusbar.policy.HeadsUpManager; import com.android.systemui.statusbar.policy.RemoteInputView; +import android.util.ArrayMap; import android.util.ArraySet; +import android.util.Pair; import java.lang.ref.WeakReference; import java.util.ArrayList; @@ -31,8 +33,9 @@ import java.util.ArrayList; */ public class RemoteInputController { - private final ArrayList<WeakReference<NotificationData.Entry>> mOpen = new ArrayList<>(); - private final ArraySet<String> mSpinning = new ArraySet<>(); + private final ArrayList<Pair<WeakReference<NotificationData.Entry>, Object>> mOpen + = new ArrayList<>(); + private final ArrayMap<String, Object> mSpinning = new ArrayMap<>(); private final ArrayList<Callback> mCallbacks = new ArrayList<>(3); private final HeadsUpManager mHeadsUpManager; @@ -41,36 +44,72 @@ public class RemoteInputController { mHeadsUpManager = headsUpManager; } - public void addRemoteInput(NotificationData.Entry entry) { + /** + * Adds a currently active remote input. + * + * @param entry the entry for which a remote input is now active. + * @param token a token identifying the view that is managing the remote input + */ + public void addRemoteInput(NotificationData.Entry entry, Object token) { Preconditions.checkNotNull(entry); + Preconditions.checkNotNull(token); boolean found = pruneWeakThenRemoveAndContains( - entry /* contains */, null /* remove */); + entry /* contains */, null /* remove */, token /* removeToken */); if (!found) { - mOpen.add(new WeakReference<>(entry)); + mOpen.add(new Pair<>(new WeakReference<>(entry), token)); } apply(entry); } - public void removeRemoteInput(NotificationData.Entry entry) { + /** + * Removes a currently active remote input. + * + * @param entry the entry for which a remote input should be removed. + * @param token a token identifying the view that is requesting the removal. If non-null, + * the entry is only removed if the token matches the last added token for this + * entry. If null, the entry is removed regardless. + */ + public void removeRemoteInput(NotificationData.Entry entry, Object token) { Preconditions.checkNotNull(entry); - pruneWeakThenRemoveAndContains(null /* contains */, entry /* remove */); + pruneWeakThenRemoveAndContains(null /* contains */, entry /* remove */, token); apply(entry); } - public void addSpinning(String key) { - mSpinning.add(key); + /** + * Adds a currently spinning (i.e. sending) remote input. + * + * @param key the key of the entry that's spinning. + * @param token the token of the view managing the remote input. + */ + public void addSpinning(String key, Object token) { + Preconditions.checkNotNull(key); + Preconditions.checkNotNull(token); + + mSpinning.put(key, token); } - public void removeSpinning(String key) { - mSpinning.remove(key); + /** + * Removes a currently spinning remote input. + * + * @param key the key of the entry for which a remote input should be removed. + * @param token a token identifying the view that is requesting the removal. If non-null, + * the entry is only removed if the token matches the last added token for this + * entry. If null, the entry is removed regardless. + */ + public void removeSpinning(String key, Object token) { + Preconditions.checkNotNull(key); + + if (token == null || mSpinning.get(key) == token) { + mSpinning.remove(key); + } } public boolean isSpinning(String key) { - return mSpinning.contains(key); + return mSpinning.containsKey(key); } private void apply(NotificationData.Entry entry) { @@ -86,14 +125,16 @@ public class RemoteInputController { * @return true if {@param entry} has an active RemoteInput */ public boolean isRemoteInputActive(NotificationData.Entry entry) { - return pruneWeakThenRemoveAndContains(entry /* contains */, null /* remove */); + return pruneWeakThenRemoveAndContains(entry /* contains */, null /* remove */, + null /* removeToken */); } /** * @return true if any entry has an active RemoteInput */ public boolean isRemoteInputActive() { - pruneWeakThenRemoveAndContains(null /* contains */, null /* remove */); + pruneWeakThenRemoveAndContains(null /* contains */, null /* remove */, + null /* removeToken */); return !mOpen.isEmpty(); } @@ -101,17 +142,27 @@ public class RemoteInputController { * Prunes dangling weak references, removes entries referring to {@param remove} and returns * whether {@param contains} is part of the array in a single loop. * @param remove if non-null, removes this entry from the active remote inputs + * @param removeToken if non-null, only removes an entry if this matches the token when the + * entry was added. * @return true if {@param contains} is in the set of active remote inputs */ private boolean pruneWeakThenRemoveAndContains( - NotificationData.Entry contains, NotificationData.Entry remove) { + NotificationData.Entry contains, NotificationData.Entry remove, Object removeToken) { boolean found = false; for (int i = mOpen.size() - 1; i >= 0; i--) { - NotificationData.Entry item = mOpen.get(i).get(); - if (item == null || item == remove) { + NotificationData.Entry item = mOpen.get(i).first.get(); + Object itemToken = mOpen.get(i).second; + boolean removeTokenMatches = (removeToken == null || itemToken == removeToken); + + if (item == null || (item == remove && removeTokenMatches)) { mOpen.remove(i); } else if (item == contains) { - found = true; + if (removeToken != null && removeToken != itemToken) { + // We need to update the token. Remove here and let caller reinsert it. + mOpen.remove(i); + } else { + found = true; + } } } return found; @@ -138,7 +189,7 @@ public class RemoteInputController { // Make a copy because closing the remote inputs will modify mOpen. ArrayList<NotificationData.Entry> list = new ArrayList<>(mOpen.size()); for (int i = mOpen.size() - 1; i >= 0; i--) { - NotificationData.Entry item = mOpen.get(i).get(); + NotificationData.Entry item = mOpen.get(i).first.get(); if (item != null && item.row != null) { list.add(item); } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java index cf87ddd17aae..a7331d8d3299 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java @@ -105,7 +105,7 @@ public class CarStatusBar extends PhoneStatusBar implements R.dimen.status_bar_connected_device_signal_margin_end)); mConnectedDeviceSignalController = new ConnectedDeviceSignalController(mContext, - mSignalsView); + mSignalsView, mBluetoothController); if (Log.isLoggable(TAG, Log.DEBUG)) { Log.d(TAG, "makeStatusBarView(). mBatteryMeterView: " + mBatteryMeterView); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/car/ConnectedDeviceSignalController.java b/packages/SystemUI/src/com/android/systemui/statusbar/car/ConnectedDeviceSignalController.java index 07856daa9d8a..66030b935f07 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/car/ConnectedDeviceSignalController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/car/ConnectedDeviceSignalController.java @@ -17,11 +17,15 @@ import android.view.View; import android.widget.ImageView; import com.android.systemui.R; import com.android.systemui.statusbar.ScalingDrawableWrapper; +import com.android.systemui.statusbar.policy.BluetoothController; + +import static com.android.systemui.statusbar.phone.PhoneStatusBar.DEBUG; /** * Controller that monitors signal strength for a device that is connected via bluetooth. */ -public class ConnectedDeviceSignalController extends BroadcastReceiver { +public class ConnectedDeviceSignalController extends BroadcastReceiver implements + BluetoothController.Callback { private final static String TAG = "DeviceSignalCtlr"; /** @@ -54,18 +58,21 @@ public class ConnectedDeviceSignalController extends BroadcastReceiver { private final BluetoothAdapter mAdapter = BluetoothAdapter.getDefaultAdapter(); private final Context mContext; - private final View mSignalsView; + private final BluetoothController mController; + private final View mSignalsView; private final ImageView mNetworkSignalView; private final float mIconScaleFactor; private BluetoothHeadsetClient mBluetoothHeadsetClient; - public ConnectedDeviceSignalController(Context context, View signalsView) { + public ConnectedDeviceSignalController(Context context, View signalsView, + BluetoothController controller) { mContext = context; - mSignalsView = signalsView; + mController = controller; + mSignalsView = signalsView; mNetworkSignalView = (ImageView) mSignalsView.findViewById(R.id.connected_device_network_signal); @@ -86,22 +93,46 @@ public class ConnectedDeviceSignalController extends BroadcastReceiver { filter.addAction(BluetoothHeadsetClient.ACTION_CONNECTION_STATE_CHANGED); filter.addAction(BluetoothHeadsetClient.ACTION_AG_EVENT); mContext.registerReceiver(this, filter); + + mController.addStateChangedCallback(this); } public void stopListening() { mContext.unregisterReceiver(this); + mController.removeStateChangedCallback(this); + } + + @Override + public void onBluetoothDevicesChanged() { + // Nothing to do here because this Controller is not displaying a list of possible + // bluetooth devices. + } + + @Override + public void onBluetoothStateChange(boolean enabled) { + if (DEBUG) { + Log.d(TAG, "onBluetoothStateChange(). enabled: " + enabled); + } + + // Only need to handle the case if bluetooth has been disabled, in which case the + // signal indicators are hidden. If bluetooth has been enabled, then this class should + // receive updates to the connection state via onReceive(). + if (!enabled) { + mNetworkSignalView.setVisibility(View.GONE); + mSignalsView.setVisibility(View.GONE); + } } @Override public void onReceive(Context context, Intent intent) { String action = intent.getAction(); - if (Log.isLoggable(TAG, Log.DEBUG)) { + if (DEBUG) { Log.d(TAG, "onReceive(). action: " + action); } if (BluetoothHeadsetClient.ACTION_AG_EVENT.equals(action)) { - if (Log.isLoggable(TAG, Log.DEBUG)) { + if (DEBUG) { Log.d(TAG, "Received ACTION_AG_EVENT"); } @@ -109,13 +140,13 @@ public class ConnectedDeviceSignalController extends BroadcastReceiver { } else if (BluetoothHeadsetClient.ACTION_CONNECTION_STATE_CHANGED.equals(action)) { int newState = intent.getIntExtra(BluetoothProfile.EXTRA_STATE, -1); - if (Log.isLoggable(TAG, Log.DEBUG)) { + if (DEBUG) { int oldState = intent.getIntExtra(BluetoothProfile.EXTRA_PREVIOUS_STATE, -1); Log.d(TAG, "ACTION_CONNECTION_STATE_CHANGED event: " + oldState + " -> " + newState); } BluetoothDevice device = - (BluetoothDevice)intent.getExtra(BluetoothDevice.EXTRA_DEVICE); + (BluetoothDevice) intent.getExtra(BluetoothDevice.EXTRA_DEVICE); updateViewVisibility(device, newState); } } @@ -128,7 +159,7 @@ public class ConnectedDeviceSignalController extends BroadcastReceiver { int networkStatus = intent.getIntExtra(BluetoothHeadsetClient.EXTRA_NETWORK_STATUS, INVALID_SIGNAL); if (networkStatus != INVALID_SIGNAL) { - if (Log.isLoggable(TAG, Log.DEBUG)) { + if (DEBUG) { Log.d(TAG, "EXTRA_NETWORK_STATUS: " + " " + networkStatus); } @@ -140,7 +171,7 @@ public class ConnectedDeviceSignalController extends BroadcastReceiver { int signalStrength = intent.getIntExtra( BluetoothHeadsetClient.EXTRA_NETWORK_SIGNAL_STRENGTH, INVALID_SIGNAL); if (signalStrength != INVALID_SIGNAL) { - if (Log.isLoggable(TAG, Log.DEBUG)) { + if (DEBUG) { Log.d(TAG, "EXTRA_NETWORK_SIGNAL_STRENGTH: " + signalStrength); } @@ -150,7 +181,7 @@ public class ConnectedDeviceSignalController extends BroadcastReceiver { int roamingStatus = intent.getIntExtra(BluetoothHeadsetClient.EXTRA_NETWORK_ROAMING, INVALID_SIGNAL); if (roamingStatus != INVALID_SIGNAL) { - if (Log.isLoggable(TAG, Log.DEBUG)) { + if (DEBUG) { Log.d(TAG, "EXTRA_NETWORK_ROAMING: " + roamingStatus); } } @@ -169,7 +200,7 @@ public class ConnectedDeviceSignalController extends BroadcastReceiver { private void updateViewVisibility(BluetoothDevice device, int newState) { if (newState == BluetoothProfile.STATE_CONNECTED) { - if (Log.isLoggable(TAG, Log.DEBUG)) { + if (DEBUG) { Log.d(TAG, "Device connected"); } @@ -186,14 +217,14 @@ public class ConnectedDeviceSignalController extends BroadcastReceiver { int signalStrength = featuresBundle.getInt( BluetoothHeadsetClient.EXTRA_NETWORK_SIGNAL_STRENGTH, INVALID_SIGNAL); if (signalStrength != INVALID_SIGNAL) { - if (Log.isLoggable(TAG, Log.DEBUG)) { + if (DEBUG) { Log.d(TAG, "EXTRA_NETWORK_SIGNAL_STRENGTH: " + signalStrength); } setNetworkSignalIcon(SIGNAL_STRENGTH_ICONS[signalStrength]); } } else if (newState == BluetoothProfile.STATE_DISCONNECTED) { - if (Log.isLoggable(TAG, Log.DEBUG)) { + if (DEBUG) { Log.d(TAG, "Device disconnected"); } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java index 40303c4ac37c..8ee014c4583a 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java @@ -313,7 +313,7 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode, PhoneStatusBarPolicy mIconPolicy; // These are no longer handled by the policy, because we need custom strategies for them - BluetoothControllerImpl mBluetoothController; + protected BluetoothControllerImpl mBluetoothController; SecurityControllerImpl mSecurityController; protected BatteryController mBatteryController; LocationControllerImpl mLocationController; @@ -1733,7 +1733,7 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode, protected void performRemoveNotification(StatusBarNotification n, boolean removeView) { Entry entry = mNotificationData.get(n.getKey()); if (mRemoteInputController.isRemoteInputActive(entry)) { - mRemoteInputController.removeRemoteInput(entry); + mRemoteInputController.removeRemoteInput(entry, null); } super.performRemoveNotification(n, removeView); } @@ -2681,7 +2681,7 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode, private void removeRemoteInputEntriesKeptUntilCollapsed() { for (int i = 0; i < mRemoteInputEntriesToRemoveOnCollapse.size(); i++) { Entry entry = mRemoteInputEntriesToRemoveOnCollapse.valueAt(i); - mRemoteInputController.removeRemoteInput(entry); + mRemoteInputController.removeRemoteInput(entry, null); removeNotification(entry.key, mLatestRankingMap); } mRemoteInputEntriesToRemoveOnCollapse.clear(); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputView.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputView.java index ab2a8bc6e92b..7b1f7071b5c7 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputView.java @@ -69,6 +69,8 @@ public class RemoteInputView extends LinearLayout implements View.OnClickListene // A marker object that let's us easily find views of this class. public static final Object VIEW_TAG = new Object(); + public final Object mToken = new Object(); + private RemoteEditText mEditText; private ImageButton mSendButton; private ProgressBar mProgressBar; @@ -140,8 +142,8 @@ public class RemoteInputView extends LinearLayout implements View.OnClickListene mSendButton.setVisibility(INVISIBLE); mProgressBar.setVisibility(VISIBLE); mEntry.remoteInputText = mEditText.getText(); - mController.addSpinning(mEntry.key); - mController.removeRemoteInput(mEntry); + mController.addSpinning(mEntry.key, mToken); + mController.removeRemoteInput(mEntry, mToken); mEditText.mShowImeOnInputConnection = false; mController.remoteInputSent(mEntry); @@ -193,7 +195,7 @@ public class RemoteInputView extends LinearLayout implements View.OnClickListene } private void onDefocus(boolean animate) { - mController.removeRemoteInput(mEntry); + mController.removeRemoteInput(mEntry, mToken); mEntry.remoteInputText = mEditText.getText(); // During removal, we get reattached and lose focus. Not hiding in that @@ -232,11 +234,11 @@ public class RemoteInputView extends LinearLayout implements View.OnClickListene @Override protected void onDetachedFromWindow() { super.onDetachedFromWindow(); - if (mEntry.row.isChangingPosition()) { + if (mEntry.row.isChangingPosition() || isTemporarilyDetached()) { return; } - mController.removeRemoteInput(mEntry); - mController.removeSpinning(mEntry.key); + mController.removeRemoteInput(mEntry, mToken); + mController.removeSpinning(mEntry.key, mToken); } public void setPendingIntent(PendingIntent pendingIntent) { @@ -265,7 +267,7 @@ public class RemoteInputView extends LinearLayout implements View.OnClickListene mEntry.notification.getPackageName()); setVisibility(VISIBLE); - mController.addRemoteInput(mEntry); + mController.addRemoteInput(mEntry, mToken); mEditText.setInnerFocusable(true); mEditText.mShowImeOnInputConnection = true; mEditText.setText(mEntry.remoteInputText); @@ -290,7 +292,7 @@ public class RemoteInputView extends LinearLayout implements View.OnClickListene mEditText.setEnabled(true); mSendButton.setVisibility(VISIBLE); mProgressBar.setVisibility(INVISIBLE); - mController.removeSpinning(mEntry.key); + mController.removeSpinning(mEntry.key, mToken); updateSendButton(); onDefocus(false /* animate */); @@ -432,6 +434,24 @@ public class RemoteInputView extends LinearLayout implements View.OnClickListene mRevealR = r; } + @Override + public void dispatchStartTemporaryDetach() { + super.dispatchStartTemporaryDetach(); + // Detach the EditText temporarily such that it doesn't get onDetachedFromWindow and + // won't lose IME focus. + detachViewFromParent(mEditText); + } + + @Override + public void dispatchFinishTemporaryDetach() { + if (isAttachedToWindow()) { + attachViewToParent(mEditText, 0, mEditText.getLayoutParams()); + } else { + removeDetachedView(mEditText, false /* animate */); + } + super.dispatchFinishTemporaryDetach(); + } + /** * An EditText that changes appearance based on whether it's focusable and becomes * un-focusable whenever the user navigates away from it or it becomes invisible. @@ -448,7 +468,15 @@ public class RemoteInputView extends LinearLayout implements View.OnClickListene } private void defocusIfNeeded(boolean animate) { - if (mRemoteInputView != null && mRemoteInputView.mEntry.row.isChangingPosition()) { + if (mRemoteInputView != null && mRemoteInputView.mEntry.row.isChangingPosition() + || isTemporarilyDetached()) { + if (isTemporarilyDetached()) { + // We might get reattached but then the other one of HUN / expanded might steal + // our focus, so we'll need to save our text here. + if (mRemoteInputView != null) { + mRemoteInputView.mEntry.remoteInputText = getText(); + } + } return; } if (isFocusable() && isEnabled()) { diff --git a/packages/SystemUI/src/com/android/systemui/tuner/PluginFragment.java b/packages/SystemUI/src/com/android/systemui/tuner/PluginFragment.java new file mode 100644 index 000000000000..132a6dd6c747 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/tuner/PluginFragment.java @@ -0,0 +1,111 @@ +/* + * Copyright (C) 2016 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the + * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +package com.android.systemui.tuner; + +import android.content.ComponentName; +import android.content.Context; +import android.content.Intent; +import android.content.pm.PackageManager; +import android.content.pm.ResolveInfo; +import android.os.Bundle; +import android.support.v14.preference.PreferenceFragment; +import android.support.v14.preference.SwitchPreference; +import android.support.v7.preference.PreferenceCategory; +import android.support.v7.preference.PreferenceScreen; +import android.support.v7.preference.PreferenceViewHolder; +import android.view.View; + +import com.android.systemui.plugins.PluginPrefs; +import com.android.systemui.R; + +import java.util.List; +import java.util.Set; + +public class PluginFragment extends PreferenceFragment { + + public static final String ACTION_PLUGIN_SETTINGS + = "com.android.systemui.action.PLUGIN_SETTINGS"; + + private PluginPrefs mPluginPrefs; + + @Override + public void onCreatePreferences(Bundle savedInstanceState, String rootKey) { + PreferenceScreen screen = getPreferenceManager().createPreferenceScreen(getContext()); + screen.setOrderingAsAdded(false); + Context prefContext = getPreferenceManager().getContext(); + mPluginPrefs = new PluginPrefs(getContext()); + Set<String> pluginActions = mPluginPrefs.getPluginList(); + for (String action : pluginActions) { + String name = action.replace("com.android.systemui.action.PLUGIN_", ""); + PreferenceCategory category = new PreferenceCategory(prefContext); + category.setTitle(name); + + List<ResolveInfo> result = getContext().getPackageManager().queryIntentServices( + new Intent(action), PackageManager.MATCH_DISABLED_COMPONENTS); + if (result.size() > 0) { + screen.addPreference(category); + } + for (ResolveInfo info : result) { + category.addPreference(new PluginPreference(prefContext, info)); + } + } + setPreferenceScreen(screen); + } + + private static class PluginPreference extends SwitchPreference { + private final ComponentName mComponent; + private final boolean mHasSettings; + + public PluginPreference(Context prefContext, ResolveInfo info) { + super(prefContext); + mComponent = new ComponentName(info.serviceInfo.packageName, info.serviceInfo.name); + PackageManager pm = prefContext.getPackageManager(); + mHasSettings = pm.resolveActivity(new Intent(ACTION_PLUGIN_SETTINGS) + .setPackage(mComponent.getPackageName()), 0) != null; + setTitle(info.serviceInfo.loadLabel(pm)); + setChecked(pm.getComponentEnabledSetting(mComponent) + != PackageManager.COMPONENT_ENABLED_STATE_DISABLED); + setWidgetLayoutResource(R.layout.tuner_widget_settings_switch); + } + + @Override + protected boolean persistBoolean(boolean value) { + getContext().getPackageManager().setComponentEnabledSetting(mComponent, + value ? PackageManager.COMPONENT_ENABLED_STATE_ENABLED + : PackageManager.COMPONENT_ENABLED_STATE_DISABLED, + PackageManager.DONT_KILL_APP); + return true; + } + + @Override + public void onBindViewHolder(PreferenceViewHolder holder) { + super.onBindViewHolder(holder); + holder.findViewById(R.id.settings).setVisibility(mHasSettings ? View.VISIBLE + : View.GONE); + holder.findViewById(R.id.divider).setVisibility(mHasSettings ? View.VISIBLE + : View.GONE); + holder.findViewById(R.id.settings).setOnClickListener(v -> { + ResolveInfo result = v.getContext().getPackageManager().resolveActivity( + new Intent(ACTION_PLUGIN_SETTINGS).setPackage( + mComponent.getPackageName()), 0); + if (result != null) { + v.getContext().startActivity(new Intent().setComponent( + new ComponentName(result.activityInfo.packageName, + result.activityInfo.name))); + } + }); + } + } +} diff --git a/packages/SystemUI/src/com/android/systemui/tuner/TunerFragment.java b/packages/SystemUI/src/com/android/systemui/tuner/TunerFragment.java index 70f2fdcfa8d3..7f63418de324 100644 --- a/packages/SystemUI/src/com/android/systemui/tuner/TunerFragment.java +++ b/packages/SystemUI/src/com/android/systemui/tuner/TunerFragment.java @@ -19,16 +19,9 @@ import android.app.AlertDialog; import android.app.Dialog; import android.app.DialogFragment; import android.content.DialogInterface; -import android.database.ContentObserver; -import android.net.Uri; import android.os.Bundle; -import android.os.Handler; import android.provider.Settings; -import android.provider.Settings.System; import android.support.v14.preference.PreferenceFragment; -import android.support.v14.preference.SwitchPreference; -import android.support.v7.preference.Preference; -import android.support.v7.preference.Preference.OnPreferenceChangeListener; import android.view.Menu; import android.view.MenuInflater; import android.view.MenuItem; @@ -36,12 +29,14 @@ import android.view.MenuItem; import com.android.internal.logging.MetricsLogger; import com.android.internal.logging.MetricsProto.MetricsEvent; import com.android.systemui.R; +import com.android.systemui.plugins.PluginPrefs; public class TunerFragment extends PreferenceFragment { private static final String TAG = "TunerFragment"; private static final String KEY_BATTERY_PCT = "battery_pct"; + private static final String KEY_PLUGINS = "plugins"; public static final String SETTING_SEEN_TUNER_WARNING = "seen_tuner_warning"; @@ -65,6 +60,9 @@ public class TunerFragment extends PreferenceFragment { @Override public void onCreatePreferences(Bundle savedInstanceState, String rootKey) { addPreferencesFromResource(R.xml.tuner_prefs); + if (!PluginPrefs.hasPlugins(getContext())) { + getPreferenceScreen().removePreference(findPreference(KEY_PLUGINS)); + } if (Settings.Secure.getInt(getContext().getContentResolver(), SETTING_SEEN_TUNER_WARNING, 0) == 0) { diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java index a2f3be720530..fa2f6ac3af82 100644 --- a/services/core/java/com/android/server/ConnectivityService.java +++ b/services/core/java/com/android/server/ConnectivityService.java @@ -5502,7 +5502,7 @@ public class ConnectivityService extends IConnectivityManager.Stub @Override public String getCaptivePortalServerUrl() { - return NetworkMonitor.getCaptivePortalServerUrl(mContext); + return NetworkMonitor.getCaptivePortalServerHttpUrl(mContext); } @Override diff --git a/services/core/java/com/android/server/accounts/AccountManagerService.java b/services/core/java/com/android/server/accounts/AccountManagerService.java index f960d8abc7d4..575018d6b908 100644 --- a/services/core/java/com/android/server/accounts/AccountManagerService.java +++ b/services/core/java/com/android/server/accounts/AccountManagerService.java @@ -77,7 +77,6 @@ import android.os.Parcel; import android.os.Process; import android.os.RemoteCallback; import android.os.RemoteException; -import android.os.ServiceManager; import android.os.SystemClock; import android.os.UserHandle; import android.os.UserManager; @@ -152,7 +151,7 @@ public class AccountManagerService @Override public void onStart() { - mService = new AccountManagerService(getContext()); + mService = new AccountManagerService(new Injector(getContext())); publishBinderService(Context.ACCOUNT_SERVICE, mService); } @@ -169,6 +168,7 @@ public class AccountManagerService private final PackageManager mPackageManager; private final AppOpsManager mAppOpsManager; private UserManager mUserManager; + private final Injector mInjector; final MessageHandler mHandler; @@ -272,22 +272,13 @@ public class AccountManagerService return sThis.get(); } - public AccountManagerService(Context context) { - this(context, context.getPackageManager(), new AccountAuthenticatorCache(context)); - } - - public AccountManagerService(Context context, PackageManager packageManager, - IAccountAuthenticatorCache authenticatorCache) { - mContext = context; - mPackageManager = packageManager; + public AccountManagerService(Injector injector) { + mInjector = injector; + mContext = injector.getContext(); + mPackageManager = mContext.getPackageManager(); mAppOpsManager = mContext.getSystemService(AppOpsManager.class); - - ServiceThread serviceThread = new ServiceThread(TAG, - android.os.Process.THREAD_PRIORITY_FOREGROUND, true /* allowIo */); - serviceThread.start(); - mHandler = new MessageHandler(serviceThread.getLooper()); - - mAuthenticatorCache = authenticatorCache; + mHandler = new MessageHandler(injector.getMessageHandlerLooper()); + mAuthenticatorCache = mInjector.getAccountAuthenticatorCache(); mAuthenticatorCache.setListener(this, null /* Handler */); sThis.set(this); @@ -373,7 +364,7 @@ public class AccountManagerService } }, UserHandle.ALL, userFilter, null, null); - LocalServices.addService(AccountManagerInternal.class, new AccountManagerInternalImpl()); + injector.addLocalService(new AccountManagerInternalImpl()); // Need to cancel account request notifications if the update/install can access the account new PackageMonitor() { @@ -424,7 +415,7 @@ public class AccountManagerService final long identity = Binder.clearCallingIdentity(); try { for (String packageName : packageNames) { - if (mContext.getPackageManager().checkPermission( + if (mPackageManager.checkPermission( Manifest.permission.GET_ACCOUNTS, packageName) != PackageManager.PERMISSION_GRANTED) { continue; @@ -710,8 +701,7 @@ public class AccountManagerService * installed on the device. */ private void addRequestsForPreInstalledApplications() { - List<PackageInfo> allInstalledPackages = mContext.getPackageManager(). - getInstalledPackages(0); + List<PackageInfo> allInstalledPackages = mPackageManager.getInstalledPackages(0); for(PackageInfo pi : allInstalledPackages) { int currentUid = pi.applicationInfo.uid; if(currentUid != -1) { @@ -1170,8 +1160,8 @@ public class AccountManagerService UserAccounts accounts = mUsers.get(userId); boolean validateAccounts = false; if (accounts == null) { - File preNDbFile = new File(getPreNDatabaseName(userId)); - File deDbFile = new File(getDeDatabaseName(userId)); + File preNDbFile = new File(mInjector.getPreNDatabaseName(userId)); + File deDbFile = new File(mInjector.getDeDatabaseName(userId)); accounts = new UserAccounts(mContext, userId, preNDbFile, deDbFile); initializeDebugDbSizeAndCompileSqlStatementForLogging( accounts.openHelper.getWritableDatabase(), accounts); @@ -1183,8 +1173,8 @@ public class AccountManagerService if (!accounts.openHelper.isCeDatabaseAttached() && mLocalUnlockedUsers.get(userId)) { Log.i(TAG, "User " + userId + " is unlocked - opening CE database"); synchronized (accounts.cacheLock) { - File preNDatabaseFile = new File(getPreNDatabaseName(userId)); - File ceDatabaseFile = new File(getCeDatabaseName(userId)); + File preNDatabaseFile = new File(mInjector.getPreNDatabaseName(userId)); + File ceDatabaseFile = new File(mInjector.getCeDatabaseName(userId)); CeDatabaseHelper.create(mContext, userId, preNDatabaseFile, ceDatabaseFile); accounts.openHelper.attachCeDatabase(ceDatabaseFile); } @@ -1255,13 +1245,13 @@ public class AccountManagerService } } Log.i(TAG, "Removing database files for user " + userId); - File dbFile = new File(getDeDatabaseName(userId)); + File dbFile = new File(mInjector.getDeDatabaseName(userId)); AccountsDb.deleteDbFileWarnIfFailed(dbFile); // Remove CE file if user is unlocked, or FBE is not enabled boolean fbeEnabled = StorageManager.isFileEncryptedNativeOrEmulated(); if (!fbeEnabled || userUnlocked) { - File ceDb = new File(getCeDatabaseName(userId)); + File ceDb = new File(mInjector.getCeDatabaseName(userId)); if (ceDb.exists()) { AccountsDb.deleteDbFileWarnIfFailed(ceDb); } @@ -4745,47 +4735,6 @@ public class AccountManagerService } } - @VisibleForTesting - String getPreNDatabaseName(int userId) { - File systemDir = Environment.getDataSystemDirectory(); - File databaseFile = new File(Environment.getUserSystemDirectory(userId), - PRE_N_DATABASE_NAME); - if (userId == 0) { - // Migrate old file, if it exists, to the new location. - // Make sure the new file doesn't already exist. A dummy file could have been - // accidentally created in the old location, causing the new one to become corrupted - // as well. - File oldFile = new File(systemDir, PRE_N_DATABASE_NAME); - if (oldFile.exists() && !databaseFile.exists()) { - // Check for use directory; create if it doesn't exist, else renameTo will fail - File userDir = Environment.getUserSystemDirectory(userId); - if (!userDir.exists()) { - if (!userDir.mkdirs()) { - throw new IllegalStateException("User dir cannot be created: " + userDir); - } - } - if (!oldFile.renameTo(databaseFile)) { - throw new IllegalStateException("User dir cannot be migrated: " + databaseFile); - } - } - } - return databaseFile.getPath(); - } - - @VisibleForTesting - String getDeDatabaseName(int userId) { - File databaseFile = new File(Environment.getDataSystemDeDirectory(userId), - AccountsDb.DE_DATABASE_NAME); - return databaseFile.getPath(); - } - - @VisibleForTesting - String getCeDatabaseName(int userId) { - File databaseFile = new File(Environment.getDataSystemCeDirectory(userId), - AccountsDb.CE_DATABASE_NAME); - return databaseFile.getPath(); - } - private void logRecord(UserAccounts accounts, String action, String tableName) { logRecord(action, tableName, -1, accounts); } @@ -4981,17 +4930,11 @@ public class AccountManagerService } } - @VisibleForTesting - protected void installNotification(int notificationId, final Notification notification, - UserHandle user) { - installNotification(notificationId, notification, "android", user.getIdentifier()); - } - private void installNotification(int notificationId, final Notification notification, String packageName, int userId) { final long token = clearCallingIdentity(); try { - INotificationManager notificationManager = NotificationManager.getService(); + INotificationManager notificationManager = mInjector.getNotificationManager(); try { notificationManager.enqueueNotificationWithTag(packageName, packageName, null, notificationId, notification, new int[1], userId); @@ -5003,16 +4946,14 @@ public class AccountManagerService } } - @VisibleForTesting - protected void cancelNotification(int id, UserHandle user) { + private void cancelNotification(int id, UserHandle user) { cancelNotification(id, mContext.getPackageName(), user); } - protected void cancelNotification(int id, String packageName, UserHandle user) { + private void cancelNotification(int id, String packageName, UserHandle user) { long identityToken = clearCallingIdentity(); try { - INotificationManager service = INotificationManager.Stub.asInterface( - ServiceManager.getService(Context.NOTIFICATION_SERVICE)); + INotificationManager service = mInjector.getNotificationManager(); service.cancelNotificationWithTag(packageName, null, id, user.getIdentifier()); } catch (RemoteException e) { /* ignore - local call */ @@ -5714,4 +5655,74 @@ public class AccountManagerService } } } + + @VisibleForTesting + static class Injector { + private final Context mContext; + + public Injector(Context context) { + mContext = context; + } + + Looper getMessageHandlerLooper() { + ServiceThread serviceThread = new ServiceThread(TAG, + android.os.Process.THREAD_PRIORITY_FOREGROUND, true /* allowIo */); + serviceThread.start(); + return serviceThread.getLooper(); + } + + Context getContext() { + return mContext; + } + + void addLocalService(AccountManagerInternal service) { + LocalServices.addService(AccountManagerInternal.class, service); + } + + String getDeDatabaseName(int userId) { + File databaseFile = new File(Environment.getDataSystemDeDirectory(userId), + AccountsDb.DE_DATABASE_NAME); + return databaseFile.getPath(); + } + + String getCeDatabaseName(int userId) { + File databaseFile = new File(Environment.getDataSystemCeDirectory(userId), + AccountsDb.CE_DATABASE_NAME); + return databaseFile.getPath(); + } + + String getPreNDatabaseName(int userId) { + File systemDir = Environment.getDataSystemDirectory(); + File databaseFile = new File(Environment.getUserSystemDirectory(userId), + PRE_N_DATABASE_NAME); + if (userId == 0) { + // Migrate old file, if it exists, to the new location. + // Make sure the new file doesn't already exist. A dummy file could have been + // accidentally created in the old location, causing the new one to become corrupted + // as well. + File oldFile = new File(systemDir, PRE_N_DATABASE_NAME); + if (oldFile.exists() && !databaseFile.exists()) { + // Check for use directory; create if it doesn't exist, else renameTo will fail + File userDir = Environment.getUserSystemDirectory(userId); + if (!userDir.exists()) { + if (!userDir.mkdirs()) { + throw new IllegalStateException("User dir cannot be created: " + userDir); + } + } + if (!oldFile.renameTo(databaseFile)) { + throw new IllegalStateException("User dir cannot be migrated: " + databaseFile); + } + } + } + return databaseFile.getPath(); + } + + IAccountAuthenticatorCache getAccountAuthenticatorCache() { + return new AccountAuthenticatorCache(mContext); + } + + INotificationManager getNotificationManager() { + return NotificationManager.getService(); + } + } } diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java index 96ba25955dce..0f351f62d991 100644 --- a/services/core/java/com/android/server/audio/AudioService.java +++ b/services/core/java/com/android/server/audio/AudioService.java @@ -209,6 +209,7 @@ public class AudioService extends IAudioService.Stub { private static final int MSG_BT_HEADSET_CNCT_FAILED = 9; private static final int MSG_SET_ALL_VOLUMES = 10; private static final int MSG_REPORT_NEW_ROUTES = 12; + private static final int MSG_SET_FORCE_BT_A2DP_USE = 13; private static final int MSG_CHECK_MUSIC_ACTIVE = 14; private static final int MSG_BROADCAST_AUDIO_BECOMING_NOISY = 15; private static final int MSG_CONFIGURE_SAFE_MEDIA_VOLUME = 16; @@ -514,10 +515,6 @@ public class AudioService extends IAudioService.Stub { // Request to override default use of A2DP for media. private boolean mBluetoothA2dpEnabled; - // FIXME: remove when MediaRouter does not use setBluetoothA2dpOn() anymore - // state of bluetooth A2DP enable request sen by deprecated APIs setBluetoothA2dpOn() and - // isBluettohA2dpOn() - private boolean mBluetoothA2dpEnabledExternal; private final Object mBluetoothA2dpEnabledLock = new Object(); // Monitoring of audio routes. Protected by mCurAudioRoutes. @@ -2718,23 +2715,22 @@ public class AudioService extends IAudioService.Stub { return (mForcedUseForComm == AudioSystem.FORCE_BT_SCO); } - /** - * Deprecated. - * Keep stub implementation until MediaRouter stops using it. - * @deprecated - * */ + /** @see AudioManager#setBluetoothA2dpOn(boolean) */ public void setBluetoothA2dpOn(boolean on) { - mBluetoothA2dpEnabledExternal = on; - Log.e(TAG, "setBluetoothA2dpOn() is deprecated, now a no-op", - new Exception("Deprecated use of setBluetoothA2dpOn()")); + synchronized (mBluetoothA2dpEnabledLock) { + mBluetoothA2dpEnabled = on; + sendMsg(mAudioHandler, MSG_SET_FORCE_BT_A2DP_USE, SENDMSG_QUEUE, + AudioSystem.FOR_MEDIA, + mBluetoothA2dpEnabled ? AudioSystem.FORCE_NONE : AudioSystem.FORCE_NO_BT_A2DP, + null, 0); + } } - /** Deprecated. - * Keep stub implementation until MediaRouter stops using it - * @deprecated - * */ + /** @see AudioManager#isBluetoothA2dpOn() */ public boolean isBluetoothA2dpOn() { - return mBluetoothA2dpEnabledExternal; + synchronized (mBluetoothA2dpEnabledLock) { + return mBluetoothA2dpEnabled; + } } /** @see AudioManager#startBluetoothSco() */ @@ -3807,11 +3803,6 @@ public class AudioService extends IAudioService.Stub { Slog.i(TAG, "setWiredDeviceConnectionState(" + state + " nm: " + name + " addr:" + address + ")"); } - if ((state == 0) && ((type == AudioSystem.DEVICE_OUT_WIRED_HEADSET) || - (type == AudioSystem.DEVICE_OUT_WIRED_HEADPHONE) || - (type == AudioSystem.DEVICE_OUT_LINE))) { - setBluetoothA2dpOnInt(true); - } int delay = checkSendBecomingNoisyIntent(type, state); queueMsgUnderWakeLock(mAudioHandler, MSG_SET_WIRED_DEVICE_CONNECTION_STATE, @@ -4623,6 +4614,7 @@ public class AudioService extends IAudioService.Stub { break; case MSG_SET_FORCE_USE: + case MSG_SET_FORCE_BT_A2DP_USE: setForceUse(msg.arg1, msg.arg2); break; @@ -5030,7 +5022,6 @@ public class AudioService extends IAudioService.Stub { devices |= dev; } } - if (devices == device) { sendMsg(mAudioHandler, MSG_BROADCAST_AUDIO_BECOMING_NOISY, @@ -5126,6 +5117,11 @@ public class AudioService extends IAudioService.Stub { } synchronized (mConnectedDevices) { + if ((state == 0) && ((device == AudioSystem.DEVICE_OUT_WIRED_HEADSET) || + (device == AudioSystem.DEVICE_OUT_WIRED_HEADPHONE) || + (device == AudioSystem.DEVICE_OUT_LINE))) { + setBluetoothA2dpOnInt(true); + } boolean isUsb = ((device & ~AudioSystem.DEVICE_OUT_ALL_USB) == 0) || (((device & AudioSystem.DEVICE_BIT_IN) != 0) && ((device & ~AudioSystem.DEVICE_IN_ALL_USB) == 0)); @@ -5609,6 +5605,7 @@ public class AudioService extends IAudioService.Stub { public void setBluetoothA2dpOnInt(boolean on) { synchronized (mBluetoothA2dpEnabledLock) { mBluetoothA2dpEnabled = on; + mAudioHandler.removeMessages(MSG_SET_FORCE_BT_A2DP_USE); setForceUseInt_SyncDevices(AudioSystem.FOR_MEDIA, mBluetoothA2dpEnabled ? AudioSystem.FORCE_NONE : AudioSystem.FORCE_NO_BT_A2DP); } @@ -5623,6 +5620,8 @@ public class AudioService extends IAudioService.Stub { } else { // config == AudioSystem.FORCE_NONE mBecomingNoisyIntentDevices |= AudioSystem.DEVICE_OUT_ALL_A2DP; } + sendMsg(mAudioHandler, MSG_REPORT_NEW_ROUTES, + SENDMSG_NOOP, 0, 0, null, 0); break; case AudioSystem.FOR_DOCK: if (config == AudioSystem.FORCE_ANALOG_DOCK) { diff --git a/services/core/java/com/android/server/connectivity/NetworkMonitor.java b/services/core/java/com/android/server/connectivity/NetworkMonitor.java index 42d80fc6fc48..6eb89facca76 100644 --- a/services/core/java/com/android/server/connectivity/NetworkMonitor.java +++ b/services/core/java/com/android/server/connectivity/NetworkMonitor.java @@ -23,7 +23,6 @@ import static android.net.CaptivePortal.APP_RETURN_WANTED_AS_IS; import android.app.AlarmManager; import android.app.PendingIntent; import android.content.BroadcastReceiver; -import android.content.ComponentName; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; @@ -37,14 +36,12 @@ import android.net.Uri; import android.net.metrics.IpConnectivityLog; import android.net.metrics.NetworkEvent; import android.net.metrics.ValidationProbeEvent; +import android.net.util.Stopwatch; import android.net.wifi.WifiInfo; import android.net.wifi.WifiManager; -import android.net.util.Stopwatch; import android.os.Handler; import android.os.Message; -import android.os.Process; import android.os.SystemClock; -import android.os.SystemProperties; import android.os.UserHandle; import android.provider.Settings; import android.telephony.CellIdentityCdma; @@ -66,27 +63,39 @@ import com.android.internal.annotations.VisibleForTesting; import com.android.internal.util.Protocol; import com.android.internal.util.State; import com.android.internal.util.StateMachine; -import com.android.internal.util.WakeupMessage; import java.io.IOException; import java.net.HttpURLConnection; import java.net.InetAddress; import java.net.MalformedURLException; -import java.net.UnknownHostException; import java.net.URL; -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.atomic.AtomicReference; +import java.net.UnknownHostException; import java.util.List; import java.util.Random; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; /** * {@hide} */ public class NetworkMonitor extends StateMachine { - private static final boolean DBG = false; private static final String TAG = NetworkMonitor.class.getSimpleName(); - private static final String DEFAULT_SERVER = "connectivitycheck.gstatic.com"; + private static final boolean DBG = false; + + // Default configuration values for captive portal detection probes. + // TODO: append a random length parameter to the default HTTPS url. + // TODO: randomize browser version ids in the default User-Agent String. + private static final String DEFAULT_HTTPS_URL = "https://www.google.com/generate_204"; + private static final String DEFAULT_HTTP_URL = + "http://connectivitycheck.gstatic.com/generate_204"; + private static final String DEFAULT_FALLBACK_URL = "http://www.google.com/gen_204"; + private static final String DEFAULT_USER_AGENT = "Mozilla/5.0 (X11; Linux x86_64) " + + "AppleWebKit/537.36 (KHTML, like Gecko) " + + "Chrome/52.0.2743.82 Safari/537.36"; + private static final int SOCKET_TIMEOUT_MS = 10000; + private static final int PROBE_TIMEOUT_MS = 3000; + public static final String ACTION_NETWORK_CONDITIONS_MEASURED = "android.net.conn.NETWORK_CONDITIONS_MEASURED"; public static final String EXTRA_CONNECTIVITY_TYPE = "extra_connectivity_type"; @@ -224,6 +233,9 @@ public class NetworkMonitor extends StateMachine { private final Stopwatch mEvaluationTimer = new Stopwatch(); + // This variable is set before transitioning to the mCaptivePortalState. + private CaptivePortalProbeResult mLastPortalProbeResult = CaptivePortalProbeResult.FAILED; + public NetworkMonitor(Context context, Handler handler, NetworkAgentInfo networkAgentInfo, NetworkRequest defaultRequest) { this(context, handler, networkAgentInfo, defaultRequest, new IpConnectivityLog()); @@ -389,6 +401,8 @@ public class NetworkMonitor extends StateMachine { sendMessage(CMD_CAPTIVE_PORTAL_APP_FINISHED, response); } })); + intent.putExtra(ConnectivityManager.EXTRA_CAPTIVE_PORTAL_URL, + mLastPortalProbeResult.detectUrl); intent.setFlags( Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT | Intent.FLAG_ACTIVITY_NEW_TASK); mContext.startActivityAsUser(intent, UserHandle.CURRENT); @@ -412,14 +426,22 @@ public class NetworkMonitor extends StateMachine { */ @VisibleForTesting public static final class CaptivePortalProbeResult { - static final CaptivePortalProbeResult FAILED = new CaptivePortalProbeResult(599, null); + static final CaptivePortalProbeResult FAILED = new CaptivePortalProbeResult(599); - final int mHttpResponseCode; // HTTP response code returned from Internet probe. - final String mRedirectUrl; // Redirect destination returned from Internet probe. + private final int mHttpResponseCode; // HTTP response code returned from Internet probe. + final String redirectUrl; // Redirect destination returned from Internet probe. + final String detectUrl; // URL where a 204 response code indicates + // captive portal has been appeased. - public CaptivePortalProbeResult(int httpResponseCode, String redirectUrl) { + public CaptivePortalProbeResult( + int httpResponseCode, String redirectUrl, String detectUrl) { mHttpResponseCode = httpResponseCode; - mRedirectUrl = redirectUrl; + this.redirectUrl = redirectUrl; + this.detectUrl = detectUrl; + } + + public CaptivePortalProbeResult(int httpResponseCode) { + this(httpResponseCode, null, null); } boolean isSuccessful() { return mHttpResponseCode == 204; } @@ -492,7 +514,8 @@ public class NetworkMonitor extends StateMachine { transitionTo(mValidatedState); } else if (probeResult.isPortal()) { mConnectivityServiceHandler.sendMessage(obtainMessage(EVENT_NETWORK_TESTED, - NETWORK_TEST_RESULT_INVALID, mNetId, probeResult.mRedirectUrl)); + NETWORK_TEST_RESULT_INVALID, mNetId, probeResult.redirectUrl)); + mLastPortalProbeResult = probeResult; transitionTo(mCaptivePortalState); } else { final Message msg = obtainMessage(CMD_REEVALUATE, ++mReevaluateToken, 0); @@ -500,7 +523,7 @@ public class NetworkMonitor extends StateMachine { logNetworkEvent(NetworkEvent.NETWORK_VALIDATION_FAILED); mConnectivityServiceHandler.sendMessage(obtainMessage( EVENT_NETWORK_TESTED, NETWORK_TEST_RESULT_INVALID, mNetId, - probeResult.mRedirectUrl)); + probeResult.redirectUrl)); if (mAttempts >= BLAME_FOR_EVALUATION_ATTEMPTS) { // Don't continue to blame UID forever. TrafficStats.clearThreadStatsUid(); @@ -585,22 +608,33 @@ public class NetworkMonitor extends StateMachine { } } - private static String getCaptivePortalServerUrl(Context context, boolean isHttps) { - String server = Settings.Global.getString(context.getContentResolver(), - Settings.Global.CAPTIVE_PORTAL_SERVER); - if (server == null) server = DEFAULT_SERVER; - return (isHttps ? "https" : "http") + "://" + server + "/generate_204"; + private static String getCaptivePortalServerHttpsUrl(Context context) { + return getSetting(context, Settings.Global.CAPTIVE_PORTAL_HTTPS_URL, DEFAULT_HTTPS_URL); + } + + public static String getCaptivePortalServerHttpUrl(Context context) { + return getSetting(context, Settings.Global.CAPTIVE_PORTAL_HTTP_URL, DEFAULT_HTTP_URL); } - public static String getCaptivePortalServerUrl(Context context) { - return getCaptivePortalServerUrl(context, false); + private static String getCaptivePortalFallbackUrl(Context context) { + return getSetting(context, + Settings.Global.CAPTIVE_PORTAL_FALLBACK_URL, DEFAULT_FALLBACK_URL); + } + + private static String getCaptivePortalUserAgent(Context context) { + return getSetting(context, Settings.Global.CAPTIVE_PORTAL_USER_AGENT, DEFAULT_USER_AGENT); + } + + private static String getSetting(Context context, String symbol, String defaultValue) { + final String value = Settings.Global.getString(context.getContentResolver(), symbol); + return value != null ? value : defaultValue; } @VisibleForTesting protected CaptivePortalProbeResult isCaptivePortal() { - if (!mIsCaptivePortalCheckEnabled) return new CaptivePortalProbeResult(204, null); + if (!mIsCaptivePortalCheckEnabled) return new CaptivePortalProbeResult(204); - URL pacUrl = null, httpUrl = null, httpsUrl = null; + URL pacUrl = null, httpsUrl = null, httpUrl = null, fallbackUrl = null; // On networks with a PAC instead of fetching a URL that should result in a 204 // response, we instead simply fetch the PAC script. This is done for a few reasons: @@ -621,20 +655,17 @@ public class NetworkMonitor extends StateMachine { // results for network validation. final ProxyInfo proxyInfo = mNetworkAgentInfo.linkProperties.getHttpProxy(); if (proxyInfo != null && !Uri.EMPTY.equals(proxyInfo.getPacFileUrl())) { - try { - pacUrl = new URL(proxyInfo.getPacFileUrl().toString()); - } catch (MalformedURLException e) { - validationLog("Invalid PAC URL: " + proxyInfo.getPacFileUrl().toString()); + pacUrl = makeURL(proxyInfo.getPacFileUrl().toString()); + if (pacUrl == null) { return CaptivePortalProbeResult.FAILED; } } if (pacUrl == null) { - try { - httpUrl = new URL(getCaptivePortalServerUrl(mContext, false)); - httpsUrl = new URL(getCaptivePortalServerUrl(mContext, true)); - } catch (MalformedURLException e) { - validationLog("Bad validation URL: " + getCaptivePortalServerUrl(mContext, false)); + httpsUrl = makeURL(getCaptivePortalServerHttpsUrl(mContext)); + httpUrl = makeURL(getCaptivePortalServerHttpUrl(mContext)); + fallbackUrl = makeURL(getCaptivePortalFallbackUrl(mContext)); + if (httpUrl == null || httpsUrl == null) { return CaptivePortalProbeResult.FAILED; } } @@ -680,7 +711,7 @@ public class NetworkMonitor extends StateMachine { if (pacUrl != null) { result = sendHttpProbe(pacUrl, ValidationProbeEvent.PROBE_PAC); } else if (mUseHttps) { - result = sendParallelHttpProbes(httpsUrl, httpUrl); + result = sendParallelHttpProbes(httpsUrl, httpUrl, fallbackUrl); } else { result = sendHttpProbe(httpUrl, ValidationProbeEvent.PROBE_HTTP); } @@ -710,6 +741,10 @@ public class NetworkMonitor extends StateMachine { urlConnection.setConnectTimeout(SOCKET_TIMEOUT_MS); urlConnection.setReadTimeout(SOCKET_TIMEOUT_MS); urlConnection.setUseCaches(false); + final String userAgent = getCaptivePortalUserAgent(mContext); + if (userAgent != null) { + urlConnection.setRequestProperty("User-Agent", userAgent); + } // Time how long it takes to get a response to our request long requestTimestamp = SystemClock.elapsedRealtime(); @@ -755,28 +790,24 @@ public class NetworkMonitor extends StateMachine { } } logValidationProbe(probeTimer.stop(), probeType, httpResponseCode); - return new CaptivePortalProbeResult(httpResponseCode, redirectUrl); + return new CaptivePortalProbeResult(httpResponseCode, redirectUrl, url.toString()); } - private CaptivePortalProbeResult sendParallelHttpProbes(URL httpsUrl, URL httpUrl) { - // Number of probes to wait for. We might wait for all of them, but we might also return if - // only one of them has replied. For example, we immediately return if the HTTP probe finds - // a captive portal, even if the HTTPS probe is timing out. + private CaptivePortalProbeResult sendParallelHttpProbes( + URL httpsUrl, URL httpUrl, URL fallbackUrl) { + // Number of probes to wait for. If a probe completes with a conclusive answer + // it shortcuts the latch immediately by forcing the count to 0. final CountDownLatch latch = new CountDownLatch(2); - // Which probe result we're going to use. This doesn't need to be atomic, but it does need - // to be final because otherwise we can't set it from the ProbeThreads. - final AtomicReference<CaptivePortalProbeResult> finalResult = new AtomicReference<>(); - final class ProbeThread extends Thread { private final boolean mIsHttps; - private volatile CaptivePortalProbeResult mResult; + private volatile CaptivePortalProbeResult mResult = CaptivePortalProbeResult.FAILED; public ProbeThread(boolean isHttps) { mIsHttps = isHttps; } - public CaptivePortalProbeResult getResult() { + public CaptivePortalProbeResult result() { return mResult; } @@ -788,32 +819,66 @@ public class NetworkMonitor extends StateMachine { mResult = sendHttpProbe(httpUrl, ValidationProbeEvent.PROBE_HTTP); } if ((mIsHttps && mResult.isSuccessful()) || (!mIsHttps && mResult.isPortal())) { - // HTTPS succeeded, or HTTP found a portal. Don't wait for the other probe. - finalResult.compareAndSet(null, mResult); - latch.countDown(); + // Stop waiting immediately if https succeeds or if http finds a portal. + while (latch.getCount() > 0) { + latch.countDown(); + } } - // Signal that one probe has completed. If we've already made a decision, or if this - // is the second probe, the latch will be at zero and we'll return a result. + // Signal this probe has completed. latch.countDown(); } } - ProbeThread httpsProbe = new ProbeThread(true); - ProbeThread httpProbe = new ProbeThread(false); - httpsProbe.start(); - httpProbe.start(); + final ProbeThread httpsProbe = new ProbeThread(true); + final ProbeThread httpProbe = new ProbeThread(false); try { - latch.await(); + httpsProbe.start(); + httpProbe.start(); + latch.await(PROBE_TIMEOUT_MS, TimeUnit.MILLISECONDS); } catch (InterruptedException e) { - validationLog("Error: probe wait interrupted!"); + validationLog("Error: probes wait interrupted!"); return CaptivePortalProbeResult.FAILED; } - // If there was no deciding probe, that means that both probes completed. Return HTTPS. - finalResult.compareAndSet(null, httpsProbe.getResult()); + final CaptivePortalProbeResult httpsResult = httpsProbe.result(); + final CaptivePortalProbeResult httpResult = httpProbe.result(); + + // Look for a conclusive probe result first. + if (httpResult.isPortal()) { + return httpResult; + } + // httpsResult.isPortal() is not expected, but check it nonetheless. + if (httpsResult.isPortal() || httpsResult.isSuccessful()) { + return httpsResult; + } + // If a fallback url is specified, use a fallback probe to try again portal detection. + if (fallbackUrl != null) { + CaptivePortalProbeResult result = + sendHttpProbe(fallbackUrl, ValidationProbeEvent.PROBE_FALLBACK); + if (result.isPortal()) { + return result; + } + } + // Otherwise wait until https probe completes and use its result. + try { + httpsProbe.join(); + } catch (InterruptedException e) { + validationLog("Error: https probe wait interrupted!"); + return CaptivePortalProbeResult.FAILED; + } + return httpsProbe.result(); + } - return finalResult.get(); + private URL makeURL(String url) { + if (url != null) { + try { + return new URL(url); + } catch (MalformedURLException e) { + validationLog("Bad URL: " + url); + } + } + return null; } /** diff --git a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java index 61374f3be093..1d3471a2d340 100644 --- a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java +++ b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java @@ -1160,14 +1160,15 @@ class PackageManagerShellCommand extends ShellCommand { private int doWriteSplit(int sessionId, String inPath, long sizeBytes, String splitName, boolean logSuccess) throws RemoteException { final PrintWriter pw = getOutPrintWriter(); - if ("-".equals(inPath)) { - inPath = null; - } else if (inPath != null) { - final File file = new File(inPath); - if (file.isFile()) { - sizeBytes = file.length(); - } + if (sizeBytes <= 0) { + pw.println("Error: must specify a APK size"); + return 1; + } + if (inPath != null && !"-".equals(inPath)) { + pw.println("Error: APK content must be streamed"); + return 1; } + inPath = null; final SessionInfo info = mInterface.getPackageInstaller().getSessionInfo(sessionId); diff --git a/services/core/java/com/android/server/power/ShutdownThread.java b/services/core/java/com/android/server/power/ShutdownThread.java index 1dbc6d944b1c..badee82becbd 100644 --- a/services/core/java/com/android/server/power/ShutdownThread.java +++ b/services/core/java/com/android/server/power/ShutdownThread.java @@ -717,6 +717,14 @@ public final class ShutdownThread extends Thread { } if (!done[0]) { Log.w(TAG, "Timed out waiting for uncrypt."); + final int uncryptTimeoutError = 100; + String timeoutMessage = String.format("uncrypt_time: %d\n" + "uncrypt_error: %d\n", + MAX_UNCRYPT_WAIT_TIME / 1000, uncryptTimeoutError); + try { + FileUtils.stringToFile(RecoverySystem.UNCRYPT_STATUS_FILE, timeoutMessage); + } catch (IOException e) { + Log.e(TAG, "Failed to write timeout message to uncrypt status", e); + } } } } diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java index a09c5976e2ec..66682d8051dd 100644 --- a/services/core/java/com/android/server/wm/DisplayContent.java +++ b/services/core/java/com/android/server/wm/DisplayContent.java @@ -20,6 +20,7 @@ import static android.app.ActivityManager.StackId.DOCKED_STACK_ID; import static android.app.ActivityManager.StackId.FREEFORM_WORKSPACE_STACK_ID; import static android.app.ActivityManager.StackId.HOME_STACK_ID; import static android.app.ActivityManager.StackId.PINNED_STACK_ID; +import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_BEHIND; import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSET; import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED; import static android.view.WindowManager.DOCKED_BOTTOM; @@ -271,7 +272,7 @@ class DisplayContent extends WindowContainer<TaskStack> { } final int orientation = super.getOrientation(); - if (orientation != SCREEN_ORIENTATION_UNSET) { + if (orientation != SCREEN_ORIENTATION_UNSET && orientation != SCREEN_ORIENTATION_BEHIND) { if (DEBUG_ORIENTATION) Slog.v(TAG_WM, "App is requesting an orientation, return " + orientation); return orientation; diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java index 3d0ca8097f02..0c57179f94b2 100644 --- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java +++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java @@ -496,6 +496,12 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { } }); } + // STOPSHIP: Remove this code once all dogfood devices are fixed. See b/31754835 + if (Intent.ACTION_BOOT_COMPLETED.equals(action) && !mOwners.hasDeviceOwner() + && !isBackupServiceEnabledInternal()) { + setBackupServiceEnabledInternal(true); + Slog.w(LOG_TAG, "Fix backup for device that is not in Device Owner mode."); + } if (Intent.ACTION_USER_UNLOCKED.equals(action) || Intent.ACTION_USER_STARTED.equals(action) || KeyChain.ACTION_TRUST_STORE_CHANGED.equals(action)) { @@ -9058,8 +9064,10 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { if (!isDeviceOwnerManagedSingleUserDevice()) { mInjector.securityLogSetLoggingEnabledProperty(false); Slog.w(LOG_TAG, "Security logging turned off as it's no longer a single user device."); - setBackupServiceEnabledInternal(false); - Slog.w(LOG_TAG, "Backup is off as it's a managed device that has more that one user."); + if (mOwners.hasDeviceOwner()) { + setBackupServiceEnabledInternal(false); + Slog.w(LOG_TAG, "Backup is off as it's a managed device that has more that one user."); + } } } @@ -9350,12 +9358,15 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { } synchronized (this) { getActiveAdminForCallerLocked(admin, DeviceAdminInfo.USES_POLICY_DEVICE_OWNER); - try { - IBackupManager ibm = mInjector.getIBackupManager(); - return ibm != null && ibm.isBackupServiceActive(UserHandle.USER_SYSTEM); - } catch (RemoteException e) { - throw new IllegalStateException("Failed requesting backup service state.", e); - } + return isBackupServiceEnabledInternal(); + } + } + private boolean isBackupServiceEnabledInternal() { + try { + IBackupManager ibm = mInjector.getIBackupManager(); + return ibm != null && ibm.isBackupServiceActive(UserHandle.USER_SYSTEM); + } catch (RemoteException e) { + throw new IllegalStateException("Failed requesting backup service state.", e); } } diff --git a/services/tests/servicestests/src/com/android/server/ConnectivityServiceTest.java b/services/tests/servicestests/src/com/android/server/ConnectivityServiceTest.java index 340be6222173..257341b72a28 100644 --- a/services/tests/servicestests/src/com/android/server/ConnectivityServiceTest.java +++ b/services/tests/servicestests/src/com/android/server/ConnectivityServiceTest.java @@ -596,7 +596,7 @@ public class ConnectivityServiceTest extends AndroidTestCase { @Override protected CaptivePortalProbeResult isCaptivePortal() { - return new CaptivePortalProbeResult(gen204ProbeResult, gen204ProbeRedirectUrl); + return new CaptivePortalProbeResult(gen204ProbeResult, gen204ProbeRedirectUrl, null); } } diff --git a/services/tests/servicestests/src/com/android/server/accounts/AccountManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/accounts/AccountManagerServiceTest.java index e72a8dc45f04..9c241d759a3e 100644 --- a/services/tests/servicestests/src/com/android/server/accounts/AccountManagerServiceTest.java +++ b/services/tests/servicestests/src/com/android/server/accounts/AccountManagerServiceTest.java @@ -16,6 +16,8 @@ package com.android.server.accounts; +import static android.database.sqlite.SQLiteDatabase.deleteDatabase; +import static org.mockito.Matchers.anyInt; import static org.mockito.Matchers.eq; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; @@ -24,7 +26,7 @@ import android.accounts.Account; import android.accounts.AccountManagerInternal; import android.accounts.AuthenticatorDescription; import android.app.AppOpsManager; -import android.app.Notification; +import android.app.INotificationManager; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; @@ -38,16 +40,14 @@ import android.database.DatabaseErrorHandler; import android.database.sqlite.SQLiteDatabase; import android.os.Bundle; import android.os.Handler; +import android.os.Looper; import android.os.UserHandle; import android.os.UserManager; import android.test.AndroidTestCase; import android.test.mock.MockContext; -import android.test.mock.MockPackageManager; import android.test.suitebuilder.annotation.SmallTest; import android.util.Log; -import com.android.server.LocalServices; - import java.io.File; import java.io.FileDescriptor; import java.io.PrintWriter; @@ -55,29 +55,38 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.Comparator; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; public class AccountManagerServiceTest extends AndroidTestCase { private static final String TAG = AccountManagerServiceTest.class.getSimpleName(); - static final String PREN_DB = "pren.db"; - static final String DE_DB = "de.db"; - static final String CE_DB = "ce.db"; + private static final String PREN_DB = "pren.db"; + private static final String DE_DB = "de.db"; + private static final String CE_DB = "ce.db"; private AccountManagerService mAms; + private TestInjector mTestInjector; @Override protected void setUp() throws Exception { Context realTestContext = getContext(); - Context mockContext = new MyMockContext(realTestContext); + MyMockContext mockContext = new MyMockContext(realTestContext); setContext(mockContext); - mAms = createAccountManagerService(mockContext, realTestContext); + mTestInjector = new TestInjector(realTestContext, mockContext); + mAms = new AccountManagerService(mTestInjector); } @Override protected void tearDown() throws Exception { - SQLiteDatabase.deleteDatabase(new File(mAms.getCeDatabaseName(UserHandle.USER_SYSTEM))); - SQLiteDatabase.deleteDatabase(new File(mAms.getDeDatabaseName(UserHandle.USER_SYSTEM))); - SQLiteDatabase.deleteDatabase(new File(mAms.getPreNDatabaseName(UserHandle.USER_SYSTEM))); - LocalServices.removeServiceForTest(AccountManagerInternal.class); + // Let async logging tasks finish, otherwise they may crash due to db being removed + CountDownLatch cdl = new CountDownLatch(1); + mAms.mHandler.post(() -> { + deleteDatabase(new File(mTestInjector.getCeDatabaseName(UserHandle.USER_SYSTEM))); + deleteDatabase(new File(mTestInjector.getDeDatabaseName(UserHandle.USER_SYSTEM))); + deleteDatabase(new File(mTestInjector.getPreNDatabaseName(UserHandle.USER_SYSTEM))); + cdl.countDown(); + }); + cdl.await(1, TimeUnit.SECONDS); super.tearDown(); } @@ -230,7 +239,7 @@ public class AccountManagerServiceTest extends AndroidTestCase { Context originalContext = ((MyMockContext)getContext()).mTestContext; // create a separate instance of AMS. It initially assumes that user0 is locked - AccountManagerService ams2 = createAccountManagerService(getContext(), originalContext); + AccountManagerService ams2 = new AccountManagerService(mTestInjector); // Verify that account can be removed when user is locked ams2.removeAccountInternal(a1); @@ -239,7 +248,7 @@ public class AccountManagerServiceTest extends AndroidTestCase { assertEquals("Only a2 should be returned", a2, accounts[0]); // Verify that CE db file is unchanged and still has 2 accounts - String ceDatabaseName = mAms.getCeDatabaseName(UserHandle.USER_SYSTEM); + String ceDatabaseName = mTestInjector.getCeDatabaseName(UserHandle.USER_SYSTEM); int accountsNumber = readNumberOfAccountsFromDbFile(originalContext, ceDatabaseName); assertEquals("CE database should still have 2 accounts", 2, accountsNumber); @@ -254,7 +263,7 @@ public class AccountManagerServiceTest extends AndroidTestCase { @SmallTest public void testPreNDatabaseMigration() throws Exception { - String preNDatabaseName = mAms.getPreNDatabaseName(UserHandle.USER_SYSTEM); + String preNDatabaseName = mTestInjector.getPreNDatabaseName(UserHandle.USER_SYSTEM); Context originalContext = ((MyMockContext) getContext()).mTestContext; PreNTestDatabaseHelper.createV4Database(originalContext, preNDatabaseName); // Assert that database was created with 1 account @@ -275,8 +284,8 @@ public class AccountManagerServiceTest extends AndroidTestCase { new File(preNDatabaseName).exists()); // Verify that ce/de files are present - String deDatabaseName = mAms.getDeDatabaseName(UserHandle.USER_SYSTEM); - String ceDatabaseName = mAms.getCeDatabaseName(UserHandle.USER_SYSTEM); + String deDatabaseName = mTestInjector.getDeDatabaseName(UserHandle.USER_SYSTEM); + String ceDatabaseName = mTestInjector.getCeDatabaseName(UserHandle.USER_SYSTEM); assertTrue("DE database file should be created at " + deDatabaseName, new File(deDatabaseName).exists()); assertTrue("CE database file should be created at " + ceDatabaseName, @@ -291,13 +300,6 @@ public class AccountManagerServiceTest extends AndroidTestCase { } } - private AccountManagerService createAccountManagerService(Context mockContext, - Context realContext) { - LocalServices.removeServiceForTest(AccountManagerInternal.class); - return new MyAccountManagerService(mockContext, - new MyMockPackageManager(), new MockAccountAuthenticatorCache(), realContext); - } - private void unlockSystemUser() { mAms.onUserUnlocked(newIntentForUser(UserHandle.USER_SYSTEM)); } @@ -366,6 +368,8 @@ public class AccountManagerServiceTest extends AndroidTestCase { this.mAppOpsManager = mock(AppOpsManager.class); this.mUserManager = mock(UserManager.class); this.mPackageManager = mock(PackageManager.class); + when(mPackageManager.checkSignatures(anyInt(), anyInt())) + .thenReturn(PackageManager.SIGNATURE_MATCH); final UserInfo ui = new UserInfo(UserHandle.USER_SYSTEM, "user0", 0); when(mUserManager.getUserInfo(eq(ui.id))).thenReturn(ui); } @@ -381,6 +385,11 @@ public class AccountManagerServiceTest extends AndroidTestCase { } @Override + public String getPackageName() { + return mTestContext.getPackageName(); + } + + @Override public Object getSystemService(String name) { if (Context.APP_OPS_SERVICE.equals(name)) { return mAppOpsManager; @@ -427,47 +436,45 @@ public class AccountManagerServiceTest extends AndroidTestCase { } } - static class MyMockPackageManager extends MockPackageManager { - @Override - public int checkSignatures(final int uid1, final int uid2) { - return PackageManager.SIGNATURE_MATCH; + static class TestInjector extends AccountManagerService.Injector { + private Context mRealContext; + TestInjector(Context realContext, MyMockContext mockContext) { + super(mockContext); + mRealContext = realContext; } @Override - public void addOnPermissionsChangeListener( - OnPermissionsChangedListener listener) { - } - } - - static class MyAccountManagerService extends AccountManagerService { - private Context mRealTestContext; - MyAccountManagerService(Context context, PackageManager packageManager, - IAccountAuthenticatorCache authenticatorCache, Context realTestContext) { - super(context, packageManager, authenticatorCache); - this.mRealTestContext = realTestContext; + Looper getMessageHandlerLooper() { + return Looper.getMainLooper(); } @Override - protected void installNotification(final int notificationId, final Notification n, UserHandle user) { + void addLocalService(AccountManagerInternal service) { } @Override - protected void cancelNotification(final int id, UserHandle user) { + IAccountAuthenticatorCache getAccountAuthenticatorCache() { + return new MockAccountAuthenticatorCache(); } @Override protected String getCeDatabaseName(int userId) { - return new File(mRealTestContext.getCacheDir(), CE_DB).getPath(); + return new File(mRealContext.getCacheDir(), CE_DB).getPath(); } @Override protected String getDeDatabaseName(int userId) { - return new File(mRealTestContext.getCacheDir(), DE_DB).getPath(); + return new File(mRealContext.getCacheDir(), DE_DB).getPath(); } @Override String getPreNDatabaseName(int userId) { - return new File(mRealTestContext.getCacheDir(), PREN_DB).getPath(); + return new File(mRealContext.getCacheDir(), PREN_DB).getPath(); + } + + @Override + INotificationManager getNotificationManager() { + return mock(INotificationManager.class); } } } diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java index 411d881c2dde..ad5b9d195e09 100644 --- a/telephony/java/android/telephony/CarrierConfigManager.java +++ b/telephony/java/android/telephony/CarrierConfigManager.java @@ -312,13 +312,23 @@ public class CarrierConfigManager { "carrier_wfc_supports_wifi_only_bool"; /** - * Default WFC_IMS_mode 0: WIFI_ONLY - * 1: CELLULAR_PREFERRED - * 2: WIFI_PREFERRED + * Default WFC_IMS_MODE for home network 0: WIFI_ONLY + * 1: CELLULAR_PREFERRED + * 2: WIFI_PREFERRED * @hide */ public static final String KEY_CARRIER_DEFAULT_WFC_IMS_MODE_INT = "carrier_default_wfc_ims_mode_int"; + + /** + * Default WFC_IMS_MODE for roaming + * See {@link KEY_CARRIER_DEFAULT_WFC_IMS_MODE_INT} for valid values. + * + * @hide + */ + public static final String KEY_CARRIER_DEFAULT_WFC_IMS_ROAMING_MODE_INT = + "carrier_default_wfc_ims_roaming_mode_int"; + /** * Default WFC_IMS_enabled: true VoWiFi by default is on * false VoWiFi by default is off @@ -1011,6 +1021,18 @@ public class CarrierConfigManager { */ public static final String KEY_RCS_CONFIG_SERVER_URL_STRING = "rcs_config_server_url_string"; + /** + * Determine whether user can change Wi-Fi Calling preference in roaming. + * {@code false} - roaming preference {@link KEY_CARRIER_DEFAULT_WFC_IMS_ROAMING_MODE_INT} is + * the same as home preference {@link KEY_CARRIER_DEFAULT_WFC_IMS_MODE_INT} + * and cannot be changed. + * {@code true} - roaming preference can be changed by user independently. + * + * @hide + */ + public static final String KEY_EDITABLE_WFC_ROAMING_MODE_BOOL = + "editable_wfc_roaming_mode_bool"; + /** The default value for every variable. */ private final static PersistableBundle sDefaults; @@ -1034,6 +1056,7 @@ public class CarrierConfigManager { sDefaults.putBoolean(KEY_CARRIER_DEFAULT_WFC_IMS_ROAMING_ENABLED_BOOL, false); sDefaults.putBoolean(KEY_CARRIER_PROMOTE_WFC_ON_CALL_FAIL_BOOL, false); sDefaults.putInt(KEY_CARRIER_DEFAULT_WFC_IMS_MODE_INT, 2); + sDefaults.putInt(KEY_CARRIER_DEFAULT_WFC_IMS_ROAMING_MODE_INT, 2); sDefaults.putBoolean(KEY_CARRIER_FORCE_DISABLE_ETWS_CMAS_TEST_BOOL, false); sDefaults.putBoolean(KEY_CARRIER_VOLTE_PROVISIONING_REQUIRED_BOOL, false); sDefaults.putBoolean(KEY_CARRIER_VOLTE_TTY_SUPPORTED_BOOL, true); @@ -1189,6 +1212,7 @@ public class CarrierConfigManager { sDefaults.putBoolean(KEY_ENHANCED_4G_LTE_TITLE_VARIANT_BOOL, false); sDefaults.putBoolean(KEY_NOTIFY_VT_HANDOVER_TO_WIFI_FAILURE_BOOL, false); sDefaults.putStringArray(FILTERED_CNAP_NAMES_STRING_ARRAY, null); + sDefaults.putBoolean(KEY_EDITABLE_WFC_ROAMING_MODE_BOOL, false); } /** diff --git a/wifi/java/android/net/wifi/nan/PublishConfig.java b/wifi/java/android/net/wifi/nan/PublishConfig.java index 91513713daa3..4b67f9ac0ef9 100644 --- a/wifi/java/android/net/wifi/nan/PublishConfig.java +++ b/wifi/java/android/net/wifi/nan/PublishConfig.java @@ -257,25 +257,6 @@ public final class PublishConfig implements Parcelable { } /** - * Specify service specific information for the publish session - a simple wrapper - * of {@link PublishConfig.Builder#setServiceSpecificInfo(byte[])} - * obtaining the data from a String. - * <p> - * Optional. Empty by default. - * - * @param serviceSpecificInfoStr The service specific information string - * to be included (as a byte array) in the publish - * information. - * - * @return The builder to facilitate chaining - * {@code builder.setXXX(..).setXXX(..)}. - */ - public Builder setServiceSpecificInfo(@NonNull String serviceSpecificInfoStr) { - mServiceSpecificInfo = serviceSpecificInfoStr.getBytes(); - return this; - } - - /** * The match filter for a publish session. Used to determine whether a service * discovery occurred - in addition to relying on the service name. * <p> diff --git a/wifi/java/android/net/wifi/nan/SubscribeConfig.java b/wifi/java/android/net/wifi/nan/SubscribeConfig.java index b1dcd8fe49d0..4352fcf6a3cf 100644 --- a/wifi/java/android/net/wifi/nan/SubscribeConfig.java +++ b/wifi/java/android/net/wifi/nan/SubscribeConfig.java @@ -289,25 +289,6 @@ public final class SubscribeConfig implements Parcelable { } /** - * Specify service specific information for the subscribe session - a simple wrapper - * of {@link SubscribeConfig.Builder#setServiceSpecificInfo(byte[])} - * obtaining the data from a String. - * <p> - * Optional. Empty by default. - * - * @param serviceSpecificInfoStr The service specific information string - * to be included (as a byte array) in the subscribe - * information. - * - * @return The builder to facilitate chaining - * {@code builder.setXXX(..).setXXX(..)}. - */ - public Builder setServiceSpecificInfo(@NonNull String serviceSpecificInfoStr) { - mServiceSpecificInfo = serviceSpecificInfoStr.getBytes(); - return this; - } - - /** * The match filter for a subscribe session. Used to determine whether a service * discovery occurred - in addition to relying on the service name. * <p> diff --git a/wifi/tests/Android.mk b/wifi/tests/Android.mk new file mode 100644 index 000000000000..5850feee004a --- /dev/null +++ b/wifi/tests/Android.mk @@ -0,0 +1,61 @@ +# Copyright (C) 2016 The Android Open Source Project +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +LOCAL_PATH:= $(call my-dir) + +# Make test APK +# ============================================================ +include $(CLEAR_VARS) + +LOCAL_MODULE_TAGS := tests + +LOCAL_SRC_FILES := $(call all-subdir-java-files) + +# This list is generated from the java source files in this module +# The list is a comma separated list of class names with * matching zero or more characters. +# Example: +# Input files: src/com/android/server/wifi/Test.java src/com/android/server/wifi/AnotherTest.java +# Generated exclude list: com.android.server.wifi.Test*,com.android.server.wifi.AnotherTest* + +# Filter all src files to just java files +local_java_files := $(filter %.java,$(LOCAL_SRC_FILES)) +# Transform java file names into full class names. +# This only works if the class name matches the file name and the directory structure +# matches the package. +local_classes := $(subst /,.,$(patsubst src/%.java,%,$(local_java_files))) +# Utility variables to allow replacing a space with a comma +comma:= , +empty:= +space:= $(empty) $(empty) +# Convert class name list to jacoco exclude list +# This appends a * to all classes and replace the space separators with commas. +# These patterns will match all classes in this module and their inner classes. +jacoco_exclude := $(subst $(space),$(comma),$(patsubst %,%*,$(local_classes))) + +jacoco_include := android.net.wifi.* + +LOCAL_JACK_COVERAGE_INCLUDE_FILTER := $(jacoco_include) +LOCAL_JACK_COVERAGE_EXCLUDE_FILTER := $(jacoco_exclude) + +LOCAL_STATIC_JAVA_LIBRARIES := \ + android-support-test \ + mockito-target-minus-junit4 \ + frameworks-base-testutils \ + +LOCAL_JAVA_LIBRARIES := \ + android.test.runner \ + +LOCAL_PACKAGE_NAME := FrameworksWifiApiTests + +include $(BUILD_PACKAGE) diff --git a/wifi/tests/AndroidManifest.xml b/wifi/tests/AndroidManifest.xml new file mode 100644 index 000000000000..4eaca2b98a1d --- /dev/null +++ b/wifi/tests/AndroidManifest.xml @@ -0,0 +1,38 @@ +<?xml version="1.0" encoding="utf-8"?> + +<!-- + ~ Copyright (C) 2016 The Android Open Source Project + ~ + ~ Licensed under the Apache License, Version 2.0 (the "License"); + ~ you may not use this file except in compliance with the License. + ~ You may obtain a copy of the License at + ~ + ~ http://www.apache.org/licenses/LICENSE-2.0 + ~ + ~ Unless required by applicable law or agreed to in writing, software + ~ distributed under the License is distributed on an "AS IS" BASIS, + ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + ~ See the License for the specific language governing permissions and + ~ limitations under the License + --> + +<manifest xmlns:android="http://schemas.android.com/apk/res/android" + package="android.net.wifi.test"> + + <application> + <uses-library android:name="android.test.runner" /> + <activity android:label="WifiTestDummyLabel" + android:name="WifiTestDummyName"> + <intent-filter> + <action android:name="android.intent.action.MAIN" /> + <category android:name="android.intent.category.LAUNCHER"/> + </intent-filter> + </activity> + </application> + + <instrumentation android:name="android.support.test.runner.AndroidJUnitRunner" + android:targetPackage="android.net.wifi.test" + android:label="Frameworks Wifi API Tests"> + </instrumentation> + +</manifest> diff --git a/wifi/tests/README.md b/wifi/tests/README.md new file mode 100644 index 000000000000..b418abd5e46b --- /dev/null +++ b/wifi/tests/README.md @@ -0,0 +1,50 @@ +# Wifi Unit Tests +This package contains unit tests for the android wifi framework APIs based on the +[Android Testing Support Library](http://developer.android.com/tools/testing-support-library/index.html). +The test cases are built using the [JUnit](http://junit.org/) and [Mockito](http://mockito.org/) +libraries. + +## Running Tests +The easiest way to run tests is simply run + +``` +frameworks/base/wifi/tests/runtests.sh +``` + +`runtests.sh` will build the test project and all of its dependencies and push the APK to the +connected device. It will then run the tests on the device. + +To pick up changes in framework/base, you will need to: +1. rebuild the framework library 'make -j32' +2. sync over the updated library to the device 'adb sync' +3. restart framework on the device 'adb shell stop' then 'adb shell start' + +To enable syncing data to the device for first time after clean reflash: +1. adb disable-verity +2. adb reboot +3. adb remount + +See below for a few example of options to limit which tests are run. +See the +[AndroidJUnitRunner Documentation](https://developer.android.com/reference/android/support/test/runner/AndroidJUnitRunner.html) +for more details on the supported options. + +``` +runtests.sh -e package android.net.wifi +runtests.sh -e class android.net.wifi.WifiScannerTest +``` + +If you manually build and push the test APK to the device you can run tests using + +``` +adb shell am instrument -w 'android.net.wifi.test/android.support.test.runner.AndroidJUnitRunner' +``` + +## Adding Tests +Tests can be added by adding classes to the src directory. JUnit4 style test cases can +be written by simply annotating test methods with `org.junit.Test`. + +## Debugging Tests +If you are trying to debug why tests are not doing what you expected, you can add android log +statements and use logcat to view them. The beginning and end of every tests is automatically logged +with the tag `TestRunner`. diff --git a/wifi/tests/runtests.sh b/wifi/tests/runtests.sh new file mode 100755 index 000000000000..ebcc2a2f34a2 --- /dev/null +++ b/wifi/tests/runtests.sh @@ -0,0 +1,24 @@ +#!/usr/bin/env bash + +if [ -z $ANDROID_BUILD_TOP ]; then + echo "You need to source and lunch before you can use this script" + exit 1 +fi + +echo "Running tests" + +set -e # fail early + +echo "+ mmma -j32 $ANDROID_BUILD_TOP/frameworks/base/wifi/tests" +# NOTE Don't actually run the command above since this shell doesn't inherit functions from the +# caller. +make -j32 -C $ANDROID_BUILD_TOP -f build/core/main.mk MODULES-IN-frameworks-base-wifi-tests + +set -x # print commands + +adb root +adb wait-for-device + +adb install -r -g "$OUT/data/app/FrameworksWifiApiTests/FrameworksWifiApiTests.apk" + +adb shell am instrument -w "$@" 'android.net.wifi.test/android.support.test.runner.AndroidJUnitRunner' diff --git a/wifi/tests/src/android/net/wifi/FakeKeys.java b/wifi/tests/src/android/net/wifi/FakeKeys.java new file mode 100644 index 000000000000..0c730705b039 --- /dev/null +++ b/wifi/tests/src/android/net/wifi/FakeKeys.java @@ -0,0 +1,83 @@ +/* + * Copyright (C) 2016 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License + */ + +package android.net.wifi; + +import java.io.ByteArrayInputStream; +import java.io.InputStream; +import java.nio.charset.StandardCharsets; +import java.security.cert.CertificateFactory; +import java.security.cert.X509Certificate; + +/** + * A class containing test certificates. + */ +public class FakeKeys { + private static final String CA_CERT0_STRING = "-----BEGIN CERTIFICATE-----\n" + + "MIIDKDCCAhCgAwIBAgIJAILlFdwzLVurMA0GCSqGSIb3DQEBCwUAMBIxEDAOBgNV\n" + + "BAMTB0VBUCBDQTEwHhcNMTYwMTEyMTE1MDE1WhcNMjYwMTA5MTE1MDE1WjASMRAw\n" + + "DgYDVQQDEwdFQVAgQ0ExMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA\n" + + "znAPUz26Msae4ws43czR41/J2QtrSIZUKmVUsVumDbYHrPNvTXKSMXAcewORDQYX\n" + + "RqvHvpn8CscB1+oGXZvHwxj4zV0WKoK2zeXkau3vcyl3HIKupJfq2TEACefVjj0t\n" + + "JW+X35PGWp9/H5zIUNVNVjS7Ums84IvKhRB8512PB9UyHagXYVX5GWpAcVpyfrlR\n" + + "FI9Qdhh+Pbk0uyktdbf/CdfgHOoebrTtwRljM0oDtX+2Cv6j0wBK7hD8pPvf1+uy\n" + + "GzczigAU/4Kw7eZqydf9B+5RupR+IZipX41xEiIrKRwqi517WWzXcjaG2cNbf451\n" + + "xpH5PnV3i1tq04jMGQUzFwIDAQABo4GAMH4wHQYDVR0OBBYEFIwX4vs8BiBcScod\n" + + "5noZHRM8E4+iMEIGA1UdIwQ7MDmAFIwX4vs8BiBcScod5noZHRM8E4+ioRakFDAS\n" + + "MRAwDgYDVQQDEwdFQVAgQ0ExggkAguUV3DMtW6swDAYDVR0TBAUwAwEB/zALBgNV\n" + + "HQ8EBAMCAQYwDQYJKoZIhvcNAQELBQADggEBAFfQqOTA7Rv7K+luQ7pnas4BYwHE\n" + + "9GEP/uohv6KOy0TGQFbrRTjFoLVNB9BZ1ymMDZ0/TIwIUc7wi7a8t5mEqYH153wW\n" + + "aWooiSjyLLhuI4sNrNCOtisdBq2r2MFXt6h0mAQYOPv8R8K7/fgSxGFqzhyNmmVL\n" + + "1qBJldx34SpwsTALQVPb4hGwJzZfr1PcpEQx6xMnTl8xEWZE3Ms99uaUxbQqIwRu\n" + + "LgAOkNCmY2m89VhzaHJ1uV85AdM/tD+Ysmlnnjt9LRCejbBipjIGjOXrg1JP+lxV\n" + + "muM4vH+P/mlmxsPPz0d65b+EGmJZpoLkO/tdNNvCYzjJpTEWpEsO6NMhKYo=\n" + + "-----END CERTIFICATE-----\n"; + public static final X509Certificate CA_CERT0 = loadCertificate(CA_CERT0_STRING); + + private static final String CA_CERT1_STRING = "-----BEGIN CERTIFICATE-----\n" + + "MIIDKDCCAhCgAwIBAgIJAOM5SzKO2pzCMA0GCSqGSIb3DQEBCwUAMBIxEDAOBgNV\n" + + "BAMTB0VBUCBDQTAwHhcNMTYwMTEyMDAxMDQ3WhcNMjYwMTA5MDAxMDQ3WjASMRAw\n" + + "DgYDVQQDEwdFQVAgQ0EwMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA\n" + + "89ug+IEKVQXnJGKg5g4uVHg6J/8iRUxR5k2eH5o03hrJNMfN2D+cBe/wCiZcnWbI\n" + + "GbGZACWm2nQth2wy9Zgm2LOd3b4ocrHYls3XLq6Qb5Dd7a0JKU7pdGufiNVEkrmF\n" + + "EB+N64wgwH4COTvCiN4erp5kyJwkfqAl2xLkZo0C464c9XoyQOXbmYD9A8v10wZu\n" + + "jyNsEo7Nr2USyw+qhjWSbFbEirP77Tvx+7pJQJwdtk1V9Tn73T2dGF2WHYejei9S\n" + + "mcWpdIUqsu9etYH+zDmtu7I1xlkwiaVsNr2+D+qaCJyOYqrDTKVNK5nmbBPXDWZc\n" + + "NoDbTOoqquX7xONpq9M6jQIDAQABo4GAMH4wHQYDVR0OBBYEFAZ3A2S4qJZZwuNY\n" + + "wkJ6mAdc0gVdMEIGA1UdIwQ7MDmAFAZ3A2S4qJZZwuNYwkJ6mAdc0gVdoRakFDAS\n" + + "MRAwDgYDVQQDEwdFQVAgQ0EwggkA4zlLMo7anMIwDAYDVR0TBAUwAwEB/zALBgNV\n" + + "HQ8EBAMCAQYwDQYJKoZIhvcNAQELBQADggEBAHmdMwEhtys4d0E+t7owBmoVR+lU\n" + + "hMCcRtWs8YKX5WIM2kTweT0h/O1xwE1mWmRv/IbDAEb8od4BjAQLhIcolStr2JaO\n" + + "9ZzyxjOnNzqeErh/1DHDbb/moPpqfeJ8YiEz7nH/YU56Q8iCPO7TsgS0sNNE7PfN\n" + + "IUsBW0yHRgpQ4OxWmiZG2YZWiECRzAC0ecPzo59N5iH4vLQIMTMYquiDeMPQnn1e\n" + + "NDGxG8gCtDKIaS6tMg3a28MvWB094pr2ETou8O1C8Ji0Y4hE8QJmSdT7I4+GZjgW\n" + + "g94DZ5RiL7sdp3vC48CXOmeT61YBIvhGUsE1rPhXqkpqQ3Z3C4TFF0jXZZc=\n" + + "-----END CERTIFICATE-----\n"; + public static final X509Certificate CA_CERT1 = loadCertificate(CA_CERT1_STRING); + + + private static X509Certificate loadCertificate(String blob) { + try { + final CertificateFactory certFactory = CertificateFactory.getInstance("X.509"); + InputStream stream = new ByteArrayInputStream(blob.getBytes(StandardCharsets.UTF_8)); + + return (X509Certificate) certFactory.generateCertificate(stream); + } catch (Exception e) { + e.printStackTrace(); + return null; + } + } +} diff --git a/wifi/tests/src/android/net/wifi/WifiEnterpriseConfigTest.java b/wifi/tests/src/android/net/wifi/WifiEnterpriseConfigTest.java new file mode 100644 index 000000000000..0d964b7c92d7 --- /dev/null +++ b/wifi/tests/src/android/net/wifi/WifiEnterpriseConfigTest.java @@ -0,0 +1,282 @@ +/* + * Copyright (C) 2016 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License + */ + +package android.net.wifi; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.assertNull; + +import android.net.wifi.WifiEnterpriseConfig.Eap; +import android.net.wifi.WifiEnterpriseConfig.Phase2; +import android.os.Parcel; +import android.security.Credentials; +import android.test.suitebuilder.annotation.SmallTest; + +import org.junit.Before; +import org.junit.Test; + +import java.security.cert.X509Certificate; + + +/** + * Unit tests for {@link android.net.wifi.WifiEnterpriseConfig}. + */ +@SmallTest +public class WifiEnterpriseConfigTest { + // Maintain a ground truth of the keystore uri prefix which is expected by wpa_supplicant. + public static final String KEYSTORE_URI = "keystore://"; + public static final String CA_CERT_PREFIX = KEYSTORE_URI + Credentials.CA_CERTIFICATE; + public static final String KEYSTORES_URI = "keystores://"; + + private WifiEnterpriseConfig mEnterpriseConfig; + + @Before + public void setUp() throws Exception { + mEnterpriseConfig = new WifiEnterpriseConfig(); + } + + @Test + public void testGetEmptyCaCertificate() { + // A newly-constructed WifiEnterpriseConfig object should have no CA certificate. + assertNull(mEnterpriseConfig.getCaCertificate()); + assertNull(mEnterpriseConfig.getCaCertificates()); + // Setting CA certificate to null explicitly. + mEnterpriseConfig.setCaCertificate(null); + assertNull(mEnterpriseConfig.getCaCertificate()); + // Setting CA certificate to null using setCaCertificates(). + mEnterpriseConfig.setCaCertificates(null); + assertNull(mEnterpriseConfig.getCaCertificates()); + // Setting CA certificate to zero-length array. + mEnterpriseConfig.setCaCertificates(new X509Certificate[0]); + assertNull(mEnterpriseConfig.getCaCertificates()); + } + + @Test + public void testSetGetSingleCaCertificate() { + X509Certificate cert0 = FakeKeys.CA_CERT0; + mEnterpriseConfig.setCaCertificate(cert0); + assertEquals(mEnterpriseConfig.getCaCertificate(), cert0); + } + + @Test + public void testSetGetMultipleCaCertificates() { + X509Certificate cert0 = FakeKeys.CA_CERT0; + X509Certificate cert1 = FakeKeys.CA_CERT1; + mEnterpriseConfig.setCaCertificates(new X509Certificate[] {cert0, cert1}); + X509Certificate[] result = mEnterpriseConfig.getCaCertificates(); + assertEquals(result.length, 2); + assertTrue(result[0] == cert0 && result[1] == cert1); + } + + @Test + public void testSaveSingleCaCertificateAlias() { + final String alias = "single_alias 0"; + mEnterpriseConfig.setCaCertificateAliases(new String[] {alias}); + assertEquals(getCaCertField(), CA_CERT_PREFIX + alias); + } + + @Test + public void testLoadSingleCaCertificateAlias() { + final String alias = "single_alias 1"; + setCaCertField(CA_CERT_PREFIX + alias); + String[] aliases = mEnterpriseConfig.getCaCertificateAliases(); + assertEquals(aliases.length, 1); + assertEquals(aliases[0], alias); + } + + @Test + public void testSaveMultipleCaCertificates() { + final String alias0 = "single_alias 0"; + final String alias1 = "single_alias 1"; + mEnterpriseConfig.setCaCertificateAliases(new String[] {alias0, alias1}); + assertEquals(getCaCertField(), String.format("%s%s %s", + KEYSTORES_URI, + WifiEnterpriseConfig.encodeCaCertificateAlias(Credentials.CA_CERTIFICATE + alias0), + WifiEnterpriseConfig.encodeCaCertificateAlias(Credentials.CA_CERTIFICATE + alias1))); + } + + @Test + public void testLoadMultipleCaCertificates() { + final String alias0 = "single_alias 0"; + final String alias1 = "single_alias 1"; + setCaCertField(String.format("%s%s %s", + KEYSTORES_URI, + WifiEnterpriseConfig.encodeCaCertificateAlias(Credentials.CA_CERTIFICATE + alias0), + WifiEnterpriseConfig.encodeCaCertificateAlias(Credentials.CA_CERTIFICATE + alias1))); + String[] aliases = mEnterpriseConfig.getCaCertificateAliases(); + assertEquals(aliases.length, 2); + assertEquals(aliases[0], alias0); + assertEquals(aliases[1], alias1); + } + + private String getCaCertField() { + return mEnterpriseConfig.getFieldValue(WifiEnterpriseConfig.CA_CERT_KEY); + } + + private void setCaCertField(String value) { + mEnterpriseConfig.setFieldValue(WifiEnterpriseConfig.CA_CERT_KEY, value); + } + + // Retrieves the value for a specific key supplied to wpa_supplicant. + private class SupplicantConfigExtractor implements WifiEnterpriseConfig.SupplicantSaver { + private String mValue = null; + private String mKey; + + SupplicantConfigExtractor(String key) { + mKey = key; + } + + @Override + public boolean saveValue(String key, String value) { + if (key.equals(mKey)) { + mValue = value; + } + return true; + } + + public String getValue() { + return mValue; + } + } + + private String getSupplicantEapMethod() { + SupplicantConfigExtractor entryExtractor = new SupplicantConfigExtractor( + WifiEnterpriseConfig.EAP_KEY); + mEnterpriseConfig.saveToSupplicant(entryExtractor); + return entryExtractor.getValue(); + } + + private String getSupplicantPhase2Method() { + SupplicantConfigExtractor entryExtractor = new SupplicantConfigExtractor( + WifiEnterpriseConfig.PHASE2_KEY); + mEnterpriseConfig.saveToSupplicant(entryExtractor); + return entryExtractor.getValue(); + } + + /** Verifies the default value for EAP outer and inner methods */ + @Test + public void eapInnerDefault() { + assertEquals(null, getSupplicantEapMethod()); + assertEquals(null, getSupplicantPhase2Method()); + } + + /** Verifies that the EAP inner method is reset when we switch to TLS */ + @Test + public void eapPhase2MethodForTls() { + // Initially select an EAP method that supports an phase2. + mEnterpriseConfig.setEapMethod(Eap.PEAP); + mEnterpriseConfig.setPhase2Method(Phase2.MSCHAPV2); + assertEquals("PEAP", getSupplicantEapMethod()); + assertEquals("\"auth=MSCHAPV2\"", getSupplicantPhase2Method()); + + // Change the EAP method to another type which supports a phase2. + mEnterpriseConfig.setEapMethod(Eap.TTLS); + assertEquals("TTLS", getSupplicantEapMethod()); + assertEquals("\"auth=MSCHAPV2\"", getSupplicantPhase2Method()); + + // Change the EAP method to TLS which does not support a phase2. + mEnterpriseConfig.setEapMethod(Eap.TLS); + assertEquals(null, getSupplicantPhase2Method()); + } + + /** Verfies that the EAP inner method is reset when we switch phase2 to NONE */ + @Test + public void eapPhase2None() { + // Initially select an EAP method that supports an phase2. + mEnterpriseConfig.setEapMethod(Eap.PEAP); + mEnterpriseConfig.setPhase2Method(Phase2.MSCHAPV2); + assertEquals("PEAP", getSupplicantEapMethod()); + assertEquals("\"auth=MSCHAPV2\"", getSupplicantPhase2Method()); + + // Change the phase2 method to NONE and ensure the value is cleared. + mEnterpriseConfig.setPhase2Method(Phase2.NONE); + assertEquals(null, getSupplicantPhase2Method()); + } + + /** Verfies that the correct "autheap" parameter is supplied for TTLS/GTC. */ + @Test + public void peapGtcToTtls() { + mEnterpriseConfig.setEapMethod(Eap.PEAP); + mEnterpriseConfig.setPhase2Method(Phase2.GTC); + assertEquals("PEAP", getSupplicantEapMethod()); + assertEquals("\"auth=GTC\"", getSupplicantPhase2Method()); + + mEnterpriseConfig.setEapMethod(Eap.TTLS); + assertEquals("TTLS", getSupplicantEapMethod()); + assertEquals("\"autheap=GTC\"", getSupplicantPhase2Method()); + } + + /** Verfies that the correct "auth" parameter is supplied for PEAP/GTC. */ + @Test + public void ttlsGtcToPeap() { + mEnterpriseConfig.setEapMethod(Eap.TTLS); + mEnterpriseConfig.setPhase2Method(Phase2.GTC); + assertEquals("TTLS", getSupplicantEapMethod()); + assertEquals("\"autheap=GTC\"", getSupplicantPhase2Method()); + + mEnterpriseConfig.setEapMethod(Eap.PEAP); + assertEquals("PEAP", getSupplicantEapMethod()); + assertEquals("\"auth=GTC\"", getSupplicantPhase2Method()); + } + + /** Verfies that the copy constructor preseves the inner method information. */ + @Test + public void copyConstructor() { + WifiEnterpriseConfig enterpriseConfig = new WifiEnterpriseConfig(); + enterpriseConfig.setEapMethod(Eap.TTLS); + enterpriseConfig.setPhase2Method(Phase2.GTC); + mEnterpriseConfig = new WifiEnterpriseConfig(enterpriseConfig); + assertEquals("TTLS", getSupplicantEapMethod()); + assertEquals("\"autheap=GTC\"", getSupplicantPhase2Method()); + } + + /** Verfies that parceling a WifiEnterpriseConfig preseves method information. */ + @Test + public void parcelConstructor() { + WifiEnterpriseConfig enterpriseConfig = new WifiEnterpriseConfig(); + enterpriseConfig.setEapMethod(Eap.TTLS); + enterpriseConfig.setPhase2Method(Phase2.GTC); + Parcel parcel = Parcel.obtain(); + enterpriseConfig.writeToParcel(parcel, 0); + parcel.setDataPosition(0); // Allow parcel to be read from the beginning. + mEnterpriseConfig = WifiEnterpriseConfig.CREATOR.createFromParcel(parcel); + assertEquals("TTLS", getSupplicantEapMethod()); + assertEquals("\"autheap=GTC\"", getSupplicantPhase2Method()); + } + + /** Verifies proper operation of the getKeyId() method. */ + @Test + public void getKeyId() { + assertEquals("NULL", mEnterpriseConfig.getKeyId(null)); + WifiEnterpriseConfig enterpriseConfig = new WifiEnterpriseConfig(); + enterpriseConfig.setEapMethod(Eap.TTLS); + enterpriseConfig.setPhase2Method(Phase2.GTC); + assertEquals("TTLS_GTC", mEnterpriseConfig.getKeyId(enterpriseConfig)); + mEnterpriseConfig.setEapMethod(Eap.PEAP); + mEnterpriseConfig.setPhase2Method(Phase2.MSCHAPV2); + assertEquals("PEAP_MSCHAPV2", mEnterpriseConfig.getKeyId(enterpriseConfig)); + } + + /** Verifies that passwords are not displayed in toString. */ + @Test + public void passwordNotInToString() { + String password = "supersecret"; + mEnterpriseConfig.setPassword(password); + assertFalse(mEnterpriseConfig.toString().contains(password)); + } +} diff --git a/wifi/tests/src/android/net/wifi/WifiScannerTest.java b/wifi/tests/src/android/net/wifi/WifiScannerTest.java new file mode 100644 index 000000000000..a829eb933b59 --- /dev/null +++ b/wifi/tests/src/android/net/wifi/WifiScannerTest.java @@ -0,0 +1,111 @@ +/* + * Copyright (C) 2016 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.net.wifi; + +import static org.junit.Assert.assertEquals; +import static org.mockito.Matchers.anyString; +import static org.mockito.Matchers.eq; +import static org.mockito.Mockito.atLeastOnce; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.validateMockitoUsage; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import android.content.Context; +import android.net.wifi.WifiScanner.BssidInfo; +import android.net.wifi.WifiScanner.BssidListener; +import android.os.Handler; +import android.os.Message; +import android.os.test.TestLooper; +import android.test.suitebuilder.annotation.SmallTest; + +import com.android.internal.util.test.BidirectionalAsyncChannelServer; + +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.mockito.ArgumentCaptor; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; + +/** + * Unit tests for {@link android.net.wifi.WifiScanner}. + */ +@SmallTest +public class WifiScannerTest { + @Mock + private Context mContext; + @Mock + private IWifiScanner mService; + @Mock + private BssidListener mBssidListener; + + private WifiScanner mWifiScanner; + private TestLooper mLooper; + private Handler mHandler; + + /** + * Setup before tests. + */ + @Before + public void setUp() throws Exception { + MockitoAnnotations.initMocks(this); + mLooper = new TestLooper(); + mHandler = mock(Handler.class); + BidirectionalAsyncChannelServer server = new BidirectionalAsyncChannelServer( + mContext, mLooper.getLooper(), mHandler); + when(mService.getMessenger()).thenReturn(server.getMessenger()); + mWifiScanner = new WifiScanner(mContext, mService, mLooper.getLooper()); + mLooper.dispatchAll(); + } + + /** + * Clean up after tests. + */ + @After + public void cleanup() { + validateMockitoUsage(); + } + + private void verifySetHotlistMessage(Handler handler) { + ArgumentCaptor<Message> messageCaptor = ArgumentCaptor.forClass(Message.class); + verify(handler, atLeastOnce()).handleMessage(messageCaptor.capture()); + assertEquals("message.what is not CMD_SET_HOTLIST", + WifiScanner.CMD_SET_HOTLIST, + messageCaptor.getValue().what); + } + + /** + * Test duplicate listeners for bssid tracking. + */ + @Test + public void testStartTrackingBssidsDuplicateListeners() throws Exception { + BssidInfo[] bssids = new BssidInfo[] { + new BssidInfo() + }; + + // First start tracking succeeds. + mWifiScanner.startTrackingBssids(bssids, -100, mBssidListener); + mLooper.dispatchAll(); + verifySetHotlistMessage(mHandler); + + // Second start tracking should fail. + mWifiScanner.startTrackingBssids(bssids, -100, mBssidListener); + mLooper.dispatchAll(); + verify(mBssidListener).onFailure(eq(WifiScanner.REASON_DUPLICATE_REQEUST), anyString()); + } +} |