diff options
46 files changed, 1146 insertions, 220 deletions
diff --git a/core/java/android/app/ActivityManagerNative.java b/core/java/android/app/ActivityManagerNative.java index f798512092e4..d91472b6a1ba 100644 --- a/core/java/android/app/ActivityManagerNative.java +++ b/core/java/android/app/ActivityManagerNative.java @@ -1229,8 +1229,9 @@ public abstract class ActivityManagerNative extends Binder implements IActivityM case UPDATE_CONFIGURATION_TRANSACTION: { data.enforceInterface(IActivityManager.descriptor); Configuration config = Configuration.CREATOR.createFromParcel(data); - updateConfiguration(config); + final boolean updated = updateConfiguration(config); reply.writeNoException(); + reply.writeInt(updated ? 1 : 0); return true; } @@ -4593,7 +4594,7 @@ class ActivityManagerProxy implements IActivityManager data.recycle(); return res; } - public void updateConfiguration(Configuration values) throws RemoteException + public boolean updateConfiguration(Configuration values) throws RemoteException { Parcel data = Parcel.obtain(); Parcel reply = Parcel.obtain(); @@ -4601,8 +4602,10 @@ class ActivityManagerProxy implements IActivityManager values.writeToParcel(data, 0); mRemote.transact(UPDATE_CONFIGURATION_TRANSACTION, data, reply, 0); reply.readException(); + boolean updated = reply.readInt() == 1; data.recycle(); reply.recycle(); + return updated; } public void setRequestedOrientation(IBinder token, int requestedOrientation) throws RemoteException { diff --git a/core/java/android/app/IActivityManager.java b/core/java/android/app/IActivityManager.java index 096f0cb190e7..c9d3682405d1 100644 --- a/core/java/android/app/IActivityManager.java +++ b/core/java/android/app/IActivityManager.java @@ -276,8 +276,9 @@ public interface IActivityManager extends IInterface { * Updates global configuration and applies changes to the entire system. * @param values Update values for global configuration. * @throws RemoteException + * @return Returns true if the configuration was updated. */ - public void updateConfiguration(Configuration values) throws RemoteException; + public boolean updateConfiguration(Configuration values) throws RemoteException; public void setRequestedOrientation(IBinder token, int requestedOrientation) throws RemoteException; diff --git a/core/java/android/provider/DocumentsContract.java b/core/java/android/provider/DocumentsContract.java index 6ddaf3bff77f..98371f444c78 100644 --- a/core/java/android/provider/DocumentsContract.java +++ b/core/java/android/provider/DocumentsContract.java @@ -36,8 +36,10 @@ import android.net.Uri; import android.os.Bundle; import android.os.CancellationSignal; import android.os.OperationCanceledException; +import android.os.Parcel; import android.os.ParcelFileDescriptor; import android.os.ParcelFileDescriptor.OnCloseListener; +import android.os.Parcelable; import android.os.RemoteException; import android.os.storage.StorageVolume; import android.system.ErrnoException; @@ -644,6 +646,8 @@ public final class DocumentsContract { public static final String METHOD_REMOVE_DOCUMENT = "android:removeDocument"; /** {@hide} */ public static final String METHOD_EJECT_ROOT = "android:ejectRoot"; + /** {@hide} */ + public static final String METHOD_FIND_PATH = "android:findPath"; /** {@hide} */ public static final String EXTRA_PARENT_URI = "parentUri"; @@ -1307,6 +1311,41 @@ public final class DocumentsContract { } /** + * Finds the canonical path to the root. Document id should be unique across + * roots. + * + * @param documentUri uri of the document which path is requested. + * @return the path to the root of the document, or {@code null} if failed. + * @see DocumentsProvider#findPath(String) + * + * {@hide} + */ + public static Path findPath(ContentResolver resolver, Uri documentUri) + throws RemoteException { + final ContentProviderClient client = resolver.acquireUnstableContentProviderClient( + documentUri.getAuthority()); + try { + return findPath(client, documentUri); + } catch (Exception e) { + Log.w(TAG, "Failed to find path", e); + return null; + } finally { + ContentProviderClient.releaseQuietly(client); + } + } + + /** {@hide} */ + public static Path findPath(ContentProviderClient client, Uri documentUri) + throws RemoteException { + final Bundle in = new Bundle(); + in.putParcelable(DocumentsContract.EXTRA_URI, documentUri); + + final Bundle out = client.call(METHOD_FIND_PATH, null, in); + + return out.getParcelable(DocumentsContract.EXTRA_RESULT); + } + + /** * Open the given image for thumbnail purposes, using any embedded EXIF * thumbnail if available, and providing orientation hints from the parent * image. @@ -1345,4 +1384,51 @@ public final class DocumentsContract { return new AssetFileDescriptor(pfd, 0, AssetFileDescriptor.UNKNOWN_LENGTH, extras); } + + /** + * Holds a path from a root to a particular document under it. + * + * @hide + */ + public static final class Path implements Parcelable { + + public final String mRootId; + public final List<String> mPath; + + /** + * Creates a Path. + * @param rootId the id of the root + * @param path the list of document ids from the root document + * at position 0 to the target document + */ + public Path(String rootId, List<String> path) { + mRootId = rootId; + mPath = path; + } + + @Override + public void writeToParcel(Parcel dest, int flags) { + dest.writeString(mRootId); + dest.writeStringList(mPath); + } + + @Override + public int describeContents() { + return 0; + } + + public static final Creator<Path> CREATOR = new Creator<Path>() { + @Override + public Path createFromParcel(Parcel in) { + final String rootId = in.readString(); + final List<String> path = in.createStringArrayList(); + return new Path(rootId, path); + } + + @Override + public Path[] newArray(int size) { + return new Path[size]; + } + }; + } } diff --git a/core/java/android/provider/DocumentsProvider.java b/core/java/android/provider/DocumentsProvider.java index 6117ce4cc24a..6234f6ae7131 100644 --- a/core/java/android/provider/DocumentsProvider.java +++ b/core/java/android/provider/DocumentsProvider.java @@ -20,6 +20,7 @@ import static android.provider.DocumentsContract.METHOD_COPY_DOCUMENT; import static android.provider.DocumentsContract.METHOD_CREATE_DOCUMENT; import static android.provider.DocumentsContract.METHOD_DELETE_DOCUMENT; import static android.provider.DocumentsContract.METHOD_EJECT_ROOT; +import static android.provider.DocumentsContract.METHOD_FIND_PATH; import static android.provider.DocumentsContract.METHOD_IS_CHILD_DOCUMENT; import static android.provider.DocumentsContract.METHOD_MOVE_DOCUMENT; import static android.provider.DocumentsContract.METHOD_REMOVE_DOCUMENT; @@ -33,6 +34,7 @@ import static android.provider.DocumentsContract.getSearchDocumentsQuery; import static android.provider.DocumentsContract.getTreeDocumentId; import static android.provider.DocumentsContract.isTreeUri; +import android.Manifest; import android.annotation.CallSuper; import android.content.ClipDescription; import android.content.ContentProvider; @@ -53,6 +55,7 @@ import android.os.ParcelFileDescriptor; import android.os.ParcelFileDescriptor.OnCloseListener; import android.provider.DocumentsContract.Document; import android.provider.DocumentsContract.Root; +import android.provider.DocumentsContract.Path; import android.util.Log; import libcore.io.IoUtils; @@ -323,6 +326,26 @@ public abstract class DocumentsProvider extends ContentProvider { } /** + * Finds the canonical path to the root for the requested document. If there are + * more than one path to this document, return the most typical one. + * + * <p>This API assumes that document id has enough info to infer the root. + * Different roots should use different document id to refer to the same + * document. + * + * @param documentId the document which path is requested. + * @return the path of the requested document to the root, or null if + * such operation is not supported. + * + * @hide + */ + public Path findPath(String documentId) + throws FileNotFoundException { + Log.w(TAG, "findPath is called on an unsupported provider."); + return null; + } + + /** * Return all roots currently provided. To display to users, you must define * at least one root. You should avoid making network requests to keep this * request fast. @@ -873,6 +896,12 @@ public abstract class DocumentsProvider extends ContentProvider { // It's responsibility of the provider to revoke any grants, as the document may be // still attached to another parents. + } else if (METHOD_FIND_PATH.equals(method)) { + getContext().enforceCallingPermission(Manifest.permission.MANAGE_DOCUMENTS, null); + + final Path path = findPath(documentId); + + out.putParcelable(DocumentsContract.EXTRA_RESULT, path); } else { throw new UnsupportedOperationException("Method not supported " + method); } diff --git a/core/java/android/widget/TextClock.java b/core/java/android/widget/TextClock.java index 278ceb28c1db..5003c610241a 100644 --- a/core/java/android/widget/TextClock.java +++ b/core/java/android/widget/TextClock.java @@ -132,7 +132,7 @@ public class TextClock extends TextView { private CharSequence mDescFormat; - private boolean mAttached; + private boolean mRegistered; private Calendar mTime; private String mTimeZone; @@ -252,7 +252,7 @@ public class TextClock extends TextView { } createTime(mTimeZone); - // Wait until onAttachedToWindow() to handle the ticker + // Wait until registering for events to handle the ticker chooseFormat(false); } @@ -503,7 +503,7 @@ public class TextClock extends TextView { boolean hadSeconds = mHasSeconds; mHasSeconds = DateFormat.hasSeconds(mFormat); - if (handleTicker && mAttached && hadSeconds != mHasSeconds) { + if (handleTicker && mRegistered && hadSeconds != mHasSeconds) { if (hadSeconds) getHandler().removeCallbacks(mTicker); else mTicker.run(); } @@ -517,11 +517,9 @@ public class TextClock extends TextView { } @Override - protected void onAttachedToWindow() { - super.onAttachedToWindow(); - - if (!mAttached) { - mAttached = true; + public void onVisibilityAggregated(boolean isVisible) { + if (!mRegistered && isVisible) { + mRegistered = true; registerReceiver(); registerObserver(); @@ -533,20 +531,13 @@ public class TextClock extends TextView { } else { onTimeChanged(); } - } - } - - @Override - protected void onDetachedFromWindow() { - super.onDetachedFromWindow(); - - if (mAttached) { + } else if (mRegistered && !isVisible) { unregisterReceiver(); unregisterObserver(); getHandler().removeCallbacks(mTicker); - mAttached = false; + mRegistered = false; } } @@ -569,7 +560,7 @@ public class TextClock extends TextView { } private void registerObserver() { - if (isAttachedToWindow()) { + if (mRegistered) { if (mFormatChangeObserver == null) { mFormatChangeObserver = new FormatChangeObserver(getHandler()); } diff --git a/core/jni/android_os_Debug.cpp b/core/jni/android_os_Debug.cpp index 97c7f049fdb9..ba9facfd19cf 100644 --- a/core/jni/android_os_Debug.cpp +++ b/core/jni/android_os_Debug.cpp @@ -430,6 +430,8 @@ static void load_maps(int pid, stats_t* stats, bool* foundSwapPss) char tmp[128]; FILE *fp; + *foundSwapPss = false; + sprintf(tmp, "/proc/%d/smaps", pid); fp = fopen(tmp, "r"); if (fp == 0) return; diff --git a/core/jni/android_os_HwBinder.cpp b/core/jni/android_os_HwBinder.cpp index 7da03143087f..13e3f0d6ae94 100644 --- a/core/jni/android_os_HwBinder.cpp +++ b/core/jni/android_os_HwBinder.cpp @@ -266,6 +266,9 @@ static jobject JHwBinder_native_getService( return NULL; } + LOG(INFO) << "Starting thread pool."; + ::android::hardware::ProcessState::self()->startThreadPool(); + return JHwRemoteBinder::NewObject(env, service); } diff --git a/core/res/res/values-gl-rES/strings.xml b/core/res/res/values-gl-rES/strings.xml index a5c3c6ee2d85..704667a4eebd 100644 --- a/core/res/res/values-gl-rES/strings.xml +++ b/core/res/res/values-gl-rES/strings.xml @@ -214,7 +214,7 @@ <string name="global_actions" product="default" msgid="2406416831541615258">"Opcións de teléfono"</string> <string name="global_action_lock" msgid="2844945191792119712">"Bloqueo da pantalla"</string> <string name="global_action_power_off" msgid="4471879440839879722">"Apagar"</string> - <string name="global_action_emergency" msgid="7112311161137421166">"Emerxencia"</string> + <string name="global_action_emergency" msgid="7112311161137421166">"Emerxencias"</string> <string name="global_action_bug_report" msgid="7934010578922304799">"Informe de erros"</string> <string name="bugreport_title" msgid="2667494803742548533">"Crear informe de erros"</string> <string name="bugreport_message" msgid="398447048750350456">"Este informe recompilará información acerca do estado actual do teu dispositivo para enviala en forma de mensaxe de correo electrónico. O informe de erros tardará un pouco en completarse desde o seu inicio ata que estea preparado para enviarse, polo que che recomendamos que teñas paciencia."</string> diff --git a/core/res/res/values-km-rKH/strings.xml b/core/res/res/values-km-rKH/strings.xml index 4eaadfe8feb0..2491f82c6e01 100644 --- a/core/res/res/values-km-rKH/strings.xml +++ b/core/res/res/values-km-rKH/strings.xml @@ -1331,7 +1331,7 @@ <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="3620440638180218181">"ការដាស់តឿនពីការប្រើទិន្នន័យ"</string> + <string name="data_usage_warning_title" msgid="3620440638180218181">"ការព្រមានអំពីការប្រើទិន្នន័យ"</string> <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 1a5f348fe81f..7a48ae58bd11 100644 --- a/core/res/res/values-ky-rKG/strings.xml +++ b/core/res/res/values-ky-rKG/strings.xml @@ -1329,7 +1329,7 @@ <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="3620440638180218181">"Дайындарды колдонуу айгайы"</string> + <string name="data_usage_warning_title" msgid="3620440638180218181">"Дайындарды колдонууну чектөө"</string> <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 f0e437a65c5b..758b21b7c896 100644 --- a/core/res/res/values-mr-rIN/strings.xml +++ b/core/res/res/values-mr-rIN/strings.xml @@ -1075,7 +1075,7 @@ <string name="network_available_sign_in" msgid="1848877297365446605">"नेटवर्कवर साइन इन करा"</string> <!-- no translation found for network_available_sign_in_detailed (8000081941447976118) --> <skip /> - <string name="wifi_no_internet" msgid="8451173622563841546">"वाय-फाय मध्ये इंटरनेट प्रवेश नाही"</string> + <string name="wifi_no_internet" msgid="8451173622563841546">"वाय-फायवरून इंटरनेटवर प्रवेश नाही"</string> <string name="wifi_no_internet_detailed" msgid="8083079241212301741">"पर्यायांसाठी टॅप करा"</string> <string name="network_switch_metered" msgid="4671730921726992671">"<xliff:g id="NETWORK_TYPE">%1$s</xliff:g> वर स्विच केले"</string> <string name="network_switch_metered_detail" msgid="5325661434777870353">"<xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> कडे इंटरनेट प्रवेश नसताना डिव्हाइस <xliff:g id="NEW_NETWORK">%1$s</xliff:g> वापरतो. शुल्क लागू शकतील."</string> diff --git a/core/res/res/values/themes_device_defaults.xml b/core/res/res/values/themes_device_defaults.xml index abb0c8f25022..4be45e990e99 100644 --- a/core/res/res/values/themes_device_defaults.xml +++ b/core/res/res/values/themes_device_defaults.xml @@ -261,6 +261,7 @@ easier. <item name="colorBackground">@color/background_floating_device_default_dark</item> <item name="colorBackgroundFloating">@color/background_floating_device_default_dark</item> <item name="colorBackgroundCacheHint">@color/background_cache_hint_selector_device_default</item> + <item name="colorButtonNormal">@color/button_normal_device_default_dark</item> </style> <!-- Variant of {@link #Theme_DeviceDefault_Dialog} that has a nice minimum width for a @@ -352,27 +353,17 @@ easier. <!-- DeviceDefault style for input methods, which is used by the {@link android.service.voice.VoiceInteractionSession} class.--> <style name="Theme.DeviceDefault.VoiceInteractionSession" parent="Theme.Material.VoiceInteractionSession"> - <!-- Color palette --> <item name="colorPrimary">@color/primary_device_default_light</item> <item name="colorPrimaryDark">@color/primary_dark_device_default_light</item> <item name="colorAccent">@color/accent_device_default_light</item> </style> - <style name="Theme.DeviceDefault.Dialog.Alert" parent="Theme.Material.Dialog.Alert"> - <item name="windowTitleStyle">@style/DialogWindowTitle.DeviceDefault</item> - - <!-- Color palette --> - <item name="colorPrimary">@color/primary_device_default_dark</item> - <item name="colorPrimaryDark">@color/primary_dark_device_default_dark</item> - <item name="colorAccent">@color/accent_device_default_dark</item> + <style name="Theme.DeviceDefault.Dialog.Alert"> + <item name="windowMinWidthMajor">@dimen/dialog_min_width_major</item> + <item name="windowMinWidthMinor">@dimen/dialog_min_width_minor</item> </style> - <style name="Theme.DeviceDefault.SearchBar" parent="Theme.Material.SearchBar"> - <!-- Color palette --> - <item name="colorPrimary">@color/primary_device_default_dark</item> - <item name="colorPrimaryDark">@color/primary_dark_device_default_dark</item> - <item name="colorAccent">@color/accent_device_default_dark</item> - </style> + <style name="Theme.DeviceDefault.SearchBar" parent="Theme.DeviceDefault.Panel"/> <style name="Theme.DeviceDefault.Dialog.NoFrame" parent="Theme.Material.Dialog.NoFrame"> <!-- Color palette --> @@ -551,6 +542,7 @@ easier. <item name="colorBackground">@color/background_device_default_dark</item> <item name="colorBackgroundFloating">@color/background_floating_device_default_dark</item> <item name="colorBackgroundCacheHint">@color/background_cache_hint_selector_device_default</item> + <item name="colorButtonNormal">@color/button_normal_device_default_dark</item> </style> <!-- Variant of {@link #Theme_DeviceDefault_Light} with no action bar --> @@ -605,6 +597,7 @@ easier. <item name="colorBackground">@color/background_device_default_dark</item> <item name="colorBackgroundFloating">@color/background_floating_device_default_dark</item> <item name="colorBackgroundCacheHint">@color/background_cache_hint_selector_device_default</item> + <item name="colorButtonNormal">@color/button_normal_device_default_light</item> </style> <!-- Variant of {@link #Theme_DeviceDefault_Light_Dialog} that has a nice minimum width for a @@ -659,120 +652,60 @@ easier. decorations, so you basically have an empty rectangle in which to place your content. It makes the window floating, with a transparent background, and turns off dimming behind the window. --> <style name="Theme.DeviceDefault.Light.Panel" parent="Theme.Material.Light.Panel"> - <!-- Color palette --> - <item name="colorPrimary">@color/primary_device_default_light</item> - <item name="colorPrimaryDark">@color/primary_dark_device_default_light</item> - <item name="colorAccent">@color/accent_device_default_light</item> - <item name="colorBackground">@color/background_device_default_dark</item> - <item name="colorBackgroundFloating">@color/background_floating_device_default_dark</item> - <item name="colorBackgroundCacheHint">@color/background_cache_hint_selector_device_default</item> + <item name="windowBackground">@color/transparent</item> + <item name="colorBackgroundCacheHint">@null</item> + <item name="windowFrame">@null</item> + <item name="windowContentOverlay">@null</item> + <item name="windowAnimationStyle">@null</item> + <item name="windowIsFloating">true</item> + <item name="backgroundDimEnabled">false</item> + <item name="windowIsTranslucent">true</item> + <item name="windowNoTitle">true</item> </style> - <style name="Theme.DeviceDefault.Light.Dialog.Alert" parent="Theme.Material.Light.Dialog.Alert"> - <item name="windowTitleStyle">@style/DialogWindowTitle.DeviceDefault.Light</item> - - <!-- Color palette --> - <item name="colorPrimary">@color/primary_device_default_light</item> - <item name="colorPrimaryDark">@color/primary_dark_device_default_light</item> - <item name="colorAccent">@color/accent_device_default_light</item> - <item name="colorBackground">@color/background_device_default_dark</item> - <item name="colorBackgroundFloating">@color/background_floating_device_default_dark</item> - <item name="colorBackgroundCacheHint">@color/background_cache_hint_selector_device_default</item> + <style name="Theme.DeviceDefault.Light.Dialog.Alert"> + <item name="windowMinWidthMajor">@dimen/dialog_min_width_major</item> + <item name="windowMinWidthMinor">@dimen/dialog_min_width_minor</item> </style> - <style name="Theme.DeviceDefault.Light.SearchBar" parent="Theme.Material.Light.SearchBar"> - <!-- Color palette --> - <item name="colorPrimary">@color/primary_device_default_light</item> - <item name="colorPrimaryDark">@color/primary_dark_device_default_light</item> - <item name="colorAccent">@color/accent_device_default_light</item> - <item name="colorBackground">@color/background_device_default_dark</item> - <item name="colorBackgroundFloating">@color/background_floating_device_default_dark</item> - <item name="colorBackgroundCacheHint">@color/background_cache_hint_selector_device_default</item> - </style> + <style name="Theme.DeviceDefault.Light.SearchBar" parent="@style/Theme.DeviceDefault.Light.Panel"/> - <style name="Theme.DeviceDefault.Light.Voice" parent="Theme.Material.Light.Voice"> - <!-- Color palette --> - <item name="colorPrimary">@color/primary_device_default_light</item> - <item name="colorPrimaryDark">@color/primary_dark_device_default_light</item> - <item name="colorAccent">@color/accent_device_default_light</item> - <item name="colorBackground">@color/background_device_default_dark</item> - <item name="colorBackgroundFloating">@color/background_floating_device_default_dark</item> - <item name="colorBackgroundCacheHint">@color/background_cache_hint_selector_device_default</item> + <style name="Theme.DeviceDefault.Light.Voice" parent="@style/Theme.DeviceDefault.Light.Dialog"> + <item name="windowAnimationStyle">@style/Animation.VoiceActivity</item> + <item name="backgroundDimEnabled">false</item> </style> <!-- DeviceDefault theme for a window that should look like the Settings app. --> - <style name="Theme.DeviceDefault.Settings" parent="Theme.Material.Settings"> - <!-- Color palette --> - <item name="colorPrimary">@color/primary_device_default_settings</item> - <item name="colorPrimaryDark">@color/primary_dark_device_default_settings</item> - <item name="colorSecondary">@color/secondary_device_default_settings</item> - <item name="colorAccent">@color/accent_device_default_light</item> - <item name="colorBackground">@color/background_device_default_dark</item> - <item name="colorBackgroundFloating">@color/background_floating_device_default_dark</item> - <item name="colorBackgroundCacheHint">@color/background_cache_hint_selector_device_default</item> + <style name="Theme.DeviceDefault.Settings" parent="Theme.DeviceDefault.Light.DarkActionBar"> + <item name="presentationTheme">@style/Theme.Material.Settings.Dialog.Presentation</item> + <item name="searchDialogTheme">@style/Theme.Material.Settings.SearchBar</item> + <item name="panelMenuListTheme">@style/Theme.Material.Settings.CompactMenu</item> </style> <!-- DeviceDefault theme for a window that should use Settings theme colors but has a full dark palette (instead of Light with dark action bar like Theme.DeviceDefault.Settings. --> - <style name="Theme.DeviceDefault.Settings.Dark" parent="Theme.Material"> - <!-- Color palette --> - <item name="colorPrimary">@color/primary_device_default_settings</item> - <item name="colorPrimaryDark">@color/primary_dark_device_default_settings</item> - <item name="colorSecondary">@color/secondary_device_default_settings</item> - <item name="colorAccent">@color/accent_device_default_dark</item> - <item name="colorBackground">@color/background_device_default_dark</item> - <item name="colorBackgroundFloating">@color/background_floating_device_default_dark</item> - <item name="colorBackgroundCacheHint">@color/background_cache_hint_selector_device_default</item> - </style> + <style name="Theme.DeviceDefault.Settings.Dark" parent="Theme.DeviceDefault"/> <!-- Variant of {@link #Theme_DeviceDefault_Settings_Dark} with no action bar --> - <style name="Theme.DeviceDefault.Settings.Dark.NoActionBar" parent="Theme.Material.NoActionBar"> - <!-- Color palette --> - <item name="colorPrimary">@color/primary_device_default_settings</item> - <item name="colorPrimaryDark">@color/primary_dark_device_default_settings</item> - <item name="colorSecondary">@color/secondary_device_default_settings</item> - <item name="colorAccent">@color/accent_device_default_dark</item> - <item name="colorBackground">@color/background_device_default_dark</item> - <item name="colorBackgroundFloating">@color/background_floating_device_default_dark</item> - <item name="colorBackgroundCacheHint">@color/background_cache_hint_selector_device_default</item> - </style> + <style name="Theme.DeviceDefault.Settings.Dark.NoActionBar" parent="Theme.DeviceDefault.NoActionBar"/> - <style name="Theme.DeviceDefault.Settings.Dialog" parent="Theme.Material.Settings.Dialog"> - <!-- Color palette --> + <style name="Theme.DeviceDefault.Settings.Dialog" parent="Theme.DeviceDefault.Light.Dialog"> <item name="colorPrimary">@color/primary_device_default_settings</item> <item name="colorPrimaryDark">@color/primary_dark_device_default_settings</item> <item name="colorSecondary">@color/secondary_device_default_settings</item> - <item name="colorAccent">@color/accent_device_default_light</item> - <item name="colorBackground">@color/background_device_default_dark</item> - <item name="colorBackgroundFloating">@color/background_floating_device_default_dark</item> - <item name="colorBackgroundCacheHint">@color/background_cache_hint_selector_device_default</item> </style> - <style name="Theme.DeviceDefault.Settings.DialogWhenLarge" parent="Theme.Material.Settings.DialogWhenLarge"> - <!-- Color palette --> - <item name="colorPrimary">@color/primary_device_default_settings</item> - <item name="colorPrimaryDark">@color/primary_dark_device_default_settings</item> - <item name="colorSecondary">@color/secondary_device_default_settings</item> - <item name="colorAccent">@color/accent_device_default_light</item> - <item name="colorBackground">@color/background_device_default_dark</item> - <item name="colorBackgroundFloating">@color/background_floating_device_default_dark</item> - <item name="colorBackgroundCacheHint">@color/background_cache_hint_selector_device_default</item> - </style> + <style name="Theme.DeviceDefault.Settings.DialogWhenLarge" parent="Theme.DeviceDefault.Light"/> - <style name="Theme.DeviceDefault.Settings.Dialog.Alert" parent="Theme.Material.Settings.Dialog.Alert"> - <!-- Color palette --> + <style name="Theme.DeviceDefault.Settings.Dialog.Alert" parent="Theme.DeviceDefault.Light.Dialog.Alert"> <item name="colorPrimary">@color/primary_device_default_settings</item> <item name="colorPrimaryDark">@color/primary_dark_device_default_settings</item> <item name="colorSecondary">@color/secondary_device_default_settings</item> - <item name="colorAccent">@color/accent_device_default_light</item> - <item name="colorBackground">@color/background_device_default_dark</item> - <item name="colorBackgroundFloating">@color/background_floating_device_default_dark</item> - <item name="colorBackgroundCacheHint">@color/background_cache_hint_selector_device_default</item> </style> <!-- Theme used for the intent picker activity. --> - <style name="Theme.DeviceDefault.Resolver" parent="Theme.Material.Light"> + <style name="Theme.DeviceDefault.Resolver" parent="Theme.DeviceDefault.Light"> <item name="windowIsTranslucent">true</item> <item name="windowNoTitle">true</item> <item name="windowBackground">@color/transparent</item> @@ -782,14 +715,6 @@ easier. <item name="colorControlActivated">?attr/colorControlHighlight</item> <item name="listPreferredItemPaddingStart">?attr/dialogPreferredPadding</item> <item name="listPreferredItemPaddingEnd">?attr/dialogPreferredPadding</item> - - <!-- Color palette --> - <item name="colorPrimary">@color/primary_device_default_light</item> - <item name="colorPrimaryDark">@color/primary_dark_device_default_light</item> - <item name="colorAccent">@color/accent_device_default_light</item> - <item name="colorBackground">@color/background_device_default_light</item> - <item name="colorBackgroundFloating">@color/background_floating_device_default_light</item> - <item name="colorBackgroundCacheHint">@color/background_cache_hint_selector_device_default</item> </style> <!-- DeviceDefault theme for the default system theme. --> diff --git a/core/tests/coretests/AndroidManifest.xml b/core/tests/coretests/AndroidManifest.xml index ee7861313428..ba1a55d7f9a6 100644 --- a/core/tests/coretests/AndroidManifest.xml +++ b/core/tests/coretests/AndroidManifest.xml @@ -1323,17 +1323,6 @@ </meta-data> </service> - <activity - android:name="android.print.mockservice.SettingsActivity" - android:permission="android.permission.START_PRINT_SERVICE_CONFIG_ACTIVITY" - android:exported="true"> - </activity> - - <activity - android:name="android.print.mockservice.AddPrintersActivity" - android:exported="true"> - </activity> - </application> <instrumentation android:name="android.support.test.runner.AndroidJUnitRunner" diff --git a/core/tests/coretests/res/xml/printservice.xml b/core/tests/coretests/res/xml/printservice.xml index b105a0f0b785..3bd2b04d7aff 100644 --- a/core/tests/coretests/res/xml/printservice.xml +++ b/core/tests/coretests/res/xml/printservice.xml @@ -16,6 +16,4 @@ limitations under the License. --> -<print-service xmlns:android="http://schemas.android.com/apk/res/android" - android:settingsActivity="android.print.mockservice.SettingsActivity" - android:addPrintersActivity="android.print.mockservice.AddPrintersActivity" /> +<print-service xmlns:android="http://schemas.android.com/apk/res/android" /> diff --git a/docs/html/_redirects.yaml b/docs/html/_redirects.yaml index 3a993d73d4fc..7200d4773517 100644 --- a/docs/html/_redirects.yaml +++ b/docs/html/_redirects.yaml @@ -806,7 +806,7 @@ redirects: - from: /preview/features/power-mgmt.html to: /training/monitoring-device-state/doze-standby.html - from: /preview/dev-community - to: https://plus.google.com/communities/103655397235276743411 + to: https://plus.google.com/communities/105153134372062985968 - from: /preview/bug to: https://source.android.com/source/report-bugs.html - from: /preview/bug/... diff --git a/docs/html/jd_extras_zh-cn.js b/docs/html/jd_extras_zh-cn.js index cb1ccb7d6ee3..866a87efed8f 100644 --- a/docs/html/jd_extras_zh-cn.js +++ b/docs/html/jd_extras_zh-cn.js @@ -244,40 +244,40 @@ METADATA['zh-cn'].collections = { "overview/zhcn/1": { "title": "", "resources": [ - "intl/zh-cn/distribute/essentials/quality/core.html", - "intl/zh-cn/distribute/essentials/quality/tablets.html", - "intl/zh-cn/distribute/tools/launch-checklist.html", - "intl/zh-cn/tools/publishing/publishing_overview.html", - "intl/zh-cn/distribute/tools/localization-checklist.html" + "distribute/essentials/quality/core.html", + "distribute/essentials/quality/tablets.html", + "distribute/tools/launch-checklist.html", + "tools/publishing/publishing_overview.html", + "distribute/tools/localization-checklist.html" ] }, "overview/zhcn/2": { "title": "", "resources": [ - "intl/zh-cn/google/play/billing/index.html", - "intl/zh-cn/google/play/billing/api.html", - "intl/zh-cn/google/play/billing/billing_admin.html", - "intl/zh-cn/google/play/billing/billing_testing.html", - "intl/zh-cn/google/play/billing/billing_best_practices.html" + "google/play/billing/index.html", + "google/play/billing/api.html", + "google/play/billing/billing_admin.html", + "google/play/billing/billing_testing.html", + "google/play/billing/billing_best_practices.html" ] }, "overview/zhcn/3": { "title": "", "resources": [ "https://play.google.com/intl/en_us/badges/", - "intl/zh-cn/distribute/tools/promote/device-art.html", - "intl/zh-cn/distribute/tools/promote/linking.html", - "intl/zh-cn/distribute/tools/promote/brand.html", - "intl/zh-cn/tools/help/proguard.html" + "distribute/tools/promote/device-art.html", + "distribute/tools/promote/linking.html", + "distribute/tools/promote/brand.html", + "tools/help/proguard.html" ] }, "overview/zhcn/4": { "title": "", "resources": [ - "intl/zh-cn/design/style/writing.html", - "intl/zh-cn/training/basics/fragments/fragment-ui.html", - "intl/zh-cn/training/multiscreen/index.html", - "intl/zh-cn/training/monitoring-device-state/index.html" + "design/style/writing.html", + "training/basics/fragments/fragment-ui.html", + "training/multiscreen/index.html", + "training/monitoring-device-state/index.html" ] }, "overview/carousel/zhcn": { diff --git a/packages/ExternalStorageProvider/src/com/android/externalstorage/ExternalStorageProvider.java b/packages/ExternalStorageProvider/src/com/android/externalstorage/ExternalStorageProvider.java index 33d6b9a33ef8..3b575a8a03a6 100644 --- a/packages/ExternalStorageProvider/src/com/android/externalstorage/ExternalStorageProvider.java +++ b/packages/ExternalStorageProvider/src/com/android/externalstorage/ExternalStorageProvider.java @@ -41,6 +41,7 @@ import android.os.storage.VolumeInfo; import android.provider.DocumentsContract; import android.provider.DocumentsContract.Document; import android.provider.DocumentsContract.Root; +import android.provider.DocumentsContract.Path; import android.provider.DocumentsProvider; import android.provider.MediaStore; import android.provider.Settings; @@ -48,6 +49,7 @@ import android.text.TextUtils; import android.util.ArrayMap; import android.util.DebugUtils; import android.util.Log; +import android.util.Pair; import android.webkit.MimeTypeMap; import com.android.internal.annotations.GuardedBy; @@ -183,7 +185,8 @@ public class ExternalStorageProvider extends DocumentsProvider { root.rootId = rootId; root.volumeId = volume.id; root.flags = Root.FLAG_LOCAL_ONLY - | Root.FLAG_SUPPORTS_SEARCH | Root.FLAG_SUPPORTS_IS_CHILD; + | Root.FLAG_SUPPORTS_SEARCH + | Root.FLAG_SUPPORTS_IS_CHILD; final DiskInfo disk = volume.getDisk(); if (DEBUG) Log.d(TAG, "Disk for root " + rootId + " is " + disk); @@ -270,7 +273,6 @@ public class ExternalStorageProvider extends DocumentsProvider { return projection != null ? projection : DEFAULT_DOCUMENT_PROJECTION; } - private String getDocIdForFile(File file) throws FileNotFoundException { return getDocIdForFileMaybeCreate(file, false); } @@ -323,6 +325,11 @@ public class ExternalStorageProvider extends DocumentsProvider { } private File getFileForDocId(String docId, boolean visible) throws FileNotFoundException { + return resolveDocId(docId, visible).second; + } + + private Pair<RootInfo, File> resolveDocId(String docId, boolean visible) + throws FileNotFoundException { final int splitIndex = docId.indexOf(':', 1); final String tag = docId.substring(0, splitIndex); final String path = docId.substring(splitIndex + 1); @@ -346,7 +353,7 @@ public class ExternalStorageProvider extends DocumentsProvider { if (!target.exists()) { throw new FileNotFoundException("Missing file for " + docId + " at " + target); } - return target; + return Pair.create(root, target); } private void includeFile(MatrixCursor result, String docId, File file) @@ -423,6 +430,28 @@ public class ExternalStorageProvider extends DocumentsProvider { } @Override + public Path findPath(String documentId) + throws FileNotFoundException { + LinkedList<String> path = new LinkedList<>(); + + final Pair<RootInfo, File> resolvedDocId = resolveDocId(documentId, false); + RootInfo root = resolvedDocId.first; + File file = resolvedDocId.second; + + if (!file.exists()) { + throw new FileNotFoundException(); + } + + while (file != null && file.getAbsolutePath().startsWith(root.path.getAbsolutePath())) { + path.addFirst(getDocIdForFile(file)); + + file = file.getParentFile(); + } + + return new Path(root.rootId, path); + } + + @Override public String createDocument(String docId, String mimeType, String displayName) throws FileNotFoundException { displayName = FileUtils.buildValidFatFilename(displayName); diff --git a/packages/PrintSpooler/tests/Android.mk b/packages/PrintSpooler/tests/Android.mk new file mode 100644 index 000000000000..83e00ce089d2 --- /dev/null +++ b/packages/PrintSpooler/tests/Android.mk @@ -0,0 +1,19 @@ +# 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) + +include $(CLEAR_VARS) + +include $(call all-makefiles-under, $(LOCAL_PATH)) diff --git a/packages/PrintSpooler/tests/outofprocess/Android.mk b/packages/PrintSpooler/tests/outofprocess/Android.mk new file mode 100644 index 000000000000..d1d0ee40ba01 --- /dev/null +++ b/packages/PrintSpooler/tests/outofprocess/Android.mk @@ -0,0 +1,28 @@ +# 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) + +include $(CLEAR_VARS) + +LOCAL_MODULE_TAGS := tests + +LOCAL_SRC_FILES := $(call all-java-files-under, src) + +LOCAL_JAVA_LIBRARIES := android.test.runner +LOCAL_STATIC_JAVA_LIBRARIES := android-support-test ub-uiautomator mockito-target-minus-junit4 + +LOCAL_PACKAGE_NAME := PrintSpoolerOutOfProcessTests + +include $(BUILD_PACKAGE) diff --git a/packages/PrintSpooler/tests/outofprocess/AndroidManifest.xml b/packages/PrintSpooler/tests/outofprocess/AndroidManifest.xml new file mode 100644 index 000000000000..4a05f6f52a9a --- /dev/null +++ b/packages/PrintSpooler/tests/outofprocess/AndroidManifest.xml @@ -0,0 +1,58 @@ +<?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="com.android.printspooler.outofprocess.tests"> + + <application> + <uses-library android:name="android.test.runner" /> + + <activity android:name=".PrintTestActivity"/> + + <service + android:name=".mockservice.MockPrintService" + android:permission="android.permission.BIND_PRINT_SERVICE"> + + <intent-filter> + <action android:name="android.printservice.PrintService" /> + </intent-filter> + <meta-data + android:name="android.printservice" + android:resource="@xml/printservice"> + </meta-data> + </service> + + <activity + android:name=".mockservice.SettingsActivity" + android:permission="android.permission.START_PRINT_SERVICE_CONFIG_ACTIVITY" + android:exported="true"> + </activity> + + <activity + android:name=".mockservice.AddPrintersActivity" + android:exported="true"> + </activity> + + </application> + + <!-- This runs in its own process, hence it instruments itself --> + <instrumentation android:name="android.support.test.runner.AndroidJUnitRunner" + android:targetPackage="com.android.printspooler.outofprocess.tests" + android:label="PrintSpooler Out of Process Test Cases"> + </instrumentation> + +</manifest> diff --git a/packages/PrintSpooler/tests/outofprocess/res/xml/printservice.xml b/packages/PrintSpooler/tests/outofprocess/res/xml/printservice.xml new file mode 100644 index 000000000000..9eecf4562bb4 --- /dev/null +++ b/packages/PrintSpooler/tests/outofprocess/res/xml/printservice.xml @@ -0,0 +1,20 @@ +<?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. + --> + +<print-service xmlns:android="http://schemas.android.com/apk/res/android" + android:addPrintersActivity="com.android.printspooler.outofprocess.tests.mockservice.AddPrintersActivity" /> diff --git a/packages/PrintSpooler/tests/outofprocess/src/com/android/printspooler/outofprocess/tests/BasePrintTest.java b/packages/PrintSpooler/tests/outofprocess/src/com/android/printspooler/outofprocess/tests/BasePrintTest.java new file mode 100644 index 000000000000..4de35701ea80 --- /dev/null +++ b/packages/PrintSpooler/tests/outofprocess/src/com/android/printspooler/outofprocess/tests/BasePrintTest.java @@ -0,0 +1,211 @@ +/* + * 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.printspooler.outofprocess.tests; + +import android.annotation.NonNull; +import android.app.Instrumentation; +import android.content.Context; +import android.content.pm.PackageManager; +import android.os.CancellationSignal; +import android.os.ParcelFileDescriptor; +import android.print.PrintAttributes; +import android.print.PrintDocumentAdapter; +import android.print.PrintManager; +import android.print.PrinterId; +import com.android.printspooler.outofprocess.tests.mockservice.PrintServiceCallbacks; +import com.android.printspooler.outofprocess.tests.mockservice.PrinterDiscoverySessionCallbacks; +import com.android.printspooler.outofprocess.tests.mockservice.StubbablePrinterDiscoverySession; +import android.printservice.CustomPrinterIconCallback; +import android.printservice.PrintJob; +import android.printservice.PrintService; +import android.support.test.InstrumentationRegistry; +import android.support.test.rule.ActivityTestRule; +import android.support.test.uiautomator.UiDevice; +import org.junit.After; +import org.junit.BeforeClass; +import org.junit.Rule; +import org.mockito.stubbing.Answer; + +import java.io.FileInputStream; +import java.io.IOException; +import java.util.List; + +import static org.junit.Assert.assertTrue; +import static org.junit.Assume.assumeTrue; +import static org.mockito.Matchers.any; +import static org.mockito.Mockito.doAnswer; +import static org.mockito.Mockito.doCallRealMethod; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +/** + * This is the base class for print tests. + */ +abstract class BasePrintTest { + protected static final long OPERATION_TIMEOUT = 30000; + private static final String PM_CLEAR_SUCCESS_OUTPUT = "Success"; + private static final int CURRENT_USER_ID = -2; // Mirrors UserHandle.USER_CURRENT + + private android.print.PrintJob mPrintJob; + + private static Instrumentation sInstrumentation; + private static UiDevice sUiDevice; + + @Rule + public ActivityTestRule<PrintTestActivity> mActivityRule = + new ActivityTestRule<>(PrintTestActivity.class, false, true); + + /** + * Return the UI device + * + * @return the UI device + */ + public UiDevice getUiDevice() { + return sUiDevice; + } + + protected static Instrumentation getInstrumentation() { + return sInstrumentation; + } + + @BeforeClass + public static void setUpClass() throws Exception { + sInstrumentation = InstrumentationRegistry.getInstrumentation(); + assumeTrue(sInstrumentation.getContext().getPackageManager().hasSystemFeature( + PackageManager.FEATURE_PRINTING)); + + sUiDevice = UiDevice.getInstance(sInstrumentation); + + // Make sure we start with a clean slate. + clearPrintSpoolerData(); + + // 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()); + } + + @After + public void exitActivities() throws Exception { + // 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(() -> { + PrintManager printManager = (PrintManager) getActivity() + .getSystemService(Context.PRINT_SERVICE); + mPrintJob = printManager.print("Print job", adapter, attributes); + }); + + return mPrintJob; + } + + protected PrintTestActivity getActivity() { + return mActivityRule.getActivity(); + } + + public static String runShellCommand(Instrumentation instrumentation, String cmd) + throws IOException { + ParcelFileDescriptor pfd = instrumentation.getUiAutomation().executeShellCommand(cmd); + byte[] buf = new byte[512]; + int bytesRead; + FileInputStream fis = new ParcelFileDescriptor.AutoCloseInputStream(pfd); + StringBuilder stdout = new StringBuilder(); + while ((bytesRead = fis.read(buf)) != -1) { + stdout.append(new String(buf, 0, bytesRead)); + } + fis.close(); + return stdout.toString(); + } + + 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, + PrintManager.PRINT_SPOOLER_PACKAGE_NAME)) + .contains(PM_CLEAR_SUCCESS_OUTPUT)); + } + + @SuppressWarnings("unchecked") + protected PrinterDiscoverySessionCallbacks createMockPrinterDiscoverySessionCallbacks( + Answer<Void> onStartPrinterDiscovery, Answer<Void> onStopPrinterDiscovery, + Answer<Void> onValidatePrinters, Answer<Void> onStartPrinterStateTracking, + Answer<Void> onRequestCustomPrinterIcon, Answer<Void> onStopPrinterStateTracking, + Answer<Void> onDestroy) { + PrinterDiscoverySessionCallbacks callbacks = mock(PrinterDiscoverySessionCallbacks.class); + + doCallRealMethod().when(callbacks).setSession(any(StubbablePrinterDiscoverySession.class)); + when(callbacks.getSession()).thenCallRealMethod(); + + if (onStartPrinterDiscovery != null) { + doAnswer(onStartPrinterDiscovery).when(callbacks).onStartPrinterDiscovery( + any(List.class)); + } + if (onStopPrinterDiscovery != null) { + doAnswer(onStopPrinterDiscovery).when(callbacks).onStopPrinterDiscovery(); + } + if (onValidatePrinters != null) { + doAnswer(onValidatePrinters).when(callbacks).onValidatePrinters( + any(List.class)); + } + if (onStartPrinterStateTracking != null) { + doAnswer(onStartPrinterStateTracking).when(callbacks).onStartPrinterStateTracking( + any(PrinterId.class)); + } + if (onRequestCustomPrinterIcon != null) { + doAnswer(onRequestCustomPrinterIcon).when(callbacks).onRequestCustomPrinterIcon( + any(PrinterId.class), any(CancellationSignal.class), + any(CustomPrinterIconCallback.class)); + } + if (onStopPrinterStateTracking != null) { + doAnswer(onStopPrinterStateTracking).when(callbacks).onStopPrinterStateTracking( + any(PrinterId.class)); + } + if (onDestroy != null) { + doAnswer(onDestroy).when(callbacks).onDestroy(); + } + + return callbacks; + } + + protected PrintServiceCallbacks createMockPrintServiceCallbacks( + Answer<PrinterDiscoverySessionCallbacks> onCreatePrinterDiscoverySessionCallbacks, + Answer<Void> onPrintJobQueued, Answer<Void> onRequestCancelPrintJob) { + final PrintServiceCallbacks service = mock(PrintServiceCallbacks.class); + + doCallRealMethod().when(service).setService(any(PrintService.class)); + when(service.getService()).thenCallRealMethod(); + + if (onCreatePrinterDiscoverySessionCallbacks != null) { + doAnswer(onCreatePrinterDiscoverySessionCallbacks).when(service) + .onCreatePrinterDiscoverySessionCallbacks(); + } + if (onPrintJobQueued != null) { + doAnswer(onPrintJobQueued).when(service).onPrintJobQueued(any(PrintJob.class)); + } + if (onRequestCancelPrintJob != null) { + doAnswer(onRequestCancelPrintJob).when(service).onRequestCancelPrintJob( + any(PrintJob.class)); + } + + return service; + } +} diff --git a/packages/PrintSpooler/tests/outofprocess/src/com/android/printspooler/outofprocess/tests/PrintTestActivity.java b/packages/PrintSpooler/tests/outofprocess/src/com/android/printspooler/outofprocess/tests/PrintTestActivity.java new file mode 100644 index 000000000000..4905a0b5b5fa --- /dev/null +++ b/packages/PrintSpooler/tests/outofprocess/src/com/android/printspooler/outofprocess/tests/PrintTestActivity.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.printspooler.outofprocess.tests; + +import android.app.Activity; +import android.os.Bundle; +import android.view.WindowManager; + +public class PrintTestActivity extends Activity { + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON + | WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON + | WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD); + } +} diff --git a/core/tests/coretests/src/android/print/WorkflowTest.java b/packages/PrintSpooler/tests/outofprocess/src/com/android/printspooler/outofprocess/tests/WorkflowTest.java index 62d8b97702db..184e55962766 100644 --- a/core/tests/coretests/src/android/print/WorkflowTest.java +++ b/packages/PrintSpooler/tests/outofprocess/src/com/android/printspooler/outofprocess/tests/WorkflowTest.java @@ -14,17 +14,23 @@ * limitations under the License. */ -package android.print; +package com.android.printspooler.outofprocess.tests; import android.graphics.pdf.PdfDocument; import android.os.Bundle; import android.os.CancellationSignal; import android.os.ParcelFileDescriptor; -import android.print.mockservice.AddPrintersActivity; -import android.print.mockservice.MockPrintService; - -import android.print.mockservice.PrinterDiscoverySessionCallbacks; -import android.print.mockservice.StubbablePrinterDiscoverySession; +import android.print.PageRange; +import android.print.PrintAttributes; +import android.print.PrintDocumentAdapter; +import android.print.PrintDocumentInfo; +import android.print.PrinterCapabilitiesInfo; +import android.print.PrinterId; +import android.print.PrinterInfo; +import com.android.printspooler.outofprocess.tests.mockservice.AddPrintersActivity; +import com.android.printspooler.outofprocess.tests.mockservice.MockPrintService; +import com.android.printspooler.outofprocess.tests.mockservice.PrinterDiscoverySessionCallbacks; +import com.android.printspooler.outofprocess.tests.mockservice.StubbablePrinterDiscoverySession; import android.print.pdf.PrintedPdfDocument; import android.support.test.filters.LargeTest; import android.support.test.uiautomator.By; diff --git a/core/tests/coretests/src/android/print/mockservice/AddPrintersActivity.java b/packages/PrintSpooler/tests/outofprocess/src/com/android/printspooler/outofprocess/tests/mockservice/AddPrintersActivity.java index 8f1a9edeacba..2ea4e7dcdbe2 100644 --- a/core/tests/coretests/src/android/print/mockservice/AddPrintersActivity.java +++ b/packages/PrintSpooler/tests/outofprocess/src/com/android/printspooler/outofprocess/tests/mockservice/AddPrintersActivity.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package android.print.mockservice; +package com.android.printspooler.outofprocess.tests.mockservice; import android.app.Activity; import android.os.Bundle; diff --git a/packages/PrintSpooler/tests/outofprocess/src/com/android/printspooler/outofprocess/tests/mockservice/MockPrintService.java b/packages/PrintSpooler/tests/outofprocess/src/com/android/printspooler/outofprocess/tests/mockservice/MockPrintService.java new file mode 100644 index 000000000000..3a231130c5c4 --- /dev/null +++ b/packages/PrintSpooler/tests/outofprocess/src/com/android/printspooler/outofprocess/tests/mockservice/MockPrintService.java @@ -0,0 +1,40 @@ +/* + * 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.printspooler.outofprocess.tests.mockservice; + +public class MockPrintService extends StubbablePrintService { + + private static final Object sLock = new Object(); + + private static PrintServiceCallbacks sCallbacks; + + public static void setCallbacks(PrintServiceCallbacks callbacks) { + synchronized (sLock) { + sCallbacks = callbacks; + } + } + + @Override + protected PrintServiceCallbacks getCallbacks() { + synchronized (sLock) { + if (sCallbacks != null) { + sCallbacks.setService(this); + } + return sCallbacks; + } + } +} diff --git a/packages/PrintSpooler/tests/outofprocess/src/com/android/printspooler/outofprocess/tests/mockservice/PrintServiceCallbacks.java b/packages/PrintSpooler/tests/outofprocess/src/com/android/printspooler/outofprocess/tests/mockservice/PrintServiceCallbacks.java new file mode 100644 index 000000000000..07baa0fe1191 --- /dev/null +++ b/packages/PrintSpooler/tests/outofprocess/src/com/android/printspooler/outofprocess/tests/mockservice/PrintServiceCallbacks.java @@ -0,0 +1,39 @@ +/* + * 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.printspooler.outofprocess.tests.mockservice; + +import android.printservice.PrintJob; +import android.printservice.PrintService; + +public abstract class PrintServiceCallbacks { + + private PrintService mService; + + public PrintService getService() { + return mService; + } + + public void setService(PrintService service) { + mService = service; + } + + public abstract PrinterDiscoverySessionCallbacks onCreatePrinterDiscoverySessionCallbacks(); + + public abstract void onRequestCancelPrintJob(PrintJob printJob); + + public abstract void onPrintJobQueued(PrintJob printJob); +} diff --git a/packages/PrintSpooler/tests/outofprocess/src/com/android/printspooler/outofprocess/tests/mockservice/PrinterDiscoverySessionCallbacks.java b/packages/PrintSpooler/tests/outofprocess/src/com/android/printspooler/outofprocess/tests/mockservice/PrinterDiscoverySessionCallbacks.java new file mode 100644 index 000000000000..5c1260c37dc4 --- /dev/null +++ b/packages/PrintSpooler/tests/outofprocess/src/com/android/printspooler/outofprocess/tests/mockservice/PrinterDiscoverySessionCallbacks.java @@ -0,0 +1,51 @@ +/* + * 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.printspooler.outofprocess.tests.mockservice; + +import android.os.CancellationSignal; +import android.print.PrinterId; +import android.printservice.CustomPrinterIconCallback; + +import java.util.List; + +public abstract class PrinterDiscoverySessionCallbacks { + + private StubbablePrinterDiscoverySession mSession; + + public void setSession(StubbablePrinterDiscoverySession session) { + mSession = session; + } + + public StubbablePrinterDiscoverySession getSession() { + return mSession; + } + + public abstract void onStartPrinterDiscovery(List<PrinterId> priorityList); + + public abstract void onStopPrinterDiscovery(); + + public abstract void onValidatePrinters(List<PrinterId> printerIds); + + public abstract void onStartPrinterStateTracking(PrinterId printerId); + + public abstract void onRequestCustomPrinterIcon(PrinterId printerId, + CancellationSignal cancellationSignal, CustomPrinterIconCallback callback); + + public abstract void onStopPrinterStateTracking(PrinterId printerId); + + public abstract void onDestroy(); +} diff --git a/packages/PrintSpooler/tests/outofprocess/src/com/android/printspooler/outofprocess/tests/mockservice/StubbablePrintService.java b/packages/PrintSpooler/tests/outofprocess/src/com/android/printspooler/outofprocess/tests/mockservice/StubbablePrintService.java new file mode 100644 index 000000000000..be9d19b4d634 --- /dev/null +++ b/packages/PrintSpooler/tests/outofprocess/src/com/android/printspooler/outofprocess/tests/mockservice/StubbablePrintService.java @@ -0,0 +1,52 @@ +/* + * 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.printspooler.outofprocess.tests.mockservice; + +import android.printservice.PrintJob; +import android.printservice.PrintService; +import android.printservice.PrinterDiscoverySession; + +public abstract class StubbablePrintService extends PrintService { + + @Override + public PrinterDiscoverySession onCreatePrinterDiscoverySession() { + PrintServiceCallbacks callbacks = getCallbacks(); + if (callbacks != null) { + return new StubbablePrinterDiscoverySession(this, + getCallbacks().onCreatePrinterDiscoverySessionCallbacks()); + } + return null; + } + + @Override + public void onRequestCancelPrintJob(PrintJob printJob) { + PrintServiceCallbacks callbacks = getCallbacks(); + if (callbacks != null) { + callbacks.onRequestCancelPrintJob(printJob); + } + } + + @Override + public void onPrintJobQueued(PrintJob printJob) { + PrintServiceCallbacks callbacks = getCallbacks(); + if (callbacks != null) { + callbacks.onPrintJobQueued(printJob); + } + } + + protected abstract PrintServiceCallbacks getCallbacks(); +} diff --git a/packages/PrintSpooler/tests/outofprocess/src/com/android/printspooler/outofprocess/tests/mockservice/StubbablePrinterDiscoverySession.java b/packages/PrintSpooler/tests/outofprocess/src/com/android/printspooler/outofprocess/tests/mockservice/StubbablePrinterDiscoverySession.java new file mode 100644 index 000000000000..a828cd6b39db --- /dev/null +++ b/packages/PrintSpooler/tests/outofprocess/src/com/android/printspooler/outofprocess/tests/mockservice/StubbablePrinterDiscoverySession.java @@ -0,0 +1,95 @@ +/* + * 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.printspooler.outofprocess.tests.mockservice; + +import android.os.CancellationSignal; +import android.print.PrinterId; +import android.printservice.CustomPrinterIconCallback; +import android.printservice.PrintService; +import android.printservice.PrinterDiscoverySession; +import android.support.annotation.NonNull; + +import java.util.List; + +public class StubbablePrinterDiscoverySession extends PrinterDiscoverySession { + private final PrintService mService; + private final PrinterDiscoverySessionCallbacks mCallbacks; + + public StubbablePrinterDiscoverySession(PrintService service, + PrinterDiscoverySessionCallbacks callbacks) { + mService = service; + mCallbacks = callbacks; + if (mCallbacks != null) { + mCallbacks.setSession(this); + } + } + + public PrintService getService() { + return mService; + } + + @Override + public void onStartPrinterDiscovery(@NonNull List<PrinterId> priorityList) { + if (mCallbacks != null) { + mCallbacks.onStartPrinterDiscovery(priorityList); + } + } + + @Override + public void onStopPrinterDiscovery() { + if (mCallbacks != null) { + mCallbacks.onStopPrinterDiscovery(); + } + } + + @Override + public void onValidatePrinters(@NonNull List<PrinterId> printerIds) { + if (mCallbacks != null) { + mCallbacks.onValidatePrinters(printerIds); + } + } + + @Override + public void onStartPrinterStateTracking(@NonNull PrinterId printerId) { + if (mCallbacks != null) { + mCallbacks.onStartPrinterStateTracking(printerId); + } + } + + @Override + public void onRequestCustomPrinterIcon(@NonNull PrinterId printerId, + @NonNull CancellationSignal cancellationSignal, + @NonNull CustomPrinterIconCallback callback) { + if (mCallbacks != null) { + mCallbacks.onRequestCustomPrinterIcon(printerId, cancellationSignal, callback); + } + } + + @Override + public void onStopPrinterStateTracking(@NonNull PrinterId printerId) { + if (mCallbacks != null) { + mCallbacks.onStopPrinterStateTracking(printerId); + } + } + + @Override + public void onDestroy() { + if (mCallbacks != null) { + mCallbacks.onDestroy(); + } + } +} diff --git a/packages/SystemUI/res/values-cs/strings.xml b/packages/SystemUI/res/values-cs/strings.xml index 4a515a67b078..01f4d9ecf50f 100644 --- a/packages/SystemUI/res/values-cs/strings.xml +++ b/packages/SystemUI/res/values-cs/strings.xml @@ -241,7 +241,7 @@ <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="1841738975235283398">"Bylo dosaženo limitu dat. Používání mobilních dat bylo vypnuto.\n\nPokud jej obnovíte, mohou vám být účtovány poplatky za využití dat."</string> + <string name="data_usage_disabled_dialog" msgid="1841738975235283398">"Byl dosažen limit dat. Používání mobilních dat bylo vypnuto.\n\nPokud jej obnovíte, mohou vám být účtovány poplatky za využití dat."</string> <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-km-rKH/strings.xml b/packages/SystemUI/res/values-km-rKH/strings.xml index ee636813617d..23db2d016942 100644 --- a/packages/SystemUI/res/values-km-rKH/strings.xml +++ b/packages/SystemUI/res/values-km-rKH/strings.xml @@ -237,7 +237,7 @@ <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="1841738975235283398">"បានឈានដល់កម្រិតទិន្នន័យដែលអ្នកបានកំណត់ហើយ។ អ្នកមិនអាចប្រើទិន្នន័យចល័តបានទៀតទេ។\n\nអាចនឹងគិតថ្លៃលើការប្រើទិន្នន័យ ប្រសិនបើអ្នកបន្តប្រើ។"</string> + <string name="data_usage_disabled_dialog" msgid="1841738975235283398">"បានឈានដល់កម្រិតទិន្នន័យដែលអ្នកបានកំណត់ហើយ។ ឥឡូវអ្នកមិនប្រើទិន្នន័យចល័តទៀតទេ។\n\nអាចនឹងគិតថ្លៃលើការប្រើទិន្នន័យ ប្រសិនបើអ្នកបន្តប្រើឡើងវិញ។"</string> <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-ky-rKG/strings.xml b/packages/SystemUI/res/values-ky-rKG/strings.xml index 62775d1be563..91ebf7c90e77 100644 --- a/packages/SystemUI/res/values-ky-rKG/strings.xml +++ b/packages/SystemUI/res/values-ky-rKG/strings.xml @@ -237,7 +237,7 @@ <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="1841738975235283398">"Сиз койгон дайындардын чегине жетти. Сиз мобилдик дайындарды колдонгон жоксуз.\n\nЭгер улантсаңыз, мобилдик дайындарды колдонгонуңуз үчүн акы алынышы мүмкүн."</string> + <string name="data_usage_disabled_dialog" msgid="1841738975235283398">"Трафик сиз койгон чекке жетти. Эми мобилдик дайындарды колдоно албайсыз.\n\nЭгер улантсаңыз, мобилдик дайындарды колдонгонуңуз үчүн акы алынышы мүмкүн."</string> <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 f6e43dd41f68..cc61b6e68247 100644 --- a/packages/SystemUI/res/values-sk/strings.xml +++ b/packages/SystemUI/res/values-sk/strings.xml @@ -570,7 +570,7 @@ <string name="keyboard_shortcut_group_applications_browser" msgid="6465985474000766533">"Prehliadač"</string> <string name="keyboard_shortcut_group_applications_contacts" msgid="2064197111278436375">"Kontakty"</string> <string name="keyboard_shortcut_group_applications_email" msgid="6257036897441939004">"E-mail"</string> - <string name="keyboard_shortcut_group_applications_im" msgid="1892749399083161405">"Okamžité správy"</string> + <string name="keyboard_shortcut_group_applications_im" msgid="1892749399083161405">"Čet"</string> <string name="keyboard_shortcut_group_applications_music" msgid="4775559515850922780">"Hudba"</string> <string name="keyboard_shortcut_group_applications_youtube" msgid="6555453761294723317">"YouTube"</string> <string name="keyboard_shortcut_group_applications_calendar" msgid="9043614299194991263">"Kalendár"</string> diff --git a/packages/SystemUI/res/values-th/strings.xml b/packages/SystemUI/res/values-th/strings.xml index 1fbd6f4da947..4f8341fc6f0d 100644 --- a/packages/SystemUI/res/values-th/strings.xml +++ b/packages/SystemUI/res/values-th/strings.xml @@ -237,7 +237,7 @@ <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="1841738975235283398">"คุณใช้อินเทอร์เน็ตเกินปริมาณที่กำหนดไว้แล้ว คุณจะไม่สามารถใช้ข้อมูลเครือข่ายมือถืออีก\n\nหากใช้ต่อ อาจมีค่าบริการสำหรับปริมาณการใช้อินเทอร์เน็ต"</string> + <string name="data_usage_disabled_dialog" msgid="1841738975235283398">"คุณใช้อินเทอร์เน็ตเกินปริมาณที่กำหนดไว้ ระบบจะไม่ใช้เครือข่ายมือถือต่อไป\n\nหากใช้ต่อ อาจมีค่าบริการตามปริมาณการใช้อินเทอร์เน็ต"</string> <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/src/com/android/systemui/statusbar/car/CarNavigationButton.java b/packages/SystemUI/src/com/android/systemui/statusbar/car/CarNavigationButton.java index 59e42443466a..f46fc6769b17 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/car/CarNavigationButton.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/car/CarNavigationButton.java @@ -18,6 +18,7 @@ package com.android.systemui.statusbar.car; import android.content.Context; import android.graphics.drawable.Drawable; import android.util.AttributeSet; +import android.widget.ImageView; import android.widget.RelativeLayout; import com.android.keyguard.AlphaOptimizedImageButton; @@ -41,6 +42,7 @@ public class CarNavigationButton extends RelativeLayout { public void onFinishInflate() { super.onFinishInflate(); mIcon = (AlphaOptimizedImageButton) findViewById(R.id.car_nav_button_icon); + mIcon.setScaleType(ImageView.ScaleType.CENTER); mIcon.setClickable(false); mIcon.setBackgroundColor(android.R.color.transparent); mIcon.setAlpha(UNSELECTED_ALPHA); diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java index c32cac8a1b37..9f2d44793f3f 100644 --- a/services/core/java/com/android/server/am/ActivityManagerService.java +++ b/services/core/java/com/android/server/am/ActivityManagerService.java @@ -1136,6 +1136,20 @@ public final class ActivityManagerService extends ActivityManagerNative */ private Configuration mTempGlobalConfig = new Configuration(); + private final UpdateConfigurationResult mTmpUpdateConfigurationResult = + new UpdateConfigurationResult(); + private static final class UpdateConfigurationResult { + // Configuration changes that were updated. + int changes; + // If the activity was relaunched to match the new configuration. + boolean activityRelaunched; + + void reset() { + changes = 0; + activityRelaunched = false; + } + } + boolean mSuppressResizeConfigChanges; /** @@ -18872,7 +18886,7 @@ public final class ActivityManagerService extends ActivityManagerNative } @Override - public void updateConfiguration(Configuration values) { + public boolean updateConfiguration(Configuration values) { enforceCallingPermission(android.Manifest.permission.CHANGE_CONFIGURATION, "updateConfiguration()"); @@ -18887,11 +18901,18 @@ public final class ActivityManagerService extends ActivityManagerNative } final long origId = Binder.clearCallingIdentity(); - if (values != null) { - Settings.System.clearConfiguration(values); + + try { + if (values != null) { + Settings.System.clearConfiguration(values); + } + updateConfigurationLocked(values, null, false, false /* persistent */, + UserHandle.USER_NULL, false /* deferResume */, + mTmpUpdateConfigurationResult); + return mTmpUpdateConfigurationResult.changes != 0; + } finally { + Binder.restoreCallingIdentity(origId); } - updateConfigurationLocked(values, null, false); - Binder.restoreCallingIdentity(origId); } } @@ -18919,6 +18940,12 @@ public final class ActivityManagerService extends ActivityManagerNative // To cache the list of supported system locales private String[] mSupportedSystemLocales = null; + private boolean updateConfigurationLocked(Configuration values, ActivityRecord starting, + boolean initLocale, boolean persistent, int userId, boolean deferResume) { + return updateConfigurationLocked(values, starting, initLocale, persistent, userId, + deferResume, null /* result */); + } + /** * Do either or both things: (1) change the current configuration, and (2) * make sure the given activity is running with the (now) current @@ -18930,7 +18957,8 @@ public final class ActivityManagerService extends ActivityManagerNative * for that particular user */ private boolean updateConfigurationLocked(Configuration values, ActivityRecord starting, - boolean initLocale, boolean persistent, int userId, boolean deferResume) { + boolean initLocale, boolean persistent, int userId, boolean deferResume, + UpdateConfigurationResult result) { int changes = 0; boolean kept = true; @@ -18949,6 +18977,11 @@ public final class ActivityManagerService extends ActivityManagerNative mWindowManager.continueSurfaceLayout(); } } + + if (result != null) { + result.changes = changes; + result.activityRelaunched = !kept; + } return kept; } diff --git a/services/core/java/com/android/server/pm/DefaultPermissionGrantPolicy.java b/services/core/java/com/android/server/pm/DefaultPermissionGrantPolicy.java index ded85f3da3d6..00e45fd9b0bc 100644 --- a/services/core/java/com/android/server/pm/DefaultPermissionGrantPolicy.java +++ b/services/core/java/com/android/server/pm/DefaultPermissionGrantPolicy.java @@ -150,6 +150,8 @@ final class DefaultPermissionGrantPolicy { private static final int MSG_READ_DEFAULT_PERMISSION_EXCEPTIONS = 1; + private static final String ACTION_TRACK = "com.android.fitness.TRACK"; + private final PackageManagerService mService; private final Handler mHandler; @@ -603,8 +605,9 @@ final class DefaultPermissionGrantPolicy { grantRuntimePermissionsLPw(musicPackage, STORAGE_PERMISSIONS, userId); } - // Android Wear Home + // Watches if (mService.hasSystemFeature(PackageManager.FEATURE_WATCH, 0)) { + // Home application on watches Intent homeIntent = new Intent(Intent.ACTION_MAIN); homeIntent.addCategory(Intent.CATEGORY_HOME_MAIN); @@ -621,6 +624,16 @@ final class DefaultPermissionGrantPolicy { grantRuntimePermissionsLPw(wearHomePackage, LOCATION_PERMISSIONS, false, userId); } + + // Fitness tracking on watches + Intent trackIntent = new Intent(ACTION_TRACK); + PackageParser.Package trackPackage = getDefaultSystemHandlerActivityPackageLPr( + trackIntent, userId); + if (trackPackage != null + && doesPackageSupportRuntimePermissions(trackPackage)) { + grantRuntimePermissionsLPw(trackPackage, SENSORS_PERMISSIONS, false, userId); + grantRuntimePermissionsLPw(trackPackage, LOCATION_PERMISSIONS, false, userId); + } } // Print Spooler diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java index 5970998247c1..33155cec6724 100644 --- a/services/core/java/com/android/server/wm/WindowManagerService.java +++ b/services/core/java/com/android/server/wm/WindowManagerService.java @@ -213,7 +213,6 @@ import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ADD_REMOVE; import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ANIM; import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_APP_TRANSITIONS; import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_BOOT; -import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_CONFIGURATION; import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_DRAG; import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_FOCUS; import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_FOCUS_LIGHT; @@ -222,12 +221,10 @@ import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_KEYGUARD; import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_KEEP_SCREEN_ON; import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_LAYOUT; import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ORIENTATION; -import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_RESIZE; import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_SCREENSHOT; import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_SCREEN_ON; import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_STACK; import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_STARTING_WINDOW; -import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_SURFACE_TRACE; import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_TASK_POSITIONING; import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_TOKEN_MOVEMENT; import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_VISIBILITY; @@ -5441,25 +5438,30 @@ public class WindowManagerService extends IWindowManager.Stub } } - public void updateRotationUnchecked(boolean alwaysSendConfiguration, boolean forceRelayout) { - if(DEBUG_ORIENTATION) Slog.v(TAG_WM, "updateRotationUnchecked(" - + "alwaysSendConfiguration=" + alwaysSendConfiguration + ")"); + private void updateRotationUnchecked(boolean alwaysSendConfiguration, + boolean forceRelayout) { + if(DEBUG_ORIENTATION) Slog.v(TAG_WM, "updateRotationUnchecked:" + + " alwaysSendConfiguration=" + alwaysSendConfiguration + + " forceRelayout=" + forceRelayout); long origId = Binder.clearCallingIdentity(); - boolean changed; - synchronized(mWindowMap) { - changed = updateRotationUncheckedLocked(false); - if (!changed || forceRelayout) { - getDefaultDisplayContentLocked().setLayoutNeeded(); - mWindowPlacerLocked.performSurfacePlacement(); + + try { + final boolean rotationChanged; + synchronized (mWindowMap) { + rotationChanged = updateRotationUncheckedLocked(false); + if (!rotationChanged || forceRelayout) { + getDefaultDisplayContentLocked().setLayoutNeeded(); + mWindowPlacerLocked.performSurfacePlacement(); + } } - } - if (changed || alwaysSendConfiguration) { - sendNewConfiguration(); + if (rotationChanged || alwaysSendConfiguration) { + sendNewConfiguration(); + } + } finally { + Binder.restoreCallingIdentity(origId); } - - Binder.restoreCallingIdentity(origId); } @@ -5470,7 +5472,7 @@ public class WindowManagerService extends IWindowManager.Stub * Returns true if the rotation has been changed. In this case YOU * MUST CALL sendNewConfiguration() TO UNFREEZE THE SCREEN. */ - public boolean updateRotationUncheckedLocked(boolean inTransaction) { + boolean updateRotationUncheckedLocked(boolean inTransaction) { if (mDeferredRotationPauseCount > 0) { // Rotation updates have been paused temporarily. Defer the update until // updates have been resumed. @@ -6121,10 +6123,25 @@ public class WindowManagerService extends IWindowManager.Stub /** * Instruct the Activity Manager to fetch new configurations, update global configuration * and broadcast changes to config-changed listeners if appropriate. + * NOTE: Can't be called with the window manager lock held since it call into activity manager. */ void sendNewConfiguration() { try { - mActivityManager.updateConfiguration(null); + final boolean configUpdated = mActivityManager.updateConfiguration(null); + if (!configUpdated) { + // Something changed (E.g. device rotation), but no configuration update is needed. + // E.g. changing device rotation by 180 degrees. Go ahead and perform surface + // placement to unfreeze the display since we froze it when the rotation was updated + // in updateRotationUncheckedLocked. + synchronized (mWindowMap) { + if (mWaitingForConfig) { + mWaitingForConfig = false; + mLastFinishedFreezeSource = "config-unchanged"; + getDefaultDisplayContentLocked().setLayoutNeeded(); + mWindowPlacerLocked.performSurfacePlacement(); + } + } + } } catch (RemoteException e) { } } diff --git a/wifi/java/android/net/wifi/nan/IWifiNanManager.aidl b/wifi/java/android/net/wifi/nan/IWifiNanManager.aidl index 56baba9141aa..548582433e47 100644 --- a/wifi/java/android/net/wifi/nan/IWifiNanManager.aidl +++ b/wifi/java/android/net/wifi/nan/IWifiNanManager.aidl @@ -23,6 +23,7 @@ import android.net.wifi.nan.IWifiNanDiscoverySessionCallback; import android.net.wifi.nan.IWifiNanEventCallback; import android.net.wifi.nan.PublishConfig; import android.net.wifi.nan.SubscribeConfig; +import android.net.wifi.nan.WifiNanCharacteristics; import android.net.wifi.RttManager; /** @@ -36,6 +37,7 @@ interface IWifiNanManager void enableUsage(); void disableUsage(); boolean isUsageEnabled(); + WifiNanCharacteristics getCharacteristics(); // client API void connect(in IBinder binder, in String callingPackage, in IWifiNanEventCallback callback, diff --git a/wifi/java/android/net/wifi/nan/PublishConfig.java b/wifi/java/android/net/wifi/nan/PublishConfig.java index 4b67f9ac0ef9..30c5bc0807bb 100644 --- a/wifi/java/android/net/wifi/nan/PublishConfig.java +++ b/wifi/java/android/net/wifi/nan/PublishConfig.java @@ -182,7 +182,7 @@ public final class PublishConfig implements Parcelable { * * @hide */ - public void validate() throws IllegalArgumentException { + public void assertValid(WifiNanCharacteristics characteristics) throws IllegalArgumentException { WifiNanUtils.validateServiceName(mServiceName); if (!LvBufferUtils.isValid(mMatchFilter, 1)) { @@ -198,6 +198,26 @@ public final class PublishConfig implements Parcelable { if (mTtlSec < 0) { throw new IllegalArgumentException("Invalid ttlSec - must be non-negative"); } + + if (characteristics != null) { + int maxServiceNameLength = characteristics.getMaxServiceNameLength(); + if (maxServiceNameLength != 0 && mServiceName.length > maxServiceNameLength) { + throw new IllegalArgumentException( + "Service name longer than supported by device characteristics"); + } + int maxServiceSpecificInfoLength = characteristics.getMaxServiceSpecificInfoLength(); + if (maxServiceSpecificInfoLength != 0 && mServiceSpecificInfo != null + && mServiceSpecificInfo.length > maxServiceSpecificInfoLength) { + throw new IllegalArgumentException( + "Service specific info longer than supported by device characteristics"); + } + int maxMatchFilterLength = characteristics.getMaxMatchFilterLength(); + if (maxMatchFilterLength != 0 && mMatchFilter != null + && mMatchFilter.length > maxMatchFilterLength) { + throw new IllegalArgumentException( + "Match filter longer than supported by device characteristics"); + } + } } /** diff --git a/wifi/java/android/net/wifi/nan/SubscribeConfig.java b/wifi/java/android/net/wifi/nan/SubscribeConfig.java index 4352fcf6a3cf..ea7b8e45b817 100644 --- a/wifi/java/android/net/wifi/nan/SubscribeConfig.java +++ b/wifi/java/android/net/wifi/nan/SubscribeConfig.java @@ -209,7 +209,7 @@ public final class SubscribeConfig implements Parcelable { * * @hide */ - public void validate() throws IllegalArgumentException { + public void assertValid(WifiNanCharacteristics characteristics) throws IllegalArgumentException { WifiNanUtils.validateServiceName(mServiceName); if (!LvBufferUtils.isValid(mMatchFilter, 1)) { @@ -229,6 +229,26 @@ public final class SubscribeConfig implements Parcelable { throw new IllegalArgumentException( "Invalid matchType - must be MATCH_FIRST_ONLY or MATCH_ALL"); } + + if (characteristics != null) { + int maxServiceNameLength = characteristics.getMaxServiceNameLength(); + if (maxServiceNameLength != 0 && mServiceName.length > maxServiceNameLength) { + throw new IllegalArgumentException( + "Service name longer than supported by device characteristics"); + } + int maxServiceSpecificInfoLength = characteristics.getMaxServiceSpecificInfoLength(); + if (maxServiceSpecificInfoLength != 0 && mServiceSpecificInfo != null + && mServiceSpecificInfo.length > maxServiceSpecificInfoLength) { + throw new IllegalArgumentException( + "Service specific info longer than supported by device characteristics"); + } + int maxMatchFilterLength = characteristics.getMaxMatchFilterLength(); + if (maxMatchFilterLength != 0 && mMatchFilter != null + && mMatchFilter.length > maxMatchFilterLength) { + throw new IllegalArgumentException( + "Match filter longer than supported by device characteristics"); + } + } } /** diff --git a/core/tests/coretests/src/android/print/mockservice/SettingsActivity.java b/wifi/java/android/net/wifi/nan/WifiNanCharacteristics.aidl index fb76e6780374..e562a0002bb4 100644 --- a/core/tests/coretests/src/android/print/mockservice/SettingsActivity.java +++ b/wifi/java/android/net/wifi/nan/WifiNanCharacteristics.aidl @@ -14,15 +14,6 @@ * limitations under the License. */ -package android.print.mockservice; +package android.net.wifi.nan; -import android.app.Activity; -import android.os.Bundle; - -public class SettingsActivity extends Activity { - - @Override - protected void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - } -} +parcelable WifiNanCharacteristics; diff --git a/wifi/java/android/net/wifi/nan/WifiNanCharacteristics.java b/wifi/java/android/net/wifi/nan/WifiNanCharacteristics.java new file mode 100644 index 000000000000..f43ed4d52742 --- /dev/null +++ b/wifi/java/android/net/wifi/nan/WifiNanCharacteristics.java @@ -0,0 +1,103 @@ +/* + * 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.nan; + +import android.os.Bundle; +import android.os.Parcel; +import android.os.Parcelable; + +/** + * The characteristics of the Wi-Fi NAN implementation. + * + * @hide PROPOSED_NAN_API + */ +public class WifiNanCharacteristics implements Parcelable { + /** @hide */ + public static final String KEY_MAX_SERVICE_NAME_LENGTH = "key_max_service_name_length"; + /** @hide */ + public static final String KEY_MAX_SERVICE_SPECIFIC_INFO_LENGTH = + "key_max_service_specific_info_length"; + /** @hide */ + public static final String KEY_MAX_MATCH_FILTER_LENGTH = "key_max_match_filter_length"; + + private Bundle mCharacteristics = new Bundle(); + + /** @hide : should not be created by apps */ + public WifiNanCharacteristics(Bundle characteristics) { + mCharacteristics = characteristics; + } + + /** + * Returns the maximum string length that can be used to specify a NAN service name. Restricts + * the parameters of the {@link PublishConfig.Builder#setServiceName(String)} and + * {@link SubscribeConfig.Builder#setServiceName(String)}. + * + * @return A positive integer, maximum string length of NAN service name. + */ + public int getMaxServiceNameLength() { + return mCharacteristics.getInt(KEY_MAX_SERVICE_NAME_LENGTH); + } + + /** + * Returns the maximum length of byte array that can be used to specify a NAN service specific + * information field: the arbitrary load used in discovery or the message length of NAN + * message exchange. Restricts the parameters of the + * {@link PublishConfig.Builder#setServiceSpecificInfo(byte[])}, + * {@link SubscribeConfig.Builder#setServiceSpecificInfo(byte[])}, and + * {@link WifiNanDiscoveryBaseSession#sendMessage(Object, int, byte[])} variants. + * + * @return A positive integer, maximum length of byte array for NAN messaging. + */ + public int getMaxServiceSpecificInfoLength() { + return mCharacteristics.getInt(KEY_MAX_SERVICE_SPECIFIC_INFO_LENGTH); + } + + /** + * Returns the maximum length of byte array that can be used to specify a NAN match filter. + * Restricts the parameters of the {@link PublishConfig.Builder#setMatchFilter(byte[])} and + * {@link SubscribeConfig.Builder#setMatchFilter(byte[])}. + * + * @return A positive integer, maximum legngth of byte array for NAN discovery match filter. + */ + public int getMaxMatchFilterLength() { + return mCharacteristics.getInt(KEY_MAX_MATCH_FILTER_LENGTH); + } + + @Override + public void writeToParcel(Parcel dest, int flags) { + dest.writeBundle(mCharacteristics); + } + + @Override + public int describeContents() { + return 0; + } + + public static final Creator<WifiNanCharacteristics> CREATOR = + new Creator<WifiNanCharacteristics>() { + @Override + public WifiNanCharacteristics createFromParcel(Parcel in) { + WifiNanCharacteristics c = new WifiNanCharacteristics(in.readBundle()); + return c; + } + + @Override + public WifiNanCharacteristics[] newArray(int size) { + return new WifiNanCharacteristics[size]; + } + }; +} diff --git a/wifi/java/android/net/wifi/nan/WifiNanManager.java b/wifi/java/android/net/wifi/nan/WifiNanManager.java index bb1543418c6d..002b95390eeb 100644 --- a/wifi/java/android/net/wifi/nan/WifiNanManager.java +++ b/wifi/java/android/net/wifi/nan/WifiNanManager.java @@ -293,6 +293,20 @@ public class WifiNanManager { } /** + * Returns the characteristics of the Wi-Fi NAN interface: a set of parameters which specify + * limitations on configurations, e.g. the maximum service name length. + * + * @return An object specifying configuration limitations of NAN. + */ + public WifiNanCharacteristics getCharacteristics() { + try { + return mService.getCharacteristics(); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + /** * Attach to the Wi-Fi NAN service - enabling the application to create discovery sessions or * create connections to peers. The device will attach to an existing cluster if it can find * one or create a new cluster (if it is the first to enable NAN in its vicinity). Results diff --git a/wifi/java/android/net/wifi/nan/WifiNanSession.java b/wifi/java/android/net/wifi/nan/WifiNanSession.java index 5fb2c066d9b9..df5e3c11b064 100644 --- a/wifi/java/android/net/wifi/nan/WifiNanSession.java +++ b/wifi/java/android/net/wifi/nan/WifiNanSession.java @@ -113,6 +113,8 @@ public class WifiNanSession { * An application must use the {@link WifiNanDiscoveryBaseSession#destroy()} to * terminate the publish discovery session once it isn't needed. This will free * resources as well terminate any on-air transmissions. + * <p>The application must have the {@link android.Manifest.permission#ACCESS_COARSE_LOCATION} + * permission to start a publish discovery session. * * @param handler The Handler on whose thread to execute the callbacks of the {@code * callback} object. If a null is provided then the application's main thread will be used. @@ -156,6 +158,8 @@ public class WifiNanSession { * An application must use the {@link WifiNanDiscoveryBaseSession#destroy()} to * terminate the subscribe discovery session once it isn't needed. This will free * resources as well terminate any on-air transmissions. + * <p>The application must have the {@link android.Manifest.permission#ACCESS_COARSE_LOCATION} + * permission to start a subscribe discovery session. * * @param handler The Handler on whose thread to execute the callbacks of the {@code * callback} object. If a null is provided then the application's main thread will be used. |