Merge "Fix incorrent page range parsing when custom print options used." into klp-dev
diff --git a/Android.mk b/Android.mk
index f97849c..b0a27e4 100644
--- a/Android.mk
+++ b/Android.mk
@@ -251,10 +251,14 @@
media/java/android/media/IAudioService.aidl \
media/java/android/media/IAudioFocusDispatcher.aidl \
media/java/android/media/IAudioRoutesObserver.aidl \
+ media/java/android/media/IMediaRouterClient.aidl \
+ media/java/android/media/IMediaRouterService.aidl \
media/java/android/media/IMediaScannerListener.aidl \
media/java/android/media/IMediaScannerService.aidl \
media/java/android/media/IRemoteControlClient.aidl \
media/java/android/media/IRemoteControlDisplay.aidl \
+ media/java/android/media/IRemoteDisplayCallback.aidl \
+ media/java/android/media/IRemoteDisplayProvider.aidl \
media/java/android/media/IRemoteVolumeObserver.aidl \
media/java/android/media/IRingtonePlayer.aidl \
telephony/java/com/android/internal/telephony/IPhoneStateListener.aidl \
diff --git a/cmds/am/src/com/android/commands/am/Am.java b/cmds/am/src/com/android/commands/am/Am.java
index c18f542..0344d26 100644
--- a/cmds/am/src/com/android/commands/am/Am.java
+++ b/cmds/am/src/com/android/commands/am/Am.java
@@ -107,7 +107,7 @@
" am switch-user <USER_ID>\n" +
" am stop-user <USER_ID>\n" +
" am stack create <TASK_ID> <RELATIVE_STACK_BOX_ID> <POSITION> <WEIGHT>\n" +
- " am stack movetask <STACK_ID> <TASK_ID> [true|false]\n" +
+ " am stack movetask <TASK_ID> <STACK_ID> [true|false]\n" +
" am stack resize <STACK_ID> <WEIGHT>\n" +
" am stack boxes\n" +
" am stack box <STACK_BOX_ID>\n" +
diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java
index bb04063..7ca3459 100644
--- a/core/java/android/app/ActivityManager.java
+++ b/core/java/android/app/ActivityManager.java
@@ -2272,9 +2272,12 @@
public static void dumpPackageStateStatic(FileDescriptor fd, String packageName) {
FileOutputStream fout = new FileOutputStream(fd);
PrintWriter pw = new FastPrintWriter(fout);
- dumpService(pw, fd, Context.ACTIVITY_SERVICE, new String[] { "package", packageName });
+ dumpService(pw, fd, Context.ACTIVITY_SERVICE, new String[] {
+ "-a", "package", packageName });
pw.println();
- dumpService(pw, fd, ProcessStats.SERVICE_NAME, new String[] { packageName });
+ dumpService(pw, fd, "meminfo", new String[] { "--local", packageName });
+ pw.println();
+ dumpService(pw, fd, ProcessStats.SERVICE_NAME, new String[] { "-a", packageName });
pw.println();
dumpService(pw, fd, "usagestats", new String[] { "--packages", packageName });
pw.println();
@@ -2296,7 +2299,7 @@
pw.flush();
tp = new TransferPipe();
tp.setBufferPrefix(" ");
- service.dump(tp.getWriteFd().getFileDescriptor(), args);
+ service.dumpAsync(tp.getWriteFd().getFileDescriptor(), args);
tp.go(fd);
} catch (Throwable e) {
if (tp != null) {
diff --git a/core/java/android/app/MediaRouteActionProvider.java b/core/java/android/app/MediaRouteActionProvider.java
index 63b641c..dffa969 100644
--- a/core/java/android/app/MediaRouteActionProvider.java
+++ b/core/java/android/app/MediaRouteActionProvider.java
@@ -16,10 +16,7 @@
package android.app;
-import com.android.internal.app.MediaRouteChooserDialogFragment;
-
import android.content.Context;
-import android.content.ContextWrapper;
import android.media.MediaRouter;
import android.media.MediaRouter.RouteInfo;
import android.util.Log;
@@ -30,22 +27,38 @@
import java.lang.ref.WeakReference;
+/**
+ * The media route action provider displays a {@link MediaRouteButton media route button}
+ * in the application's {@link ActionBar} to allow the user to select routes and
+ * to control the currently selected route.
+ * <p>
+ * The application must specify the kinds of routes that the user should be allowed
+ * to select by specifying the route types with the {@link #setRouteTypes} method.
+ * </p><p>
+ * Refer to {@link MediaRouteButton} for a description of the button that will
+ * appear in the action bar menu. Note that instead of disabling the button
+ * when no routes are available, the action provider will instead make the
+ * menu item invisible. In this way, the button will only be visible when it
+ * is possible for the user to discover and select a matching route.
+ * </p>
+ */
public class MediaRouteActionProvider extends ActionProvider {
private static final String TAG = "MediaRouteActionProvider";
- private Context mContext;
- private MediaRouter mRouter;
- private MenuItem mMenuItem;
- private MediaRouteButton mView;
+ private final Context mContext;
+ private final MediaRouter mRouter;
+ private final MediaRouterCallback mCallback;
+
private int mRouteTypes;
+ private MediaRouteButton mButton;
private View.OnClickListener mExtendedSettingsListener;
- private RouterCallback mCallback;
public MediaRouteActionProvider(Context context) {
super(context);
+
mContext = context;
mRouter = (MediaRouter) context.getSystemService(Context.MEDIA_ROUTER_SERVICE);
- mCallback = new RouterCallback(this);
+ mCallback = new MediaRouterCallback(this);
// Start with live audio by default.
// TODO Update this when new route types are added; segment by API level
@@ -53,80 +66,74 @@
setRouteTypes(MediaRouter.ROUTE_TYPE_LIVE_AUDIO);
}
+ /**
+ * Sets the types of routes that will be shown in the media route chooser dialog
+ * launched by this button.
+ *
+ * @param types The route types to match.
+ */
public void setRouteTypes(int types) {
- if (mRouteTypes == types) return;
- if (mRouteTypes != 0) {
- mRouter.removeCallback(mCallback);
+ if (mRouteTypes != types) {
+ // FIXME: We currently have no way of knowing whether the action provider
+ // is still needed by the UI. Unfortunately this means the action provider
+ // may leak callbacks until garbage collection occurs. This may result in
+ // media route providers doing more work than necessary in the short term
+ // while trying to discover routes that are no longer of interest to the
+ // application. To solve this problem, the action provider will need some
+ // indication from the framework that it is being destroyed.
+ if (mRouteTypes != 0) {
+ mRouter.removeCallback(mCallback);
+ }
+ mRouteTypes = types;
+ if (types != 0) {
+ mRouter.addCallback(types, mCallback,
+ MediaRouter.CALLBACK_FLAG_PASSIVE_DISCOVERY);
+ }
+ refreshRoute();
+
+ if (mButton != null) {
+ mButton.setRouteTypes(mRouteTypes);
+ }
}
- mRouteTypes = types;
- if (types != 0) {
- mRouter.addCallback(types, mCallback);
- }
- if (mView != null) {
- mView.setRouteTypes(mRouteTypes);
+ }
+
+ public void setExtendedSettingsClickListener(View.OnClickListener listener) {
+ mExtendedSettingsListener = listener;
+ if (mButton != null) {
+ mButton.setExtendedSettingsClickListener(listener);
}
}
@Override
+ @SuppressWarnings("deprecation")
public View onCreateActionView() {
throw new UnsupportedOperationException("Use onCreateActionView(MenuItem) instead.");
}
@Override
public View onCreateActionView(MenuItem item) {
- if (mMenuItem != null || mView != null) {
+ if (mButton != null) {
Log.e(TAG, "onCreateActionView: this ActionProvider is already associated " +
"with a menu item. Don't reuse MediaRouteActionProvider instances! " +
"Abandoning the old one...");
}
- mMenuItem = item;
- mView = new MediaRouteButton(mContext);
- mView.setCheatSheetEnabled(true);
- mView.setRouteTypes(mRouteTypes);
- mView.setExtendedSettingsClickListener(mExtendedSettingsListener);
- mView.setLayoutParams(new ViewGroup.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT,
+
+ mButton = new MediaRouteButton(mContext);
+ mButton.setCheatSheetEnabled(true);
+ mButton.setRouteTypes(mRouteTypes);
+ mButton.setExtendedSettingsClickListener(mExtendedSettingsListener);
+ mButton.setLayoutParams(new ViewGroup.LayoutParams(
+ ViewGroup.LayoutParams.WRAP_CONTENT,
ViewGroup.LayoutParams.MATCH_PARENT));
- return mView;
+ return mButton;
}
@Override
public boolean onPerformDefaultAction() {
- final FragmentManager fm = getActivity().getFragmentManager();
- // See if one is already attached to this activity.
- MediaRouteChooserDialogFragment dialogFragment =
- (MediaRouteChooserDialogFragment) fm.findFragmentByTag(
- MediaRouteChooserDialogFragment.FRAGMENT_TAG);
- if (dialogFragment != null) {
- Log.w(TAG, "onPerformDefaultAction(): Chooser dialog already showing!");
- return false;
+ if (mButton != null) {
+ return mButton.showDialogInternal();
}
-
- dialogFragment = new MediaRouteChooserDialogFragment();
- dialogFragment.setExtendedSettingsClickListener(mExtendedSettingsListener);
- dialogFragment.setRouteTypes(mRouteTypes);
- dialogFragment.show(fm, MediaRouteChooserDialogFragment.FRAGMENT_TAG);
- return true;
- }
-
- private Activity getActivity() {
- // Gross way of unwrapping the Activity so we can get the FragmentManager
- Context context = mContext;
- while (context instanceof ContextWrapper && !(context instanceof Activity)) {
- context = ((ContextWrapper) context).getBaseContext();
- }
- if (!(context instanceof Activity)) {
- throw new IllegalStateException("The MediaRouteActionProvider's Context " +
- "is not an Activity.");
- }
-
- return (Activity) context;
- }
-
- public void setExtendedSettingsClickListener(View.OnClickListener listener) {
- mExtendedSettingsListener = listener;
- if (mView != null) {
- mView.setExtendedSettingsClickListener(listener);
- }
+ return false;
}
@Override
@@ -136,36 +143,43 @@
@Override
public boolean isVisible() {
- return mRouter.getRouteCount() > 1;
+ return mRouter.isRouteAvailable(mRouteTypes,
+ MediaRouter.AVAILABILITY_FLAG_IGNORE_DEFAULT_ROUTE);
}
- private static class RouterCallback extends MediaRouter.SimpleCallback {
- private WeakReference<MediaRouteActionProvider> mAp;
+ private void refreshRoute() {
+ refreshVisibility();
+ }
- RouterCallback(MediaRouteActionProvider ap) {
- mAp = new WeakReference<MediaRouteActionProvider>(ap);
+ private static class MediaRouterCallback extends MediaRouter.SimpleCallback {
+ private final WeakReference<MediaRouteActionProvider> mProviderWeak;
+
+ public MediaRouterCallback(MediaRouteActionProvider provider) {
+ mProviderWeak = new WeakReference<MediaRouteActionProvider>(provider);
}
@Override
public void onRouteAdded(MediaRouter router, RouteInfo info) {
- final MediaRouteActionProvider ap = mAp.get();
- if (ap == null) {
- router.removeCallback(this);
- return;
- }
-
- ap.refreshVisibility();
+ refreshRoute(router);
}
@Override
public void onRouteRemoved(MediaRouter router, RouteInfo info) {
- final MediaRouteActionProvider ap = mAp.get();
- if (ap == null) {
- router.removeCallback(this);
- return;
- }
+ refreshRoute(router);
+ }
- ap.refreshVisibility();
+ @Override
+ public void onRouteChanged(MediaRouter router, RouteInfo info) {
+ refreshRoute(router);
+ }
+
+ private void refreshRoute(MediaRouter router) {
+ MediaRouteActionProvider provider = mProviderWeak.get();
+ if (provider != null) {
+ provider.refreshRoute();
+ } else {
+ router.removeCallback(this);
+ }
}
}
}
diff --git a/core/java/android/app/MediaRouteButton.java b/core/java/android/app/MediaRouteButton.java
index 7e0a27a..a7982f4 100644
--- a/core/java/android/app/MediaRouteButton.java
+++ b/core/java/android/app/MediaRouteButton.java
@@ -17,7 +17,7 @@
package android.app;
import com.android.internal.R;
-import com.android.internal.app.MediaRouteChooserDialogFragment;
+import com.android.internal.app.MediaRouteDialogPresenter;
import android.content.Context;
import android.content.ContextWrapper;
@@ -30,7 +30,6 @@
import android.media.MediaRouter.RouteInfo;
import android.text.TextUtils;
import android.util.AttributeSet;
-import android.util.Log;
import android.view.Gravity;
import android.view.HapticFeedbackConstants;
import android.view.SoundEffectConstants;
@@ -38,17 +37,15 @@
import android.widget.Toast;
public class MediaRouteButton extends View {
- private static final String TAG = "MediaRouteButton";
+ private final MediaRouter mRouter;
+ private final MediaRouterCallback mCallback;
- private MediaRouter mRouter;
- private final MediaRouteCallback mRouterCallback = new MediaRouteCallback();
private int mRouteTypes;
private boolean mAttachedToWindow;
private Drawable mRemoteIndicator;
private boolean mRemoteActive;
- private boolean mToggleMode;
private boolean mCheatSheetEnabled;
private boolean mIsConnecting;
@@ -56,12 +53,13 @@
private int mMinHeight;
private OnClickListener mExtendedSettingsClickListener;
- private MediaRouteChooserDialogFragment mDialogFragment;
+ // The checked state is used when connected to a remote route.
private static final int[] CHECKED_STATE_SET = {
R.attr.state_checked
};
+ // The activated state is used while connecting to a remote route.
private static final int[] ACTIVATED_STATE_SET = {
R.attr.state_activated
};
@@ -78,6 +76,7 @@
super(context, attrs, defStyleAttr);
mRouter = (MediaRouter)context.getSystemService(Context.MEDIA_ROUTER_SERVICE);
+ mCallback = new MediaRouterCallback();
TypedArray a = context.obtainStyledAttributes(attrs,
com.android.internal.R.styleable.MediaRouteButton, defStyleAttr, 0);
@@ -98,19 +97,87 @@
setRouteTypes(routeTypes);
}
- private void setRemoteIndicatorDrawable(Drawable d) {
- if (mRemoteIndicator != null) {
- mRemoteIndicator.setCallback(null);
- unscheduleDrawable(mRemoteIndicator);
+ /**
+ * Gets the media route types for filtering the routes that the user can
+ * select using the media route chooser dialog.
+ *
+ * @return The route types.
+ */
+ public int getRouteTypes() {
+ return mRouteTypes;
+ }
+
+ /**
+ * Sets the types of routes that will be shown in the media route chooser dialog
+ * launched by this button.
+ *
+ * @param types The route types to match.
+ */
+ public void setRouteTypes(int types) {
+ if (mRouteTypes != types) {
+ if (mAttachedToWindow && mRouteTypes != 0) {
+ mRouter.removeCallback(mCallback);
+ }
+
+ mRouteTypes = types;
+
+ if (mAttachedToWindow && types != 0) {
+ mRouter.addCallback(types, mCallback,
+ MediaRouter.CALLBACK_FLAG_PASSIVE_DISCOVERY);
+ }
+
+ refreshRoute();
}
- mRemoteIndicator = d;
- if (d != null) {
- d.setCallback(this);
- d.setState(getDrawableState());
- d.setVisible(getVisibility() == VISIBLE, false);
+ }
+
+ public void setExtendedSettingsClickListener(OnClickListener listener) {
+ mExtendedSettingsClickListener = listener;
+ }
+
+ /**
+ * Show the route chooser or controller dialog.
+ * <p>
+ * If the default route is selected or if the currently selected route does
+ * not match the {@link #getRouteTypes route types}, then shows the route chooser dialog.
+ * Otherwise, shows the route controller dialog to offer the user
+ * a choice to disconnect from the route or perform other control actions
+ * such as setting the route's volume.
+ * </p><p>
+ * This will attach a {@link DialogFragment} to the containing Activity.
+ * </p>
+ */
+ public void showDialog() {
+ showDialogInternal();
+ }
+
+ boolean showDialogInternal() {
+ if (!mAttachedToWindow) {
+ return false;
}
- refreshDrawableState();
+ DialogFragment f = MediaRouteDialogPresenter.showDialogFragment(getActivity(),
+ mRouteTypes, mExtendedSettingsClickListener);
+ return f != null;
+ }
+
+ private Activity getActivity() {
+ // Gross way of unwrapping the Activity so we can get the FragmentManager
+ Context context = getContext();
+ while (context instanceof ContextWrapper) {
+ if (context instanceof Activity) {
+ return (Activity)context;
+ }
+ context = ((ContextWrapper)context).getBaseContext();
+ }
+ throw new IllegalStateException("The MediaRouteButton's Context is not an Activity.");
+ }
+
+ /**
+ * Sets whether to enable showing a toast with the content descriptor of the
+ * button when the button is long pressed.
+ */
+ void setCheatSheetEnabled(boolean enable) {
+ mCheatSheetEnabled = enable;
}
@Override
@@ -120,29 +187,7 @@
if (!handled) {
playSoundEffect(SoundEffectConstants.CLICK);
}
-
- if (mToggleMode) {
- if (mRemoteActive) {
- mRouter.selectRouteInt(mRouteTypes, mRouter.getDefaultRoute());
- } else {
- final int N = mRouter.getRouteCount();
- for (int i = 0; i < N; i++) {
- final RouteInfo route = mRouter.getRouteAt(i);
- if ((route.getSupportedTypes() & mRouteTypes) != 0 &&
- route != mRouter.getDefaultRoute()) {
- mRouter.selectRouteInt(mRouteTypes, route);
- }
- }
- }
- } else {
- showDialog();
- }
-
- return handled;
- }
-
- void setCheatSheetEnabled(boolean enable) {
- mCheatSheetEnabled = enable;
+ return showDialogInternal() || handled;
}
@Override
@@ -183,85 +228,9 @@
}
cheatSheet.show();
performHapticFeedback(HapticFeedbackConstants.LONG_PRESS);
-
return true;
}
- public void setRouteTypes(int types) {
- if (types == mRouteTypes) {
- // Already registered; nothing to do.
- return;
- }
-
- if (mAttachedToWindow && mRouteTypes != 0) {
- mRouter.removeCallback(mRouterCallback);
- }
-
- mRouteTypes = types;
-
- if (mAttachedToWindow) {
- updateRouteInfo();
- mRouter.addCallback(types, mRouterCallback);
- }
- }
-
- private void updateRouteInfo() {
- updateRemoteIndicator();
- updateRouteCount();
- }
-
- public int getRouteTypes() {
- return mRouteTypes;
- }
-
- void updateRemoteIndicator() {
- final RouteInfo selected = mRouter.getSelectedRoute(mRouteTypes);
- final boolean isRemote = selected != mRouter.getDefaultRoute();
- final boolean isConnecting = selected != null &&
- selected.getStatusCode() == RouteInfo.STATUS_CONNECTING;
-
- boolean needsRefresh = false;
- if (mRemoteActive != isRemote) {
- mRemoteActive = isRemote;
- needsRefresh = true;
- }
- if (mIsConnecting != isConnecting) {
- mIsConnecting = isConnecting;
- needsRefresh = true;
- }
-
- if (needsRefresh) {
- refreshDrawableState();
- }
- }
-
- void updateRouteCount() {
- final int N = mRouter.getRouteCount();
- int count = 0;
- boolean hasVideoRoutes = false;
- for (int i = 0; i < N; i++) {
- final RouteInfo route = mRouter.getRouteAt(i);
- final int routeTypes = route.getSupportedTypes();
- if ((routeTypes & mRouteTypes) != 0) {
- if (route instanceof RouteGroup) {
- count += ((RouteGroup) route).getRouteCount();
- } else {
- count++;
- }
- if ((routeTypes & MediaRouter.ROUTE_TYPE_LIVE_VIDEO) != 0) {
- hasVideoRoutes = true;
- }
- }
- }
-
- setEnabled(count != 0);
-
- // Only allow toggling if we have more than just user routes.
- // Don't toggle if we support video routes, we may have to let the dialog scan.
- mToggleMode = count == 2 && (mRouteTypes & MediaRouter.ROUTE_TYPE_LIVE_AUDIO) != 0 &&
- !hasVideoRoutes;
- }
-
@Override
protected int[] onCreateDrawableState(int extraSpace) {
final int[] drawableState = super.onCreateDrawableState(extraSpace + 1);
@@ -289,6 +258,21 @@
}
}
+ private void setRemoteIndicatorDrawable(Drawable d) {
+ if (mRemoteIndicator != null) {
+ mRemoteIndicator.setCallback(null);
+ unscheduleDrawable(mRemoteIndicator);
+ }
+ mRemoteIndicator = d;
+ if (d != null) {
+ d.setCallback(this);
+ d.setState(getDrawableState());
+ d.setVisible(getVisibility() == VISIBLE, false);
+ }
+
+ refreshDrawableState();
+ }
+
@Override
protected boolean verifyDrawable(Drawable who) {
return super.verifyDrawable(who) || who == mRemoteIndicator;
@@ -297,12 +281,16 @@
@Override
public void jumpDrawablesToCurrentState() {
super.jumpDrawablesToCurrentState();
- if (mRemoteIndicator != null) mRemoteIndicator.jumpToCurrentState();
+
+ if (mRemoteIndicator != null) {
+ mRemoteIndicator.jumpToCurrentState();
+ }
}
@Override
public void setVisibility(int visibility) {
super.setVisibility(visibility);
+
if (mRemoteIndicator != null) {
mRemoteIndicator.setVisible(getVisibility() == VISIBLE, false);
}
@@ -311,19 +299,22 @@
@Override
public void onAttachedToWindow() {
super.onAttachedToWindow();
+
mAttachedToWindow = true;
if (mRouteTypes != 0) {
- mRouter.addCallback(mRouteTypes, mRouterCallback);
- updateRouteInfo();
+ mRouter.addCallback(mRouteTypes, mCallback,
+ MediaRouter.CALLBACK_FLAG_PASSIVE_DISCOVERY);
}
+ refreshRoute();
}
@Override
public void onDetachedFromWindow() {
- if (mRouteTypes != 0) {
- mRouter.removeCallback(mRouterCallback);
- }
mAttachedToWindow = false;
+ if (mRouteTypes != 0) {
+ mRouter.removeCallback(mCallback);
+ }
+
super.onDetachedFromWindow();
}
@@ -386,93 +377,71 @@
final int drawLeft = left + (right - left - drawWidth) / 2;
final int drawTop = top + (bottom - top - drawHeight) / 2;
- mRemoteIndicator.setBounds(drawLeft, drawTop, drawLeft + drawWidth, drawTop + drawHeight);
+ mRemoteIndicator.setBounds(drawLeft, drawTop,
+ drawLeft + drawWidth, drawTop + drawHeight);
mRemoteIndicator.draw(canvas);
}
- public void setExtendedSettingsClickListener(OnClickListener listener) {
- mExtendedSettingsClickListener = listener;
- if (mDialogFragment != null) {
- mDialogFragment.setExtendedSettingsClickListener(listener);
- }
- }
+ private void refreshRoute() {
+ if (mAttachedToWindow) {
+ final MediaRouter.RouteInfo route = mRouter.getSelectedRoute();
+ final boolean isRemote = !route.isDefault() && route.matchesTypes(mRouteTypes);
+ final boolean isConnecting = isRemote && route.isConnecting();
- /**
- * Asynchronously show the route chooser dialog.
- * This will attach a {@link DialogFragment} to the containing Activity.
- */
- public void showDialog() {
- final FragmentManager fm = getActivity().getFragmentManager();
- if (mDialogFragment == null) {
- // See if one is already attached to this activity.
- mDialogFragment = (MediaRouteChooserDialogFragment) fm.findFragmentByTag(
- MediaRouteChooserDialogFragment.FRAGMENT_TAG);
- }
- if (mDialogFragment != null) {
- Log.w(TAG, "showDialog(): Already showing!");
- return;
- }
-
- mDialogFragment = new MediaRouteChooserDialogFragment();
- mDialogFragment.setExtendedSettingsClickListener(mExtendedSettingsClickListener);
- mDialogFragment.setLauncherListener(new MediaRouteChooserDialogFragment.LauncherListener() {
- @Override
- public void onDetached(MediaRouteChooserDialogFragment detachedFragment) {
- mDialogFragment = null;
+ boolean needsRefresh = false;
+ if (mRemoteActive != isRemote) {
+ mRemoteActive = isRemote;
+ needsRefresh = true;
}
- });
- mDialogFragment.setRouteTypes(mRouteTypes);
- mDialogFragment.show(fm, MediaRouteChooserDialogFragment.FRAGMENT_TAG);
+ if (mIsConnecting != isConnecting) {
+ mIsConnecting = isConnecting;
+ needsRefresh = true;
+ }
+
+ if (needsRefresh) {
+ refreshDrawableState();
+ }
+
+ setEnabled(mRouter.isRouteAvailable(mRouteTypes,
+ MediaRouter.AVAILABILITY_FLAG_IGNORE_DEFAULT_ROUTE));
+ }
}
- private Activity getActivity() {
- // Gross way of unwrapping the Activity so we can get the FragmentManager
- Context context = getContext();
- while (context instanceof ContextWrapper && !(context instanceof Activity)) {
- context = ((ContextWrapper) context).getBaseContext();
- }
- if (!(context instanceof Activity)) {
- throw new IllegalStateException("The MediaRouteButton's Context is not an Activity.");
- }
-
- return (Activity) context;
- }
-
- private class MediaRouteCallback extends MediaRouter.SimpleCallback {
- @Override
- public void onRouteSelected(MediaRouter router, int type, RouteInfo info) {
- updateRemoteIndicator();
- }
-
- @Override
- public void onRouteUnselected(MediaRouter router, int type, RouteInfo info) {
- updateRemoteIndicator();
- }
-
- @Override
- public void onRouteChanged(MediaRouter router, RouteInfo info) {
- updateRemoteIndicator();
- }
-
+ private final class MediaRouterCallback extends MediaRouter.SimpleCallback {
@Override
public void onRouteAdded(MediaRouter router, RouteInfo info) {
- updateRouteCount();
+ refreshRoute();
}
@Override
public void onRouteRemoved(MediaRouter router, RouteInfo info) {
- updateRouteCount();
+ refreshRoute();
+ }
+
+ @Override
+ public void onRouteChanged(MediaRouter router, RouteInfo info) {
+ refreshRoute();
+ }
+
+ @Override
+ public void onRouteSelected(MediaRouter router, int type, RouteInfo info) {
+ refreshRoute();
+ }
+
+ @Override
+ public void onRouteUnselected(MediaRouter router, int type, RouteInfo info) {
+ refreshRoute();
}
@Override
public void onRouteGrouped(MediaRouter router, RouteInfo info, RouteGroup group,
int index) {
- updateRouteCount();
+ refreshRoute();
}
@Override
public void onRouteUngrouped(MediaRouter router, RouteInfo info, RouteGroup group) {
- updateRouteCount();
+ refreshRoute();
}
}
}
diff --git a/core/java/android/content/SyncInfo.java b/core/java/android/content/SyncInfo.java
index 0284882..cffc653 100644
--- a/core/java/android/content/SyncInfo.java
+++ b/core/java/android/content/SyncInfo.java
@@ -55,6 +55,14 @@
}
/** @hide */
+ public SyncInfo(SyncInfo other) {
+ this.authorityId = other.authorityId;
+ this.account = new Account(other.account.name, other.account.type);
+ this.authority = other.authority;
+ this.startTime = other.startTime;
+ }
+
+ /** @hide */
public int describeContents() {
return 0;
}
diff --git a/core/java/android/content/pm/IPackageManager.aidl b/core/java/android/content/pm/IPackageManager.aidl
index 267fb2a..20002ad 100644
--- a/core/java/android/content/pm/IPackageManager.aidl
+++ b/core/java/android/content/pm/IPackageManager.aidl
@@ -53,6 +53,7 @@
* {@hide}
*/
interface IPackageManager {
+ boolean isPackageAvailable(String packageName, int userId);
PackageInfo getPackageInfo(String packageName, int flags, int userId);
int getPackageUid(String packageName, int userId);
int[] getPackageGids(String packageName);
diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java
index 17d13e5..e6da288 100644
--- a/core/java/android/content/pm/PackageParser.java
+++ b/core/java/android/content/pm/PackageParser.java
@@ -282,6 +282,10 @@
|| (flags & PackageManager.GET_UNINSTALLED_PACKAGES) != 0;
}
+ public static boolean isAvailable(PackageUserState state) {
+ return checkUseInstalledOrBlocked(0, state);
+ }
+
public static PackageInfo generatePackageInfo(PackageParser.Package p,
int gids[], int flags, long firstInstallTime, long lastUpdateTime,
HashSet<String> grantedPermissions, PackageUserState state, int userId) {
diff --git a/core/java/android/hardware/camera2/CameraCharacteristics.java b/core/java/android/hardware/camera2/CameraCharacteristics.java
index 4fe2c4d..a38beec 100644
--- a/core/java/android/hardware/camera2/CameraCharacteristics.java
+++ b/core/java/android/hardware/camera2/CameraCharacteristics.java
@@ -334,6 +334,27 @@
/**
* <p>
+ * If set to 1, the HAL will always split result
+ * metadata for a single capture into multiple buffers,
+ * returned using multiple process_capture_result calls.
+ * </p>
+ * <p>
+ * Does not need to be listed in static
+ * metadata. Support for partial results will be reworked in
+ * future versions of camera service. This quirk will stop
+ * working at that point; DO NOT USE without careful
+ * consideration of future support.
+ * </p>
+ *
+ * <b>Optional</b> - This value may be null on some devices.
+ *
+ * @hide
+ */
+ public static final Key<Byte> QUIRKS_USE_PARTIAL_RESULT =
+ new Key<Byte>("android.quirks.usePartialResult", byte.class);
+
+ /**
+ * <p>
* How many output streams can be allocated at
* the same time for each type of stream
* </p>
diff --git a/core/java/android/hardware/camera2/CameraDevice.java b/core/java/android/hardware/camera2/CameraDevice.java
index 7095e4d..9e8d7d1 100644
--- a/core/java/android/hardware/camera2/CameraDevice.java
+++ b/core/java/android/hardware/camera2/CameraDevice.java
@@ -631,6 +631,36 @@
}
/**
+ * This method is called when some results from an image capture are
+ * available.
+ *
+ * <p>The result provided here will contain some subset of the fields of
+ * a full result. Multiple onCapturePartial calls may happen per
+ * capture; a given result field will only be present in one partial
+ * capture at most. The final onCaptureCompleted call will always
+ * contain all the fields, whether onCapturePartial was called or
+ * not.</p>
+ *
+ * <p>The default implementation of this method does nothing.</p>
+ *
+ * @param camera The CameraDevice sending the callback.
+ * @param request The request that was given to the CameraDevice
+ * @param result The partial output metadata from the capture, which
+ * includes a subset of the CaptureResult fields.
+ *
+ * @see #capture
+ * @see #captureBurst
+ * @see #setRepeatingRequest
+ * @see #setRepeatingBurst
+ *
+ * @hide
+ */
+ public void onCapturePartial(CameraDevice camera,
+ CaptureRequest request, CaptureResult result) {
+ // default empty implementation
+ }
+
+ /**
* This method is called when an image capture has completed and the
* result metadata is available.
*
diff --git a/core/java/android/hardware/camera2/CaptureResult.java b/core/java/android/hardware/camera2/CaptureResult.java
index dbd0457..535b963 100644
--- a/core/java/android/hardware/camera2/CaptureResult.java
+++ b/core/java/android/hardware/camera2/CaptureResult.java
@@ -591,6 +591,32 @@
/**
* <p>
+ * Whether a result given to the framework is the
+ * final one for the capture, or only a partial that contains a
+ * subset of the full set of dynamic metadata
+ * values.
+ * </p>
+ * <p>
+ * The entries in the result metadata buffers for a
+ * single capture may not overlap, except for this entry. The
+ * FINAL buffers must retain FIFO ordering relative to the
+ * requests that generate them, so the FINAL buffer for frame 3 must
+ * always be sent to the framework after the FINAL buffer for frame 2, and
+ * before the FINAL buffer for frame 4. PARTIAL buffers may be returned
+ * in any order relative to other frames, but all PARTIAL buffers for a given
+ * capture must arrive before the FINAL buffer for that capture. This entry may
+ * only be used by the HAL if quirks.usePartialResult is set to 1.
+ * </p>
+ *
+ * <b>Optional</b> - This value may be null on some devices.
+ *
+ * @hide
+ */
+ public static final Key<Boolean> QUIRKS_PARTIAL_RESULT =
+ new Key<Boolean>("android.quirks.partialResult", boolean.class);
+
+ /**
+ * <p>
* A frame counter set by the framework. This value monotonically
* increases with every new result (that is, each new result has a unique
* frameCount value).
diff --git a/core/java/android/hardware/camera2/impl/CameraDevice.java b/core/java/android/hardware/camera2/impl/CameraDevice.java
index c428a17..40586f0 100644
--- a/core/java/android/hardware/camera2/impl/CameraDevice.java
+++ b/core/java/android/hardware/camera2/impl/CameraDevice.java
@@ -279,6 +279,10 @@
checkIfCameraClosed();
int requestId;
+ if (repeating) {
+ stopRepeating();
+ }
+
try {
requestId = mRemoteDevice.submitRequest(request, repeating);
} catch (CameraRuntimeException e) {
@@ -293,10 +297,6 @@
}
if (repeating) {
- // Queue for deletion after in-flight requests finish
- if (mRepeatingRequestId != REQUEST_ID_NONE) {
- mRepeatingRequestIdDeletedList.add(mRepeatingRequestId);
- }
mRepeatingRequestId = requestId;
}
@@ -577,6 +577,9 @@
}
final CaptureListenerHolder holder;
+ Boolean quirkPartial = result.get(CaptureResult.QUIRKS_PARTIAL_RESULT);
+ boolean quirkIsPartialResult = (quirkPartial != null && quirkPartial);
+
synchronized (mLock) {
// TODO: move this whole map into this class to make it more testable,
// exposing the methods necessary like subscribeToRequest, unsubscribe..
@@ -585,7 +588,7 @@
holder = CameraDevice.this.mCaptureListenerMap.get(requestId);
// Clean up listener once we no longer expect to see it.
- if (holder != null && !holder.isRepeating()) {
+ if (holder != null && !holder.isRepeating() && !quirkIsPartialResult) {
CameraDevice.this.mCaptureListenerMap.remove(requestId);
}
@@ -595,7 +598,7 @@
// If we received a result for a repeating request and have
// prior repeating requests queued for deletion, remove those
// requests from mCaptureListenerMap.
- if (holder != null && holder.isRepeating()
+ if (holder != null && holder.isRepeating() && !quirkIsPartialResult
&& mRepeatingRequestIdDeletedList.size() > 0) {
Iterator<Integer> iter = mRepeatingRequestIdDeletedList.iterator();
while (iter.hasNext()) {
@@ -619,8 +622,25 @@
final CaptureRequest request = holder.getRequest();
final CaptureResult resultAsCapture = new CaptureResult(result, request, requestId);
- holder.getHandler().post(
- new Runnable() {
+ Runnable resultDispatch = null;
+
+ // Either send a partial result or the final capture completed result
+ if (quirkIsPartialResult) {
+ // Partial result
+ resultDispatch = new Runnable() {
+ @Override
+ public void run() {
+ if (!CameraDevice.this.isClosed()){
+ holder.getListener().onCapturePartial(
+ CameraDevice.this,
+ request,
+ resultAsCapture);
+ }
+ }
+ };
+ } else {
+ // Final capture result
+ resultDispatch = new Runnable() {
@Override
public void run() {
if (!CameraDevice.this.isClosed()){
@@ -630,7 +650,10 @@
resultAsCapture);
}
}
- });
+ };
+ }
+
+ holder.getHandler().post(resultDispatch);
}
}
diff --git a/core/java/android/hardware/display/DisplayManager.java b/core/java/android/hardware/display/DisplayManager.java
index f12be5f..d5208d9 100644
--- a/core/java/android/hardware/display/DisplayManager.java
+++ b/core/java/android/hardware/display/DisplayManager.java
@@ -299,6 +299,10 @@
/**
* Initiates a fresh scan of availble Wifi displays.
* The results are sent as a {@link #ACTION_WIFI_DISPLAY_STATUS_CHANGED} broadcast.
+ * <p>
+ * Requires {@link android.Manifest.permission#CONFIGURE_WIFI_DISPLAY}.
+ * </p>
+ *
* @hide
*/
public void scanWifiDisplays() {
@@ -312,8 +316,7 @@
* Automatically remembers the display after a successful connection, if not
* already remembered.
* </p><p>
- * Requires {@link android.Manifest.permission#CONFIGURE_WIFI_DISPLAY} to connect
- * to unknown displays. No permissions are required to connect to already known displays.
+ * Requires {@link android.Manifest.permission#CONFIGURE_WIFI_DISPLAY}.
* </p>
*
* @param deviceAddress The MAC address of the device to which we should connect.
diff --git a/core/java/android/net/ProxyProperties.java b/core/java/android/net/ProxyProperties.java
index 78ac75f..010e527 100644
--- a/core/java/android/net/ProxyProperties.java
+++ b/core/java/android/net/ProxyProperties.java
@@ -139,6 +139,17 @@
return false;
}
+ public boolean isValid() {
+ if (!TextUtils.isEmpty(mPacFileUrl)) return true;
+ try {
+ Proxy.validate(mHost == null ? "" : mHost, mPort == 0 ? "" : Integer.toString(mPort),
+ mExclusionList == null ? "" : mExclusionList);
+ } catch (IllegalArgumentException e) {
+ return false;
+ }
+ return true;
+ }
+
public java.net.Proxy makeProxy() {
java.net.Proxy proxy = java.net.Proxy.NO_PROXY;
if (mHost != null) {
diff --git a/core/java/android/os/BatteryStats.java b/core/java/android/os/BatteryStats.java
index 7ae8ca8..9ada6e6 100644
--- a/core/java/android/os/BatteryStats.java
+++ b/core/java/android/os/BatteryStats.java
@@ -106,6 +106,11 @@
public static final int FOREGROUND_ACTIVITY = 10;
/**
+ * A constant indicating a wifi batched scan is active
+ */
+ public static final int WIFI_BATCHED_SCAN = 11;
+
+ /**
* Include all of the data in the stats, including previously saved data.
*/
public static final int STATS_SINCE_CHARGED = 0;
@@ -270,6 +275,8 @@
public abstract void noteFullWifiLockReleasedLocked();
public abstract void noteWifiScanStartedLocked();
public abstract void noteWifiScanStoppedLocked();
+ public abstract void noteWifiBatchedScanStartedLocked(int csph);
+ public abstract void noteWifiBatchedScanStoppedLocked();
public abstract void noteWifiMulticastEnabledLocked();
public abstract void noteWifiMulticastDisabledLocked();
public abstract void noteAudioTurnedOnLocked();
@@ -281,6 +288,7 @@
public abstract long getWifiRunningTime(long batteryRealtime, int which);
public abstract long getFullWifiLockTime(long batteryRealtime, int which);
public abstract long getWifiScanTime(long batteryRealtime, int which);
+ public abstract long getWifiBatchedScanTime(int csphBin, long batteryRealtime, int which);
public abstract long getWifiMulticastTime(long batteryRealtime,
int which);
public abstract long getAudioTurnedOnTime(long batteryRealtime, int which);
@@ -288,6 +296,8 @@
public abstract Timer getForegroundActivityTimer();
public abstract Timer getVibratorOnTimer();
+ public static final int NUM_WIFI_BATCHED_SCAN_BINS = 5;
+
/**
* Note that these must match the constants in android.os.PowerManager.
* Also, if the user activity types change, the BatteryStatsImpl.VERSION must
@@ -2081,9 +2091,11 @@
TimeUtils.formatDuration(ew.usedTime, pw);
pw.print(" over ");
TimeUtils.formatDuration(ew.overTime, pw);
- pw.print(" (");
- pw.print((ew.usedTime*100)/ew.overTime);
- pw.println("%)");
+ if (ew.overTime != 0) {
+ pw.print(" (");
+ pw.print((ew.usedTime*100)/ew.overTime);
+ pw.println("%)");
+ }
}
}
uidActivity = true;
diff --git a/core/java/android/preference/Preference.java b/core/java/android/preference/Preference.java
index 37a8102..f7d1eb7 100644
--- a/core/java/android/preference/Preference.java
+++ b/core/java/android/preference/Preference.java
@@ -1069,11 +1069,11 @@
* @return 0 if the same; less than 0 if this Preference sorts ahead of <var>another</var>;
* greater than 0 if this Preference sorts after <var>another</var>.
*/
+ @Override
public int compareTo(Preference another) {
- if (mOrder != DEFAULT_ORDER
- || (mOrder == DEFAULT_ORDER && another.mOrder != DEFAULT_ORDER)) {
+ if (mOrder != another.mOrder) {
// Do order comparison
- return mOrder - another.mOrder;
+ return mOrder - another.mOrder;
} else if (mTitle == another.mTitle) {
// If titles are null or share same object comparison
return 0;
diff --git a/core/java/android/preference/PreferenceActivity.java b/core/java/android/preference/PreferenceActivity.java
index ed9264a..7ddfa87 100644
--- a/core/java/android/preference/PreferenceActivity.java
+++ b/core/java/android/preference/PreferenceActivity.java
@@ -521,7 +521,9 @@
int initialTitle = getIntent().getIntExtra(EXTRA_SHOW_FRAGMENT_TITLE, 0);
int initialShortTitle = getIntent().getIntExtra(EXTRA_SHOW_FRAGMENT_SHORT_TITLE, 0);
- if (savedInstanceState != null) {
+ // Restore from headers only if they are supported which
+ // is in multi-pane mode.
+ if (savedInstanceState != null && !mSinglePane) {
// We are restarting from a previous saved state; used that to
// initialize, instead of starting fresh.
ArrayList<Header> headers = savedInstanceState.getParcelableArrayList(HEADERS_TAG);
@@ -573,14 +575,12 @@
// Single pane, showing just a prefs fragment.
findViewById(com.android.internal.R.id.headers).setVisibility(View.GONE);
mPrefsContainer.setVisibility(View.VISIBLE);
- CharSequence initialTitleStr = null;
- CharSequence initialShortTitleStr = null;
if (initialTitle != 0) {
- initialTitleStr = getText(initialTitle);
- initialShortTitleStr = initialShortTitle != 0
+ CharSequence initialTitleStr = getText(initialTitle);
+ CharSequence initialShortTitleStr = initialShortTitle != 0
? getText(initialShortTitle) : null;
+ showBreadCrumbs(initialTitleStr, initialShortTitleStr);
}
- showBreadCrumbs(initialTitleStr, initialShortTitleStr);
} else if (mHeaders.size() > 0) {
setListAdapter(new HeaderAdapter(this, mHeaders));
if (!mSinglePane) {
diff --git a/core/java/android/print/PrintDocumentAdapter.java b/core/java/android/print/PrintDocumentAdapter.java
index 9e811a6..1f59bef 100644
--- a/core/java/android/print/PrintDocumentAdapter.java
+++ b/core/java/android/print/PrintDocumentAdapter.java
@@ -141,15 +141,36 @@
* or {@link LayoutResultCallback#onLayoutCancelled()} if layout was
* cancelled in a response to a cancellation request via the passed in
* {@link CancellationSignal}. Note that you <strong>must</strong> call one of
- * the methods of the given callback for this method to be considered complete.
+ * the methods of the given callback for this method to be considered complete
+ * which is you will not receive any calls to this adapter until the current
+ * layout operation is complete by invoking a method on the callback instance.
+ * The callback methods can be invoked from an arbitrary thread.
* </p>
* <p>
+ * One of the arguments passed to this method is a {@link CancellationSignal}
+ * which is used to propagate requests from the system to your application for
+ * canceling the current layout operation. For example, a cancellation may be
+ * requested if the user changes a print option that may affect layout while
+ * you are performing a layout operation. In such a case the system will make
+ * an attempt to cancel the current layout as another one will have to be performed.
+ * Typically, you should register a cancellation callback in the cancellation
+ * signal. The cancellation callback <strong>will not</strong> be made on the
+ * main thread and can be registered as follows:
+ * </p>
+ * <pre>
+ * cancellationSignal.setOnCancelListener(new OnCancelListener() {
+ * @Override
+ * public void onCancel() {
+ * // Cancel layout
+ * }
+ * });
+ * </pre>
+ * <p>
* <strong>Note:</strong> If the content is large and a layout will be
* performed, it is a good practice to schedule the work on a dedicated
* thread and register an observer in the provided {@link
* CancellationSignal} upon invocation of which you should stop the
- * layout. The cancellation callback <strong>will not</strong> be made on
- * the main thread.
+ * layout.
* </p>
*
* @param oldAttributes The old print attributes.
@@ -177,14 +198,36 @@
* CharSequence)}, if an error occurred; or {@link WriteResultCallback#onWriteCancelled()},
* if writing was cancelled in a response to a cancellation request via the passed
* in {@link CancellationSignal}. Note that you <strong>must</strong> call one of
- * the methods of the given callback for this method to be considered complete.
+ * the methods of the given callback for this method to be considered complete which
+ * is you will not receive any calls to this adapter until the current write
+ * operation is complete by invoking a method on the callback instance. The callback
+ * methods can be invoked from an arbitrary thread.
* </p>
* <p>
+ * One of the arguments passed to this method is a {@link CancellationSignal}
+ * which is used to propagate requests from the system to your application for
+ * canceling the current write operation. For example, a cancellation may be
+ * requested if the user changes a print option that may affect layout while
+ * you are performing a write operation. In such a case the system will make
+ * an attempt to cancel the current write as a layout will have to be performed
+ * which then may be followed by a write. Typically, you should register a
+ * cancellation callback in the cancellation signal. The cancellation callback
+ * <strong>will not</strong> be made on the main thread and can be registered
+ * as follows:
+ * </p>
+ * <pre>
+ * cancellationSignal.setOnCancelListener(new OnCancelListener() {
+ * @Override
+ * public void onCancel() {
+ * // Cancel write
+ * }
+ * });
+ * </pre>
+ * <p>
* <strong>Note:</strong> If the printed content is large, it is a good
* practice to schedule writing it on a dedicated thread and register an
* observer in the provided {@link CancellationSignal} upon invocation of
- * which you should stop writing. The cancellation callback will not be
- * made on the main thread.
+ * which you should stop writing.
* </p>
*
* @param pages The pages whose content to print - non-overlapping in ascending order.
diff --git a/core/java/android/print/PrintManager.java b/core/java/android/print/PrintManager.java
index d6d56bb..d1bb8fd 100644
--- a/core/java/android/print/PrintManager.java
+++ b/core/java/android/print/PrintManager.java
@@ -860,6 +860,11 @@
}
final ILayoutResultCallback callback;
synchronized (mLock) {
+ if (mDestroyed) {
+ Log.e(LOG_TAG, "PrintDocumentAdapter is destroyed. Did you "
+ + "finish the printing activity before print completion?");
+ return;
+ }
callback = mCallback;
clearLocked();
}
@@ -876,6 +881,11 @@
public void onLayoutFailed(CharSequence error) {
final ILayoutResultCallback callback;
synchronized (mLock) {
+ if (mDestroyed) {
+ Log.e(LOG_TAG, "PrintDocumentAdapter is destroyed. Did you "
+ + "finish the printing activity before print completion?");
+ return;
+ }
callback = mCallback;
clearLocked();
}
@@ -891,6 +901,11 @@
@Override
public void onLayoutCancelled() {
synchronized (mLock) {
+ if (mDestroyed) {
+ Log.e(LOG_TAG, "PrintDocumentAdapter is destroyed. Did you "
+ + "finish the printing activity before print completion?");
+ return;
+ }
clearLocked();
}
}
@@ -918,6 +933,11 @@
public void onWriteFinished(PageRange[] pages) {
final IWriteResultCallback callback;
synchronized (mLock) {
+ if (mDestroyed) {
+ Log.e(LOG_TAG, "PrintDocumentAdapter is destroyed. Did you "
+ + "finish the printing activity before print completion?");
+ return;
+ }
callback = mCallback;
clearLocked();
}
@@ -940,6 +960,11 @@
public void onWriteFailed(CharSequence error) {
final IWriteResultCallback callback;
synchronized (mLock) {
+ if (mDestroyed) {
+ Log.e(LOG_TAG, "PrintDocumentAdapter is destroyed. Did you "
+ + "finish the printing activity before print completion?");
+ return;
+ }
callback = mCallback;
clearLocked();
}
@@ -955,6 +980,11 @@
@Override
public void onWriteCancelled() {
synchronized (mLock) {
+ if (mDestroyed) {
+ Log.e(LOG_TAG, "PrintDocumentAdapter is destroyed. Did you "
+ + "finish the printing activity before print completion?");
+ return;
+ }
clearLocked();
}
}
diff --git a/core/java/android/provider/DocumentsProvider.java b/core/java/android/provider/DocumentsProvider.java
index cc81be5..49816f8 100644
--- a/core/java/android/provider/DocumentsProvider.java
+++ b/core/java/android/provider/DocumentsProvider.java
@@ -62,7 +62,8 @@
* android:authorities="com.example.mycloudprovider"
* android:exported="true"
* android:grantUriPermissions="true"
- * android:permission="android.permission.MANAGE_DOCUMENTS">
+ * android:permission="android.permission.MANAGE_DOCUMENTS"
+ * android:enabled="@bool/isAtLeastKitKat">
* <intent-filter>
* <action android:name="android.content.action.DOCUMENTS_PROVIDER" />
* </intent-filter>
@@ -252,7 +253,8 @@
* {@link DocumentsContract#EXTRA_LOADING} on the Cursor to indicate that
* you are still fetching additional data. Then, when the network data is
* available, you can send a change notification to trigger a requery and
- * return the complete contents.
+ * return the complete contents. To return a Cursor with extras, you need to
+ * extend and override {@link Cursor#getExtras()}.
* <p>
* To support change notifications, you must
* {@link Cursor#setNotificationUri(ContentResolver, Uri)} with a relevant
@@ -362,7 +364,7 @@
* @param documentId the document to return.
* @param mode the mode to open with, such as 'r', 'w', or 'rw'.
* @param signal used by the caller to signal if the request should be
- * cancelled.
+ * cancelled. May be null.
* @see ParcelFileDescriptor#open(java.io.File, int, android.os.Handler,
* OnCloseListener)
* @see ParcelFileDescriptor#createReliablePipe()
@@ -386,7 +388,7 @@
* @param documentId the document to return.
* @param sizeHint hint of the optimal thumbnail dimensions.
* @param signal used by the caller to signal if the request should be
- * cancelled.
+ * cancelled. May be null.
* @see Document#FLAG_SUPPORTS_THUMBNAIL
*/
@SuppressWarnings("unused")
diff --git a/core/java/android/text/InputType.java b/core/java/android/text/InputType.java
index 6d066d6..c596388 100644
--- a/core/java/android/text/InputType.java
+++ b/core/java/android/text/InputType.java
@@ -46,9 +46,9 @@
* of text being given. Currently supported classes are:
* {@link #TYPE_CLASS_TEXT}, {@link #TYPE_CLASS_NUMBER},
* {@link #TYPE_CLASS_PHONE}, {@link #TYPE_CLASS_DATETIME}.
- * If the class is not one you
+ * <p>IME authors: If the class is not one you
* understand, assume {@link #TYPE_CLASS_TEXT} with NO variation
- * or flags.
+ * or flags.<p>
*/
public static final int TYPE_MASK_CLASS = 0x0000000f;
@@ -69,7 +69,10 @@
* This should be interpreted to mean that the target input connection
* is not rich, it can not process and show things like candidate text nor
* retrieve the current text, so the input method will need to run in a
- * limited "generate key events" mode.
+ * limited "generate key events" mode, if it supports it. Note that some
+ * input methods may not support it, for example a voice-based input
+ * method will likely not be able to generate key events even if this
+ * flag is set.
*/
public static final int TYPE_NULL = 0x00000000;
@@ -94,48 +97,70 @@
* Flag for {@link #TYPE_CLASS_TEXT}: capitalize all characters. Overrides
* {@link #TYPE_TEXT_FLAG_CAP_WORDS} and
* {@link #TYPE_TEXT_FLAG_CAP_SENTENCES}. This value is explicitly defined
- * to be the same as {@link TextUtils#CAP_MODE_CHARACTERS}.
+ * to be the same as {@link TextUtils#CAP_MODE_CHARACTERS}. Of course,
+ * this only affects languages where there are upper-case and lower-case letters.
*/
public static final int TYPE_TEXT_FLAG_CAP_CHARACTERS = 0x00001000;
/**
- * Flag for {@link #TYPE_CLASS_TEXT}: capitalize first character of
- * all words. Overrides {@link #TYPE_TEXT_FLAG_CAP_SENTENCES}. This
+ * Flag for {@link #TYPE_CLASS_TEXT}: capitalize the first character of
+ * every word. Overrides {@link #TYPE_TEXT_FLAG_CAP_SENTENCES}. This
* value is explicitly defined
- * to be the same as {@link TextUtils#CAP_MODE_WORDS}.
+ * to be the same as {@link TextUtils#CAP_MODE_WORDS}. Of course,
+ * this only affects languages where there are upper-case and lower-case letters.
*/
public static final int TYPE_TEXT_FLAG_CAP_WORDS = 0x00002000;
/**
- * Flag for {@link #TYPE_CLASS_TEXT}: capitalize first character of
+ * Flag for {@link #TYPE_CLASS_TEXT}: capitalize the first character of
* each sentence. This value is explicitly defined
- * to be the same as {@link TextUtils#CAP_MODE_SENTENCES}.
+ * to be the same as {@link TextUtils#CAP_MODE_SENTENCES}. For example
+ * in English it means to capitalize after a period and a space (note that other
+ * languages may have different characters for period, or not use spaces,
+ * or use different grammatical rules). Of course,
+ * this only affects languages where there are upper-case and lower-case letters.
*/
public static final int TYPE_TEXT_FLAG_CAP_SENTENCES = 0x00004000;
/**
* Flag for {@link #TYPE_CLASS_TEXT}: the user is entering free-form
- * text that should have auto-correction applied to it.
+ * text that should have auto-correction applied to it. Without this flag,
+ * the IME will not try to correct typos. You should always set this flag
+ * unless you really expect users to type non-words in this field, for
+ * example to choose a name for a character in a game.
+ * Contrast this with {@link #TYPE_TEXT_FLAG_AUTO_COMPLETE} and
+ * {@link #TYPE_TEXT_FLAG_NO_SUGGESTIONS}:
+ * {@code TYPE_TEXT_FLAG_AUTO_CORRECT} means that the IME will try to
+ * auto-correct typos as the user is typing, but does not define whether
+ * the IME offers an interface to show suggestions.
*/
public static final int TYPE_TEXT_FLAG_AUTO_CORRECT = 0x00008000;
/**
- * Flag for {@link #TYPE_CLASS_TEXT}: the text editor is performing
- * auto-completion of the text being entered based on its own semantics,
- * which it will present to the user as they type. This generally means
- * that the input method should not be showing candidates itself, but can
- * expect for the editor to supply its own completions/candidates from
+ * Flag for {@link #TYPE_CLASS_TEXT}: the text editor (which means
+ * the application) is performing auto-completion of the text being entered
+ * based on its own semantics, which it will present to the user as they type.
+ * This generally means that the input method should not be showing
+ * candidates itself, but can expect the editor to supply its own
+ * completions/candidates from
* {@link android.view.inputmethod.InputMethodSession#displayCompletions
* InputMethodSession.displayCompletions()} as a result of the editor calling
* {@link android.view.inputmethod.InputMethodManager#displayCompletions
* InputMethodManager.displayCompletions()}.
+ * Note the contrast with {@link #TYPE_TEXT_FLAG_AUTO_CORRECT} and
+ * {@link #TYPE_TEXT_FLAG_NO_SUGGESTIONS}:
+ * {@code TYPE_TEXT_FLAG_AUTO_COMPLETE} means the editor should show an
+ * interface for displaying suggestions, but instead of supplying its own
+ * it will rely on the Editor to pass completions/corrections.
*/
public static final int TYPE_TEXT_FLAG_AUTO_COMPLETE = 0x00010000;
/**
* Flag for {@link #TYPE_CLASS_TEXT}: multiple lines of text can be
* entered into the field. If this flag is not set, the text field
- * will be constrained to a single line.
+ * will be constrained to a single line. The IME may also choose not to
+ * display an enter key when this flag is not set, as there should be no
+ * need to create new lines.
*/
public static final int TYPE_TEXT_FLAG_MULTI_LINE = 0x00020000;
@@ -152,6 +177,16 @@
* do not contain words from the language and do not benefit from any
* dictionary-based completions or corrections. It overrides the
* {@link #TYPE_TEXT_FLAG_AUTO_CORRECT} value when set.
+ * Please avoid using this unless you are certain this is what you want.
+ * Many input methods need suggestions to work well, for example the ones
+ * based on gesture typing. Consider clearing
+ * {@link #TYPE_TEXT_FLAG_AUTO_CORRECT} instead if you just do not
+ * want the IME to correct typos.
+ * Note the contrast with {@link #TYPE_TEXT_FLAG_AUTO_CORRECT} and
+ * {@link #TYPE_TEXT_FLAG_AUTO_COMPLETE}:
+ * {@code TYPE_TEXT_FLAG_NO_SUGGESTIONS} means the IME should never
+ * show an interface to display suggestions. Most IMEs will also take this to
+ * mean they should not try to auto-correct what the user is typing.
*/
public static final int TYPE_TEXT_FLAG_NO_SUGGESTIONS = 0x00080000;
@@ -224,7 +259,9 @@
/**
* Variation of {@link #TYPE_CLASS_TEXT}: entering text for phonetic
- * pronunciation, such as a phonetic name field in contacts.
+ * pronunciation, such as a phonetic name field in contacts. This is mostly
+ * useful for languages where one spelling may have several phonetic
+ * readings, like Japanese.
*/
public static final int TYPE_TEXT_VARIATION_PHONETIC = 0x000000c0;
@@ -255,12 +292,13 @@
// ----------------------------------------------------------------------
/**
- * Class for numeric text. This class supports the following flag:
+ * Class for numeric text. This class supports the following flags:
* {@link #TYPE_NUMBER_FLAG_SIGNED} and
* {@link #TYPE_NUMBER_FLAG_DECIMAL}. It also supports the following
* variations: {@link #TYPE_NUMBER_VARIATION_NORMAL} and
- * {@link #TYPE_NUMBER_VARIATION_PASSWORD}. If you do not recognize
- * the variation, normal should be assumed.
+ * {@link #TYPE_NUMBER_VARIATION_PASSWORD}.
+ * <p>IME authors: If you do not recognize
+ * the variation, normal should be assumed.</p>
*/
public static final int TYPE_CLASS_NUMBER = 0x00000002;
@@ -318,7 +356,7 @@
* following variations:
* {@link #TYPE_DATETIME_VARIATION_NORMAL}
* {@link #TYPE_DATETIME_VARIATION_DATE}, and
- * {@link #TYPE_DATETIME_VARIATION_TIME},.
+ * {@link #TYPE_DATETIME_VARIATION_TIME}.
*/
public static final int TYPE_CLASS_DATETIME = 0x00000004;
diff --git a/core/java/android/view/Display.java b/core/java/android/view/Display.java
index 354ea66..7d310a2 100644
--- a/core/java/android/view/Display.java
+++ b/core/java/android/view/Display.java
@@ -643,6 +643,15 @@
|| uid == 0;
}
+ /**
+ * Returns true if the display is a public presentation display.
+ * @hide
+ */
+ public boolean isPublicPresentation() {
+ return (mFlags & (Display.FLAG_PRIVATE | Display.FLAG_PRESENTATION)) ==
+ Display.FLAG_PRESENTATION;
+ }
+
private void updateDisplayInfoLocked() {
// Note: The display manager caches display info objects on our behalf.
DisplayInfo newInfo = mGlobal.getDisplayInfo(mDisplayId);
diff --git a/core/java/android/view/IWindowManager.aidl b/core/java/android/view/IWindowManager.aidl
index 1b76cb1..c92a104 100644
--- a/core/java/android/view/IWindowManager.aidl
+++ b/core/java/android/view/IWindowManager.aidl
@@ -78,7 +78,8 @@
void addWindowToken(IBinder token, int type);
void removeWindowToken(IBinder token);
void addAppToken(int addPos, IApplicationToken token, int groupId, int stackId,
- int requestedOrientation, boolean fullscreen, boolean showWhenLocked, int userId);
+ int requestedOrientation, boolean fullscreen, boolean showWhenLocked, int userId,
+ int configChanges);
void setAppGroupId(IBinder token, int groupId);
void setAppOrientation(IApplicationToken token, int requestedOrientation);
int getAppOrientation(IApplicationToken token);
diff --git a/core/java/android/view/ScaleGestureDetector.java b/core/java/android/view/ScaleGestureDetector.java
index f36c78f..42a58a8 100644
--- a/core/java/android/view/ScaleGestureDetector.java
+++ b/core/java/android/view/ScaleGestureDetector.java
@@ -323,6 +323,10 @@
mInProgress = false;
mInitialSpan = 0;
mDoubleTapMode = DOUBLE_TAP_MODE_NONE;
+ } else if (mDoubleTapMode == DOUBLE_TAP_MODE_IN_PROGRESS && streamComplete) {
+ mInProgress = false;
+ mInitialSpan = 0;
+ mDoubleTapMode = DOUBLE_TAP_MODE_NONE;
}
if (streamComplete) {
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index aa2b0d4..06f8e8c 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -18,7 +18,6 @@
import android.content.ClipData;
import android.content.Context;
-import android.content.pm.ApplicationInfo;
import android.content.res.Configuration;
import android.content.res.Resources;
import android.content.res.TypedArray;
@@ -3102,7 +3101,15 @@
*/
private static final int UNDEFINED_PADDING = Integer.MIN_VALUE;
- private boolean mUseBackgroundPadding = false;
+ /**
+ * Cache if a left padding has been defined
+ */
+ private boolean mLeftPaddingDefined = false;
+
+ /**
+ * Cache if a right padding has been defined
+ */
+ private boolean mRightPaddingDefined = false;
/**
* @hide
@@ -3532,10 +3539,10 @@
int overScrollMode = mOverScrollMode;
boolean initializeScrollbars = false;
- boolean leftPaddingDefined = false;
- boolean rightPaddingDefined = false;
boolean startPaddingDefined = false;
boolean endPaddingDefined = false;
+ boolean leftPaddingDefined = false;
+ boolean rightPaddingDefined = false;
final int targetSdkVersion = context.getApplicationInfo().targetSdkVersion;
@@ -3867,6 +3874,11 @@
setBackground(background);
}
+ // setBackground above will record that padding is currently provided by the background.
+ // If we have padding specified via xml, record that here instead and use it.
+ mLeftPaddingDefined = leftPaddingDefined;
+ mRightPaddingDefined = rightPaddingDefined;
+
if (padding >= 0) {
leftPadding = padding;
topPadding = padding;
@@ -3884,11 +3896,11 @@
// Padding from the background drawable is stored at this point in mUserPaddingLeftInitial
// and mUserPaddingRightInitial) so drawable padding will be used as ultimate default if
// defined.
- if (!leftPaddingDefined && startPaddingDefined) {
+ if (!mLeftPaddingDefined && startPaddingDefined) {
leftPadding = startPadding;
}
mUserPaddingLeftInitial = (leftPadding >= 0) ? leftPadding : mUserPaddingLeftInitial;
- if (!rightPaddingDefined && endPaddingDefined) {
+ if (!mRightPaddingDefined && endPaddingDefined) {
rightPadding = endPadding;
}
mUserPaddingRightInitial = (rightPadding >= 0) ? rightPadding : mUserPaddingRightInitial;
@@ -3900,10 +3912,10 @@
// defined.
final boolean hasRelativePadding = startPaddingDefined || endPaddingDefined;
- if (leftPaddingDefined && !hasRelativePadding) {
+ if (mLeftPaddingDefined && !hasRelativePadding) {
mUserPaddingLeftInitial = leftPadding;
}
- if (rightPaddingDefined && !hasRelativePadding) {
+ if (mRightPaddingDefined && !hasRelativePadding) {
mUserPaddingRightInitial = rightPadding;
}
}
@@ -12347,15 +12359,19 @@
// If start / end padding are defined, they will be resolved (hence overriding) to
// left / right or right / left depending on the resolved layout direction.
// If start / end padding are not defined, use the left / right ones.
- if (mBackground != null && mUseBackgroundPadding) {
+ if (mBackground != null && (!mLeftPaddingDefined || !mRightPaddingDefined)) {
Rect padding = sThreadLocal.get();
if (padding == null) {
padding = new Rect();
sThreadLocal.set(padding);
}
mBackground.getPadding(padding);
- mUserPaddingLeftInitial = padding.left;
- mUserPaddingRightInitial = padding.right;
+ if (!mLeftPaddingDefined) {
+ mUserPaddingLeftInitial = padding.left;
+ }
+ if (!mRightPaddingDefined) {
+ mUserPaddingRightInitial = padding.right;
+ }
}
switch (resolvedLayoutDirection) {
case LAYOUT_DIRECTION_RTL:
@@ -15352,9 +15368,8 @@
mUserPaddingRightInitial = padding.right;
internalSetPadding(padding.left, padding.top, padding.right, padding.bottom);
}
- mUseBackgroundPadding = true;
- } else {
- mUseBackgroundPadding = false;
+ mLeftPaddingDefined = false;
+ mRightPaddingDefined = false;
}
// Compare the minimum sizes of the old Drawable and the new. If there isn't an old or
@@ -15380,8 +15395,6 @@
/* Remove the background */
mBackground = null;
- mUseBackgroundPadding = false;
-
if ((mPrivateFlags & PFLAG_ONLY_DRAWS_BACKGROUND) != 0) {
/*
* This view ONLY drew the background before and we're removing
@@ -15453,7 +15466,8 @@
mUserPaddingLeftInitial = left;
mUserPaddingRightInitial = right;
- mUseBackgroundPadding = false;
+ mLeftPaddingDefined = true;
+ mRightPaddingDefined = true;
internalSetPadding(left, top, right, bottom);
}
@@ -15540,8 +15554,8 @@
mUserPaddingStart = start;
mUserPaddingEnd = end;
-
- mUseBackgroundPadding = false;
+ mLeftPaddingDefined = true;
+ mRightPaddingDefined = true;
switch(getLayoutDirection()) {
case LAYOUT_DIRECTION_RTL:
diff --git a/core/java/android/view/inputmethod/EditorInfo.java b/core/java/android/view/inputmethod/EditorInfo.java
index 5146567..d4e005b 100644
--- a/core/java/android/view/inputmethod/EditorInfo.java
+++ b/core/java/android/view/inputmethod/EditorInfo.java
@@ -70,14 +70,14 @@
/**
* Bits of {@link #IME_MASK_ACTION}: the action key performs a "search"
* operation, taking the user to the results of searching for the text
- * the have typed (in whatever context is appropriate).
+ * they have typed (in whatever context is appropriate).
*/
public static final int IME_ACTION_SEARCH = 0x00000003;
/**
* Bits of {@link #IME_MASK_ACTION}: the action key performs a "send"
* operation, delivering the text to its target. This is typically used
- * when composing a message.
+ * when composing a message in IM or SMS where sending is immediate.
*/
public static final int IME_ACTION_SEND = 0x00000004;
@@ -89,22 +89,31 @@
/**
* Bits of {@link #IME_MASK_ACTION}: the action key performs a "done"
- * operation, typically meaning the IME will be closed.
+ * operation, typically meaning there is nothing more to input and the
+ * IME will be closed.
*/
public static final int IME_ACTION_DONE = 0x00000006;
/**
* Bits of {@link #IME_MASK_ACTION}: Like {@link #IME_ACTION_NEXT}, but
* for moving to the previous field. This will normally not be used to
- * specify an action (since it precludes {@link #IME_ACTION_NEXT}, but
+ * specify an action (since it precludes {@link #IME_ACTION_NEXT}), but
* can be returned to the app if it sets {@link #IME_FLAG_NAVIGATE_PREVIOUS}.
*/
public static final int IME_ACTION_PREVIOUS = 0x00000007;
/**
* Flag of {@link #imeOptions}: used to request that the IME never go
- * into fullscreen mode. Applications need to be aware that the flag is not
- * a guarantee, and not all IMEs will respect it.
+ * into fullscreen mode.
+ * By default, IMEs may go into full screen mode when they think
+ * it's appropriate, for example on small screens in landscape
+ * orientation where displaying a software keyboard may occlude
+ * such a large portion of the screen that the remaining part is
+ * too small to meaningfully display the application UI.
+ * If this flag is set, compliant IMEs will never go into full screen mode,
+ * and always leave some space to display the application UI.
+ * Applications need to be aware that the flag is not a guarantee, and
+ * some IMEs may ignore it.
*/
public static final int IME_FLAG_NO_FULLSCREEN = 0x2000000;
@@ -136,50 +145,56 @@
* Flag of {@link #imeOptions}: used to specify that the IME does not need
* to show its extracted text UI. For input methods that may be fullscreen,
* often when in landscape mode, this allows them to be smaller and let part
- * of the application be shown behind. Though there will likely be limited
- * access to the application available from the user, it can make the
- * experience of a (mostly) fullscreen IME less jarring. Note that when
- * this flag is specified the IME may <em>not</em> be set up to be able
- * to display text, so it should only be used in situations where this is
- * not needed.
+ * of the application be shown behind, through transparent UI parts in the
+ * fullscreen IME. The part of the UI visible to the user may not be responsive
+ * to touch because the IME will receive touch events, which may confuse the
+ * user; use {@link #IME_FLAG_NO_FULLSCREEN} instead for a better experience.
+ * Using this flag is discouraged and it may become deprecated in the future.
+ * Its meaning is unclear in some situations and it may not work appropriately
+ * on older versions of the platform.
*/
public static final int IME_FLAG_NO_EXTRACT_UI = 0x10000000;
/**
- * Flag of {@link #imeOptions}: used in conjunction with
- * {@link #IME_MASK_ACTION}, this indicates that the action should not
- * be available as an accessory button when the input method is full-screen.
- * Note that by setting this flag, there can be cases where the action
- * is simply never available to the user. Setting this generally means
- * that you think showing text being edited is more important than the
- * action you have supplied.
+ * Flag of {@link #imeOptions}: used in conjunction with one of the actions
+ * masked by {@link #IME_MASK_ACTION}, this indicates that the action
+ * should not be available as an accessory button on the right of the extracted
+ * text when the input method is full-screen. Note that by setting this flag,
+ * there can be cases where the action is simply never available to the
+ * user. Setting this generally means that you think that in fullscreen mode,
+ * where there is little space to show the text, it's not worth taking some
+ * screen real estate to display the action and it should be used instead
+ * to show more text.
*/
public static final int IME_FLAG_NO_ACCESSORY_ACTION = 0x20000000;
/**
- * Flag of {@link #imeOptions}: used in conjunction with
- * {@link #IME_MASK_ACTION}, this indicates that the action should not
- * be available in-line as a replacement for "enter" key. Typically this is
- * because the action has such a significant impact or is not recoverable
- * enough that accidentally hitting it should be avoided, such as sending
- * a message. Note that {@link android.widget.TextView} will automatically set this
- * flag for you on multi-line text views.
+ * Flag of {@link #imeOptions}: used in conjunction with one of the actions
+ * masked by {@link #IME_MASK_ACTION}. If this flag is not set, IMEs will
+ * normally replace the "enter" key with the action supplied. This flag
+ * indicates that the action should not be available in-line as a replacement
+ * for the "enter" key. Typically this is because the action has such a
+ * significant impact or is not recoverable enough that accidentally hitting
+ * it should be avoided, such as sending a message. Note that
+ * {@link android.widget.TextView} will automatically set this flag for you
+ * on multi-line text views.
*/
public static final int IME_FLAG_NO_ENTER_ACTION = 0x40000000;
/**
- * Flag of {@link #imeOptions}: used to request that the IME is capable of
+ * Flag of {@link #imeOptions}: used to request an IME that is capable of
* inputting ASCII characters. The intention of this flag is to ensure that
- * the user can type Roman alphabet characters in a {@link android.widget.TextView}
- * used for, typically, account ID or password input. It is expected that IMEs
- * normally are able to input ASCII even without being told so (such IMEs
- * already respect this flag in a sense), but there could be some cases they
- * aren't when, for instance, only non-ASCII input languagaes like Arabic,
- * Greek, Hebrew, Russian are enabled in the IME. Applications need to be
- * aware that the flag is not a guarantee, and not all IMEs will respect it.
+ * the user can type Roman alphabet characters in a {@link android.widget.TextView}.
+ * It is typically used for an account ID or password input. A lot of the time,
+ * IMEs are already able to input ASCII even without being told so (such IMEs
+ * already respect this flag in a sense), but there are cases when this is not
+ * the default. For instance, users of languages using a different script like
+ * Arabic, Greek, Hebrew or Russian typically have a keyboard that can't
+ * input ASCII characters by default. Applications need to be
+ * aware that the flag is not a guarantee, and some IMEs may not respect it.
* However, it is strongly recommended for IME authors to respect this flag
- * especially when their IME could end up with a state that has only non-ASCII
- * input languages enabled.
+ * especially when their IME could end up with a state where only languages
+ * using non-ASCII are enabled.
*/
public static final int IME_FLAG_FORCE_ASCII = 0x80000000;
@@ -209,8 +224,13 @@
/**
* In some cases an IME may be able to display an arbitrary label for
- * a command the user can perform, which you can specify here. You can
- * not count on this being used.
+ * a command the user can perform, which you can specify here. This is
+ * typically used as the label for the action to use in-line as a replacement
+ * for the "enter" key (see {@link #actionId}). Remember the key where
+ * this will be displayed is typically very small, and there are significant
+ * localization challenges to make this fit in all supported languages. Also
+ * you can not count absolutely on this being used, as some IMEs may
+ * ignore this.
*/
public CharSequence actionLabel = null;
@@ -224,13 +244,17 @@
/**
* The text offset of the start of the selection at the time editing
- * began; -1 if not known.
+ * began; -1 if not known. Keep in mind some IMEs may not be able
+ * to give their full feature set without knowing the cursor position;
+ * avoid passing -1 here if you can.
*/
public int initialSelStart = -1;
/**
* The text offset of the end of the selection at the time editing
- * began; -1 if not known.
+ * began; -1 if not known. Keep in mind some IMEs may not be able
+ * to give their full feature set without knowing the cursor position;
+ * avoid passing -1 here if you can.
*/
public int initialSelEnd = -1;
@@ -280,7 +304,7 @@
* Any extra data to supply to the input method. This is for extended
* communication with specific input methods; the name fields in the
* bundle should be scoped (such as "com.mydomain.im.SOME_FIELD") so
- * that they don't conflict with others. This field is can be
+ * that they don't conflict with others. This field can be
* filled in from the {@link android.R.attr#editorExtras}
* attribute of a TextView.
*/
diff --git a/core/java/android/view/inputmethod/InputConnection.java b/core/java/android/view/inputmethod/InputConnection.java
index 59330ca..3537aec 100644
--- a/core/java/android/view/inputmethod/InputConnection.java
+++ b/core/java/android/view/inputmethod/InputConnection.java
@@ -142,7 +142,11 @@
* conditions in implementing this call. An IME can make a change
* to the text and use this method right away; you need to make
* sure the returned value is consistent with the result of the
- * latest edits.
+ * latest edits. Also, you may return less than n characters if performance
+ * dictates so, but keep in mind IMEs are relying on this for many
+ * functions: you should not, for example, limit the returned value to
+ * the current line, and specifically do not return 0 characters unless
+ * the cursor is really at the start of the text.</p>
*
* @param n The expected length of the text.
* @param flags Supplies additional options controlling how the text is
@@ -176,7 +180,11 @@
* conditions in implementing this call. An IME can make a change
* to the text and use this method right away; you need to make
* sure the returned value is consistent with the result of the
- * latest edits.</p>
+ * latest edits. Also, you may return less than n characters if performance
+ * dictates so, but keep in mind IMEs are relying on this for many
+ * functions: you should not, for example, limit the returned value to
+ * the current line, and specifically do not return 0 characters unless
+ * the cursor is really at the end of the text.</p>
*
* @param n The expected length of the text.
* @param flags Supplies additional options controlling how the text is
diff --git a/core/java/android/view/inputmethod/InputMethodSubtype.java b/core/java/android/view/inputmethod/InputMethodSubtype.java
index 40f95ce..2ab3024 100644
--- a/core/java/android/view/inputmethod/InputMethodSubtype.java
+++ b/core/java/android/view/inputmethod/InputMethodSubtype.java
@@ -534,6 +534,13 @@
private static int hashCodeInternal(String locale, String mode, String extraValue,
boolean isAuxiliary, boolean overridesImplicitlyEnabledSubtype,
boolean isAsciiCapable) {
+ // CAVEAT: Must revisit how to compute needsToCalculateCompatibleHashCode when a new
+ // attribute is added in order to avoid enabled subtypes being unexpectedly disabled.
+ final boolean needsToCalculateCompatibleHashCode = !isAsciiCapable;
+ if (needsToCalculateCompatibleHashCode) {
+ return Arrays.hashCode(new Object[] {locale, mode, extraValue, isAuxiliary,
+ overridesImplicitlyEnabledSubtype});
+ }
return Arrays.hashCode(new Object[] {locale, mode, extraValue, isAuxiliary,
overridesImplicitlyEnabledSubtype, isAsciiCapable});
}
diff --git a/core/java/android/widget/ImageView.java b/core/java/android/widget/ImageView.java
index 9e35a23..7daf798 100644
--- a/core/java/android/widget/ImageView.java
+++ b/core/java/android/widget/ImageView.java
@@ -710,6 +710,7 @@
}
d.setLevel(mLevel);
d.setLayoutDirection(getLayoutDirection());
+ d.setVisible(getVisibility() == VISIBLE, true);
mDrawableWidth = d.getIntrinsicWidth();
mDrawableHeight = d.getIntrinsicHeight();
applyColorMod();
diff --git a/core/java/android/widget/VideoView.java b/core/java/android/widget/VideoView.java
index fbdf318..d57b739 100644
--- a/core/java/android/widget/VideoView.java
+++ b/core/java/android/widget/VideoView.java
@@ -56,7 +56,17 @@
* can load images from various sources (such as resources or content
* providers), takes care of computing its measurement from the video so that
* it can be used in any layout manager, and provides various display options
- * such as scaling and tinting.
+ * such as scaling and tinting.<p>
+ *
+ * <em>Note: VideoView does not retain its full state when going into the
+ * background.</em> In particular, it does not restore the current play state,
+ * play position, selected tracks, or any subtitle tracks added via
+ * {@link #addSubtitleSource addSubtitleSource()}. Applications should
+ * save and restore these on their own in
+ * {@link android.app.Activity#onSaveInstanceState} and
+ * {@link android.app.Activity#onRestoreInstanceState}.<p>
+ * Also note that the audio session id (from {@link #getAudioSessionId}) may
+ * change from its previously returned value when the VideoView is restored.
*/
public class VideoView extends SurfaceView
implements MediaPlayerControl, SubtitleController.Anchor {
diff --git a/core/java/com/android/internal/app/IBatteryStats.aidl b/core/java/com/android/internal/app/IBatteryStats.aidl
index 525517c..43c4b49 100644
--- a/core/java/com/android/internal/app/IBatteryStats.aidl
+++ b/core/java/com/android/internal/app/IBatteryStats.aidl
@@ -68,6 +68,8 @@
void noteFullWifiLockReleasedFromSource(in WorkSource ws);
void noteWifiScanStartedFromSource(in WorkSource ws);
void noteWifiScanStoppedFromSource(in WorkSource ws);
+ void noteWifiBatchedScanStartedFromSource(in WorkSource ws, int csph);
+ void noteWifiBatchedScanStoppedFromSource(in WorkSource ws);
void noteWifiMulticastEnabledFromSource(in WorkSource ws);
void noteWifiMulticastDisabledFromSource(in WorkSource ws);
void noteNetworkInterfaceType(String iface, int type);
diff --git a/core/java/com/android/internal/app/MediaRouteChooserDialog.java b/core/java/com/android/internal/app/MediaRouteChooserDialog.java
new file mode 100644
index 0000000..47d2a9c
--- /dev/null
+++ b/core/java/com/android/internal/app/MediaRouteChooserDialog.java
@@ -0,0 +1,273 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.app;
+
+import com.android.internal.R;
+
+import android.app.Dialog;
+import android.content.Context;
+import android.media.MediaRouter;
+import android.media.MediaRouter.RouteInfo;
+import android.os.Bundle;
+import android.text.TextUtils;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.Window;
+import android.widget.AdapterView;
+import android.widget.ArrayAdapter;
+import android.widget.Button;
+import android.widget.ListView;
+import android.widget.TextView;
+
+import java.util.Comparator;
+
+/**
+ * This class implements the route chooser dialog for {@link MediaRouter}.
+ * <p>
+ * This dialog allows the user to choose a route that matches a given selector.
+ * </p>
+ *
+ * @see MediaRouteButton
+ * @see MediaRouteActionProvider
+ *
+ * TODO: Move this back into the API, as in the support library media router.
+ */
+public class MediaRouteChooserDialog extends Dialog {
+ private final MediaRouter mRouter;
+ private final MediaRouterCallback mCallback;
+
+ private int mRouteTypes;
+ private View.OnClickListener mExtendedSettingsClickListener;
+ private RouteAdapter mAdapter;
+ private ListView mListView;
+ private Button mExtendedSettingsButton;
+ private boolean mAttachedToWindow;
+
+ public MediaRouteChooserDialog(Context context, int theme) {
+ super(context, theme);
+
+ mRouter = (MediaRouter) context.getSystemService(Context.MEDIA_ROUTER_SERVICE);
+ mCallback = new MediaRouterCallback();
+ }
+
+ /**
+ * Gets the media route types for filtering the routes that the user can
+ * select using the media route chooser dialog.
+ *
+ * @return The route types.
+ */
+ public int getRouteTypes() {
+ return mRouteTypes;
+ }
+
+ /**
+ * Sets the types of routes that will be shown in the media route chooser dialog
+ * launched by this button.
+ *
+ * @param types The route types to match.
+ */
+ public void setRouteTypes(int types) {
+ if (mRouteTypes != types) {
+ mRouteTypes = types;
+
+ if (mAttachedToWindow) {
+ mRouter.removeCallback(mCallback);
+ mRouter.addCallback(types, mCallback,
+ MediaRouter.CALLBACK_FLAG_PERFORM_ACTIVE_SCAN);
+ }
+
+ refreshRoutes();
+ }
+ }
+
+ public void setExtendedSettingsClickListener(View.OnClickListener listener) {
+ if (listener != mExtendedSettingsClickListener) {
+ mExtendedSettingsClickListener = listener;
+ updateExtendedSettingsButton();
+ }
+ }
+
+ /**
+ * Returns true if the route should be included in the list.
+ * <p>
+ * The default implementation returns true for enabled non-default routes that
+ * match the route types. Subclasses can override this method to filter routes
+ * differently.
+ * </p>
+ *
+ * @param route The route to consider, never null.
+ * @return True if the route should be included in the chooser dialog.
+ */
+ public boolean onFilterRoute(MediaRouter.RouteInfo route) {
+ return !route.isDefault() && route.isEnabled() && route.matchesTypes(mRouteTypes);
+ }
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ getWindow().requestFeature(Window.FEATURE_LEFT_ICON);
+
+ setContentView(R.layout.media_route_chooser_dialog);
+ setTitle(mRouteTypes == MediaRouter.ROUTE_TYPE_REMOTE_DISPLAY
+ ? R.string.media_route_chooser_title_for_remote_display
+ : R.string.media_route_chooser_title);
+
+ // Must be called after setContentView.
+ getWindow().setFeatureDrawableResource(Window.FEATURE_LEFT_ICON,
+ R.drawable.ic_media_route_off_holo_dark);
+
+ mAdapter = new RouteAdapter(getContext());
+ mListView = (ListView)findViewById(R.id.media_route_list);
+ mListView.setAdapter(mAdapter);
+ mListView.setOnItemClickListener(mAdapter);
+ mListView.setEmptyView(findViewById(android.R.id.empty));
+
+ mExtendedSettingsButton = (Button)findViewById(R.id.media_route_extended_settings_button);
+ updateExtendedSettingsButton();
+ }
+
+ private void updateExtendedSettingsButton() {
+ if (mExtendedSettingsButton != null) {
+ mExtendedSettingsButton.setOnClickListener(mExtendedSettingsClickListener);
+ mExtendedSettingsButton.setVisibility(
+ mExtendedSettingsClickListener != null ? View.VISIBLE : View.GONE);
+ }
+ }
+
+ @Override
+ public void onAttachedToWindow() {
+ super.onAttachedToWindow();
+
+ mAttachedToWindow = true;
+ mRouter.addCallback(mRouteTypes, mCallback, MediaRouter.CALLBACK_FLAG_PERFORM_ACTIVE_SCAN);
+ refreshRoutes();
+ }
+
+ @Override
+ public void onDetachedFromWindow() {
+ mAttachedToWindow = false;
+ mRouter.removeCallback(mCallback);
+
+ super.onDetachedFromWindow();
+ }
+
+ /**
+ * Refreshes the list of routes that are shown in the chooser dialog.
+ */
+ public void refreshRoutes() {
+ if (mAttachedToWindow) {
+ mAdapter.update();
+ }
+ }
+
+ private final class RouteAdapter extends ArrayAdapter<MediaRouter.RouteInfo>
+ implements ListView.OnItemClickListener {
+ private final LayoutInflater mInflater;
+
+ public RouteAdapter(Context context) {
+ super(context, 0);
+ mInflater = LayoutInflater.from(context);
+ }
+
+ public void update() {
+ clear();
+ final int count = mRouter.getRouteCount();
+ for (int i = 0; i < count; i++) {
+ MediaRouter.RouteInfo route = mRouter.getRouteAt(i);
+ if (onFilterRoute(route)) {
+ add(route);
+ }
+ }
+ sort(RouteComparator.sInstance);
+ notifyDataSetChanged();
+ }
+
+ @Override
+ public boolean areAllItemsEnabled() {
+ return false;
+ }
+
+ @Override
+ public boolean isEnabled(int position) {
+ return getItem(position).isEnabled();
+ }
+
+ @Override
+ public View getView(int position, View convertView, ViewGroup parent) {
+ View view = convertView;
+ if (view == null) {
+ view = mInflater.inflate(R.layout.media_route_list_item, parent, false);
+ }
+ MediaRouter.RouteInfo route = getItem(position);
+ TextView text1 = (TextView)view.findViewById(android.R.id.text1);
+ TextView text2 = (TextView)view.findViewById(android.R.id.text2);
+ text1.setText(route.getName());
+ CharSequence description = route.getDescription();
+ if (TextUtils.isEmpty(description)) {
+ text2.setVisibility(View.GONE);
+ text2.setText("");
+ } else {
+ text2.setVisibility(View.VISIBLE);
+ text2.setText(description);
+ }
+ view.setEnabled(route.isEnabled());
+ return view;
+ }
+
+ @Override
+ public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
+ MediaRouter.RouteInfo route = getItem(position);
+ if (route.isEnabled()) {
+ route.select();
+ dismiss();
+ }
+ }
+ }
+
+ private final class MediaRouterCallback extends MediaRouter.SimpleCallback {
+ @Override
+ public void onRouteAdded(MediaRouter router, MediaRouter.RouteInfo info) {
+ refreshRoutes();
+ }
+
+ @Override
+ public void onRouteRemoved(MediaRouter router, MediaRouter.RouteInfo info) {
+ refreshRoutes();
+ }
+
+ @Override
+ public void onRouteChanged(MediaRouter router, MediaRouter.RouteInfo info) {
+ refreshRoutes();
+ }
+
+ @Override
+ public void onRouteSelected(MediaRouter router, int type, RouteInfo info) {
+ dismiss();
+ }
+ }
+
+ private static final class RouteComparator implements Comparator<MediaRouter.RouteInfo> {
+ public static final RouteComparator sInstance = new RouteComparator();
+
+ @Override
+ public int compare(MediaRouter.RouteInfo lhs, MediaRouter.RouteInfo rhs) {
+ return lhs.getName().toString().compareTo(rhs.getName().toString());
+ }
+ }
+}
diff --git a/core/java/com/android/internal/app/MediaRouteChooserDialogFragment.java b/core/java/com/android/internal/app/MediaRouteChooserDialogFragment.java
index e300021..ae362af 100644
--- a/core/java/com/android/internal/app/MediaRouteChooserDialogFragment.java
+++ b/core/java/com/android/internal/app/MediaRouteChooserDialogFragment.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2012 The Android Open Source Project
+ * Copyright (C) 2013 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -16,675 +16,86 @@
package com.android.internal.app;
-import com.android.internal.R;
-
-import android.app.Activity;
import android.app.Dialog;
import android.app.DialogFragment;
-import android.app.MediaRouteActionProvider;
-import android.app.MediaRouteButton;
import android.content.Context;
-import android.graphics.drawable.Drawable;
-import android.hardware.display.DisplayManager;
-import android.media.MediaRouter;
-import android.media.MediaRouter.RouteCategory;
-import android.media.MediaRouter.RouteGroup;
-import android.media.MediaRouter.RouteInfo;
import android.os.Bundle;
-import android.text.TextUtils;
-import android.view.KeyEvent;
-import android.view.LayoutInflater;
import android.view.View;
-import android.view.ViewGroup;
-import android.widget.AdapterView;
-import android.widget.BaseAdapter;
-import android.widget.CheckBox;
-import android.widget.Checkable;
-import android.widget.ImageButton;
-import android.widget.ImageView;
-import android.widget.ListView;
-import android.widget.SeekBar;
-import android.widget.TextView;
-
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.Comparator;
-import java.util.List;
+import android.view.View.OnClickListener;
/**
- * This class implements the route chooser dialog for {@link MediaRouter}.
+ * Media route chooser dialog fragment.
+ * <p>
+ * Creates a {@link MediaRouteChooserDialog}. The application may subclass
+ * this dialog fragment to customize the media route chooser dialog.
+ * </p>
*
- * @see MediaRouteButton
- * @see MediaRouteActionProvider
+ * TODO: Move this back into the API, as in the support library media router.
*/
public class MediaRouteChooserDialogFragment extends DialogFragment {
- private static final String TAG = "MediaRouteChooserDialogFragment";
- public static final String FRAGMENT_TAG = "android:MediaRouteChooserDialogFragment";
+ private final String ARGUMENT_ROUTE_TYPES = "routeTypes";
- private static final int[] ITEM_LAYOUTS = new int[] {
- R.layout.media_route_list_item_top_header,
- R.layout.media_route_list_item_section_header,
- R.layout.media_route_list_item,
- R.layout.media_route_list_item_checkable,
- R.layout.media_route_list_item_collapse_group
- };
+ private View.OnClickListener mExtendedSettingsClickListener;
- MediaRouter mRouter;
- private int mRouteTypes;
-
- private LayoutInflater mInflater;
- private LauncherListener mLauncherListener;
- private View.OnClickListener mExtendedSettingsListener;
- private RouteAdapter mAdapter;
- private ListView mListView;
- private SeekBar mVolumeSlider;
- private ImageView mVolumeIcon;
-
- final RouteComparator mComparator = new RouteComparator();
- final MediaRouterCallback mCallback = new MediaRouterCallback();
- private boolean mIgnoreSliderVolumeChanges;
- private boolean mIgnoreCallbackVolumeChanges;
-
+ /**
+ * Creates a media route chooser dialog fragment.
+ * <p>
+ * All subclasses of this class must also possess a default constructor.
+ * </p>
+ */
public MediaRouteChooserDialogFragment() {
- setStyle(STYLE_NO_TITLE, R.style.Theme_DeviceDefault_Dialog);
+ setCancelable(true);
+ setStyle(STYLE_NORMAL, android.R.style.Theme_DeviceDefault_Dialog);
}
- public void setLauncherListener(LauncherListener listener) {
- mLauncherListener = listener;
- }
-
- @Override
- public void onAttach(Activity activity) {
- super.onAttach(activity);
- mRouter = (MediaRouter) activity.getSystemService(Context.MEDIA_ROUTER_SERVICE);
- mRouter.addCallback(mRouteTypes, mCallback, MediaRouter.CALLBACK_FLAG_PERFORM_ACTIVE_SCAN);
- }
-
- @Override
- public void onDetach() {
- super.onDetach();
- if (mLauncherListener != null) {
- mLauncherListener.onDetached(this);
- }
- if (mAdapter != null) {
- mAdapter = null;
- }
- mInflater = null;
- mRouter.removeCallback(mCallback);
- mRouter = null;
- }
-
- public void setExtendedSettingsClickListener(View.OnClickListener listener) {
- mExtendedSettingsListener = listener;
+ public int getRouteTypes() {
+ Bundle args = getArguments();
+ return args != null ? args.getInt(ARGUMENT_ROUTE_TYPES) : 0;
}
public void setRouteTypes(int types) {
- mRouteTypes = types;
- }
-
- void updateVolume() {
- if (mRouter == null) return;
-
- final RouteInfo selectedRoute = mRouter.getSelectedRoute(mRouteTypes);
- mVolumeIcon.setImageResource(selectedRoute == null ||
- selectedRoute.getPlaybackType() == RouteInfo.PLAYBACK_TYPE_LOCAL ?
- R.drawable.ic_audio_vol : R.drawable.ic_media_route_on_holo_dark);
-
- mIgnoreSliderVolumeChanges = true;
-
- if (selectedRoute == null ||
- selectedRoute.getVolumeHandling() == RouteInfo.PLAYBACK_VOLUME_FIXED) {
- // Disable the slider and show it at max volume.
- mVolumeSlider.setMax(1);
- mVolumeSlider.setProgress(1);
- mVolumeSlider.setEnabled(false);
- } else {
- mVolumeSlider.setEnabled(true);
- mVolumeSlider.setMax(selectedRoute.getVolumeMax());
- mVolumeSlider.setProgress(selectedRoute.getVolume());
- }
-
- mIgnoreSliderVolumeChanges = false;
- }
-
- void changeVolume(int newValue) {
- if (mIgnoreSliderVolumeChanges) return;
-
- final RouteInfo selectedRoute = mRouter.getSelectedRoute(mRouteTypes);
- if (selectedRoute != null &&
- selectedRoute.getVolumeHandling() == RouteInfo.PLAYBACK_VOLUME_VARIABLE) {
- final int maxVolume = selectedRoute.getVolumeMax();
- newValue = Math.max(0, Math.min(newValue, maxVolume));
- selectedRoute.requestSetVolume(newValue);
- }
- }
-
- @Override
- public View onCreateView(LayoutInflater inflater, ViewGroup container,
- Bundle savedInstanceState) {
- mInflater = inflater;
- final View layout = inflater.inflate(R.layout.media_route_chooser_layout, container, false);
-
- mVolumeIcon = (ImageView) layout.findViewById(R.id.volume_icon);
- mVolumeSlider = (SeekBar) layout.findViewById(R.id.volume_slider);
- updateVolume();
- mVolumeSlider.setOnSeekBarChangeListener(new VolumeSliderChangeListener());
-
- if (mExtendedSettingsListener != null) {
- final View extendedSettingsButton = layout.findViewById(R.id.extended_settings);
- extendedSettingsButton.setVisibility(View.VISIBLE);
- extendedSettingsButton.setOnClickListener(mExtendedSettingsListener);
- }
-
- final ListView list = (ListView) layout.findViewById(R.id.list);
- list.setItemsCanFocus(true);
- list.setAdapter(mAdapter = new RouteAdapter());
- list.setOnItemClickListener(mAdapter);
-
- mListView = list;
-
- mAdapter.scrollToSelectedItem();
-
- return layout;
- }
-
- @Override
- public Dialog onCreateDialog(Bundle savedInstanceState) {
- return new RouteChooserDialog(getActivity(), getTheme());
- }
-
- private static class ViewHolder {
- public TextView text1;
- public TextView text2;
- public ImageView icon;
- public ImageButton expandGroupButton;
- public RouteAdapter.ExpandGroupListener expandGroupListener;
- public int position;
- public CheckBox check;
- }
-
- private class RouteAdapter extends BaseAdapter implements ListView.OnItemClickListener {
- private static final int VIEW_TOP_HEADER = 0;
- private static final int VIEW_SECTION_HEADER = 1;
- private static final int VIEW_ROUTE = 2;
- private static final int VIEW_GROUPING_ROUTE = 3;
- private static final int VIEW_GROUPING_DONE = 4;
-
- private int mSelectedItemPosition = -1;
- private final ArrayList<Object> mItems = new ArrayList<Object>();
-
- private RouteCategory mCategoryEditingGroups;
- private RouteGroup mEditingGroup;
-
- // Temporary lists for manipulation
- private final ArrayList<RouteInfo> mCatRouteList = new ArrayList<RouteInfo>();
- private final ArrayList<RouteInfo> mSortRouteList = new ArrayList<RouteInfo>();
-
- private boolean mIgnoreUpdates;
-
- RouteAdapter() {
- update();
- }
-
- void update() {
- /*
- * This is kind of wacky, but our data sets are going to be
- * fairly small on average. Ideally we should be able to do some of this stuff
- * in-place instead.
- *
- * Basic idea: each entry in mItems represents an item in the list for quick access.
- * Entries can be a RouteCategory (section header), a RouteInfo with a category of
- * mCategoryEditingGroups (a flattened RouteInfo pulled out of its group, allowing
- * the user to change the group),
- */
- if (mIgnoreUpdates) return;
-
- mItems.clear();
-
- final RouteInfo selectedRoute = mRouter.getSelectedRoute(mRouteTypes);
- mSelectedItemPosition = -1;
-
- List<RouteInfo> routes;
- final int catCount = mRouter.getCategoryCount();
- for (int i = 0; i < catCount; i++) {
- final RouteCategory cat = mRouter.getCategoryAt(i);
- routes = cat.getRoutes(mCatRouteList);
-
- if (!cat.isSystem()) {
- mItems.add(cat);
- }
-
- if (cat == mCategoryEditingGroups) {
- addGroupEditingCategoryRoutes(routes);
- } else {
- addSelectableRoutes(selectedRoute, routes);
- }
-
- routes.clear();
+ if (types != getRouteTypes()) {
+ Bundle args = getArguments();
+ if (args == null) {
+ args = new Bundle();
}
+ args.putInt(ARGUMENT_ROUTE_TYPES, types);
+ setArguments(args);
- notifyDataSetChanged();
- if (mListView != null && mSelectedItemPosition >= 0) {
- mListView.setItemChecked(mSelectedItemPosition, true);
- }
- }
-
- void scrollToEditingGroup() {
- if (mCategoryEditingGroups == null || mListView == null) return;
-
- int pos = 0;
- int bound = 0;
- final int itemCount = mItems.size();
- for (int i = 0; i < itemCount; i++) {
- final Object item = mItems.get(i);
- if (item != null && item == mCategoryEditingGroups) {
- bound = i;
- }
- if (item == null) {
- pos = i;
- break; // this is always below the category header; we can stop here.
- }
- }
-
- mListView.smoothScrollToPosition(pos, bound);
- }
-
- void scrollToSelectedItem() {
- if (mListView == null || mSelectedItemPosition < 0) return;
-
- mListView.smoothScrollToPosition(mSelectedItemPosition);
- }
-
- void addSelectableRoutes(RouteInfo selectedRoute, List<RouteInfo> from) {
- final int routeCount = from.size();
- for (int j = 0; j < routeCount; j++) {
- final RouteInfo info = from.get(j);
- if (info == selectedRoute) {
- mSelectedItemPosition = mItems.size();
- }
- mItems.add(info);
- }
- }
-
- void addGroupEditingCategoryRoutes(List<RouteInfo> from) {
- // Unpack groups and flatten for presentation
- // mSortRouteList will always be empty here.
- final int topCount = from.size();
- for (int i = 0; i < topCount; i++) {
- final RouteInfo route = from.get(i);
- final RouteGroup group = route.getGroup();
- if (group == route) {
- // This is a group, unpack it.
- final int groupCount = group.getRouteCount();
- for (int j = 0; j < groupCount; j++) {
- final RouteInfo innerRoute = group.getRouteAt(j);
- mSortRouteList.add(innerRoute);
- }
- } else {
- mSortRouteList.add(route);
- }
- }
- // Sort by name. This will keep the route positions relatively stable even though they
- // will be repeatedly added and removed.
- Collections.sort(mSortRouteList, mComparator);
-
- mItems.addAll(mSortRouteList);
- mSortRouteList.clear();
-
- mItems.add(null); // Sentinel reserving space for the "done" button.
- }
-
- @Override
- public int getCount() {
- return mItems.size();
- }
-
- @Override
- public int getViewTypeCount() {
- return 5;
- }
-
- @Override
- public int getItemViewType(int position) {
- final Object item = getItem(position);
- if (item instanceof RouteCategory) {
- return position == 0 ? VIEW_TOP_HEADER : VIEW_SECTION_HEADER;
- } else if (item == null) {
- return VIEW_GROUPING_DONE;
- } else {
- final RouteInfo info = (RouteInfo) item;
- if (info.getCategory() == mCategoryEditingGroups) {
- return VIEW_GROUPING_ROUTE;
- }
- return VIEW_ROUTE;
- }
- }
-
- @Override
- public boolean areAllItemsEnabled() {
- return false;
- }
-
- @Override
- public boolean isEnabled(int position) {
- switch (getItemViewType(position)) {
- case VIEW_ROUTE:
- return ((RouteInfo) mItems.get(position)).isEnabled();
- case VIEW_GROUPING_ROUTE:
- case VIEW_GROUPING_DONE:
- return true;
- default:
- return false;
- }
- }
-
- @Override
- public Object getItem(int position) {
- return mItems.get(position);
- }
-
- @Override
- public long getItemId(int position) {
- return position;
- }
-
- @Override
- public View getView(int position, View convertView, ViewGroup parent) {
- final int viewType = getItemViewType(position);
-
- ViewHolder holder;
- if (convertView == null) {
- convertView = mInflater.inflate(ITEM_LAYOUTS[viewType], parent, false);
- holder = new ViewHolder();
- holder.position = position;
- holder.text1 = (TextView) convertView.findViewById(R.id.text1);
- holder.text2 = (TextView) convertView.findViewById(R.id.text2);
- holder.icon = (ImageView) convertView.findViewById(R.id.icon);
- holder.check = (CheckBox) convertView.findViewById(R.id.check);
- holder.expandGroupButton = (ImageButton) convertView.findViewById(
- R.id.expand_button);
- if (holder.expandGroupButton != null) {
- holder.expandGroupListener = new ExpandGroupListener();
- holder.expandGroupButton.setOnClickListener(holder.expandGroupListener);
- }
-
- final View fview = convertView;
- final ListView list = (ListView) parent;
- final ViewHolder fholder = holder;
- convertView.setOnClickListener(new View.OnClickListener() {
- @Override public void onClick(View v) {
- list.performItemClick(fview, fholder.position, 0);
- }
- });
- convertView.setTag(holder);
- } else {
- holder = (ViewHolder) convertView.getTag();
- holder.position = position;
- }
-
- switch (viewType) {
- case VIEW_ROUTE:
- case VIEW_GROUPING_ROUTE:
- bindItemView(position, holder);
- break;
- case VIEW_SECTION_HEADER:
- case VIEW_TOP_HEADER:
- bindHeaderView(position, holder);
- break;
- }
-
- convertView.setActivated(position == mSelectedItemPosition);
- convertView.setEnabled(isEnabled(position));
-
- return convertView;
- }
-
- void bindItemView(int position, ViewHolder holder) {
- RouteInfo info = (RouteInfo) mItems.get(position);
- holder.text1.setText(info.getName(getActivity()));
- final CharSequence status = info.getStatus();
- if (TextUtils.isEmpty(status)) {
- holder.text2.setVisibility(View.GONE);
- } else {
- holder.text2.setVisibility(View.VISIBLE);
- holder.text2.setText(status);
- }
- Drawable icon = info.getIconDrawable();
- if (icon != null) {
- // Make sure we have a fresh drawable where it doesn't matter if we mutate it
- icon = icon.getConstantState().newDrawable(getResources());
- }
- holder.icon.setImageDrawable(icon);
- holder.icon.setVisibility(icon != null ? View.VISIBLE : View.GONE);
-
- RouteCategory cat = info.getCategory();
- boolean canGroup = false;
- if (cat == mCategoryEditingGroups) {
- RouteGroup group = info.getGroup();
- holder.check.setEnabled(group.getRouteCount() > 1);
- holder.check.setChecked(group == mEditingGroup);
- } else {
- if (cat.isGroupable()) {
- final RouteGroup group = (RouteGroup) info;
- canGroup = group.getRouteCount() > 1 ||
- getItemViewType(position - 1) == VIEW_ROUTE ||
- (position < getCount() - 1 &&
- getItemViewType(position + 1) == VIEW_ROUTE);
- }
- }
-
- if (holder.expandGroupButton != null) {
- holder.expandGroupButton.setVisibility(canGroup ? View.VISIBLE : View.GONE);
- holder.expandGroupListener.position = position;
- }
- }
-
- void bindHeaderView(int position, ViewHolder holder) {
- RouteCategory cat = (RouteCategory) mItems.get(position);
- holder.text1.setText(cat.getName(getActivity()));
- }
-
- @Override
- public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
- final int type = getItemViewType(position);
- if (type == VIEW_SECTION_HEADER || type == VIEW_TOP_HEADER) {
- return;
- } else if (type == VIEW_GROUPING_DONE) {
- finishGrouping();
- return;
- } else {
- final Object item = getItem(position);
- if (!(item instanceof RouteInfo)) {
- // Oops. Stale event running around? Skip it.
- return;
- }
-
- final RouteInfo route = (RouteInfo) item;
- if (type == VIEW_ROUTE) {
- mRouter.selectRouteInt(mRouteTypes, route);
- dismiss();
- } else if (type == VIEW_GROUPING_ROUTE) {
- final Checkable c = (Checkable) view;
- final boolean wasChecked = c.isChecked();
-
- mIgnoreUpdates = true;
- RouteGroup oldGroup = route.getGroup();
- if (!wasChecked && oldGroup != mEditingGroup) {
- // Assumption: in a groupable category oldGroup will never be null.
- if (mRouter.getSelectedRoute(mRouteTypes) == oldGroup) {
- // Old group was selected but is now empty. Select the group
- // we're manipulating since that's where the last route went.
- mRouter.selectRouteInt(mRouteTypes, mEditingGroup);
- }
- oldGroup.removeRoute(route);
- mEditingGroup.addRoute(route);
- c.setChecked(true);
- } else if (wasChecked && mEditingGroup.getRouteCount() > 1) {
- mEditingGroup.removeRoute(route);
-
- // In a groupable category this will add
- // the route into its own new group.
- mRouter.addRouteInt(route);
- }
- mIgnoreUpdates = false;
- update();
- }
- }
- }
-
- boolean isGrouping() {
- return mCategoryEditingGroups != null;
- }
-
- void finishGrouping() {
- mCategoryEditingGroups = null;
- mEditingGroup = null;
- getDialog().setCanceledOnTouchOutside(true);
- update();
- scrollToSelectedItem();
- }
-
- class ExpandGroupListener implements View.OnClickListener {
- int position;
-
- @Override
- public void onClick(View v) {
- // Assumption: this is only available for the user to click if we're presenting
- // a groupable category, where every top-level route in the category is a group.
- final RouteGroup group = (RouteGroup) getItem(position);
- mEditingGroup = group;
- mCategoryEditingGroups = group.getCategory();
- getDialog().setCanceledOnTouchOutside(false);
- mRouter.selectRouteInt(mRouteTypes, mEditingGroup);
- update();
- scrollToEditingGroup();
+ MediaRouteChooserDialog dialog = (MediaRouteChooserDialog)getDialog();
+ if (dialog != null) {
+ dialog.setRouteTypes(types);
}
}
}
- class MediaRouterCallback extends MediaRouter.Callback {
- @Override
- public void onRouteSelected(MediaRouter router, int type, RouteInfo info) {
- mAdapter.update();
- updateVolume();
- }
+ public void setExtendedSettingsClickListener(View.OnClickListener listener) {
+ if (listener != mExtendedSettingsClickListener) {
+ mExtendedSettingsClickListener = listener;
- @Override
- public void onRouteUnselected(MediaRouter router, int type, RouteInfo info) {
- mAdapter.update();
- }
-
- @Override
- public void onRouteAdded(MediaRouter router, RouteInfo info) {
- mAdapter.update();
- }
-
- @Override
- public void onRouteRemoved(MediaRouter router, RouteInfo info) {
- if (info == mAdapter.mEditingGroup) {
- mAdapter.finishGrouping();
- }
- mAdapter.update();
- }
-
- @Override
- public void onRouteChanged(MediaRouter router, RouteInfo info) {
- mAdapter.notifyDataSetChanged();
- }
-
- @Override
- public void onRouteGrouped(MediaRouter router, RouteInfo info,
- RouteGroup group, int index) {
- mAdapter.update();
- }
-
- @Override
- public void onRouteUngrouped(MediaRouter router, RouteInfo info, RouteGroup group) {
- mAdapter.update();
- }
-
- @Override
- public void onRouteVolumeChanged(MediaRouter router, RouteInfo info) {
- if (!mIgnoreCallbackVolumeChanges) {
- updateVolume();
- }
- }
- }
-
- class RouteComparator implements Comparator<RouteInfo> {
- @Override
- public int compare(RouteInfo lhs, RouteInfo rhs) {
- return lhs.getName(getActivity()).toString()
- .compareTo(rhs.getName(getActivity()).toString());
- }
- }
-
- class RouteChooserDialog extends Dialog {
- public RouteChooserDialog(Context context, int theme) {
- super(context, theme);
- }
-
- @Override
- public void onBackPressed() {
- if (mAdapter != null && mAdapter.isGrouping()) {
- mAdapter.finishGrouping();
- } else {
- super.onBackPressed();
- }
- }
-
- public boolean onKeyDown(int keyCode, KeyEvent event) {
- if (keyCode == KeyEvent.KEYCODE_VOLUME_DOWN && mVolumeSlider.isEnabled()) {
- final RouteInfo selectedRoute = mRouter.getSelectedRoute(mRouteTypes);
- if (selectedRoute != null) {
- selectedRoute.requestUpdateVolume(-1);
- return true;
- }
- } else if (keyCode == KeyEvent.KEYCODE_VOLUME_UP && mVolumeSlider.isEnabled()) {
- final RouteInfo selectedRoute = mRouter.getSelectedRoute(mRouteTypes);
- if (selectedRoute != null) {
- mRouter.getSelectedRoute(mRouteTypes).requestUpdateVolume(1);
- return true;
- }
- }
- return super.onKeyDown(keyCode, event);
- }
-
- public boolean onKeyUp(int keyCode, KeyEvent event) {
- if (keyCode == KeyEvent.KEYCODE_VOLUME_DOWN && mVolumeSlider.isEnabled()) {
- return true;
- } else if (keyCode == KeyEvent.KEYCODE_VOLUME_UP && mVolumeSlider.isEnabled()) {
- return true;
- } else {
- return super.onKeyUp(keyCode, event);
+ MediaRouteChooserDialog dialog = (MediaRouteChooserDialog)getDialog();
+ if (dialog != null) {
+ dialog.setExtendedSettingsClickListener(listener);
}
}
}
/**
- * Implemented by the MediaRouteButton that launched this dialog
+ * Called when the chooser dialog is being created.
+ * <p>
+ * Subclasses may override this method to customize the dialog.
+ * </p>
*/
- public interface LauncherListener {
- public void onDetached(MediaRouteChooserDialogFragment detachedFragment);
+ public MediaRouteChooserDialog onCreateChooserDialog(
+ Context context, Bundle savedInstanceState) {
+ return new MediaRouteChooserDialog(context, getTheme());
}
- class VolumeSliderChangeListener implements SeekBar.OnSeekBarChangeListener {
-
- @Override
- public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
- changeVolume(progress);
- }
-
- @Override
- public void onStartTrackingTouch(SeekBar seekBar) {
- mIgnoreCallbackVolumeChanges = true;
- }
-
- @Override
- public void onStopTrackingTouch(SeekBar seekBar) {
- mIgnoreCallbackVolumeChanges = false;
- updateVolume();
- }
-
+ @Override
+ public Dialog onCreateDialog(Bundle savedInstanceState) {
+ MediaRouteChooserDialog dialog = onCreateChooserDialog(getActivity(), savedInstanceState);
+ dialog.setRouteTypes(getRouteTypes());
+ dialog.setExtendedSettingsClickListener(mExtendedSettingsClickListener);
+ return dialog;
}
}
diff --git a/core/java/com/android/internal/app/MediaRouteControllerDialog.java b/core/java/com/android/internal/app/MediaRouteControllerDialog.java
new file mode 100644
index 0000000..8fc99c7
--- /dev/null
+++ b/core/java/com/android/internal/app/MediaRouteControllerDialog.java
@@ -0,0 +1,318 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.app;
+
+import com.android.internal.R;
+
+import android.app.Dialog;
+import android.app.MediaRouteActionProvider;
+import android.app.MediaRouteButton;
+import android.content.Context;
+import android.graphics.drawable.Drawable;
+import android.media.MediaRouter;
+import android.media.MediaRouter.RouteGroup;
+import android.media.MediaRouter.RouteInfo;
+import android.os.Bundle;
+import android.view.KeyEvent;
+import android.view.View;
+import android.view.Window;
+import android.widget.Button;
+import android.widget.FrameLayout;
+import android.widget.LinearLayout;
+import android.widget.SeekBar;
+
+/**
+ * This class implements the route controller dialog for {@link MediaRouter}.
+ * <p>
+ * This dialog allows the user to control or disconnect from the currently selected route.
+ * </p>
+ *
+ * @see MediaRouteButton
+ * @see MediaRouteActionProvider
+ *
+ * TODO: Move this back into the API, as in the support library media router.
+ */
+public class MediaRouteControllerDialog extends Dialog {
+ // Time to wait before updating the volume when the user lets go of the seek bar
+ // to allow the route provider time to propagate the change and publish a new
+ // route descriptor.
+ private static final int VOLUME_UPDATE_DELAY_MILLIS = 250;
+
+ private final MediaRouter mRouter;
+ private final MediaRouterCallback mCallback;
+ private final MediaRouter.RouteInfo mRoute;
+
+ private boolean mCreated;
+ private Drawable mMediaRouteConnectingDrawable;
+ private Drawable mMediaRouteOnDrawable;
+ private Drawable mCurrentIconDrawable;
+
+ private boolean mVolumeControlEnabled = true;
+ private LinearLayout mVolumeLayout;
+ private SeekBar mVolumeSlider;
+ private boolean mVolumeSliderTouched;
+
+ private View mControlView;
+
+ private Button mDisconnectButton;
+
+ public MediaRouteControllerDialog(Context context, int theme) {
+ super(context, theme);
+
+ mRouter = (MediaRouter) context.getSystemService(Context.MEDIA_ROUTER_SERVICE);
+ mCallback = new MediaRouterCallback();
+ mRoute = mRouter.getSelectedRoute();
+ }
+
+ /**
+ * Gets the route that this dialog is controlling.
+ */
+ public MediaRouter.RouteInfo getRoute() {
+ return mRoute;
+ }
+
+ /**
+ * Provides the subclass an opportunity to create a view that will
+ * be included within the body of the dialog to offer additional media controls
+ * for the currently playing content.
+ *
+ * @param savedInstanceState The dialog's saved instance state.
+ * @return The media control view, or null if none.
+ */
+ public View onCreateMediaControlView(Bundle savedInstanceState) {
+ return null;
+ }
+
+ /**
+ * Gets the media control view that was created by {@link #onCreateMediaControlView(Bundle)}.
+ *
+ * @return The media control view, or null if none.
+ */
+ public View getMediaControlView() {
+ return mControlView;
+ }
+
+ /**
+ * Sets whether to enable the volume slider and volume control using the volume keys
+ * when the route supports it.
+ * <p>
+ * The default value is true.
+ * </p>
+ */
+ public void setVolumeControlEnabled(boolean enable) {
+ if (mVolumeControlEnabled != enable) {
+ mVolumeControlEnabled = enable;
+ if (mCreated) {
+ updateVolume();
+ }
+ }
+ }
+
+ /**
+ * Returns whether to enable the volume slider and volume control using the volume keys
+ * when the route supports it.
+ */
+ public boolean isVolumeControlEnabled() {
+ return mVolumeControlEnabled;
+ }
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ getWindow().requestFeature(Window.FEATURE_LEFT_ICON);
+
+ setContentView(R.layout.media_route_controller_dialog);
+
+ mVolumeLayout = (LinearLayout)findViewById(R.id.media_route_volume_layout);
+ mVolumeSlider = (SeekBar)findViewById(R.id.media_route_volume_slider);
+ mVolumeSlider.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
+ private final Runnable mStopTrackingTouch = new Runnable() {
+ @Override
+ public void run() {
+ if (mVolumeSliderTouched) {
+ mVolumeSliderTouched = false;
+ updateVolume();
+ }
+ }
+ };
+
+ @Override
+ public void onStartTrackingTouch(SeekBar seekBar) {
+ if (mVolumeSliderTouched) {
+ mVolumeSlider.removeCallbacks(mStopTrackingTouch);
+ } else {
+ mVolumeSliderTouched = true;
+ }
+ }
+
+ @Override
+ public void onStopTrackingTouch(SeekBar seekBar) {
+ // Defer resetting mVolumeSliderTouched to allow the media route provider
+ // a little time to settle into its new state and publish the final
+ // volume update.
+ mVolumeSlider.postDelayed(mStopTrackingTouch, VOLUME_UPDATE_DELAY_MILLIS);
+ }
+
+ @Override
+ public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
+ if (fromUser) {
+ mRoute.requestSetVolume(progress);
+ }
+ }
+ });
+
+ mDisconnectButton = (Button)findViewById(R.id.media_route_disconnect_button);
+ mDisconnectButton.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ if (mRoute.isSelected()) {
+ mRouter.getDefaultRoute().select();
+ }
+ dismiss();
+ }
+ });
+
+ mCreated = true;
+ if (update()) {
+ mControlView = onCreateMediaControlView(savedInstanceState);
+ FrameLayout controlFrame =
+ (FrameLayout)findViewById(R.id.media_route_control_frame);
+ if (mControlView != null) {
+ controlFrame.addView(mControlView);
+ controlFrame.setVisibility(View.VISIBLE);
+ } else {
+ controlFrame.setVisibility(View.GONE);
+ }
+ }
+ }
+
+
+ @Override
+ public void onAttachedToWindow() {
+ super.onAttachedToWindow();
+
+ mRouter.addCallback(0, mCallback, MediaRouter.CALLBACK_FLAG_UNFILTERED_EVENTS);
+ update();
+ }
+
+ @Override
+ public void onDetachedFromWindow() {
+ mRouter.removeCallback(mCallback);
+
+ super.onDetachedFromWindow();
+ }
+
+ @Override
+ public boolean onKeyDown(int keyCode, KeyEvent event) {
+ if (keyCode == KeyEvent.KEYCODE_VOLUME_DOWN
+ || keyCode == KeyEvent.KEYCODE_VOLUME_UP) {
+ mRoute.requestUpdateVolume(keyCode == KeyEvent.KEYCODE_VOLUME_DOWN ? -1 : 1);
+ return true;
+ }
+ return super.onKeyDown(keyCode, event);
+ }
+
+ @Override
+ public boolean onKeyUp(int keyCode, KeyEvent event) {
+ if (keyCode == KeyEvent.KEYCODE_VOLUME_DOWN
+ || keyCode == KeyEvent.KEYCODE_VOLUME_UP) {
+ return true;
+ }
+ return super.onKeyUp(keyCode, event);
+ }
+
+ private boolean update() {
+ if (!mRoute.isSelected() || mRoute.isDefault()) {
+ dismiss();
+ return false;
+ }
+
+ setTitle(mRoute.getName());
+ updateVolume();
+
+ Drawable icon = getIconDrawable();
+ if (icon != mCurrentIconDrawable) {
+ mCurrentIconDrawable = icon;
+ getWindow().setFeatureDrawable(Window.FEATURE_LEFT_ICON, icon);
+ }
+ return true;
+ }
+
+ private Drawable getIconDrawable() {
+ if (mRoute.isConnecting()) {
+ if (mMediaRouteConnectingDrawable == null) {
+ mMediaRouteConnectingDrawable = getContext().getResources().getDrawable(
+ R.drawable.ic_media_route_connecting_holo_dark);
+ }
+ return mMediaRouteConnectingDrawable;
+ } else {
+ if (mMediaRouteOnDrawable == null) {
+ mMediaRouteOnDrawable = getContext().getResources().getDrawable(
+ R.drawable.ic_media_route_on_holo_dark);
+ }
+ return mMediaRouteOnDrawable;
+ }
+ }
+
+ private void updateVolume() {
+ if (!mVolumeSliderTouched) {
+ if (isVolumeControlAvailable()) {
+ mVolumeLayout.setVisibility(View.VISIBLE);
+ mVolumeSlider.setMax(mRoute.getVolumeMax());
+ mVolumeSlider.setProgress(mRoute.getVolume());
+ } else {
+ mVolumeLayout.setVisibility(View.GONE);
+ }
+ }
+ }
+
+ private boolean isVolumeControlAvailable() {
+ return mVolumeControlEnabled && mRoute.getVolumeHandling() ==
+ MediaRouter.RouteInfo.PLAYBACK_VOLUME_VARIABLE;
+ }
+
+ private final class MediaRouterCallback extends MediaRouter.SimpleCallback {
+ @Override
+ public void onRouteUnselected(MediaRouter router, int type, RouteInfo info) {
+ update();
+ }
+
+ @Override
+ public void onRouteChanged(MediaRouter router, MediaRouter.RouteInfo route) {
+ update();
+ }
+
+ @Override
+ public void onRouteVolumeChanged(MediaRouter router, MediaRouter.RouteInfo route) {
+ if (route == mRoute) {
+ updateVolume();
+ }
+ }
+
+ @Override
+ public void onRouteGrouped(MediaRouter router, RouteInfo info, RouteGroup group,
+ int index) {
+ update();
+ }
+
+ @Override
+ public void onRouteUngrouped(MediaRouter router, RouteInfo info, RouteGroup group) {
+ update();
+ }
+ }
+}
diff --git a/core/java/com/android/internal/app/MediaRouteControllerDialogFragment.java b/core/java/com/android/internal/app/MediaRouteControllerDialogFragment.java
new file mode 100644
index 0000000..108e81f
--- /dev/null
+++ b/core/java/com/android/internal/app/MediaRouteControllerDialogFragment.java
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.app;
+
+import android.app.Dialog;
+import android.app.DialogFragment;
+import android.content.Context;
+import android.os.Bundle;
+
+/**
+ * Media route controller dialog fragment.
+ * <p>
+ * Creates a {@link MediaRouteControllerDialog}. The application may subclass
+ * this dialog fragment to customize the media route controller dialog.
+ * </p>
+ *
+ * TODO: Move this back into the API, as in the support library media router.
+ */
+public class MediaRouteControllerDialogFragment extends DialogFragment {
+ /**
+ * Creates a media route controller dialog fragment.
+ * <p>
+ * All subclasses of this class must also possess a default constructor.
+ * </p>
+ */
+ public MediaRouteControllerDialogFragment() {
+ setCancelable(true);
+ setStyle(STYLE_NORMAL, android.R.style.Theme_DeviceDefault_Dialog);
+ }
+
+ /**
+ * Called when the controller dialog is being created.
+ * <p>
+ * Subclasses may override this method to customize the dialog.
+ * </p>
+ */
+ public MediaRouteControllerDialog onCreateControllerDialog(
+ Context context, Bundle savedInstanceState) {
+ return new MediaRouteControllerDialog(context, getTheme());
+ }
+
+ @Override
+ public Dialog onCreateDialog(Bundle savedInstanceState) {
+ return onCreateControllerDialog(getActivity(), savedInstanceState);
+ }
+}
diff --git a/core/java/com/android/internal/app/MediaRouteDialogPresenter.java b/core/java/com/android/internal/app/MediaRouteDialogPresenter.java
new file mode 100644
index 0000000..fad7fd4
--- /dev/null
+++ b/core/java/com/android/internal/app/MediaRouteDialogPresenter.java
@@ -0,0 +1,87 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.app;
+
+
+import android.app.Activity;
+import android.app.Dialog;
+import android.app.DialogFragment;
+import android.app.FragmentManager;
+import android.content.Context;
+import android.media.MediaRouter;
+import android.util.Log;
+import android.view.View;
+
+/**
+ * Shows media route dialog as appropriate.
+ * @hide
+ */
+public abstract class MediaRouteDialogPresenter {
+ private static final String TAG = "MediaRouter";
+
+ private static final String CHOOSER_FRAGMENT_TAG =
+ "android.app.MediaRouteButton:MediaRouteChooserDialogFragment";
+ private static final String CONTROLLER_FRAGMENT_TAG =
+ "android.app.MediaRouteButton:MediaRouteControllerDialogFragment";
+
+ public static DialogFragment showDialogFragment(Activity activity,
+ int routeTypes, View.OnClickListener extendedSettingsClickListener) {
+ final MediaRouter router = (MediaRouter)activity.getSystemService(
+ Context.MEDIA_ROUTER_SERVICE);
+ final FragmentManager fm = activity.getFragmentManager();
+
+ MediaRouter.RouteInfo route = router.getSelectedRoute();
+ if (route.isDefault() || !route.matchesTypes(routeTypes)) {
+ if (fm.findFragmentByTag(CHOOSER_FRAGMENT_TAG) != null) {
+ Log.w(TAG, "showDialog(): Route chooser dialog already showing!");
+ return null;
+ }
+ MediaRouteChooserDialogFragment f = new MediaRouteChooserDialogFragment();
+ f.setRouteTypes(routeTypes);
+ f.setExtendedSettingsClickListener(extendedSettingsClickListener);
+ f.show(fm, CHOOSER_FRAGMENT_TAG);
+ return f;
+ } else {
+ if (fm.findFragmentByTag(CONTROLLER_FRAGMENT_TAG) != null) {
+ Log.w(TAG, "showDialog(): Route controller dialog already showing!");
+ return null;
+ }
+ MediaRouteControllerDialogFragment f = new MediaRouteControllerDialogFragment();
+ f.show(fm, CONTROLLER_FRAGMENT_TAG);
+ return f;
+ }
+ }
+
+ public static Dialog createDialog(Context context,
+ int routeTypes, View.OnClickListener extendedSettingsClickListener) {
+ final MediaRouter router = (MediaRouter)context.getSystemService(
+ Context.MEDIA_ROUTER_SERVICE);
+
+ MediaRouter.RouteInfo route = router.getSelectedRoute();
+ if (route.isDefault() || !route.matchesTypes(routeTypes)) {
+ final MediaRouteChooserDialog d = new MediaRouteChooserDialog(
+ context, android.R.style.Theme_DeviceDefault_Dialog);
+ d.setRouteTypes(routeTypes);
+ d.setExtendedSettingsClickListener(extendedSettingsClickListener);
+ return d;
+ } else {
+ MediaRouteControllerDialog d = new MediaRouteControllerDialog(
+ context, android.R.style.Theme_DeviceDefault_Dialog);
+ return d;
+ }
+ }
+}
diff --git a/core/java/com/android/internal/app/ProcessStats.java b/core/java/com/android/internal/app/ProcessStats.java
index 20b8c95..0cad33c 100644
--- a/core/java/com/android/internal/app/ProcessStats.java
+++ b/core/java/com/android/internal/app/ProcessStats.java
@@ -1758,21 +1758,34 @@
mStartTime, now);
ArrayMap<String, SparseArray<PackageState>> pkgMap = mPackages.getMap();
boolean printedHeader = false;
+ boolean sepNeeded = false;
for (int ip=0; ip<pkgMap.size(); ip++) {
- String pkgName = pkgMap.keyAt(ip);
- if (reqPackage != null && !reqPackage.equals(pkgName)) {
- continue;
- }
- SparseArray<PackageState> uids = pkgMap.valueAt(ip);
+ final String pkgName = pkgMap.keyAt(ip);
+ final SparseArray<PackageState> uids = pkgMap.valueAt(ip);
for (int iu=0; iu<uids.size(); iu++) {
- int uid = uids.keyAt(iu);
- PackageState pkgState = uids.valueAt(iu);
+ final int uid = uids.keyAt(iu);
+ final PackageState pkgState = uids.valueAt(iu);
final int NPROCS = pkgState.mProcesses.size();
final int NSRVS = pkgState.mServices.size();
+ final boolean pkgMatch = reqPackage == null || reqPackage.equals(pkgName);
+ if (!pkgMatch) {
+ boolean procMatch = false;
+ for (int iproc=0; iproc<NPROCS; iproc++) {
+ ProcessState proc = pkgState.mProcesses.valueAt(iproc);
+ if (reqPackage.equals(proc.mName)) {
+ procMatch = true;
+ break;
+ }
+ }
+ if (!procMatch) {
+ continue;
+ }
+ }
if (NPROCS > 0 || NSRVS > 0) {
if (!printedHeader) {
pw.println("Per-Package Stats:");
printedHeader = true;
+ sepNeeded = true;
}
pw.print(" * "); pw.print(pkgName); pw.print(" / ");
UserHandle.formatUid(pw, uid); pw.println(":");
@@ -1780,6 +1793,9 @@
if (!dumpSummary || dumpAll) {
for (int iproc=0; iproc<NPROCS; iproc++) {
ProcessState proc = pkgState.mProcesses.valueAt(iproc);
+ if (!pkgMatch && !reqPackage.equals(proc.mName)) {
+ continue;
+ }
if (activeOnly && !proc.isInUse()) {
pw.print(" (Not active: ");
pw.print(pkgState.mProcesses.keyAt(iproc)); pw.println(")");
@@ -1787,7 +1803,11 @@
}
pw.print(" Process ");
pw.print(pkgState.mProcesses.keyAt(iproc));
- pw.print(" (");
+ if (proc.mCommonProcess.mMultiPackage) {
+ pw.print(" (multi, ");
+ } else {
+ pw.print(" (unique, ");
+ }
pw.print(proc.mDurationsTableSize);
pw.print(" entries)");
pw.println(":");
@@ -1801,6 +1821,9 @@
ArrayList<ProcessState> procs = new ArrayList<ProcessState>();
for (int iproc=0; iproc<NPROCS; iproc++) {
ProcessState proc = pkgState.mProcesses.valueAt(iproc);
+ if (!pkgMatch && !reqPackage.equals(proc.mName)) {
+ continue;
+ }
if (activeOnly && !proc.isInUse()) {
continue;
}
@@ -1811,6 +1834,9 @@
}
for (int isvc=0; isvc<NSRVS; isvc++) {
ServiceState svc = pkgState.mServices.valueAt(isvc);
+ if (!pkgMatch && !reqPackage.equals(svc.mProcessName)) {
+ continue;
+ }
if (activeOnly && !svc.isInUse()) {
pw.print(" (Not active: ");
pw.print(pkgState.mServices.keyAt(isvc)); pw.println(")");
@@ -1840,64 +1866,73 @@
if (svc.mOwner != null) {
pw.print(" mOwner="); pw.println(svc.mOwner);
}
+ if (svc.mStarted || svc.mRestarting) {
+ pw.print(" mStarted="); pw.print(svc.mStarted);
+ pw.print(" mRestarting="); pw.println(svc.mRestarting);
+ }
}
}
}
}
- if (reqPackage == null) {
- ArrayMap<String, SparseArray<ProcessState>> procMap = mProcesses.getMap();
- printedHeader = false;
- int numShownProcs = 0, numTotalProcs = 0;
- for (int ip=0; ip<procMap.size(); ip++) {
- String procName = procMap.keyAt(ip);
- SparseArray<ProcessState> uids = procMap.valueAt(ip);
- for (int iu=0; iu<uids.size(); iu++) {
- int uid = uids.keyAt(iu);
- numTotalProcs++;
- ProcessState proc = uids.valueAt(iu);
- if (proc.mDurationsTableSize == 0 && proc.mCurState == STATE_NOTHING
- && proc.mPssTableSize == 0) {
- continue;
- }
- numShownProcs++;
- if (!printedHeader) {
- pw.println();
- pw.println("Per-Process Stats:");
- printedHeader = true;
- }
- if (activeOnly && !proc.isInUse()) {
- pw.print(" (Not active: "); pw.print(procName); pw.println(")");
- continue;
- }
- pw.print(" * "); pw.print(procName); pw.print(" / ");
- UserHandle.formatUid(pw, uid);
- pw.print(" ("); pw.print(proc.mDurationsTableSize);
- pw.print(" entries)"); pw.println(":");
- dumpProcessState(pw, " ", proc, ALL_SCREEN_ADJ, ALL_MEM_ADJ,
- ALL_PROC_STATES, now);
- dumpProcessPss(pw, " ", proc, ALL_SCREEN_ADJ, ALL_MEM_ADJ,
- ALL_PROC_STATES);
- if (dumpAll) {
- dumpProcessInternalLocked(pw, " ", proc, dumpAll);
- }
+ ArrayMap<String, SparseArray<ProcessState>> procMap = mProcesses.getMap();
+ printedHeader = false;
+ int numShownProcs = 0, numTotalProcs = 0;
+ for (int ip=0; ip<procMap.size(); ip++) {
+ String procName = procMap.keyAt(ip);
+ SparseArray<ProcessState> uids = procMap.valueAt(ip);
+ for (int iu=0; iu<uids.size(); iu++) {
+ int uid = uids.keyAt(iu);
+ numTotalProcs++;
+ ProcessState proc = uids.valueAt(iu);
+ if (proc.mDurationsTableSize == 0 && proc.mCurState == STATE_NOTHING
+ && proc.mPssTableSize == 0) {
+ continue;
}
+ if (!proc.mMultiPackage) {
+ continue;
+ }
+ if (reqPackage != null && !reqPackage.equals(procName)
+ && !reqPackage.equals(proc.mPackage)) {
+ continue;
+ }
+ numShownProcs++;
+ if (sepNeeded) {
+ pw.println();
+ }
+ sepNeeded = true;
+ if (!printedHeader) {
+ pw.println("Multi-Package Common Processes:");
+ printedHeader = true;
+ }
+ if (activeOnly && !proc.isInUse()) {
+ pw.print(" (Not active: "); pw.print(procName); pw.println(")");
+ continue;
+ }
+ pw.print(" * "); pw.print(procName); pw.print(" / ");
+ UserHandle.formatUid(pw, uid);
+ pw.print(" ("); pw.print(proc.mDurationsTableSize);
+ pw.print(" entries)"); pw.println(":");
+ dumpProcessState(pw, " ", proc, ALL_SCREEN_ADJ, ALL_MEM_ADJ,
+ ALL_PROC_STATES, now);
+ dumpProcessPss(pw, " ", proc, ALL_SCREEN_ADJ, ALL_MEM_ADJ,
+ ALL_PROC_STATES);
+ dumpProcessInternalLocked(pw, " ", proc, dumpAll);
}
- if (dumpAll) {
- pw.println();
- pw.print(" Total procs: "); pw.print(numShownProcs);
- pw.print(" shown of "); pw.print(numTotalProcs); pw.println(" total");
- }
+ }
+ if (dumpAll) {
+ pw.println();
+ pw.print(" Total procs: "); pw.print(numShownProcs);
+ pw.print(" shown of "); pw.print(numTotalProcs); pw.println(" total");
+ }
+ if (sepNeeded) {
pw.println();
- if (dumpSummary) {
- pw.println("Summary:");
- dumpSummaryLocked(pw, reqPackage, now, activeOnly);
- } else {
- dumpTotalsLocked(pw, now);
- }
+ }
+ if (dumpSummary) {
+ pw.println("Summary:");
+ dumpSummaryLocked(pw, reqPackage, now, activeOnly);
} else {
- pw.println();
dumpTotalsLocked(pw, now);
}
@@ -2031,17 +2066,20 @@
public ArrayList<ProcessState> collectProcessesLocked(int[] screenStates, int[] memStates,
int[] procStates, int sortProcStates[], long now, String reqPackage,
boolean activeOnly) {
- ArraySet<ProcessState> foundProcs = new ArraySet<ProcessState>();
- ArrayMap<String, SparseArray<PackageState>> pkgMap = mPackages.getMap();
+ final ArraySet<ProcessState> foundProcs = new ArraySet<ProcessState>();
+ final ArrayMap<String, SparseArray<PackageState>> pkgMap = mPackages.getMap();
for (int ip=0; ip<pkgMap.size(); ip++) {
- if (reqPackage != null && !reqPackage.equals(pkgMap.keyAt(ip))) {
- continue;
- }
- SparseArray<PackageState> procs = pkgMap.valueAt(ip);
+ final String pkgName = pkgMap.keyAt(ip);
+ final SparseArray<PackageState> procs = pkgMap.valueAt(ip);
for (int iu=0; iu<procs.size(); iu++) {
- PackageState state = procs.valueAt(iu);
- for (int iproc=0; iproc<state.mProcesses.size(); iproc++) {
- ProcessState proc = state.mProcesses.valueAt(iproc);
+ final PackageState state = procs.valueAt(iu);
+ final int NPROCS = state.mProcesses.size();
+ final boolean pkgMatch = reqPackage == null || reqPackage.equals(pkgName);
+ for (int iproc=0; iproc<NPROCS; iproc++) {
+ final ProcessState proc = state.mProcesses.valueAt(iproc);
+ if (!pkgMatch && !reqPackage.equals(proc.mName)) {
+ continue;
+ }
if (activeOnly && !proc.isInUse()) {
continue;
}
@@ -2601,23 +2639,35 @@
}
}
- void incStartedServices(int memFactor, long now) {
+ void incStartedServices(int memFactor, long now, String serviceName) {
+ if (false) {
+ RuntimeException here = new RuntimeException("here");
+ here.fillInStackTrace();
+ Slog.d(TAG, "incStartedServices: " + this + " service=" + serviceName
+ + " to " + (mNumStartedServices+1), here);
+ }
if (mCommonProcess != this) {
- mCommonProcess.incStartedServices(memFactor, now);
+ mCommonProcess.incStartedServices(memFactor, now, serviceName);
}
mNumStartedServices++;
if (mNumStartedServices == 1 && mCurState == STATE_NOTHING) {
- setState(STATE_NOTHING, memFactor, now, null);
+ setState(STATE_SERVICE_RESTARTING + (memFactor*STATE_COUNT), now);
}
}
- void decStartedServices(int memFactor, long now) {
+ void decStartedServices(int memFactor, long now, String serviceName) {
+ if (false) {
+ RuntimeException here = new RuntimeException("here");
+ here.fillInStackTrace();
+ Slog.d(TAG, "decActiveServices: " + this + " service=" + serviceName
+ + " to " + (mNumStartedServices-1), here);
+ }
if (mCommonProcess != this) {
- mCommonProcess.decStartedServices(memFactor, now);
+ mCommonProcess.decStartedServices(memFactor, now, serviceName);
}
mNumStartedServices--;
- if (mNumStartedServices == 0 && mCurState == STATE_SERVICE_RESTARTING) {
- setState(STATE_NOTHING, memFactor, now, null);
+ if (mNumStartedServices == 0 && (mCurState%STATE_COUNT) == STATE_SERVICE_RESTARTING) {
+ setState(STATE_NOTHING, now);
} else if (mNumStartedServices < 0) {
Slog.wtfStack(TAG, "Proc started services underrun: pkg="
+ mPackage + " uid=" + mUid + " name=" + mName);
@@ -2873,6 +2923,8 @@
public int mRunState = STATE_NOTHING;
long mRunStartTime;
+ boolean mStarted;
+ boolean mRestarting;
int mStartedCount;
public int mStartedState = STATE_NOTHING;
long mStartedStartTime;
@@ -2902,10 +2954,9 @@
// There was already an old owner, reset this object for its
// new owner.
mOwner = newOwner;
- if (mStartedState != STATE_NOTHING || mBoundState != STATE_NOTHING
- || mExecState != STATE_NOTHING) {
+ if (mStarted || mBoundState != STATE_NOTHING || mExecState != STATE_NOTHING) {
long now = SystemClock.uptimeMillis();
- if (mStartedState != STATE_NOTHING) {
+ if (mStarted) {
if (DEBUG) Slog.d(TAG, "Service has new owner " + newOwner
+ " from " + mOwner + " while started: pkg="
+ mPackage + " service=" + mName + " proc=" + mProc);
@@ -2931,10 +2982,9 @@
public void clearCurrentOwner(Object owner, boolean silently) {
if (mOwner == owner) {
mProc.decActiveServices(mName);
- if (mStartedState != STATE_NOTHING || mBoundState != STATE_NOTHING
- || mExecState != STATE_NOTHING) {
+ if (mStarted || mBoundState != STATE_NOTHING || mExecState != STATE_NOTHING) {
long now = SystemClock.uptimeMillis();
- if (mStartedState != STATE_NOTHING) {
+ if (mStarted) {
if (!silently) {
Slog.wtfStack(TAG, "Service owner " + owner
+ " cleared while started: pkg=" + mPackage + " service="
@@ -3042,7 +3092,18 @@
if (mOwner == null) {
Slog.wtf(TAG, "Starting service " + this + " without owner");
}
+ mStarted = started;
+ updateStartedState(memFactor, now);
+ }
+
+ public void setRestarting(boolean restarting, int memFactor, long now) {
+ mRestarting = restarting;
+ updateStartedState(memFactor, now);
+ }
+
+ void updateStartedState(int memFactor, long now) {
final boolean wasStarted = mStartedState != STATE_NOTHING;
+ final boolean started = mStarted || mRestarting;
final int state = started ? memFactor : STATE_NOTHING;
if (mStartedState != state) {
if (mStartedState != STATE_NOTHING) {
@@ -3056,9 +3117,9 @@
mProc = mProc.pullFixedProc(mPackage);
if (wasStarted != started) {
if (started) {
- mProc.incStartedServices(memFactor, now);
+ mProc.incStartedServices(memFactor, now, mName);
} else {
- mProc.decStartedServices(memFactor, now);
+ mProc.decStartedServices(memFactor, now, mName);
}
}
updateRunning(memFactor, now);
diff --git a/core/java/com/android/internal/backup/IBackupTransport.aidl b/core/java/com/android/internal/backup/IBackupTransport.aidl
index 5bfa1b2..1e37fd9 100644
--- a/core/java/com/android/internal/backup/IBackupTransport.aidl
+++ b/core/java/com/android/internal/backup/IBackupTransport.aidl
@@ -23,6 +23,12 @@
/** {@hide} */
interface IBackupTransport {
+ /**
+ * Ask the transport for the name under which it should be registered. This will
+ * typically be its host service's component name, but need not be.
+ */
+ String name();
+
/**
* Ask the transport for an Intent that can be used to launch any internal
* configuration Activity that it wishes to present. For example, the transport
diff --git a/core/java/com/android/internal/backup/LocalTransport.java b/core/java/com/android/internal/backup/LocalTransport.java
index eb2d1fe..494bc78 100644
--- a/core/java/com/android/internal/backup/LocalTransport.java
+++ b/core/java/com/android/internal/backup/LocalTransport.java
@@ -19,6 +19,7 @@
import android.app.backup.BackupDataInput;
import android.app.backup.BackupDataOutput;
import android.app.backup.RestoreSet;
+import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageInfo;
@@ -71,6 +72,10 @@
}
}
+ public String name() {
+ return new ComponentName(mContext, this.getClass()).flattenToShortString();
+ }
+
public Intent configurationIntent() {
// The local transport is not user-configurable
return null;
diff --git a/core/java/com/android/internal/backup/LocalTransportService.java b/core/java/com/android/internal/backup/LocalTransportService.java
new file mode 100644
index 0000000..d05699a
--- /dev/null
+++ b/core/java/com/android/internal/backup/LocalTransportService.java
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.backup;
+
+import android.app.Service;
+import android.content.Intent;
+import android.os.IBinder;
+
+public class LocalTransportService extends Service {
+ private static LocalTransport sTransport = null;
+
+ @Override
+ public void onCreate() {
+ if (sTransport == null) {
+ sTransport = new LocalTransport(this);
+ }
+ }
+
+ @Override
+ public IBinder onBind(Intent intent) {
+ return sTransport;
+ }
+}
diff --git a/core/java/com/android/internal/os/BatteryStatsImpl.java b/core/java/com/android/internal/os/BatteryStatsImpl.java
index a99aa33..0a702ff 100644
--- a/core/java/com/android/internal/os/BatteryStatsImpl.java
+++ b/core/java/com/android/internal/os/BatteryStatsImpl.java
@@ -84,7 +84,7 @@
private static final int MAGIC = 0xBA757475; // 'BATSTATS'
// Current on-disk Parcel version
- private static final int VERSION = 66 + (USE_OLD_HISTORY ? 1000 : 0);
+ private static final int VERSION = 67 + (USE_OLD_HISTORY ? 1000 : 0);
// Maximum number of items we will record in the history.
private static final int MAX_HISTORY_ITEMS = 2000;
@@ -154,6 +154,8 @@
final ArrayList<StopwatchTimer> mFullWifiLockTimers = new ArrayList<StopwatchTimer>();
final ArrayList<StopwatchTimer> mWifiMulticastTimers = new ArrayList<StopwatchTimer>();
final ArrayList<StopwatchTimer> mWifiScanTimers = new ArrayList<StopwatchTimer>();
+ final SparseArray<ArrayList<StopwatchTimer>> mWifiBatchedScanTimers =
+ new SparseArray<ArrayList<StopwatchTimer>>();
// Last partial timers we use for distributing CPU usage.
final ArrayList<StopwatchTimer> mLastPartialTimers = new ArrayList<StopwatchTimer>();
@@ -2404,6 +2406,14 @@
getUidStatsLocked(uid).noteWifiScanStoppedLocked();
}
+ public void noteWifiBatchedScanStartedLocked(int uid, int csph) {
+ getUidStatsLocked(uid).noteWifiBatchedScanStartedLocked(csph);
+ }
+
+ public void noteWifiBatchedScanStoppedLocked(int uid) {
+ getUidStatsLocked(uid).noteWifiBatchedScanStoppedLocked();
+ }
+
int mWifiMulticastNesting = 0;
public void noteWifiMulticastEnabledLocked(int uid) {
@@ -2456,6 +2466,20 @@
}
}
+ public void noteWifiBatchedScanStartedFromSourceLocked(WorkSource ws, int csph) {
+ int N = ws.size();
+ for (int i=0; i<N; i++) {
+ noteWifiBatchedScanStartedLocked(ws.get(i), csph);
+ }
+ }
+
+ public void noteWifiBatchedScanStoppedFromSourceLocked(WorkSource ws) {
+ int N = ws.size();
+ for (int i=0; i<N; i++) {
+ noteWifiBatchedScanStoppedLocked(ws.get(i));
+ }
+ }
+
public void noteWifiMulticastEnabledFromSourceLocked(WorkSource ws) {
int N = ws.size();
for (int i=0; i<N; i++) {
@@ -2579,6 +2603,10 @@
boolean mWifiScanStarted;
StopwatchTimer mWifiScanTimer;
+ private static final int NO_BATCHED_SCAN_STARTED = -1;
+ int mWifiBatchedScanBinStarted = NO_BATCHED_SCAN_STARTED;
+ StopwatchTimer[] mWifiBatchedScanTimer;
+
boolean mWifiMulticastEnabled;
StopwatchTimer mWifiMulticastTimer;
@@ -2629,6 +2657,7 @@
mFullWifiLockTimers, mUnpluggables);
mWifiScanTimer = new StopwatchTimer(Uid.this, WIFI_SCAN,
mWifiScanTimers, mUnpluggables);
+ mWifiBatchedScanTimer = new StopwatchTimer[NUM_WIFI_BATCHED_SCAN_BINS];
mWifiMulticastTimer = new StopwatchTimer(Uid.this, WIFI_MULTICAST_ENABLED,
mWifiMulticastTimers, mUnpluggables);
}
@@ -2719,6 +2748,36 @@
}
@Override
+ public void noteWifiBatchedScanStartedLocked(int csph) {
+ int bin = 0;
+ while (csph > 8 && bin < NUM_WIFI_BATCHED_SCAN_BINS) {
+ csph = csph >> 3;
+ bin++;
+ }
+
+ if (mWifiBatchedScanBinStarted == bin) return;
+
+ if (mWifiBatchedScanBinStarted != NO_BATCHED_SCAN_STARTED) {
+ mWifiBatchedScanTimer[mWifiBatchedScanBinStarted].
+ stopRunningLocked(BatteryStatsImpl.this);
+ }
+ mWifiBatchedScanBinStarted = bin;
+ if (mWifiBatchedScanTimer[bin] == null) {
+ makeWifiBatchedScanBin(bin, null);
+ }
+ mWifiBatchedScanTimer[bin].startRunningLocked(BatteryStatsImpl.this);
+ }
+
+ @Override
+ public void noteWifiBatchedScanStoppedLocked() {
+ if (mWifiBatchedScanBinStarted != NO_BATCHED_SCAN_STARTED) {
+ mWifiBatchedScanTimer[mWifiBatchedScanBinStarted].
+ stopRunningLocked(BatteryStatsImpl.this);
+ mWifiBatchedScanBinStarted = NO_BATCHED_SCAN_STARTED;
+ }
+ }
+
+ @Override
public void noteWifiMulticastEnabledLocked() {
if (!mWifiMulticastEnabled) {
mWifiMulticastEnabled = true;
@@ -2854,6 +2913,15 @@
}
@Override
+ public long getWifiBatchedScanTime(int csphBin, long batteryRealtime, int which) {
+ if (csphBin < 0 || csphBin >= NUM_WIFI_BATCHED_SCAN_BINS) return 0;
+ if (mWifiBatchedScanTimer[csphBin] == null) {
+ return 0;
+ }
+ return mWifiBatchedScanTimer[csphBin].getTotalTimeLocked(batteryRealtime, which);
+ }
+
+ @Override
public long getWifiMulticastTime(long batteryRealtime, int which) {
if (mWifiMulticastTimer == null) {
return 0;
@@ -2914,6 +2982,24 @@
return mUserActivityCounters[type].getCountLocked(which);
}
+ void makeWifiBatchedScanBin(int i, Parcel in) {
+ if (i < 0 || i >= NUM_WIFI_BATCHED_SCAN_BINS) return;
+
+ ArrayList<StopwatchTimer> collected = mWifiBatchedScanTimers.get(i);
+ if (collected == null) {
+ collected = new ArrayList<StopwatchTimer>();
+ mWifiBatchedScanTimers.put(i, collected);
+ }
+ if (in == null) {
+ mWifiBatchedScanTimer[i] = new StopwatchTimer(this, WIFI_BATCHED_SCAN, collected,
+ mUnpluggables);
+ } else {
+ mWifiBatchedScanTimer[i] = new StopwatchTimer(this, WIFI_BATCHED_SCAN, collected,
+ mUnpluggables, in);
+ }
+ }
+
+
void initUserActivityLocked() {
mUserActivityCounters = new Counter[NUM_USER_ACTIVITY_TYPES];
for (int i=0; i<NUM_USER_ACTIVITY_TYPES; i++) {
@@ -2974,6 +3060,14 @@
active |= !mWifiScanTimer.reset(BatteryStatsImpl.this, false);
active |= mWifiScanStarted;
}
+ if (mWifiBatchedScanTimer != null) {
+ for (int i = 0; i < NUM_WIFI_BATCHED_SCAN_BINS; i++) {
+ if (mWifiBatchedScanTimer[i] != null) {
+ active |= !mWifiBatchedScanTimer[i].reset(BatteryStatsImpl.this, false);
+ }
+ }
+ active |= (mWifiBatchedScanBinStarted != NO_BATCHED_SCAN_STARTED);
+ }
if (mWifiMulticastTimer != null) {
active |= !mWifiMulticastTimer.reset(BatteryStatsImpl.this, false);
active |= mWifiMulticastEnabled;
@@ -3080,6 +3174,11 @@
if (mWifiScanTimer != null) {
mWifiScanTimer.detach();
}
+ for (int i = 0; i < NUM_WIFI_BATCHED_SCAN_BINS; i++) {
+ if (mWifiBatchedScanTimer[i] != null) {
+ mWifiBatchedScanTimer[i].detach();
+ }
+ }
if (mWifiMulticastTimer != null) {
mWifiMulticastTimer.detach();
}
@@ -3157,6 +3256,14 @@
} else {
out.writeInt(0);
}
+ for (int i = 0; i < NUM_WIFI_BATCHED_SCAN_BINS; i++) {
+ if (mWifiBatchedScanTimer[i] != null) {
+ out.writeInt(1);
+ mWifiBatchedScanTimer[i].writeToParcel(out, batteryRealtime);
+ } else {
+ out.writeInt(0);
+ }
+ }
if (mWifiMulticastTimer != null) {
out.writeInt(1);
mWifiMulticastTimer.writeToParcel(out, batteryRealtime);
@@ -3266,6 +3373,14 @@
} else {
mWifiScanTimer = null;
}
+ mWifiBatchedScanBinStarted = NO_BATCHED_SCAN_STARTED;
+ for (int i = 0; i < NUM_WIFI_BATCHED_SCAN_BINS; i++) {
+ if (in.readInt() != 0) {
+ makeWifiBatchedScanBin(i, in);
+ } else {
+ mWifiBatchedScanTimer[i] = null;
+ }
+ }
mWifiMulticastEnabled = false;
if (in.readInt() != 0) {
mWifiMulticastTimer = new StopwatchTimer(Uid.this, WIFI_MULTICAST_ENABLED,
@@ -5463,6 +5578,13 @@
if (in.readInt() != 0) {
u.mWifiScanTimer.readSummaryFromParcelLocked(in);
}
+ u.mWifiBatchedScanBinStarted = Uid.NO_BATCHED_SCAN_STARTED;
+ for (int i = 0; i < Uid.NUM_WIFI_BATCHED_SCAN_BINS; i++) {
+ if (in.readInt() != 0) {
+ u.makeWifiBatchedScanBin(i, null);
+ u.mWifiBatchedScanTimer[i].readSummaryFromParcelLocked(in);
+ }
+ }
u.mWifiMulticastEnabled = false;
if (in.readInt() != 0) {
u.mWifiMulticastTimer.readSummaryFromParcelLocked(in);
@@ -5674,6 +5796,14 @@
} else {
out.writeInt(0);
}
+ for (int i = 0; i < Uid.NUM_WIFI_BATCHED_SCAN_BINS; i++) {
+ if (u.mWifiBatchedScanTimer[i] != null) {
+ out.writeInt(1);
+ u.mWifiBatchedScanTimer[i].writeSummaryFromParcelLocked(out, NOWREAL);
+ } else {
+ out.writeInt(0);
+ }
+ }
if (u.mWifiMulticastTimer != null) {
out.writeInt(1);
u.mWifiMulticastTimer.writeSummaryFromParcelLocked(out, NOWREAL);
@@ -5909,6 +6039,7 @@
mWifiRunningTimers.clear();
mFullWifiLockTimers.clear();
mWifiScanTimers.clear();
+ mWifiBatchedScanTimers.clear();
mWifiMulticastTimers.clear();
sNumSpeedSteps = in.readInt();
diff --git a/core/java/com/android/internal/os/PowerProfile.java b/core/java/com/android/internal/os/PowerProfile.java
index 99a6843..94750d3 100644
--- a/core/java/com/android/internal/os/PowerProfile.java
+++ b/core/java/com/android/internal/os/PowerProfile.java
@@ -136,6 +136,13 @@
public static final String POWER_CPU_SPEEDS = "cpu.speeds";
/**
+ * Power consumed by wif batched scaning. Broken down into bins by
+ * Channels Scanned per Hour. May do 1-720 scans per hour of 1-100 channels
+ * for a range of 1-72,000. Going logrithmic (1-8, 9-64, 65-512, 513-4096, 4097-)!
+ */
+ public static final String POWER_WIFI_BATCHED_SCAN = "wifi.batchedscan";
+
+ /**
* Battery capacity in milliAmpHour (mAh).
*/
public static final String POWER_BATTERY_CAPACITY = "battery.capacity";
@@ -171,7 +178,7 @@
String element = parser.getName();
if (element == null) break;
-
+
if (parsingArray && !element.equals(TAG_ARRAYITEM)) {
// Finish array
sPowerMap.put(arrayName, array.toArray(new Double[array.size()]));
diff --git a/core/java/com/android/internal/view/CheckableLinearLayout.java b/core/java/com/android/internal/view/CheckableLinearLayout.java
deleted file mode 100644
index 3fb7cec..0000000
--- a/core/java/com/android/internal/view/CheckableLinearLayout.java
+++ /dev/null
@@ -1,65 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.internal.view;
-
-import com.android.internal.R;
-
-import android.content.Context;
-import android.util.AttributeSet;
-import android.widget.Checkable;
-import android.widget.CheckBox;
-import android.widget.LinearLayout;
-
-public class CheckableLinearLayout extends LinearLayout implements Checkable {
- private CheckBox mCheckBox;
-
- public CheckableLinearLayout(Context context) {
- super(context);
- // TODO Auto-generated constructor stub
- }
-
- public CheckableLinearLayout(Context context, AttributeSet attrs) {
- super(context, attrs);
- // TODO Auto-generated constructor stub
- }
-
- public CheckableLinearLayout(Context context, AttributeSet attrs, int defStyle) {
- super(context, attrs, defStyle);
- // TODO Auto-generated constructor stub
- }
-
- @Override
- protected void onFinishInflate() {
- super.onFinishInflate();
- mCheckBox = (CheckBox) findViewById(R.id.check);
- }
-
- @Override
- public void setChecked(boolean checked) {
- mCheckBox.setChecked(checked);
- }
-
- @Override
- public boolean isChecked() {
- return mCheckBox.isChecked();
- }
-
- @Override
- public void toggle() {
- mCheckBox.toggle();
- }
-}
diff --git a/core/java/com/android/internal/widget/ActionBarView.java b/core/java/com/android/internal/widget/ActionBarView.java
index 5f9d8f2..786f5cf 100644
--- a/core/java/com/android/internal/widget/ActionBarView.java
+++ b/core/java/com/android/internal/widget/ActionBarView.java
@@ -526,7 +526,7 @@
if (mLogoNavItem != null) {
mLogoNavItem.setTitle(title);
}
- mUpGoerFive.setContentDescription(buildHomeContentDescription());
+ updateHomeAccessibility(mUpGoerFive.isEnabled());
}
public CharSequence getSubtitle() {
@@ -544,7 +544,7 @@
(!TextUtils.isEmpty(mTitle) || !TextUtils.isEmpty(mSubtitle));
mTitleLayout.setVisibility(visible ? VISIBLE : GONE);
}
- mUpGoerFive.setContentDescription(buildHomeContentDescription());
+ updateHomeAccessibility(mUpGoerFive.isEnabled());
}
public void setHomeButtonEnabled(boolean enable) {
@@ -681,7 +681,7 @@
}
// Make sure the home button has an accurate content description for accessibility.
- updateHomeAccessibility(!mUpGoerFive.isEnabled());
+ updateHomeAccessibility(mUpGoerFive.isEnabled());
}
public void setIcon(Drawable icon) {
@@ -1332,11 +1332,13 @@
public void setHomeActionContentDescription(CharSequence description) {
mHomeDescription = description;
+ updateHomeAccessibility(mUpGoerFive.isEnabled());
}
public void setHomeActionContentDescription(int resId) {
mHomeDescriptionRes = resId;
mHomeDescription = resId != 0 ? getResources().getText(resId) : null;
+ updateHomeAccessibility(mUpGoerFive.isEnabled());
}
static class SavedState extends BaseSavedState {
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 6ddd3fe..b198937 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -1992,6 +1992,14 @@
android:description="@string/permdesc_bindWallpaper"
android:protectionLevel="signature|system" />
+ <!-- Must be required by a {@link com.android.media.remotedisplay.RemoteDisplayProvider},
+ to ensure that only the system can bind to it.
+ @hide -->
+ <permission android:name="android.permission.BIND_REMOTE_DISPLAY"
+ android:label="@string/permlab_bindRemoteDisplay"
+ android:description="@string/permdesc_bindRemoteDisplay"
+ android:protectionLevel="signature" />
+
<!-- Must be required by device administration receiver, to ensure that only the
system can interact with it. -->
<permission android:name="android.permission.BIND_DEVICE_ADMIN"
@@ -2681,6 +2689,15 @@
<service android:name="android.hardware.location.GeofenceHardwareService"
android:permission="android.permission.LOCATION_HARDWARE"
android:exported="false" />
+
+ <service android:name="com.android.internal.backup.LocalTransportService"
+ android:permission="android.permission.CONFIRM_FULL_BACKUP"
+ android:exported="false">
+ <intent-filter>
+ <action android:name="android.backup.TRANSPORT_HOST" />
+ </intent-filter>
+ </service>
+
</application>
</manifest>
diff --git a/core/res/res/drawable-hdpi/ic_media_group_collapse.png b/core/res/res/drawable-hdpi/ic_media_group_collapse.png
deleted file mode 100644
index 89abf2c..0000000
--- a/core/res/res/drawable-hdpi/ic_media_group_collapse.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_media_group_expand.png b/core/res/res/drawable-hdpi/ic_media_group_expand.png
deleted file mode 100644
index d9470b2..0000000
--- a/core/res/res/drawable-hdpi/ic_media_group_expand.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_media_route_disabled_holo_dark.png b/core/res/res/drawable-hdpi/ic_media_route_disabled_holo_dark.png
index b47d666..458a2a6 100644
--- a/core/res/res/drawable-hdpi/ic_media_route_disabled_holo_dark.png
+++ b/core/res/res/drawable-hdpi/ic_media_route_disabled_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_media_route_off_holo_dark.png b/core/res/res/drawable-hdpi/ic_media_route_off_holo_dark.png
index 13d803c..c91faa9 100644
--- a/core/res/res/drawable-hdpi/ic_media_route_off_holo_dark.png
+++ b/core/res/res/drawable-hdpi/ic_media_route_off_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_media_route_off_holo_light.png b/core/res/res/drawable-hdpi/ic_media_route_off_holo_light.png
index 3ae436b..14c9183 100644
--- a/core/res/res/drawable-hdpi/ic_media_route_off_holo_light.png
+++ b/core/res/res/drawable-hdpi/ic_media_route_off_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_media_route_on_0_holo_dark.png b/core/res/res/drawable-hdpi/ic_media_route_on_0_holo_dark.png
index 24824fc..b388d86 100644
--- a/core/res/res/drawable-hdpi/ic_media_route_on_0_holo_dark.png
+++ b/core/res/res/drawable-hdpi/ic_media_route_on_0_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_media_route_on_0_holo_light.png b/core/res/res/drawable-hdpi/ic_media_route_on_0_holo_light.png
index af3819b..76c1323 100644
--- a/core/res/res/drawable-hdpi/ic_media_route_on_0_holo_light.png
+++ b/core/res/res/drawable-hdpi/ic_media_route_on_0_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_media_route_on_1_holo_dark.png b/core/res/res/drawable-hdpi/ic_media_route_on_1_holo_dark.png
index 83dc251..fd39f9d 100644
--- a/core/res/res/drawable-hdpi/ic_media_route_on_1_holo_dark.png
+++ b/core/res/res/drawable-hdpi/ic_media_route_on_1_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_media_route_on_1_holo_light.png b/core/res/res/drawable-hdpi/ic_media_route_on_1_holo_light.png
index 8d9d592..c74727a 100644
--- a/core/res/res/drawable-hdpi/ic_media_route_on_1_holo_light.png
+++ b/core/res/res/drawable-hdpi/ic_media_route_on_1_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_media_route_on_2_holo_dark.png b/core/res/res/drawable-hdpi/ic_media_route_on_2_holo_dark.png
index 1310ec9..826c9ae 100644
--- a/core/res/res/drawable-hdpi/ic_media_route_on_2_holo_dark.png
+++ b/core/res/res/drawable-hdpi/ic_media_route_on_2_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_media_route_on_2_holo_light.png b/core/res/res/drawable-hdpi/ic_media_route_on_2_holo_light.png
index 1705074..d0baec3 100644
--- a/core/res/res/drawable-hdpi/ic_media_route_on_2_holo_light.png
+++ b/core/res/res/drawable-hdpi/ic_media_route_on_2_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_media_route_on_holo_dark.png b/core/res/res/drawable-hdpi/ic_media_route_on_holo_dark.png
index 7027b88..c60ff59 100644
--- a/core/res/res/drawable-hdpi/ic_media_route_on_holo_dark.png
+++ b/core/res/res/drawable-hdpi/ic_media_route_on_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_media_route_on_holo_light.png b/core/res/res/drawable-hdpi/ic_media_route_on_holo_light.png
index 7027b88..75552cc 100644
--- a/core/res/res/drawable-hdpi/ic_media_route_on_holo_light.png
+++ b/core/res/res/drawable-hdpi/ic_media_route_on_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_notification_cast_0.png b/core/res/res/drawable-hdpi/ic_notification_cast_0.png
new file mode 100644
index 0000000..a35f281
--- /dev/null
+++ b/core/res/res/drawable-hdpi/ic_notification_cast_0.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_notification_cast_1.png b/core/res/res/drawable-hdpi/ic_notification_cast_1.png
new file mode 100644
index 0000000..9f6e2ad
--- /dev/null
+++ b/core/res/res/drawable-hdpi/ic_notification_cast_1.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_notification_cast_2.png b/core/res/res/drawable-hdpi/ic_notification_cast_2.png
new file mode 100644
index 0000000..737137a
--- /dev/null
+++ b/core/res/res/drawable-hdpi/ic_notification_cast_2.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_notification_cast_on.png b/core/res/res/drawable-hdpi/ic_notification_cast_on.png
new file mode 100644
index 0000000..ff2753a
--- /dev/null
+++ b/core/res/res/drawable-hdpi/ic_notification_cast_on.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_notify_wifidisplay.png b/core/res/res/drawable-hdpi/ic_notify_wifidisplay.png
deleted file mode 100644
index 35f27df..0000000
--- a/core/res/res/drawable-hdpi/ic_notify_wifidisplay.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_media_group_collapse.png b/core/res/res/drawable-mdpi/ic_media_group_collapse.png
deleted file mode 100644
index 34454ac..0000000
--- a/core/res/res/drawable-mdpi/ic_media_group_collapse.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_media_group_expand.png b/core/res/res/drawable-mdpi/ic_media_group_expand.png
deleted file mode 100644
index 8ce5a44..0000000
--- a/core/res/res/drawable-mdpi/ic_media_group_expand.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_media_route_off_holo_dark.png b/core/res/res/drawable-mdpi/ic_media_route_off_holo_dark.png
index 6764598..9d92648 100644
--- a/core/res/res/drawable-mdpi/ic_media_route_off_holo_dark.png
+++ b/core/res/res/drawable-mdpi/ic_media_route_off_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_media_route_off_holo_light.png b/core/res/res/drawable-mdpi/ic_media_route_off_holo_light.png
index 94e0bb6..3e27fc8 100644
--- a/core/res/res/drawable-mdpi/ic_media_route_off_holo_light.png
+++ b/core/res/res/drawable-mdpi/ic_media_route_off_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_media_route_on_0_holo_dark.png b/core/res/res/drawable-mdpi/ic_media_route_on_0_holo_dark.png
index 5ce2f20..72b9e78 100644
--- a/core/res/res/drawable-mdpi/ic_media_route_on_0_holo_dark.png
+++ b/core/res/res/drawable-mdpi/ic_media_route_on_0_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_media_route_on_0_holo_light.png b/core/res/res/drawable-mdpi/ic_media_route_on_0_holo_light.png
index 5105e90..bd462a2 100644
--- a/core/res/res/drawable-mdpi/ic_media_route_on_0_holo_light.png
+++ b/core/res/res/drawable-mdpi/ic_media_route_on_0_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_media_route_on_1_holo_dark.png b/core/res/res/drawable-mdpi/ic_media_route_on_1_holo_dark.png
index 68c06ed..0a2cc89 100644
--- a/core/res/res/drawable-mdpi/ic_media_route_on_1_holo_dark.png
+++ b/core/res/res/drawable-mdpi/ic_media_route_on_1_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_media_route_on_1_holo_light.png b/core/res/res/drawable-mdpi/ic_media_route_on_1_holo_light.png
index 6e9b144..d162503 100644
--- a/core/res/res/drawable-mdpi/ic_media_route_on_1_holo_light.png
+++ b/core/res/res/drawable-mdpi/ic_media_route_on_1_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_media_route_on_2_holo_dark.png b/core/res/res/drawable-mdpi/ic_media_route_on_2_holo_dark.png
index 45dc56f3d..997e32b 100644
--- a/core/res/res/drawable-mdpi/ic_media_route_on_2_holo_dark.png
+++ b/core/res/res/drawable-mdpi/ic_media_route_on_2_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_media_route_on_2_holo_light.png b/core/res/res/drawable-mdpi/ic_media_route_on_2_holo_light.png
index 46e743a..d314967 100644
--- a/core/res/res/drawable-mdpi/ic_media_route_on_2_holo_light.png
+++ b/core/res/res/drawable-mdpi/ic_media_route_on_2_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_media_route_on_holo_dark.png b/core/res/res/drawable-mdpi/ic_media_route_on_holo_dark.png
index e384691..f15d7a9 100644
--- a/core/res/res/drawable-mdpi/ic_media_route_on_holo_dark.png
+++ b/core/res/res/drawable-mdpi/ic_media_route_on_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_media_route_on_holo_light.png b/core/res/res/drawable-mdpi/ic_media_route_on_holo_light.png
index e384691..26d46f8 100644
--- a/core/res/res/drawable-mdpi/ic_media_route_on_holo_light.png
+++ b/core/res/res/drawable-mdpi/ic_media_route_on_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_notification_cast_0.png b/core/res/res/drawable-mdpi/ic_notification_cast_0.png
new file mode 100644
index 0000000..d9cedbd
--- /dev/null
+++ b/core/res/res/drawable-mdpi/ic_notification_cast_0.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_notification_cast_1.png b/core/res/res/drawable-mdpi/ic_notification_cast_1.png
new file mode 100644
index 0000000..414c67f
--- /dev/null
+++ b/core/res/res/drawable-mdpi/ic_notification_cast_1.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_notification_cast_2.png b/core/res/res/drawable-mdpi/ic_notification_cast_2.png
new file mode 100644
index 0000000..280a888
--- /dev/null
+++ b/core/res/res/drawable-mdpi/ic_notification_cast_2.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_notification_cast_on.png b/core/res/res/drawable-mdpi/ic_notification_cast_on.png
new file mode 100644
index 0000000..ab5f1d7
--- /dev/null
+++ b/core/res/res/drawable-mdpi/ic_notification_cast_on.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_notify_wifidisplay.png b/core/res/res/drawable-mdpi/ic_notify_wifidisplay.png
deleted file mode 100644
index f9c8678..0000000
--- a/core/res/res/drawable-mdpi/ic_notify_wifidisplay.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/ic_media_group_collapse.png b/core/res/res/drawable-xhdpi/ic_media_group_collapse.png
deleted file mode 100644
index 2fb7428..0000000
--- a/core/res/res/drawable-xhdpi/ic_media_group_collapse.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/ic_media_group_expand.png b/core/res/res/drawable-xhdpi/ic_media_group_expand.png
deleted file mode 100644
index 5755b9d..0000000
--- a/core/res/res/drawable-xhdpi/ic_media_group_expand.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/ic_media_route_disabled_holo_dark.png b/core/res/res/drawable-xhdpi/ic_media_route_disabled_holo_dark.png
index 1d48e12..045eee0 100644
--- a/core/res/res/drawable-xhdpi/ic_media_route_disabled_holo_dark.png
+++ b/core/res/res/drawable-xhdpi/ic_media_route_disabled_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/ic_media_route_disabled_holo_light.png b/core/res/res/drawable-xhdpi/ic_media_route_disabled_holo_light.png
index 2c8d1ec..6e14e29 100644
--- a/core/res/res/drawable-xhdpi/ic_media_route_disabled_holo_light.png
+++ b/core/res/res/drawable-xhdpi/ic_media_route_disabled_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/ic_media_route_off_holo_dark.png b/core/res/res/drawable-xhdpi/ic_media_route_off_holo_dark.png
index 00b2043..121bbf6 100644
--- a/core/res/res/drawable-xhdpi/ic_media_route_off_holo_dark.png
+++ b/core/res/res/drawable-xhdpi/ic_media_route_off_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/ic_media_route_off_holo_light.png b/core/res/res/drawable-xhdpi/ic_media_route_off_holo_light.png
index ce1d939..468a0c3 100644
--- a/core/res/res/drawable-xhdpi/ic_media_route_off_holo_light.png
+++ b/core/res/res/drawable-xhdpi/ic_media_route_off_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/ic_media_route_on_0_holo_dark.png b/core/res/res/drawable-xhdpi/ic_media_route_on_0_holo_dark.png
index 3064b46..414a322 100644
--- a/core/res/res/drawable-xhdpi/ic_media_route_on_0_holo_dark.png
+++ b/core/res/res/drawable-xhdpi/ic_media_route_on_0_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/ic_media_route_on_0_holo_light.png b/core/res/res/drawable-xhdpi/ic_media_route_on_0_holo_light.png
index 4316686..6088a48 100644
--- a/core/res/res/drawable-xhdpi/ic_media_route_on_0_holo_light.png
+++ b/core/res/res/drawable-xhdpi/ic_media_route_on_0_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/ic_media_route_on_1_holo_dark.png b/core/res/res/drawable-xhdpi/ic_media_route_on_1_holo_dark.png
index 25c4e31..363d7d4 100644
--- a/core/res/res/drawable-xhdpi/ic_media_route_on_1_holo_dark.png
+++ b/core/res/res/drawable-xhdpi/ic_media_route_on_1_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/ic_media_route_on_1_holo_light.png b/core/res/res/drawable-xhdpi/ic_media_route_on_1_holo_light.png
index 8e32bd2..edf731e 100644
--- a/core/res/res/drawable-xhdpi/ic_media_route_on_1_holo_light.png
+++ b/core/res/res/drawable-xhdpi/ic_media_route_on_1_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/ic_media_route_on_2_holo_dark.png b/core/res/res/drawable-xhdpi/ic_media_route_on_2_holo_dark.png
index aeaa78f..85cba7b 100644
--- a/core/res/res/drawable-xhdpi/ic_media_route_on_2_holo_dark.png
+++ b/core/res/res/drawable-xhdpi/ic_media_route_on_2_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/ic_media_route_on_2_holo_light.png b/core/res/res/drawable-xhdpi/ic_media_route_on_2_holo_light.png
index 85277fa..e65ac31 100644
--- a/core/res/res/drawable-xhdpi/ic_media_route_on_2_holo_light.png
+++ b/core/res/res/drawable-xhdpi/ic_media_route_on_2_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/ic_media_route_on_holo_dark.png b/core/res/res/drawable-xhdpi/ic_media_route_on_holo_dark.png
index b01dbe8..d8e3e3a 100644
--- a/core/res/res/drawable-xhdpi/ic_media_route_on_holo_dark.png
+++ b/core/res/res/drawable-xhdpi/ic_media_route_on_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/ic_media_route_on_holo_light.png b/core/res/res/drawable-xhdpi/ic_media_route_on_holo_light.png
index c19a2ad..562dc9a 100644
--- a/core/res/res/drawable-xhdpi/ic_media_route_on_holo_light.png
+++ b/core/res/res/drawable-xhdpi/ic_media_route_on_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/ic_notification_cast_0.png b/core/res/res/drawable-xhdpi/ic_notification_cast_0.png
new file mode 100644
index 0000000..5fb23a0
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/ic_notification_cast_0.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/ic_notification_cast_1.png b/core/res/res/drawable-xhdpi/ic_notification_cast_1.png
new file mode 100644
index 0000000..f01d17d
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/ic_notification_cast_1.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/ic_notification_cast_2.png b/core/res/res/drawable-xhdpi/ic_notification_cast_2.png
new file mode 100644
index 0000000..4f4ba7f
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/ic_notification_cast_2.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/ic_notification_cast_on.png b/core/res/res/drawable-xhdpi/ic_notification_cast_on.png
new file mode 100644
index 0000000..38f15dd
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/ic_notification_cast_on.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/ic_notify_wifidisplay.png b/core/res/res/drawable-xhdpi/ic_notify_wifidisplay.png
deleted file mode 100644
index 4cc0ee8..0000000
--- a/core/res/res/drawable-xhdpi/ic_notify_wifidisplay.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_media_route_disabled_holo_dark.png b/core/res/res/drawable-xxhdpi/ic_media_route_disabled_holo_dark.png
index 7b0c383..178774c 100644
--- a/core/res/res/drawable-xxhdpi/ic_media_route_disabled_holo_dark.png
+++ b/core/res/res/drawable-xxhdpi/ic_media_route_disabled_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_media_route_disabled_holo_light.png b/core/res/res/drawable-xxhdpi/ic_media_route_disabled_holo_light.png
index efb624e..2dc2092 100644
--- a/core/res/res/drawable-xxhdpi/ic_media_route_disabled_holo_light.png
+++ b/core/res/res/drawable-xxhdpi/ic_media_route_disabled_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_media_route_off_holo_dark.png b/core/res/res/drawable-xxhdpi/ic_media_route_off_holo_dark.png
index 5ee57e4..592ee8c 100644
--- a/core/res/res/drawable-xxhdpi/ic_media_route_off_holo_dark.png
+++ b/core/res/res/drawable-xxhdpi/ic_media_route_off_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_media_route_off_holo_light.png b/core/res/res/drawable-xxhdpi/ic_media_route_off_holo_light.png
index 6bc2e4a..f0549e2 100644
--- a/core/res/res/drawable-xxhdpi/ic_media_route_off_holo_light.png
+++ b/core/res/res/drawable-xxhdpi/ic_media_route_off_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_media_route_on_0_holo_dark.png b/core/res/res/drawable-xxhdpi/ic_media_route_on_0_holo_dark.png
index c13af9c..91268f5 100644
--- a/core/res/res/drawable-xxhdpi/ic_media_route_on_0_holo_dark.png
+++ b/core/res/res/drawable-xxhdpi/ic_media_route_on_0_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_media_route_on_0_holo_light.png b/core/res/res/drawable-xxhdpi/ic_media_route_on_0_holo_light.png
index 744fb42..9d5436f 100644
--- a/core/res/res/drawable-xxhdpi/ic_media_route_on_0_holo_light.png
+++ b/core/res/res/drawable-xxhdpi/ic_media_route_on_0_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_media_route_on_1_holo_dark.png b/core/res/res/drawable-xxhdpi/ic_media_route_on_1_holo_dark.png
index ca4d59c..8e77483 100644
--- a/core/res/res/drawable-xxhdpi/ic_media_route_on_1_holo_dark.png
+++ b/core/res/res/drawable-xxhdpi/ic_media_route_on_1_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_media_route_on_1_holo_light.png b/core/res/res/drawable-xxhdpi/ic_media_route_on_1_holo_light.png
index fde5688..f396d22 100644
--- a/core/res/res/drawable-xxhdpi/ic_media_route_on_1_holo_light.png
+++ b/core/res/res/drawable-xxhdpi/ic_media_route_on_1_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_media_route_on_2_holo_dark.png b/core/res/res/drawable-xxhdpi/ic_media_route_on_2_holo_dark.png
index b8715c3..260bab4 100644
--- a/core/res/res/drawable-xxhdpi/ic_media_route_on_2_holo_dark.png
+++ b/core/res/res/drawable-xxhdpi/ic_media_route_on_2_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_media_route_on_2_holo_light.png b/core/res/res/drawable-xxhdpi/ic_media_route_on_2_holo_light.png
index 668bb25..2c9fb1d 100644
--- a/core/res/res/drawable-xxhdpi/ic_media_route_on_2_holo_light.png
+++ b/core/res/res/drawable-xxhdpi/ic_media_route_on_2_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_media_route_on_holo_dark.png b/core/res/res/drawable-xxhdpi/ic_media_route_on_holo_dark.png
index 7f54a62..bdbd59c 100644
--- a/core/res/res/drawable-xxhdpi/ic_media_route_on_holo_dark.png
+++ b/core/res/res/drawable-xxhdpi/ic_media_route_on_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_media_route_on_holo_light.png b/core/res/res/drawable-xxhdpi/ic_media_route_on_holo_light.png
index 2df924d..f5c33dd 100644
--- a/core/res/res/drawable-xxhdpi/ic_media_route_on_holo_light.png
+++ b/core/res/res/drawable-xxhdpi/ic_media_route_on_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_notification_cast_0.png b/core/res/res/drawable-xxhdpi/ic_notification_cast_0.png
new file mode 100644
index 0000000..f5b16ed
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/ic_notification_cast_0.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_notification_cast_1.png b/core/res/res/drawable-xxhdpi/ic_notification_cast_1.png
new file mode 100644
index 0000000..22efeec
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/ic_notification_cast_1.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_notification_cast_2.png b/core/res/res/drawable-xxhdpi/ic_notification_cast_2.png
new file mode 100644
index 0000000..e24cd97
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/ic_notification_cast_2.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_notification_cast_on.png b/core/res/res/drawable-xxhdpi/ic_notification_cast_on.png
new file mode 100644
index 0000000..da1a627
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/ic_notification_cast_on.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_notify_wifidisplay.png b/core/res/res/drawable-xxhdpi/ic_notify_wifidisplay.png
deleted file mode 100644
index fea4774..0000000
--- a/core/res/res/drawable-xxhdpi/ic_notify_wifidisplay.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable/ic_notification_cast_connecting.xml b/core/res/res/drawable/ic_notification_cast_connecting.xml
new file mode 100644
index 0000000..a390bce
--- /dev/null
+++ b/core/res/res/drawable/ic_notification_cast_connecting.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+ * Copyright 2013, 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.
+ */
+-->
+<animation-list
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:oneshot="false">
+ <item android:drawable="@drawable/ic_notification_cast_0" android:duration="500" />
+ <item android:drawable="@drawable/ic_notification_cast_1" android:duration="500" />
+ <item android:drawable="@drawable/ic_notification_cast_2" android:duration="500" />
+ <item android:drawable="@drawable/ic_notification_cast_1" android:duration="500" />
+</animation-list>
diff --git a/core/res/res/layout/immersive_mode_cling.xml b/core/res/res/layout/immersive_mode_cling.xml
index f97225e..c0cd93d 100644
--- a/core/res/res/layout/immersive_mode_cling.xml
+++ b/core/res/res/layout/immersive_mode_cling.xml
@@ -37,8 +37,8 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@drawable/cling_bg"
- android:paddingLeft="14dp"
- android:paddingRight="14dp"
+ android:paddingStart="14dp"
+ android:paddingEnd="14dp"
android:paddingTop="24dp"
android:paddingBottom="24dp">
<TextView
diff --git a/core/res/res/layout/media_route_chooser_dialog.xml b/core/res/res/layout/media_route_chooser_dialog.xml
new file mode 100644
index 0000000..d1c6267
--- /dev/null
+++ b/core/res/res/layout/media_route_chooser_dialog.xml
@@ -0,0 +1,59 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2013 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="vertical"
+ android:divider="?android:attr/dividerHorizontal"
+ android:showDividers="middle">
+ <!-- List of routes. -->
+ <ListView android:id="@+id/media_route_list"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_weight="1" />
+
+ <!-- Content to show when list is empty. -->
+ <LinearLayout android:id="@android:id/empty"
+ android:layout_width="match_parent"
+ android:layout_height="64dp"
+ android:orientation="horizontal"
+ android:paddingLeft="16dp"
+ android:paddingRight="16dp"
+ android:visibility="gone">
+ <ProgressBar android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center" />
+ <TextView android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center"
+ android:paddingLeft="16dp"
+ android:text="@string/media_route_chooser_searching" />
+ </LinearLayout>
+
+ <!-- Settings button. -->
+ <LinearLayout android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ style="?attr/buttonBarStyle">
+ <Button android:id="@+id/media_route_extended_settings_button"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ style="?attr/buttonBarButtonStyle"
+ android:gravity="center"
+ android:text="@string/media_route_chooser_extended_settings"
+ android:visibility="gone" />
+ </LinearLayout>
+</LinearLayout>
diff --git a/core/res/res/layout/media_route_chooser_layout.xml b/core/res/res/layout/media_route_chooser_layout.xml
deleted file mode 100644
index 5fcb8c8..0000000
--- a/core/res/res/layout/media_route_chooser_layout.xml
+++ /dev/null
@@ -1,48 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2012 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:orientation="vertical"
- android:showDividers="middle"
- android:divider="?android:attr/dividerHorizontal">
- <LinearLayout android:layout_width="match_parent"
- android:layout_height="?android:attr/listPreferredItemHeight"
- android:gravity="center_vertical"
- android:padding="8dp">
- <ImageView android:id="@+id/volume_icon"
- android:layout_width="48dp"
- android:layout_height="48dp"
- android:src="@android:drawable/ic_audio_vol"
- android:gravity="center"
- android:scaleType="center" />
- <SeekBar android:id="@+id/volume_slider"
- android:layout_width="0dp"
- android:layout_height="wrap_content"
- android:layout_weight="1"
- android:layout_marginStart="8dp"
- android:layout_marginEnd="8dp" />
- <ImageButton android:id="@+id/extended_settings"
- android:layout_width="48dp"
- android:layout_height="48dp"
- android:background="?android:attr/selectableItemBackground"
- android:src="@android:drawable/ic_sysbar_quicksettings"
- android:visibility="gone" />
- </LinearLayout>
- <ListView android:id="@id/list"
- android:layout_width="match_parent"
- android:layout_height="wrap_content" />
-</LinearLayout>
diff --git a/core/res/res/layout/media_route_controller_dialog.xml b/core/res/res/layout/media_route_controller_dialog.xml
new file mode 100644
index 0000000..78287e0
--- /dev/null
+++ b/core/res/res/layout/media_route_controller_dialog.xml
@@ -0,0 +1,60 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2013 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="vertical"
+ android:divider="?android:attr/dividerHorizontal"
+ android:showDividers="middle">
+ <!-- Optional volume slider section. -->
+ <LinearLayout android:id="@+id/media_route_volume_layout"
+ android:layout_width="match_parent"
+ android:layout_height="64dp"
+ android:gravity="center_vertical"
+ android:padding="8dp"
+ android:visibility="gone">
+ <ImageView android:layout_width="48dp"
+ android:layout_height="48dp"
+ android:src="@drawable/ic_audio_vol"
+ android:gravity="center"
+ android:scaleType="center" />
+ <SeekBar android:id="@+id/media_route_volume_slider"
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:layout_weight="1"
+ android:layout_marginLeft="8dp"
+ android:layout_marginRight="8dp" />
+ </LinearLayout>
+
+ <!-- Optional content view section. -->
+ <FrameLayout android:id="@+id/media_route_control_frame"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:visibility="gone" />
+
+ <!-- Disconnect button. -->
+ <LinearLayout android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ style="?attr/buttonBarStyle">
+ <Button android:id="@+id/media_route_disconnect_button"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ style="?attr/buttonBarButtonStyle"
+ android:gravity="center"
+ android:text="@string/media_route_controller_disconnect" />
+ </LinearLayout>
+</LinearLayout>
diff --git a/core/res/res/layout/media_route_list_item.xml b/core/res/res/layout/media_route_list_item.xml
index 423d544..bdca433 100644
--- a/core/res/res/layout/media_route_list_item.xml
+++ b/core/res/res/layout/media_route_list_item.xml
@@ -20,13 +20,6 @@
android:background="@drawable/item_background_activated_holo_dark"
android:gravity="center_vertical">
- <ImageView android:layout_width="56dp"
- android:layout_height="56dp"
- android:scaleType="center"
- android:id="@+id/icon"
- android:visibility="gone"
- android:duplicateParentState="true" />
-
<LinearLayout android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
@@ -53,14 +46,4 @@
android:duplicateParentState="true" />
</LinearLayout>
- <ImageButton
- android:layout_width="56dp"
- android:layout_height="56dp"
- android:id="@+id/expand_button"
- android:background="?android:attr/selectableItemBackground"
- android:src="@drawable/ic_media_group_expand"
- android:scaleType="center"
- android:visibility="gone"
- android:duplicateParentState="true" />
-
</LinearLayout>
diff --git a/core/res/res/layout/media_route_list_item_checkable.xml b/core/res/res/layout/media_route_list_item_checkable.xml
deleted file mode 100644
index 5fb82f7..0000000
--- a/core/res/res/layout/media_route_list_item_checkable.xml
+++ /dev/null
@@ -1,60 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2012 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.
--->
-
-<com.android.internal.view.CheckableLinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="match_parent"
- android:layout_height="?android:attr/listPreferredItemHeight"
- android:background="?android:attr/selectableItemBackground"
- android:gravity="center_vertical">
-
- <ImageView android:layout_width="56dp"
- android:layout_height="56dp"
- android:scaleType="center"
- android:id="@+id/icon"
- android:visibility="gone" />
-
- <LinearLayout android:layout_width="0dp"
- android:layout_height="match_parent"
- android:layout_weight="1"
- android:orientation="vertical"
- android:gravity="start|center_vertical"
- android:paddingStart="?android:attr/listPreferredItemPaddingStart"
- android:paddingEnd="?android:attr/listPreferredItemPaddingEnd">
-
- <TextView android:id="@android:id/text1"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:singleLine="true"
- android:ellipsize="marquee"
- android:textAppearance="?android:attr/textAppearanceMedium" />
-
- <TextView android:id="@android:id/text2"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:singleLine="true"
- android:ellipsize="marquee"
- android:textAppearance="?android:attr/textAppearanceSmall" />
- </LinearLayout>
-
- <CheckBox
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_marginEnd="16dp"
- android:id="@+id/check"
- android:focusable="false"
- android:clickable="false" />
-
-</com.android.internal.view.CheckableLinearLayout>
diff --git a/core/res/res/layout/media_route_list_item_collapse_group.xml b/core/res/res/layout/media_route_list_item_collapse_group.xml
deleted file mode 100644
index 323e24d..0000000
--- a/core/res/res/layout/media_route_list_item_collapse_group.xml
+++ /dev/null
@@ -1,44 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2012 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.
--->
-
-<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:background="?android:attr/selectableItemBackground">
- <LinearLayout
- android:layout_width="match_parent"
- android:layout_height="?android:attr/listPreferredItemHeightSmall"
- android:background="#19ffffff"
- android:paddingStart="?android:attr/listPreferredItemPaddingStart"
- android:paddingEnd="?android:attr/listPreferredItemPaddingEnd"
- android:gravity="center_vertical">
-
- <TextView android:layout_width="0dp"
- android:layout_height="wrap_content"
- android:layout_weight="1"
- android:singleLine="true"
- android:ellipsize="marquee"
- android:text="@string/media_route_chooser_grouping_done"
- android:textAppearance="?android:attr/textAppearanceMedium" />
-
- <ImageView
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:src="@drawable/ic_media_group_collapse"
- android:scaleType="center" />
-
- </LinearLayout>
-</FrameLayout>
\ No newline at end of file
diff --git a/core/res/res/layout/media_route_list_item_section_header.xml b/core/res/res/layout/media_route_list_item_section_header.xml
deleted file mode 100644
index 949635f..0000000
--- a/core/res/res/layout/media_route_list_item_section_header.xml
+++ /dev/null
@@ -1,34 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2012 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.
--->
-
-<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:paddingTop="16dp">
- <TextView
- android:id="@android:id/text1"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:textAppearance="?android:attr/textAppearanceSmall"
- android:background="#19ffffff"
- android:textStyle="bold"
- android:textAllCaps="true"
- android:gravity="center_vertical"
- android:paddingStart="?android:attr/listPreferredItemPaddingStart"
- android:paddingEnd="?android:attr/listPreferredItemPaddingEnd"
- android:minHeight="24dp"
- />
-</FrameLayout>
diff --git a/core/res/res/layout/media_route_list_item_top_header.xml b/core/res/res/layout/media_route_list_item_top_header.xml
deleted file mode 100644
index 0c49b24..0000000
--- a/core/res/res/layout/media_route_list_item_top_header.xml
+++ /dev/null
@@ -1,29 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2012 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-
-<TextView xmlns:android="http://schemas.android.com/apk/res/android"
- android:id="@android:id/text1"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:textAppearance="?android:attr/textAppearanceSmall"
- android:background="#19ffffff"
- android:textStyle="bold"
- android:textAllCaps="true"
- android:gravity="center_vertical"
- android:paddingStart="?android:attr/listPreferredItemPaddingStart"
- android:paddingEnd="?android:attr/listPreferredItemPaddingEnd"
- android:minHeight="24dp"
-/>
diff --git a/core/res/res/values-af/strings.xml b/core/res/res/values-af/strings.xml
index b27ac62..0358de3 100644
--- a/core/res/res/values-af/strings.xml
+++ b/core/res/res/values-af/strings.xml
@@ -382,6 +382,8 @@
<string name="permdesc_bindVpnService" msgid="2067845564581693905">"Dit laat die houer toe om aan die topvlak-koppelvlak van \'n VPN-diens te bind. Dit moet nooit vir normale programme nodig wees nie."</string>
<string name="permlab_bindWallpaper" msgid="8716400279937856462">"bind aan \'n muurpapier"</string>
<string name="permdesc_bindWallpaper" msgid="7108428692595491668">"Dit laat die houer toe om aan die topvlak-koppelvlak van \'n muurpapier te bind. Dit moet nooit vir normale programme nodig wees nie."</string>
+ <string name="permlab_bindRemoteDisplay" msgid="1782923938029941960">"koppel aan \'n afstandskerm"</string>
+ <string name="permdesc_bindRemoteDisplay" msgid="1261242718727295981">"Dit laat die houer toe om aan die top-koppelvlak van \'n afstandskerm te koppel. Behoort nooit vir gewone programme nodig te wees nie."</string>
<string name="permlab_bindRemoteViews" msgid="5697987759897367099">"bind aan \'n legstukdiens"</string>
<string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"Dit laat die houer toe om aan die topvlak-koppelvlak van \'n legstuk-diens te bind. Dit moet nooit vir normale programme nodig wees nie."</string>
<string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"skakel met \'n toestel-admin"</string>
@@ -1489,8 +1491,12 @@
<string name="default_audio_route_category_name" msgid="3722811174003886946">"Stelsel"</string>
<string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Bluetooth-oudio"</string>
<string name="wireless_display_route_description" msgid="9070346425023979651">"Draadlose skerm"</string>
- <string name="media_route_chooser_grouping_done" msgid="7966438307723317169">"Klaar"</string>
<string name="media_route_button_content_description" msgid="5758553567065145276">"Media-uitvoer"</string>
+ <string name="media_route_chooser_title" msgid="1751618554539087622">"Koppel aan toestel"</string>
+ <string name="media_route_chooser_title_for_remote_display" msgid="3395541745872017583">"Saai skerm uit na toestel"</string>
+ <string name="media_route_chooser_searching" msgid="4776236202610828706">"Soek tans vir toestelle…"</string>
+ <string name="media_route_chooser_extended_settings" msgid="87015534236701604">"Instellings"</string>
+ <string name="media_route_controller_disconnect" msgid="8966120286374158649">"Ontkoppel"</string>
<string name="media_route_status_scanning" msgid="7279908761758293783">"Skandeer tans..."</string>
<string name="media_route_status_connecting" msgid="6422571716007825440">"Koppel tans..."</string>
<string name="media_route_status_available" msgid="6983258067194649391">"Beskikbaar"</string>
@@ -1501,8 +1507,10 @@
<string name="display_manager_overlay_display_name" msgid="5142365982271620716">"Oorlegger #<xliff:g id="ID">%1$d</xliff:g>"</string>
<string name="display_manager_overlay_display_title" msgid="652124517672257172">"<xliff:g id="NAME">%1$s</xliff:g>: <xliff:g id="WIDTH">%2$d</xliff:g>x<xliff:g id="HEIGHT">%3$d</xliff:g>, <xliff:g id="DPI">%4$d</xliff:g> dpi"</string>
<string name="display_manager_overlay_display_secure_suffix" msgid="6022119702628572080">", veilig"</string>
- <string name="wifi_display_notification_title" msgid="2223050649240326557">"Draadlose skerm is gekoppel"</string>
- <string name="wifi_display_notification_message" msgid="4498802012464170685">"Hierdie skerm word op \'n ander toestel gewys"</string>
+ <string name="wifi_display_notification_connecting_title" msgid="2838646471050359706">"Skerm word tans uitgesaai"</string>
+ <string name="wifi_display_notification_connecting_message" msgid="5837350993752841389">"Koppel tans aan <xliff:g id="NAME">%1$s</xliff:g>"</string>
+ <string name="wifi_display_notification_connected_title" msgid="8567308065912676285">"Skerm word tans uitgesaai"</string>
+ <string name="wifi_display_notification_connected_message" msgid="2587209325701109715">"Gekoppel aan <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="wifi_display_notification_disconnect" msgid="6183754463561153372">"Ontkoppel"</string>
<string name="kg_emergency_call_label" msgid="684946192523830531">"Noodoproep"</string>
<string name="kg_forgot_pattern_button_text" msgid="8852021467868220608">"Het jy die patroon vergeet?"</string>
diff --git a/core/res/res/values-am/strings.xml b/core/res/res/values-am/strings.xml
index 1f9599d..1e320e2 100644
--- a/core/res/res/values-am/strings.xml
+++ b/core/res/res/values-am/strings.xml
@@ -269,7 +269,7 @@
<string name="permdesc_sendSms" msgid="7094729298204937667">"መተግበሪያው የኤስ.ኤም.ኤስ. መልዕክቶችን እንዲልክ ይፈቅድለታል። ይህ ያልተጠበቁ ወጪዎችን ሊያስከትል ይችላል። ተንኮል አዘል መተግበሪያዎች ያላንተ ማረጋገጫ መልዕክቶችን በመላክ ገንዘብ ሊያስወጡህ ይችላሉ።"</string>
<string name="permlab_sendRespondViaMessageRequest" msgid="8713889105305943200">"የበመልዕክት-በኩል-ምላሽ-ስጥ ክስተቶችን ይላኩ"</string>
<string name="permdesc_sendRespondViaMessageRequest" msgid="7107648548468778734">"መተግበሪያው ሌሎች የመልዕክት መላኪያ መተግበሪያዎች ለመጪ ጥሪዎች በመልዕክት-በኩል-ምላሽ-መስጠት ስራን እንዲይዙ ጥያቄዎች እንዲልክላቸው ያስችለዋል።"</string>
- <string name="permlab_readSms" msgid="8745086572213270480">"የጽሑፍ መልዕክቶችህን አንብብ (ኤስ.ኤም.ኤስ. ወይም ኤም.ኤም.ኤስ.)"</string>
+ <string name="permlab_readSms" msgid="8745086572213270480">"የጽሑፍ መልዕክቶችዎን ያንብቡ (ኤስ.ኤም.ኤስ. ወይም ኤም.ኤም.ኤስ.)"</string>
<string name="permdesc_readSms" product="tablet" msgid="2467981548684735522">"መገለጫው በጡባዊ ቱኮህ ወይም በSIM ካርድህ የተከማቹ የኤስ.ኤም.ኤስ. መልእክቶችን እንዲያነብ ይፈቅድለታል። ይህ መተግበሪያው ይዘት ወይም ሚስጥራዊነትን ከግምት ሳያስገባ ሁሉንም የኤስ.ኤም.ኤስ. መልእክቶች እንዲያነብ ይፈቅድለታል።"</string>
<string name="permdesc_readSms" product="default" msgid="3695967533457240550">"መገለጫው በስልክህ ወይም በSIM ካርድህ የተከማቹ የኤስ.ኤም.ኤስ. መልእክቶችን እንዲያነብ ይፈቅድለታል። ይህ መተግበሪያው ይዘት ወይም ሚስጥራዊነትን ከግምት ሳያስገባ ሁሉንም የኤስ.ኤም.ኤስ. መልእክቶች እንዲያነብ ይፈቅድለታል።"</string>
<string name="permlab_writeSms" msgid="3216950472636214774">"የጽሑፍ መልዕክቶችህን አርትዕ (ኤስ.ኤም.ኤስ. ወይም ኤም.ኤም.ኤስ.)"</string>
@@ -382,6 +382,8 @@
<string name="permdesc_bindVpnService" msgid="2067845564581693905">"የVPN ግልጋሎትን ወደ ከፍተኛ-ደረጃ በየነ ገጽ ለማሳር ለመያዣው ይፈቅዳሉ፡፡ለተለመዱ መተግበሪያዎች አያስፈልግም፡፡"</string>
<string name="permlab_bindWallpaper" msgid="8716400279937856462">"በልጣፍ ጠርዝ"</string>
<string name="permdesc_bindWallpaper" msgid="7108428692595491668">"ያዡ ግቤት ስልቱን ወደ ከፍተኛ-ደረጃ ልጣፍ ለመጠረዝ ይፈቅዳሉ። ለመደበኛ ትግበራዎች በፍፁም አያስፈልግም።"</string>
+ <string name="permlab_bindRemoteDisplay" msgid="1782923938029941960">"ከአንድ የርቀት ማሳያ ጋር ይጠርዛል"</string>
+ <string name="permdesc_bindRemoteDisplay" msgid="1261242718727295981">"ያዢው ከአንድ የርቀት ማሳያ ከፍተኛ-ደረጃ በይነገጽ ጋር እንዲጠርዝ ይፈቅድለታል። ለመደበኛ መተግበሪያዎች በጭራሽ አያስፈልግም።"</string>
<string name="permlab_bindRemoteViews" msgid="5697987759897367099">"ወደ ፍርግም አገልግሎት አያይዝ"</string>
<string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"ያዡ ግቤት ስልቱን ወደ ከፍተኛ-ደረጃ ፍርግም አገልግሎት ለመጠረዝ ይፈቅዳሉ። ለመደበኛ ትግበራዎች በፍፁም አያስፈልግም።"</string>
<string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"ከመሣሪያ አስተዳደር ጋር ተገናኝ"</string>
@@ -498,9 +500,9 @@
<string name="permdesc_mediaContentControl" msgid="1637478200272062">"መተግበሪያው የሚዲያ መልሰህ አጫውትን እንዲቆጣጠር እና የሚዲያ መረጃውን (ርእስ፣ ደራሲ...) እንዲደርስ ይፈቅድለታል።"</string>
<string name="permlab_modifyAudioSettings" msgid="6095859937069146086">"የድምፅ ቅንብሮችን ለውጥ"</string>
<string name="permdesc_modifyAudioSettings" msgid="3522565366806248517">"መተግበሪያው አንደ የድምጽ መጠን እና ለውጽአት የትኛውን የድምጽ ማጉያ ጥቅም ላይ እንደዋለ የመሳሰሉ ሁለንተናዊ የድምጽ ቅንብሮችን እንዲያስተካክል ይፈቅድለታል።"</string>
- <string name="permlab_recordAudio" msgid="3876049771427466323">"ኦዲዮ ቅዳ"</string>
+ <string name="permlab_recordAudio" msgid="3876049771427466323">"ኦዲዮ ይቅዱ"</string>
<string name="permdesc_recordAudio" msgid="4906839301087980680">"መተግበሪያው ድምጽን በማይክሮፎን እንዲቀዳ ይፈቅድለታል። ይህ ፈቃድ መተግበሪያው ያላንተ ማረጋገጫ በማንኛውም ጊዜ ድምጽ እንዲቀዳ ይፈቅድለታል።"</string>
- <string name="permlab_camera" msgid="3616391919559751192">"ፎቶዎች እና ቪዲዮዎች አንሳ"</string>
+ <string name="permlab_camera" msgid="3616391919559751192">"ፎቶዎች እና ቪዲዮዎች ያንሱ"</string>
<string name="permdesc_camera" msgid="8497216524735535009">"መተግበሪያው በካሜራው ፎቶዎችንና ቪዲዮዎችን እንዲያነሳ ይፈቅድለታል። ይህ ፈቃድ መተግበሪያው ካሜራውን በማንኛውም ጊዜ ያላንተ ማረጋገጫ እንዲጠቀም ይፈቅድለታል።"</string>
<string name="permlab_cameraDisableTransmitLed" msgid="2651072630501126222">"ካሜራው ስራ ላይ ሲሆን የማስተላለፍ አመልካች ኤል ኢ ዲን ያሰናክሉ"</string>
<string name="permdesc_cameraDisableTransmitLed" msgid="4764585465480295341">"ቀድሞ የተጫነ የስርዓት መተግበሪያ ካሜራውን አመላካች ኤል ኢ ዲ እንዳይጠቀም እንዲያሰናክል ያስችለዋል።"</string>
@@ -583,12 +585,12 @@
<string name="permdesc_setTimeZone" product="default" msgid="4499943488436633398">" የስልኩን ሰዓት መለወጥ ለመተግበሪያው ይፈቅዳሉ።"</string>
<string name="permlab_accountManagerService" msgid="4829262349691386986">"እንደ አውርድአዸራጅአገልግሎት"</string>
<string name="permdesc_accountManagerService" msgid="1948455552333615954">" ወደ መለያ አረጋጋጮች ጥሪ ለማድረግ ለመተግበሪያ ይፈቅዳሉ።"</string>
- <string name="permlab_getAccounts" msgid="1086795467760122114">"መሣሪያው ላይ ያሉ መለያዎችን አግኝ"</string>
+ <string name="permlab_getAccounts" msgid="1086795467760122114">"መሣሪያው ላይ ያሉ መለያዎችን ያግኙ"</string>
<string name="permdesc_getAccounts" product="tablet" msgid="2741496534769660027">"መተግበሪያው በጡባዊ ተኮው የሚታወቁትን መለያዎች ዝርዝር እንዲያገኝ ይፈቅድለታል። ይህ በጫንዋቸው ማናቸውም መተግበሪያዎች የተፈጠሩ መለያዎችን ሊያጠቃልል ይችላል።"</string>
<string name="permdesc_getAccounts" product="default" msgid="3448316822451807382">"መተግበሪያው በስልኩ የሚታወቁትን መለያዎች ዝርዝር እንዲያገኝ ይፈቅድለታል። ይህ በጫንዋቸው ማናቸውም መተግበሪያዎች የተፈጠሩ መለያዎችን ሊያጠቃልል ይችላል።"</string>
<string name="permlab_authenticateAccounts" msgid="5265908481172736933">"መለያዎችን ፍጠርና የይለፍ ቃላትን አስቀምጥ"</string>
<string name="permdesc_authenticateAccounts" msgid="5472124296908977260">"የመለያ አረጋጋጭ መለያ መናጅ ችሎታን ለመጠቀም፣ መለያ መፍጠር እና የይለፍ ቃሎችን ለማግኘት እና ለማቀናጀት አክሎ ለመተግበሪያው ይፈቅዳሉ ።"</string>
- <string name="permlab_manageAccounts" msgid="4983126304757177305">"መለያዎችን አክል ወይም አስወግድ"</string>
+ <string name="permlab_manageAccounts" msgid="4983126304757177305">"መለያዎችን ያክሉ ወይም ያስወግዱ"</string>
<string name="permdesc_manageAccounts" msgid="8698295625488292506">"መለያዎችን እንደ ማከል እና ማስወገድ ክወናዎችን እና የይለፍ ቃልን መሰረዝ ለማከናወን ለመተግበሪያው ይፈቅዳሉ፡፡"</string>
<string name="permlab_useCredentials" msgid="235481396163877642">"በመሣሪያው ላይ ያሉ መለያዎችን ይጠቀሙ"</string>
<string name="permdesc_useCredentials" msgid="7984227147403346422">"የማረጋገጫ የምስጋና የምስክር ወረቀትን ለመጠየቅ ለመተግበሪያው ይፈቅዳሉ፡፡"</string>
@@ -643,7 +645,7 @@
<string name="permdesc_readDictionary" msgid="659614600338904243">"መተግበሪያው ተጠቃሚው በተጠቃሚው መዝገበ-ቃላት አከማችቷቸው ሊሆኑ የሚችሉ ሁሉንም ቃላት፣ ስሞችና ሐረጋት እንዲያነባቸው ይፈቅድለታል።"</string>
<string name="permlab_writeDictionary" msgid="2183110402314441106">"በተጠቃሚ በተገለጸ መዝገበ ቃላት ላይ ቃላትን ያክላል"</string>
<string name="permdesc_writeDictionary" msgid="8185385716255065291">"በተጠቃሚ መዝገበ ቃላት ውስጥ አዲስ ቃል እንዲጽፍ ለመተግበሪያው ይፈቅዳሉ፡፡"</string>
- <string name="permlab_sdcardRead" product="nosdcard" msgid="367275095159405468">"የUSB ማከማቻህን ይዘቶች አንብብ"</string>
+ <string name="permlab_sdcardRead" product="nosdcard" msgid="367275095159405468">"የUSB ማከማቻዎን ይዘቶች ያንብቡ"</string>
<string name="permlab_sdcardRead" product="default" msgid="2188156462934977940">"የSD ካርድህን ይዘቶች አንብብ"</string>
<string name="permdesc_sdcardRead" product="nosdcard" msgid="3446988712598386079">"መተግበሪያው የእርስዎ USB ማከማቻ ይዘቶችን እንዲያነብ ያስችለዋል።"</string>
<string name="permdesc_sdcardRead" product="default" msgid="2607362473654975411">"መተግበሪያው የእርስዎ SD ካርድ ይዘቶችን እንዲያነብ ያስችለዋል።"</string>
@@ -1489,8 +1491,12 @@
<string name="default_audio_route_category_name" msgid="3722811174003886946">"ስርዓት"</string>
<string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"የብሉቱዝ ድምጽ"</string>
<string name="wireless_display_route_description" msgid="9070346425023979651">"ገመድ አልባ ማሳያ"</string>
- <string name="media_route_chooser_grouping_done" msgid="7966438307723317169">"ተከናውኗል"</string>
<string name="media_route_button_content_description" msgid="5758553567065145276">"የሚዲያ ውጽዓት"</string>
+ <string name="media_route_chooser_title" msgid="1751618554539087622">"ከመሳሪያ ጋር ያገናኙ"</string>
+ <string name="media_route_chooser_title_for_remote_display" msgid="3395541745872017583">"ማያ ገጽን ወደ መሣሪያ ይውሰዱ"</string>
+ <string name="media_route_chooser_searching" msgid="4776236202610828706">"መሳሪያዎችን በመፈለግ ላይ…"</string>
+ <string name="media_route_chooser_extended_settings" msgid="87015534236701604">"ቅንብሮች"</string>
+ <string name="media_route_controller_disconnect" msgid="8966120286374158649">"ግንኙነት አቋርጥ"</string>
<string name="media_route_status_scanning" msgid="7279908761758293783">"በመቃኘት ላይ..."</string>
<string name="media_route_status_connecting" msgid="6422571716007825440">"በማገናኘት ላይ..."</string>
<string name="media_route_status_available" msgid="6983258067194649391">"የሚገኙ"</string>
@@ -1501,8 +1507,10 @@
<string name="display_manager_overlay_display_name" msgid="5142365982271620716">"ተደራቢ #<xliff:g id="ID">%1$d</xliff:g>"</string>
<string name="display_manager_overlay_display_title" msgid="652124517672257172">"<xliff:g id="NAME">%1$s</xliff:g>፦ <xliff:g id="WIDTH">%2$d</xliff:g>x<xliff:g id="HEIGHT">%3$d</xliff:g>፣ <xliff:g id="DPI">%4$d</xliff:g> dpi"</string>
<string name="display_manager_overlay_display_secure_suffix" msgid="6022119702628572080">"፣ የተጠበቀ"</string>
- <string name="wifi_display_notification_title" msgid="2223050649240326557">"ገመድ አልባ ማሳያ ተገናኝቷል"</string>
- <string name="wifi_display_notification_message" msgid="4498802012464170685">"ይህ ማያ ገጽ በሌላ መሣሪያ ላይ እያሳየ ነው"</string>
+ <string name="wifi_display_notification_connecting_title" msgid="2838646471050359706">"ማያ ገጽን በመውሰድ ላይ"</string>
+ <string name="wifi_display_notification_connecting_message" msgid="5837350993752841389">"ከ<xliff:g id="NAME">%1$s</xliff:g> ጋር በመገናኘት ላይ"</string>
+ <string name="wifi_display_notification_connected_title" msgid="8567308065912676285">"ማያ ገጽን በመውሰድ ላይ"</string>
+ <string name="wifi_display_notification_connected_message" msgid="2587209325701109715">"ከ<xliff:g id="NAME">%1$s</xliff:g> ጋር ተገናኝቷል"</string>
<string name="wifi_display_notification_disconnect" msgid="6183754463561153372">"ግንኙነት አቋርጥ"</string>
<string name="kg_emergency_call_label" msgid="684946192523830531">"የአደጋ ጊዜ ጥሪ"</string>
<string name="kg_forgot_pattern_button_text" msgid="8852021467868220608">"ስርዓተ ጥለቱን እርሳ"</string>
diff --git a/core/res/res/values-ar/strings.xml b/core/res/res/values-ar/strings.xml
index ab03375..18296ea 100644
--- a/core/res/res/values-ar/strings.xml
+++ b/core/res/res/values-ar/strings.xml
@@ -382,6 +382,8 @@
<string name="permdesc_bindVpnService" msgid="2067845564581693905">"للسماح للمالك بالالتزام بواجهة المستوى العلوي لخدمة الشبكة الظاهرية الخاصة (VPN). لن تكون هناك حاجة إليه مطلقًا مع التطبيقات العادية."</string>
<string name="permlab_bindWallpaper" msgid="8716400279937856462">"الالتزام بخلفية ما"</string>
<string name="permdesc_bindWallpaper" msgid="7108428692595491668">"للسماح للمالك بالالتزام بواجهة المستوى العلوي للخلفية. لن تكون هناك حاجة إليه مطلقًا مع التطبيقات العادية."</string>
+ <string name="permlab_bindRemoteDisplay" msgid="1782923938029941960">"الربط بالشاشة عن بُعد"</string>
+ <string name="permdesc_bindRemoteDisplay" msgid="1261242718727295981">"للسماح للمالك بالالتزام بواجهة المستوى العلوي للعرض عن بُعد. لن تكون هناك حاجة إليه مطلقًا مع التطبيقات العادية."</string>
<string name="permlab_bindRemoteViews" msgid="5697987759897367099">"الالتزام بخدمة أداة"</string>
<string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"للسماح للمالك بالالتزام بواجهة المستوى العلوي لخدمة الأداة. لن تكون هناك حاجة إليه مطلقًا مع التطبيقات العادية."</string>
<string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"التفاعل مع مشرف الجهاز"</string>
@@ -1489,8 +1491,12 @@
<string name="default_audio_route_category_name" msgid="3722811174003886946">"النظام"</string>
<string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"صوت بلوتوث"</string>
<string name="wireless_display_route_description" msgid="9070346425023979651">"عرض شاشة لاسلكي"</string>
- <string name="media_route_chooser_grouping_done" msgid="7966438307723317169">"تم"</string>
<string name="media_route_button_content_description" msgid="5758553567065145276">"المنفذ الإعلامي"</string>
+ <string name="media_route_chooser_title" msgid="1751618554539087622">"الاتصال بجهاز"</string>
+ <string name="media_route_chooser_title_for_remote_display" msgid="3395541745872017583">"بث الشاشة على الجهاز"</string>
+ <string name="media_route_chooser_searching" msgid="4776236202610828706">"جارٍ البحث عن الأجهزة…"</string>
+ <string name="media_route_chooser_extended_settings" msgid="87015534236701604">"الإعدادات"</string>
+ <string name="media_route_controller_disconnect" msgid="8966120286374158649">"قطع الاتصال"</string>
<string name="media_route_status_scanning" msgid="7279908761758293783">"جارٍ الفحص..."</string>
<string name="media_route_status_connecting" msgid="6422571716007825440">"جارٍ الاتصال..."</string>
<string name="media_route_status_available" msgid="6983258067194649391">"متاح"</string>
@@ -1501,8 +1507,10 @@
<string name="display_manager_overlay_display_name" msgid="5142365982271620716">"المركب #<xliff:g id="ID">%1$d</xliff:g>"</string>
<string name="display_manager_overlay_display_title" msgid="652124517672257172">"<xliff:g id="NAME">%1$s</xliff:g>: <xliff:g id="WIDTH">%2$d</xliff:g>x<xliff:g id="HEIGHT">%3$d</xliff:g>، <xliff:g id="DPI">%4$d</xliff:g> نقطة لكل بوصة"</string>
<string name="display_manager_overlay_display_secure_suffix" msgid="6022119702628572080">"آمن"</string>
- <string name="wifi_display_notification_title" msgid="2223050649240326557">"تم التوصيل بشاشة لاسلكية"</string>
- <string name="wifi_display_notification_message" msgid="4498802012464170685">"يتم عرض هذه الشاشة على جهاز آخر"</string>
+ <string name="wifi_display_notification_connecting_title" msgid="2838646471050359706">"جارٍ بث الشاشة"</string>
+ <string name="wifi_display_notification_connecting_message" msgid="5837350993752841389">"جارٍ الاتصال بـ <xliff:g id="NAME">%1$s</xliff:g>"</string>
+ <string name="wifi_display_notification_connected_title" msgid="8567308065912676285">"جارٍ بث الشاشة"</string>
+ <string name="wifi_display_notification_connected_message" msgid="2587209325701109715">"متصل بـ <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="wifi_display_notification_disconnect" msgid="6183754463561153372">"قطع الاتصال"</string>
<string name="kg_emergency_call_label" msgid="684946192523830531">"الاتصال بالطوارئ"</string>
<string name="kg_forgot_pattern_button_text" msgid="8852021467868220608">"نسيت النقش"</string>
diff --git a/core/res/res/values-be/strings.xml b/core/res/res/values-be/strings.xml
index 00a77a3..a0dd5d8 100644
--- a/core/res/res/values-be/strings.xml
+++ b/core/res/res/values-be/strings.xml
@@ -396,6 +396,10 @@
<string name="permdesc_bindVpnService" msgid="2067845564581693905">"Дазваляе ўладальніку звязвацца з інтэрфейсам службы VPN вышэйшага ўзроўню. Не патрэбна для звычайных прыкладанняў."</string>
<string name="permlab_bindWallpaper" msgid="8716400279937856462">"прывязаць да шпалер"</string>
<string name="permdesc_bindWallpaper" msgid="7108428692595491668">"Дазваляе ўладальніку ўсталёўваць прывязку да інтэрфейсу шпалер верхняга ўзроўню. Не патрабуецца для звычайных прыкладанняў."</string>
+ <!-- no translation found for permlab_bindRemoteDisplay (1782923938029941960) -->
+ <skip />
+ <!-- no translation found for permdesc_bindRemoteDisplay (1261242718727295981) -->
+ <skip />
<string name="permlab_bindRemoteViews" msgid="5697987759897367099">"прывязаць да службы віджэту"</string>
<string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"Дазваляе ўладальніку прывязвацца да інтэрфейсу верхняга ўзроўню службы віджэта. Не патрабуецца для звычайных прыкладанняў."</string>
<string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"узаемадзейнічаць з адміністратарам прылады"</string>
@@ -1536,8 +1540,15 @@
<string name="default_audio_route_category_name" msgid="3722811174003886946">"Сістэма"</string>
<string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Bluetooth-аўдыё"</string>
<string name="wireless_display_route_description" msgid="9070346425023979651">"Бесправадны дысплей"</string>
- <string name="media_route_chooser_grouping_done" msgid="7966438307723317169">"Гатова"</string>
<string name="media_route_button_content_description" msgid="5758553567065145276">"Мультымедыйны выхад"</string>
+ <!-- no translation found for media_route_chooser_title (1751618554539087622) -->
+ <skip />
+ <!-- no translation found for media_route_chooser_searching (4776236202610828706) -->
+ <skip />
+ <!-- no translation found for media_route_chooser_extended_settings (87015534236701604) -->
+ <skip />
+ <!-- no translation found for media_route_controller_disconnect (8966120286374158649) -->
+ <skip />
<string name="media_route_status_scanning" msgid="7279908761758293783">"Сканiраванне..."</string>
<string name="media_route_status_connecting" msgid="6422571716007825440">"Падключэнне..."</string>
<string name="media_route_status_available" msgid="6983258067194649391">"Даступна"</string>
@@ -1550,8 +1561,14 @@
<string name="display_manager_overlay_display_title" msgid="652124517672257172">"<xliff:g id="NAME">%1$s</xliff:g>: <xliff:g id="WIDTH">%2$d</xliff:g>x<xliff:g id="HEIGHT">%3$d</xliff:g>, <xliff:g id="DPI">%4$d</xliff:g> кр. на цалю"</string>
<!-- no translation found for display_manager_overlay_display_secure_suffix (6022119702628572080) -->
<skip />
- <string name="wifi_display_notification_title" msgid="2223050649240326557">"Падключаны бесправадны дысплей"</string>
- <string name="wifi_display_notification_message" msgid="4498802012464170685">"Гэты экран паказваецца на іншай прыладзе"</string>
+ <!-- no translation found for wifi_display_notification_connecting_title (9102788196896266990) -->
+ <skip />
+ <!-- no translation found for wifi_display_notification_connecting_message (5837350993752841389) -->
+ <skip />
+ <!-- no translation found for wifi_display_notification_connected_title (4118323329495921271) -->
+ <skip />
+ <!-- no translation found for wifi_display_notification_connected_message (2587209325701109715) -->
+ <skip />
<string name="wifi_display_notification_disconnect" msgid="6183754463561153372">"Адключыць"</string>
<string name="kg_emergency_call_label" msgid="684946192523830531">"Экстранны выклік"</string>
<string name="kg_forgot_pattern_button_text" msgid="8852021467868220608">"Забылі ключ"</string>
diff --git a/core/res/res/values-bg/strings.xml b/core/res/res/values-bg/strings.xml
index d16796e..0d1cdaf 100644
--- a/core/res/res/values-bg/strings.xml
+++ b/core/res/res/values-bg/strings.xml
@@ -382,6 +382,8 @@
<string name="permdesc_bindVpnService" msgid="2067845564581693905">"Разрешава на притежателя да се обвърже с интерфейса от най-високото ниво на услуга за VPN. Нормалните приложения би трябвало никога да не се нуждаят от това."</string>
<string name="permlab_bindWallpaper" msgid="8716400279937856462">"обвързване с тапет"</string>
<string name="permdesc_bindWallpaper" msgid="7108428692595491668">"Разрешава на притежателя да се обвърже с интерфейса от най-високото ниво на тапет. Нормалните приложения би трябвало никога да не се нуждаят от това."</string>
+ <string name="permlab_bindRemoteDisplay" msgid="1782923938029941960">"свързване с отдалечен екран"</string>
+ <string name="permdesc_bindRemoteDisplay" msgid="1261242718727295981">"Разрешава на притежателя да се свърже с интерфейса от първо ниво на отдалечен екран. Нормалните приложения би трябвало никога да не се нуждаят от това."</string>
<string name="permlab_bindRemoteViews" msgid="5697987759897367099">"обвързване с услуга за приспособления"</string>
<string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"Разрешава на притежателя да се обвърже с интерфейса от най-високото ниво на услуга за приспособления. Нормалните приложения би трябвало никога да не се нуждаят от това."</string>
<string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"взаимодействие с администратор на устройството"</string>
@@ -1489,8 +1491,12 @@
<string name="default_audio_route_category_name" msgid="3722811174003886946">"Система"</string>
<string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Звук през Bluetooth"</string>
<string name="wireless_display_route_description" msgid="9070346425023979651">"Безжичен дисплей"</string>
- <string name="media_route_chooser_grouping_done" msgid="7966438307723317169">"Готово"</string>
<string name="media_route_button_content_description" msgid="5758553567065145276">"Изходяща мултимедия"</string>
+ <string name="media_route_chooser_title" msgid="1751618554539087622">"Свързване с устройство"</string>
+ <string name="media_route_chooser_title_for_remote_display" msgid="3395541745872017583">"Екран за предаване към устройството"</string>
+ <string name="media_route_chooser_searching" msgid="4776236202610828706">"Търсят се устройства…"</string>
+ <string name="media_route_chooser_extended_settings" msgid="87015534236701604">"Настройки"</string>
+ <string name="media_route_controller_disconnect" msgid="8966120286374158649">"Прекратяване на връзката"</string>
<string name="media_route_status_scanning" msgid="7279908761758293783">"Сканира се..."</string>
<string name="media_route_status_connecting" msgid="6422571716007825440">"Установява се връзка..."</string>
<string name="media_route_status_available" msgid="6983258067194649391">"Налице"</string>
@@ -1501,8 +1507,10 @@
<string name="display_manager_overlay_display_name" msgid="5142365982271620716">"Наслагване №<xliff:g id="ID">%1$d</xliff:g>"</string>
<string name="display_manager_overlay_display_title" msgid="652124517672257172">"„<xliff:g id="NAME">%1$s</xliff:g>“: <xliff:g id="WIDTH">%2$d</xliff:g> x <xliff:g id="HEIGHT">%3$d</xliff:g>, <xliff:g id="DPI">%4$d</xliff:g> dpi"</string>
<string name="display_manager_overlay_display_secure_suffix" msgid="6022119702628572080">", защитено"</string>
- <string name="wifi_display_notification_title" msgid="2223050649240326557">"Безжичният дисплей е свързан"</string>
- <string name="wifi_display_notification_message" msgid="4498802012464170685">"Този екран се показва на друго устройство"</string>
+ <string name="wifi_display_notification_connecting_title" msgid="2838646471050359706">"Екранът се предава"</string>
+ <string name="wifi_display_notification_connecting_message" msgid="5837350993752841389">"Установява се връзка с/ъс „<xliff:g id="NAME">%1$s</xliff:g>“"</string>
+ <string name="wifi_display_notification_connected_title" msgid="8567308065912676285">"Екранът се предава"</string>
+ <string name="wifi_display_notification_connected_message" msgid="2587209325701109715">"Установена е връзка с/ъс „<xliff:g id="NAME">%1$s</xliff:g>“"</string>
<string name="wifi_display_notification_disconnect" msgid="6183754463561153372">"Прекратяване на връзката"</string>
<string name="kg_emergency_call_label" msgid="684946192523830531">"Спешно обаждане"</string>
<string name="kg_forgot_pattern_button_text" msgid="8852021467868220608">"Забравена фигура"</string>
diff --git a/core/res/res/values-ca/strings.xml b/core/res/res/values-ca/strings.xml
index 65416f1..e0d07bf 100644
--- a/core/res/res/values-ca/strings.xml
+++ b/core/res/res/values-ca/strings.xml
@@ -382,6 +382,8 @@
<string name="permdesc_bindVpnService" msgid="2067845564581693905">"Permet que el titular vinculi a la interfície de nivell superior d\'un servei de VPN. No s\'hauria de necessitar mai per a les aplicacions normals."</string>
<string name="permlab_bindWallpaper" msgid="8716400279937856462">"enllaça amb un fons de pantalla"</string>
<string name="permdesc_bindWallpaper" msgid="7108428692595491668">"Permet que el titular vinculi a la interfície de nivell superior d\'un fons de pantalla. No s\'hauria de necessitar mai per a les aplicacions normals."</string>
+ <string name="permlab_bindRemoteDisplay" msgid="1782923938029941960">"vincula a una pantalla remota"</string>
+ <string name="permdesc_bindRemoteDisplay" msgid="1261242718727295981">"Permet que el titular es vinculi a la interfície de nivell superior d\'una pantalla remota. No s\'hauria de necessitar mai per a les aplicacions normals."</string>
<string name="permlab_bindRemoteViews" msgid="5697987759897367099">"vincula a un servei de widget"</string>
<string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"Permet que el titular vinculi a la interfície de nivell superior d\'un servei de widget. No s\'hauria de necessitar mai per a les aplicacions normals."</string>
<string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"interactuar amb un administrador del dispositiu"</string>
@@ -1489,8 +1491,12 @@
<string name="default_audio_route_category_name" msgid="3722811174003886946">"Sistema"</string>
<string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Àudio per Bluetooth"</string>
<string name="wireless_display_route_description" msgid="9070346425023979651">"Pantalla sense fil"</string>
- <string name="media_route_chooser_grouping_done" msgid="7966438307723317169">"Fet"</string>
<string name="media_route_button_content_description" msgid="5758553567065145276">"Sortida de contingut multimèdia"</string>
+ <string name="media_route_chooser_title" msgid="1751618554539087622">"Connexió al dispositiu"</string>
+ <string name="media_route_chooser_title_for_remote_display" msgid="3395541745872017583">"Emissió de pantalla al dispositiu"</string>
+ <string name="media_route_chooser_searching" msgid="4776236202610828706">"S\'estan cercant dispositius…"</string>
+ <string name="media_route_chooser_extended_settings" msgid="87015534236701604">"Configuració"</string>
+ <string name="media_route_controller_disconnect" msgid="8966120286374158649">"Desconnecta"</string>
<string name="media_route_status_scanning" msgid="7279908761758293783">"S\'està cercant…"</string>
<string name="media_route_status_connecting" msgid="6422571716007825440">"S\'està connectant..."</string>
<string name="media_route_status_available" msgid="6983258067194649391">"Disponible"</string>
@@ -1501,8 +1507,10 @@
<string name="display_manager_overlay_display_name" msgid="5142365982271620716">"Superposa #<xliff:g id="ID">%1$d</xliff:g>"</string>
<string name="display_manager_overlay_display_title" msgid="652124517672257172">"<xliff:g id="NAME">%1$s</xliff:g>: <xliff:g id="WIDTH">%2$d</xliff:g> x <xliff:g id="HEIGHT">%3$d</xliff:g>, <xliff:g id="DPI">%4$d</xliff:g> dpi"</string>
<string name="display_manager_overlay_display_secure_suffix" msgid="6022119702628572080">", segur"</string>
- <string name="wifi_display_notification_title" msgid="2223050649240326557">"La pantalla sense fil està connectada"</string>
- <string name="wifi_display_notification_message" msgid="4498802012464170685">"Aquesta pantalla es mostra en un altre dispositiu"</string>
+ <string name="wifi_display_notification_connecting_title" msgid="2838646471050359706">"Emissió de pantalla"</string>
+ <string name="wifi_display_notification_connecting_message" msgid="5837350993752841389">"S\'està connectant a <xliff:g id="NAME">%1$s</xliff:g>"</string>
+ <string name="wifi_display_notification_connected_title" msgid="8567308065912676285">"Emissió de pantalla"</string>
+ <string name="wifi_display_notification_connected_message" msgid="2587209325701109715">"Connectat a <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="wifi_display_notification_disconnect" msgid="6183754463561153372">"Desconnecta"</string>
<string name="kg_emergency_call_label" msgid="684946192523830531">"Trucada d\'emergència"</string>
<string name="kg_forgot_pattern_button_text" msgid="8852021467868220608">"Patró oblidat"</string>
diff --git a/core/res/res/values-cs/strings.xml b/core/res/res/values-cs/strings.xml
index f4cb4d0..14d6dd5 100644
--- a/core/res/res/values-cs/strings.xml
+++ b/core/res/res/values-cs/strings.xml
@@ -382,6 +382,8 @@
<string name="permdesc_bindVpnService" msgid="2067845564581693905">"Umožňuje držiteli navázat se na nejvyšší úroveň služby VPN. Běžné aplikace by toto oprávnění neměly nikdy požadovat."</string>
<string name="permlab_bindWallpaper" msgid="8716400279937856462">"vazba na tapetu"</string>
<string name="permdesc_bindWallpaper" msgid="7108428692595491668">"Umožňuje držiteli navázat se na nejvyšší úroveň rozhraní tapety. Běžné aplikace by toto oprávnění neměly nikdy požadovat."</string>
+ <string name="permlab_bindRemoteDisplay" msgid="1782923938029941960">"připojit se ke vzdálenému displeji"</string>
+ <string name="permdesc_bindRemoteDisplay" msgid="1261242718727295981">"Umožňuje držiteli připojit se k vysokoúrovňovému rozhraní vzdáleného displeje. Běžné aplikace by toto oprávnění neměly nikdy potřebovat."</string>
<string name="permlab_bindRemoteViews" msgid="5697987759897367099">"navázat se na službu widgetu"</string>
<string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"Umožňuje držiteli navázat se na nejvyšší úroveň služby widgetu. Běžné aplikace by toto oprávnění neměly nikdy požadovat."</string>
<string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"komunikovat se správcem zařízení"</string>
@@ -1489,8 +1491,12 @@
<string name="default_audio_route_category_name" msgid="3722811174003886946">"Systém"</string>
<string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Bluetooth Audio"</string>
<string name="wireless_display_route_description" msgid="9070346425023979651">"Bezdrátový displej"</string>
- <string name="media_route_chooser_grouping_done" msgid="7966438307723317169">"Hotovo"</string>
<string name="media_route_button_content_description" msgid="5758553567065145276">"Výstup médií"</string>
+ <string name="media_route_chooser_title" msgid="1751618554539087622">"Připojení k zařízení"</string>
+ <string name="media_route_chooser_title_for_remote_display" msgid="3395541745872017583">"Odesílání obsahu obrazovky do zařízení"</string>
+ <string name="media_route_chooser_searching" msgid="4776236202610828706">"Vyhledávání zařízení…"</string>
+ <string name="media_route_chooser_extended_settings" msgid="87015534236701604">"Nastavení"</string>
+ <string name="media_route_controller_disconnect" msgid="8966120286374158649">"Odpojit"</string>
<string name="media_route_status_scanning" msgid="7279908761758293783">"Vyhledávání…"</string>
<string name="media_route_status_connecting" msgid="6422571716007825440">"Připojování…"</string>
<string name="media_route_status_available" msgid="6983258067194649391">"Dostupná"</string>
@@ -1501,8 +1507,10 @@
<string name="display_manager_overlay_display_name" msgid="5142365982271620716">"Překryvná vrstva č. <xliff:g id="ID">%1$d</xliff:g>"</string>
<string name="display_manager_overlay_display_title" msgid="652124517672257172">"<xliff:g id="NAME">%1$s</xliff:g>: <xliff:g id="WIDTH">%2$d</xliff:g>x<xliff:g id="HEIGHT">%3$d</xliff:g>, <xliff:g id="DPI">%4$d</xliff:g> dpi"</string>
<string name="display_manager_overlay_display_secure_suffix" msgid="6022119702628572080">", zabezpečené"</string>
- <string name="wifi_display_notification_title" msgid="2223050649240326557">"Bezdrátový displej je připojen"</string>
- <string name="wifi_display_notification_message" msgid="4498802012464170685">"Tato obrazovka se zobrazuje v jiném zařízení"</string>
+ <string name="wifi_display_notification_connecting_title" msgid="2838646471050359706">"Odesílání obsahu obrazovky"</string>
+ <string name="wifi_display_notification_connecting_message" msgid="5837350993752841389">"Připojování k obrazovce <xliff:g id="NAME">%1$s</xliff:g>"</string>
+ <string name="wifi_display_notification_connected_title" msgid="8567308065912676285">"Odesílání obsahu obrazovky"</string>
+ <string name="wifi_display_notification_connected_message" msgid="2587209325701109715">"Připojeno k obrazovce <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="wifi_display_notification_disconnect" msgid="6183754463561153372">"Odpojit"</string>
<string name="kg_emergency_call_label" msgid="684946192523830531">"Tísňové volání"</string>
<string name="kg_forgot_pattern_button_text" msgid="8852021467868220608">"Zapomenuté gesto"</string>
diff --git a/core/res/res/values-da/strings.xml b/core/res/res/values-da/strings.xml
index 997837a..0219a0f 100644
--- a/core/res/res/values-da/strings.xml
+++ b/core/res/res/values-da/strings.xml
@@ -382,6 +382,8 @@
<string name="permdesc_bindVpnService" msgid="2067845564581693905">"Tillader, at brugeren forpligter sig til en VPN-tjenestes grænseflade på øverste niveau. Bør aldrig være nødvendigt i almindelige apps."</string>
<string name="permlab_bindWallpaper" msgid="8716400279937856462">"forpligt til et tapet"</string>
<string name="permdesc_bindWallpaper" msgid="7108428692595491668">"Tillader, at indehaveren kan binde en baggrunds grænseflade på øverste niveau. Dette bør aldrig være nødvendigt for almindelige apps."</string>
+ <string name="permlab_bindRemoteDisplay" msgid="1782923938029941960">"bind til en ekstern skærm"</string>
+ <string name="permdesc_bindRemoteDisplay" msgid="1261242718727295981">"Tillader, at brugeren kan foretage en binding til grænsefladens øverste niveau på en ekstern skærm. Bør aldrig være nødvendigt til almindelige apps."</string>
<string name="permlab_bindRemoteViews" msgid="5697987759897367099">"forpligt til en widgettjeneste"</string>
<string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"Tillader, at brugeren kan forpligte sig til en grænseflade for en widgettjeneste på øverste niveau. Bør aldrig være nødvendigt til almindelige apps."</string>
<string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"kommunikere med en enhedsadministrator"</string>
@@ -1119,7 +1121,7 @@
<string name="loading" msgid="7933681260296021180">"Indlæser…"</string>
<string name="capital_on" msgid="1544682755514494298">"TIL"</string>
<string name="capital_off" msgid="6815870386972805832">"FRA"</string>
- <string name="whichApplication" msgid="4533185947064773386">"Fuldfør handling ved hjælp af"</string>
+ <string name="whichApplication" msgid="4533185947064773386">"Brug"</string>
<string name="whichHomeApplication" msgid="4616420172727326782">"Vælg en startsideapp"</string>
<string name="alwaysUse" msgid="4583018368000610438">"Brug som standard til denne handling."</string>
<string name="clearDefaultHintMsg" msgid="3252584689512077257">"Ryd standard i Systemindstillinger > Apps > Downloadet."</string>
@@ -1489,8 +1491,12 @@
<string name="default_audio_route_category_name" msgid="3722811174003886946">"System"</string>
<string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Bluetooth-lyd"</string>
<string name="wireless_display_route_description" msgid="9070346425023979651">"Trådløs skærm"</string>
- <string name="media_route_chooser_grouping_done" msgid="7966438307723317169">"Udfør"</string>
<string name="media_route_button_content_description" msgid="5758553567065145276">"Medieudgang"</string>
+ <string name="media_route_chooser_title" msgid="1751618554539087622">"Opret forbindelse til enheden"</string>
+ <string name="media_route_chooser_title_for_remote_display" msgid="3395541745872017583">"Send skærm til enhed"</string>
+ <string name="media_route_chooser_searching" msgid="4776236202610828706">"Søger efter enheder…"</string>
+ <string name="media_route_chooser_extended_settings" msgid="87015534236701604">"Indstillinger"</string>
+ <string name="media_route_controller_disconnect" msgid="8966120286374158649">"Afbryd forbindelsen"</string>
<string name="media_route_status_scanning" msgid="7279908761758293783">"Søger..."</string>
<string name="media_route_status_connecting" msgid="6422571716007825440">"Opretter forbindelse..."</string>
<string name="media_route_status_available" msgid="6983258067194649391">"Tilgængelig"</string>
@@ -1501,8 +1507,10 @@
<string name="display_manager_overlay_display_name" msgid="5142365982271620716">"Overlejring nr. <xliff:g id="ID">%1$d</xliff:g>"</string>
<string name="display_manager_overlay_display_title" msgid="652124517672257172">"<xliff:g id="NAME">%1$s</xliff:g>: <xliff:g id="WIDTH">%2$d</xliff:g> x <xliff:g id="HEIGHT">%3$d</xliff:g>, <xliff:g id="DPI">%4$d</xliff:g> dpi"</string>
<string name="display_manager_overlay_display_secure_suffix" msgid="6022119702628572080">", sikker"</string>
- <string name="wifi_display_notification_title" msgid="2223050649240326557">"Der er tilsluttet en trådløs skærm"</string>
- <string name="wifi_display_notification_message" msgid="4498802012464170685">"Denne skærm vises på en anden enhed"</string>
+ <string name="wifi_display_notification_connecting_title" msgid="2838646471050359706">"Skærm sendes"</string>
+ <string name="wifi_display_notification_connecting_message" msgid="5837350993752841389">"Der oprettes forbindelse til <xliff:g id="NAME">%1$s</xliff:g>"</string>
+ <string name="wifi_display_notification_connected_title" msgid="8567308065912676285">"Skærm sendes"</string>
+ <string name="wifi_display_notification_connected_message" msgid="2587209325701109715">"Forbundet til <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="wifi_display_notification_disconnect" msgid="6183754463561153372">"Afbryd forbindelsen"</string>
<string name="kg_emergency_call_label" msgid="684946192523830531">"Nødopkald"</string>
<string name="kg_forgot_pattern_button_text" msgid="8852021467868220608">"Glemt mønster"</string>
diff --git a/core/res/res/values-de/strings.xml b/core/res/res/values-de/strings.xml
index 4f40d72..34f28fc 100644
--- a/core/res/res/values-de/strings.xml
+++ b/core/res/res/values-de/strings.xml
@@ -382,6 +382,8 @@
<string name="permdesc_bindVpnService" msgid="2067845564581693905">"Ermöglicht dem Halter, sich an die Oberfläche eines VPN-Dienstes auf oberster Ebene zu binden. Sollte nie für normale Apps benötigt werden."</string>
<string name="permlab_bindWallpaper" msgid="8716400279937856462">"An einen Hintergrund binden"</string>
<string name="permdesc_bindWallpaper" msgid="7108428692595491668">"Ermöglicht dem Halter, sich an die Oberfläche eines Hintergrunds auf oberster Ebene zu binden. Sollte nie für normale Apps benötigt werden."</string>
+ <string name="permlab_bindRemoteDisplay" msgid="1782923938029941960">"An Remote-Display binden"</string>
+ <string name="permdesc_bindRemoteDisplay" msgid="1261242718727295981">"Ermöglicht dem Halter, sich an die Oberfläche eines Remote-Displays auf oberster Ebene zu binden. Sollte für normale Apps nie benötigt werden."</string>
<string name="permlab_bindRemoteViews" msgid="5697987759897367099">"An einen Widget-Dienst binden"</string>
<string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"Ermöglicht dem Halter, sich an die Oberfläche eines Widget-Dienstes auf oberster Ebene zu binden. Sollte nie für normale Apps benötigt werden."</string>
<string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"Interaktion mit einem Geräteadministrator"</string>
@@ -1489,8 +1491,12 @@
<string name="default_audio_route_category_name" msgid="3722811174003886946">"System"</string>
<string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Bluetooth-Audio"</string>
<string name="wireless_display_route_description" msgid="9070346425023979651">"Kabellose Übertragung (WiDi)"</string>
- <string name="media_route_chooser_grouping_done" msgid="7966438307723317169">"Fertig"</string>
<string name="media_route_button_content_description" msgid="5758553567065145276">"Medienausgabe"</string>
+ <string name="media_route_chooser_title" msgid="1751618554539087622">"Mit Gerät verbinden"</string>
+ <string name="media_route_chooser_title_for_remote_display" msgid="3395541745872017583">"Bildschirm auf Gerät übertragen"</string>
+ <string name="media_route_chooser_searching" msgid="4776236202610828706">"Geräte werden gesucht…"</string>
+ <string name="media_route_chooser_extended_settings" msgid="87015534236701604">"Einstellungen"</string>
+ <string name="media_route_controller_disconnect" msgid="8966120286374158649">"Verbindung trennen"</string>
<string name="media_route_status_scanning" msgid="7279908761758293783">"Wird gescannt..."</string>
<string name="media_route_status_connecting" msgid="6422571716007825440">"Verbindung wird hergestellt..."</string>
<string name="media_route_status_available" msgid="6983258067194649391">"Verfügbar"</string>
@@ -1501,8 +1507,10 @@
<string name="display_manager_overlay_display_name" msgid="5142365982271620716">"Overlay-Nr. <xliff:g id="ID">%1$d</xliff:g>"</string>
<string name="display_manager_overlay_display_title" msgid="652124517672257172">"<xliff:g id="NAME">%1$s</xliff:g>: <xliff:g id="WIDTH">%2$d</xliff:g> x <xliff:g id="HEIGHT">%3$d</xliff:g>, <xliff:g id="DPI">%4$d</xliff:g> dpi"</string>
<string name="display_manager_overlay_display_secure_suffix" msgid="6022119702628572080">", sicher"</string>
- <string name="wifi_display_notification_title" msgid="2223050649240326557">"Kabellose Übertragung (WiDi) ist aktiviert."</string>
- <string name="wifi_display_notification_message" msgid="4498802012464170685">"Dieser Bildschirm wird auf einem anderen Gerät angezeigt."</string>
+ <string name="wifi_display_notification_connecting_title" msgid="2838646471050359706">"Bildschirm wird übertragen"</string>
+ <string name="wifi_display_notification_connecting_message" msgid="5837350993752841389">"Verbindung mit <xliff:g id="NAME">%1$s</xliff:g> wird hergestellt."</string>
+ <string name="wifi_display_notification_connected_title" msgid="8567308065912676285">"Bildschirm wird übertragen"</string>
+ <string name="wifi_display_notification_connected_message" msgid="2587209325701109715">"Verbunden mit <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="wifi_display_notification_disconnect" msgid="6183754463561153372">"Verbindung trennen"</string>
<string name="kg_emergency_call_label" msgid="684946192523830531">"Notruf"</string>
<string name="kg_forgot_pattern_button_text" msgid="8852021467868220608">"Muster vergessen"</string>
diff --git a/core/res/res/values-el/strings.xml b/core/res/res/values-el/strings.xml
index 6a34a6a..ee98ceb 100644
--- a/core/res/res/values-el/strings.xml
+++ b/core/res/res/values-el/strings.xml
@@ -382,6 +382,8 @@
<string name="permdesc_bindVpnService" msgid="2067845564581693905">"Επιτρέπει στον κάτοχο τη δέσμευση στη διεπαφή ανωτάτου επιπέδου μιας υπηρεσίας Vpn. Δεν απαιτείται για κανονικές εφαρμογές."</string>
<string name="permlab_bindWallpaper" msgid="8716400279937856462">"δέσμευση σε ταπετσαρία"</string>
<string name="permdesc_bindWallpaper" msgid="7108428692595491668">"Επιτρέπει στον κάτοχο τη δέσμευση στη διεπαφή ανωτάτου επιπέδου μιας ταπετσαρίας. Δεν απαιτείται για συνήθεις εφαρμογές."</string>
+ <string name="permlab_bindRemoteDisplay" msgid="1782923938029941960">"μεταφορά σε μια απομακρυσμένη οθόνη"</string>
+ <string name="permdesc_bindRemoteDisplay" msgid="1261242718727295981">"Επιτρέπει στον κάτοχο τη δέσμευση στη διεπαφή ανωτάτου επιπέδου μιας απομακρυσμένης οθόνης. Δεν απαιτείται ποτέ για κανονικές εφαρμογές."</string>
<string name="permlab_bindRemoteViews" msgid="5697987759897367099">"δέσμευση σε υπηρεσία γραφικών στοιχείων"</string>
<string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"Επιτρέπει στον κάτοχο τη δέσμευση στη διεπαφή ανωτάτου επιπέδου μιας υπηρεσίας γραφικών στοιχείων. Δεν απαιτείται για κανονικές εφαρμογές."</string>
<string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"επικοινωνία με έναν διαχειριστή συσκευής"</string>
@@ -1489,8 +1491,12 @@
<string name="default_audio_route_category_name" msgid="3722811174003886946">"Σύστημα"</string>
<string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Ήχος Bluetooth"</string>
<string name="wireless_display_route_description" msgid="9070346425023979651">"Ασύρματη οθόνη"</string>
- <string name="media_route_chooser_grouping_done" msgid="7966438307723317169">"Τέλος"</string>
<string name="media_route_button_content_description" msgid="5758553567065145276">"Έξοδος μέσων"</string>
+ <string name="media_route_chooser_title" msgid="1751618554539087622">"Σύνδεση με τη συσκευή"</string>
+ <string name="media_route_chooser_title_for_remote_display" msgid="3395541745872017583">"Μετάδοση οθόνης σε συσκευή"</string>
+ <string name="media_route_chooser_searching" msgid="4776236202610828706">"Αναζήτηση συσκευών…"</string>
+ <string name="media_route_chooser_extended_settings" msgid="87015534236701604">"Ρυθμίσεις"</string>
+ <string name="media_route_controller_disconnect" msgid="8966120286374158649">"Αποσύνδεση"</string>
<string name="media_route_status_scanning" msgid="7279908761758293783">"Σάρωση…"</string>
<string name="media_route_status_connecting" msgid="6422571716007825440">"Σύνδεση…"</string>
<string name="media_route_status_available" msgid="6983258067194649391">"Διαθέσιμη"</string>
@@ -1501,8 +1507,10 @@
<string name="display_manager_overlay_display_name" msgid="5142365982271620716">"Επικάλυψη #<xliff:g id="ID">%1$d</xliff:g>"</string>
<string name="display_manager_overlay_display_title" msgid="652124517672257172">"<xliff:g id="NAME">%1$s</xliff:g>: <xliff:g id="WIDTH">%2$d</xliff:g>x<xliff:g id="HEIGHT">%3$d</xliff:g>, <xliff:g id="DPI">%4$d</xliff:g> dpi"</string>
<string name="display_manager_overlay_display_secure_suffix" msgid="6022119702628572080">", ασφαλές"</string>
- <string name="wifi_display_notification_title" msgid="2223050649240326557">"Έχει συνδεθεί ασύρματη οθόνη"</string>
- <string name="wifi_display_notification_message" msgid="4498802012464170685">"Αυτή η οθόνη εμφανίζεται σε μια άλλη συσκευή"</string>
+ <string name="wifi_display_notification_connecting_title" msgid="2838646471050359706">"Μετάδοση οθόνης"</string>
+ <string name="wifi_display_notification_connecting_message" msgid="5837350993752841389">"Γίενται σύνδεση με το <xliff:g id="NAME">%1$s</xliff:g>"</string>
+ <string name="wifi_display_notification_connected_title" msgid="8567308065912676285">"Μετάδοση οθόνης"</string>
+ <string name="wifi_display_notification_connected_message" msgid="2587209325701109715">"Συνδέθηκε με το <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="wifi_display_notification_disconnect" msgid="6183754463561153372">"Αποσύνδεση"</string>
<string name="kg_emergency_call_label" msgid="684946192523830531">"Κλήσεις επείγουσας ανάγκης"</string>
<string name="kg_forgot_pattern_button_text" msgid="8852021467868220608">"Ξεχάσατε το μοτίβο"</string>
diff --git a/core/res/res/values-en-rGB/strings.xml b/core/res/res/values-en-rGB/strings.xml
index b706ee8..d2c53cc 100644
--- a/core/res/res/values-en-rGB/strings.xml
+++ b/core/res/res/values-en-rGB/strings.xml
@@ -382,6 +382,8 @@
<string name="permdesc_bindVpnService" msgid="2067845564581693905">"Allows the holder to bind to the top-level interface of a Vpn service. Should never be needed for normal apps."</string>
<string name="permlab_bindWallpaper" msgid="8716400279937856462">"bind to wallpaper"</string>
<string name="permdesc_bindWallpaper" msgid="7108428692595491668">"Allows the holder to bind to the top-level interface of wallpaper. Should never be needed for normal applications."</string>
+ <string name="permlab_bindRemoteDisplay" msgid="1782923938029941960">"bind to a remote display"</string>
+ <string name="permdesc_bindRemoteDisplay" msgid="1261242718727295981">"Allows the holder to bind to the top-level interface of a remote display. Should never be needed for normal apps."</string>
<string name="permlab_bindRemoteViews" msgid="5697987759897367099">"bind to a widget service"</string>
<string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"Allows the holder to bind to the top-level interface of a widget service. Should never be needed for normal apps."</string>
<string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"interact with device admin"</string>
@@ -1489,8 +1491,12 @@
<string name="default_audio_route_category_name" msgid="3722811174003886946">"System"</string>
<string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Bluetooth audio"</string>
<string name="wireless_display_route_description" msgid="9070346425023979651">"Wireless display"</string>
- <string name="media_route_chooser_grouping_done" msgid="7966438307723317169">"Done"</string>
<string name="media_route_button_content_description" msgid="5758553567065145276">"Media output"</string>
+ <string name="media_route_chooser_title" msgid="1751618554539087622">"Connect to device"</string>
+ <string name="media_route_chooser_title_for_remote_display" msgid="3395541745872017583">"Cast screen to device"</string>
+ <string name="media_route_chooser_searching" msgid="4776236202610828706">"Searching for devices…"</string>
+ <string name="media_route_chooser_extended_settings" msgid="87015534236701604">"Settings"</string>
+ <string name="media_route_controller_disconnect" msgid="8966120286374158649">"Disconnect"</string>
<string name="media_route_status_scanning" msgid="7279908761758293783">"Scanning..."</string>
<string name="media_route_status_connecting" msgid="6422571716007825440">"Connecting..."</string>
<string name="media_route_status_available" msgid="6983258067194649391">"Available"</string>
@@ -1501,8 +1507,10 @@
<string name="display_manager_overlay_display_name" msgid="5142365982271620716">"Overlay #<xliff:g id="ID">%1$d</xliff:g>"</string>
<string name="display_manager_overlay_display_title" msgid="652124517672257172">"<xliff:g id="NAME">%1$s</xliff:g>: <xliff:g id="WIDTH">%2$d</xliff:g>x<xliff:g id="HEIGHT">%3$d</xliff:g>, <xliff:g id="DPI">%4$d</xliff:g> dpi"</string>
<string name="display_manager_overlay_display_secure_suffix" msgid="6022119702628572080">", secure"</string>
- <string name="wifi_display_notification_title" msgid="2223050649240326557">"Wireless display is connected"</string>
- <string name="wifi_display_notification_message" msgid="4498802012464170685">"This screen is showing on another device"</string>
+ <string name="wifi_display_notification_connecting_title" msgid="2838646471050359706">"Casting screen"</string>
+ <string name="wifi_display_notification_connecting_message" msgid="5837350993752841389">"Connecting to <xliff:g id="NAME">%1$s</xliff:g>"</string>
+ <string name="wifi_display_notification_connected_title" msgid="8567308065912676285">"Casting screen"</string>
+ <string name="wifi_display_notification_connected_message" msgid="2587209325701109715">"Connected to <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="wifi_display_notification_disconnect" msgid="6183754463561153372">"Disconnect"</string>
<string name="kg_emergency_call_label" msgid="684946192523830531">"Emergency call"</string>
<string name="kg_forgot_pattern_button_text" msgid="8852021467868220608">"Forgot Pattern"</string>
diff --git a/core/res/res/values-en-rIN/strings.xml b/core/res/res/values-en-rIN/strings.xml
index b706ee8..d2c53cc 100644
--- a/core/res/res/values-en-rIN/strings.xml
+++ b/core/res/res/values-en-rIN/strings.xml
@@ -382,6 +382,8 @@
<string name="permdesc_bindVpnService" msgid="2067845564581693905">"Allows the holder to bind to the top-level interface of a Vpn service. Should never be needed for normal apps."</string>
<string name="permlab_bindWallpaper" msgid="8716400279937856462">"bind to wallpaper"</string>
<string name="permdesc_bindWallpaper" msgid="7108428692595491668">"Allows the holder to bind to the top-level interface of wallpaper. Should never be needed for normal applications."</string>
+ <string name="permlab_bindRemoteDisplay" msgid="1782923938029941960">"bind to a remote display"</string>
+ <string name="permdesc_bindRemoteDisplay" msgid="1261242718727295981">"Allows the holder to bind to the top-level interface of a remote display. Should never be needed for normal apps."</string>
<string name="permlab_bindRemoteViews" msgid="5697987759897367099">"bind to a widget service"</string>
<string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"Allows the holder to bind to the top-level interface of a widget service. Should never be needed for normal apps."</string>
<string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"interact with device admin"</string>
@@ -1489,8 +1491,12 @@
<string name="default_audio_route_category_name" msgid="3722811174003886946">"System"</string>
<string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Bluetooth audio"</string>
<string name="wireless_display_route_description" msgid="9070346425023979651">"Wireless display"</string>
- <string name="media_route_chooser_grouping_done" msgid="7966438307723317169">"Done"</string>
<string name="media_route_button_content_description" msgid="5758553567065145276">"Media output"</string>
+ <string name="media_route_chooser_title" msgid="1751618554539087622">"Connect to device"</string>
+ <string name="media_route_chooser_title_for_remote_display" msgid="3395541745872017583">"Cast screen to device"</string>
+ <string name="media_route_chooser_searching" msgid="4776236202610828706">"Searching for devices…"</string>
+ <string name="media_route_chooser_extended_settings" msgid="87015534236701604">"Settings"</string>
+ <string name="media_route_controller_disconnect" msgid="8966120286374158649">"Disconnect"</string>
<string name="media_route_status_scanning" msgid="7279908761758293783">"Scanning..."</string>
<string name="media_route_status_connecting" msgid="6422571716007825440">"Connecting..."</string>
<string name="media_route_status_available" msgid="6983258067194649391">"Available"</string>
@@ -1501,8 +1507,10 @@
<string name="display_manager_overlay_display_name" msgid="5142365982271620716">"Overlay #<xliff:g id="ID">%1$d</xliff:g>"</string>
<string name="display_manager_overlay_display_title" msgid="652124517672257172">"<xliff:g id="NAME">%1$s</xliff:g>: <xliff:g id="WIDTH">%2$d</xliff:g>x<xliff:g id="HEIGHT">%3$d</xliff:g>, <xliff:g id="DPI">%4$d</xliff:g> dpi"</string>
<string name="display_manager_overlay_display_secure_suffix" msgid="6022119702628572080">", secure"</string>
- <string name="wifi_display_notification_title" msgid="2223050649240326557">"Wireless display is connected"</string>
- <string name="wifi_display_notification_message" msgid="4498802012464170685">"This screen is showing on another device"</string>
+ <string name="wifi_display_notification_connecting_title" msgid="2838646471050359706">"Casting screen"</string>
+ <string name="wifi_display_notification_connecting_message" msgid="5837350993752841389">"Connecting to <xliff:g id="NAME">%1$s</xliff:g>"</string>
+ <string name="wifi_display_notification_connected_title" msgid="8567308065912676285">"Casting screen"</string>
+ <string name="wifi_display_notification_connected_message" msgid="2587209325701109715">"Connected to <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="wifi_display_notification_disconnect" msgid="6183754463561153372">"Disconnect"</string>
<string name="kg_emergency_call_label" msgid="684946192523830531">"Emergency call"</string>
<string name="kg_forgot_pattern_button_text" msgid="8852021467868220608">"Forgot Pattern"</string>
diff --git a/core/res/res/values-es-rUS/strings.xml b/core/res/res/values-es-rUS/strings.xml
index 165b6a6..114f6f5 100644
--- a/core/res/res/values-es-rUS/strings.xml
+++ b/core/res/res/values-es-rUS/strings.xml
@@ -382,6 +382,8 @@
<string name="permdesc_bindVpnService" msgid="2067845564581693905">"Permite al titular vincularse a la interfaz de nivel superior de un servicio de VPN. Las aplicaciones normales no deberían necesitar este permiso."</string>
<string name="permlab_bindWallpaper" msgid="8716400279937856462">"vincular a un fondo de pantalla"</string>
<string name="permdesc_bindWallpaper" msgid="7108428692595491668">"Permite al propietario vincularse a la interfaz de nivel superior de un fondo de pantalla. Las aplicaciones normales no deben utilizar este permiso."</string>
+ <string name="permlab_bindRemoteDisplay" msgid="1782923938029941960">"vincular a una pantalla remota"</string>
+ <string name="permdesc_bindRemoteDisplay" msgid="1261242718727295981">"Permite al propietario vincularse a la interfaz de nivel superior de una pantalla remota. Las aplicaciones normales no deberían necesitar este permiso."</string>
<string name="permlab_bindRemoteViews" msgid="5697987759897367099">"vincular a un servicio de widget"</string>
<string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"Permite al propietario vincularse a la interfaz de nivel superior del servicio de widget. Las aplicaciones normales no deberían necesitar este permiso."</string>
<string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"interactuar con un administrador de dispositivos"</string>
@@ -1489,8 +1491,12 @@
<string name="default_audio_route_category_name" msgid="3722811174003886946">"Sistema"</string>
<string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Audio Bluetooth"</string>
<string name="wireless_display_route_description" msgid="9070346425023979651">"Pantalla inalámbrica"</string>
- <string name="media_route_chooser_grouping_done" msgid="7966438307723317169">"Listo"</string>
<string name="media_route_button_content_description" msgid="5758553567065145276">"Salida multimedia"</string>
+ <string name="media_route_chooser_title" msgid="1751618554539087622">"Conectar al dispositivo"</string>
+ <string name="media_route_chooser_title_for_remote_display" msgid="3395541745872017583">"Transmitir pantalla a dispositivo"</string>
+ <string name="media_route_chooser_searching" msgid="4776236202610828706">"Buscando dispositivos…"</string>
+ <string name="media_route_chooser_extended_settings" msgid="87015534236701604">"Configuración"</string>
+ <string name="media_route_controller_disconnect" msgid="8966120286374158649">"Desconectar"</string>
<string name="media_route_status_scanning" msgid="7279908761758293783">"Examinando..."</string>
<string name="media_route_status_connecting" msgid="6422571716007825440">"Conectando..."</string>
<string name="media_route_status_available" msgid="6983258067194649391">"Disponible"</string>
@@ -1501,8 +1507,10 @@
<string name="display_manager_overlay_display_name" msgid="5142365982271620716">"Superposición #<xliff:g id="ID">%1$d</xliff:g>"</string>
<string name="display_manager_overlay_display_title" msgid="652124517672257172">"<xliff:g id="NAME">%1$s</xliff:g>: <xliff:g id="WIDTH">%2$d</xliff:g> x <xliff:g id="HEIGHT">%3$d</xliff:g>, <xliff:g id="DPI">%4$d</xliff:g> ppp"</string>
<string name="display_manager_overlay_display_secure_suffix" msgid="6022119702628572080">", segura"</string>
- <string name="wifi_display_notification_title" msgid="2223050649240326557">"Se conectó la pantalla inalámbrica"</string>
- <string name="wifi_display_notification_message" msgid="4498802012464170685">"Esta pantalla se muestra en otro dispositivo."</string>
+ <string name="wifi_display_notification_connecting_title" msgid="2838646471050359706">"Transmitiendo pantalla"</string>
+ <string name="wifi_display_notification_connecting_message" msgid="5837350993752841389">"Estableciendo conexión con <xliff:g id="NAME">%1$s</xliff:g>"</string>
+ <string name="wifi_display_notification_connected_title" msgid="8567308065912676285">"Transmitiendo pantalla"</string>
+ <string name="wifi_display_notification_connected_message" msgid="2587209325701109715">"Se estableció conexión con <xliff:g id="NAME">%1$s</xliff:g>."</string>
<string name="wifi_display_notification_disconnect" msgid="6183754463561153372">"Desconectar"</string>
<string name="kg_emergency_call_label" msgid="684946192523830531">"Realizar llamada de emergencia"</string>
<string name="kg_forgot_pattern_button_text" msgid="8852021467868220608">"¿Olvidaste el patrón?"</string>
diff --git a/core/res/res/values-es/strings.xml b/core/res/res/values-es/strings.xml
index c38a075..f758989 100644
--- a/core/res/res/values-es/strings.xml
+++ b/core/res/res/values-es/strings.xml
@@ -382,6 +382,8 @@
<string name="permdesc_bindVpnService" msgid="2067845564581693905">"Permite enlazar con la interfaz de nivel superior de un servicio de VPN. Las aplicaciones normales no deberían necesitar este permiso."</string>
<string name="permlab_bindWallpaper" msgid="8716400279937856462">"enlazar con un fondo de pantalla"</string>
<string name="permdesc_bindWallpaper" msgid="7108428692595491668">"Permite enlazar con la interfaz de nivel superior de un fondo de pantalla. Las aplicaciones normales no deberían necesitar este permiso."</string>
+ <string name="permlab_bindRemoteDisplay" msgid="1782923938029941960">"enlazar a una pantalla remota"</string>
+ <string name="permdesc_bindRemoteDisplay" msgid="1261242718727295981">"Permite enlazar con la interfaz de nivel superior de una pantalla remota. Las aplicaciones normales no deberían necesitar este permiso."</string>
<string name="permlab_bindRemoteViews" msgid="5697987759897367099">"enlazar con un servicio de widget"</string>
<string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"Permite enlazar con la interfaz de nivel superior de un servicio de widget. Las aplicaciones normales no deberían necesitar este permiso."</string>
<string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"interactuar con el administrador de un dispositivo"</string>
@@ -788,7 +790,7 @@
<string name="imProtocolYahoo" msgid="8271439408469021273">"Yahoo!"</string>
<string name="imProtocolSkype" msgid="9019296744622832951">"Skype"</string>
<string name="imProtocolQq" msgid="8887484379494111884">"QQ"</string>
- <string name="imProtocolGoogleTalk" msgid="493902321140277304">"Conversaciones"</string>
+ <string name="imProtocolGoogleTalk" msgid="493902321140277304">"Hangouts"</string>
<string name="imProtocolIcq" msgid="1574870433606517315">"ICQ"</string>
<string name="imProtocolJabber" msgid="2279917630875771722">"Jabber"</string>
<string name="imProtocolNetMeeting" msgid="8287625655986827971">"NetMeeting"</string>
@@ -1489,8 +1491,12 @@
<string name="default_audio_route_category_name" msgid="3722811174003886946">"Sistema"</string>
<string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Audio Bluetooth"</string>
<string name="wireless_display_route_description" msgid="9070346425023979651">"Pantalla inalámbrica"</string>
- <string name="media_route_chooser_grouping_done" msgid="7966438307723317169">"Fin"</string>
<string name="media_route_button_content_description" msgid="5758553567065145276">"Salida multimedia"</string>
+ <string name="media_route_chooser_title" msgid="1751618554539087622">"Conectar a dispositivo"</string>
+ <string name="media_route_chooser_title_for_remote_display" msgid="3395541745872017583">"Enviar pantalla a dispositivo"</string>
+ <string name="media_route_chooser_searching" msgid="4776236202610828706">"Buscando dispositivos…"</string>
+ <string name="media_route_chooser_extended_settings" msgid="87015534236701604">"Ajustes"</string>
+ <string name="media_route_controller_disconnect" msgid="8966120286374158649">"Desconectar"</string>
<string name="media_route_status_scanning" msgid="7279908761758293783">"Analizando..."</string>
<string name="media_route_status_connecting" msgid="6422571716007825440">"Conectando..."</string>
<string name="media_route_status_available" msgid="6983258067194649391">"Disponible"</string>
@@ -1501,8 +1507,10 @@
<string name="display_manager_overlay_display_name" msgid="5142365982271620716">"Superposición #<xliff:g id="ID">%1$d</xliff:g>"</string>
<string name="display_manager_overlay_display_title" msgid="652124517672257172">"<xliff:g id="NAME">%1$s</xliff:g>: <xliff:g id="WIDTH">%2$d</xliff:g> x <xliff:g id="HEIGHT">%3$d</xliff:g>, <xliff:g id="DPI">%4$d</xliff:g> dpi"</string>
<string name="display_manager_overlay_display_secure_suffix" msgid="6022119702628572080">", seguro"</string>
- <string name="wifi_display_notification_title" msgid="2223050649240326557">"Pantalla inalámbrica conectada"</string>
- <string name="wifi_display_notification_message" msgid="4498802012464170685">"Esta pantalla se muestra en otro dispositivo."</string>
+ <string name="wifi_display_notification_connecting_title" msgid="2838646471050359706">"Enviando pantalla"</string>
+ <string name="wifi_display_notification_connecting_message" msgid="5837350993752841389">"Conectando a <xliff:g id="NAME">%1$s</xliff:g>"</string>
+ <string name="wifi_display_notification_connected_title" msgid="8567308065912676285">"Enviando pantalla"</string>
+ <string name="wifi_display_notification_connected_message" msgid="2587209325701109715">"Conectado a <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="wifi_display_notification_disconnect" msgid="6183754463561153372">"Desconectar"</string>
<string name="kg_emergency_call_label" msgid="684946192523830531">"Llamada de emergencia"</string>
<string name="kg_forgot_pattern_button_text" msgid="8852021467868220608">"¿Has olvidado el patrón?"</string>
diff --git a/core/res/res/values-et-rEE/strings.xml b/core/res/res/values-et-rEE/strings.xml
index 5f05ac2..39523ef 100644
--- a/core/res/res/values-et-rEE/strings.xml
+++ b/core/res/res/values-et-rEE/strings.xml
@@ -382,6 +382,8 @@
<string name="permdesc_bindVpnService" msgid="2067845564581693905">"Võimaldab omanikul siduda VPN-teenuse ülataseme liidesega. Tavarakenduste puhul ei peaks seda kunagi vaja minema."</string>
<string name="permlab_bindWallpaper" msgid="8716400279937856462">"taustapildiga sidumine"</string>
<string name="permdesc_bindWallpaper" msgid="7108428692595491668">"Lubab omanikul siduda taustapildi ülataseme liidesega. Tavarakenduste puhul ei peaks seda kunagi vaja minema."</string>
+ <string name="permlab_bindRemoteDisplay" msgid="1782923938029941960">"kaugekraaniga sidumine"</string>
+ <string name="permdesc_bindRemoteDisplay" msgid="1261242718727295981">"Lubab omanikul siduda rakenduse kaugekraani ülataseme liidesega. Tavarakenduste puhul ei peaks seda kunagi vaja minema."</string>
<string name="permlab_bindRemoteViews" msgid="5697987759897367099">"vidinateenusega sidumine"</string>
<string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"Lubab omanikul siduda vidina teenuse ülataseme liidesega. Tavarakenduste puhul ei peaks seda kunagi vaja minema."</string>
<string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"seadme administraatoriga suhtlemine"</string>
@@ -1489,8 +1491,12 @@
<string name="default_audio_route_category_name" msgid="3722811174003886946">"Süsteem"</string>
<string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Bluetooth-heli"</string>
<string name="wireless_display_route_description" msgid="9070346425023979651">"Juhtmeta ekraan"</string>
- <string name="media_route_chooser_grouping_done" msgid="7966438307723317169">"Valmis"</string>
<string name="media_route_button_content_description" msgid="5758553567065145276">"Meediaväljund"</string>
+ <string name="media_route_chooser_title" msgid="1751618554539087622">"Seadmega ühendamine"</string>
+ <string name="media_route_chooser_title_for_remote_display" msgid="3395541745872017583">"Ekraanikuva ülekandmine seadmesse"</string>
+ <string name="media_route_chooser_searching" msgid="4776236202610828706">"Seadmete otsimine …"</string>
+ <string name="media_route_chooser_extended_settings" msgid="87015534236701604">"Seaded"</string>
+ <string name="media_route_controller_disconnect" msgid="8966120286374158649">"Katkesta ühendus"</string>
<string name="media_route_status_scanning" msgid="7279908761758293783">"Skaneering ..."</string>
<string name="media_route_status_connecting" msgid="6422571716007825440">"Ühendan..."</string>
<string name="media_route_status_available" msgid="6983258067194649391">"Saadaval"</string>
@@ -1501,8 +1507,10 @@
<string name="display_manager_overlay_display_name" msgid="5142365982271620716">"Ülekate nr .<xliff:g id="ID">%1$d</xliff:g>"</string>
<string name="display_manager_overlay_display_title" msgid="652124517672257172">"<xliff:g id="NAME">%1$s</xliff:g>: <xliff:g id="WIDTH">%2$d</xliff:g> x <xliff:g id="HEIGHT">%3$d</xliff:g>, <xliff:g id="DPI">%4$d</xliff:g> dpi"</string>
<string name="display_manager_overlay_display_secure_suffix" msgid="6022119702628572080">", turvaline"</string>
- <string name="wifi_display_notification_title" msgid="2223050649240326557">"Juhtmeta ekraaniühendus on loodud"</string>
- <string name="wifi_display_notification_message" msgid="4498802012464170685">"Ekraan on näha teises seadmes"</string>
+ <string name="wifi_display_notification_connecting_title" msgid="2838646471050359706">"Ekraanikuva ülekandmine"</string>
+ <string name="wifi_display_notification_connecting_message" msgid="5837350993752841389">"Ühendamine ekraaniga <xliff:g id="NAME">%1$s</xliff:g>"</string>
+ <string name="wifi_display_notification_connected_title" msgid="8567308065912676285">"Ekraanikuva ülekandmine"</string>
+ <string name="wifi_display_notification_connected_message" msgid="2587209325701109715">"Ühendatud ekraaniga <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="wifi_display_notification_disconnect" msgid="6183754463561153372">"Katkesta ühendus"</string>
<string name="kg_emergency_call_label" msgid="684946192523830531">"Hädaabikõne"</string>
<string name="kg_forgot_pattern_button_text" msgid="8852021467868220608">"Unustasin mustri"</string>
diff --git a/core/res/res/values-fa/strings.xml b/core/res/res/values-fa/strings.xml
index baa11fa..93a8eec 100644
--- a/core/res/res/values-fa/strings.xml
+++ b/core/res/res/values-fa/strings.xml
@@ -382,6 +382,8 @@
<string name="permdesc_bindVpnService" msgid="2067845564581693905">"به دارنده اجازه میدهد که به رابط سطح بالای سرویس Vpn متصل شود. هرگز برای برنامههای معمولی مورد نیاز نیست."</string>
<string name="permlab_bindWallpaper" msgid="8716400279937856462">"پیوند شده به تصویر زمینه"</string>
<string name="permdesc_bindWallpaper" msgid="7108428692595491668">"به دارنده اجازه میدهد تا به رابط سطح بالای تصویر زمینه متصل شود. برنامههای معمولی هرگز به این ویژگی نیاز ندارند."</string>
+ <string name="permlab_bindRemoteDisplay" msgid="1782923938029941960">"اتصال به نمایشگر راه دور"</string>
+ <string name="permdesc_bindRemoteDisplay" msgid="1261242718727295981">"به دارنده امکان میدهد تا به رابط سطح بالای نمایشگر راه دور وصل شود. نباید هرگز برای برنامههای عادی لازم باشد."</string>
<string name="permlab_bindRemoteViews" msgid="5697987759897367099">"اتصال به یک سرویس ابزارک"</string>
<string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"به دارنده اجازه میدهد که به رابط سطح بالای سرویس ابزارک متصل شود. هرگز برای برنامههای معمولی مورد نیاز نیست."</string>
<string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"تعامل با یک سرپرست دستگاه"</string>
@@ -1489,8 +1491,12 @@
<string name="default_audio_route_category_name" msgid="3722811174003886946">"سیستم"</string>
<string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"بلوتوثهای صوتی"</string>
<string name="wireless_display_route_description" msgid="9070346425023979651">"صفحه نمایش بیسیم"</string>
- <string name="media_route_chooser_grouping_done" msgid="7966438307723317169">"انجام شد"</string>
<string name="media_route_button_content_description" msgid="5758553567065145276">"خروجی رسانه"</string>
+ <string name="media_route_chooser_title" msgid="1751618554539087622">"برقراری ارتباط با دستگاه"</string>
+ <string name="media_route_chooser_title_for_remote_display" msgid="3395541745872017583">"فرستادن صفحه نمایش به دستگاه"</string>
+ <string name="media_route_chooser_searching" msgid="4776236202610828706">"در حال جستجو برای دستگاهها..."</string>
+ <string name="media_route_chooser_extended_settings" msgid="87015534236701604">"تنظیمات"</string>
+ <string name="media_route_controller_disconnect" msgid="8966120286374158649">"قطع ارتباط"</string>
<string name="media_route_status_scanning" msgid="7279908761758293783">"در حال اسکن کردن…"</string>
<string name="media_route_status_connecting" msgid="6422571716007825440">"درحال اتصال…"</string>
<string name="media_route_status_available" msgid="6983258067194649391">"در دسترس"</string>
@@ -1501,8 +1507,10 @@
<string name="display_manager_overlay_display_name" msgid="5142365982271620716">"همپوشانی #<xliff:g id="ID">%1$d</xliff:g>"</string>
<string name="display_manager_overlay_display_title" msgid="652124517672257172">"<xliff:g id="NAME">%1$s</xliff:g>: <xliff:g id="WIDTH">%2$d</xliff:g>x<xliff:g id="HEIGHT">%3$d</xliff:g>, <xliff:g id="DPI">%4$d</xliff:g> dpi"</string>
<string name="display_manager_overlay_display_secure_suffix" msgid="6022119702628572080">"، امن"</string>
- <string name="wifi_display_notification_title" msgid="2223050649240326557">"نمایشگر بیسیم متصل است"</string>
- <string name="wifi_display_notification_message" msgid="4498802012464170685">"این صفحه در حال نمایش در دستگاه دیگری است"</string>
+ <string name="wifi_display_notification_connecting_title" msgid="2838646471050359706">"درحال فرستادن صفحه نمایش"</string>
+ <string name="wifi_display_notification_connecting_message" msgid="5837350993752841389">"درحال اتصال به <xliff:g id="NAME">%1$s</xliff:g>"</string>
+ <string name="wifi_display_notification_connected_title" msgid="8567308065912676285">"درحال فرستادن صفحه نمایش"</string>
+ <string name="wifi_display_notification_connected_message" msgid="2587209325701109715">"به <xliff:g id="NAME">%1$s</xliff:g> متصل شد"</string>
<string name="wifi_display_notification_disconnect" msgid="6183754463561153372">"قطع اتصال"</string>
<string name="kg_emergency_call_label" msgid="684946192523830531">"تماس اضطراری"</string>
<string name="kg_forgot_pattern_button_text" msgid="8852021467868220608">"الگو را فراموش کردهاید"</string>
diff --git a/core/res/res/values-fi/strings.xml b/core/res/res/values-fi/strings.xml
index 3718ccc..e4d4e3e 100644
--- a/core/res/res/values-fi/strings.xml
+++ b/core/res/res/values-fi/strings.xml
@@ -382,6 +382,8 @@
<string name="permdesc_bindVpnService" msgid="2067845564581693905">"Antaa sovelluksen sitoutua VPN-palvelun ylemmän tason käyttöliittymään. Ei tavallisten sovellusten käyttöön."</string>
<string name="permlab_bindWallpaper" msgid="8716400279937856462">"sido taustakuvaan"</string>
<string name="permdesc_bindWallpaper" msgid="7108428692595491668">"Antaa sovelluksen sitoutua taustakuvan ylätason käyttöliittymään. Ei tavallisten sovellusten käyttöön."</string>
+ <string name="permlab_bindRemoteDisplay" msgid="1782923938029941960">"etänäyttöön sitoutuminen"</string>
+ <string name="permdesc_bindRemoteDisplay" msgid="1261242718727295981">"Antaa sovelluksen sitoutua etänäytön ylemmän tason käyttöliittymään. Ei tavallisten sovelluksien käyttöön."</string>
<string name="permlab_bindRemoteViews" msgid="5697987759897367099">"sitoudu widget-palveluun"</string>
<string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"Antaa sovelluksen sitoutua widget-palvelun ylemmän tason käyttöliittymään. Ei tavallisten sovelluksien käyttöön."</string>
<string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"kommunikoi laitteen järjestelmänvalvojan kanssa"</string>
@@ -1489,8 +1491,12 @@
<string name="default_audio_route_category_name" msgid="3722811174003886946">"Järjestelmä"</string>
<string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Bluetooth-ääni"</string>
<string name="wireless_display_route_description" msgid="9070346425023979651">"Langaton näyttö"</string>
- <string name="media_route_chooser_grouping_done" msgid="7966438307723317169">"Valmis"</string>
<string name="media_route_button_content_description" msgid="5758553567065145276">"Median äänentoisto"</string>
+ <string name="media_route_chooser_title" msgid="1751618554539087622">"Yhdistä laitteeseen"</string>
+ <string name="media_route_chooser_title_for_remote_display" msgid="3395541745872017583">"Lähetä näyttö laitteeseen"</string>
+ <string name="media_route_chooser_searching" msgid="4776236202610828706">"Etsitään laitteita…"</string>
+ <string name="media_route_chooser_extended_settings" msgid="87015534236701604">"Asetukset"</string>
+ <string name="media_route_controller_disconnect" msgid="8966120286374158649">"Katkaise yhteys"</string>
<string name="media_route_status_scanning" msgid="7279908761758293783">"Etsitään..."</string>
<string name="media_route_status_connecting" msgid="6422571716007825440">"Yhdistetään..."</string>
<string name="media_route_status_available" msgid="6983258067194649391">"Käytettävissä"</string>
@@ -1501,8 +1507,10 @@
<string name="display_manager_overlay_display_name" msgid="5142365982271620716">"Peittokuva # <xliff:g id="ID">%1$d</xliff:g>"</string>
<string name="display_manager_overlay_display_title" msgid="652124517672257172">"<xliff:g id="NAME">%1$s</xliff:g>: <xliff:g id="WIDTH">%2$d</xliff:g> x <xliff:g id="HEIGHT">%3$d</xliff:g>, <xliff:g id="DPI">%4$d</xliff:g> dpi"</string>
<string name="display_manager_overlay_display_secure_suffix" msgid="6022119702628572080">", suojattu"</string>
- <string name="wifi_display_notification_title" msgid="2223050649240326557">"Langaton näyttö on yhdistetty"</string>
- <string name="wifi_display_notification_message" msgid="4498802012464170685">"Tämä ruutu näkyy toisella laitteella"</string>
+ <string name="wifi_display_notification_connecting_title" msgid="2838646471050359706">"Lähetetään näyttöä"</string>
+ <string name="wifi_display_notification_connecting_message" msgid="5837350993752841389">"Yhdistetään näyttöön <xliff:g id="NAME">%1$s</xliff:g>"</string>
+ <string name="wifi_display_notification_connected_title" msgid="8567308065912676285">"Lähetetään näyttöä"</string>
+ <string name="wifi_display_notification_connected_message" msgid="2587209325701109715">"Yhdistetty näyttöön <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="wifi_display_notification_disconnect" msgid="6183754463561153372">"Katkaise yhteys"</string>
<string name="kg_emergency_call_label" msgid="684946192523830531">"Hätäpuhelu"</string>
<string name="kg_forgot_pattern_button_text" msgid="8852021467868220608">"Unohtunut kuvio"</string>
diff --git a/core/res/res/values-fr-rCA/strings.xml b/core/res/res/values-fr-rCA/strings.xml
index bbfaad7..7c11f9a 100644
--- a/core/res/res/values-fr-rCA/strings.xml
+++ b/core/res/res/values-fr-rCA/strings.xml
@@ -382,6 +382,8 @@
<string name="permdesc_bindVpnService" msgid="2067845564581693905">"Permet à l\'application autorisée de s\'associer à l\'interface de plus haut niveau d\'un service RPV. Les applications standards ne doivent jamais avoir recours à cette fonctionnalité."</string>
<string name="permlab_bindWallpaper" msgid="8716400279937856462">"se fixer à un fond d\'écran"</string>
<string name="permdesc_bindWallpaper" msgid="7108428692595491668">"Permet à l\'application autorisée de s\'associer à l\'interface de plus haut niveau d\'un fond d\'écran. Les applications standards ne doivent jamais avoir recours à cette fonctionnalité."</string>
+ <string name="permlab_bindRemoteDisplay" msgid="1782923938029941960">"lier à un écran distant"</string>
+ <string name="permdesc_bindRemoteDisplay" msgid="1261242718727295981">"Permet à l\'application autorisée de s\'associer à l\'interface de plus haut niveau d\'un écran distant. Les applications standards ne doivent jamais avoir recours à cette fonctionnalité."</string>
<string name="permlab_bindRemoteViews" msgid="5697987759897367099">"s\'associer à un service de widget"</string>
<string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"Permet à l\'application autorisée de s\'associer à l\'interface de plus haut niveau d\'un service de widget. Les applications standards ne doivent jamais avoir recours à cette fonctionnalité."</string>
<string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"interagir avec l\'administrateur d\'un périphérique"</string>
@@ -788,7 +790,7 @@
<string name="imProtocolYahoo" msgid="8271439408469021273">"Yahoo"</string>
<string name="imProtocolSkype" msgid="9019296744622832951">"Skype"</string>
<string name="imProtocolQq" msgid="8887484379494111884">"QQ"</string>
- <string name="imProtocolGoogleTalk" msgid="493902321140277304">"Conversations"</string>
+ <string name="imProtocolGoogleTalk" msgid="493902321140277304">"Hangouts"</string>
<string name="imProtocolIcq" msgid="1574870433606517315">"ICQ"</string>
<string name="imProtocolJabber" msgid="2279917630875771722">"Jabber"</string>
<string name="imProtocolNetMeeting" msgid="8287625655986827971">"NetMeeting"</string>
@@ -1489,8 +1491,12 @@
<string name="default_audio_route_category_name" msgid="3722811174003886946">"Système"</string>
<string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Audio Bluetooth"</string>
<string name="wireless_display_route_description" msgid="9070346425023979651">"Affichage sans fil"</string>
- <string name="media_route_chooser_grouping_done" msgid="7966438307723317169">"Terminé"</string>
<string name="media_route_button_content_description" msgid="5758553567065145276">"Sortie multimédia"</string>
+ <string name="media_route_chooser_title" msgid="1751618554539087622">"Connexion à l\'appareil"</string>
+ <string name="media_route_chooser_title_for_remote_display" msgid="3395541745872017583">"Diffuser l\'écran sur l\'appareil"</string>
+ <string name="media_route_chooser_searching" msgid="4776236202610828706">"Recherche d\'appareils en cours…"</string>
+ <string name="media_route_chooser_extended_settings" msgid="87015534236701604">"Paramètres"</string>
+ <string name="media_route_controller_disconnect" msgid="8966120286374158649">"Déconnecter"</string>
<string name="media_route_status_scanning" msgid="7279908761758293783">"Analyse en cours..."</string>
<string name="media_route_status_connecting" msgid="6422571716007825440">"Connexion en cours..."</string>
<string name="media_route_status_available" msgid="6983258067194649391">"Disponible"</string>
@@ -1501,8 +1507,10 @@
<string name="display_manager_overlay_display_name" msgid="5142365982271620716">"Superposition n° <xliff:g id="ID">%1$d</xliff:g>"</string>
<string name="display_manager_overlay_display_title" msgid="652124517672257172">"<xliff:g id="NAME">%1$s</xliff:g> : <xliff:g id="WIDTH">%2$d</xliff:g> x <xliff:g id="HEIGHT">%3$d</xliff:g>, <xliff:g id="DPI">%4$d</xliff:g> ppp"</string>
<string name="display_manager_overlay_display_secure_suffix" msgid="6022119702628572080">", sécurisé"</string>
- <string name="wifi_display_notification_title" msgid="2223050649240326557">"L\'affichage sans fil est connecté."</string>
- <string name="wifi_display_notification_message" msgid="4498802012464170685">"Cet écran s\'affiche sur un autre appareil."</string>
+ <string name="wifi_display_notification_connecting_title" msgid="2838646471050359706">"Connexion à l\'écran en cours"</string>
+ <string name="wifi_display_notification_connecting_message" msgid="5837350993752841389">"Connexion au réseau <xliff:g id="NAME">%1$s</xliff:g> en cours…"</string>
+ <string name="wifi_display_notification_connected_title" msgid="8567308065912676285">"Diffusion de l\'écran en cours"</string>
+ <string name="wifi_display_notification_connected_message" msgid="2587209325701109715">"Connecté à <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="wifi_display_notification_disconnect" msgid="6183754463561153372">"Déconnecter"</string>
<string name="kg_emergency_call_label" msgid="684946192523830531">"Appel d\'urgence"</string>
<string name="kg_forgot_pattern_button_text" msgid="8852021467868220608">"J\'ai oublié le schéma"</string>
diff --git a/core/res/res/values-fr/strings.xml b/core/res/res/values-fr/strings.xml
index a6d7687..04a55f2 100644
--- a/core/res/res/values-fr/strings.xml
+++ b/core/res/res/values-fr/strings.xml
@@ -382,6 +382,8 @@
<string name="permdesc_bindVpnService" msgid="2067845564581693905">"Permet à l\'application autorisée de s\'associer à l\'interface de plus haut niveau d\'un service VPN. Les applications standards ne doivent jamais avoir recours à cette fonctionnalité."</string>
<string name="permlab_bindWallpaper" msgid="8716400279937856462">"Se fixer sur un fond d\'écran"</string>
<string name="permdesc_bindWallpaper" msgid="7108428692595491668">"Permet à l\'application autorisée de s\'associer à l\'interface de plus haut niveau d\'un fond d\'écran. Les applications standards ne doivent jamais avoir recours à cette fonctionnalité."</string>
+ <string name="permlab_bindRemoteDisplay" msgid="1782923938029941960">"s\'associer à un écran à distance"</string>
+ <string name="permdesc_bindRemoteDisplay" msgid="1261242718727295981">"Permettre à l\'application autorisée de s\'associer à l\'interface de niveau supérieur d\'un écran à distance. Cette fonctionnalité ne devrait pas être nécessaire pour les applications standards."</string>
<string name="permlab_bindRemoteViews" msgid="5697987759897367099">"associer à un service widget"</string>
<string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"Permet à l\'application autorisée de s\'associer à l\'interface de plus haut niveau d\'un service widget. Les applications standards ne doivent jamais avoir recours à cette fonctionnalité."</string>
<string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"interagir avec l\'administrateur du périphérique"</string>
@@ -1489,8 +1491,12 @@
<string name="default_audio_route_category_name" msgid="3722811174003886946">"Système"</string>
<string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Audio Bluetooth"</string>
<string name="wireless_display_route_description" msgid="9070346425023979651">"Affichage sans fil"</string>
- <string name="media_route_chooser_grouping_done" msgid="7966438307723317169">"OK"</string>
<string name="media_route_button_content_description" msgid="5758553567065145276">"Sortie multimédia"</string>
+ <string name="media_route_chooser_title" msgid="1751618554539087622">"Connexion à l\'appareil"</string>
+ <string name="media_route_chooser_title_for_remote_display" msgid="3395541745872017583">"Diffuser l\'écran sur l\'appareil"</string>
+ <string name="media_route_chooser_searching" msgid="4776236202610828706">"Recherche d\'appareils en cours…"</string>
+ <string name="media_route_chooser_extended_settings" msgid="87015534236701604">"Paramètres"</string>
+ <string name="media_route_controller_disconnect" msgid="8966120286374158649">"Déconnecter"</string>
<string name="media_route_status_scanning" msgid="7279908761758293783">"Analyse en cours..."</string>
<string name="media_route_status_connecting" msgid="6422571716007825440">"Connexion en cours..."</string>
<string name="media_route_status_available" msgid="6983258067194649391">"Disponible"</string>
@@ -1501,8 +1507,10 @@
<string name="display_manager_overlay_display_name" msgid="5142365982271620716">"Superposition n° <xliff:g id="ID">%1$d</xliff:g>"</string>
<string name="display_manager_overlay_display_title" msgid="652124517672257172">"<xliff:g id="NAME">%1$s</xliff:g> : <xliff:g id="WIDTH">%2$d</xliff:g> x <xliff:g id="HEIGHT">%3$d</xliff:g>, <xliff:g id="DPI">%4$d</xliff:g> dpi"</string>
<string name="display_manager_overlay_display_secure_suffix" msgid="6022119702628572080">", sécurisé"</string>
- <string name="wifi_display_notification_title" msgid="2223050649240326557">"L\'affichage sans fil est connecté."</string>
- <string name="wifi_display_notification_message" msgid="4498802012464170685">"Cet écran s\'affiche sur un autre appareil."</string>
+ <string name="wifi_display_notification_connecting_title" msgid="2838646471050359706">"Diffusion de l\'écran en cours"</string>
+ <string name="wifi_display_notification_connecting_message" msgid="5837350993752841389">"Connexion à <xliff:g id="NAME">%1$s</xliff:g> en cours…"</string>
+ <string name="wifi_display_notification_connected_title" msgid="8567308065912676285">"Diffusion de l\'écran en cours"</string>
+ <string name="wifi_display_notification_connected_message" msgid="2587209325701109715">"Connecté à <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="wifi_display_notification_disconnect" msgid="6183754463561153372">"Déconnecter"</string>
<string name="kg_emergency_call_label" msgid="684946192523830531">"Appel d\'urgence"</string>
<string name="kg_forgot_pattern_button_text" msgid="8852021467868220608">"J\'ai oublié le schéma"</string>
diff --git a/core/res/res/values-hi/strings.xml b/core/res/res/values-hi/strings.xml
index 59ac55c..2650108 100644
--- a/core/res/res/values-hi/strings.xml
+++ b/core/res/res/values-hi/strings.xml
@@ -382,6 +382,8 @@
<string name="permdesc_bindVpnService" msgid="2067845564581693905">"धारक को किसी Vpn सेवा के शीर्ष-स्तर इंटरफ़ेस से आबद्ध होने देता है. सामान्य ऐप्स के लिए कभी भी आवश्यक नहीं होना चाहिए."</string>
<string name="permlab_bindWallpaper" msgid="8716400279937856462">"वॉलपेपर से आबद्ध करें"</string>
<string name="permdesc_bindWallpaper" msgid="7108428692595491668">"धारक को किसी वॉलपेपर के शीर्ष-स्तर इंटरफ़ेस से आबद्ध होने देता है. सामान्य ऐप्स के लिए कभी भी आवश्यक नहीं होना चाहिए."</string>
+ <string name="permlab_bindRemoteDisplay" msgid="1782923938029941960">"रिमोट डिस्प्ले से आबद्ध करें"</string>
+ <string name="permdesc_bindRemoteDisplay" msgid="1261242718727295981">"धारक को किसी रिमोट डिस्प्ले के शीर्ष-स्तरीय इंटरफ़ेस से आबद्ध होने देती है. सामान्य ऐप्स के लिए कभी भी आवश्यक नहीं होना चाहिए."</string>
<string name="permlab_bindRemoteViews" msgid="5697987759897367099">"किसी विजेट सेवा से आबद्ध करें"</string>
<string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"धारक को किसी विजेट सेवा के शीर्ष-स्तर इंटरफ़ेस से आबद्ध होने देता है. सामान्य ऐप्स के लिए कभी भी आवश्यक नहीं होना चाहिए."</string>
<string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"किसी उपकरण व्यवस्थापक के साथ सहभागिता करें"</string>
@@ -1489,8 +1491,12 @@
<string name="default_audio_route_category_name" msgid="3722811174003886946">"सिस्टम"</string>
<string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Bluetooth ऑडियो"</string>
<string name="wireless_display_route_description" msgid="9070346425023979651">"वायरलेस प्रदर्शन"</string>
- <string name="media_route_chooser_grouping_done" msgid="7966438307723317169">"पूर्ण"</string>
<string name="media_route_button_content_description" msgid="5758553567065145276">"मीडिया आउटपुट"</string>
+ <string name="media_route_chooser_title" msgid="1751618554539087622">"उपकरण से कनेक्ट करें"</string>
+ <string name="media_route_chooser_title_for_remote_display" msgid="3395541745872017583">"स्क्रीन को उपकरण में कास्ट करें"</string>
+ <string name="media_route_chooser_searching" msgid="4776236202610828706">"उपकरण खोजे जा रहे हैं…"</string>
+ <string name="media_route_chooser_extended_settings" msgid="87015534236701604">"सेटिंग"</string>
+ <string name="media_route_controller_disconnect" msgid="8966120286374158649">"डिस्कनेक्ट करें"</string>
<string name="media_route_status_scanning" msgid="7279908761758293783">"स्कैन कर रहा है..."</string>
<string name="media_route_status_connecting" msgid="6422571716007825440">"कनेक्ट हो रहा है..."</string>
<string name="media_route_status_available" msgid="6983258067194649391">"उपलब्ध"</string>
@@ -1501,8 +1507,10 @@
<string name="display_manager_overlay_display_name" msgid="5142365982271620716">"ओवरले #<xliff:g id="ID">%1$d</xliff:g>"</string>
<string name="display_manager_overlay_display_title" msgid="652124517672257172">"<xliff:g id="NAME">%1$s</xliff:g>: <xliff:g id="WIDTH">%2$d</xliff:g>x<xliff:g id="HEIGHT">%3$d</xliff:g>, <xliff:g id="DPI">%4$d</xliff:g> dpi"</string>
<string name="display_manager_overlay_display_secure_suffix" msgid="6022119702628572080">", सुरक्षित"</string>
- <string name="wifi_display_notification_title" msgid="2223050649240326557">"वायरलेस डिस्प्ले कनेक्ट है"</string>
- <string name="wifi_display_notification_message" msgid="4498802012464170685">"यह स्क्रीन अन्य उपकरण पर दिखाई दे रही है"</string>
+ <string name="wifi_display_notification_connecting_title" msgid="2838646471050359706">"स्क्रीन कास्ट हो रही है"</string>
+ <string name="wifi_display_notification_connecting_message" msgid="5837350993752841389">"<xliff:g id="NAME">%1$s</xliff:g> से कनेक्ट हो रहा है"</string>
+ <string name="wifi_display_notification_connected_title" msgid="8567308065912676285">"स्क्रीन कास्ट हो रही है"</string>
+ <string name="wifi_display_notification_connected_message" msgid="2587209325701109715">"<xliff:g id="NAME">%1$s</xliff:g> से कनेक्ट है"</string>
<string name="wifi_display_notification_disconnect" msgid="6183754463561153372">"डिस्कनेक्ट करें"</string>
<string name="kg_emergency_call_label" msgid="684946192523830531">"आपातकालीन कॉल"</string>
<string name="kg_forgot_pattern_button_text" msgid="8852021467868220608">"आकार भूल गए"</string>
diff --git a/core/res/res/values-hr/strings.xml b/core/res/res/values-hr/strings.xml
index 2b04e02..829c03d 100644
--- a/core/res/res/values-hr/strings.xml
+++ b/core/res/res/values-hr/strings.xml
@@ -382,6 +382,8 @@
<string name="permdesc_bindVpnService" msgid="2067845564581693905">"Nositelju omogućuje vezanje uz sučelje najviše razine VPN usluge. Ne bi smjelo biti potrebno za normalne aplikacije."</string>
<string name="permlab_bindWallpaper" msgid="8716400279937856462">"povezano s pozadinskom slikom"</string>
<string name="permdesc_bindWallpaper" msgid="7108428692595491668">"Nositelju omogućuje povezivanje sa sučeljem pozadinske slike najviše razine. Ne bi smjelo biti potrebno za normalne aplikacije."</string>
+ <string name="permlab_bindRemoteDisplay" msgid="1782923938029941960">"vezanje uz udaljeni zaslon"</string>
+ <string name="permdesc_bindRemoteDisplay" msgid="1261242718727295981">"Nositelju omogućuje vezanje uza sučelje najviše razine udaljenog zaslona. Ne bi smjelo biti potrebno za normalne aplikacije."</string>
<string name="permlab_bindRemoteViews" msgid="5697987759897367099">"vezanje na uslugu widgeta"</string>
<string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"Nositelju omogućuje vezanje uz sučelje najviše razine usluge widgeta. Ne bi smjelo biti potrebno za normalne aplikacije."</string>
<string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"interakcija s administratorom uređaja"</string>
@@ -1489,8 +1491,12 @@
<string name="default_audio_route_category_name" msgid="3722811174003886946">"Sustav"</string>
<string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Bluetooth zvuk"</string>
<string name="wireless_display_route_description" msgid="9070346425023979651">"Bežični prikaz"</string>
- <string name="media_route_chooser_grouping_done" msgid="7966438307723317169">"Gotovo"</string>
<string name="media_route_button_content_description" msgid="5758553567065145276">"Medijski izlaz"</string>
+ <string name="media_route_chooser_title" msgid="1751618554539087622">"Povezivanje s uređajem"</string>
+ <string name="media_route_chooser_title_for_remote_display" msgid="3395541745872017583">"Emitiranje zaslona na uređaj"</string>
+ <string name="media_route_chooser_searching" msgid="4776236202610828706">"Traženje uređaja…"</string>
+ <string name="media_route_chooser_extended_settings" msgid="87015534236701604">"Postavke"</string>
+ <string name="media_route_controller_disconnect" msgid="8966120286374158649">"Prekini vezu"</string>
<string name="media_route_status_scanning" msgid="7279908761758293783">"Skeniranje..."</string>
<string name="media_route_status_connecting" msgid="6422571716007825440">"Povezivanje..."</string>
<string name="media_route_status_available" msgid="6983258067194649391">"Dostupno"</string>
@@ -1501,8 +1507,10 @@
<string name="display_manager_overlay_display_name" msgid="5142365982271620716">"Preklapanje br. <xliff:g id="ID">%1$d</xliff:g>"</string>
<string name="display_manager_overlay_display_title" msgid="652124517672257172">"<xliff:g id="NAME">%1$s</xliff:g>: <xliff:g id="WIDTH">%2$d</xliff:g> x <xliff:g id="HEIGHT">%3$d</xliff:g>, <xliff:g id="DPI">%4$d</xliff:g> dpi"</string>
<string name="display_manager_overlay_display_secure_suffix" msgid="6022119702628572080">", sigurno"</string>
- <string name="wifi_display_notification_title" msgid="2223050649240326557">"Bežični je prikaz povezan"</string>
- <string name="wifi_display_notification_message" msgid="4498802012464170685">"Ovaj se zaslon prikazuje na nekom drugom uređaju"</string>
+ <string name="wifi_display_notification_connecting_title" msgid="2838646471050359706">"Emitiranje zaslona"</string>
+ <string name="wifi_display_notification_connecting_message" msgid="5837350993752841389">"Povezivanje sa zaslonom <xliff:g id="NAME">%1$s</xliff:g>"</string>
+ <string name="wifi_display_notification_connected_title" msgid="8567308065912676285">"Emitiranje zaslona"</string>
+ <string name="wifi_display_notification_connected_message" msgid="2587209325701109715">"Povezan sa zaslonom <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="wifi_display_notification_disconnect" msgid="6183754463561153372">"Isključi"</string>
<string name="kg_emergency_call_label" msgid="684946192523830531">"Hitan poziv"</string>
<string name="kg_forgot_pattern_button_text" msgid="8852021467868220608">"Zaboravili ste obrazac"</string>
diff --git a/core/res/res/values-hu/strings.xml b/core/res/res/values-hu/strings.xml
index 71f6bdc..4c9f400 100644
--- a/core/res/res/values-hu/strings.xml
+++ b/core/res/res/values-hu/strings.xml
@@ -382,6 +382,8 @@
<string name="permdesc_bindVpnService" msgid="2067845564581693905">"Lehetővé teszi a használó számára, hogy csatlakozzon egy VPN-szolgáltatás legfelső szintű kezelőfelületéhez. A normál alkalmazásoknak erre soha nincs szüksége."</string>
<string name="permlab_bindWallpaper" msgid="8716400279937856462">"összekapcsolás háttérképpel"</string>
<string name="permdesc_bindWallpaper" msgid="7108428692595491668">"Lehetővé teszi, hogy a tulajdonos kötelezővé tegye egy háttérkép legfelső szintű felületét. A normál alkalmazásoknak erre soha nincs szüksége."</string>
+ <string name="permlab_bindRemoteDisplay" msgid="1782923938029941960">"csatlakozás egy távoli kijelzőhöz"</string>
+ <string name="permdesc_bindRemoteDisplay" msgid="1261242718727295981">"Lehetővé teszi a használó számára, hogy csatlakozzon egy távoli kijelző legfelső szintű kezelőfelületéhez. A normál alkalmazásoknak erre soha nincs szükségük."</string>
<string name="permlab_bindRemoteViews" msgid="5697987759897367099">"csatlakozás modulszolgáltatáshoz"</string>
<string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"Lehetővé teszi a használó számára, hogy csatlakozzon egy modulszolgáltatás legfelső szintű kezelőfelületéhez. A normál alkalmazásoknak erre soha nincs szüksége."</string>
<string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"az eszközkezelő használata"</string>
@@ -1489,8 +1491,12 @@
<string name="default_audio_route_category_name" msgid="3722811174003886946">"Rendszer"</string>
<string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Bluetooth hang"</string>
<string name="wireless_display_route_description" msgid="9070346425023979651">"Vezeték nélküli kijelző"</string>
- <string name="media_route_chooser_grouping_done" msgid="7966438307723317169">"Kész"</string>
<string name="media_route_button_content_description" msgid="5758553567065145276">"Médiakimenet"</string>
+ <string name="media_route_chooser_title" msgid="1751618554539087622">"Csatlakozás adott eszközhöz"</string>
+ <string name="media_route_chooser_title_for_remote_display" msgid="3395541745872017583">"Képernyő átküldése az eszközre"</string>
+ <string name="media_route_chooser_searching" msgid="4776236202610828706">"Eszközkeresés…"</string>
+ <string name="media_route_chooser_extended_settings" msgid="87015534236701604">"Beállítások"</string>
+ <string name="media_route_controller_disconnect" msgid="8966120286374158649">"Leválasztás"</string>
<string name="media_route_status_scanning" msgid="7279908761758293783">"Keresés..."</string>
<string name="media_route_status_connecting" msgid="6422571716007825440">"Kapcsolódás..."</string>
<string name="media_route_status_available" msgid="6983258067194649391">"Elérhető"</string>
@@ -1501,8 +1507,10 @@
<string name="display_manager_overlay_display_name" msgid="5142365982271620716">"<xliff:g id="ID">%1$d</xliff:g>. fedvény"</string>
<string name="display_manager_overlay_display_title" msgid="652124517672257172">"<xliff:g id="NAME">%1$s</xliff:g>: <xliff:g id="WIDTH">%2$d</xliff:g> x <xliff:g id="HEIGHT">%3$d</xliff:g>, <xliff:g id="DPI">%4$d</xliff:g> képpont"</string>
<string name="display_manager_overlay_display_secure_suffix" msgid="6022119702628572080">", biztonságos"</string>
- <string name="wifi_display_notification_title" msgid="2223050649240326557">"Vezeték nélküli kijelző csatlakoztatva"</string>
- <string name="wifi_display_notification_message" msgid="4498802012464170685">"Ez a kijelző megjelenítést végez egy másik eszközön"</string>
+ <string name="wifi_display_notification_connecting_title" msgid="2838646471050359706">"Képernyő átküldése…"</string>
+ <string name="wifi_display_notification_connecting_message" msgid="5837350993752841389">"Csatlakozás a következőhöz: <xliff:g id="NAME">%1$s</xliff:g>"</string>
+ <string name="wifi_display_notification_connected_title" msgid="8567308065912676285">"Képernyő átküldése…"</string>
+ <string name="wifi_display_notification_connected_message" msgid="2587209325701109715">"Csatlakozva a következőhöz: <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="wifi_display_notification_disconnect" msgid="6183754463561153372">"Szétkapcsol"</string>
<string name="kg_emergency_call_label" msgid="684946192523830531">"Segélyhívás"</string>
<string name="kg_forgot_pattern_button_text" msgid="8852021467868220608">"Elfelejtett minta"</string>
diff --git a/core/res/res/values-hy-rAM/strings.xml b/core/res/res/values-hy-rAM/strings.xml
index f5ed539..85eedba 100644
--- a/core/res/res/values-hy-rAM/strings.xml
+++ b/core/res/res/values-hy-rAM/strings.xml
@@ -382,6 +382,8 @@
<string name="permdesc_bindVpnService" msgid="2067845564581693905">"Թույլ է տալիս սեփականատիրոջը միանալ Vpn ծառայության վերին մակարդակի ինտերֆեյսին: Սովորական հավելվածների համար երբևէ չպետք է անհրաժեշտ լինի:"</string>
<string name="permlab_bindWallpaper" msgid="8716400279937856462">"միանալ պաստառին"</string>
<string name="permdesc_bindWallpaper" msgid="7108428692595491668">"Թույլ է տալիս սեփականատիրոջը միանալ պաստառի վերին մակարդակի ինտերֆեյսին: Սովորական հավելվածների համար երբևէ չպետք է անհրաժեշտ լինի:"</string>
+ <string name="permlab_bindRemoteDisplay" msgid="1782923938029941960">"միանալ հեռակա էկրանին"</string>
+ <string name="permdesc_bindRemoteDisplay" msgid="1261242718727295981">"Թույլ է տալիս սեփականատիրոջը միանալ հեռակա էկրանի վերին մակարդակի ինտերֆեյսին: Սովորական ծրագրերի համար երբևէ չպետք է անհրաժեշտ լինի:"</string>
<string name="permlab_bindRemoteViews" msgid="5697987759897367099">"միանալ վիջեթ ծառայությանը"</string>
<string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"Թույլ է տալիս սեփականատիրոջը միանալ վիջեթ ծառայության վերին մակարդակի ինտերֆեյսին: Սովորական հավելվածների համար երբևէ չպետք է անհրաժեշտ լինի:"</string>
<string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"փոխգործակցել սարքի կառավարչի հետ"</string>
@@ -1489,8 +1491,12 @@
<string name="default_audio_route_category_name" msgid="3722811174003886946">"Համակարգ"</string>
<string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Bluetooth-ի ձայնանյութ"</string>
<string name="wireless_display_route_description" msgid="9070346425023979651">"Անլար էկրան"</string>
- <string name="media_route_chooser_grouping_done" msgid="7966438307723317169">"Կատարված է"</string>
<string name="media_route_button_content_description" msgid="5758553567065145276">"Մեդիա արտածում"</string>
+ <string name="media_route_chooser_title" msgid="1751618554539087622">"Միանալ սարքին"</string>
+ <string name="media_route_chooser_title_for_remote_display" msgid="3395541745872017583">"Հեռարձակել էկրանը սարքի վրա"</string>
+ <string name="media_route_chooser_searching" msgid="4776236202610828706">"Որոնվում են սարքեր..."</string>
+ <string name="media_route_chooser_extended_settings" msgid="87015534236701604">"Կարգավորումներ"</string>
+ <string name="media_route_controller_disconnect" msgid="8966120286374158649">"Անջատել"</string>
<string name="media_route_status_scanning" msgid="7279908761758293783">"Սկանավորում..."</string>
<string name="media_route_status_connecting" msgid="6422571716007825440">"Միանում է..."</string>
<string name="media_route_status_available" msgid="6983258067194649391">"Հասանելի է"</string>
@@ -1501,8 +1507,10 @@
<string name="display_manager_overlay_display_name" msgid="5142365982271620716">"Վերածածկ #<xliff:g id="ID">%1$d</xliff:g>"</string>
<string name="display_manager_overlay_display_title" msgid="652124517672257172">"<xliff:g id="NAME">%1$s</xliff:g>. <xliff:g id="WIDTH">%2$d</xliff:g>x<xliff:g id="HEIGHT">%3$d</xliff:g>, <xliff:g id="DPI">%4$d</xliff:g> կմվ"</string>
<string name="display_manager_overlay_display_secure_suffix" msgid="6022119702628572080">", անվտանգ"</string>
- <string name="wifi_display_notification_title" msgid="2223050649240326557">"Անլար ցուցադրումը կապակցված է"</string>
- <string name="wifi_display_notification_message" msgid="4498802012464170685">"Այս էկրանը ցուցադրվում է այլ սարքում"</string>
+ <string name="wifi_display_notification_connecting_title" msgid="2838646471050359706">"Էկրանի հեռարձակում"</string>
+ <string name="wifi_display_notification_connecting_message" msgid="5837350993752841389">"Միանում է <xliff:g id="NAME">%1$s</xliff:g>-ին"</string>
+ <string name="wifi_display_notification_connected_title" msgid="8567308065912676285">"Էկրանը հեռարձակվում է"</string>
+ <string name="wifi_display_notification_connected_message" msgid="2587209325701109715">"Միացված է <xliff:g id="NAME">%1$s</xliff:g>-ին"</string>
<string name="wifi_display_notification_disconnect" msgid="6183754463561153372">"Անջատել"</string>
<string name="kg_emergency_call_label" msgid="684946192523830531">"Արտակարգ իրավիճակի հեռախոսազանգ"</string>
<string name="kg_forgot_pattern_button_text" msgid="8852021467868220608">"Մոռացել եմ սխեման"</string>
diff --git a/core/res/res/values-in/strings.xml b/core/res/res/values-in/strings.xml
index d6d91fb..633621a 100644
--- a/core/res/res/values-in/strings.xml
+++ b/core/res/res/values-in/strings.xml
@@ -382,6 +382,8 @@
<string name="permdesc_bindVpnService" msgid="2067845564581693905">"Mengizinkan pemegang mengikat antarmuka tingkat tinggi dari suatu layanan Vpn. Tidak pernah diperlukan oleh apl normal."</string>
<string name="permlab_bindWallpaper" msgid="8716400279937856462">"mengikat ke wallpaper"</string>
<string name="permdesc_bindWallpaper" msgid="7108428692595491668">"Mengizinkan pemegang mengikat antarmuka tingkat tinggi dari suatu wallpaper. Tidak pernah diperlukan oleh apl normal."</string>
+ <string name="permlab_bindRemoteDisplay" msgid="1782923938029941960">"mengikat ke layar jarak jauh"</string>
+ <string name="permdesc_bindRemoteDisplay" msgid="1261242718727295981">"Mengizinkan pemegang mengikat ke antarmuka tingkat atas dari layar jarak jauh. Tidak pernah diperlukan untuk aplikasi normal."</string>
<string name="permlab_bindRemoteViews" msgid="5697987759897367099">"mengikat ke layanan widget"</string>
<string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"Mengizinkan pemegang mengikat antarmuka tingkat tinggi dari suatu layanan widget. Tidak pernah diperlukan oleh apl normal."</string>
<string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"berinteraksi dengan admin perangkat"</string>
@@ -1489,8 +1491,12 @@
<string name="default_audio_route_category_name" msgid="3722811174003886946">"Sistem"</string>
<string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Audio Bluetooth"</string>
<string name="wireless_display_route_description" msgid="9070346425023979651">"Layar nirkabel"</string>
- <string name="media_route_chooser_grouping_done" msgid="7966438307723317169">"Selesai"</string>
<string name="media_route_button_content_description" msgid="5758553567065145276">"Keluaran media"</string>
+ <string name="media_route_chooser_title" msgid="1751618554539087622">"Sambungkan ke perangkat"</string>
+ <string name="media_route_chooser_title_for_remote_display" msgid="3395541745872017583">"Transmisi layar ke perangkat"</string>
+ <string name="media_route_chooser_searching" msgid="4776236202610828706">"Menelusuri perangkat…"</string>
+ <string name="media_route_chooser_extended_settings" msgid="87015534236701604">"Setelan"</string>
+ <string name="media_route_controller_disconnect" msgid="8966120286374158649">"Putuskan sambungan"</string>
<string name="media_route_status_scanning" msgid="7279908761758293783">"Memindai..."</string>
<string name="media_route_status_connecting" msgid="6422571716007825440">"Menyambung..."</string>
<string name="media_route_status_available" msgid="6983258067194649391">"Tersedia"</string>
@@ -1501,8 +1507,10 @@
<string name="display_manager_overlay_display_name" msgid="5142365982271620716">"Hamparan #<xliff:g id="ID">%1$d</xliff:g>"</string>
<string name="display_manager_overlay_display_title" msgid="652124517672257172">"<xliff:g id="NAME">%1$s</xliff:g>: <xliff:g id="WIDTH">%2$d</xliff:g>x<xliff:g id="HEIGHT">%3$d</xliff:g>, <xliff:g id="DPI">%4$d</xliff:g> dpi"</string>
<string name="display_manager_overlay_display_secure_suffix" msgid="6022119702628572080">", aman"</string>
- <string name="wifi_display_notification_title" msgid="2223050649240326557">"Layar nirkabel tersambung"</string>
- <string name="wifi_display_notification_message" msgid="4498802012464170685">"Layar ini ditampilkan di perangkat lain"</string>
+ <string name="wifi_display_notification_connecting_title" msgid="2838646471050359706">"Transmisi layar"</string>
+ <string name="wifi_display_notification_connecting_message" msgid="5837350993752841389">"Menyambung ke <xliff:g id="NAME">%1$s</xliff:g>"</string>
+ <string name="wifi_display_notification_connected_title" msgid="8567308065912676285">"Transmisi layar"</string>
+ <string name="wifi_display_notification_connected_message" msgid="2587209325701109715">"Tersambung ke <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="wifi_display_notification_disconnect" msgid="6183754463561153372">"Putuskan sambungan"</string>
<string name="kg_emergency_call_label" msgid="684946192523830531">"Panggilan darurat"</string>
<string name="kg_forgot_pattern_button_text" msgid="8852021467868220608">"Lupa Pola?"</string>
diff --git a/core/res/res/values-it/strings.xml b/core/res/res/values-it/strings.xml
index 88d69de..6bae95b 100644
--- a/core/res/res/values-it/strings.xml
+++ b/core/res/res/values-it/strings.xml
@@ -382,6 +382,8 @@
<string name="permdesc_bindVpnService" msgid="2067845564581693905">"Consente l\'associazione all\'interfaccia principale di un servizio VPN. Non dovrebbe mai essere necessario per le normali applicazioni."</string>
<string name="permlab_bindWallpaper" msgid="8716400279937856462">"associazione a sfondo"</string>
<string name="permdesc_bindWallpaper" msgid="7108428692595491668">"Consente l\'associazione di uno sfondo all\'interfaccia principale. Non dovrebbe mai essere necessaria per le normali applicazioni."</string>
+ <string name="permlab_bindRemoteDisplay" msgid="1782923938029941960">"collega a un display remoto"</string>
+ <string name="permdesc_bindRemoteDisplay" msgid="1261242718727295981">"Consente al titolare di collegarsi all\'interfaccia di primo livello di un display remoto. Non dovrebbe essere mai necessaria per le normali applicazioni."</string>
<string name="permlab_bindRemoteViews" msgid="5697987759897367099">"associazione a un servizio widget"</string>
<string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"Consente l\'associazione all\'interfaccia principale di un servizio widget. Non dovrebbe mai essere necessario per le normali applicazioni."</string>
<string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"interazione con un amministratore dispositivo"</string>
@@ -1489,8 +1491,12 @@
<string name="default_audio_route_category_name" msgid="3722811174003886946">"Sistema"</string>
<string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Audio Bluetooth"</string>
<string name="wireless_display_route_description" msgid="9070346425023979651">"Visualizzazione wireless"</string>
- <string name="media_route_chooser_grouping_done" msgid="7966438307723317169">"Fine"</string>
<string name="media_route_button_content_description" msgid="5758553567065145276">"Uscita media"</string>
+ <string name="media_route_chooser_title" msgid="1751618554539087622">"Connetti al dispositivo"</string>
+ <string name="media_route_chooser_title_for_remote_display" msgid="3395541745872017583">"Trasmetti schermo al dispositivo"</string>
+ <string name="media_route_chooser_searching" msgid="4776236202610828706">"Ricerca di dispositivi in corso…"</string>
+ <string name="media_route_chooser_extended_settings" msgid="87015534236701604">"Impostazioni"</string>
+ <string name="media_route_controller_disconnect" msgid="8966120286374158649">"Disconnetti"</string>
<string name="media_route_status_scanning" msgid="7279908761758293783">"Ricerca in corso..."</string>
<string name="media_route_status_connecting" msgid="6422571716007825440">"Connessione..."</string>
<string name="media_route_status_available" msgid="6983258067194649391">"Disponibile"</string>
@@ -1501,8 +1507,10 @@
<string name="display_manager_overlay_display_name" msgid="5142365982271620716">"Overlay n. <xliff:g id="ID">%1$d</xliff:g>"</string>
<string name="display_manager_overlay_display_title" msgid="652124517672257172">"<xliff:g id="NAME">%1$s</xliff:g>: <xliff:g id="WIDTH">%2$d</xliff:g> x <xliff:g id="HEIGHT">%3$d</xliff:g>, <xliff:g id="DPI">%4$d</xliff:g> dpi"</string>
<string name="display_manager_overlay_display_secure_suffix" msgid="6022119702628572080">", opzione sicura"</string>
- <string name="wifi_display_notification_title" msgid="2223050649240326557">"Il display wireless è connesso"</string>
- <string name="wifi_display_notification_message" msgid="4498802012464170685">"Questa schermata è mostrata su un altro dispositivo"</string>
+ <string name="wifi_display_notification_connecting_title" msgid="2838646471050359706">"Trasmissione schermo"</string>
+ <string name="wifi_display_notification_connecting_message" msgid="5837350993752841389">"Collegamento a <xliff:g id="NAME">%1$s</xliff:g> in corso"</string>
+ <string name="wifi_display_notification_connected_title" msgid="8567308065912676285">"Trasmissione schermo attiva"</string>
+ <string name="wifi_display_notification_connected_message" msgid="2587209325701109715">"Collegato a <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="wifi_display_notification_disconnect" msgid="6183754463561153372">"Disconnetti"</string>
<string name="kg_emergency_call_label" msgid="684946192523830531">"Chiamata di emergenza"</string>
<string name="kg_forgot_pattern_button_text" msgid="8852021467868220608">"Sequenza dimenticata"</string>
diff --git a/core/res/res/values-iw/strings.xml b/core/res/res/values-iw/strings.xml
index 8dcdac5..1d42f65 100644
--- a/core/res/res/values-iw/strings.xml
+++ b/core/res/res/values-iw/strings.xml
@@ -382,6 +382,8 @@
<string name="permdesc_bindVpnService" msgid="2067845564581693905">"מאפשר למשתמש לבצע איגוד לממשק ברמה עליונה של שירות VPN. הרשאה זו לעולם אינה נחוצה לאפליקציות רגילים."</string>
<string name="permlab_bindWallpaper" msgid="8716400279937856462">"קשור לטפט"</string>
<string name="permdesc_bindWallpaper" msgid="7108428692595491668">"מאפשר למשתמש לבצע איגוד לממשק הרמה העליונה של טפט. הרשאה זו לעולם אינה נחוצה לאפליקציות רגילים."</string>
+ <string name="permlab_bindRemoteDisplay" msgid="1782923938029941960">"איגוד לצג מרוחק"</string>
+ <string name="permdesc_bindRemoteDisplay" msgid="1261242718727295981">"הרשאה זו מאפשרת למשתמש לבצע איגוד לממשק הרמה העליונה של צג רחוק. לעולם אינה אמורה להיות נחוצה לאפליקציות רגילות."</string>
<string name="permlab_bindRemoteViews" msgid="5697987759897367099">"הכפפה לשירות Widget"</string>
<string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"מאפשר למשתמש לבצע איגוד לממשק הרמה העליונה של שירות Widget. הרשאה זו לעולם אינה נחוצה לאפליקציות רגילים."</string>
<string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"קיים אינטראקציה עם מנהל המכשיר"</string>
@@ -1489,8 +1491,12 @@
<string name="default_audio_route_category_name" msgid="3722811174003886946">"מערכת"</string>
<string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"אודיו Bluetooth"</string>
<string name="wireless_display_route_description" msgid="9070346425023979651">"צג אלחוטי"</string>
- <string name="media_route_chooser_grouping_done" msgid="7966438307723317169">"סיום"</string>
<string name="media_route_button_content_description" msgid="5758553567065145276">"פלט מדיה"</string>
+ <string name="media_route_chooser_title" msgid="1751618554539087622">"התחברות למכשיר"</string>
+ <string name="media_route_chooser_title_for_remote_display" msgid="3395541745872017583">"העברת מסך אל מכשיר"</string>
+ <string name="media_route_chooser_searching" msgid="4776236202610828706">"מחפש מכשירים…"</string>
+ <string name="media_route_chooser_extended_settings" msgid="87015534236701604">"הגדרות"</string>
+ <string name="media_route_controller_disconnect" msgid="8966120286374158649">"התנתק"</string>
<string name="media_route_status_scanning" msgid="7279908761758293783">"סורק..."</string>
<string name="media_route_status_connecting" msgid="6422571716007825440">"מתחבר..."</string>
<string name="media_route_status_available" msgid="6983258067194649391">"זמין"</string>
@@ -1501,8 +1507,10 @@
<string name="display_manager_overlay_display_name" msgid="5142365982271620716">"שכבת על #<xliff:g id="ID">%1$d</xliff:g>"</string>
<string name="display_manager_overlay_display_title" msgid="652124517672257172">"<xliff:g id="NAME">%1$s</xliff:g>: <xliff:g id="WIDTH">%2$d</xliff:g>x<xliff:g id="HEIGHT">%3$d</xliff:g>, <xliff:g id="DPI">%4$d</xliff:g> dpi"</string>
<string name="display_manager_overlay_display_secure_suffix" msgid="6022119702628572080">", מאובטח"</string>
- <string name="wifi_display_notification_title" msgid="2223050649240326557">"מסך אלחוטי מחובר"</string>
- <string name="wifi_display_notification_message" msgid="4498802012464170685">"מסך זה מוצג במכשיר אחר"</string>
+ <string name="wifi_display_notification_connecting_title" msgid="2838646471050359706">"העברת מסך מתבצעת"</string>
+ <string name="wifi_display_notification_connecting_message" msgid="5837350993752841389">"מתחבר אל <xliff:g id="NAME">%1$s</xliff:g>"</string>
+ <string name="wifi_display_notification_connected_title" msgid="8567308065912676285">"העברת מסך מתבצעת"</string>
+ <string name="wifi_display_notification_connected_message" msgid="2587209325701109715">"מחובר אל <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="wifi_display_notification_disconnect" msgid="6183754463561153372">"נתק"</string>
<string name="kg_emergency_call_label" msgid="684946192523830531">"שיחת חירום"</string>
<string name="kg_forgot_pattern_button_text" msgid="8852021467868220608">"שכחת את הקו"</string>
diff --git a/core/res/res/values-ja/strings.xml b/core/res/res/values-ja/strings.xml
index 0dc0a30..559d53f 100644
--- a/core/res/res/values-ja/strings.xml
+++ b/core/res/res/values-ja/strings.xml
@@ -382,6 +382,8 @@
<string name="permdesc_bindVpnService" msgid="2067845564581693905">"VPNサービスのトップレベルインターフェースにバインドすることを所有者に許可します。通常のアプリでは不要です。"</string>
<string name="permlab_bindWallpaper" msgid="8716400279937856462">"壁紙にバインド"</string>
<string name="permdesc_bindWallpaper" msgid="7108428692595491668">"壁紙のトップレベルインターフェースにバインドすることを所有者に許可します。通常のアプリでは不要です。"</string>
+ <string name="permlab_bindRemoteDisplay" msgid="1782923938029941960">"リモートディスプレイへのバインド"</string>
+ <string name="permdesc_bindRemoteDisplay" msgid="1261242718727295981">"リモートディスプレイのトップレベルインターフェースにバインドすることを所有者に許可します。通常のアプリでは不要です。"</string>
<string name="permlab_bindRemoteViews" msgid="5697987759897367099">"ウィジェットサービスにバインド"</string>
<string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"ウィジェットサービスのトップレベルインターフェースにバインドすることを所有者に許可します。通常のアプリでは不要です。"</string>
<string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"デバイス管理者との通信"</string>
@@ -1489,8 +1491,12 @@
<string name="default_audio_route_category_name" msgid="3722811174003886946">"システム"</string>
<string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Bluetooth音声"</string>
<string name="wireless_display_route_description" msgid="9070346425023979651">"ワイヤレスディスプレイ"</string>
- <string name="media_route_chooser_grouping_done" msgid="7966438307723317169">"完了"</string>
<string name="media_route_button_content_description" msgid="5758553567065145276">"メディア出力"</string>
+ <string name="media_route_chooser_title" msgid="1751618554539087622">"端末に接続"</string>
+ <string name="media_route_chooser_title_for_remote_display" msgid="3395541745872017583">"端末への画面のキャスト"</string>
+ <string name="media_route_chooser_searching" msgid="4776236202610828706">"端末を検索しています…"</string>
+ <string name="media_route_chooser_extended_settings" msgid="87015534236701604">"設定"</string>
+ <string name="media_route_controller_disconnect" msgid="8966120286374158649">"接続を解除"</string>
<string name="media_route_status_scanning" msgid="7279908761758293783">"スキャン中..."</string>
<string name="media_route_status_connecting" msgid="6422571716007825440">"接続中..."</string>
<string name="media_route_status_available" msgid="6983258067194649391">"利用できます"</string>
@@ -1501,8 +1507,10 @@
<string name="display_manager_overlay_display_name" msgid="5142365982271620716">"オーバーレイ第<xliff:g id="ID">%1$d</xliff:g>"</string>
<string name="display_manager_overlay_display_title" msgid="652124517672257172">"<xliff:g id="NAME">%1$s</xliff:g>: <xliff:g id="WIDTH">%2$d</xliff:g>x<xliff:g id="HEIGHT">%3$d</xliff:g>、<xliff:g id="DPI">%4$d</xliff:g> dpi"</string>
<string name="display_manager_overlay_display_secure_suffix" msgid="6022119702628572080">"、セキュア"</string>
- <string name="wifi_display_notification_title" msgid="2223050649240326557">"ワイヤレスディスプレイが接続されています"</string>
- <string name="wifi_display_notification_message" msgid="4498802012464170685">"この画面は別の端末で表示されています"</string>
+ <string name="wifi_display_notification_connecting_title" msgid="2838646471050359706">"画面のキャスト中"</string>
+ <string name="wifi_display_notification_connecting_message" msgid="5837350993752841389">"<xliff:g id="NAME">%1$s</xliff:g>に接続しています"</string>
+ <string name="wifi_display_notification_connected_title" msgid="8567308065912676285">"画面のキャスト中"</string>
+ <string name="wifi_display_notification_connected_message" msgid="2587209325701109715">"<xliff:g id="NAME">%1$s</xliff:g>に接続しました"</string>
<string name="wifi_display_notification_disconnect" msgid="6183754463561153372">"切断"</string>
<string name="kg_emergency_call_label" msgid="684946192523830531">"緊急通報"</string>
<string name="kg_forgot_pattern_button_text" msgid="8852021467868220608">"パターンを忘れた場合"</string>
diff --git a/core/res/res/values-ka-rGE/strings.xml b/core/res/res/values-ka-rGE/strings.xml
index efc85ba..7f4dc90 100644
--- a/core/res/res/values-ka-rGE/strings.xml
+++ b/core/res/res/values-ka-rGE/strings.xml
@@ -382,6 +382,8 @@
<string name="permdesc_bindVpnService" msgid="2067845564581693905">"აპს შეეძლება Vpn სერვისის ზედა დონის ინტერფეისთან დაკავშირება. არასდროს გამოიყენება ჩვეულებრივ აპებში."</string>
<string name="permlab_bindWallpaper" msgid="8716400279937856462">"ფონზე მიჭედება"</string>
<string name="permdesc_bindWallpaper" msgid="7108428692595491668">"მფლობელს შეეძლება ფონის ზედა დონის ინტერფეისთან დაკავშირება. არასდროს გამოიყენება ჩვეულებრივ აპებში."</string>
+ <string name="permlab_bindRemoteDisplay" msgid="1782923938029941960">"დისტანციურ მონიტორზე მიბმა"</string>
+ <string name="permdesc_bindRemoteDisplay" msgid="1261242718727295981">"მფლობელს შეეძლება მიებას დისტანციურ მონიტორის ზედა დონის ინტერფეისს. ჩვეულებრივ აპს ეს წესით არასოდეს უნდა დაჭირდეს."</string>
<string name="permlab_bindRemoteViews" msgid="5697987759897367099">"ვიჯეტ სერვისთან დაკავშირება"</string>
<string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"აპს შეეძლება ზედა დონის ინტერფეისის ვიჯეტთან დაკავშირება. არასდროს გამოიყენება ჩვეულებრივ აპებში."</string>
<string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"მოწყობილობის ადმინთან ინტერაქცია"</string>
@@ -1489,8 +1491,12 @@
<string name="default_audio_route_category_name" msgid="3722811174003886946">"სისტემა"</string>
<string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Bluetooth აუდიო"</string>
<string name="wireless_display_route_description" msgid="9070346425023979651">"უსადენო ეკრანი"</string>
- <string name="media_route_chooser_grouping_done" msgid="7966438307723317169">"დასრულდა"</string>
<string name="media_route_button_content_description" msgid="5758553567065145276">"მედია გამომავალი"</string>
+ <string name="media_route_chooser_title" msgid="1751618554539087622">"მოწყობილობასთან დაკავშირება"</string>
+ <string name="media_route_chooser_title_for_remote_display" msgid="3395541745872017583">"ეკრანის მოწყობილობაზე გადაცემა"</string>
+ <string name="media_route_chooser_searching" msgid="4776236202610828706">"მოწყობილობების ძიება…"</string>
+ <string name="media_route_chooser_extended_settings" msgid="87015534236701604">"პარამეტრები"</string>
+ <string name="media_route_controller_disconnect" msgid="8966120286374158649">"კავშირის გაწყვეტა"</string>
<string name="media_route_status_scanning" msgid="7279908761758293783">"სკანირება..."</string>
<string name="media_route_status_connecting" msgid="6422571716007825440">"დაკავშირება..."</string>
<string name="media_route_status_available" msgid="6983258067194649391">"ხელმისაწვდომი"</string>
@@ -1501,8 +1507,10 @@
<string name="display_manager_overlay_display_name" msgid="5142365982271620716">"გადაფარვა #<xliff:g id="ID">%1$d</xliff:g>"</string>
<string name="display_manager_overlay_display_title" msgid="652124517672257172">"<xliff:g id="NAME">%1$s</xliff:g>: <xliff:g id="WIDTH">%2$d</xliff:g>x<xliff:g id="HEIGHT">%3$d</xliff:g>, <xliff:g id="DPI">%4$d</xliff:g> dpi"</string>
<string name="display_manager_overlay_display_secure_suffix" msgid="6022119702628572080">", დაცული"</string>
- <string name="wifi_display_notification_title" msgid="2223050649240326557">"უსადენო ეკრანი დაკავშირებულია"</string>
- <string name="wifi_display_notification_message" msgid="4498802012464170685">"გამოსახულება გადაეცემა სხვა მოწყობილობას"</string>
+ <string name="wifi_display_notification_connecting_title" msgid="2838646471050359706">"მიმდინარეობს ეკრანის გადაცემა"</string>
+ <string name="wifi_display_notification_connecting_message" msgid="5837350993752841389">"<xliff:g id="NAME">%1$s</xliff:g>-თან დაკავშირება"</string>
+ <string name="wifi_display_notification_connected_title" msgid="8567308065912676285">"მიმდინარეობს ეკრანის გადაცემა"</string>
+ <string name="wifi_display_notification_connected_message" msgid="2587209325701109715">"დაკავშირებულია <xliff:g id="NAME">%1$s</xliff:g>-თან"</string>
<string name="wifi_display_notification_disconnect" msgid="6183754463561153372">"კავშირის გაწყვეტა"</string>
<string name="kg_emergency_call_label" msgid="684946192523830531">"გადაუდებელი დახმარების ზარი"</string>
<string name="kg_forgot_pattern_button_text" msgid="8852021467868220608">"დაგავიწყდათ ნიმუში"</string>
diff --git a/core/res/res/values-km-rKH/strings.xml b/core/res/res/values-km-rKH/strings.xml
index 1014da4..3bf648b 100644
--- a/core/res/res/values-km-rKH/strings.xml
+++ b/core/res/res/values-km-rKH/strings.xml
@@ -382,6 +382,8 @@
<string name="permdesc_bindVpnService" msgid="2067845564581693905">"ឲ្យម្ចាស់ចងចំណុចប្រទាក់កម្រិតកំពូលនៃសេវាកម្ម Vpn ។ មិនគួរចាំបាច់សម្រាប់កម្មវិធីធម្មតាទេ។"</string>
<string name="permlab_bindWallpaper" msgid="8716400279937856462">"ចងទៅផ្ទាំងរូបភាព"</string>
<string name="permdesc_bindWallpaper" msgid="7108428692595491668">"ឲ្យម្ចាស់ចងចំណុចប្រទាក់កម្រិតកំពូលនៃផ្ទាំងរូបភាព។ មិនគួរចាំបាច់សម្រាប់កម្មវិធីធម្មតាទេ។"</string>
+ <string name="permlab_bindRemoteDisplay" msgid="1782923938029941960">"ភ្ជាប់ទៅការបង្ហាញពីចម្ងាយ"</string>
+ <string name="permdesc_bindRemoteDisplay" msgid="1261242718727295981">"អនុញ្ញាតឲ្យម្ចាស់ភ្ជាប់ទៅចំណុចប្រទាក់កម្រិតកំពូលនៃការបង្ហាញពីចម្ងាយ។ មិនគួរចាំបាច់សម្រាប់កម្មវិធីធម្មតាទេ។"</string>
<string name="permlab_bindRemoteViews" msgid="5697987759897367099">"ចងសេវាកម្មធាតុក្រាហ្វិក"</string>
<string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"ឲ្យម្ចាស់ចងចំណុចប្រទាក់កម្រិតកំពូលនៃសេវាកម្មធាតុក្រាហ្វិក។ មិនគួរចាំបាច់សម្រាប់កម្មវិធីធម្មតាទេ។"</string>
<string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"ទាក់ទងជាមួយអ្នកគ្រប់គ្រងឧបករណ៍"</string>
@@ -788,7 +790,7 @@
<string name="imProtocolYahoo" msgid="8271439408469021273">"Yahoo"</string>
<string name="imProtocolSkype" msgid="9019296744622832951">"Skype"</string>
<string name="imProtocolQq" msgid="8887484379494111884">"QQ"</string>
- <string name="imProtocolGoogleTalk" msgid="493902321140277304">"ការជជែក"</string>
+ <string name="imProtocolGoogleTalk" msgid="493902321140277304">"Hangouts"</string>
<string name="imProtocolIcq" msgid="1574870433606517315">"ICQ"</string>
<string name="imProtocolJabber" msgid="2279917630875771722">"Jabber"</string>
<string name="imProtocolNetMeeting" msgid="8287625655986827971">"NetMeeting"</string>
@@ -1489,8 +1491,12 @@
<string name="default_audio_route_category_name" msgid="3722811174003886946">"ប្រព័ន្ធ"</string>
<string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"សំឡេងប៊្លូធូស"</string>
<string name="wireless_display_route_description" msgid="9070346425023979651">"បង្ហាញបណ្ដាញឥតខ្សែ"</string>
- <string name="media_route_chooser_grouping_done" msgid="7966438307723317169">"រួចរាល់"</string>
<string name="media_route_button_content_description" msgid="5758553567065145276">"លទ្ធផលមេឌៀ"</string>
+ <string name="media_route_chooser_title" msgid="1751618554539087622">"ភ្ជាប់ឧបករណ៍"</string>
+ <string name="media_route_chooser_title_for_remote_display" msgid="3395541745872017583">"ចាត់ថ្នាក់អេក្រង់ទៅឧបករណ៍"</string>
+ <string name="media_route_chooser_searching" msgid="4776236202610828706">"កំពុងស្វែងរកឧបករណ៍..."</string>
+ <string name="media_route_chooser_extended_settings" msgid="87015534236701604">"ការកំណត់"</string>
+ <string name="media_route_controller_disconnect" msgid="8966120286374158649">"ផ្ដាច់"</string>
<string name="media_route_status_scanning" msgid="7279908761758293783">"កំពុងវិភាគរក…"</string>
<string name="media_route_status_connecting" msgid="6422571716007825440">"កំពុងភ្ជាប់…"</string>
<string name="media_route_status_available" msgid="6983258067194649391">"ទំនេរ"</string>
@@ -1501,8 +1507,10 @@
<string name="display_manager_overlay_display_name" msgid="5142365982271620716">"#<xliff:g id="ID">%1$d</xliff:g> ត្រួតគ្នា"</string>
<string name="display_manager_overlay_display_title" msgid="652124517672257172">"<xliff:g id="NAME">%1$s</xliff:g>: <xliff:g id="WIDTH">%2$d</xliff:g>x<xliff:g id="HEIGHT">%3$d</xliff:g>, <xliff:g id="DPI">%4$d</xliff:g> dpi"</string>
<string name="display_manager_overlay_display_secure_suffix" msgid="6022119702628572080">", សុវត្ថិភាព"</string>
- <string name="wifi_display_notification_title" msgid="2223050649240326557">"បានភ្ជាប់ការបង្ហាញបណ្ដាញឥតខ្សែ"</string>
- <string name="wifi_display_notification_message" msgid="4498802012464170685">"អេក្រង់នេះបង្ហាញលើឧបករណ៍ផ្សេង"</string>
+ <string name="wifi_display_notification_connecting_title" msgid="2838646471050359706">"ចាត់ថ្នាក់អេក្រង់"</string>
+ <string name="wifi_display_notification_connecting_message" msgid="5837350993752841389">"កំពុងតភ្ជាប់ទៅ <xliff:g id="NAME">%1$s</xliff:g>"</string>
+ <string name="wifi_display_notification_connected_title" msgid="8567308065912676285">"ចាត់ថ្នាក់អេក្រង់"</string>
+ <string name="wifi_display_notification_connected_message" msgid="2587209325701109715">"តភ្ជាប់ទៅ <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="wifi_display_notification_disconnect" msgid="6183754463561153372">"ផ្ដាច់"</string>
<string name="kg_emergency_call_label" msgid="684946192523830531">"ការហៅពេលអាសន្ន"</string>
<string name="kg_forgot_pattern_button_text" msgid="8852021467868220608">"ភ្លេចលំនាំ"</string>
diff --git a/core/res/res/values-ko/strings.xml b/core/res/res/values-ko/strings.xml
index 2240069..d5eb619 100644
--- a/core/res/res/values-ko/strings.xml
+++ b/core/res/res/values-ko/strings.xml
@@ -382,6 +382,8 @@
<string name="permdesc_bindVpnService" msgid="2067845564581693905">"권한을 가진 프로그램이 VPN 서비스에 대한 최상위 인터페이스를 사용하도록 허용합니다. 일반 앱에는 필요하지 않습니다."</string>
<string name="permlab_bindWallpaper" msgid="8716400279937856462">"배경화면 연결"</string>
<string name="permdesc_bindWallpaper" msgid="7108428692595491668">"권한을 가진 프로그램이 배경화면에 대한 최상위 인터페이스를 사용하도록 허용합니다. 일반 앱에는 필요하지 않습니다."</string>
+ <string name="permlab_bindRemoteDisplay" msgid="1782923938029941960">"원격 디스플레이에 연결"</string>
+ <string name="permdesc_bindRemoteDisplay" msgid="1261242718727295981">"권한을 가진 프로그램이 원격 디스플레이에 대한 최상위 인터페이스를 사용하도록 허용합니다. 일반 앱에는 필요하지 않습니다."</string>
<string name="permlab_bindRemoteViews" msgid="5697987759897367099">"위젯 서비스와 연결"</string>
<string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"권한을 가진 프로그램이 위젯 서비스에 대한 최상위 인터페이스를 사용하도록 허용합니다. 일반 앱에는 필요하지 않습니다."</string>
<string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"기기 관리자와 상호 작용"</string>
@@ -1489,8 +1491,12 @@
<string name="default_audio_route_category_name" msgid="3722811174003886946">"시스템"</string>
<string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"블루투스 오디오"</string>
<string name="wireless_display_route_description" msgid="9070346425023979651">"무선 디스플레이"</string>
- <string name="media_route_chooser_grouping_done" msgid="7966438307723317169">"완료"</string>
<string name="media_route_button_content_description" msgid="5758553567065145276">"미디어 출력"</string>
+ <string name="media_route_chooser_title" msgid="1751618554539087622">"기기에 연결"</string>
+ <string name="media_route_chooser_title_for_remote_display" msgid="3395541745872017583">"기기로 화면 전송"</string>
+ <string name="media_route_chooser_searching" msgid="4776236202610828706">"기기 검색 중…"</string>
+ <string name="media_route_chooser_extended_settings" msgid="87015534236701604">"설정"</string>
+ <string name="media_route_controller_disconnect" msgid="8966120286374158649">"연결 해제"</string>
<string name="media_route_status_scanning" msgid="7279908761758293783">"검색 중..."</string>
<string name="media_route_status_connecting" msgid="6422571716007825440">"연결 중..."</string>
<string name="media_route_status_available" msgid="6983258067194649391">"사용 가능"</string>
@@ -1501,8 +1507,10 @@
<string name="display_manager_overlay_display_name" msgid="5142365982271620716">"<xliff:g id="ID">%1$d</xliff:g>번째 오버레이"</string>
<string name="display_manager_overlay_display_title" msgid="652124517672257172">"<xliff:g id="NAME">%1$s</xliff:g>: <xliff:g id="WIDTH">%2$d</xliff:g>x<xliff:g id="HEIGHT">%3$d</xliff:g>, <xliff:g id="DPI">%4$d</xliff:g> dpi"</string>
<string name="display_manager_overlay_display_secure_suffix" msgid="6022119702628572080">", 보안"</string>
- <string name="wifi_display_notification_title" msgid="2223050649240326557">"무선 디스플레이가 연결되었습니다."</string>
- <string name="wifi_display_notification_message" msgid="4498802012464170685">"이 화면은 다른 기기에서 표시되고 있습니다."</string>
+ <string name="wifi_display_notification_connecting_title" msgid="2838646471050359706">"화면 전송 중"</string>
+ <string name="wifi_display_notification_connecting_message" msgid="5837350993752841389">"<xliff:g id="NAME">%1$s</xliff:g>에 연결 중"</string>
+ <string name="wifi_display_notification_connected_title" msgid="8567308065912676285">"화면 전송 중"</string>
+ <string name="wifi_display_notification_connected_message" msgid="2587209325701109715">"<xliff:g id="NAME">%1$s</xliff:g>에 연결됨"</string>
<string name="wifi_display_notification_disconnect" msgid="6183754463561153372">"연결 해제"</string>
<string name="kg_emergency_call_label" msgid="684946192523830531">"긴급 통화"</string>
<string name="kg_forgot_pattern_button_text" msgid="8852021467868220608">"패턴을 잊음"</string>
diff --git a/core/res/res/values-lo-rLA/strings.xml b/core/res/res/values-lo-rLA/strings.xml
index b6de941..8d88dfee9f 100644
--- a/core/res/res/values-lo-rLA/strings.xml
+++ b/core/res/res/values-lo-rLA/strings.xml
@@ -382,6 +382,8 @@
<string name="permdesc_bindVpnService" msgid="2067845564581693905">"ອະນຸຍາດໃຫ້ເຈົ້າຂອງເຊື່ອມໂຍງກັບສ່ວນຕິດຕໍ່ລະດັບເທິງສຸດ ຂອງບໍລິການ VPN. ແອັບຯທົ່ວໄປບໍ່ຄວນຈຳເປັນຕ້ອງໃຊ້."</string>
<string name="permlab_bindWallpaper" msgid="8716400279937856462">"ເຊື່ອມໂຍງກັບພາບພື້ນຫຼັງ"</string>
<string name="permdesc_bindWallpaper" msgid="7108428692595491668">"ອະນຸຍາດໃຫ້ຜູ່ໃຊ້ເຊື່ອມໂຍງກັບສ່ວນຕິດຕໍ່ລະດັບສູງສຸດ ຂອງພາບພື້ນຫຼັງໃດນຶ່ງ. ແອັບຯທຳມະດາບໍ່ຄວນຈຳເປັນຕ້ອງໃຊ້."</string>
+ <string name="permlab_bindRemoteDisplay" msgid="1782923938029941960">"ຜູກກັນເພື່ອສະແດງຜົນທາງໄກ."</string>
+ <string name="permdesc_bindRemoteDisplay" msgid="1261242718727295981">"ອະນຸຍາດໃຫ້ຜູ່ຖືຜູກກັບສ່ວນຕິດຕໍ່ລະດັບສູງສຸດ ຂອງການສະແດງຜົນທາງໄກ. ບໍ່ຈຳເປັນສຳລັບແອັບຯທົ່ວໄປ."</string>
<string name="permlab_bindRemoteViews" msgid="5697987759897367099">"ເຊື່ອມໂຍງໄປຫາບໍລິການວິດເຈັດ"</string>
<string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"ອະນຸຍາດໃຫ້ຜູ່ຖືຜູກກັບອິນເຕີເຟດລະດັບສູງສຸດ ຂອງບໍລິການວິເຈັດ. ບໍ່ຈຳເປັນສຳລັບແອັບຯທົ່ວໄປ."</string>
<string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"ຕິດຕໍ່ກັບຜູ່ເບິ່ງແຍງອຸປະກອນ"</string>
@@ -1489,8 +1491,12 @@
<string name="default_audio_route_category_name" msgid="3722811174003886946">"ລະບົບ"</string>
<string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"ສຽງ Bluetooth"</string>
<string name="wireless_display_route_description" msgid="9070346425023979651">"ການສະແດງຜົນໄຮ້ສາຍ"</string>
- <string name="media_route_chooser_grouping_done" msgid="7966438307723317169">"ແລ້ວໆ"</string>
<string name="media_route_button_content_description" msgid="5758553567065145276">"ມີເດຍເອົ້າພຸດ"</string>
+ <string name="media_route_chooser_title" msgid="1751618554539087622">"ເຊື່ອມຕໍ່ຫາອຸປະກອນ"</string>
+ <string name="media_route_chooser_title_for_remote_display" msgid="3395541745872017583">"ສົ່ງພາບໜ້າຈໍໄປຫາອຸປະກອນ"</string>
+ <string name="media_route_chooser_searching" msgid="4776236202610828706">"ກຳລັງຊອກຫາອຸປະກອນ..."</string>
+ <string name="media_route_chooser_extended_settings" msgid="87015534236701604">"ການຕັ້ງຄ່າ"</string>
+ <string name="media_route_controller_disconnect" msgid="8966120286374158649">"ຕັດການເຊື່ອມຕໍ່"</string>
<string name="media_route_status_scanning" msgid="7279908761758293783">"ກຳລັງສະແກນ..."</string>
<string name="media_route_status_connecting" msgid="6422571716007825440">"ກຳລັງເຊື່ອມຕໍ່..."</string>
<string name="media_route_status_available" msgid="6983258067194649391">"ສາມາດໃຊ້ໄດ້"</string>
@@ -1501,8 +1507,10 @@
<string name="display_manager_overlay_display_name" msgid="5142365982271620716">"ການວາງຊ້ອນ #<xliff:g id="ID">%1$d</xliff:g>"</string>
<string name="display_manager_overlay_display_title" msgid="652124517672257172">"<xliff:g id="NAME">%1$s</xliff:g>: <xliff:g id="WIDTH">%2$d</xliff:g>x<xliff:g id="HEIGHT">%3$d</xliff:g>, <xliff:g id="DPI">%4$d</xliff:g> dpi"</string>
<string name="display_manager_overlay_display_secure_suffix" msgid="6022119702628572080">", ປອດໄພ"</string>
- <string name="wifi_display_notification_title" msgid="2223050649240326557">"ເຊື່ອມຕໍ່ການສະແດງຜົນໄຮ້ສາຍແລ້ວ"</string>
- <string name="wifi_display_notification_message" msgid="4498802012464170685">"ຈໍນີ້ກຳລັງສະແດງຢູ່ໃນອຸປະກອນອື່ນ"</string>
+ <string name="wifi_display_notification_connecting_title" msgid="2838646471050359706">"ກຳລັງສົ່ງພາບໜ້າຈໍ"</string>
+ <string name="wifi_display_notification_connecting_message" msgid="5837350993752841389">"ກຳລັງເຊື່ອມຕໍ່ຫາ <xliff:g id="NAME">%1$s</xliff:g>"</string>
+ <string name="wifi_display_notification_connected_title" msgid="8567308065912676285">"ການສົ່ງພາບໜ້າຈໍ"</string>
+ <string name="wifi_display_notification_connected_message" msgid="2587209325701109715">"ເຊື່ອມຕໍ່ກັບ <xliff:g id="NAME">%1$s</xliff:g> ແລ້ວ"</string>
<string name="wifi_display_notification_disconnect" msgid="6183754463561153372">"ຢຸດການເຊື່ອມຕໍ່"</string>
<string name="kg_emergency_call_label" msgid="684946192523830531">"ການໂທສຸກເສີນ"</string>
<string name="kg_forgot_pattern_button_text" msgid="8852021467868220608">"ລືມຮູບແບບປົດລັອກ?"</string>
diff --git a/core/res/res/values-lt/strings.xml b/core/res/res/values-lt/strings.xml
index c32bd9d..614bcd6 100644
--- a/core/res/res/values-lt/strings.xml
+++ b/core/res/res/values-lt/strings.xml
@@ -382,6 +382,8 @@
<string name="permdesc_bindVpnService" msgid="2067845564581693905">"Leidžiama savininkui susisaistyti su aukščiausio lygio VPN paslaugos sąsaja. Įprastoms programoms to neturėtų prireikti."</string>
<string name="permlab_bindWallpaper" msgid="8716400279937856462">"susaistyti su darbalaukio fonu"</string>
<string name="permdesc_bindWallpaper" msgid="7108428692595491668">"Leidžiama savininką susaistyti su aukščiausio lygio darbalaukio fono sąsaja. Įprastoms programoms to neturėtų prireikti."</string>
+ <string name="permlab_bindRemoteDisplay" msgid="1782923938029941960">"susisaistyti su nuotoliniu ekranu"</string>
+ <string name="permdesc_bindRemoteDisplay" msgid="1261242718727295981">"Leidžiama savininkui susisaistyti su aukščiausiojo lygio nuotolinio ekrano sąsaja. Įprastoms programoms to neturėtų prireikti."</string>
<string name="permlab_bindRemoteViews" msgid="5697987759897367099">"susaistyti su valdiklio paslauga"</string>
<string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"Leidžiama savininkui susisaistyti su aukščiausio lygio valdiklio paslaugos sąsaja. Įprastoms programoms to neturėtų prireikti."</string>
<string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"sąveikauti su įrenginio administratoriumi"</string>
@@ -1489,8 +1491,12 @@
<string name="default_audio_route_category_name" msgid="3722811174003886946">"Sistema"</string>
<string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"„Bluetooth“ garsas"</string>
<string name="wireless_display_route_description" msgid="9070346425023979651">"Belaidis rodymas"</string>
- <string name="media_route_chooser_grouping_done" msgid="7966438307723317169">"Atlikta"</string>
<string name="media_route_button_content_description" msgid="5758553567065145276">"Medijos išvestis"</string>
+ <string name="media_route_chooser_title" msgid="1751618554539087622">"Prijungimas prie įrenginio"</string>
+ <string name="media_route_chooser_title_for_remote_display" msgid="3395541745872017583">"Perduoti ekraną į įrenginį"</string>
+ <string name="media_route_chooser_searching" msgid="4776236202610828706">"Ieškoma įrenginių…"</string>
+ <string name="media_route_chooser_extended_settings" msgid="87015534236701604">"Nustatymai"</string>
+ <string name="media_route_controller_disconnect" msgid="8966120286374158649">"Atjungti"</string>
<string name="media_route_status_scanning" msgid="7279908761758293783">"Nuskaitoma..."</string>
<string name="media_route_status_connecting" msgid="6422571716007825440">"Jungiama..."</string>
<string name="media_route_status_available" msgid="6983258067194649391">"Pasiekiama"</string>
@@ -1501,8 +1507,10 @@
<string name="display_manager_overlay_display_name" msgid="5142365982271620716">"Perdanga nr. <xliff:g id="ID">%1$d</xliff:g>"</string>
<string name="display_manager_overlay_display_title" msgid="652124517672257172">"„<xliff:g id="NAME">%1$s</xliff:g>“: <xliff:g id="WIDTH">%2$d</xliff:g> x <xliff:g id="HEIGHT">%3$d</xliff:g>, <xliff:g id="DPI">%4$d</xliff:g> tašk. colyje"</string>
<string name="display_manager_overlay_display_secure_suffix" msgid="6022119702628572080">", saugu"</string>
- <string name="wifi_display_notification_title" msgid="2223050649240326557">"Prijungtas belaidis monitorius"</string>
- <string name="wifi_display_notification_message" msgid="4498802012464170685">"Šis ekranas rodomas kitame įrenginyje"</string>
+ <string name="wifi_display_notification_connecting_title" msgid="2838646471050359706">"Perduodamas ekranas"</string>
+ <string name="wifi_display_notification_connecting_message" msgid="5837350993752841389">"Prisijungiama prie „<xliff:g id="NAME">%1$s</xliff:g>“"</string>
+ <string name="wifi_display_notification_connected_title" msgid="8567308065912676285">"Perduodamas ekranas"</string>
+ <string name="wifi_display_notification_connected_message" msgid="2587209325701109715">"Prisijungta prie „<xliff:g id="NAME">%1$s</xliff:g>“"</string>
<string name="wifi_display_notification_disconnect" msgid="6183754463561153372">"Atjungti"</string>
<string name="kg_emergency_call_label" msgid="684946192523830531">"Skambutis pagalbos numeriu"</string>
<string name="kg_forgot_pattern_button_text" msgid="8852021467868220608">"Pamiršau atrakinimo piešinį"</string>
diff --git a/core/res/res/values-lv/strings.xml b/core/res/res/values-lv/strings.xml
index 66a5d73..9f3cb53 100644
--- a/core/res/res/values-lv/strings.xml
+++ b/core/res/res/values-lv/strings.xml
@@ -382,6 +382,8 @@
<string name="permdesc_bindVpnService" msgid="2067845564581693905">"Ļauj īpašniekam izveidot saiti ar VPN pakalpojuma augšējā līmeņa saskarni. Parastajām lietotnēm tas nekad nav nepieciešams."</string>
<string name="permlab_bindWallpaper" msgid="8716400279937856462">"saistīt ar tapeti"</string>
<string name="permdesc_bindWallpaper" msgid="7108428692595491668">"Ļauj īpašniekam piesaistīt tapetes augstākā līmeņa lietotāja saskarni. Parastajām lietotnēm tas nekad nav nepieciešams."</string>
+ <string name="permlab_bindRemoteDisplay" msgid="1782923938029941960">"Saites izveide ar attālu displeju"</string>
+ <string name="permdesc_bindRemoteDisplay" msgid="1261242718727295981">"Ļauj īpašniekam izveidot saiti ar attāla displeja augšējā līmeņa saskarni. Parastajām lietotnēm tas nekad nav nepieciešams."</string>
<string name="permlab_bindRemoteViews" msgid="5697987759897367099">"saistīt ar logrīka pakalpojumu"</string>
<string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"Ļauj īpašniekam izveidot saiti ar logrīka pakalpojuma augšējā līmeņa saskarni. Parastajām lietotnēm tas nekad nav nepieciešams."</string>
<string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"mijiedarboties ar ierīces administratoru"</string>
@@ -1489,8 +1491,12 @@
<string name="default_audio_route_category_name" msgid="3722811174003886946">"Sistēma"</string>
<string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Bluetooth audio"</string>
<string name="wireless_display_route_description" msgid="9070346425023979651">"Bezvadu attēlošana"</string>
- <string name="media_route_chooser_grouping_done" msgid="7966438307723317169">"Gatavs"</string>
<string name="media_route_button_content_description" msgid="5758553567065145276">"Multivides izeja"</string>
+ <string name="media_route_chooser_title" msgid="1751618554539087622">"Savienojuma izveide ar ierīci"</string>
+ <string name="media_route_chooser_title_for_remote_display" msgid="3395541745872017583">"Ekrāna apraide uz ierīci"</string>
+ <string name="media_route_chooser_searching" msgid="4776236202610828706">"Notiek ierīču meklēšana…"</string>
+ <string name="media_route_chooser_extended_settings" msgid="87015534236701604">"Iestatījumi"</string>
+ <string name="media_route_controller_disconnect" msgid="8966120286374158649">"Atvienot"</string>
<string name="media_route_status_scanning" msgid="7279908761758293783">"Notiek meklēšana..."</string>
<string name="media_route_status_connecting" msgid="6422571716007825440">"Notiek savienojuma izveide..."</string>
<string name="media_route_status_available" msgid="6983258067194649391">"Pieejams"</string>
@@ -1501,8 +1507,10 @@
<string name="display_manager_overlay_display_name" msgid="5142365982271620716">"Pārklājums Nr. <xliff:g id="ID">%1$d</xliff:g>"</string>
<string name="display_manager_overlay_display_title" msgid="652124517672257172">"<xliff:g id="NAME">%1$s</xliff:g>: <xliff:g id="WIDTH">%2$d</xliff:g> x <xliff:g id="HEIGHT">%3$d</xliff:g>, <xliff:g id="DPI">%4$d</xliff:g> dpi"</string>
<string name="display_manager_overlay_display_secure_suffix" msgid="6022119702628572080">", drošs"</string>
- <string name="wifi_display_notification_title" msgid="2223050649240326557">"Bezvadu attēlošanas savienojums ir izveidots."</string>
- <string name="wifi_display_notification_message" msgid="4498802012464170685">"Šis ekrāns tiek rādīts citā ierīcē."</string>
+ <string name="wifi_display_notification_connecting_title" msgid="2838646471050359706">"Ekrāna apraidīšana"</string>
+ <string name="wifi_display_notification_connecting_message" msgid="5837350993752841389">"Notiek savienojuma izveide ar: <xliff:g id="NAME">%1$s</xliff:g>"</string>
+ <string name="wifi_display_notification_connected_title" msgid="8567308065912676285">"Ekrāna apraidīšana"</string>
+ <string name="wifi_display_notification_connected_message" msgid="2587209325701109715">"Izveidots savienojums ar: <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="wifi_display_notification_disconnect" msgid="6183754463561153372">"Pārtraukt savienojumu"</string>
<string name="kg_emergency_call_label" msgid="684946192523830531">"Ārkārtas izsaukums"</string>
<string name="kg_forgot_pattern_button_text" msgid="8852021467868220608">"Aizmirsu kombināciju"</string>
diff --git a/core/res/res/values-mcc310-mnc260/config.xml b/core/res/res/values-mcc310-mnc260/config.xml
index 886ecbe..d602c9f 100644
--- a/core/res/res/values-mcc310-mnc260/config.xml
+++ b/core/res/res/values-mcc310-mnc260/config.xml
@@ -21,22 +21,6 @@
for different hardware and product builds. -->
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <!-- Array of ConnectivityManager.TYPE_xxxx values allowable for tethering -->
- <!-- Common options are [1, 4] for TYPE_WIFI and TYPE_MOBILE_DUN or
- <!== [0,1,5,7] for TYPE_MOBILE, TYPE_WIFI, TYPE_MOBILE_HIPRI and TYPE_BLUETOOTH -->
- <integer-array translatable="false" name="config_tether_upstream_types">
- <item>1</item>
- <item>4</item>
- <item>7</item>
- <item>9</item>
- </integer-array>
-
- <!-- String containing the apn value for tethering. May be overriden by secure settings
- TETHER_DUN_APN. Value is a comma separated series of strings:
- "name,apn,proxy,port,username,password,server,mmsc,mmsproxy,mmsport,mcc,mnc,auth,type"
- note that empty fields can be ommitted: "name,apn,,,,,,,,,310,260,,DUN" -->
- <string translatable="false" name="config_tether_apndata">T-Mobile Tethering,pcweb.tmobile.com,,,,,,,,,310,260,,DUN</string>
-
<!-- Configure mobile network MTU. Carrier specific value is set here.
-->
<integer name="config_mobile_mtu">1440</integer>
diff --git a/core/res/res/values-mn-rMN/strings.xml b/core/res/res/values-mn-rMN/strings.xml
index 6ce299d..252a959 100644
--- a/core/res/res/values-mn-rMN/strings.xml
+++ b/core/res/res/values-mn-rMN/strings.xml
@@ -382,6 +382,8 @@
<string name="permdesc_bindVpnService" msgid="2067845564581693905">"Эзэмшигч нь VPN үйлчилгээний дээд-төвшиний интерфейстэй холбох боломжтой. Энгийн апп-д шаардлагагүй."</string>
<string name="permlab_bindWallpaper" msgid="8716400279937856462">"ханын зурагтай холбох"</string>
<string name="permdesc_bindWallpaper" msgid="7108428692595491668">"Эзэмшигч нь ханын зурагны дээд-төвшиний интерфейстэй холбох боломжтой. Энгийн апп-уудад шаардлагагүй."</string>
+ <string name="permlab_bindRemoteDisplay" msgid="1782923938029941960">"алсын дэлгэцтэй холбогдох"</string>
+ <string name="permdesc_bindRemoteDisplay" msgid="1261242718727295981">"Эзэмшигчид алсын дэлгэц дэх дээд давхаргын интерфэйстэй холбогдох боломж олгоно. Энгийн апп-д шаардагдахгүй."</string>
<string name="permlab_bindRemoteViews" msgid="5697987759897367099">"виджет үйлчилгээтэй холбох"</string>
<string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"Эзэмшигч нь виджет үйлчилгээний дээд-төвшиний интерфейстэй холбох боломжтой. Энгийн апп-д шаардлагагүй."</string>
<string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"төхөөрөмжийн админтай харилцан үйлчлэх"</string>
@@ -788,7 +790,7 @@
<string name="imProtocolYahoo" msgid="8271439408469021273">"Yahoo"</string>
<string name="imProtocolSkype" msgid="9019296744622832951">"Skype"</string>
<string name="imProtocolQq" msgid="8887484379494111884">"QQ"</string>
- <string name="imProtocolGoogleTalk" msgid="493902321140277304">"Цугларалт"</string>
+ <string name="imProtocolGoogleTalk" msgid="493902321140277304">"Hangouts"</string>
<string name="imProtocolIcq" msgid="1574870433606517315">"ICQ"</string>
<string name="imProtocolJabber" msgid="2279917630875771722">"Jabber"</string>
<string name="imProtocolNetMeeting" msgid="8287625655986827971">"NetMeeting"</string>
@@ -1489,8 +1491,12 @@
<string name="default_audio_route_category_name" msgid="3722811174003886946">"Систем"</string>
<string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Блютүүт аудио"</string>
<string name="wireless_display_route_description" msgid="9070346425023979651">"Утасгүй дэлгэц"</string>
- <string name="media_route_chooser_grouping_done" msgid="7966438307723317169">"Дууссан"</string>
<string name="media_route_button_content_description" msgid="5758553567065145276">"Медиа гаралт"</string>
+ <string name="media_route_chooser_title" msgid="1751618554539087622">"Төхөөрөмжтэй холбох"</string>
+ <string name="media_route_chooser_title_for_remote_display" msgid="3395541745872017583">"Дэлгэцийг төхөөрөмж рүү дамжуулах"</string>
+ <string name="media_route_chooser_searching" msgid="4776236202610828706">"Төхөөрөмжүүдийг хайж байна…"</string>
+ <string name="media_route_chooser_extended_settings" msgid="87015534236701604">"Тохиргоо"</string>
+ <string name="media_route_controller_disconnect" msgid="8966120286374158649">"Салгах"</string>
<string name="media_route_status_scanning" msgid="7279908761758293783">"Скан хийж байна..."</string>
<string name="media_route_status_connecting" msgid="6422571716007825440">"Холбогдож байна..."</string>
<string name="media_route_status_available" msgid="6983258067194649391">"Боломжтой"</string>
@@ -1501,8 +1507,10 @@
<string name="display_manager_overlay_display_name" msgid="5142365982271620716">"Давхарга #<xliff:g id="ID">%1$d</xliff:g>"</string>
<string name="display_manager_overlay_display_title" msgid="652124517672257172">"<xliff:g id="NAME">%1$s</xliff:g>: <xliff:g id="WIDTH">%2$d</xliff:g>x<xliff:g id="HEIGHT">%3$d</xliff:g>, <xliff:g id="DPI">%4$d</xliff:g> dpi"</string>
<string name="display_manager_overlay_display_secure_suffix" msgid="6022119702628572080">", найдвартай"</string>
- <string name="wifi_display_notification_title" msgid="2223050649240326557">"Утасгүй дэлгэц холбогдов"</string>
- <string name="wifi_display_notification_message" msgid="4498802012464170685">"Энэ дэлгэц өөр төхөөрөмжийг харуулж байна"</string>
+ <string name="wifi_display_notification_connecting_title" msgid="2838646471050359706">"Дэлгэцийг дамжуулж байна"</string>
+ <string name="wifi_display_notification_connecting_message" msgid="5837350993752841389">"<xliff:g id="NAME">%1$s</xliff:g> руу холбогдож байна"</string>
+ <string name="wifi_display_notification_connected_title" msgid="8567308065912676285">"Дэлгэцийг дамжуулж байна"</string>
+ <string name="wifi_display_notification_connected_message" msgid="2587209325701109715">"<xliff:g id="NAME">%1$s</xliff:g> руу холбогдсон"</string>
<string name="wifi_display_notification_disconnect" msgid="6183754463561153372">"Салгах"</string>
<string name="kg_emergency_call_label" msgid="684946192523830531">"Яаралтай дуудлага"</string>
<string name="kg_forgot_pattern_button_text" msgid="8852021467868220608">"Хээг мартсан"</string>
diff --git a/core/res/res/values-ms-rMY/strings.xml b/core/res/res/values-ms-rMY/strings.xml
index 8203921..284837a 100644
--- a/core/res/res/values-ms-rMY/strings.xml
+++ b/core/res/res/values-ms-rMY/strings.xml
@@ -382,6 +382,8 @@
<string name="permdesc_bindVpnService" msgid="2067845564581693905">"Membenarkan pemegang terikat dengan antara muka peringkat tertinggi bagi perkhidmatan Vpn. Tidak sekali-kali diperlukan untuk apl biasa."</string>
<string name="permlab_bindWallpaper" msgid="8716400279937856462">"terikat pada kertas dinding"</string>
<string name="permdesc_bindWallpaper" msgid="7108428692595491668">"Membenarkan pemegang terikat dengan antara muka peringkat tertinggi bagi kertas dinding. Tidak sekali-kali diperlukan untuk apl biasa."</string>
+ <string name="permlab_bindRemoteDisplay" msgid="1782923938029941960">"terikat kepada paparan jauh"</string>
+ <string name="permdesc_bindRemoteDisplay" msgid="1261242718727295981">"Membenarkan pemegang terikat dengan antara muka peringkat tertinggi bagi paparan jauh. Tidak sekali-kali diperlukan untuk apl biasa."</string>
<string name="permlab_bindRemoteViews" msgid="5697987759897367099">"terikat kepada perkhidmatan widget"</string>
<string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"Membenarkan pemegang terikat dengan antara muka peringkat tertinggi bagi perkhidmatan widget. Tidak sekali-kali diperlukan untuk apl biasa."</string>
<string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"berinteraksi dengan pentadbir peranti"</string>
@@ -1489,8 +1491,12 @@
<string name="default_audio_route_category_name" msgid="3722811174003886946">"Sistem"</string>
<string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Audio Bluetooth"</string>
<string name="wireless_display_route_description" msgid="9070346425023979651">"Paparan wayarles"</string>
- <string name="media_route_chooser_grouping_done" msgid="7966438307723317169">"Selesai"</string>
<string name="media_route_button_content_description" msgid="5758553567065145276">"Output media"</string>
+ <string name="media_route_chooser_title" msgid="1751618554539087622">"Sambung ke peranti"</string>
+ <string name="media_route_chooser_title_for_remote_display" msgid="3395541745872017583">"Hantar skrin ke peranti"</string>
+ <string name="media_route_chooser_searching" msgid="4776236202610828706">"Mencari peranti..."</string>
+ <string name="media_route_chooser_extended_settings" msgid="87015534236701604">"Tetapan"</string>
+ <string name="media_route_controller_disconnect" msgid="8966120286374158649">"Putuskan sambungan"</string>
<string name="media_route_status_scanning" msgid="7279908761758293783">"Mengimbas…"</string>
<string name="media_route_status_connecting" msgid="6422571716007825440">"Menyambung..."</string>
<string name="media_route_status_available" msgid="6983258067194649391">"Tersedia"</string>
@@ -1501,8 +1507,10 @@
<string name="display_manager_overlay_display_name" msgid="5142365982271620716">"Tindih #<xliff:g id="ID">%1$d</xliff:g>"</string>
<string name="display_manager_overlay_display_title" msgid="652124517672257172">"<xliff:g id="NAME">%1$s</xliff:g>: <xliff:g id="WIDTH">%2$d</xliff:g>x<xliff:g id="HEIGHT">%3$d</xliff:g>, <xliff:g id="DPI">%4$d</xliff:g> dpi"</string>
<string name="display_manager_overlay_display_secure_suffix" msgid="6022119702628572080">", selamat"</string>
- <string name="wifi_display_notification_title" msgid="2223050649240326557">"Paparan wayarles disambungkan"</string>
- <string name="wifi_display_notification_message" msgid="4498802012464170685">"Skrin ini ditunjukkan pada peranti lain"</string>
+ <string name="wifi_display_notification_connecting_title" msgid="2838646471050359706">"Menghantar skrin"</string>
+ <string name="wifi_display_notification_connecting_message" msgid="5837350993752841389">"Menyambung ke <xliff:g id="NAME">%1$s</xliff:g>"</string>
+ <string name="wifi_display_notification_connected_title" msgid="8567308065912676285">"Menghantar skrin"</string>
+ <string name="wifi_display_notification_connected_message" msgid="2587209325701109715">"Disambungkan ke <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="wifi_display_notification_disconnect" msgid="6183754463561153372">"Putus sambungan"</string>
<string name="kg_emergency_call_label" msgid="684946192523830531">"Panggilan kecemasan"</string>
<string name="kg_forgot_pattern_button_text" msgid="8852021467868220608">"Lupa Corak"</string>
diff --git a/core/res/res/values-nb/strings.xml b/core/res/res/values-nb/strings.xml
index 8aed6f1..7b77a1c 100644
--- a/core/res/res/values-nb/strings.xml
+++ b/core/res/res/values-nb/strings.xml
@@ -382,6 +382,8 @@
<string name="permdesc_bindVpnService" msgid="2067845564581693905">"Lar innehaveren binde seg til det øverste nivået av grensesnittet for en VPN-tjeneste. Skal aldri være nødvendig for vanlige apper."</string>
<string name="permlab_bindWallpaper" msgid="8716400279937856462">"binde til bakgrunnsbilde"</string>
<string name="permdesc_bindWallpaper" msgid="7108428692595491668">"Lar innehaveren binde det øverste nivået av grensesnittet til en bakgrunn. Skal aldri være nødvendig for vanlige apper."</string>
+ <string name="permlab_bindRemoteDisplay" msgid="1782923938029941960">"binde til ekstern skjerm"</string>
+ <string name="permdesc_bindRemoteDisplay" msgid="1261242718727295981">"Lar innehaveren binde seg til det øverste grensesnittnivået for ekstern skjerm. Skal aldri være nødvendig for vanlige apper."</string>
<string name="permlab_bindRemoteViews" msgid="5697987759897367099">"binde til modultjenste"</string>
<string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"Lar innehaveren binde seg til det øverste nivået av grensesnittet for en modultjeneste. Skal aldri være nødvendig for vanlige apper."</string>
<string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"kommunisere med enhetsadministrator"</string>
@@ -1489,8 +1491,12 @@
<string name="default_audio_route_category_name" msgid="3722811174003886946">"System"</string>
<string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Bluetooth-lyd"</string>
<string name="wireless_display_route_description" msgid="9070346425023979651">"Trådløs skjerm"</string>
- <string name="media_route_chooser_grouping_done" msgid="7966438307723317169">"Fullført"</string>
<string name="media_route_button_content_description" msgid="5758553567065145276">"Medieutgang"</string>
+ <string name="media_route_chooser_title" msgid="1751618554539087622">"Koble til enheten"</string>
+ <string name="media_route_chooser_title_for_remote_display" msgid="3395541745872017583">"Send skjermen til enheten"</string>
+ <string name="media_route_chooser_searching" msgid="4776236202610828706">"Søker etter enheter …"</string>
+ <string name="media_route_chooser_extended_settings" msgid="87015534236701604">"Innstillinger"</string>
+ <string name="media_route_controller_disconnect" msgid="8966120286374158649">"Koble fra"</string>
<string name="media_route_status_scanning" msgid="7279908761758293783">"Skanner ..."</string>
<string name="media_route_status_connecting" msgid="6422571716007825440">"Kobler til ..."</string>
<string name="media_route_status_available" msgid="6983258067194649391">"Tilgjengelig"</string>
@@ -1501,8 +1507,10 @@
<string name="display_manager_overlay_display_name" msgid="5142365982271620716">"Overlegg #<xliff:g id="ID">%1$d</xliff:g>"</string>
<string name="display_manager_overlay_display_title" msgid="652124517672257172">"<xliff:g id="NAME">%1$s</xliff:g>: <xliff:g id="WIDTH">%2$d</xliff:g> x <xliff:g id="HEIGHT">%3$d</xliff:g>, <xliff:g id="DPI">%4$d</xliff:g> dpi"</string>
<string name="display_manager_overlay_display_secure_suffix" msgid="6022119702628572080">", sikker"</string>
- <string name="wifi_display_notification_title" msgid="2223050649240326557">"Trådløs skjermdeling er tilkoblet"</string>
- <string name="wifi_display_notification_message" msgid="4498802012464170685">"Denne skjermen vises på en annen enhet"</string>
+ <string name="wifi_display_notification_connecting_title" msgid="2838646471050359706">"Sender skjermen …"</string>
+ <string name="wifi_display_notification_connecting_message" msgid="5837350993752841389">"Kobler til <xliff:g id="NAME">%1$s</xliff:g>"</string>
+ <string name="wifi_display_notification_connected_title" msgid="8567308065912676285">"Sender skjermen …"</string>
+ <string name="wifi_display_notification_connected_message" msgid="2587209325701109715">"Koblet til <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="wifi_display_notification_disconnect" msgid="6183754463561153372">"Koble fra"</string>
<string name="kg_emergency_call_label" msgid="684946192523830531">"Nødnummer"</string>
<string name="kg_forgot_pattern_button_text" msgid="8852021467868220608">"Har du glemt mønsteret?"</string>
diff --git a/core/res/res/values-nl/strings.xml b/core/res/res/values-nl/strings.xml
index 5838aef..ba221cc 100644
--- a/core/res/res/values-nl/strings.xml
+++ b/core/res/res/values-nl/strings.xml
@@ -382,6 +382,8 @@
<string name="permdesc_bindVpnService" msgid="2067845564581693905">"Staat de houder toe verbinding te maken met de hoofdinterface van een VPN-service. Nooit vereist voor normale apps."</string>
<string name="permlab_bindWallpaper" msgid="8716400279937856462">"verbinden met een achtergrond"</string>
<string name="permdesc_bindWallpaper" msgid="7108428692595491668">"Hiermee wordt de houder toegestaan zich te verbinden met de hoofdinterface van een achtergrond. Nooit vereist voor normale apps."</string>
+ <string name="permlab_bindRemoteDisplay" msgid="1782923938029941960">"verbinding maken met een extern display"</string>
+ <string name="permdesc_bindRemoteDisplay" msgid="1261242718727295981">"Hiermee wordt de houder toegestaan verbinding te maken met de hoofdinterface van een extern display. Nooit vereist voor normale apps."</string>
<string name="permlab_bindRemoteViews" msgid="5697987759897367099">"verbinden met een widgetservice"</string>
<string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"Hiermee wordt de houder toegestaan verbinding te maken met de hoofdinterface van een widgetservice. Nooit vereist voor normale apps."</string>
<string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"interactie met apparaatbeheer"</string>
@@ -1489,8 +1491,12 @@
<string name="default_audio_route_category_name" msgid="3722811174003886946">"Systeem"</string>
<string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Bluetooth-audio"</string>
<string name="wireless_display_route_description" msgid="9070346425023979651">"Draadloze weergave"</string>
- <string name="media_route_chooser_grouping_done" msgid="7966438307723317169">"Gereed"</string>
<string name="media_route_button_content_description" msgid="5758553567065145276">"Media-uitvoer"</string>
+ <string name="media_route_chooser_title" msgid="1751618554539087622">"Verbinding maken met apparaat"</string>
+ <string name="media_route_chooser_title_for_remote_display" msgid="3395541745872017583">"Scherm sturen naar apparaat"</string>
+ <string name="media_route_chooser_searching" msgid="4776236202610828706">"Zoeken naar apparaten…"</string>
+ <string name="media_route_chooser_extended_settings" msgid="87015534236701604">"Instellingen"</string>
+ <string name="media_route_controller_disconnect" msgid="8966120286374158649">"Verbinding verbreken"</string>
<string name="media_route_status_scanning" msgid="7279908761758293783">"Scannen..."</string>
<string name="media_route_status_connecting" msgid="6422571716007825440">"Verbinden..."</string>
<string name="media_route_status_available" msgid="6983258067194649391">"Beschikbaar"</string>
@@ -1501,8 +1507,10 @@
<string name="display_manager_overlay_display_name" msgid="5142365982271620716">"Overlay <xliff:g id="ID">%1$d</xliff:g>"</string>
<string name="display_manager_overlay_display_title" msgid="652124517672257172">"<xliff:g id="NAME">%1$s</xliff:g>: <xliff:g id="WIDTH">%2$d</xliff:g>x<xliff:g id="HEIGHT">%3$d</xliff:g>, <xliff:g id="DPI">%4$d</xliff:g> dpi"</string>
<string name="display_manager_overlay_display_secure_suffix" msgid="6022119702628572080">", beveiligd"</string>
- <string name="wifi_display_notification_title" msgid="2223050649240326557">"Draadloze weergave is aangesloten"</string>
- <string name="wifi_display_notification_message" msgid="4498802012464170685">"Dit scherm wordt op een ander apparaat weergegeven"</string>
+ <string name="wifi_display_notification_connecting_title" msgid="2838646471050359706">"Scherm sturen"</string>
+ <string name="wifi_display_notification_connecting_message" msgid="5837350993752841389">"Verbinden met <xliff:g id="NAME">%1$s</xliff:g>"</string>
+ <string name="wifi_display_notification_connected_title" msgid="8567308065912676285">"Scherm sturen"</string>
+ <string name="wifi_display_notification_connected_message" msgid="2587209325701109715">"Verbonden met <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="wifi_display_notification_disconnect" msgid="6183754463561153372">"Verbinding verbreken"</string>
<string name="kg_emergency_call_label" msgid="684946192523830531">"Noodoproep"</string>
<string name="kg_forgot_pattern_button_text" msgid="8852021467868220608">"Patroon vergeten"</string>
diff --git a/core/res/res/values-pl/strings.xml b/core/res/res/values-pl/strings.xml
index 847f9cc..217d2c9 100644
--- a/core/res/res/values-pl/strings.xml
+++ b/core/res/res/values-pl/strings.xml
@@ -382,6 +382,8 @@
<string name="permdesc_bindVpnService" msgid="2067845564581693905">"Pozwala na tworzenie powiązania z interfejsem najwyższego poziomu usługi VPN. Nie powinno być nigdy potrzebne w przypadku zwykłych aplikacji."</string>
<string name="permlab_bindWallpaper" msgid="8716400279937856462">"powiązanie z tapetą"</string>
<string name="permdesc_bindWallpaper" msgid="7108428692595491668">"Pozwala na tworzenie powiązania z interfejsem najwyższego poziomu tapety. Nieprzeznaczone dla zwykłych aplikacji."</string>
+ <string name="permlab_bindRemoteDisplay" msgid="1782923938029941960">"powiązanie z wyświetlaczem zdalnym"</string>
+ <string name="permdesc_bindRemoteDisplay" msgid="1261242718727295981">"Zezwala na tworzenie powiązania z interfejsem najwyższego poziomu wyświetlacza zdalnego. Nieprzeznaczone dla zwykłych aplikacji."</string>
<string name="permlab_bindRemoteViews" msgid="5697987759897367099">"powiązanie z usługą widżetów"</string>
<string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"Zezwala na tworzenie powiązania z interfejsem najwyższego poziomu usługi widżetów. Nie powinno być nigdy potrzebne w przypadku zwykłych aplikacji."</string>
<string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"interakcja z administratorem urządzenia"</string>
@@ -1489,8 +1491,12 @@
<string name="default_audio_route_category_name" msgid="3722811174003886946">"System"</string>
<string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Dźwięk Bluetooth"</string>
<string name="wireless_display_route_description" msgid="9070346425023979651">"Wyświetlacz bezprzewodowy"</string>
- <string name="media_route_chooser_grouping_done" msgid="7966438307723317169">"Gotowe"</string>
<string name="media_route_button_content_description" msgid="5758553567065145276">"Wyjście multimediów"</string>
+ <string name="media_route_chooser_title" msgid="1751618554539087622">"Połącz z urządzeniem"</string>
+ <string name="media_route_chooser_title_for_remote_display" msgid="3395541745872017583">"Prezentuj ekran na urządzeniu"</string>
+ <string name="media_route_chooser_searching" msgid="4776236202610828706">"Szukam urządzeń…"</string>
+ <string name="media_route_chooser_extended_settings" msgid="87015534236701604">"Ustawienia"</string>
+ <string name="media_route_controller_disconnect" msgid="8966120286374158649">"Rozłącz"</string>
<string name="media_route_status_scanning" msgid="7279908761758293783">"Skanuję..."</string>
<string name="media_route_status_connecting" msgid="6422571716007825440">"Łączę..."</string>
<string name="media_route_status_available" msgid="6983258067194649391">"Dostępne"</string>
@@ -1501,8 +1507,10 @@
<string name="display_manager_overlay_display_name" msgid="5142365982271620716">"Nakładka nr <xliff:g id="ID">%1$d</xliff:g>"</string>
<string name="display_manager_overlay_display_title" msgid="652124517672257172">"<xliff:g id="NAME">%1$s</xliff:g>: <xliff:g id="WIDTH">%2$d</xliff:g> x <xliff:g id="HEIGHT">%3$d</xliff:g>, <xliff:g id="DPI">%4$d</xliff:g> dpi"</string>
<string name="display_manager_overlay_display_secure_suffix" msgid="6022119702628572080">", bezpieczny"</string>
- <string name="wifi_display_notification_title" msgid="2223050649240326557">"Podłączony jest wyświetlacz bezprzewodowy"</string>
- <string name="wifi_display_notification_message" msgid="4498802012464170685">"Ten ekran jest wyświetlany na innym urządzeniu"</string>
+ <string name="wifi_display_notification_connecting_title" msgid="2838646471050359706">"Rozpoczynam prezentowanie ekranu"</string>
+ <string name="wifi_display_notification_connecting_message" msgid="5837350993752841389">"Łączę z <xliff:g id="NAME">%1$s</xliff:g>"</string>
+ <string name="wifi_display_notification_connected_title" msgid="8567308065912676285">"Trwa prezentowanie ekranu"</string>
+ <string name="wifi_display_notification_connected_message" msgid="2587209325701109715">"Połączono z <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="wifi_display_notification_disconnect" msgid="6183754463561153372">"Rozłącz"</string>
<string name="kg_emergency_call_label" msgid="684946192523830531">"Połączenie alarmowe"</string>
<string name="kg_forgot_pattern_button_text" msgid="8852021467868220608">"Nie pamiętam wzoru"</string>
diff --git a/core/res/res/values-pt-rPT/strings.xml b/core/res/res/values-pt-rPT/strings.xml
index 2aa5e9a..2d69f9c 100644
--- a/core/res/res/values-pt-rPT/strings.xml
+++ b/core/res/res/values-pt-rPT/strings.xml
@@ -382,6 +382,8 @@
<string name="permdesc_bindVpnService" msgid="2067845564581693905">"Permite que o titular se vincule à interface de nível superior de um serviço de VPN. Nunca deverá ser necessário para aplicações normais."</string>
<string name="permlab_bindWallpaper" msgid="8716400279937856462">"vincular a uma imagem de fundo"</string>
<string name="permdesc_bindWallpaper" msgid="7108428692595491668">"Permite ao titular vincular-se à interface de nível superior de uma imagem de fundo. Nunca deverá ser necessário para aplicações normais."</string>
+ <string name="permlab_bindRemoteDisplay" msgid="1782923938029941960">"associar a um ecrã remoto"</string>
+ <string name="permdesc_bindRemoteDisplay" msgid="1261242718727295981">"Permite ao detentor associar a interface de nível superior a um ecrã remoto. Nunca deve ser necessário para aplicações normais."</string>
<string name="permlab_bindRemoteViews" msgid="5697987759897367099">"vincular a um serviço de widget"</string>
<string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"Permite que o titular vincule a interface de nível superior de um serviço de widget. Nunca deverá ser necessário para aplicações normais."</string>
<string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"interagir com um administrador do dispositivo"</string>
@@ -1489,8 +1491,12 @@
<string name="default_audio_route_category_name" msgid="3722811174003886946">"Sistema"</string>
<string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Áudio Bluetooth"</string>
<string name="wireless_display_route_description" msgid="9070346425023979651">"Visualização sem fios"</string>
- <string name="media_route_chooser_grouping_done" msgid="7966438307723317169">"Concluído"</string>
<string name="media_route_button_content_description" msgid="5758553567065145276">"Saída de som multimédia"</string>
+ <string name="media_route_chooser_title" msgid="1751618554539087622">"Ligar ao dispositivo"</string>
+ <string name="media_route_chooser_title_for_remote_display" msgid="3395541745872017583">"Transmitir ecrã para o dispositivo"</string>
+ <string name="media_route_chooser_searching" msgid="4776236202610828706">"A pesquisar dispositivos…"</string>
+ <string name="media_route_chooser_extended_settings" msgid="87015534236701604">"Definições"</string>
+ <string name="media_route_controller_disconnect" msgid="8966120286374158649">"Desligar"</string>
<string name="media_route_status_scanning" msgid="7279908761758293783">"A procurar..."</string>
<string name="media_route_status_connecting" msgid="6422571716007825440">"A ligar..."</string>
<string name="media_route_status_available" msgid="6983258067194649391">"Disponível"</string>
@@ -1501,8 +1507,10 @@
<string name="display_manager_overlay_display_name" msgid="5142365982271620716">"Sobreposição #<xliff:g id="ID">%1$d</xliff:g>"</string>
<string name="display_manager_overlay_display_title" msgid="652124517672257172">"<xliff:g id="NAME">%1$s</xliff:g>: <xliff:g id="WIDTH">%2$d</xliff:g>x<xliff:g id="HEIGHT">%3$d</xliff:g>, <xliff:g id="DPI">%4$d</xliff:g> ppp"</string>
<string name="display_manager_overlay_display_secure_suffix" msgid="6022119702628572080">", protegido"</string>
- <string name="wifi_display_notification_title" msgid="2223050649240326557">"O Display sem fios está ligado"</string>
- <string name="wifi_display_notification_message" msgid="4498802012464170685">"Este ecrã está a ser apresentado noutro dispositivo"</string>
+ <string name="wifi_display_notification_connecting_title" msgid="2838646471050359706">"A transmitir o ecrã"</string>
+ <string name="wifi_display_notification_connecting_message" msgid="5837350993752841389">"A ligar a <xliff:g id="NAME">%1$s</xliff:g>"</string>
+ <string name="wifi_display_notification_connected_title" msgid="8567308065912676285">"A transmitir o ecrã"</string>
+ <string name="wifi_display_notification_connected_message" msgid="2587209325701109715">"Ligado a <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="wifi_display_notification_disconnect" msgid="6183754463561153372">"Desligar"</string>
<string name="kg_emergency_call_label" msgid="684946192523830531">"Chamada de emergência"</string>
<string name="kg_forgot_pattern_button_text" msgid="8852021467868220608">"Esqueceu-se da Sequência"</string>
diff --git a/core/res/res/values-pt/strings.xml b/core/res/res/values-pt/strings.xml
index b13044f..f1ad4d7 100644
--- a/core/res/res/values-pt/strings.xml
+++ b/core/res/res/values-pt/strings.xml
@@ -382,6 +382,8 @@
<string name="permdesc_bindVpnService" msgid="2067845564581693905">"Permite que seu proprietário sujeite a interface de alto nível de um serviço de VPN. Nunca deve ser necessário para aplicativos normais."</string>
<string name="permlab_bindWallpaper" msgid="8716400279937856462">"sujeitar-se a um plano de fundo"</string>
<string name="permdesc_bindWallpaper" msgid="7108428692595491668">"Permite que o proprietário utilize interface de nível superior de um plano de fundo. Nunca deve ser necessário para aplicativos normais."</string>
+ <string name="permlab_bindRemoteDisplay" msgid="1782923938029941960">"usar uma tela remota"</string>
+ <string name="permdesc_bindRemoteDisplay" msgid="1261242718727295981">"Permite que o proprietário use a interface de nível superior de uma tela remota. Não deve ser necessário para aplicativos comuns."</string>
<string name="permlab_bindRemoteViews" msgid="5697987759897367099">"sujeitar-se a um serviço de widget"</string>
<string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"Permite que o proprietário utilize a interface de nível superior de um serviço de widget. Nunca deve ser necessário para aplicativos normais."</string>
<string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"interagir com o administrador de um dispositivo"</string>
@@ -1489,8 +1491,12 @@
<string name="default_audio_route_category_name" msgid="3722811174003886946">"Sistema"</string>
<string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Áudio Bluetooth"</string>
<string name="wireless_display_route_description" msgid="9070346425023979651">"Display sem fio"</string>
- <string name="media_route_chooser_grouping_done" msgid="7966438307723317169">"Concluído"</string>
<string name="media_route_button_content_description" msgid="5758553567065145276">"Saída de mídia"</string>
+ <string name="media_route_chooser_title" msgid="1751618554539087622">"Conectar ao dispositivo"</string>
+ <string name="media_route_chooser_title_for_remote_display" msgid="3395541745872017583">"Transmitir tela para dispositivo"</string>
+ <string name="media_route_chooser_searching" msgid="4776236202610828706">"Procurando dispositivos…"</string>
+ <string name="media_route_chooser_extended_settings" msgid="87015534236701604">"Configurações"</string>
+ <string name="media_route_controller_disconnect" msgid="8966120286374158649">"Desconectar"</string>
<string name="media_route_status_scanning" msgid="7279908761758293783">"Verificando..."</string>
<string name="media_route_status_connecting" msgid="6422571716007825440">"Conectando..."</string>
<string name="media_route_status_available" msgid="6983258067194649391">"Disponível"</string>
@@ -1501,8 +1507,10 @@
<string name="display_manager_overlay_display_name" msgid="5142365982271620716">"Sobreposição nº <xliff:g id="ID">%1$d</xliff:g>"</string>
<string name="display_manager_overlay_display_title" msgid="652124517672257172">"<xliff:g id="NAME">%1$s</xliff:g>: <xliff:g id="WIDTH">%2$d</xliff:g>x<xliff:g id="HEIGHT">%3$d</xliff:g>, <xliff:g id="DPI">%4$d</xliff:g> dpi"</string>
<string name="display_manager_overlay_display_secure_suffix" msgid="6022119702628572080">", seguro"</string>
- <string name="wifi_display_notification_title" msgid="2223050649240326557">"O Display sem fio está conectado"</string>
- <string name="wifi_display_notification_message" msgid="4498802012464170685">"Tela exibida em outro dispositivo."</string>
+ <string name="wifi_display_notification_connecting_title" msgid="2838646471050359706">"Transmitindo a tela"</string>
+ <string name="wifi_display_notification_connecting_message" msgid="5837350993752841389">"Conectando a <xliff:g id="NAME">%1$s</xliff:g>"</string>
+ <string name="wifi_display_notification_connected_title" msgid="8567308065912676285">"Transmitindo a tela"</string>
+ <string name="wifi_display_notification_connected_message" msgid="2587209325701109715">"Conectado a <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="wifi_display_notification_disconnect" msgid="6183754463561153372">"Desconectar"</string>
<string name="kg_emergency_call_label" msgid="684946192523830531">"Chamada de emergência"</string>
<string name="kg_forgot_pattern_button_text" msgid="8852021467868220608">"Esqueci o padrão"</string>
diff --git a/core/res/res/values-rm/strings.xml b/core/res/res/values-rm/strings.xml
index 5c56441..6ea1e9e 100644
--- a/core/res/res/values-rm/strings.xml
+++ b/core/res/res/values-rm/strings.xml
@@ -598,6 +598,10 @@
<string name="permlab_bindWallpaper" msgid="8716400279937856462">"sa fixar vid in fund davos"</string>
<!-- no translation found for permdesc_bindWallpaper (7108428692595491668) -->
<skip />
+ <!-- no translation found for permlab_bindRemoteDisplay (1782923938029941960) -->
+ <skip />
+ <!-- no translation found for permdesc_bindRemoteDisplay (1261242718727295981) -->
+ <skip />
<!-- no translation found for permlab_bindRemoteViews (5697987759897367099) -->
<skip />
<!-- no translation found for permdesc_bindRemoteViews (4717987810137692572) -->
@@ -2411,10 +2415,18 @@
<skip />
<!-- no translation found for wireless_display_route_description (9070346425023979651) -->
<skip />
- <!-- no translation found for media_route_chooser_grouping_done (7966438307723317169) -->
- <skip />
<!-- no translation found for media_route_button_content_description (5758553567065145276) -->
<skip />
+ <!-- no translation found for media_route_chooser_title (1751618554539087622) -->
+ <skip />
+ <!-- no translation found for media_route_chooser_title_for_remote_display (3395541745872017583) -->
+ <skip />
+ <!-- no translation found for media_route_chooser_searching (4776236202610828706) -->
+ <skip />
+ <!-- no translation found for media_route_chooser_extended_settings (87015534236701604) -->
+ <skip />
+ <!-- no translation found for media_route_controller_disconnect (8966120286374158649) -->
+ <skip />
<!-- no translation found for media_route_status_scanning (7279908761758293783) -->
<skip />
<!-- no translation found for media_route_status_connecting (6422571716007825440) -->
@@ -2435,9 +2447,13 @@
<skip />
<!-- no translation found for display_manager_overlay_display_secure_suffix (6022119702628572080) -->
<skip />
- <!-- no translation found for wifi_display_notification_title (2223050649240326557) -->
+ <!-- no translation found for wifi_display_notification_connecting_title (2838646471050359706) -->
<skip />
- <!-- no translation found for wifi_display_notification_message (4498802012464170685) -->
+ <!-- no translation found for wifi_display_notification_connecting_message (5837350993752841389) -->
+ <skip />
+ <!-- no translation found for wifi_display_notification_connected_title (8567308065912676285) -->
+ <skip />
+ <!-- no translation found for wifi_display_notification_connected_message (2587209325701109715) -->
<skip />
<!-- no translation found for wifi_display_notification_disconnect (6183754463561153372) -->
<skip />
diff --git a/core/res/res/values-ro/strings.xml b/core/res/res/values-ro/strings.xml
index f29a7e6..c3f9157 100644
--- a/core/res/res/values-ro/strings.xml
+++ b/core/res/res/values-ro/strings.xml
@@ -382,6 +382,8 @@
<string name="permdesc_bindVpnService" msgid="2067845564581693905">"Permite proprietarului să se conecteze la interfaţa de nivel superior a unui serviciu VPN. Nu ar trebui să fie niciodată necesară pentru aplicaţiile obişnuite."</string>
<string name="permlab_bindWallpaper" msgid="8716400279937856462">"conectare la o imagine de fundal"</string>
<string name="permdesc_bindWallpaper" msgid="7108428692595491668">"Permite proprietarului să se conecteze la interfaţa de nivel superior a unei imagini de fundal. Nu ar trebui să fie niciodată necesară pentru aplicaţiile obişnuite."</string>
+ <string name="permlab_bindRemoteDisplay" msgid="1782923938029941960">"conectare la un ecran la distanță"</string>
+ <string name="permdesc_bindRemoteDisplay" msgid="1261242718727295981">"Permite proprietarului să se conecteze la interfața de nivel superior a unui ecran la distanță. Nu ar trebui să fie niciodată necesară pentru aplicațiile obișnuite."</string>
<string name="permlab_bindRemoteViews" msgid="5697987759897367099">"conectare la un serviciu widget"</string>
<string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"Permite proprietarului să se conecteze la interfaţa de nivel superior a unui serviciu widget. Nu ar trebui să fie niciodată necesară pentru aplicaţiile obişnuite."</string>
<string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"interacţionare cu administratorul unui dispozitiv"</string>
@@ -1489,8 +1491,12 @@
<string name="default_audio_route_category_name" msgid="3722811174003886946">"Sistem"</string>
<string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Audio Bluetooth"</string>
<string name="wireless_display_route_description" msgid="9070346425023979651">"Ecran wireless"</string>
- <string name="media_route_chooser_grouping_done" msgid="7966438307723317169">"Terminat"</string>
<string name="media_route_button_content_description" msgid="5758553567065145276">"Rezultate media"</string>
+ <string name="media_route_chooser_title" msgid="1751618554539087622">"Conectați-vă la dispozitiv"</string>
+ <string name="media_route_chooser_title_for_remote_display" msgid="3395541745872017583">"Trimiteți ecranul pe dispozitiv"</string>
+ <string name="media_route_chooser_searching" msgid="4776236202610828706">"Se caută dispozitive..."</string>
+ <string name="media_route_chooser_extended_settings" msgid="87015534236701604">"Setări"</string>
+ <string name="media_route_controller_disconnect" msgid="8966120286374158649">"Deconectați-vă"</string>
<string name="media_route_status_scanning" msgid="7279908761758293783">"Se scanează..."</string>
<string name="media_route_status_connecting" msgid="6422571716007825440">"Se conectează..."</string>
<string name="media_route_status_available" msgid="6983258067194649391">"Disponibilă"</string>
@@ -1501,8 +1507,10 @@
<string name="display_manager_overlay_display_name" msgid="5142365982271620716">"Suprapunerea <xliff:g id="ID">%1$d</xliff:g>"</string>
<string name="display_manager_overlay_display_title" msgid="652124517672257172">"<xliff:g id="NAME">%1$s</xliff:g>: <xliff:g id="WIDTH">%2$d</xliff:g>x<xliff:g id="HEIGHT">%3$d</xliff:g>, <xliff:g id="DPI">%4$d</xliff:g> dpi"</string>
<string name="display_manager_overlay_display_secure_suffix" msgid="6022119702628572080">", securizat"</string>
- <string name="wifi_display_notification_title" msgid="2223050649240326557">"Ecranul wireless este conectat"</string>
- <string name="wifi_display_notification_message" msgid="4498802012464170685">"Acest ecran este afişat pe alt gadget"</string>
+ <string name="wifi_display_notification_connecting_title" msgid="2838646471050359706">"Se trimite ecranul"</string>
+ <string name="wifi_display_notification_connecting_message" msgid="5837350993752841389">"Se conectează la <xliff:g id="NAME">%1$s</xliff:g>"</string>
+ <string name="wifi_display_notification_connected_title" msgid="8567308065912676285">"Se trimite ecranul"</string>
+ <string name="wifi_display_notification_connected_message" msgid="2587209325701109715">"Conectat la <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="wifi_display_notification_disconnect" msgid="6183754463561153372">"Deconectaţi-vă"</string>
<string name="kg_emergency_call_label" msgid="684946192523830531">"Apel de urgenţă"</string>
<string name="kg_forgot_pattern_button_text" msgid="8852021467868220608">"Model uitat"</string>
diff --git a/core/res/res/values-ru/strings.xml b/core/res/res/values-ru/strings.xml
index 44db6b6..13f18c3 100644
--- a/core/res/res/values-ru/strings.xml
+++ b/core/res/res/values-ru/strings.xml
@@ -382,6 +382,8 @@
<string name="permdesc_bindVpnService" msgid="2067845564581693905">"Приложение сможет подключаться к базовому интерфейсу службы VPN. Это разрешение не используется обычными приложениями."</string>
<string name="permlab_bindWallpaper" msgid="8716400279937856462">"Привязка к фоновому рисунку"</string>
<string name="permdesc_bindWallpaper" msgid="7108428692595491668">"Приложение сможет подключаться к базовому интерфейсу службы обоев. Это разрешение не используется обычными приложениями."</string>
+ <string name="permlab_bindRemoteDisplay" msgid="1782923938029941960">"Подключение к удаленному дисплею"</string>
+ <string name="permdesc_bindRemoteDisplay" msgid="1261242718727295981">"Приложение сможет подключаться к базовому интерфейсу удаленного дисплея. Это разрешение обычно используется только специальными приложениями."</string>
<string name="permlab_bindRemoteViews" msgid="5697987759897367099">"Подключение к службе виджетов"</string>
<string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"Приложение сможет подключаться к базовому интерфейсу службы виджетов. Это разрешение не используется обычными приложениями."</string>
<string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"Взаимодействие с администратором устройства"</string>
@@ -1348,7 +1350,7 @@
<string name="submit" msgid="1602335572089911941">"Отправить"</string>
<string name="car_mode_disable_notification_title" msgid="3164768212003864316">"Включен режим \"Штурман\""</string>
<string name="car_mode_disable_notification_message" msgid="8035230537563503262">"Чтобы выйти, нажмите здесь."</string>
- <string name="tethered_notification_title" msgid="3146694234398202601">"USB-модем/точка доступа Wi-Fi используется"</string>
+ <string name="tethered_notification_title" msgid="3146694234398202601">"Включен режим модема"</string>
<string name="tethered_notification_message" msgid="6857031760103062982">"Нажмите для настройки."</string>
<string name="back_button_label" msgid="2300470004503343439">"Назад"</string>
<string name="next_button_label" msgid="1080555104677992408">"Далее"</string>
@@ -1489,8 +1491,12 @@
<string name="default_audio_route_category_name" msgid="3722811174003886946">"Система"</string>
<string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Воспроизведение звука через Bluetooth"</string>
<string name="wireless_display_route_description" msgid="9070346425023979651">"Беспроводной монитор"</string>
- <string name="media_route_chooser_grouping_done" msgid="7966438307723317169">"Готово"</string>
<string name="media_route_button_content_description" msgid="5758553567065145276">"Перенаправлять поток мультимедиа"</string>
+ <string name="media_route_chooser_title" msgid="1751618554539087622">"Подключение к устройству"</string>
+ <string name="media_route_chooser_title_for_remote_display" msgid="3395541745872017583">"Подключение к удаленному дисплею"</string>
+ <string name="media_route_chooser_searching" msgid="4776236202610828706">"Поиск устройств…"</string>
+ <string name="media_route_chooser_extended_settings" msgid="87015534236701604">"Настройки"</string>
+ <string name="media_route_controller_disconnect" msgid="8966120286374158649">"Отключить"</string>
<string name="media_route_status_scanning" msgid="7279908761758293783">"Сканирование..."</string>
<string name="media_route_status_connecting" msgid="6422571716007825440">"Подключение..."</string>
<string name="media_route_status_available" msgid="6983258067194649391">"Доступен"</string>
@@ -1501,8 +1507,10 @@
<string name="display_manager_overlay_display_name" msgid="5142365982271620716">"Наложение № <xliff:g id="ID">%1$d</xliff:g>"</string>
<string name="display_manager_overlay_display_title" msgid="652124517672257172">"<xliff:g id="NAME">%1$s</xliff:g>: <xliff:g id="WIDTH">%2$d</xliff:g> х <xliff:g id="HEIGHT">%3$d</xliff:g>, <xliff:g id="DPI">%4$d</xliff:g> тчк/дюйм"</string>
<string name="display_manager_overlay_display_secure_suffix" msgid="6022119702628572080">", безопасный"</string>
- <string name="wifi_display_notification_title" msgid="2223050649240326557">"Беспроводной проектор подключен"</string>
- <string name="wifi_display_notification_message" msgid="4498802012464170685">"Изображение передается на другое устройство"</string>
+ <string name="wifi_display_notification_connecting_title" msgid="2838646471050359706">"Подключение к удаленному дисплею"</string>
+ <string name="wifi_display_notification_connecting_message" msgid="5837350993752841389">"Подключение к <xliff:g id="NAME">%1$s</xliff:g>"</string>
+ <string name="wifi_display_notification_connected_title" msgid="8567308065912676285">"Удаленный дисплей подключен"</string>
+ <string name="wifi_display_notification_connected_message" msgid="2587209325701109715">"Подключено к <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="wifi_display_notification_disconnect" msgid="6183754463561153372">"Отключить"</string>
<string name="kg_emergency_call_label" msgid="684946192523830531">"Экстренный вызов"</string>
<string name="kg_forgot_pattern_button_text" msgid="8852021467868220608">"Забыли графический ключ?"</string>
diff --git a/core/res/res/values-sk/strings.xml b/core/res/res/values-sk/strings.xml
index a4e57fb..3467b4d 100644
--- a/core/res/res/values-sk/strings.xml
+++ b/core/res/res/values-sk/strings.xml
@@ -382,6 +382,8 @@
<string name="permdesc_bindVpnService" msgid="2067845564581693905">"Umožňuje držiteľovi viazať sa na najvyššiu úroveň rozhrania služby VPN. Bežné aplikácie by toto nastavenie nemali nikdy potrebovať."</string>
<string name="permlab_bindWallpaper" msgid="8716400279937856462">"väzba na tapetu"</string>
<string name="permdesc_bindWallpaper" msgid="7108428692595491668">"Umožňuje držiteľovi viazať sa na najvyššiu úroveň rozhrania tapety. Bežné aplikácie by toto nastavenie nemali nikdy potrebovať."</string>
+ <string name="permlab_bindRemoteDisplay" msgid="1782923938029941960">"viazať na vzdialený displej"</string>
+ <string name="permdesc_bindRemoteDisplay" msgid="1261242718727295981">"Umožňuje držiteľovi viazať sa na najvyššiu úroveň rozhrania vzdialeného displeja. Bežné aplikácie by toto nastavenie nemali nikdy potrebovať."</string>
<string name="permlab_bindRemoteViews" msgid="5697987759897367099">"viazať sa k službe miniaplikácie"</string>
<string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"Umožňuje držiteľovi viazať sa na najvyššiu úroveň rozhrania služby miniaplikácií. Bežné aplikácie by toto nastavenie nemali nikdy potrebovať."</string>
<string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"komunikovať so správcom zariadenia"</string>
@@ -1489,8 +1491,12 @@
<string name="default_audio_route_category_name" msgid="3722811174003886946">"Systém"</string>
<string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Bluetooth audio"</string>
<string name="wireless_display_route_description" msgid="9070346425023979651">"Bezdrôtový displej"</string>
- <string name="media_route_chooser_grouping_done" msgid="7966438307723317169">"Hotovo"</string>
<string name="media_route_button_content_description" msgid="5758553567065145276">"Výstup médií"</string>
+ <string name="media_route_chooser_title" msgid="1751618554539087622">"Pripojenie k zariadeniu"</string>
+ <string name="media_route_chooser_title_for_remote_display" msgid="3395541745872017583">"Odovzdanie obraz. na prehratie v zariad."</string>
+ <string name="media_route_chooser_searching" msgid="4776236202610828706">"Prebieha vyhľadávanie zariadení…"</string>
+ <string name="media_route_chooser_extended_settings" msgid="87015534236701604">"Nastavenia"</string>
+ <string name="media_route_controller_disconnect" msgid="8966120286374158649">"Odpojiť"</string>
<string name="media_route_status_scanning" msgid="7279908761758293783">"Prebieha vyhľadávanie..."</string>
<string name="media_route_status_connecting" msgid="6422571716007825440">"Prebieha pripájanie…"</string>
<string name="media_route_status_available" msgid="6983258067194649391">"K dispozícii"</string>
@@ -1501,8 +1507,10 @@
<string name="display_manager_overlay_display_name" msgid="5142365982271620716">"Prekrytie č. <xliff:g id="ID">%1$d</xliff:g>"</string>
<string name="display_manager_overlay_display_title" msgid="652124517672257172">"<xliff:g id="NAME">%1$s</xliff:g>: <xliff:g id="WIDTH">%2$d</xliff:g> x <xliff:g id="HEIGHT">%3$d</xliff:g>, <xliff:g id="DPI">%4$d</xliff:g> dpi"</string>
<string name="display_manager_overlay_display_secure_suffix" msgid="6022119702628572080">", zabezpečené"</string>
- <string name="wifi_display_notification_title" msgid="2223050649240326557">"Bezdrôtový displej je pripojený"</string>
- <string name="wifi_display_notification_message" msgid="4498802012464170685">"Táto obrazovka sa zobrazuje na inom zariadení"</string>
+ <string name="wifi_display_notification_connecting_title" msgid="2838646471050359706">"Odovzdávanie obrazovky na prehratie"</string>
+ <string name="wifi_display_notification_connecting_message" msgid="5837350993752841389">"Prebieha pripájanie k obrazovke <xliff:g id="NAME">%1$s</xliff:g>"</string>
+ <string name="wifi_display_notification_connected_title" msgid="8567308065912676285">"Odovzdávanie obrazovky na prehratie"</string>
+ <string name="wifi_display_notification_connected_message" msgid="2587209325701109715">"Pripojené k obrazovke <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="wifi_display_notification_disconnect" msgid="6183754463561153372">"Odpojiť"</string>
<string name="kg_emergency_call_label" msgid="684946192523830531">"Tiesňové volanie"</string>
<string name="kg_forgot_pattern_button_text" msgid="8852021467868220608">"Nepamätám si vzor"</string>
diff --git a/core/res/res/values-sl/strings.xml b/core/res/res/values-sl/strings.xml
index c364397..0d76bbf 100644
--- a/core/res/res/values-sl/strings.xml
+++ b/core/res/res/values-sl/strings.xml
@@ -382,6 +382,8 @@
<string name="permdesc_bindVpnService" msgid="2067845564581693905">"Lastniku omogoča povezovanje z vmesnikom storitve navideznega zasebnega omrežja najvišje ravni. Ne uporabljajte za navadne programe."</string>
<string name="permlab_bindWallpaper" msgid="8716400279937856462">"povezovanje z ozadjem"</string>
<string name="permdesc_bindWallpaper" msgid="7108428692595491668">"Imetniku omogoča povezavo z vmesnikom ozadja najvišje ravni. Tega nikoli ni treba uporabiti za navadne programe."</string>
+ <string name="permlab_bindRemoteDisplay" msgid="1782923938029941960">"povezava z oddaljenim prikazom"</string>
+ <string name="permdesc_bindRemoteDisplay" msgid="1261242718727295981">"Imetniku omogoča povezovanje z vmesnikom oddaljenega prikaza najvišje ravni. Tega ni treba nikoli uporabiti za navadne aplikacije."</string>
<string name="permlab_bindRemoteViews" msgid="5697987759897367099">"poveži s storitvijo pripomočka"</string>
<string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"Lastniku omogoča povezovanje z vmesnikom storitve pripomočka najvišje ravni. Tega ni treba nikoli uporabiti za navadne programe."</string>
<string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"interakcija s skrbnikom naprave"</string>
@@ -1489,8 +1491,12 @@
<string name="default_audio_route_category_name" msgid="3722811174003886946">"Sistem"</string>
<string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Zvok prek Bluetootha"</string>
<string name="wireless_display_route_description" msgid="9070346425023979651">"Brezžični prikaz"</string>
- <string name="media_route_chooser_grouping_done" msgid="7966438307723317169">"Končano"</string>
<string name="media_route_button_content_description" msgid="5758553567065145276">"Izhod predstavnosti"</string>
+ <string name="media_route_chooser_title" msgid="1751618554539087622">"Povezovanje z napravo"</string>
+ <string name="media_route_chooser_title_for_remote_display" msgid="3395541745872017583">"Predvajanje zaslona v napravi"</string>
+ <string name="media_route_chooser_searching" msgid="4776236202610828706">"Iskanje naprav …"</string>
+ <string name="media_route_chooser_extended_settings" msgid="87015534236701604">"Nastavitve"</string>
+ <string name="media_route_controller_disconnect" msgid="8966120286374158649">"Prekinitev povezave"</string>
<string name="media_route_status_scanning" msgid="7279908761758293783">"Pregledovanje ..."</string>
<string name="media_route_status_connecting" msgid="6422571716007825440">"Vzpostavljanje povezave ..."</string>
<string name="media_route_status_available" msgid="6983258067194649391">"Na voljo"</string>
@@ -1501,8 +1507,10 @@
<string name="display_manager_overlay_display_name" msgid="5142365982271620716">"Prekrivanje #<xliff:g id="ID">%1$d</xliff:g>"</string>
<string name="display_manager_overlay_display_title" msgid="652124517672257172">"<xliff:g id="NAME">%1$s</xliff:g>: <xliff:g id="WIDTH">%2$d</xliff:g> x <xliff:g id="HEIGHT">%3$d</xliff:g>, <xliff:g id="DPI">%4$d</xliff:g> pik na palec"</string>
<string name="display_manager_overlay_display_secure_suffix" msgid="6022119702628572080">", varen"</string>
- <string name="wifi_display_notification_title" msgid="2223050649240326557">"Brezžični zaslon je povezan"</string>
- <string name="wifi_display_notification_message" msgid="4498802012464170685">"Ta zaslon je prikazan v drugi napravi"</string>
+ <string name="wifi_display_notification_connecting_title" msgid="2838646471050359706">"Predvajanje zaslona"</string>
+ <string name="wifi_display_notification_connecting_message" msgid="5837350993752841389">"Povezovanje z zaslonom <xliff:g id="NAME">%1$s</xliff:g>"</string>
+ <string name="wifi_display_notification_connected_title" msgid="8567308065912676285">"Predvajanje zaslona"</string>
+ <string name="wifi_display_notification_connected_message" msgid="2587209325701109715">"Vzpostavljena povezava z zaslonom <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="wifi_display_notification_disconnect" msgid="6183754463561153372">"Prekini povezavo"</string>
<string name="kg_emergency_call_label" msgid="684946192523830531">"Klic v sili"</string>
<string name="kg_forgot_pattern_button_text" msgid="8852021467868220608">"Pozabljen vzorec"</string>
diff --git a/core/res/res/values-sr/strings.xml b/core/res/res/values-sr/strings.xml
index 605cde5..6fb9ea2 100644
--- a/core/res/res/values-sr/strings.xml
+++ b/core/res/res/values-sr/strings.xml
@@ -382,6 +382,8 @@
<string name="permdesc_bindVpnService" msgid="2067845564581693905">"Дозвољава власнику да се повеже са интерфејсом VPN услуге највишег нивоа. Уобичајене апликације никада не би требало да је користе."</string>
<string name="permlab_bindWallpaper" msgid="8716400279937856462">"обавезивање на позадину"</string>
<string name="permdesc_bindWallpaper" msgid="7108428692595491668">"Дозвољава власнику да се повеже са интерфејсом позадине највишег нивоа. Уобичајене апликације никада не би требало да је користе."</string>
+ <string name="permlab_bindRemoteDisplay" msgid="1782923938029941960">"повезивање са удаљеним екраном"</string>
+ <string name="permdesc_bindRemoteDisplay" msgid="1261242718727295981">"Дозвољава власнику да се повеже са интерфејсом удаљеног екрана највишег нивоа. Уобичајене апликације никада не би требало да је користе."</string>
<string name="permlab_bindRemoteViews" msgid="5697987759897367099">"обавезивање на услугу виџета"</string>
<string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"Дозвољава власнику да се обавеже на интерфејс услуге виџета највишег нивоа. Уобичајене апликације никада не би требало да је користе."</string>
<string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"интеракција са администратором уређаја"</string>
@@ -1489,8 +1491,12 @@
<string name="default_audio_route_category_name" msgid="3722811174003886946">"Систем"</string>
<string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Bluetooth аудио"</string>
<string name="wireless_display_route_description" msgid="9070346425023979651">"Бежични екран"</string>
- <string name="media_route_chooser_grouping_done" msgid="7966438307723317169">"Готово"</string>
<string name="media_route_button_content_description" msgid="5758553567065145276">"Излаз медија"</string>
+ <string name="media_route_chooser_title" msgid="1751618554539087622">"Повежите са уређајем"</string>
+ <string name="media_route_chooser_title_for_remote_display" msgid="3395541745872017583">"Пребаците екран на уређај"</string>
+ <string name="media_route_chooser_searching" msgid="4776236202610828706">"Тражење уређаја…"</string>
+ <string name="media_route_chooser_extended_settings" msgid="87015534236701604">"Подешавања"</string>
+ <string name="media_route_controller_disconnect" msgid="8966120286374158649">"Прекини везу"</string>
<string name="media_route_status_scanning" msgid="7279908761758293783">"Скенирање..."</string>
<string name="media_route_status_connecting" msgid="6422571716007825440">"Повезивање..."</string>
<string name="media_route_status_available" msgid="6983258067194649391">"Доступна"</string>
@@ -1501,8 +1507,10 @@
<string name="display_manager_overlay_display_name" msgid="5142365982271620716">"Постављени елемент бр. <xliff:g id="ID">%1$d</xliff:g>"</string>
<string name="display_manager_overlay_display_title" msgid="652124517672257172">"<xliff:g id="NAME">%1$s</xliff:g>: <xliff:g id="WIDTH">%2$d</xliff:g>×<xliff:g id="HEIGHT">%3$d</xliff:g>, <xliff:g id="DPI">%4$d</xliff:g> dpi"</string>
<string name="display_manager_overlay_display_secure_suffix" msgid="6022119702628572080">", безбедно"</string>
- <string name="wifi_display_notification_title" msgid="2223050649240326557">"Бежични екран је повезан"</string>
- <string name="wifi_display_notification_message" msgid="4498802012464170685">"Овај екран се приказује на другом уређају"</string>
+ <string name="wifi_display_notification_connecting_title" msgid="2838646471050359706">"Пребацивање екрана"</string>
+ <string name="wifi_display_notification_connecting_message" msgid="5837350993752841389">"Повезивање са <xliff:g id="NAME">%1$s</xliff:g>"</string>
+ <string name="wifi_display_notification_connected_title" msgid="8567308065912676285">"Пребацивање екрана"</string>
+ <string name="wifi_display_notification_connected_message" msgid="2587209325701109715">"Повезано је са <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="wifi_display_notification_disconnect" msgid="6183754463561153372">"Прекини везу"</string>
<string name="kg_emergency_call_label" msgid="684946192523830531">"Хитни позив"</string>
<string name="kg_forgot_pattern_button_text" msgid="8852021467868220608">"Заборављени шаблон"</string>
diff --git a/core/res/res/values-sv/strings.xml b/core/res/res/values-sv/strings.xml
index 86eaa11..db7d7d0 100644
--- a/core/res/res/values-sv/strings.xml
+++ b/core/res/res/values-sv/strings.xml
@@ -382,6 +382,8 @@
<string name="permdesc_bindVpnService" msgid="2067845564581693905">"Innehavaren tillåts att binda till den översta nivåns gränssnitt för en VPN-tjänst. Ska inte behövas för vanliga appar."</string>
<string name="permlab_bindWallpaper" msgid="8716400279937856462">"binda till en bakgrund"</string>
<string name="permdesc_bindWallpaper" msgid="7108428692595491668">"Innehavaren kan binda till den översta nivåns gränssnitt för en bakgrund. Ska inte behövas för vanliga appar."</string>
+ <string name="permlab_bindRemoteDisplay" msgid="1782923938029941960">"bind till en fjärrskärm"</string>
+ <string name="permdesc_bindRemoteDisplay" msgid="1261242718727295981">"Innehavaren tillåts att binda till den översta nivåns gränssnitt för en fjärrskärm. Ska inte behövas för vanliga appar."</string>
<string name="permlab_bindRemoteViews" msgid="5697987759897367099">"bind till en widget"</string>
<string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"Innehavaren tillåts att binda till den översta nivåns gränssnitt för en widget. Ska inte behövas för vanliga appar."</string>
<string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"arbeta med en enhetsadministratör"</string>
@@ -1489,8 +1491,12 @@
<string name="default_audio_route_category_name" msgid="3722811174003886946">"System"</string>
<string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Bluetooth-ljud"</string>
<string name="wireless_display_route_description" msgid="9070346425023979651">"Trådlös skärm"</string>
- <string name="media_route_chooser_grouping_done" msgid="7966438307723317169">"Klar"</string>
<string name="media_route_button_content_description" msgid="5758553567065145276">"Medieuppspelning"</string>
+ <string name="media_route_chooser_title" msgid="1751618554539087622">"Anslut till enhet"</string>
+ <string name="media_route_chooser_title_for_remote_display" msgid="3395541745872017583">"Överför skärmen till enheten"</string>
+ <string name="media_route_chooser_searching" msgid="4776236202610828706">"Söker efter enheter ..."</string>
+ <string name="media_route_chooser_extended_settings" msgid="87015534236701604">"Inställningar"</string>
+ <string name="media_route_controller_disconnect" msgid="8966120286374158649">"Koppla från"</string>
<string name="media_route_status_scanning" msgid="7279908761758293783">"Skannar…"</string>
<string name="media_route_status_connecting" msgid="6422571716007825440">"Ansluter ..."</string>
<string name="media_route_status_available" msgid="6983258067194649391">"Tillgängliga"</string>
@@ -1501,8 +1507,10 @@
<string name="display_manager_overlay_display_name" msgid="5142365982271620716">"Överlagring #<xliff:g id="ID">%1$d</xliff:g>"</string>
<string name="display_manager_overlay_display_title" msgid="652124517672257172">"<xliff:g id="NAME">%1$s</xliff:g>: <xliff:g id="WIDTH">%2$d</xliff:g> x <xliff:g id="HEIGHT">%3$d</xliff:g>, <xliff:g id="DPI">%4$d</xliff:g> dpi"</string>
<string name="display_manager_overlay_display_secure_suffix" msgid="6022119702628572080">", säker"</string>
- <string name="wifi_display_notification_title" msgid="2223050649240326557">"Trådlös anslutning till skärm"</string>
- <string name="wifi_display_notification_message" msgid="4498802012464170685">"Den här skärmen visas på en annan enhet"</string>
+ <string name="wifi_display_notification_connecting_title" msgid="2838646471050359706">"Överför skärmen"</string>
+ <string name="wifi_display_notification_connecting_message" msgid="5837350993752841389">"Ansluter till <xliff:g id="NAME">%1$s</xliff:g>"</string>
+ <string name="wifi_display_notification_connected_title" msgid="8567308065912676285">"Överför skärmen"</string>
+ <string name="wifi_display_notification_connected_message" msgid="2587209325701109715">"Ansluten till <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="wifi_display_notification_disconnect" msgid="6183754463561153372">"Koppla från"</string>
<string name="kg_emergency_call_label" msgid="684946192523830531">"Nödsamtal"</string>
<string name="kg_forgot_pattern_button_text" msgid="8852021467868220608">"Har du glömt ditt grafiska lösenord?"</string>
diff --git a/core/res/res/values-sw/strings.xml b/core/res/res/values-sw/strings.xml
index aa4b279..30c8092 100644
--- a/core/res/res/values-sw/strings.xml
+++ b/core/res/res/values-sw/strings.xml
@@ -382,6 +382,8 @@
<string name="permdesc_bindVpnService" msgid="2067845564581693905">"Inaruhusu kishikiliaji kushurutisha kusano ya kiwango cha juu cha huduma ya Vpn. Haipaswi kuhitajika kwa programu za kawaida."</string>
<string name="permlab_bindWallpaper" msgid="8716400279937856462">"funga kwa mandhari"</string>
<string name="permdesc_bindWallpaper" msgid="7108428692595491668">"Inaruhusu kishikiliaji kushurutisha kwa kusano ya kiwango cha juu cha mandhari. Haipaswi kamwe kuhitajika kwa programu za kawaida."</string>
+ <string name="permlab_bindRemoteDisplay" msgid="1782923938029941960">"fungisha kwenye mwonekano wa mbali"</string>
+ <string name="permdesc_bindRemoteDisplay" msgid="1261242718727295981">"Huruhusu mtumiaji kujifungia kiolesura cha kiwango cha juu cha mwonekano wa mbali. Haipaswi kuhitajika kwa programu za kawaida."</string>
<string name="permlab_bindRemoteViews" msgid="5697987759897367099">"funga kwenye huduma ya widget"</string>
<string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"Inaruhusu mmiliki kushurutisha kusano ya kiwango cha juu ya huduma ya wijeti. Haipaswi kuhitajika kwa programu za kawaida."</string>
<string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"jiunge na msimamizi wa kifaa"</string>
@@ -1489,8 +1491,12 @@
<string name="default_audio_route_category_name" msgid="3722811174003886946">"Mfumo"</string>
<string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Sauti ya Bluetooth"</string>
<string name="wireless_display_route_description" msgid="9070346425023979651">"Uonyeshaji usiotumia waya"</string>
- <string name="media_route_chooser_grouping_done" msgid="7966438307723317169">"Nimemaliza"</string>
<string name="media_route_button_content_description" msgid="5758553567065145276">"Towe la midia"</string>
+ <string name="media_route_chooser_title" msgid="1751618554539087622">"Unganisha kwenye kifaa"</string>
+ <string name="media_route_chooser_title_for_remote_display" msgid="3395541745872017583">"Tuma skrini kwa kifaa"</string>
+ <string name="media_route_chooser_searching" msgid="4776236202610828706">"Inatafuta vifaa..."</string>
+ <string name="media_route_chooser_extended_settings" msgid="87015534236701604">"Mipangilio"</string>
+ <string name="media_route_controller_disconnect" msgid="8966120286374158649">"Ondoa"</string>
<string name="media_route_status_scanning" msgid="7279908761758293783">"Inatambaza..."</string>
<string name="media_route_status_connecting" msgid="6422571716007825440">"Inaunganisha..."</string>
<string name="media_route_status_available" msgid="6983258067194649391">"Inapatikana"</string>
@@ -1501,8 +1507,10 @@
<string name="display_manager_overlay_display_name" msgid="5142365982271620716">"Uwekeleaji #<xliff:g id="ID">%1$d</xliff:g>"</string>
<string name="display_manager_overlay_display_title" msgid="652124517672257172">"<xliff:g id="NAME">%1$s</xliff:g>: <xliff:g id="WIDTH">%2$d</xliff:g>x<xliff:g id="HEIGHT">%3$d</xliff:g>, <xliff:g id="DPI">%4$d</xliff:g> dpi"</string>
<string name="display_manager_overlay_display_secure_suffix" msgid="6022119702628572080">", salama"</string>
- <string name="wifi_display_notification_title" msgid="2223050649240326557">"Onyesho pasiwaya limeunganishwa"</string>
- <string name="wifi_display_notification_message" msgid="4498802012464170685">"Skrini hii inaonyesha kwenye kifaa kingine"</string>
+ <string name="wifi_display_notification_connecting_title" msgid="2838646471050359706">"Utumaji wa skrini"</string>
+ <string name="wifi_display_notification_connecting_message" msgid="5837350993752841389">"Inaunganishwa kwenye <xliff:g id="NAME">%1$s</xliff:g>"</string>
+ <string name="wifi_display_notification_connected_title" msgid="8567308065912676285">"Utumaji wa skrini"</string>
+ <string name="wifi_display_notification_connected_message" msgid="2587209325701109715">"Imeungwanishwa kwenye <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="wifi_display_notification_disconnect" msgid="6183754463561153372">"Tenganisha"</string>
<string name="kg_emergency_call_label" msgid="684946192523830531">"Simu ya dharura"</string>
<string name="kg_forgot_pattern_button_text" msgid="8852021467868220608">"Umesahau Ruwaza"</string>
diff --git a/core/res/res/values-th/strings.xml b/core/res/res/values-th/strings.xml
index 4622005..f298a8f 100644
--- a/core/res/res/values-th/strings.xml
+++ b/core/res/res/values-th/strings.xml
@@ -382,6 +382,8 @@
<string name="permdesc_bindVpnService" msgid="2067845564581693905">"อนุญาตให้เจ้าของเชื่อมโยงกับส่วนติดต่อผู้ใช้ระดับสูงสุดของบริการ VPN ไม่ควรต้องใช้สำหรับแอปพลิเคชันทั่วไป"</string>
<string name="permlab_bindWallpaper" msgid="8716400279937856462">"เชื่อมโยงกับวอลเปเปอร์"</string>
<string name="permdesc_bindWallpaper" msgid="7108428692595491668">"อนุญาตให้ผู้ใช้เชื่อมโยงกับส่วนติดต่อผู้ใช้ระดับสูงสุดของวอลเปเปอร์ ไม่ควรต้องใช้สำหรับแอปพลิเคชันทั่วไป"</string>
+ <string name="permlab_bindRemoteDisplay" msgid="1782923938029941960">"ผูกกับจอแสดงผลระยะไกล"</string>
+ <string name="permdesc_bindRemoteDisplay" msgid="1261242718727295981">"อนุญาตให้ผู้ใช้ผูกกับอินเทอร์เฟซระดับสูงสุดของจอแสดงผลระยะไกล ซึ่งแอปพลิเคชันทั่วไปไม่จำเป็นต้องใช้"</string>
<string name="permlab_bindRemoteViews" msgid="5697987759897367099">"เชื่อมโยงกับบริการวิดเจ็ต"</string>
<string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"อนุญาตให้ผู้ใช้เชื่อมโยงกับส่วนติดต่อผู้ใช้ระดับสูงสุดของบริการวิดเจ็ต ไม่ควรต้องใช้สำหรับแอปพลิเคชันทั่วไป"</string>
<string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"ติดต่อกับผู้ดูแลอุปกรณ์"</string>
@@ -1489,8 +1491,12 @@
<string name="default_audio_route_category_name" msgid="3722811174003886946">"ระบบ"</string>
<string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"เสียงบลูทูธ"</string>
<string name="wireless_display_route_description" msgid="9070346425023979651">"การแสดงผลแบบไร้สาย"</string>
- <string name="media_route_chooser_grouping_done" msgid="7966438307723317169">"เสร็จสิ้น"</string>
<string name="media_route_button_content_description" msgid="5758553567065145276">"เอาต์พุตสื่อ"</string>
+ <string name="media_route_chooser_title" msgid="1751618554539087622">"เชื่อมต่อกับอุปกรณ์"</string>
+ <string name="media_route_chooser_title_for_remote_display" msgid="3395541745872017583">"ส่งหน้าจอไปยังอุปกรณ์"</string>
+ <string name="media_route_chooser_searching" msgid="4776236202610828706">"กำลังค้นหาอุปกรณ์…"</string>
+ <string name="media_route_chooser_extended_settings" msgid="87015534236701604">"การตั้งค่า"</string>
+ <string name="media_route_controller_disconnect" msgid="8966120286374158649">"ยกเลิกการเชื่อมต่อ"</string>
<string name="media_route_status_scanning" msgid="7279908761758293783">"กำลังสแกน..."</string>
<string name="media_route_status_connecting" msgid="6422571716007825440">"กำลังเชื่อมต่อ..."</string>
<string name="media_route_status_available" msgid="6983258067194649391">"พร้อมใช้งาน"</string>
@@ -1501,8 +1507,10 @@
<string name="display_manager_overlay_display_name" msgid="5142365982271620716">"การวางซ้อน #<xliff:g id="ID">%1$d</xliff:g>"</string>
<string name="display_manager_overlay_display_title" msgid="652124517672257172">"<xliff:g id="NAME">%1$s</xliff:g>: <xliff:g id="WIDTH">%2$d</xliff:g>x<xliff:g id="HEIGHT">%3$d</xliff:g>, <xliff:g id="DPI">%4$d</xliff:g> dpi"</string>
<string name="display_manager_overlay_display_secure_suffix" msgid="6022119702628572080">", ปลอดภัย"</string>
- <string name="wifi_display_notification_title" msgid="2223050649240326557">"เชื่อมต่อการแสดงผลแบบไร้สายอยู่"</string>
- <string name="wifi_display_notification_message" msgid="4498802012464170685">"หน้าจอนี้กำลังแสดงบนอุปกรณ์อื่น"</string>
+ <string name="wifi_display_notification_connecting_title" msgid="2838646471050359706">"กำลังส่งหน้าจอ"</string>
+ <string name="wifi_display_notification_connecting_message" msgid="5837350993752841389">"กำลังเชื่อมต่อไปยัง <xliff:g id="NAME">%1$s</xliff:g>"</string>
+ <string name="wifi_display_notification_connected_title" msgid="8567308065912676285">"กำลังส่งหน้าจอ"</string>
+ <string name="wifi_display_notification_connected_message" msgid="2587209325701109715">"เชื่อมต่อกับ <xliff:g id="NAME">%1$s</xliff:g> แล้ว"</string>
<string name="wifi_display_notification_disconnect" msgid="6183754463561153372">"หยุดเชื่อมต่อ"</string>
<string name="kg_emergency_call_label" msgid="684946192523830531">"หมายเลขฉุกเฉิน"</string>
<string name="kg_forgot_pattern_button_text" msgid="8852021467868220608">"ลืมรูปแบบใช่หรือไม่"</string>
diff --git a/core/res/res/values-tl/strings.xml b/core/res/res/values-tl/strings.xml
index 897a111..85dd968 100644
--- a/core/res/res/values-tl/strings.xml
+++ b/core/res/res/values-tl/strings.xml
@@ -382,6 +382,8 @@
<string name="permdesc_bindVpnService" msgid="2067845564581693905">"Pinapayagan ang may-hawak na sumailalim sa nangungunang interface ng serbisyo ng Vpn. Hindi kailanman dapat na kailanganin para sa normal na apps."</string>
<string name="permlab_bindWallpaper" msgid="8716400279937856462">"sumailalim sa wallpaper"</string>
<string name="permdesc_bindWallpaper" msgid="7108428692595491668">"Pinapayagan ang may-hawak na sumailalim sa nangungunang interface ng isang wallpaper. Hindi kailanman dapat na kailanganin para sa normal na apps."</string>
+ <string name="permlab_bindRemoteDisplay" msgid="1782923938029941960">"magpasaklaw sa isang remote na display"</string>
+ <string name="permdesc_bindRemoteDisplay" msgid="1261242718727295981">"Binibigyang-daan ang may-hawak na masaklaw ang pinakamataas na antas ng interface ng isang remote na display. Hindi dapat kailanman kailanganin ng normal na apps."</string>
<string name="permlab_bindRemoteViews" msgid="5697987759897367099">"itali sa serbisyo ng widget"</string>
<string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"Pinapayagan ang may-hawak na sumailalim sa nangungunang interface ng serbisyo ng widget. Hindi kailanman dapat na kailanganin para sa normal na apps."</string>
<string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"makipag-ugnay sa tagapangasiwa ng device"</string>
@@ -1489,8 +1491,12 @@
<string name="default_audio_route_category_name" msgid="3722811174003886946">"System"</string>
<string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Audio sa Bluetooth"</string>
<string name="wireless_display_route_description" msgid="9070346425023979651">"Wireless display"</string>
- <string name="media_route_chooser_grouping_done" msgid="7966438307723317169">"Tapos na"</string>
<string name="media_route_button_content_description" msgid="5758553567065145276">"Output ng media"</string>
+ <string name="media_route_chooser_title" msgid="1751618554539087622">"Kumonekta sa device"</string>
+ <string name="media_route_chooser_title_for_remote_display" msgid="3395541745872017583">"I-cast ang screen sa device"</string>
+ <string name="media_route_chooser_searching" msgid="4776236202610828706">"Naghahanap ng mga device…"</string>
+ <string name="media_route_chooser_extended_settings" msgid="87015534236701604">"Mga Setting"</string>
+ <string name="media_route_controller_disconnect" msgid="8966120286374158649">"Idiskonekta"</string>
<string name="media_route_status_scanning" msgid="7279908761758293783">"Nagsa-scan..."</string>
<string name="media_route_status_connecting" msgid="6422571716007825440">"Kumukonekta..."</string>
<string name="media_route_status_available" msgid="6983258067194649391">"Available"</string>
@@ -1501,8 +1507,10 @@
<string name="display_manager_overlay_display_name" msgid="5142365982271620716">"Overlay #<xliff:g id="ID">%1$d</xliff:g>"</string>
<string name="display_manager_overlay_display_title" msgid="652124517672257172">"<xliff:g id="NAME">%1$s</xliff:g>: <xliff:g id="WIDTH">%2$d</xliff:g>x<xliff:g id="HEIGHT">%3$d</xliff:g>, <xliff:g id="DPI">%4$d</xliff:g> dpi"</string>
<string name="display_manager_overlay_display_secure_suffix" msgid="6022119702628572080">", secure"</string>
- <string name="wifi_display_notification_title" msgid="2223050649240326557">"Nakakonekta ang wireless na display"</string>
- <string name="wifi_display_notification_message" msgid="4498802012464170685">"Lumalabas ang screen na ito sa isa pang device"</string>
+ <string name="wifi_display_notification_connecting_title" msgid="2838646471050359706">"Kina-cast ang screen"</string>
+ <string name="wifi_display_notification_connecting_message" msgid="5837350993752841389">"Kumokonekta sa <xliff:g id="NAME">%1$s</xliff:g>"</string>
+ <string name="wifi_display_notification_connected_title" msgid="8567308065912676285">"Kina-cast ang screen"</string>
+ <string name="wifi_display_notification_connected_message" msgid="2587209325701109715">"Nakakonekta sa <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="wifi_display_notification_disconnect" msgid="6183754463561153372">"Alisin sa pagkakakonekta"</string>
<string name="kg_emergency_call_label" msgid="684946192523830531">"Emergency na tawag"</string>
<string name="kg_forgot_pattern_button_text" msgid="8852021467868220608">"Nakalimutan ang Pattern"</string>
diff --git a/core/res/res/values-tr/strings.xml b/core/res/res/values-tr/strings.xml
index ffb6ca1..9ca752e 100644
--- a/core/res/res/values-tr/strings.xml
+++ b/core/res/res/values-tr/strings.xml
@@ -382,6 +382,8 @@
<string name="permdesc_bindVpnService" msgid="2067845564581693905">"Cihazın sahibine bir VPN hizmetinin en üst düzey arayüzüne bağlanma izni verir. Normal uygulamalarda hiçbir zaman gerek duyulmaz."</string>
<string name="permlab_bindWallpaper" msgid="8716400279937856462">"bir duvar kağıdına tabi kıl"</string>
<string name="permdesc_bindWallpaper" msgid="7108428692595491668">"Cihazın sahibine, duvar kağıdının en üst düzey arayüzüne bağlanma izni verir. Normal uygulamalarda hiçbir zaman gerek duyulmaz."</string>
+ <string name="permlab_bindRemoteDisplay" msgid="1782923938029941960">"uzak ekrana bağlan"</string>
+ <string name="permdesc_bindRemoteDisplay" msgid="1261242718727295981">"İzin sahibine, bir uzak ekranın en üst düzey arayüzüne bağlanma izni verir. Normal uygulamalarda hiçbir zaman gerek duyulmaz."</string>
<string name="permlab_bindRemoteViews" msgid="5697987759897367099">"bir widget hizmetine bağla"</string>
<string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"Cihazın sahibine bir widget hizmetinin en üst düzey arayüzüne bağlanma izni verir. Normal uygulamalarda hiçbir zaman gerek duyulmaz."</string>
<string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"bir cihaz yöneticisi ile etkileşimde bulun"</string>
@@ -1489,8 +1491,12 @@
<string name="default_audio_route_category_name" msgid="3722811174003886946">"Sistem"</string>
<string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Bluetooth ses"</string>
<string name="wireless_display_route_description" msgid="9070346425023979651">"Kablosuz ekran"</string>
- <string name="media_route_chooser_grouping_done" msgid="7966438307723317169">"Tamamlandı"</string>
<string name="media_route_button_content_description" msgid="5758553567065145276">"Medya çıkışı"</string>
+ <string name="media_route_chooser_title" msgid="1751618554539087622">"Cihaza bağlanın"</string>
+ <string name="media_route_chooser_title_for_remote_display" msgid="3395541745872017583">"Ekranı cihaza yayınlayın"</string>
+ <string name="media_route_chooser_searching" msgid="4776236202610828706">"Cihaz aranıyor…"</string>
+ <string name="media_route_chooser_extended_settings" msgid="87015534236701604">"Ayarlar"</string>
+ <string name="media_route_controller_disconnect" msgid="8966120286374158649">"Bağlantıyı kes"</string>
<string name="media_route_status_scanning" msgid="7279908761758293783">"Taranıyor..."</string>
<string name="media_route_status_connecting" msgid="6422571716007825440">"Bağlanılıyor..."</string>
<string name="media_route_status_available" msgid="6983258067194649391">"Kullanılabilir"</string>
@@ -1501,8 +1507,10 @@
<string name="display_manager_overlay_display_name" msgid="5142365982271620716">"Yer Paylaşımı No. <xliff:g id="ID">%1$d</xliff:g>"</string>
<string name="display_manager_overlay_display_title" msgid="652124517672257172">"<xliff:g id="NAME">%1$s</xliff:g>: <xliff:g id="WIDTH">%2$d</xliff:g>x<xliff:g id="HEIGHT">%3$d</xliff:g>, <xliff:g id="DPI">%4$d</xliff:g> dpi"</string>
<string name="display_manager_overlay_display_secure_suffix" msgid="6022119702628572080">", güvenli"</string>
- <string name="wifi_display_notification_title" msgid="2223050649240326557">"Kablosuz ekrana bağlandı"</string>
- <string name="wifi_display_notification_message" msgid="4498802012464170685">"Bu ekran başka bir cihazda gösteriliyor"</string>
+ <string name="wifi_display_notification_connecting_title" msgid="2838646471050359706">"Ekran yayınlanıyor"</string>
+ <string name="wifi_display_notification_connecting_message" msgid="5837350993752841389">"<xliff:g id="NAME">%1$s</xliff:g> bağlantısı yapılıyor"</string>
+ <string name="wifi_display_notification_connected_title" msgid="8567308065912676285">"Ekran yayınlanıyor"</string>
+ <string name="wifi_display_notification_connected_message" msgid="2587209325701109715">"<xliff:g id="NAME">%1$s</xliff:g> bağlantısı yapıldı"</string>
<string name="wifi_display_notification_disconnect" msgid="6183754463561153372">"Bağlantıyı kes"</string>
<string name="kg_emergency_call_label" msgid="684946192523830531">"Acil durum çağrısı"</string>
<string name="kg_forgot_pattern_button_text" msgid="8852021467868220608">"Deseni Unuttunuz mu?"</string>
diff --git a/core/res/res/values-uk/strings.xml b/core/res/res/values-uk/strings.xml
index f6bc23d..556b35b 100644
--- a/core/res/res/values-uk/strings.xml
+++ b/core/res/res/values-uk/strings.xml
@@ -382,6 +382,8 @@
<string name="permdesc_bindVpnService" msgid="2067845564581693905">"Дозволяє власникові прив’язуватися до інтерфейсу верхнього рівня служби VPN. Ніколи не застосовується для звичайних програм."</string>
<string name="permlab_bindWallpaper" msgid="8716400279937856462">"прив’язати до фонового малюнка"</string>
<string name="permdesc_bindWallpaper" msgid="7108428692595491668">"Дозволяє власнику прив’язуватися до інтерфейсу верхнього рівня фонового малюнка. Ніколи не застосовується для звичайних програм."</string>
+ <string name="permlab_bindRemoteDisplay" msgid="1782923938029941960">"прив’язуватися до віддаленого екрана"</string>
+ <string name="permdesc_bindRemoteDisplay" msgid="1261242718727295981">"Дозволяє власникові прив’язуватися до інтерфейсу верхнього рівня віддаленого екрана. Ніколи не застосовується для звичайних програм."</string>
<string name="permlab_bindRemoteViews" msgid="5697987759897367099">"прив\'язувати до служби віджетів"</string>
<string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"Дозволяє власникові прив’язуватися до інтерфейсу верхнього рівня служби віджетів. Ніколи не застосовується для звичайних програм."</string>
<string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"взаємодіяти з адмін. пристрою"</string>
@@ -1489,8 +1491,12 @@
<string name="default_audio_route_category_name" msgid="3722811174003886946">"Система"</string>
<string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Аудіо Bluetooth"</string>
<string name="wireless_display_route_description" msgid="9070346425023979651">"Бездротовий екран"</string>
- <string name="media_route_chooser_grouping_done" msgid="7966438307723317169">"Готово"</string>
<string name="media_route_button_content_description" msgid="5758553567065145276">"Вивід медіа-даних"</string>
+ <string name="media_route_chooser_title" msgid="1751618554539087622">"Під’єднатися до пристрою"</string>
+ <string name="media_route_chooser_title_for_remote_display" msgid="3395541745872017583">"Транслювати екран на пристрій"</string>
+ <string name="media_route_chooser_searching" msgid="4776236202610828706">"Пошук пристроїв…"</string>
+ <string name="media_route_chooser_extended_settings" msgid="87015534236701604">"Налаштування"</string>
+ <string name="media_route_controller_disconnect" msgid="8966120286374158649">"Від’єднатися"</string>
<string name="media_route_status_scanning" msgid="7279908761758293783">"Сканування..."</string>
<string name="media_route_status_connecting" msgid="6422571716007825440">"З’єднання..."</string>
<string name="media_route_status_available" msgid="6983258067194649391">"Доступно"</string>
@@ -1501,8 +1507,10 @@
<string name="display_manager_overlay_display_name" msgid="5142365982271620716">"Накладання №<xliff:g id="ID">%1$d</xliff:g>"</string>
<string name="display_manager_overlay_display_title" msgid="652124517672257172">"<xliff:g id="NAME">%1$s</xliff:g>: <xliff:g id="WIDTH">%2$d</xliff:g>х<xliff:g id="HEIGHT">%3$d</xliff:g>, <xliff:g id="DPI">%4$d</xliff:g> dpi"</string>
<string name="display_manager_overlay_display_secure_suffix" msgid="6022119702628572080">", безпечний"</string>
- <string name="wifi_display_notification_title" msgid="2223050649240326557">"Бездротовий екран під’єднано"</string>
- <string name="wifi_display_notification_message" msgid="4498802012464170685">"Цей екран відображається на іншому пристрої"</string>
+ <string name="wifi_display_notification_connecting_title" msgid="2838646471050359706">"Транслювання екрана"</string>
+ <string name="wifi_display_notification_connecting_message" msgid="5837350993752841389">"<xliff:g id="NAME">%1$s</xliff:g> – під’єднання"</string>
+ <string name="wifi_display_notification_connected_title" msgid="8567308065912676285">"Транслювання екрана"</string>
+ <string name="wifi_display_notification_connected_message" msgid="2587209325701109715">"<xliff:g id="NAME">%1$s</xliff:g> – під’єднано"</string>
<string name="wifi_display_notification_disconnect" msgid="6183754463561153372">"Від’єднати"</string>
<string name="kg_emergency_call_label" msgid="684946192523830531">"Екстрений виклик"</string>
<string name="kg_forgot_pattern_button_text" msgid="8852021467868220608">"Не пам’ятаю ключ"</string>
diff --git a/core/res/res/values-vi/strings.xml b/core/res/res/values-vi/strings.xml
index ec68f3a..c8f5014 100644
--- a/core/res/res/values-vi/strings.xml
+++ b/core/res/res/values-vi/strings.xml
@@ -382,6 +382,8 @@
<string name="permdesc_bindVpnService" msgid="2067845564581693905">"Cho phép chủ sở hữu liên kết với giao diện cấp cao nhất của dịch vụ Vpn. Không cần thiết cho các ứng dụng thông thường."</string>
<string name="permlab_bindWallpaper" msgid="8716400279937856462">"liên kết với hình nền"</string>
<string name="permdesc_bindWallpaper" msgid="7108428692595491668">"Cho phép chủ sở hữu liên kết với giao diện cấp cao nhất của hình nền. Không cần thiết cho các ứng dụng thông thường."</string>
+ <string name="permlab_bindRemoteDisplay" msgid="1782923938029941960">"liên kết với màn hình từ xa"</string>
+ <string name="permdesc_bindRemoteDisplay" msgid="1261242718727295981">"Cho phép chủ sở hữu liên kết với giao diện cấp cao nhất của màn hình từ xa. Không cần thiết cho các ứng dụng thông thường."</string>
<string name="permlab_bindRemoteViews" msgid="5697987759897367099">"liên kết với dịch vụ tiện ích con"</string>
<string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"Cho phép chủ sở hữu liên kết với giao diện cấp cao nhất của dịch vụ tiện ích con. Không cần thiết cho các ứng dụng thông thường."</string>
<string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"tương tác với quản trị viên thiết bị"</string>
@@ -1489,8 +1491,12 @@
<string name="default_audio_route_category_name" msgid="3722811174003886946">"Hệ thống"</string>
<string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Âm thanh Bluetooth"</string>
<string name="wireless_display_route_description" msgid="9070346425023979651">"Hiển thị không dây"</string>
- <string name="media_route_chooser_grouping_done" msgid="7966438307723317169">"Xong"</string>
<string name="media_route_button_content_description" msgid="5758553567065145276">"Đầu ra phương tiện"</string>
+ <string name="media_route_chooser_title" msgid="1751618554539087622">"Kết nối với thiết bị"</string>
+ <string name="media_route_chooser_title_for_remote_display" msgid="3395541745872017583">"Truyền màn hình tới thiết bị"</string>
+ <string name="media_route_chooser_searching" msgid="4776236202610828706">"Đang tìm kiếm thiết bị…"</string>
+ <string name="media_route_chooser_extended_settings" msgid="87015534236701604">"Cài đặt"</string>
+ <string name="media_route_controller_disconnect" msgid="8966120286374158649">"Ngắt kết nối"</string>
<string name="media_route_status_scanning" msgid="7279908761758293783">"Đang quét..."</string>
<string name="media_route_status_connecting" msgid="6422571716007825440">"Đang kết nối..."</string>
<string name="media_route_status_available" msgid="6983258067194649391">"Khả dụng"</string>
@@ -1501,8 +1507,10 @@
<string name="display_manager_overlay_display_name" msgid="5142365982271620716">"Lớp phủ #<xliff:g id="ID">%1$d</xliff:g>"</string>
<string name="display_manager_overlay_display_title" msgid="652124517672257172">"<xliff:g id="NAME">%1$s</xliff:g>: <xliff:g id="WIDTH">%2$d</xliff:g>x<xliff:g id="HEIGHT">%3$d</xliff:g>, <xliff:g id="DPI">%4$d</xliff:g> dpi"</string>
<string name="display_manager_overlay_display_secure_suffix" msgid="6022119702628572080">", an toàn"</string>
- <string name="wifi_display_notification_title" msgid="2223050649240326557">"Hiển thị không dây đã được kết nối"</string>
- <string name="wifi_display_notification_message" msgid="4498802012464170685">"Màn hình này đang hiển thị trên thiết bị khác"</string>
+ <string name="wifi_display_notification_connecting_title" msgid="2838646471050359706">"Truyền màn hình"</string>
+ <string name="wifi_display_notification_connecting_message" msgid="5837350993752841389">"Đang kết nối với <xliff:g id="NAME">%1$s</xliff:g>"</string>
+ <string name="wifi_display_notification_connected_title" msgid="8567308065912676285">"Truyền màn hình"</string>
+ <string name="wifi_display_notification_connected_message" msgid="2587209325701109715">"Đã kết nối với <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="wifi_display_notification_disconnect" msgid="6183754463561153372">"Ngắt kết nối"</string>
<string name="kg_emergency_call_label" msgid="684946192523830531">"Cuộc gọi khẩn cấp"</string>
<string name="kg_forgot_pattern_button_text" msgid="8852021467868220608">"Đã quên hình"</string>
diff --git a/core/res/res/values-zh-rCN/strings.xml b/core/res/res/values-zh-rCN/strings.xml
index 180accb..ba226af8 100644
--- a/core/res/res/values-zh-rCN/strings.xml
+++ b/core/res/res/values-zh-rCN/strings.xml
@@ -382,6 +382,8 @@
<string name="permdesc_bindVpnService" msgid="2067845564581693905">"允许用户绑定到 VPN 服务的顶级接口。普通应用绝不需要此权限。"</string>
<string name="permlab_bindWallpaper" msgid="8716400279937856462">"绑定到壁纸"</string>
<string name="permdesc_bindWallpaper" msgid="7108428692595491668">"允许用户绑定到壁纸的顶级接口。普通应用绝不需要此权限。"</string>
+ <string name="permlab_bindRemoteDisplay" msgid="1782923938029941960">"绑定至远程显示屏"</string>
+ <string name="permdesc_bindRemoteDisplay" msgid="1261242718727295981">"允许应用绑定至远程显示屏的顶级接口。普通应用绝不需要此权限。"</string>
<string name="permlab_bindRemoteViews" msgid="5697987759897367099">"绑定到小部件服务"</string>
<string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"允许应用绑定到小部件服务的顶级接口。普通应用绝不需要此权限。"</string>
<string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"与设备管理器交互"</string>
@@ -1489,8 +1491,12 @@
<string name="default_audio_route_category_name" msgid="3722811174003886946">"系统"</string>
<string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"蓝牙音频"</string>
<string name="wireless_display_route_description" msgid="9070346425023979651">"无线显示"</string>
- <string name="media_route_chooser_grouping_done" msgid="7966438307723317169">"完成"</string>
<string name="media_route_button_content_description" msgid="5758553567065145276">"媒体输出线路"</string>
+ <string name="media_route_chooser_title" msgid="1751618554539087622">"连接到设备"</string>
+ <string name="media_route_chooser_title_for_remote_display" msgid="3395541745872017583">"将屏幕投射到设备上"</string>
+ <string name="media_route_chooser_searching" msgid="4776236202610828706">"正在搜索设备…"</string>
+ <string name="media_route_chooser_extended_settings" msgid="87015534236701604">"设置"</string>
+ <string name="media_route_controller_disconnect" msgid="8966120286374158649">"断开连接"</string>
<string name="media_route_status_scanning" msgid="7279908761758293783">"正在扫描..."</string>
<string name="media_route_status_connecting" msgid="6422571716007825440">"正在连接..."</string>
<string name="media_route_status_available" msgid="6983258067194649391">"可连接"</string>
@@ -1501,8 +1507,10 @@
<string name="display_manager_overlay_display_name" msgid="5142365982271620716">"叠加视图 #<xliff:g id="ID">%1$d</xliff:g>"</string>
<string name="display_manager_overlay_display_title" msgid="652124517672257172">"<xliff:g id="NAME">%1$s</xliff:g>:<xliff:g id="WIDTH">%2$d</xliff:g>x<xliff:g id="HEIGHT">%3$d</xliff:g>,<xliff:g id="DPI">%4$d</xliff:g> dpi"</string>
<string name="display_manager_overlay_display_secure_suffix" msgid="6022119702628572080">",安全"</string>
- <string name="wifi_display_notification_title" msgid="2223050649240326557">"已连接到无线显示设备"</string>
- <string name="wifi_display_notification_message" msgid="4498802012464170685">"此屏幕的内容正显示在另一台设备上"</string>
+ <string name="wifi_display_notification_connecting_title" msgid="2838646471050359706">"正在投射屏幕"</string>
+ <string name="wifi_display_notification_connecting_message" msgid="5837350993752841389">"正在连接到“<xliff:g id="NAME">%1$s</xliff:g>”"</string>
+ <string name="wifi_display_notification_connected_title" msgid="8567308065912676285">"正在投射屏幕"</string>
+ <string name="wifi_display_notification_connected_message" msgid="2587209325701109715">"已连接到“<xliff:g id="NAME">%1$s</xliff:g>”"</string>
<string name="wifi_display_notification_disconnect" msgid="6183754463561153372">"断开连接"</string>
<string name="kg_emergency_call_label" msgid="684946192523830531">"紧急呼救"</string>
<string name="kg_forgot_pattern_button_text" msgid="8852021467868220608">"忘记了图案"</string>
diff --git a/core/res/res/values-zh-rHK/strings.xml b/core/res/res/values-zh-rHK/strings.xml
index 0fd3fdb..fa0c49b 100644
--- a/core/res/res/values-zh-rHK/strings.xml
+++ b/core/res/res/values-zh-rHK/strings.xml
@@ -382,6 +382,8 @@
<string name="permdesc_bindVpnService" msgid="2067845564581693905">"允許應用程式繫結至 VPN 服務的頂層介面 (不建議一般應用程式使用)。"</string>
<string name="permlab_bindWallpaper" msgid="8716400279937856462">"繫結至桌布"</string>
<string name="permdesc_bindWallpaper" msgid="7108428692595491668">"允許應用程式繫結至桌布的頂層介面 (不建議一般應用程式使用)。"</string>
+ <string name="permlab_bindRemoteDisplay" msgid="1782923938029941960">"繫結至遠端螢幕"</string>
+ <string name="permdesc_bindRemoteDisplay" msgid="1261242718727295981">"允許應用程式繫結至遠端屏螢的頂層介面 (不建議一般應用程式使用)。"</string>
<string name="permlab_bindRemoteViews" msgid="5697987759897367099">"繫結至小工具服務"</string>
<string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"允許應用程式繫結至小工具服務的頂層介面 (不建議一般應用程式使用)。"</string>
<string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"與裝置管理員互動"</string>
@@ -1489,8 +1491,12 @@
<string name="default_audio_route_category_name" msgid="3722811174003886946">"系統"</string>
<string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"藍牙音頻"</string>
<string name="wireless_display_route_description" msgid="9070346425023979651">"無線螢幕分享"</string>
- <string name="media_route_chooser_grouping_done" msgid="7966438307723317169">"完成"</string>
<string name="media_route_button_content_description" msgid="5758553567065145276">"媒體輸出"</string>
+ <string name="media_route_chooser_title" msgid="1751618554539087622">"連接裝置"</string>
+ <string name="media_route_chooser_title_for_remote_display" msgid="3395541745872017583">"在裝置上放送螢幕"</string>
+ <string name="media_route_chooser_searching" msgid="4776236202610828706">"正在搜尋裝置…"</string>
+ <string name="media_route_chooser_extended_settings" msgid="87015534236701604">"設定"</string>
+ <string name="media_route_controller_disconnect" msgid="8966120286374158649">"停止連接"</string>
<string name="media_route_status_scanning" msgid="7279908761758293783">"正在掃描…"</string>
<string name="media_route_status_connecting" msgid="6422571716007825440">"正在連線..."</string>
<string name="media_route_status_available" msgid="6983258067194649391">"可用"</string>
@@ -1501,8 +1507,10 @@
<string name="display_manager_overlay_display_name" msgid="5142365982271620716">"重疊效果 #<xliff:g id="ID">%1$d</xliff:g>"</string>
<string name="display_manager_overlay_display_title" msgid="652124517672257172">"<xliff:g id="NAME">%1$s</xliff:g>:<xliff:g id="WIDTH">%2$d</xliff:g>x<xliff:g id="HEIGHT">%3$d</xliff:g>,<xliff:g id="DPI">%4$d</xliff:g> dpi"</string>
<string name="display_manager_overlay_display_secure_suffix" msgid="6022119702628572080">"(安全)"</string>
- <string name="wifi_display_notification_title" msgid="2223050649240326557">"已連接無線顯示裝置"</string>
- <string name="wifi_display_notification_message" msgid="4498802012464170685">"這個畫面正在另一部裝置上顯示"</string>
+ <string name="wifi_display_notification_connecting_title" msgid="2838646471050359706">"正在放送螢幕"</string>
+ <string name="wifi_display_notification_connecting_message" msgid="5837350993752841389">"正在連線到「<xliff:g id="NAME">%1$s</xliff:g>」"</string>
+ <string name="wifi_display_notification_connected_title" msgid="8567308065912676285">"正在放送螢幕"</string>
+ <string name="wifi_display_notification_connected_message" msgid="2587209325701109715">"已連線到「<xliff:g id="NAME">%1$s</xliff:g>」"</string>
<string name="wifi_display_notification_disconnect" msgid="6183754463561153372">"中斷連線"</string>
<string name="kg_emergency_call_label" msgid="684946192523830531">"緊急電話"</string>
<string name="kg_forgot_pattern_button_text" msgid="8852021467868220608">"忘記圖案"</string>
diff --git a/core/res/res/values-zh-rTW/strings.xml b/core/res/res/values-zh-rTW/strings.xml
index 8f8ccdd..40d6260 100644
--- a/core/res/res/values-zh-rTW/strings.xml
+++ b/core/res/res/values-zh-rTW/strings.xml
@@ -382,6 +382,8 @@
<string name="permdesc_bindVpnService" msgid="2067845564581693905">"允許應用程式聯繫至 VPN 服務的頂層介面 (一般應用程式不需使用)。"</string>
<string name="permlab_bindWallpaper" msgid="8716400279937856462">"連結至桌布"</string>
<string name="permdesc_bindWallpaper" msgid="7108428692595491668">"允許應用程式繫結至桌布的頂層介面 (一般應用程式不需使用)。"</string>
+ <string name="permlab_bindRemoteDisplay" msgid="1782923938029941960">"繫結至遠端螢幕"</string>
+ <string name="permdesc_bindRemoteDisplay" msgid="1261242718727295981">"允許應用程式繫結至遠端螢幕的頂層介面 (一般應用程式不需使用)。"</string>
<string name="permlab_bindRemoteViews" msgid="5697987759897367099">"繫結至小工具服務"</string>
<string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"允許應用程式繫結至小工具服務的頂層介面 (一般應用程式不需使用)。"</string>
<string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"與裝置管理員互動"</string>
@@ -1489,8 +1491,12 @@
<string name="default_audio_route_category_name" msgid="3722811174003886946">"系統"</string>
<string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"藍牙音訊"</string>
<string name="wireless_display_route_description" msgid="9070346425023979651">"無線螢幕分享"</string>
- <string name="media_route_chooser_grouping_done" msgid="7966438307723317169">"完成"</string>
<string name="media_route_button_content_description" msgid="5758553567065145276">"媒體輸出"</string>
+ <string name="media_route_chooser_title" msgid="1751618554539087622">"連線至裝置"</string>
+ <string name="media_route_chooser_title_for_remote_display" msgid="3395541745872017583">"將螢幕投放到裝置上"</string>
+ <string name="media_route_chooser_searching" msgid="4776236202610828706">"正在搜尋裝置..."</string>
+ <string name="media_route_chooser_extended_settings" msgid="87015534236701604">"設定"</string>
+ <string name="media_route_controller_disconnect" msgid="8966120286374158649">"中斷連線"</string>
<string name="media_route_status_scanning" msgid="7279908761758293783">"掃描中..."</string>
<string name="media_route_status_connecting" msgid="6422571716007825440">"連線中…"</string>
<string name="media_route_status_available" msgid="6983258067194649391">"可以使用"</string>
@@ -1501,8 +1507,10 @@
<string name="display_manager_overlay_display_name" msgid="5142365982271620716">"第 <xliff:g id="ID">%1$d</xliff:g> 個重疊效果"</string>
<string name="display_manager_overlay_display_title" msgid="652124517672257172">"<xliff:g id="NAME">%1$s</xliff:g>:<xliff:g id="WIDTH">%2$d</xliff:g>x<xliff:g id="HEIGHT">%3$d</xliff:g>,<xliff:g id="DPI">%4$d</xliff:g> dpi"</string>
<string name="display_manager_overlay_display_secure_suffix" msgid="6022119702628572080">"(安全)"</string>
- <string name="wifi_display_notification_title" msgid="2223050649240326557">"已連接無線顯示器"</string>
- <string name="wifi_display_notification_message" msgid="4498802012464170685">"其他裝置正在顯示這個畫面"</string>
+ <string name="wifi_display_notification_connecting_title" msgid="2838646471050359706">"正在投放螢幕"</string>
+ <string name="wifi_display_notification_connecting_message" msgid="5837350993752841389">"正在連線至「<xliff:g id="NAME">%1$s</xliff:g>」"</string>
+ <string name="wifi_display_notification_connected_title" msgid="8567308065912676285">"正在投放螢幕"</string>
+ <string name="wifi_display_notification_connected_message" msgid="2587209325701109715">"已連線至「<xliff:g id="NAME">%1$s</xliff:g>」"</string>
<string name="wifi_display_notification_disconnect" msgid="6183754463561153372">"中斷連線"</string>
<string name="kg_emergency_call_label" msgid="684946192523830531">"緊急電話"</string>
<string name="kg_forgot_pattern_button_text" msgid="8852021467868220608">"忘記圖形"</string>
diff --git a/core/res/res/values-zu/strings.xml b/core/res/res/values-zu/strings.xml
index 9f47a5c..563cb3f 100644
--- a/core/res/res/values-zu/strings.xml
+++ b/core/res/res/values-zu/strings.xml
@@ -382,6 +382,8 @@
<string name="permdesc_bindVpnService" msgid="2067845564581693905">"Ivumela umnini ukuthi abophele kwissekelo esingaphezulu sesevisi ye-Vpm. Ayidingakeli izinhlelo zokusebenza ezejwayelekile."</string>
<string name="permlab_bindWallpaper" msgid="8716400279937856462">"hlanganisa kwiphephadonga"</string>
<string name="permdesc_bindWallpaper" msgid="7108428692595491668">"Ivumela umbambi ukuhlanganisa uxhumano nomsebenzisi kwezinga eliphezulu lwephephadonga. Akusoze kwadingeka kwezinhlelo zokusebenza ezivamile."</string>
+ <string name="permlab_bindRemoteDisplay" msgid="1782923938029941960">"bophezela kusibonisi sesilawuli kude"</string>
+ <string name="permdesc_bindRemoteDisplay" msgid="1261242718727295981">"Ivumela umbambi ukuhlanganisa isixhumi esibonakalayo esisezingeni eliphezulu sesibonisi sesilawuli kude. Akumele idingelwe izinhlelo zokusebenza ezijwayelekile."</string>
<string name="permlab_bindRemoteViews" msgid="5697987759897367099">"bophezela kube isevisi yesinqunjana"</string>
<string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"Ivumela umbambi ukuhlanganisa uxhumano nomsebenzisi kwezinga eliphezulu lensizakalo yesinqunjwana. Akusoze kwadingeka kwezinhlelo zokusebenza ezivamile."</string>
<string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"xhumana nomphathi wedivaysi"</string>
@@ -1489,8 +1491,12 @@
<string name="default_audio_route_category_name" msgid="3722811174003886946">"Isistimu"</string>
<string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Umsindo we-Bluetooth"</string>
<string name="wireless_display_route_description" msgid="9070346425023979651">"Ukubonisa okungenazintambo"</string>
- <string name="media_route_chooser_grouping_done" msgid="7966438307723317169">"Qedile"</string>
<string name="media_route_button_content_description" msgid="5758553567065145276">"Okukhiphayo kwemidiya"</string>
+ <string name="media_route_chooser_title" msgid="1751618554539087622">"Xhuma kudivayisi"</string>
+ <string name="media_route_chooser_title_for_remote_display" msgid="3395541745872017583">"Lingisa isikrini kudivayisi"</string>
+ <string name="media_route_chooser_searching" msgid="4776236202610828706">"Isesha amadivayisi…"</string>
+ <string name="media_route_chooser_extended_settings" msgid="87015534236701604">"Izilungiselelo"</string>
+ <string name="media_route_controller_disconnect" msgid="8966120286374158649">"Nqamula"</string>
<string name="media_route_status_scanning" msgid="7279908761758293783">"Iyaskena..."</string>
<string name="media_route_status_connecting" msgid="6422571716007825440">"Iyaxhuma..."</string>
<string name="media_route_status_available" msgid="6983258067194649391">"Kuyatholakala"</string>
@@ -1501,8 +1507,10 @@
<string name="display_manager_overlay_display_name" msgid="5142365982271620716">"Isendlalelo #<xliff:g id="ID">%1$d</xliff:g>"</string>
<string name="display_manager_overlay_display_title" msgid="652124517672257172">"<xliff:g id="NAME">%1$s</xliff:g>: <xliff:g id="WIDTH">%2$d</xliff:g>x<xliff:g id="HEIGHT">%3$d</xliff:g>, <xliff:g id="DPI">%4$d</xliff:g> dpi"</string>
<string name="display_manager_overlay_display_secure_suffix" msgid="6022119702628572080">", kuphephile"</string>
- <string name="wifi_display_notification_title" msgid="2223050649240326557">"Ukubukeka okungenantambo kuxhunyiwe"</string>
- <string name="wifi_display_notification_message" msgid="4498802012464170685">"Lesi sikrini siyabonakala kwenye idivayisi"</string>
+ <string name="wifi_display_notification_connecting_title" msgid="2838646471050359706">"Isikrini sokulingisa"</string>
+ <string name="wifi_display_notification_connecting_message" msgid="5837350993752841389">"Ixhuma ku-<xliff:g id="NAME">%1$s</xliff:g>"</string>
+ <string name="wifi_display_notification_connected_title" msgid="8567308065912676285">"Isikrini sokulingisa"</string>
+ <string name="wifi_display_notification_connected_message" msgid="2587209325701109715">"Kuxhunywe ku-<xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="wifi_display_notification_disconnect" msgid="6183754463561153372">"Nqamula"</string>
<string name="kg_emergency_call_label" msgid="684946192523830531">"Ucingo lwezimo eziphuthumayo"</string>
<string name="kg_forgot_pattern_button_text" msgid="8852021467868220608">"Ukhohlwe iphethini?"</string>
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 18cf57d..b34c792 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -1189,6 +1189,9 @@
<item>12</item> <!-- EVDO_B -->
</integer-array>
+ <!-- Set to true if after a provisioning apn the radio should be restarted -->
+ <bool name="config_restartRadioAfterProvisioning">false</bool>
+
<!-- Vibrator pattern to be used as the default for notifications
that specify DEFAULT_VIBRATE.
-->
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index 62f26c6..9025400a 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -1052,6 +1052,12 @@
interface of a wallpaper. Should never be needed for normal apps.</string>
<!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
+ <string name="permlab_bindRemoteDisplay">bind to a remote display</string>
+ <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
+ <string name="permdesc_bindRemoteDisplay">Allows the holder to bind to the top-level
+ interface of a remote display. Should never be needed for normal apps.</string>
+
+ <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
<string name="permlab_bindRemoteViews">bind to a widget service</string>
<!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
<string name="permdesc_bindRemoteViews">Allows the holder to bind to the top-level
@@ -4090,12 +4096,24 @@
<!-- Description of a wireless display route. [CHAR LIMIT=50] -->
<string name="wireless_display_route_description">Wireless display</string>
- <!-- "Done" button for MediaRouter chooser dialog when grouping routes. [CHAR LIMIT=NONE] -->
- <string name="media_route_chooser_grouping_done">Done</string>
-
<!-- Content description of a MediaRouteButton for accessibility support -->
<string name="media_route_button_content_description">Media output</string>
+ <!-- Title of the media route chooser dialog. [CHAR LIMIT=40] -->
+ <string name="media_route_chooser_title">Connect to device</string>
+
+ <!-- Title of the media route chooser dialog for selecting remote display routes. [CHAR LIMIT=40] -->
+ <string name="media_route_chooser_title_for_remote_display">Cast screen to device</string>
+
+ <!-- Placeholder text to show when no devices have been found. [CHAR LIMIT=50] -->
+ <string name="media_route_chooser_searching">Searching for devices\u2026</string>
+
+ <!-- Button to access extended settings. [CHAR LIMIT=30] -->
+ <string name="media_route_chooser_extended_settings">Settings</string>
+
+ <!-- Button to disconnect from a media route. [CHAR LIMIT=30] -->
+ <string name="media_route_controller_disconnect">Disconnect</string>
+
<!-- Status message for remote routes attempting to scan/determine availability -->
<string name="media_route_status_scanning">Scanning...</string>
@@ -4128,10 +4146,14 @@
<!-- Title text to append when the display is secure. [CHAR LIMIT=30] -->
<string name="display_manager_overlay_display_secure_suffix">, secure</string>
+ <!-- Title of the notification to indicate the process of connecting to a wifi display. [CHAR LIMIT=50] -->
+ <string name="wifi_display_notification_connecting_title">Casting screen</string>
+ <!-- Message of the notification to indicate the process of connecting to a wifi display. [CHAR LIMIT=80] -->
+ <string name="wifi_display_notification_connecting_message">Connecting to <xliff:g id="name">%1$s</xliff:g></string>
<!-- Title of the notification to indicate an active wifi display connection. [CHAR LIMIT=50] -->
- <string name="wifi_display_notification_title">Wireless display is connected</string>
+ <string name="wifi_display_notification_connected_title">Casting screen</string>
<!-- Message of the notification to indicate an active wifi display connection. [CHAR LIMIT=80] -->
- <string name="wifi_display_notification_message">This screen is showing on another device</string>
+ <string name="wifi_display_notification_connected_message">Connected to <xliff:g id="name">%1$s</xliff:g></string>
<!-- Label of a button to disconnect an active wifi display connection. [CHAR LIMIT=25] -->
<string name="wifi_display_notification_disconnect">Disconnect</string>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index b85bff4..6d90973 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -283,6 +283,7 @@
<java-symbol type="bool" name="config_safe_media_volume_enabled" />
<java-symbol type="bool" name="config_camera_sound_forced" />
<java-symbol type="bool" name="config_dontPreferApn" />
+ <java-symbol type="bool" name="config_restartRadioAfterProvisioning" />
<java-symbol type="bool" name="config_speed_up_audio_on_mt_calls" />
<java-symbol type="bool" name="config_useFixedVolume" />
<java-symbol type="bool" name="config_forceDefaultOrientation" />
@@ -1096,7 +1097,11 @@
<java-symbol type="drawable" name="notification_template_icon_bg" />
<java-symbol type="drawable" name="notification_template_icon_low_bg" />
<java-symbol type="drawable" name="ic_media_route_on_holo_dark" />
+ <java-symbol type="drawable" name="ic_media_route_off_holo_dark" />
+ <java-symbol type="drawable" name="ic_media_route_connecting_holo_dark" />
<java-symbol type="drawable" name="ic_media_route_disabled_holo_dark" />
+ <java-symbol type="drawable" name="ic_notification_cast_connecting" />
+ <java-symbol type="drawable" name="ic_notification_cast_on" />
<java-symbol type="drawable" name="cling_button" />
<java-symbol type="drawable" name="cling_arrow_up" />
<java-symbol type="drawable" name="cling_bg" />
@@ -1253,17 +1258,17 @@
<java-symbol type="attr" name="mediaRouteButtonStyle" />
<java-symbol type="attr" name="externalRouteEnabledDrawable" />
- <java-symbol type="id" name="extended_settings" />
- <java-symbol type="id" name="check" />
- <java-symbol type="id" name="volume_slider" />
- <java-symbol type="id" name="volume_icon" />
- <java-symbol type="drawable" name="ic_media_route_on_holo_dark" />
- <java-symbol type="layout" name="media_route_chooser_layout" />
- <java-symbol type="layout" name="media_route_list_item_top_header" />
- <java-symbol type="layout" name="media_route_list_item_section_header" />
+ <java-symbol type="layout" name="media_route_chooser_dialog" />
+ <java-symbol type="layout" name="media_route_controller_dialog" />
<java-symbol type="layout" name="media_route_list_item" />
- <java-symbol type="layout" name="media_route_list_item_checkable" />
- <java-symbol type="layout" name="media_route_list_item_collapse_group" />
+ <java-symbol type="id" name="media_route_list" />
+ <java-symbol type="id" name="media_route_volume_layout" />
+ <java-symbol type="id" name="media_route_volume_slider" />
+ <java-symbol type="id" name="media_route_control_frame" />
+ <java-symbol type="id" name="media_route_disconnect_button" />
+ <java-symbol type="id" name="media_route_extended_settings_button" />
+ <java-symbol type="string" name="media_route_chooser_title" />
+ <java-symbol type="string" name="media_route_chooser_title_for_remote_display" />
<java-symbol type="string" name="bluetooth_a2dp_audio_route_name" />
<java-symbol type="dimen" name="config_minScalingSpan" />
@@ -1451,7 +1456,6 @@
<java-symbol type="color" name="config_defaultNotificationColor" />
<java-symbol type="color" name="input_method_navigation_guard" />
<java-symbol type="drawable" name="ic_notification_ime_default" />
- <java-symbol type="drawable" name="ic_notify_wifidisplay" />
<java-symbol type="drawable" name="ic_menu_refresh" />
<java-symbol type="drawable" name="stat_notify_car_mode" />
<java-symbol type="drawable" name="stat_notify_disabled" />
@@ -1594,8 +1598,10 @@
<java-symbol type="string" name="vpn_lockdown_error" />
<java-symbol type="string" name="vpn_lockdown_config" />
<java-symbol type="string" name="wallpaper_binding_label" />
- <java-symbol type="string" name="wifi_display_notification_title" />
- <java-symbol type="string" name="wifi_display_notification_message" />
+ <java-symbol type="string" name="wifi_display_notification_connecting_title" />
+ <java-symbol type="string" name="wifi_display_notification_connecting_message" />
+ <java-symbol type="string" name="wifi_display_notification_connected_title" />
+ <java-symbol type="string" name="wifi_display_notification_connected_message" />
<java-symbol type="string" name="wifi_display_notification_disconnect" />
<java-symbol type="style" name="Theme.Dialog.AppError" />
<java-symbol type="style" name="Theme.Toast" />
diff --git a/core/res/res/xml/power_profile.xml b/core/res/res/xml/power_profile.xml
index 7af3b9c..3215e17 100644
--- a/core/res/res/xml/power_profile.xml
+++ b/core/res/res/xml/power_profile.xml
@@ -58,4 +58,12 @@
</array>
<!-- This is the battery capacity in mAh (measured at nominal voltage) -->
<item name="battery.capacity">1000</item>
+
+ <array name="wifi.batchedscan"> <!-- mA -->
+ <value>.0002</value> <!-- 1-8/hr -->
+ <value>.002</value> <!-- 9-64/hr -->
+ <value>.02</value> <!-- 65-512/hr -->
+ <value>.2</value> <!-- 513-4,096/hr -->
+ <value>2</value> <!-- 4097-/hr -->
+ </array>
</device>
diff --git a/core/tests/bandwidthtests/src/com/android/bandwidthtest/BandwidthTest.java b/core/tests/bandwidthtests/src/com/android/bandwidthtest/BandwidthTest.java
index 76b702e..4a58f88 100644
--- a/core/tests/bandwidthtests/src/com/android/bandwidthtest/BandwidthTest.java
+++ b/core/tests/bandwidthtests/src/com/android/bandwidthtest/BandwidthTest.java
@@ -36,8 +36,6 @@
import com.android.bandwidthtest.util.ConnectionUtil;
import java.io.File;
-import java.util.HashMap;
-import java.util.Map;
/**
* Test that downloads files from a test server and reports the bandwidth metrics collected.
@@ -131,8 +129,8 @@
results.putString("device_id", mDeviceId);
results.putString("timestamp", ts);
results.putInt("size", FILE_SIZE);
- AddStatsToResults(PROF_LABEL, prof_stats, results);
- AddStatsToResults(PROC_LABEL, proc_stats, results);
+ addStatsToResults(PROF_LABEL, prof_stats, results, mUid);
+ addStatsToResults(PROC_LABEL, proc_stats, results, mUid);
getInstrumentation().sendStatus(INSTRUMENTATION_IN_PROGRESS, results);
// Clean up.
@@ -185,8 +183,8 @@
results.putString("device_id", mDeviceId);
results.putString("timestamp", ts);
results.putInt("size", FILE_SIZE);
- AddStatsToResults(PROF_LABEL, prof_stats, results);
- AddStatsToResults(PROC_LABEL, proc_stats, results);
+ addStatsToResults(PROF_LABEL, prof_stats, results, mUid);
+ addStatsToResults(PROC_LABEL, proc_stats, results, mUid);
getInstrumentation().sendStatus(INSTRUMENTATION_IN_PROGRESS, results);
// Clean up.
@@ -242,8 +240,9 @@
results.putString("device_id", mDeviceId);
results.putString("timestamp", ts);
results.putInt("size", FILE_SIZE);
- AddStatsToResults(PROF_LABEL, prof_stats, results);
- AddStatsToResults(PROC_LABEL, proc_stats, results);
+ addStatsToResults(PROF_LABEL, prof_stats, results, mUid);
+ // remember to use download manager uid for proc stats
+ addStatsToResults(PROC_LABEL, proc_stats, results, downloadManagerUid);
getInstrumentation().sendStatus(INSTRUMENTATION_IN_PROGRESS, results);
// Clean up.
@@ -302,46 +301,35 @@
* @param label to attach to this given stats.
* @param stats {@link NetworkStats} to add.
* @param results {@link Bundle} to be added to.
+ * @param uid for which to report the results.
*/
- public void AddStatsToResults(String label, NetworkStats stats, Bundle results){
+ public void addStatsToResults(String label, NetworkStats stats, Bundle results, int uid){
if (results == null || results.isEmpty()) {
Log.e(LOG_TAG, "Empty bundle provided.");
return;
}
- // Merge stats across all sets.
- Map<Integer, Entry> totalStats = new HashMap<Integer, Entry>();
+ Entry totalStats = null;
for (int i = 0; i < stats.size(); ++i) {
Entry statsEntry = stats.getValues(i, null);
// We are only interested in the all inclusive stats.
if (statsEntry.tag != 0) {
continue;
}
- Entry mapEntry = null;
- if (totalStats.containsKey(statsEntry.uid)) {
- mapEntry = totalStats.get(statsEntry.uid);
- switch (statsEntry.set) {
- case NetworkStats.SET_ALL:
- mapEntry.rxBytes = statsEntry.rxBytes;
- mapEntry.txBytes = statsEntry.txBytes;
- break;
- case NetworkStats.SET_DEFAULT:
- case NetworkStats.SET_FOREGROUND:
- mapEntry.rxBytes += statsEntry.rxBytes;
- mapEntry.txBytes += statsEntry.txBytes;
- break;
- default:
- Log.w(LOG_TAG, "Invalid state found in NetworkStats.");
- }
+ // skip stats for other uids
+ if (statsEntry.uid != uid) {
+ continue;
+ }
+ if (totalStats == null || statsEntry.set == NetworkStats.SET_ALL) {
+ totalStats = statsEntry;
} else {
- totalStats.put(statsEntry.uid, statsEntry);
+ totalStats.rxBytes += statsEntry.rxBytes;
+ totalStats.txBytes += statsEntry.txBytes;
}
}
- // Ouput merged stats to bundle.
- for (Entry entry : totalStats.values()) {
- results.putInt(label + "uid", entry.uid);
- results.putLong(label + "tx", entry.txBytes);
- results.putLong(label + "rx", entry.rxBytes);
- }
+ // Output merged stats to bundle.
+ results.putInt(label + "uid", totalStats.uid);
+ results.putLong(label + "tx", totalStats.txBytes);
+ results.putLong(label + "rx", totalStats.rxBytes);
}
/**
diff --git a/data/sounds/AudioPackage10.mk b/data/sounds/AudioPackage10.mk
index 783e1f8..ae4bc88 100644
--- a/data/sounds/AudioPackage10.mk
+++ b/data/sounds/AudioPackage10.mk
@@ -17,19 +17,19 @@
$(LOCAL_PATH)/alarms/ogg/Osmium.ogg:system/media/audio/alarms/Osmium.ogg \
$(LOCAL_PATH)/alarms/ogg/Platinum.ogg:system/media/audio/alarms/Platinum.ogg \
$(LOCAL_PATH)/effects/ogg/Effect_Tick_48k.ogg:system/media/audio/ui/Effect_Tick.ogg \
- $(LOCAL_PATH)/effects/ogg/KeypressStandard_120_48k.ogg:system/media/audio/ui/KeypressStandard.ogg \
- $(LOCAL_PATH)/effects/ogg/KeypressSpacebar_120_48k.ogg:system/media/audio/ui/KeypressSpacebar.ogg \
- $(LOCAL_PATH)/effects/ogg/KeypressDelete_120_48k.ogg:system/media/audio/ui/KeypressDelete.ogg \
- $(LOCAL_PATH)/effects/ogg/KeypressInvalid_120_48k.ogg:system/media/audio/ui/KeypressInvalid.ogg \
- $(LOCAL_PATH)/effects/ogg/KeypressReturn_120_48k.ogg:system/media/audio/ui/KeypressReturn.ogg \
+ $(LOCAL_PATH)/effects/ogg/KeypressStandard_48k.ogg:system/media/audio/ui/KeypressStandard.ogg \
+ $(LOCAL_PATH)/effects/ogg/KeypressSpacebar_48k.ogg:system/media/audio/ui/KeypressSpacebar.ogg \
+ $(LOCAL_PATH)/effects/ogg/KeypressDelete_48k.ogg:system/media/audio/ui/KeypressDelete.ogg \
+ $(LOCAL_PATH)/effects/ogg/KeypressInvalid_48k.ogg:system/media/audio/ui/KeypressInvalid.ogg \
+ $(LOCAL_PATH)/effects/ogg/KeypressReturn_48k.ogg:system/media/audio/ui/KeypressReturn.ogg \
$(LOCAL_PATH)/effects/ogg/VideoRecord_48k.ogg:system/media/audio/ui/VideoRecord.ogg \
$(LOCAL_PATH)/effects/ogg/camera_click_48k.ogg:system/media/audio/ui/camera_click.ogg \
$(LOCAL_PATH)/effects/ogg/camera_focus.ogg:system/media/audio/ui/camera_focus.ogg \
$(LOCAL_PATH)/effects/ogg/LowBattery.ogg:system/media/audio/ui/LowBattery.ogg \
$(LOCAL_PATH)/effects/ogg/Dock.ogg:system/media/audio/ui/Dock.ogg \
$(LOCAL_PATH)/effects/ogg/Undock.ogg:system/media/audio/ui/Undock.ogg \
- $(LOCAL_PATH)/effects/ogg/Lock.ogg:system/media/audio/ui/Lock.ogg \
- $(LOCAL_PATH)/effects/ogg/Unlock.ogg:system/media/audio/ui/Unlock.ogg \
+ $(LOCAL_PATH)/effects/ogg/Lock_48k.ogg:system/media/audio/ui/Lock.ogg \
+ $(LOCAL_PATH)/effects/ogg/Unlock_48k.ogg:system/media/audio/ui/Unlock.ogg \
$(LOCAL_PATH)/effects/ogg/WirelessChargingStarted.ogg:system/media/audio/ui/WirelessChargingStarted.ogg \
$(LOCAL_PATH)/notifications/ogg/Adara.ogg:system/media/audio/notifications/Adara.ogg \
$(LOCAL_PATH)/notifications/ogg/Alya.ogg:system/media/audio/notifications/Alya.ogg \
diff --git a/data/sounds/AudioPackage11.mk b/data/sounds/AudioPackage11.mk
index b30be56..3c09297 100644
--- a/data/sounds/AudioPackage11.mk
+++ b/data/sounds/AudioPackage11.mk
@@ -17,19 +17,19 @@
$(LOCAL_PATH)/alarms/ogg/Osmium.ogg:system/media/audio/alarms/Osmium.ogg \
$(LOCAL_PATH)/alarms/ogg/Platinum.ogg:system/media/audio/alarms/Platinum.ogg \
$(LOCAL_PATH)/effects/ogg/Effect_Tick_48k.ogg:system/media/audio/ui/Effect_Tick.ogg \
- $(LOCAL_PATH)/effects/ogg/KeypressStandard_120_48k.ogg:system/media/audio/ui/KeypressStandard.ogg \
- $(LOCAL_PATH)/effects/ogg/KeypressSpacebar_120_48k.ogg:system/media/audio/ui/KeypressSpacebar.ogg \
- $(LOCAL_PATH)/effects/ogg/KeypressDelete_120_48k.ogg:system/media/audio/ui/KeypressDelete.ogg \
- $(LOCAL_PATH)/effects/ogg/KeypressInvalid_120_48k.ogg:system/media/audio/ui/KeypressInvalid.ogg \
- $(LOCAL_PATH)/effects/ogg/KeypressReturn_120_48k.ogg:system/media/audio/ui/KeypressReturn.ogg \
+ $(LOCAL_PATH)/effects/ogg/KeypressStandard_48k.ogg:system/media/audio/ui/KeypressStandard.ogg \
+ $(LOCAL_PATH)/effects/ogg/KeypressSpacebar_48k.ogg:system/media/audio/ui/KeypressSpacebar.ogg \
+ $(LOCAL_PATH)/effects/ogg/KeypressDelete_48k.ogg:system/media/audio/ui/KeypressDelete.ogg \
+ $(LOCAL_PATH)/effects/ogg/KeypressInvalid_48k.ogg:system/media/audio/ui/KeypressInvalid.ogg \
+ $(LOCAL_PATH)/effects/ogg/KeypressReturn_48k.ogg:system/media/audio/ui/KeypressReturn.ogg \
$(LOCAL_PATH)/effects/ogg/VideoRecord_48k.ogg:system/media/audio/ui/VideoRecord.ogg \
$(LOCAL_PATH)/effects/ogg/camera_click_48k.ogg:system/media/audio/ui/camera_click.ogg \
$(LOCAL_PATH)/effects/ogg/camera_focus.ogg:system/media/audio/ui/camera_focus.ogg \
$(LOCAL_PATH)/effects/ogg/LowBattery.ogg:system/media/audio/ui/LowBattery.ogg \
$(LOCAL_PATH)/effects/ogg/Dock.ogg:system/media/audio/ui/Dock.ogg \
$(LOCAL_PATH)/effects/ogg/Undock.ogg:system/media/audio/ui/Undock.ogg \
- $(LOCAL_PATH)/effects/ogg/Lock.ogg:system/media/audio/ui/Lock.ogg \
- $(LOCAL_PATH)/effects/ogg/Unlock.ogg:system/media/audio/ui/Unlock.ogg \
+ $(LOCAL_PATH)/effects/ogg/Lock_48k.ogg:system/media/audio/ui/Lock.ogg \
+ $(LOCAL_PATH)/effects/ogg/Unlock_48k.ogg:system/media/audio/ui/Unlock.ogg \
$(LOCAL_PATH)/effects/ogg/WirelessChargingStarted.ogg:system/media/audio/ui/WirelessChargingStarted.ogg \
$(LOCAL_PATH)/notifications/ogg/Adara.ogg:system/media/audio/notifications/Adara.ogg \
$(LOCAL_PATH)/notifications/ogg/Alya.ogg:system/media/audio/notifications/Alya.ogg \
diff --git a/data/sounds/AudioPackage8.mk b/data/sounds/AudioPackage8.mk
index 49b6154..0f4b8ad 100644
--- a/data/sounds/AudioPackage8.mk
+++ b/data/sounds/AudioPackage8.mk
@@ -17,11 +17,11 @@
$(LOCAL_PATH)/alarms/ogg/Plutonium.ogg:system/media/audio/alarms/Plutonium.ogg \
$(LOCAL_PATH)/alarms/ogg/Promethium.ogg:system/media/audio/alarms/Promethium.ogg \
$(LOCAL_PATH)/effects/ogg/Effect_Tick.ogg:system/media/audio/ui/Effect_Tick.ogg \
- $(LOCAL_PATH)/effects/ogg/KeypressStandard_120.ogg:system/media/audio/ui/KeypressStandard.ogg \
- $(LOCAL_PATH)/effects/ogg/KeypressSpacebar_120.ogg:system/media/audio/ui/KeypressSpacebar.ogg \
- $(LOCAL_PATH)/effects/ogg/KeypressDelete_120.ogg:system/media/audio/ui/KeypressDelete.ogg \
- $(LOCAL_PATH)/effects/ogg/KeypressInvalid_120.ogg:system/media/audio/ui/KeypressInvalid.ogg \
- $(LOCAL_PATH)/effects/ogg/KeypressReturn_120.ogg:system/media/audio/ui/KeypressReturn.ogg \
+ $(LOCAL_PATH)/effects/ogg/KeypressStandard.ogg:system/media/audio/ui/KeypressStandard.ogg \
+ $(LOCAL_PATH)/effects/ogg/KeypressSpacebar.ogg:system/media/audio/ui/KeypressSpacebar.ogg \
+ $(LOCAL_PATH)/effects/ogg/KeypressDelete.ogg:system/media/audio/ui/KeypressDelete.ogg \
+ $(LOCAL_PATH)/effects/ogg/KeypressInvalid.ogg:system/media/audio/ui/KeypressInvalid.ogg \
+ $(LOCAL_PATH)/effects/ogg/KeypressReturn.ogg:system/media/audio/ui/KeypressReturn.ogg \
$(LOCAL_PATH)/effects/ogg/VideoRecord.ogg:system/media/audio/ui/VideoRecord.ogg \
$(LOCAL_PATH)/effects/ogg/camera_click.ogg:system/media/audio/ui/camera_click.ogg \
$(LOCAL_PATH)/effects/ogg/camera_focus.ogg:system/media/audio/ui/camera_focus.ogg \
diff --git a/data/sounds/AudioPackage9.mk b/data/sounds/AudioPackage9.mk
index 87b7764..36dc921 100644
--- a/data/sounds/AudioPackage9.mk
+++ b/data/sounds/AudioPackage9.mk
@@ -17,11 +17,11 @@
$(LOCAL_PATH)/alarms/ogg/Osmium.ogg:system/media/audio/alarms/Osmium.ogg \
$(LOCAL_PATH)/alarms/ogg/Platinum.ogg:system/media/audio/alarms/Platinum.ogg \
$(LOCAL_PATH)/effects/ogg/Effect_Tick.ogg:system/media/audio/ui/Effect_Tick.ogg \
- $(LOCAL_PATH)/effects/ogg/KeypressStandard_120.ogg:system/media/audio/ui/KeypressStandard.ogg \
- $(LOCAL_PATH)/effects/ogg/KeypressSpacebar_120.ogg:system/media/audio/ui/KeypressSpacebar.ogg \
- $(LOCAL_PATH)/effects/ogg/KeypressDelete_120.ogg:system/media/audio/ui/KeypressDelete.ogg \
- $(LOCAL_PATH)/effects/ogg/KeypressInvalid_120.ogg:system/media/audio/ui/KeypressInvalid.ogg \
- $(LOCAL_PATH)/effects/ogg/KeypressReturn_120.ogg:system/media/audio/ui/KeypressReturn.ogg \
+ $(LOCAL_PATH)/effects/ogg/KeypressStandard.ogg:system/media/audio/ui/KeypressStandard.ogg \
+ $(LOCAL_PATH)/effects/ogg/KeypressSpacebar.ogg:system/media/audio/ui/KeypressSpacebar.ogg \
+ $(LOCAL_PATH)/effects/ogg/KeypressDelete.ogg:system/media/audio/ui/KeypressDelete.ogg \
+ $(LOCAL_PATH)/effects/ogg/KeypressInvalid.ogg:system/media/audio/ui/KeypressInvalid.ogg \
+ $(LOCAL_PATH)/effects/ogg/KeypressReturn.ogg:system/media/audio/ui/KeypressReturn.ogg \
$(LOCAL_PATH)/effects/ogg/VideoRecord.ogg:system/media/audio/ui/VideoRecord.ogg \
$(LOCAL_PATH)/effects/ogg/camera_click.ogg:system/media/audio/ui/camera_click.ogg \
$(LOCAL_PATH)/effects/ogg/camera_focus.ogg:system/media/audio/ui/camera_focus.ogg \
diff --git a/data/sounds/notifications/ogg/Tethys_48k.ogg b/data/sounds/notifications/ogg/Tethys_48k.ogg
index a9d8bbd..355d522 100644
--- a/data/sounds/notifications/ogg/Tethys_48k.ogg
+++ b/data/sounds/notifications/ogg/Tethys_48k.ogg
Binary files differ
diff --git a/graphics/java/android/graphics/drawable/DrawableContainer.java b/graphics/java/android/graphics/drawable/DrawableContainer.java
index af8441a..aac7876 100644
--- a/graphics/java/android/graphics/drawable/DrawableContainer.java
+++ b/graphics/java/android/graphics/drawable/DrawableContainer.java
@@ -88,9 +88,10 @@
@Override
public boolean getPadding(Rect padding) {
final Rect r = mDrawableContainerState.getConstantPadding();
- boolean result = true;
+ boolean result;
if (r != null) {
padding.set(r);
+ result = (r.left | r.top | r.bottom | r.right) != 0;
} else {
if (mCurrDrawable != null) {
result = mCurrDrawable.getPadding(padding);
diff --git a/graphics/java/android/graphics/drawable/NinePatchDrawable.java b/graphics/java/android/graphics/drawable/NinePatchDrawable.java
index ab34c0f..9c57a2c 100644
--- a/graphics/java/android/graphics/drawable/NinePatchDrawable.java
+++ b/graphics/java/android/graphics/drawable/NinePatchDrawable.java
@@ -244,7 +244,7 @@
} else {
padding.set(mPadding);
}
- return true;
+ return (padding.left | padding.top | padding.right | padding.bottom) != 0;
}
/**
diff --git a/media/java/android/media/IMediaRouterClient.aidl b/media/java/android/media/IMediaRouterClient.aidl
new file mode 100644
index 0000000..9640dcb
--- /dev/null
+++ b/media/java/android/media/IMediaRouterClient.aidl
@@ -0,0 +1,24 @@
+/*
+ * Copyright (C) 2013 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.media;
+
+/**
+ * {@hide}
+ */
+oneway interface IMediaRouterClient {
+ void onStateChanged();
+}
diff --git a/media/java/android/media/IMediaRouterService.aidl b/media/java/android/media/IMediaRouterService.aidl
new file mode 100644
index 0000000..f8f5fdf
--- /dev/null
+++ b/media/java/android/media/IMediaRouterService.aidl
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2013 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.media;
+
+import android.media.IMediaRouterClient;
+import android.media.MediaRouterClientState;
+
+/**
+ * {@hide}
+ */
+interface IMediaRouterService {
+ void registerClientAsUser(IMediaRouterClient client, String packageName, int userId);
+ void unregisterClient(IMediaRouterClient client);
+
+ MediaRouterClientState getState(IMediaRouterClient client);
+
+ void setDiscoveryRequest(IMediaRouterClient client, int routeTypes, boolean activeScan);
+ void setSelectedRoute(IMediaRouterClient client, String routeId, boolean explicit);
+ void requestSetVolume(IMediaRouterClient client, String routeId, int volume);
+ void requestUpdateVolume(IMediaRouterClient client, String routeId, int direction);
+}
diff --git a/media/java/android/media/IRemoteDisplayCallback.aidl b/media/java/android/media/IRemoteDisplayCallback.aidl
new file mode 100644
index 0000000..19cf070
--- /dev/null
+++ b/media/java/android/media/IRemoteDisplayCallback.aidl
@@ -0,0 +1,26 @@
+/*
+ * Copyright (C) 2013 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.media;
+
+import android.media.RemoteDisplayState;
+
+/**
+ * {@hide}
+ */
+oneway interface IRemoteDisplayCallback {
+ void onStateChanged(in RemoteDisplayState state);
+}
diff --git a/media/java/android/media/IRemoteDisplayProvider.aidl b/media/java/android/media/IRemoteDisplayProvider.aidl
new file mode 100644
index 0000000..b0d7379
--- /dev/null
+++ b/media/java/android/media/IRemoteDisplayProvider.aidl
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2013 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.media;
+
+import android.media.IRemoteDisplayCallback;
+
+/**
+ * {@hide}
+ */
+oneway interface IRemoteDisplayProvider {
+ void setCallback(in IRemoteDisplayCallback callback);
+ void setDiscoveryMode(int mode);
+ void connect(String id);
+ void disconnect(String id);
+ void setVolume(String id, int volume);
+ void adjustVolume(String id, int delta);
+}
diff --git a/media/java/android/media/MediaFocusControl.java b/media/java/android/media/MediaFocusControl.java
index 59d411d..34008bb 100644
--- a/media/java/android/media/MediaFocusControl.java
+++ b/media/java/android/media/MediaFocusControl.java
@@ -1930,7 +1930,6 @@
int rccId = RemoteControlClient.RCSE_ID_UNREGISTERED;
synchronized(mAudioFocusLock) {
synchronized(mRCStack) {
- boolean wasCurrentRcController = isCurrentRcController(mediaIntent);
// store the new display information
try {
for (int index = mRCStack.size()-1; index >= 0; index--) {
@@ -1977,9 +1976,9 @@
Log.e(TAG, "Wrong index accessing RC stack, lock error? ", e);
}
- // if the eventReceiver is now at the top of the stack but wasn't before
+ // if the eventReceiver is at the top of the stack
// then check for potential refresh of the remote controls
- if (isCurrentRcController(mediaIntent) && !wasCurrentRcController) {
+ if (isCurrentRcController(mediaIntent)) {
checkUpdateRemoteControlDisplay_syncAfRcs(RC_INFO_ALL);
}
}//synchronized(mRCStack)
diff --git a/media/java/android/media/MediaRouter.java b/media/java/android/media/MediaRouter.java
index 9a79c94..525dc4f 100644
--- a/media/java/android/media/MediaRouter.java
+++ b/media/java/android/media/MediaRouter.java
@@ -16,11 +16,15 @@
package android.media;
+import com.android.internal.util.Objects;
+
+import android.Manifest;
import android.app.ActivityThread;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
+import android.content.pm.PackageManager;
import android.content.res.Resources;
import android.graphics.drawable.Drawable;
import android.hardware.display.DisplayManager;
@@ -28,8 +32,10 @@
import android.hardware.display.WifiDisplayStatus;
import android.os.Handler;
import android.os.IBinder;
+import android.os.Process;
import android.os.RemoteException;
import android.os.ServiceManager;
+import android.os.UserHandle;
import android.text.TextUtils;
import android.util.Log;
import android.view.Display;
@@ -52,14 +58,17 @@
*/
public class MediaRouter {
private static final String TAG = "MediaRouter";
+ private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
static class Static implements DisplayManager.DisplayListener {
// Time between wifi display scans when actively scanning in milliseconds.
- private static final int WIFI_DISPLAY_SCAN_INTERVAL = 15000;
+ private static final int WIFI_DISPLAY_SCAN_INTERVAL = 10000;
+ final Context mAppContext;
final Resources mResources;
final IAudioService mAudioService;
final DisplayManager mDisplayService;
+ final IMediaRouterService mMediaRouterService;
final Handler mHandler;
final CopyOnWriteArrayList<CallbackInfo> mCallbacks =
new CopyOnWriteArrayList<CallbackInfo>();
@@ -76,9 +85,16 @@
RouteInfo mSelectedRoute;
- WifiDisplayStatus mLastKnownWifiDisplayStatus;
+ final boolean mCanConfigureWifiDisplays;
boolean mActivelyScanningWifiDisplays;
+ int mDiscoveryRequestRouteTypes;
+ boolean mDiscoverRequestActiveScan;
+
+ int mCurrentUserId = -1;
+ IMediaRouterClient mClient;
+ MediaRouterClientState mClientState;
+
final IAudioRoutesObserver.Stub mAudioRoutesObserver = new IAudioRoutesObserver.Stub() {
@Override
public void dispatchAudioRoutesChanged(final AudioRoutesInfo newRoutes) {
@@ -101,6 +117,7 @@
};
Static(Context appContext) {
+ mAppContext = appContext;
mResources = Resources.getSystem();
mHandler = new Handler(appContext.getMainLooper());
@@ -109,10 +126,20 @@
mDisplayService = (DisplayManager) appContext.getSystemService(Context.DISPLAY_SERVICE);
+ mMediaRouterService = IMediaRouterService.Stub.asInterface(
+ ServiceManager.getService(Context.MEDIA_ROUTER_SERVICE));
+
mSystemCategory = new RouteCategory(
com.android.internal.R.string.default_audio_route_category_name,
ROUTE_TYPE_LIVE_AUDIO | ROUTE_TYPE_LIVE_VIDEO, false);
mSystemCategory.mIsSystem = true;
+
+ // Only the system can configure wifi displays. The display manager
+ // enforces this with a permission check. Set a flag here so that we
+ // know whether this process is actually allowed to scan and connect.
+ mCanConfigureWifiDisplays = appContext.checkPermission(
+ Manifest.permission.CONFIGURE_WIFI_DISPLAY,
+ Process.myPid(), Process.myUid()) == PackageManager.PERMISSION_GRANTED;
}
// Called after sStatic is initialized
@@ -120,8 +147,7 @@
mDefaultAudioVideo = new RouteInfo(mSystemCategory);
mDefaultAudioVideo.mNameResId = com.android.internal.R.string.default_audio_route_name;
mDefaultAudioVideo.mSupportedTypes = ROUTE_TYPE_LIVE_AUDIO | ROUTE_TYPE_LIVE_VIDEO;
- mDefaultAudioVideo.mPresentationDisplay = choosePresentationDisplayForRoute(
- mDefaultAudioVideo, getAllPresentationDisplays());
+ mDefaultAudioVideo.updatePresentationDisplay();
addRouteStatic(mDefaultAudioVideo);
// This will select the active wifi display route if there is one.
@@ -146,10 +172,13 @@
updateAudioRoutes(newAudioRoutes);
}
+ // Bind to the media router service.
+ rebindAsUser(UserHandle.myUserId());
+
// Select the default route if the above didn't sync us up
// appropriately with relevant system state.
if (mSelectedRoute == null) {
- selectRouteStatic(mDefaultAudioVideo.getSupportedTypes(), mDefaultAudioVideo);
+ selectDefaultRouteStatic();
}
}
@@ -197,7 +226,7 @@
dispatchRouteChanged(sStatic.mBluetoothA2dpRoute);
}
} else if (sStatic.mBluetoothA2dpRoute != null) {
- removeRoute(sStatic.mBluetoothA2dpRoute);
+ removeRouteStatic(sStatic.mBluetoothA2dpRoute);
sStatic.mBluetoothA2dpRoute = null;
}
}
@@ -205,16 +234,52 @@
if (mBluetoothA2dpRoute != null) {
if (mainType != AudioRoutesInfo.MAIN_SPEAKER &&
mSelectedRoute == mBluetoothA2dpRoute && !a2dpEnabled) {
- selectRouteStatic(ROUTE_TYPE_LIVE_AUDIO, mDefaultAudioVideo);
+ selectRouteStatic(ROUTE_TYPE_LIVE_AUDIO, mDefaultAudioVideo, false);
} else if ((mSelectedRoute == mDefaultAudioVideo || mSelectedRoute == null) &&
a2dpEnabled) {
- selectRouteStatic(ROUTE_TYPE_LIVE_AUDIO, mBluetoothA2dpRoute);
+ selectRouteStatic(ROUTE_TYPE_LIVE_AUDIO, mBluetoothA2dpRoute, false);
}
}
}
- void updateActiveScan() {
- if (hasActiveScanCallbackOfType(ROUTE_TYPE_LIVE_VIDEO)) {
+ void updateDiscoveryRequest() {
+ // What are we looking for today?
+ int routeTypes = 0;
+ int passiveRouteTypes = 0;
+ boolean activeScan = false;
+ boolean activeScanWifiDisplay = false;
+ final int count = mCallbacks.size();
+ for (int i = 0; i < count; i++) {
+ CallbackInfo cbi = mCallbacks.get(i);
+ if ((cbi.flags & (CALLBACK_FLAG_PERFORM_ACTIVE_SCAN
+ | CALLBACK_FLAG_REQUEST_DISCOVERY)) != 0) {
+ // Discovery explicitly requested.
+ routeTypes |= cbi.type;
+ } else if ((cbi.flags & CALLBACK_FLAG_PASSIVE_DISCOVERY) != 0) {
+ // Discovery only passively requested.
+ passiveRouteTypes |= cbi.type;
+ } else {
+ // Legacy case since applications don't specify the discovery flag.
+ // Unfortunately we just have to assume they always need discovery
+ // whenever they have a callback registered.
+ routeTypes |= cbi.type;
+ }
+ if ((cbi.flags & CALLBACK_FLAG_PERFORM_ACTIVE_SCAN) != 0) {
+ activeScan = true;
+ if ((cbi.type & ROUTE_TYPE_REMOTE_DISPLAY) != 0) {
+ activeScanWifiDisplay = true;
+ }
+ }
+ }
+ if (routeTypes != 0 || activeScan) {
+ // If someone else requests discovery then enable the passive listeners.
+ // This is used by the MediaRouteButton and MediaRouteActionProvider since
+ // they don't receive lifecycle callbacks from the Activity.
+ routeTypes |= passiveRouteTypes;
+ }
+
+ // Update wifi display scanning.
+ if (activeScanWifiDisplay && mCanConfigureWifiDisplays) {
if (!mActivelyScanningWifiDisplays) {
mActivelyScanningWifiDisplays = true;
mHandler.post(mScanWifiDisplays);
@@ -225,18 +290,14 @@
mHandler.removeCallbacks(mScanWifiDisplays);
}
}
- }
- private boolean hasActiveScanCallbackOfType(int type) {
- final int count = mCallbacks.size();
- for (int i = 0; i < count; i++) {
- CallbackInfo cbi = mCallbacks.get(i);
- if ((cbi.flags & CALLBACK_FLAG_PERFORM_ACTIVE_SCAN) != 0
- && (cbi.type & type) != 0) {
- return true;
- }
+ // Tell the media router service all about it.
+ if (routeTypes != mDiscoveryRequestRouteTypes
+ || activeScan != mDiscoverRequestActiveScan) {
+ mDiscoveryRequestRouteTypes = routeTypes;
+ mDiscoverRequestActiveScan = activeScan;
+ publishClientDiscoveryRequest();
}
- return false;
}
@Override
@@ -259,18 +320,268 @@
}
private void updatePresentationDisplays(int changedDisplayId) {
- final Display[] displays = getAllPresentationDisplays();
final int count = mRoutes.size();
for (int i = 0; i < count; i++) {
- final RouteInfo info = mRoutes.get(i);
- Display display = choosePresentationDisplayForRoute(info, displays);
- if (display != info.mPresentationDisplay
- || (display != null && display.getDisplayId() == changedDisplayId)) {
- info.mPresentationDisplay = display;
- dispatchRoutePresentationDisplayChanged(info);
+ final RouteInfo route = mRoutes.get(i);
+ if (route.updatePresentationDisplay() || (route.mPresentationDisplay != null
+ && route.mPresentationDisplay.getDisplayId() == changedDisplayId)) {
+ dispatchRoutePresentationDisplayChanged(route);
}
}
}
+
+ void setSelectedRoute(RouteInfo info, boolean explicit) {
+ // Must be non-reentrant.
+ mSelectedRoute = info;
+ publishClientSelectedRoute(explicit);
+ }
+
+ void rebindAsUser(int userId) {
+ if (mCurrentUserId != userId || userId < 0 || mClient == null) {
+ if (mClient != null) {
+ try {
+ mMediaRouterService.unregisterClient(mClient);
+ } catch (RemoteException ex) {
+ Log.e(TAG, "Unable to unregister media router client.", ex);
+ }
+ mClient = null;
+ }
+
+ mCurrentUserId = userId;
+
+ try {
+ Client client = new Client();
+ mMediaRouterService.registerClientAsUser(client,
+ mAppContext.getPackageName(), userId);
+ mClient = client;
+ } catch (RemoteException ex) {
+ Log.e(TAG, "Unable to register media router client.", ex);
+ }
+
+ publishClientDiscoveryRequest();
+ publishClientSelectedRoute(false);
+ updateClientState();
+ }
+ }
+
+ void publishClientDiscoveryRequest() {
+ if (mClient != null) {
+ try {
+ mMediaRouterService.setDiscoveryRequest(mClient,
+ mDiscoveryRequestRouteTypes, mDiscoverRequestActiveScan);
+ } catch (RemoteException ex) {
+ Log.e(TAG, "Unable to publish media router client discovery request.", ex);
+ }
+ }
+ }
+
+ void publishClientSelectedRoute(boolean explicit) {
+ if (mClient != null) {
+ try {
+ mMediaRouterService.setSelectedRoute(mClient,
+ mSelectedRoute != null ? mSelectedRoute.mGlobalRouteId : null,
+ explicit);
+ } catch (RemoteException ex) {
+ Log.e(TAG, "Unable to publish media router client selected route.", ex);
+ }
+ }
+ }
+
+ void updateClientState() {
+ // Update the client state.
+ mClientState = null;
+ if (mClient != null) {
+ try {
+ mClientState = mMediaRouterService.getState(mClient);
+ } catch (RemoteException ex) {
+ Log.e(TAG, "Unable to retrieve media router client state.", ex);
+ }
+ }
+ final ArrayList<MediaRouterClientState.RouteInfo> globalRoutes =
+ mClientState != null ? mClientState.routes : null;
+ final String globallySelectedRouteId = mClientState != null ?
+ mClientState.globallySelectedRouteId : null;
+
+ // Add or update routes.
+ final int globalRouteCount = globalRoutes != null ? globalRoutes.size() : 0;
+ for (int i = 0; i < globalRouteCount; i++) {
+ final MediaRouterClientState.RouteInfo globalRoute = globalRoutes.get(i);
+ RouteInfo route = findGlobalRoute(globalRoute.id);
+ if (route == null) {
+ route = makeGlobalRoute(globalRoute);
+ addRouteStatic(route);
+ } else {
+ updateGlobalRoute(route, globalRoute);
+ }
+ }
+
+ // Synchronize state with the globally selected route.
+ if (globallySelectedRouteId != null) {
+ final RouteInfo route = findGlobalRoute(globallySelectedRouteId);
+ if (route == null) {
+ Log.w(TAG, "Could not find new globally selected route: "
+ + globallySelectedRouteId);
+ } else if (route != mSelectedRoute) {
+ if (DEBUG) {
+ Log.d(TAG, "Selecting new globally selected route: " + route);
+ }
+ selectRouteStatic(route.mSupportedTypes, route, false);
+ }
+ } else if (mSelectedRoute != null && mSelectedRoute.mGlobalRouteId != null) {
+ if (DEBUG) {
+ Log.d(TAG, "Unselecting previous globally selected route: " + mSelectedRoute);
+ }
+ selectDefaultRouteStatic();
+ }
+
+ // Remove defunct routes.
+ outer: for (int i = mRoutes.size(); i-- > 0; ) {
+ final RouteInfo route = mRoutes.get(i);
+ final String globalRouteId = route.mGlobalRouteId;
+ if (globalRouteId != null) {
+ for (int j = 0; j < globalRouteCount; j++) {
+ MediaRouterClientState.RouteInfo globalRoute = globalRoutes.get(j);
+ if (globalRouteId.equals(globalRoute.id)) {
+ continue outer; // found
+ }
+ }
+ // not found
+ removeRouteStatic(route);
+ }
+ }
+ }
+
+ void requestSetVolume(RouteInfo route, int volume) {
+ if (route.mGlobalRouteId != null && mClient != null) {
+ try {
+ mMediaRouterService.requestSetVolume(mClient,
+ route.mGlobalRouteId, volume);
+ } catch (RemoteException ex) {
+ Log.w(TAG, "Unable to request volume change.", ex);
+ }
+ }
+ }
+
+ void requestUpdateVolume(RouteInfo route, int direction) {
+ if (route.mGlobalRouteId != null && mClient != null) {
+ try {
+ mMediaRouterService.requestUpdateVolume(mClient,
+ route.mGlobalRouteId, direction);
+ } catch (RemoteException ex) {
+ Log.w(TAG, "Unable to request volume change.", ex);
+ }
+ }
+ }
+
+ RouteInfo makeGlobalRoute(MediaRouterClientState.RouteInfo globalRoute) {
+ RouteInfo route = new RouteInfo(sStatic.mSystemCategory);
+ route.mGlobalRouteId = globalRoute.id;
+ route.mName = globalRoute.name;
+ route.mDescription = globalRoute.description;
+ route.mSupportedTypes = globalRoute.supportedTypes;
+ route.mEnabled = globalRoute.enabled;
+ route.setRealStatusCode(globalRoute.statusCode);
+ route.mPlaybackType = globalRoute.playbackType;
+ route.mPlaybackStream = globalRoute.playbackStream;
+ route.mVolume = globalRoute.volume;
+ route.mVolumeMax = globalRoute.volumeMax;
+ route.mVolumeHandling = globalRoute.volumeHandling;
+ route.mPresentationDisplayId = globalRoute.presentationDisplayId;
+ route.updatePresentationDisplay();
+ return route;
+ }
+
+ void updateGlobalRoute(RouteInfo route, MediaRouterClientState.RouteInfo globalRoute) {
+ boolean changed = false;
+ boolean volumeChanged = false;
+ boolean presentationDisplayChanged = false;
+
+ if (!Objects.equal(route.mName, globalRoute.name)) {
+ route.mName = globalRoute.name;
+ changed = true;
+ }
+ if (!Objects.equal(route.mDescription, globalRoute.description)) {
+ route.mDescription = globalRoute.description;
+ changed = true;
+ }
+ final int oldSupportedTypes = route.mSupportedTypes;
+ if (oldSupportedTypes != globalRoute.supportedTypes) {
+ route.mSupportedTypes = globalRoute.supportedTypes;
+ changed = true;
+ }
+ if (route.mEnabled != globalRoute.enabled) {
+ route.mEnabled = globalRoute.enabled;
+ changed = true;
+ }
+ if (route.mRealStatusCode != globalRoute.statusCode) {
+ route.setRealStatusCode(globalRoute.statusCode);
+ changed = true;
+ }
+ if (route.mPlaybackType != globalRoute.playbackType) {
+ route.mPlaybackType = globalRoute.playbackType;
+ changed = true;
+ }
+ if (route.mPlaybackStream != globalRoute.playbackStream) {
+ route.mPlaybackStream = globalRoute.playbackStream;
+ changed = true;
+ }
+ if (route.mVolume != globalRoute.volume) {
+ route.mVolume = globalRoute.volume;
+ changed = true;
+ volumeChanged = true;
+ }
+ if (route.mVolumeMax != globalRoute.volumeMax) {
+ route.mVolumeMax = globalRoute.volumeMax;
+ changed = true;
+ volumeChanged = true;
+ }
+ if (route.mVolumeHandling != globalRoute.volumeHandling) {
+ route.mVolumeHandling = globalRoute.volumeHandling;
+ changed = true;
+ volumeChanged = true;
+ }
+ if (route.mPresentationDisplayId != globalRoute.presentationDisplayId) {
+ route.mPresentationDisplayId = globalRoute.presentationDisplayId;
+ route.updatePresentationDisplay();
+ changed = true;
+ presentationDisplayChanged = true;
+ }
+
+ if (changed) {
+ dispatchRouteChanged(route, oldSupportedTypes);
+ }
+ if (volumeChanged) {
+ dispatchRouteVolumeChanged(route);
+ }
+ if (presentationDisplayChanged) {
+ dispatchRoutePresentationDisplayChanged(route);
+ }
+ }
+
+ RouteInfo findGlobalRoute(String globalRouteId) {
+ final int count = mRoutes.size();
+ for (int i = 0; i < count; i++) {
+ final RouteInfo route = mRoutes.get(i);
+ if (globalRouteId.equals(route.mGlobalRouteId)) {
+ return route;
+ }
+ }
+ return null;
+ }
+
+ final class Client extends IMediaRouterClient.Stub {
+ @Override
+ public void onStateChanged() {
+ mHandler.post(new Runnable() {
+ @Override
+ public void run() {
+ if (Client.this == mClient) {
+ updateClientState();
+ }
+ }
+ });
+ }
+ }
}
static Static sStatic;
@@ -285,7 +596,7 @@
* <p>Once initiated this routing is transparent to the application. All audio
* played on the media stream will be routed to the selected destination.</p>
*/
- public static final int ROUTE_TYPE_LIVE_AUDIO = 0x1;
+ public static final int ROUTE_TYPE_LIVE_AUDIO = 1 << 0;
/**
* Route type flag for live video.
@@ -302,7 +613,13 @@
* @see RouteInfo#getPresentationDisplay()
* @see android.app.Presentation
*/
- public static final int ROUTE_TYPE_LIVE_VIDEO = 0x2;
+ public static final int ROUTE_TYPE_LIVE_VIDEO = 1 << 1;
+
+ /**
+ * Temporary interop constant to identify remote displays.
+ * @hide To be removed when media router API is updated.
+ */
+ public static final int ROUTE_TYPE_REMOTE_DISPLAY = 1 << 2;
/**
* Route type flag for application-specific usage.
@@ -312,7 +629,10 @@
* is expected to interpret the meaning of these events and perform the requested
* routing tasks.</p>
*/
- public static final int ROUTE_TYPE_USER = 0x00800000;
+ public static final int ROUTE_TYPE_USER = 1 << 23;
+
+ static final int ROUTE_TYPE_ANY = ROUTE_TYPE_LIVE_AUDIO | ROUTE_TYPE_LIVE_VIDEO
+ | ROUTE_TYPE_REMOTE_DISPLAY | ROUTE_TYPE_USER;
/**
* Flag for {@link #addCallback}: Actively scan for routes while this callback
@@ -336,11 +656,40 @@
* Flag for {@link #addCallback}: Do not filter route events.
* <p>
* When this flag is specified, the callback will be invoked for event that affect any
- * route event if they do not match the callback's associated media route selector.
+ * route even if they do not match the callback's filter.
* </p>
*/
public static final int CALLBACK_FLAG_UNFILTERED_EVENTS = 1 << 1;
+ /**
+ * Explicitly requests discovery.
+ *
+ * @hide Future API ported from support library. Revisit this later.
+ */
+ public static final int CALLBACK_FLAG_REQUEST_DISCOVERY = 1 << 2;
+
+ /**
+ * Requests that discovery be performed but only if there is some other active
+ * callback already registered.
+ *
+ * @hide Compatibility workaround for the fact that applications do not currently
+ * request discovery explicitly (except when using the support library API).
+ */
+ public static final int CALLBACK_FLAG_PASSIVE_DISCOVERY = 1 << 3;
+
+ /**
+ * Flag for {@link #isRouteAvailable}: Ignore the default route.
+ * <p>
+ * This flag is used to determine whether a matching non-default route is available.
+ * This constraint may be used to decide whether to offer the route chooser dialog
+ * to the user. There is no point offering the chooser if there are no
+ * non-default choices.
+ * </p>
+ *
+ * @hide Future API ported from support library. Revisit this later.
+ */
+ public static final int AVAILABILITY_FLAG_IGNORE_DEFAULT_ROUTE = 1 << 0;
+
// Maps application contexts
static final HashMap<Context, MediaRouter> sRouters = new HashMap<Context, MediaRouter>();
@@ -352,6 +701,9 @@
if ((types & ROUTE_TYPE_LIVE_VIDEO) != 0) {
result.append("ROUTE_TYPE_LIVE_VIDEO ");
}
+ if ((types & ROUTE_TYPE_REMOTE_DISPLAY) != 0) {
+ result.append("ROUTE_TYPE_REMOTE_DISPLAY ");
+ }
if ((types & ROUTE_TYPE_USER) != 0) {
result.append("ROUTE_TYPE_USER ");
}
@@ -388,6 +740,11 @@
return sStatic.mSystemCategory;
}
+ /** @hide */
+ public RouteInfo getSelectedRoute() {
+ return getSelectedRoute(ROUTE_TYPE_ANY);
+ }
+
/**
* Return the currently selected route for any of the given types
*
@@ -411,6 +768,38 @@
}
/**
+ * Returns true if there is a route that matches the specified types.
+ * <p>
+ * This method returns true if there are any available routes that match the types
+ * regardless of whether they are enabled or disabled. If the
+ * {@link #AVAILABILITY_FLAG_IGNORE_DEFAULT_ROUTE} flag is specified, then
+ * the method will only consider non-default routes.
+ * </p>
+ *
+ * @param types The types to match.
+ * @param flags Flags to control the determination of whether a route may be available.
+ * May be zero or {@link #AVAILABILITY_FLAG_IGNORE_DEFAULT_ROUTE}.
+ * @return True if a matching route may be available.
+ *
+ * @hide Future API ported from support library. Revisit this later.
+ */
+ public boolean isRouteAvailable(int types, int flags) {
+ final int count = sStatic.mRoutes.size();
+ for (int i = 0; i < count; i++) {
+ RouteInfo route = sStatic.mRoutes.get(i);
+ if (route.matchesTypes(types)) {
+ if ((flags & AVAILABILITY_FLAG_IGNORE_DEFAULT_ROUTE) == 0
+ || route != sStatic.mDefaultAudioVideo) {
+ return true;
+ }
+ }
+ }
+
+ // It doesn't look like we can find a matching route right now.
+ return false;
+ }
+
+ /**
* Add a callback to listen to events about specific kinds of media routes.
* If the specified callback is already registered, its registration will be updated for any
* additional route types specified.
@@ -453,9 +842,7 @@
info = new CallbackInfo(cb, types, flags, this);
sStatic.mCallbacks.add(info);
}
- if ((info.flags & CALLBACK_FLAG_PERFORM_ACTIVE_SCAN) != 0) {
- sStatic.updateActiveScan();
- }
+ sStatic.updateDiscoveryRequest();
}
/**
@@ -466,10 +853,8 @@
public void removeCallback(Callback cb) {
int index = findCallbackInfo(cb);
if (index >= 0) {
- CallbackInfo info = sStatic.mCallbacks.remove(index);
- if ((info.flags & CALLBACK_FLAG_PERFORM_ACTIVE_SCAN) != 0) {
- sStatic.updateActiveScan();
- }
+ sStatic.mCallbacks.remove(index);
+ sStatic.updateDiscoveryRequest();
} else {
Log.w(TAG, "removeCallback(" + cb + "): callback not registered");
}
@@ -499,20 +884,20 @@
* @param route Route to select
*/
public void selectRoute(int types, RouteInfo route) {
- selectRouteStatic(types, route);
+ selectRouteStatic(types, route, true);
}
-
+
/**
* @hide internal use
*/
- public void selectRouteInt(int types, RouteInfo route) {
- selectRouteStatic(types, route);
+ public void selectRouteInt(int types, RouteInfo route, boolean explicit) {
+ selectRouteStatic(types, route, explicit);
}
- static void selectRouteStatic(int types, RouteInfo route) {
+ static void selectRouteStatic(int types, RouteInfo route, boolean explicit) {
final RouteInfo oldRoute = sStatic.mSelectedRoute;
if (oldRoute == route) return;
- if ((route.getSupportedTypes() & types) == 0) {
+ if (!route.matchesTypes(types)) {
Log.w(TAG, "selectRoute ignored; cannot select route with supported types " +
typesToString(route.getSupportedTypes()) + " into route types " +
typesToString(types));
@@ -535,21 +920,43 @@
final boolean newRouteHasAddress = route != null && route.mDeviceAddress != null;
if (activeDisplay != null || oldRouteHasAddress || newRouteHasAddress) {
if (newRouteHasAddress && !matchesDeviceAddress(activeDisplay, route)) {
- sStatic.mDisplayService.connectWifiDisplay(route.mDeviceAddress);
+ if (sStatic.mCanConfigureWifiDisplays) {
+ sStatic.mDisplayService.connectWifiDisplay(route.mDeviceAddress);
+ } else {
+ Log.e(TAG, "Cannot connect to wifi displays because this process "
+ + "is not allowed to do so.");
+ }
} else if (activeDisplay != null && !newRouteHasAddress) {
sStatic.mDisplayService.disconnectWifiDisplay();
}
}
+ sStatic.setSelectedRoute(route, explicit);
+
if (oldRoute != null) {
dispatchRouteUnselected(types & oldRoute.getSupportedTypes(), oldRoute);
+ if (oldRoute.resolveStatusCode()) {
+ dispatchRouteChanged(oldRoute);
+ }
}
- sStatic.mSelectedRoute = route;
if (route != null) {
+ if (route.resolveStatusCode()) {
+ dispatchRouteChanged(route);
+ }
dispatchRouteSelected(types & route.getSupportedTypes(), route);
}
}
+ static void selectDefaultRouteStatic() {
+ // TODO: Be smarter about the route types here; this selects for all valid.
+ if (sStatic.mSelectedRoute != sStatic.mBluetoothA2dpRoute
+ && sStatic.mBluetoothA2dpRoute != null) {
+ selectRouteStatic(ROUTE_TYPE_ANY, sStatic.mBluetoothA2dpRoute, false);
+ } else {
+ selectRouteStatic(ROUTE_TYPE_ANY, sStatic.mDefaultAudioVideo, false);
+ }
+ }
+
/**
* Compare the device address of a display and a route.
* Nulls/no device address will match another null/no address.
@@ -612,7 +1019,7 @@
* @see #addUserRoute(UserRouteInfo)
*/
public void removeUserRoute(UserRouteInfo info) {
- removeRoute(info);
+ removeRouteStatic(info);
}
/**
@@ -626,7 +1033,7 @@
// TODO Right now, RouteGroups only ever contain user routes.
// The code below will need to change if this assumption does.
if (info instanceof UserRouteInfo || info instanceof RouteGroup) {
- removeRouteAt(i);
+ removeRouteStatic(info);
i--;
}
}
@@ -636,10 +1043,10 @@
* @hide internal use only
*/
public void removeRouteInt(RouteInfo info) {
- removeRoute(info);
+ removeRouteStatic(info);
}
- static void removeRoute(RouteInfo info) {
+ static void removeRouteStatic(RouteInfo info) {
if (sStatic.mRoutes.remove(info)) {
final RouteCategory removingCat = info.getCategory();
final int count = sStatic.mRoutes.size();
@@ -651,42 +1058,9 @@
break;
}
}
- if (info == sStatic.mSelectedRoute) {
+ if (info.isSelected()) {
// Removing the currently selected route? Select the default before we remove it.
- // TODO: Be smarter about the route types here; this selects for all valid.
- if (info != sStatic.mBluetoothA2dpRoute && sStatic.mBluetoothA2dpRoute != null) {
- selectRouteStatic(ROUTE_TYPE_LIVE_AUDIO | ROUTE_TYPE_USER,
- sStatic.mBluetoothA2dpRoute);
- } else {
- selectRouteStatic(ROUTE_TYPE_LIVE_AUDIO | ROUTE_TYPE_USER,
- sStatic.mDefaultAudioVideo);
- }
- }
- if (!found) {
- sStatic.mCategories.remove(removingCat);
- }
- dispatchRouteRemoved(info);
- }
- }
-
- void removeRouteAt(int routeIndex) {
- if (routeIndex >= 0 && routeIndex < sStatic.mRoutes.size()) {
- final RouteInfo info = sStatic.mRoutes.remove(routeIndex);
- final RouteCategory removingCat = info.getCategory();
- final int count = sStatic.mRoutes.size();
- boolean found = false;
- for (int i = 0; i < count; i++) {
- final RouteCategory cat = sStatic.mRoutes.get(i).getCategory();
- if (removingCat == cat) {
- found = true;
- break;
- }
- }
- if (info == sStatic.mSelectedRoute) {
- // Removing the currently selected route? Select the default before we remove it.
- // TODO: Be smarter about the route types here; this selects for all valid.
- selectRouteStatic(ROUTE_TYPE_LIVE_AUDIO | ROUTE_TYPE_LIVE_VIDEO | ROUTE_TYPE_USER,
- sStatic.mDefaultAudioVideo);
+ selectDefaultRouteStatic();
}
if (!found) {
sStatic.mCategories.remove(removingCat);
@@ -752,7 +1126,7 @@
*
* @see #addUserRoute(UserRouteInfo)
* @see #removeUserRoute(UserRouteInfo)
- * @see #createRouteCategory(CharSequence)
+ * @see #createRouteCategory(CharSequence, boolean)
*/
public UserRouteInfo createUserRoute(RouteCategory category) {
return new UserRouteInfo(category);
@@ -780,6 +1154,23 @@
return new RouteCategory(nameResId, ROUTE_TYPE_USER, isGroupable);
}
+ /**
+ * Rebinds the media router to handle routes that belong to the specified user.
+ * Requires the interact across users permission to access the routes of another user.
+ * <p>
+ * This method is a complete hack to work around the singleton nature of the
+ * media router when running inside of singleton processes like QuickSettings.
+ * This mechanism should be burned to the ground when MediaRouter is redesigned.
+ * Ideally the current user would be pulled from the Context but we need to break
+ * down MediaRouter.Static before we can get there.
+ * </p>
+ *
+ * @hide
+ */
+ public void rebindAsUser(int userId) {
+ sStatic.rebindAsUser(userId);
+ }
+
static void updateRoute(final RouteInfo info) {
dispatchRouteChanged(info);
}
@@ -801,10 +1192,34 @@
}
static void dispatchRouteChanged(RouteInfo info) {
+ dispatchRouteChanged(info, info.mSupportedTypes);
+ }
+
+ static void dispatchRouteChanged(RouteInfo info, int oldSupportedTypes) {
+ final int newSupportedTypes = info.mSupportedTypes;
for (CallbackInfo cbi : sStatic.mCallbacks) {
- if (cbi.filterRouteEvent(info)) {
+ // Reconstruct some of the history for callbacks that may not have observed
+ // all of the events needed to correctly interpret the current state.
+ // FIXME: This is a strong signal that we should deprecate route type filtering
+ // completely in the future because it can lead to inconsistencies in
+ // applications.
+ final boolean oldVisibility = cbi.filterRouteEvent(oldSupportedTypes);
+ final boolean newVisibility = cbi.filterRouteEvent(newSupportedTypes);
+ if (!oldVisibility && newVisibility) {
+ cbi.cb.onRouteAdded(cbi.router, info);
+ if (info.isSelected()) {
+ cbi.cb.onRouteSelected(cbi.router, newSupportedTypes, info);
+ }
+ }
+ if (oldVisibility || newVisibility) {
cbi.cb.onRouteChanged(cbi.router, info);
}
+ if (oldVisibility && !newVisibility) {
+ if (info.isSelected()) {
+ cbi.cb.onRouteUnselected(cbi.router, oldSupportedTypes, info);
+ }
+ cbi.cb.onRouteRemoved(cbi.router, info);
+ }
}
}
@@ -875,65 +1290,73 @@
}
}
- static void updateWifiDisplayStatus(WifiDisplayStatus newStatus) {
- final WifiDisplayStatus oldStatus = sStatic.mLastKnownWifiDisplayStatus;
-
- // TODO Naive implementation. Make this smarter later.
+ static void updateWifiDisplayStatus(WifiDisplayStatus status) {
boolean wantScan = false;
- boolean blockScan = false;
- WifiDisplay[] oldDisplays = oldStatus != null ?
- oldStatus.getDisplays() : WifiDisplay.EMPTY_ARRAY;
- WifiDisplay[] newDisplays;
+ WifiDisplay[] displays;
WifiDisplay activeDisplay;
- if (newStatus.getFeatureState() == WifiDisplayStatus.FEATURE_STATE_ON) {
- newDisplays = newStatus.getDisplays();
- activeDisplay = newStatus.getActiveDisplay();
+ if (status.getFeatureState() == WifiDisplayStatus.FEATURE_STATE_ON) {
+ displays = status.getDisplays();
+ activeDisplay = status.getActiveDisplay();
+
+ // Only the system is able to connect to wifi display routes.
+ // The display manager will enforce this with a permission check but it
+ // still publishes information about all available displays.
+ // Filter the list down to just the active display.
+ if (!sStatic.mCanConfigureWifiDisplays) {
+ if (activeDisplay != null) {
+ displays = new WifiDisplay[] { activeDisplay };
+ } else {
+ displays = WifiDisplay.EMPTY_ARRAY;
+ }
+ }
} else {
- newDisplays = WifiDisplay.EMPTY_ARRAY;
+ displays = WifiDisplay.EMPTY_ARRAY;
activeDisplay = null;
}
- for (int i = 0; i < newDisplays.length; i++) {
- final WifiDisplay d = newDisplays[i];
- if (d.isRemembered()) {
+ // Add or update routes.
+ for (int i = 0; i < displays.length; i++) {
+ final WifiDisplay d = displays[i];
+ if (shouldShowWifiDisplay(d, activeDisplay)) {
RouteInfo route = findWifiDisplayRoute(d);
if (route == null) {
- route = makeWifiDisplayRoute(d, newStatus);
+ route = makeWifiDisplayRoute(d, status);
addRouteStatic(route);
wantScan = true;
} else {
- updateWifiDisplayRoute(route, d, newStatus);
+ updateWifiDisplayRoute(route, d, status);
}
if (d.equals(activeDisplay)) {
- selectRouteStatic(route.getSupportedTypes(), route);
-
- // Don't scan if we're already connected to a wifi display,
- // the scanning process can cause a hiccup with some configurations.
- blockScan = true;
- }
- }
- }
- for (int i = 0; i < oldDisplays.length; i++) {
- final WifiDisplay d = oldDisplays[i];
- if (d.isRemembered()) {
- final WifiDisplay newDisplay = findMatchingDisplay(d, newDisplays);
- if (newDisplay == null || !newDisplay.isRemembered()) {
- removeRoute(findWifiDisplayRoute(d));
+ selectRouteStatic(route.getSupportedTypes(), route, false);
}
}
}
- if (wantScan && !blockScan) {
+ // Remove stale routes.
+ for (int i = sStatic.mRoutes.size(); i-- > 0; ) {
+ RouteInfo route = sStatic.mRoutes.get(i);
+ if (route.mDeviceAddress != null) {
+ WifiDisplay d = findWifiDisplay(displays, route.mDeviceAddress);
+ if (d == null || !shouldShowWifiDisplay(d, activeDisplay)) {
+ removeRouteStatic(route);
+ }
+ }
+ }
+
+ // Don't scan if we're already connected to a wifi display,
+ // the scanning process can cause a hiccup with some configurations.
+ if (wantScan && activeDisplay != null && sStatic.mCanConfigureWifiDisplays) {
sStatic.mDisplayService.scanWifiDisplays();
}
+ }
- sStatic.mLastKnownWifiDisplayStatus = newStatus;
+ private static boolean shouldShowWifiDisplay(WifiDisplay d, WifiDisplay activeDisplay) {
+ return d.isRemembered() || d.equals(activeDisplay);
}
static int getWifiDisplayStatusCode(WifiDisplay d, WifiDisplayStatus wfdStatus) {
- int newStatus = RouteInfo.STATUS_NONE;
-
+ int newStatus;
if (wfdStatus.getScanState() == WifiDisplayStatus.SCAN_STATE_SCANNING) {
newStatus = RouteInfo.STATUS_SCANNING;
} else if (d.isAvailable()) {
@@ -947,7 +1370,7 @@
final int activeState = wfdStatus.getActiveDisplayState();
switch (activeState) {
case WifiDisplayStatus.DISPLAY_STATE_CONNECTED:
- newStatus = RouteInfo.STATUS_NONE;
+ newStatus = RouteInfo.STATUS_CONNECTED;
break;
case WifiDisplayStatus.DISPLAY_STATE_CONNECTING:
newStatus = RouteInfo.STATUS_CONNECTING;
@@ -968,18 +1391,17 @@
static RouteInfo makeWifiDisplayRoute(WifiDisplay display, WifiDisplayStatus wfdStatus) {
final RouteInfo newRoute = new RouteInfo(sStatic.mSystemCategory);
newRoute.mDeviceAddress = display.getDeviceAddress();
- newRoute.mSupportedTypes = ROUTE_TYPE_LIVE_AUDIO | ROUTE_TYPE_LIVE_VIDEO;
+ newRoute.mSupportedTypes = ROUTE_TYPE_LIVE_AUDIO | ROUTE_TYPE_LIVE_VIDEO
+ | ROUTE_TYPE_REMOTE_DISPLAY;
newRoute.mVolumeHandling = RouteInfo.PLAYBACK_VOLUME_FIXED;
newRoute.mPlaybackType = RouteInfo.PLAYBACK_TYPE_REMOTE;
- newRoute.setStatusCode(getWifiDisplayStatusCode(display, wfdStatus));
+ newRoute.setRealStatusCode(getWifiDisplayStatusCode(display, wfdStatus));
newRoute.mEnabled = isWifiDisplayEnabled(display, wfdStatus);
newRoute.mName = display.getFriendlyDisplayName();
newRoute.mDescription = sStatic.mResources.getText(
com.android.internal.R.string.wireless_display_route_description);
-
- newRoute.mPresentationDisplay = choosePresentationDisplayForRoute(newRoute,
- sStatic.getAllPresentationDisplays());
+ newRoute.updatePresentationDisplay();
return newRoute;
}
@@ -996,24 +1418,23 @@
changed |= route.mEnabled != enabled;
route.mEnabled = enabled;
- changed |= route.setStatusCode(getWifiDisplayStatusCode(display, wfdStatus));
+ changed |= route.setRealStatusCode(getWifiDisplayStatusCode(display, wfdStatus));
if (changed) {
dispatchRouteChanged(route);
}
- if (!enabled && route == sStatic.mSelectedRoute) {
+ if (!enabled && route.isSelected()) {
// Oops, no longer available. Reselect the default.
- final RouteInfo defaultRoute = sStatic.mDefaultAudioVideo;
- selectRouteStatic(defaultRoute.getSupportedTypes(), defaultRoute);
+ selectDefaultRouteStatic();
}
}
- private static WifiDisplay findMatchingDisplay(WifiDisplay d, WifiDisplay[] displays) {
+ private static WifiDisplay findWifiDisplay(WifiDisplay[] displays, String deviceAddress) {
for (int i = 0; i < displays.length; i++) {
- final WifiDisplay other = displays[i];
- if (d.hasSameAddress(other)) {
- return other;
+ final WifiDisplay d = displays[i];
+ if (d.getDeviceAddress().equals(deviceAddress)) {
+ return d;
}
}
return null;
@@ -1030,27 +1451,6 @@
return null;
}
- private static Display choosePresentationDisplayForRoute(RouteInfo route, Display[] displays) {
- if ((route.mSupportedTypes & ROUTE_TYPE_LIVE_VIDEO) != 0) {
- if (route.mDeviceAddress != null) {
- // Find the indicated Wifi display by its address.
- for (Display display : displays) {
- if (display.getType() == Display.TYPE_WIFI
- && route.mDeviceAddress.equals(display.getAddress())) {
- return display;
- }
- }
- return null;
- }
-
- if (route == sStatic.mDefaultAudioVideo && displays.length > 0) {
- // Choose the first presentation display from the list.
- return displays[0];
- }
- }
- return null;
- }
-
/**
* Information about a media route.
*/
@@ -1071,12 +1471,18 @@
int mPlaybackStream = AudioManager.STREAM_MUSIC;
VolumeCallbackInfo mVcb;
Display mPresentationDisplay;
+ int mPresentationDisplayId = -1;
String mDeviceAddress;
boolean mEnabled = true;
+ // An id by which the route is known to the media router service.
+ // Null if this route only exists as an artifact within this process.
+ String mGlobalRouteId;
+
// A predetermined connection status that can override mStatus
- private int mStatusCode;
+ private int mRealStatusCode;
+ private int mResolvedStatusCode;
/** @hide */ public static final int STATUS_NONE = 0;
/** @hide */ public static final int STATUS_SCANNING = 1;
@@ -1084,19 +1490,20 @@
/** @hide */ public static final int STATUS_AVAILABLE = 3;
/** @hide */ public static final int STATUS_NOT_AVAILABLE = 4;
/** @hide */ public static final int STATUS_IN_USE = 5;
+ /** @hide */ public static final int STATUS_CONNECTED = 6;
private Object mTag;
/**
* The default playback type, "local", indicating the presentation of the media is happening
* on the same device (e.g. a phone, a tablet) as where it is controlled from.
- * @see #setPlaybackType(int)
+ * @see #getPlaybackType()
*/
public final static int PLAYBACK_TYPE_LOCAL = 0;
/**
* A playback type indicating the presentation of the media is happening on
* a different device (i.e. the remote device) than where it is controlled from.
- * @see #setPlaybackType(int)
+ * @see #getPlaybackType()
*/
public final static int PLAYBACK_TYPE_REMOTE = 1;
/**
@@ -1104,12 +1511,13 @@
* controlled from this object. An example of fixed playback volume is a remote player,
* playing over HDMI where the user prefers to control the volume on the HDMI sink, rather
* than attenuate at the source.
- * @see #setVolumeHandling(int)
+ * @see #getVolumeHandling()
*/
public final static int PLAYBACK_VOLUME_FIXED = 0;
/**
* Playback information indicating the playback volume is variable and can be controlled
* from this object.
+ * @see #getVolumeHandling()
*/
public final static int PLAYBACK_VOLUME_VARIABLE = 1;
@@ -1178,38 +1586,71 @@
* Set this route's status by predetermined status code. If the caller
* should dispatch a route changed event this call will return true;
*/
- boolean setStatusCode(int statusCode) {
- if (statusCode != mStatusCode) {
- mStatusCode = statusCode;
- int resId = 0;
- switch (statusCode) {
- case STATUS_SCANNING:
- resId = com.android.internal.R.string.media_route_status_scanning;
- break;
- case STATUS_CONNECTING:
- resId = com.android.internal.R.string.media_route_status_connecting;
- break;
- case STATUS_AVAILABLE:
- resId = com.android.internal.R.string.media_route_status_available;
- break;
- case STATUS_NOT_AVAILABLE:
- resId = com.android.internal.R.string.media_route_status_not_available;
- break;
- case STATUS_IN_USE:
- resId = com.android.internal.R.string.media_route_status_in_use;
- break;
- }
- mStatus = resId != 0 ? sStatic.mResources.getText(resId) : null;
- return true;
+ boolean setRealStatusCode(int statusCode) {
+ if (mRealStatusCode != statusCode) {
+ mRealStatusCode = statusCode;
+ return resolveStatusCode();
}
return false;
}
/**
+ * Resolves the status code whenever the real status code or selection state
+ * changes.
+ */
+ boolean resolveStatusCode() {
+ int statusCode = mRealStatusCode;
+ if (isSelected()) {
+ switch (statusCode) {
+ // If the route is selected and its status appears to be between states
+ // then report it as connecting even though it has not yet had a chance
+ // to officially move into the CONNECTING state. Note that routes in
+ // the NONE state are assumed to not require an explicit connection
+ // lifecycle whereas those that are AVAILABLE are assumed to have
+ // to eventually proceed to CONNECTED.
+ case STATUS_AVAILABLE:
+ case STATUS_SCANNING:
+ statusCode = STATUS_CONNECTING;
+ break;
+ }
+ }
+ if (mResolvedStatusCode == statusCode) {
+ return false;
+ }
+
+ mResolvedStatusCode = statusCode;
+ int resId;
+ switch (statusCode) {
+ case STATUS_SCANNING:
+ resId = com.android.internal.R.string.media_route_status_scanning;
+ break;
+ case STATUS_CONNECTING:
+ resId = com.android.internal.R.string.media_route_status_connecting;
+ break;
+ case STATUS_AVAILABLE:
+ resId = com.android.internal.R.string.media_route_status_available;
+ break;
+ case STATUS_NOT_AVAILABLE:
+ resId = com.android.internal.R.string.media_route_status_not_available;
+ break;
+ case STATUS_IN_USE:
+ resId = com.android.internal.R.string.media_route_status_in_use;
+ break;
+ case STATUS_CONNECTED:
+ case STATUS_NONE:
+ default:
+ resId = 0;
+ break;
+ }
+ mStatus = resId != 0 ? sStatic.mResources.getText(resId) : null;
+ return true;
+ }
+
+ /**
* @hide
*/
public int getStatusCode() {
- return mStatusCode;
+ return mResolvedStatusCode;
}
/**
@@ -1219,6 +1660,11 @@
return mSupportedTypes;
}
+ /** @hide */
+ public boolean matchesTypes(int types) {
+ return (mSupportedTypes & types) != 0;
+ }
+
/**
* @return The group that this route belongs to.
*/
@@ -1317,9 +1763,7 @@
Log.e(TAG, "Error setting local stream volume", e);
}
} else {
- Log.e(TAG, getClass().getSimpleName() + ".requestSetVolume(): " +
- "Non-local volume playback on system route? " +
- "Could not request volume change.");
+ sStatic.requestSetVolume(this, volume);
}
}
@@ -1338,9 +1782,7 @@
Log.e(TAG, "Error setting local stream volume", e);
}
} else {
- Log.e(TAG, getClass().getSimpleName() + ".requestChangeVolume(): " +
- "Non-local volume playback on system route? " +
- "Could not request volume change.");
+ sStatic.requestUpdateVolume(this, direction);
}
}
@@ -1402,6 +1844,55 @@
return mPresentationDisplay;
}
+ boolean updatePresentationDisplay() {
+ Display display = choosePresentationDisplay();
+ if (mPresentationDisplay != display) {
+ mPresentationDisplay = display;
+ return true;
+ }
+ return false;
+ }
+
+ private Display choosePresentationDisplay() {
+ if ((mSupportedTypes & ROUTE_TYPE_LIVE_VIDEO) != 0) {
+ Display[] displays = sStatic.getAllPresentationDisplays();
+
+ // Ensure that the specified display is valid for presentations.
+ // This check will normally disallow the default display unless it was
+ // configured as a presentation display for some reason.
+ if (mPresentationDisplayId >= 0) {
+ for (Display display : displays) {
+ if (display.getDisplayId() == mPresentationDisplayId) {
+ return display;
+ }
+ }
+ return null;
+ }
+
+ // Find the indicated Wifi display by its address.
+ if (mDeviceAddress != null) {
+ for (Display display : displays) {
+ if (display.getType() == Display.TYPE_WIFI
+ && mDeviceAddress.equals(display.getAddress())) {
+ return display;
+ }
+ }
+ return null;
+ }
+
+ // For the default route, choose the first presentation display from the list.
+ if (this == sStatic.mDefaultAudioVideo && displays.length > 0) {
+ return displays[0];
+ }
+ }
+ return null;
+ }
+
+ /** @hide */
+ public String getDeviceAddress() {
+ return mDeviceAddress;
+ }
+
/**
* Returns true if this route is enabled and may be selected.
*
@@ -1418,7 +1909,22 @@
* @return True if this route is in the process of connecting.
*/
public boolean isConnecting() {
- return mStatusCode == STATUS_CONNECTING;
+ return mResolvedStatusCode == STATUS_CONNECTING;
+ }
+
+ /** @hide */
+ public boolean isSelected() {
+ return this == sStatic.mSelectedRoute;
+ }
+
+ /** @hide */
+ public boolean isDefault() {
+ return this == sStatic.mDefaultAudioVideo;
+ }
+
+ /** @hide */
+ public void select() {
+ selectRouteStatic(mSupportedTypes, this, true);
}
void setStatusInt(CharSequence status) {
@@ -1432,6 +1938,7 @@
}
final IRemoteVolumeObserver.Stub mRemoteVolObserver = new IRemoteVolumeObserver.Stub() {
+ @Override
public void dispatchRemoteVolumeUpdate(final int direction, final int value) {
sStatic.mHandler.post(new Runnable() {
@Override
@@ -1460,7 +1967,7 @@
", status=" + getStatus() +
", category=" + getCategory() +
", supportedTypes=" + supportedTypes +
- ", presentationDisplay=" + mPresentationDisplay + "}";
+ ", presentationDisplay=" + mPresentationDisplay + " }";
}
}
@@ -1716,6 +2223,7 @@
mVolumeHandling = PLAYBACK_VOLUME_FIXED;
}
+ @Override
CharSequence getName(Resources res) {
if (mUpdateName) updateName();
return super.getName(res);
@@ -1916,7 +2424,7 @@
final int count = mRoutes.size();
if (count == 0) {
// Don't keep empty groups in the router.
- MediaRouter.removeRoute(this);
+ MediaRouter.removeRouteStatic(this);
return;
}
@@ -2071,6 +2579,7 @@
return mIsSystem;
}
+ @Override
public String toString() {
return "RouteCategory{ name=" + mName + " types=" + typesToString(mTypes) +
" groupable=" + mGroupable + " }";
@@ -2091,8 +2600,12 @@
}
public boolean filterRouteEvent(RouteInfo route) {
+ return filterRouteEvent(route.mSupportedTypes);
+ }
+
+ public boolean filterRouteEvent(int supportedTypes) {
return (flags & CALLBACK_FLAG_UNFILTERED_EVENTS) != 0
- || (type & route.mSupportedTypes) != 0;
+ || (type & supportedTypes) != 0;
}
}
diff --git a/media/java/android/media/MediaRouterClientState.aidl b/media/java/android/media/MediaRouterClientState.aidl
new file mode 100644
index 0000000..70077119
--- /dev/null
+++ b/media/java/android/media/MediaRouterClientState.aidl
@@ -0,0 +1,18 @@
+/* Copyright 2013, 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.media;
+
+parcelable MediaRouterClientState;
diff --git a/media/java/android/media/MediaRouterClientState.java b/media/java/android/media/MediaRouterClientState.java
new file mode 100644
index 0000000..54b8276
--- /dev/null
+++ b/media/java/android/media/MediaRouterClientState.java
@@ -0,0 +1,200 @@
+/*
+ * Copyright (C) 2013 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.media;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import java.util.ArrayList;
+
+/**
+ * Information available from MediaRouterService about the state perceived by
+ * a particular client and the routes that are available to it.
+ *
+ * Clients must not modify the contents of this object.
+ * @hide
+ */
+public final class MediaRouterClientState implements Parcelable {
+ /**
+ * A list of all known routes.
+ */
+ public final ArrayList<RouteInfo> routes;
+
+ /**
+ * The id of the current globally selected route, or null if none.
+ * Globally selected routes override any other route selections that applications
+ * may have made. Used for remote displays.
+ */
+ public String globallySelectedRouteId;
+
+ public MediaRouterClientState() {
+ routes = new ArrayList<RouteInfo>();
+ }
+
+ MediaRouterClientState(Parcel src) {
+ routes = src.createTypedArrayList(RouteInfo.CREATOR);
+ globallySelectedRouteId = src.readString();
+ }
+
+ public RouteInfo getRoute(String id) {
+ final int count = routes.size();
+ for (int i = 0; i < count; i++) {
+ final RouteInfo route = routes.get(i);
+ if (route.id.equals(id)) {
+ return route;
+ }
+ }
+ return null;
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeTypedList(routes);
+ dest.writeString(globallySelectedRouteId);
+ }
+
+ @Override
+ public String toString() {
+ return "MediaRouterClientState{ globallySelectedRouteId="
+ + globallySelectedRouteId + ", routes=" + routes.toString() + " }";
+ }
+
+ public static final Parcelable.Creator<MediaRouterClientState> CREATOR =
+ new Parcelable.Creator<MediaRouterClientState>() {
+ @Override
+ public MediaRouterClientState createFromParcel(Parcel in) {
+ return new MediaRouterClientState(in);
+ }
+
+ @Override
+ public MediaRouterClientState[] newArray(int size) {
+ return new MediaRouterClientState[size];
+ }
+ };
+
+ public static final class RouteInfo implements Parcelable {
+ public String id;
+ public String name;
+ public String description;
+ public int supportedTypes;
+ public boolean enabled;
+ public int statusCode;
+ public int playbackType;
+ public int playbackStream;
+ public int volume;
+ public int volumeMax;
+ public int volumeHandling;
+ public int presentationDisplayId;
+
+ public RouteInfo(String id) {
+ this.id = id;
+ enabled = true;
+ statusCode = MediaRouter.RouteInfo.STATUS_NONE;
+ playbackType = MediaRouter.RouteInfo.PLAYBACK_TYPE_REMOTE;
+ playbackStream = -1;
+ volumeHandling = MediaRouter.RouteInfo.PLAYBACK_VOLUME_FIXED;
+ presentationDisplayId = -1;
+ }
+
+ public RouteInfo(RouteInfo other) {
+ id = other.id;
+ name = other.name;
+ description = other.description;
+ supportedTypes = other.supportedTypes;
+ enabled = other.enabled;
+ statusCode = other.statusCode;
+ playbackType = other.playbackType;
+ playbackStream = other.playbackStream;
+ volume = other.volume;
+ volumeMax = other.volumeMax;
+ volumeHandling = other.volumeHandling;
+ presentationDisplayId = other.presentationDisplayId;
+ }
+
+ RouteInfo(Parcel in) {
+ id = in.readString();
+ name = in.readString();
+ description = in.readString();
+ supportedTypes = in.readInt();
+ enabled = in.readInt() != 0;
+ statusCode = in.readInt();
+ playbackType = in.readInt();
+ playbackStream = in.readInt();
+ volume = in.readInt();
+ volumeMax = in.readInt();
+ volumeHandling = in.readInt();
+ presentationDisplayId = in.readInt();
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeString(id);
+ dest.writeString(name);
+ dest.writeString(description);
+ dest.writeInt(supportedTypes);
+ dest.writeInt(enabled ? 1 : 0);
+ dest.writeInt(statusCode);
+ dest.writeInt(playbackType);
+ dest.writeInt(playbackStream);
+ dest.writeInt(volume);
+ dest.writeInt(volumeMax);
+ dest.writeInt(volumeHandling);
+ dest.writeInt(presentationDisplayId);
+ }
+
+ @Override
+ public String toString() {
+ return "RouteInfo{ id=" + id
+ + ", name=" + name
+ + ", description=" + description
+ + ", supportedTypes=0x" + Integer.toHexString(supportedTypes)
+ + ", enabled=" + enabled
+ + ", statusCode=" + statusCode
+ + ", playbackType=" + playbackType
+ + ", playbackStream=" + playbackStream
+ + ", volume=" + volume
+ + ", volumeMax=" + volumeMax
+ + ", volumeHandling=" + volumeHandling
+ + ", presentationDisplayId=" + presentationDisplayId
+ + " }";
+ }
+
+ @SuppressWarnings("hiding")
+ public static final Parcelable.Creator<RouteInfo> CREATOR =
+ new Parcelable.Creator<RouteInfo>() {
+ @Override
+ public RouteInfo createFromParcel(Parcel in) {
+ return new RouteInfo(in);
+ }
+
+ @Override
+ public RouteInfo[] newArray(int size) {
+ return new RouteInfo[size];
+ }
+ };
+ }
+}
diff --git a/media/java/android/media/RemoteDisplayState.aidl b/media/java/android/media/RemoteDisplayState.aidl
new file mode 100644
index 0000000..b3262fc
--- /dev/null
+++ b/media/java/android/media/RemoteDisplayState.aidl
@@ -0,0 +1,18 @@
+/* Copyright 2013, 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.media;
+
+parcelable RemoteDisplayState;
diff --git a/media/java/android/media/RemoteDisplayState.java b/media/java/android/media/RemoteDisplayState.java
new file mode 100644
index 0000000..1197f65
--- /dev/null
+++ b/media/java/android/media/RemoteDisplayState.java
@@ -0,0 +1,189 @@
+/*
+ * Copyright (C) 2013 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.media;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.text.TextUtils;
+
+import java.util.ArrayList;
+
+/**
+ * Information available from IRemoteDisplayProvider about available remote displays.
+ *
+ * Clients must not modify the contents of this object.
+ * @hide
+ */
+public final class RemoteDisplayState implements Parcelable {
+ // Note: These constants are used by the remote display provider API.
+ // Do not change them!
+ public static final String SERVICE_INTERFACE =
+ "com.android.media.remotedisplay.RemoteDisplayProvider";
+ public static final int DISCOVERY_MODE_NONE = 0;
+ public static final int DISCOVERY_MODE_PASSIVE = 1;
+ public static final int DISCOVERY_MODE_ACTIVE = 2;
+
+ /**
+ * A list of all remote displays.
+ */
+ public final ArrayList<RemoteDisplayInfo> displays;
+
+ public RemoteDisplayState() {
+ displays = new ArrayList<RemoteDisplayInfo>();
+ }
+
+ RemoteDisplayState(Parcel src) {
+ displays = src.createTypedArrayList(RemoteDisplayInfo.CREATOR);
+ }
+
+ public boolean isValid() {
+ if (displays == null) {
+ return false;
+ }
+ final int count = displays.size();
+ for (int i = 0; i < count; i++) {
+ if (!displays.get(i).isValid()) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeTypedList(displays);
+ }
+
+ public static final Parcelable.Creator<RemoteDisplayState> CREATOR =
+ new Parcelable.Creator<RemoteDisplayState>() {
+ @Override
+ public RemoteDisplayState createFromParcel(Parcel in) {
+ return new RemoteDisplayState(in);
+ }
+
+ @Override
+ public RemoteDisplayState[] newArray(int size) {
+ return new RemoteDisplayState[size];
+ }
+ };
+
+ public static final class RemoteDisplayInfo implements Parcelable {
+ // Note: These constants are used by the remote display provider API.
+ // Do not change them!
+ public static final int STATUS_NOT_AVAILABLE = 0;
+ public static final int STATUS_IN_USE = 1;
+ public static final int STATUS_AVAILABLE = 2;
+ public static final int STATUS_CONNECTING = 3;
+ public static final int STATUS_CONNECTED = 4;
+
+ public static final int PLAYBACK_VOLUME_VARIABLE =
+ MediaRouter.RouteInfo.PLAYBACK_VOLUME_VARIABLE;
+ public static final int PLAYBACK_VOLUME_FIXED =
+ MediaRouter.RouteInfo.PLAYBACK_VOLUME_FIXED;
+
+ public String id;
+ public String name;
+ public String description;
+ public int status;
+ public int volume;
+ public int volumeMax;
+ public int volumeHandling;
+ public int presentationDisplayId;
+
+ public RemoteDisplayInfo(String id) {
+ this.id = id;
+ status = STATUS_NOT_AVAILABLE;
+ volumeHandling = MediaRouter.RouteInfo.PLAYBACK_VOLUME_FIXED;
+ presentationDisplayId = -1;
+ }
+
+ public RemoteDisplayInfo(RemoteDisplayInfo other) {
+ id = other.id;
+ name = other.name;
+ description = other.description;
+ status = other.status;
+ volume = other.volume;
+ volumeMax = other.volumeMax;
+ volumeHandling = other.volumeHandling;
+ presentationDisplayId = other.presentationDisplayId;
+ }
+
+ RemoteDisplayInfo(Parcel in) {
+ id = in.readString();
+ name = in.readString();
+ description = in.readString();
+ status = in.readInt();
+ volume = in.readInt();
+ volumeMax = in.readInt();
+ volumeHandling = in.readInt();
+ presentationDisplayId = in.readInt();
+ }
+
+ public boolean isValid() {
+ return !TextUtils.isEmpty(id) && !TextUtils.isEmpty(name);
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeString(id);
+ dest.writeString(name);
+ dest.writeString(description);
+ dest.writeInt(status);
+ dest.writeInt(volume);
+ dest.writeInt(volumeMax);
+ dest.writeInt(volumeHandling);
+ dest.writeInt(presentationDisplayId);
+ }
+
+ @Override
+ public String toString() {
+ return "RemoteDisplayInfo{ id=" + id
+ + ", name=" + name
+ + ", description=" + description
+ + ", status=" + status
+ + ", volume=" + volume
+ + ", volumeMax=" + volumeMax
+ + ", volumeHandling=" + volumeHandling
+ + ", presentationDisplayId=" + presentationDisplayId
+ + " }";
+ }
+
+ @SuppressWarnings("hiding")
+ public static final Parcelable.Creator<RemoteDisplayInfo> CREATOR =
+ new Parcelable.Creator<RemoteDisplayInfo>() {
+ @Override
+ public RemoteDisplayInfo createFromParcel(Parcel in) {
+ return new RemoteDisplayInfo(in);
+ }
+
+ @Override
+ public RemoteDisplayInfo[] newArray(int size) {
+ return new RemoteDisplayInfo[size];
+ }
+ };
+ }
+}
diff --git a/media/lib/Android.mk b/media/lib/Android.mk
new file mode 100644
index 0000000..50799a6
--- /dev/null
+++ b/media/lib/Android.mk
@@ -0,0 +1,46 @@
+#
+# Copyright (C) 2013 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)
+
+# the library
+# ============================================================
+include $(CLEAR_VARS)
+
+LOCAL_MODULE:= com.android.media.remotedisplay
+LOCAL_MODULE_TAGS := optional
+
+LOCAL_SRC_FILES := \
+ $(call all-subdir-java-files) \
+ $(call all-aidl-files-under, java)
+
+include $(BUILD_JAVA_LIBRARY)
+
+
+# ==== com.android.media.remotedisplay.xml lib def ========================
+include $(CLEAR_VARS)
+
+LOCAL_MODULE := com.android.media.remotedisplay.xml
+LOCAL_MODULE_TAGS := optional
+
+LOCAL_MODULE_CLASS := ETC
+
+# This will install the file in /system/etc/permissions
+#
+LOCAL_MODULE_PATH := $(TARGET_OUT_ETC)/permissions
+
+LOCAL_SRC_FILES := $(LOCAL_MODULE)
+
+include $(BUILD_PREBUILT)
diff --git a/media/lib/README.txt b/media/lib/README.txt
new file mode 100644
index 0000000..cade3df
--- /dev/null
+++ b/media/lib/README.txt
@@ -0,0 +1,28 @@
+This library (com.android.media.remotedisplay.jar) is a shared java library
+containing classes required by unbundled remote display providers.
+
+--- Rules of this library ---
+o This library is effectively a PUBLIC API for unbundled remote display providers
+ that may be distributed outside the system image. So it MUST BE API STABLE.
+ You can add but not remove. The rules are the same as for the
+ public platform SDK API.
+o This library can see and instantiate internal platform classes, but it must not
+ expose them in any public method (or by extending them via inheritance). This would
+ break clients of the library because they cannot see the internal platform classes.
+
+This library is distributed in the system image, and loaded as
+a shared library. So you can change the implementation, but not
+the interface. In this way it is like framework.jar.
+
+--- Why does this library exists? ---
+
+Unbundled remote display providers (such as Cast) cannot use internal
+platform classes.
+
+This library will eventually be replaced when the media route provider
+infrastructure that is currently defined in the support library is reintegrated
+with the framework in a new API. That API isn't ready yet so this
+library is a compromise to make new capabilities available to the system
+without exposing the full surface area of the support library media
+route provider protocol.
+
diff --git a/media/lib/com.android.media.remotedisplay.xml b/media/lib/com.android.media.remotedisplay.xml
new file mode 100644
index 0000000..77a91d2
--- /dev/null
+++ b/media/lib/com.android.media.remotedisplay.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2013 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.
+-->
+
+<permissions>
+ <library name="com.android.media.remotedisplay"
+ file="/system/framework/com.android.media.remotedisplay.jar" />
+</permissions>
diff --git a/media/lib/java/com/android/media/remotedisplay/RemoteDisplay.java b/media/lib/java/com/android/media/remotedisplay/RemoteDisplay.java
new file mode 100644
index 0000000..5e15702
--- /dev/null
+++ b/media/lib/java/com/android/media/remotedisplay/RemoteDisplay.java
@@ -0,0 +1,173 @@
+/*
+ * Copyright (C) 2013 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.media.remotedisplay;
+
+import com.android.internal.util.Objects;
+
+import android.media.MediaRouter;
+import android.media.RemoteDisplayState.RemoteDisplayInfo;
+import android.text.TextUtils;
+
+/**
+ * Represents a remote display that has been discovered.
+ */
+public class RemoteDisplay {
+ private final RemoteDisplayInfo mMutableInfo;
+ private RemoteDisplayInfo mImmutableInfo;
+
+ /**
+ * Status code: Indicates that the remote display is not available.
+ */
+ public static final int STATUS_NOT_AVAILABLE = RemoteDisplayInfo.STATUS_NOT_AVAILABLE;
+
+ /**
+ * Status code: Indicates that the remote display is in use by someone else.
+ */
+ public static final int STATUS_IN_USE = RemoteDisplayInfo.STATUS_IN_USE;
+
+ /**
+ * Status code: Indicates that the remote display is available for new connections.
+ */
+ public static final int STATUS_AVAILABLE = RemoteDisplayInfo.STATUS_AVAILABLE;
+
+ /**
+ * Status code: Indicates that the remote display is current connecting.
+ */
+ public static final int STATUS_CONNECTING = RemoteDisplayInfo.STATUS_CONNECTING;
+
+ /**
+ * Status code: Indicates that the remote display is connected and is mirroring
+ * display contents.
+ */
+ public static final int STATUS_CONNECTED = RemoteDisplayInfo.STATUS_CONNECTED;
+
+ /**
+ * Volume handling: Output volume can be changed.
+ */
+ public static final int PLAYBACK_VOLUME_VARIABLE =
+ RemoteDisplayInfo.PLAYBACK_VOLUME_VARIABLE;
+
+ /**
+ * Volume handling: Output volume is fixed.
+ */
+ public static final int PLAYBACK_VOLUME_FIXED =
+ RemoteDisplayInfo.PLAYBACK_VOLUME_FIXED;
+
+ /**
+ * Creates a remote display with the specified name and id.
+ */
+ public RemoteDisplay(String id, String name) {
+ if (TextUtils.isEmpty(id)) {
+ throw new IllegalArgumentException("id must not be null or empty");
+ }
+ mMutableInfo = new RemoteDisplayInfo(id);
+ setName(name);
+ }
+
+ public String getId() {
+ return mMutableInfo.id;
+ }
+
+ public String getName() {
+ return mMutableInfo.name;
+ }
+
+ public void setName(String name) {
+ if (!Objects.equal(mMutableInfo.name, name)) {
+ mMutableInfo.name = name;
+ mImmutableInfo = null;
+ }
+ }
+
+ public String getDescription() {
+ return mMutableInfo.description;
+ }
+
+ public void setDescription(String description) {
+ if (!Objects.equal(mMutableInfo.description, description)) {
+ mMutableInfo.description = description;
+ mImmutableInfo = null;
+ }
+ }
+
+ public int getStatus() {
+ return mMutableInfo.status;
+ }
+
+ public void setStatus(int status) {
+ if (mMutableInfo.status != status) {
+ mMutableInfo.status = status;
+ mImmutableInfo = null;
+ }
+ }
+
+ public int getVolume() {
+ return mMutableInfo.volume;
+ }
+
+ public void setVolume(int volume) {
+ if (mMutableInfo.volume != volume) {
+ mMutableInfo.volume = volume;
+ mImmutableInfo = null;
+ }
+ }
+
+ public int getVolumeMax() {
+ return mMutableInfo.volumeMax;
+ }
+
+ public void setVolumeMax(int volumeMax) {
+ if (mMutableInfo.volumeMax != volumeMax) {
+ mMutableInfo.volumeMax = volumeMax;
+ mImmutableInfo = null;
+ }
+ }
+
+ public int getVolumeHandling() {
+ return mMutableInfo.volumeHandling;
+ }
+
+ public void setVolumeHandling(int volumeHandling) {
+ if (mMutableInfo.volumeHandling != volumeHandling) {
+ mMutableInfo.volumeHandling = volumeHandling;
+ mImmutableInfo = null;
+ }
+ }
+
+ public int getPresentationDisplayId() {
+ return mMutableInfo.presentationDisplayId;
+ }
+
+ public void setPresentationDisplayId(int presentationDisplayId) {
+ if (mMutableInfo.presentationDisplayId != presentationDisplayId) {
+ mMutableInfo.presentationDisplayId = presentationDisplayId;
+ mImmutableInfo = null;
+ }
+ }
+
+ @Override
+ public String toString() {
+ return "RemoteDisplay{" + mMutableInfo.toString() + "}";
+ }
+
+ RemoteDisplayInfo getInfo() {
+ if (mImmutableInfo == null) {
+ mImmutableInfo = new RemoteDisplayInfo(mMutableInfo);
+ }
+ return mImmutableInfo;
+ }
+}
diff --git a/media/lib/java/com/android/media/remotedisplay/RemoteDisplayProvider.java b/media/lib/java/com/android/media/remotedisplay/RemoteDisplayProvider.java
new file mode 100644
index 0000000..e2df77c
--- /dev/null
+++ b/media/lib/java/com/android/media/remotedisplay/RemoteDisplayProvider.java
@@ -0,0 +1,407 @@
+/*
+ * Copyright (C) 2013 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.media.remotedisplay;
+
+import android.app.PendingIntent;
+import android.app.Service;
+import android.content.Context;
+import android.content.Intent;
+import android.media.IRemoteDisplayCallback;
+import android.media.IRemoteDisplayProvider;
+import android.media.RemoteDisplayState;
+import android.os.Handler;
+import android.os.IBinder;
+import android.os.Looper;
+import android.os.Message;
+import android.os.RemoteException;
+import android.provider.Settings;
+import android.util.ArrayMap;
+
+import java.util.Collection;
+
+/**
+ * Base class for remote display providers implemented as unbundled services.
+ * <p>
+ * To implement your remote display provider service, create a subclass of
+ * {@link Service} and override the {@link Service#onBind Service.onBind()} method
+ * to return the provider's binder when the {@link #SERVICE_INTERFACE} is requested.
+ * </p>
+ * <pre>
+ * public class SampleRemoteDisplayProviderService extends Service {
+ * private SampleProvider mProvider;
+ *
+ * public IBinder onBind(Intent intent) {
+ * if (intent.getAction().equals(RemoteDisplayProvider.SERVICE_INTERFACE)) {
+ * if (mProvider == null) {
+ * mProvider = new SampleProvider(this);
+ * }
+ * return mProvider.getBinder();
+ * }
+ * return null;
+ * }
+ *
+ * class SampleProvider extends RemoteDisplayProvider {
+ * public SampleProvider() {
+ * super(SampleRemoteDisplayProviderService.this);
+ * }
+ *
+ * // --- Implementation goes here ---
+ * }
+ * }
+ * </pre>
+ * <p>
+ * Declare your remote display provider service in your application manifest
+ * like this:
+ * </p>
+ * <pre>
+ * <application>
+ * <uses-library android:name="com.android.media.remotedisplay" />
+ *
+ * <service android:name=".SampleRemoteDisplayProviderService"
+ * android:label="@string/sample_remote_display_provider_service"
+ * android:exported="true"
+ * android:permission="android.permission.BIND_REMOTE_DISPLAY">
+ * <intent-filter>
+ * <action android:name="com.android.media.remotedisplay.RemoteDisplayProvider" />
+ * </intent-filter>
+ * </service>
+ * </application>
+ * </pre>
+ * <p>
+ * This object is not thread safe. It is only intended to be accessed on the
+ * {@link Context#getMainLooper main looper thread} of an application.
+ * </p><p>
+ * IMPORTANT: This class is effectively a public API for unbundled applications, and
+ * must remain API stable. See README.txt in the root of this package for more information.
+ * </p>
+ */
+public abstract class RemoteDisplayProvider {
+ private static final int MSG_SET_CALLBACK = 1;
+ private static final int MSG_SET_DISCOVERY_MODE = 2;
+ private static final int MSG_CONNECT = 3;
+ private static final int MSG_DISCONNECT = 4;
+ private static final int MSG_SET_VOLUME = 5;
+ private static final int MSG_ADJUST_VOLUME = 6;
+
+ private final Context mContext;
+ private final ProviderStub mStub;
+ private final ProviderHandler mHandler;
+ private final ArrayMap<String, RemoteDisplay> mDisplays =
+ new ArrayMap<String, RemoteDisplay>();
+ private IRemoteDisplayCallback mCallback;
+ private int mDiscoveryMode = DISCOVERY_MODE_NONE;
+
+ private PendingIntent mSettingsPendingIntent;
+
+ /**
+ * The {@link Intent} that must be declared as handled by the service.
+ * Put this in your manifest.
+ */
+ public static final String SERVICE_INTERFACE = RemoteDisplayState.SERVICE_INTERFACE;
+
+ /**
+ * Discovery mode: Do not perform any discovery.
+ */
+ public static final int DISCOVERY_MODE_NONE = RemoteDisplayState.DISCOVERY_MODE_NONE;
+
+ /**
+ * Discovery mode: Passive or low-power periodic discovery.
+ * <p>
+ * This mode indicates that an application is interested in knowing whether there
+ * are any remote displays paired or available but doesn't need the latest or
+ * most detailed information. The provider may scan at a lower rate or rely on
+ * knowledge of previously paired devices.
+ * </p>
+ */
+ public static final int DISCOVERY_MODE_PASSIVE = RemoteDisplayState.DISCOVERY_MODE_PASSIVE;
+
+ /**
+ * Discovery mode: Active discovery.
+ * <p>
+ * This mode indicates that the user is actively trying to connect to a route
+ * and we should perform continuous scans. This mode may use significantly more
+ * power but is intended to be short-lived.
+ * </p>
+ */
+ public static final int DISCOVERY_MODE_ACTIVE = RemoteDisplayState.DISCOVERY_MODE_ACTIVE;
+
+ /**
+ * Creates a remote display provider.
+ *
+ * @param context The application context for the remote display provider.
+ */
+ public RemoteDisplayProvider(Context context) {
+ mContext = context;
+ mStub = new ProviderStub();
+ mHandler = new ProviderHandler(context.getMainLooper());
+ }
+
+ /**
+ * Gets the context of the remote display provider.
+ */
+ public final Context getContext() {
+ return mContext;
+ }
+
+ /**
+ * Gets the Binder associated with the provider.
+ * <p>
+ * This is intended to be used for the onBind() method of a service that implements
+ * a remote display provider service.
+ * </p>
+ *
+ * @return The IBinder instance associated with the provider.
+ */
+ public IBinder getBinder() {
+ return mStub;
+ }
+
+ /**
+ * Called when the current discovery mode changes.
+ *
+ * @param mode The new discovery mode.
+ */
+ public void onDiscoveryModeChanged(int mode) {
+ }
+
+ /**
+ * Called when the system would like to connect to a display.
+ *
+ * @param display The remote display.
+ */
+ public void onConnect(RemoteDisplay display) {
+ }
+
+ /**
+ * Called when the system would like to disconnect from a display.
+ *
+ * @param display The remote display.
+ */
+ public void onDisconnect(RemoteDisplay display) {
+ }
+
+ /**
+ * Called when the system would like to set the volume of a display.
+ *
+ * @param display The remote display.
+ * @param volume The desired volume.
+ */
+ public void onSetVolume(RemoteDisplay display, int volume) {
+ }
+
+ /**
+ * Called when the system would like to adjust the volume of a display.
+ *
+ * @param display The remote display.
+ * @param delta An increment to add to the current volume, such as +1 or -1.
+ */
+ public void onAdjustVolume(RemoteDisplay display, int delta) {
+ }
+
+ /**
+ * Gets the current discovery mode.
+ *
+ * @return The current discovery mode.
+ */
+ public int getDiscoveryMode() {
+ return mDiscoveryMode;
+ }
+
+ /**
+ * Gets the current collection of displays.
+ *
+ * @return The current collection of displays, which must not be modified.
+ */
+ public Collection<RemoteDisplay> getDisplays() {
+ return mDisplays.values();
+ }
+
+ /**
+ * Adds the specified remote display and notifies the system.
+ *
+ * @param display The remote display that was added.
+ * @throws IllegalStateException if there is already a display with the same id.
+ */
+ public void addDisplay(RemoteDisplay display) {
+ if (display == null || mDisplays.containsKey(display.getId())) {
+ throw new IllegalArgumentException("display");
+ }
+ mDisplays.put(display.getId(), display);
+ publishState();
+ }
+
+ /**
+ * Updates information about the specified remote display and notifies the system.
+ *
+ * @param display The remote display that was added.
+ * @throws IllegalStateException if the display was n
+ */
+ public void updateDisplay(RemoteDisplay display) {
+ if (display == null || mDisplays.get(display.getId()) != display) {
+ throw new IllegalArgumentException("display");
+ }
+ publishState();
+ }
+
+ /**
+ * Removes the specified remote display and tells the system about it.
+ *
+ * @param display The remote display that was removed.
+ */
+ public void removeDisplay(RemoteDisplay display) {
+ if (display == null || mDisplays.get(display.getId()) != display) {
+ throw new IllegalArgumentException("display");
+ }
+ mDisplays.remove(display.getId());
+ publishState();
+ }
+
+ /**
+ * Finds the remote display with the specified id, returns null if not found.
+ *
+ * @param id Id of the remote display.
+ * @return The display, or null if none.
+ */
+ public RemoteDisplay findRemoteDisplay(String id) {
+ return mDisplays.get(id);
+ }
+
+ /**
+ * Gets a pending intent to launch the remote display settings activity.
+ *
+ * @return A pending intent to launch the settings activity.
+ */
+ public PendingIntent getSettingsPendingIntent() {
+ if (mSettingsPendingIntent == null) {
+ Intent settingsIntent = new Intent(Settings.ACTION_WIFI_DISPLAY_SETTINGS);
+ settingsIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
+ | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED
+ | Intent.FLAG_ACTIVITY_CLEAR_TOP);
+ mSettingsPendingIntent = PendingIntent.getActivity(
+ mContext, 0, settingsIntent, 0, null);
+ }
+ return mSettingsPendingIntent;
+ }
+
+ void setCallback(IRemoteDisplayCallback callback) {
+ mCallback = callback;
+ publishState();
+ }
+
+ void setDiscoveryMode(int mode) {
+ if (mDiscoveryMode != mode) {
+ mDiscoveryMode = mode;
+ onDiscoveryModeChanged(mode);
+ }
+ }
+
+ void publishState() {
+ if (mCallback != null) {
+ RemoteDisplayState state = new RemoteDisplayState();
+ final int count = mDisplays.size();
+ for (int i = 0; i < count; i++) {
+ final RemoteDisplay display = mDisplays.valueAt(i);
+ state.displays.add(display.getInfo());
+ }
+ try {
+ mCallback.onStateChanged(state);
+ } catch (RemoteException ex) {
+ // system server died?
+ }
+ }
+ }
+
+ final class ProviderStub extends IRemoteDisplayProvider.Stub {
+ @Override
+ public void setCallback(IRemoteDisplayCallback callback) {
+ mHandler.obtainMessage(MSG_SET_CALLBACK, callback).sendToTarget();
+ }
+
+ @Override
+ public void setDiscoveryMode(int mode) {
+ mHandler.obtainMessage(MSG_SET_DISCOVERY_MODE, mode, 0).sendToTarget();
+ }
+
+ @Override
+ public void connect(String id) {
+ mHandler.obtainMessage(MSG_CONNECT, id).sendToTarget();
+ }
+
+ @Override
+ public void disconnect(String id) {
+ mHandler.obtainMessage(MSG_DISCONNECT, id).sendToTarget();
+ }
+
+ @Override
+ public void setVolume(String id, int volume) {
+ mHandler.obtainMessage(MSG_SET_VOLUME, volume, 0, id).sendToTarget();
+ }
+
+ @Override
+ public void adjustVolume(String id, int delta) {
+ mHandler.obtainMessage(MSG_ADJUST_VOLUME, delta, 0, id).sendToTarget();
+ }
+ }
+
+ final class ProviderHandler extends Handler {
+ public ProviderHandler(Looper looper) {
+ super(looper, null, true);
+ }
+
+ @Override
+ public void handleMessage(Message msg) {
+ switch (msg.what) {
+ case MSG_SET_CALLBACK: {
+ setCallback((IRemoteDisplayCallback)msg.obj);
+ break;
+ }
+ case MSG_SET_DISCOVERY_MODE: {
+ setDiscoveryMode(msg.arg1);
+ break;
+ }
+ case MSG_CONNECT: {
+ RemoteDisplay display = findRemoteDisplay((String)msg.obj);
+ if (display != null) {
+ onConnect(display);
+ }
+ break;
+ }
+ case MSG_DISCONNECT: {
+ RemoteDisplay display = findRemoteDisplay((String)msg.obj);
+ if (display != null) {
+ onDisconnect(display);
+ }
+ break;
+ }
+ case MSG_SET_VOLUME: {
+ RemoteDisplay display = findRemoteDisplay((String)msg.obj);
+ if (display != null) {
+ onSetVolume(display, msg.arg1);
+ }
+ break;
+ }
+ case MSG_ADJUST_VOLUME: {
+ RemoteDisplay display = findRemoteDisplay((String)msg.obj);
+ if (display != null) {
+ onAdjustVolume(display, msg.arg1);
+ }
+ break;
+ }
+ }
+ }
+ }
+}
diff --git a/packages/DocumentsUI/src/com/android/documentsui/FilteringCursorWrapper.java b/packages/DocumentsUI/src/com/android/documentsui/FilteringCursorWrapper.java
index 55d73f23..1cbc221 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/FilteringCursorWrapper.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/FilteringCursorWrapper.java
@@ -51,7 +51,7 @@
mPosition = new int[count];
cursor.moveToPosition(-1);
- while (cursor.moveToNext()) {
+ while (cursor.moveToNext() && mCount < count) {
final String mimeType = getCursorString(cursor, Document.COLUMN_MIME_TYPE);
final long lastModified = getCursorLong(cursor, Document.COLUMN_LAST_MODIFIED);
if (rejectMimes != null && MimePredicate.mimeMatches(rejectMimes, mimeType)) {
diff --git a/packages/DocumentsUI/src/com/android/documentsui/RecentLoader.java b/packages/DocumentsUI/src/com/android/documentsui/RecentLoader.java
index 3a8a3fb..34ce42d 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/RecentLoader.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/RecentLoader.java
@@ -55,6 +55,10 @@
public class RecentLoader extends AsyncTaskLoader<DirectoryResult> {
private static final boolean LOGD = true;
+ // TODO: clean up cursor ownership so background thread doesn't traverse
+ // previously returned cursors for filtering/sorting; this currently races
+ // with the UI thread.
+
private static final int MAX_OUTSTANDING_RECENTS = 4;
private static final int MAX_OUTSTANDING_RECENTS_SVELTE = 2;
diff --git a/packages/ExternalStorageProvider/AndroidManifest.xml b/packages/ExternalStorageProvider/AndroidManifest.xml
index 5169fef..edd6255 100644
--- a/packages/ExternalStorageProvider/AndroidManifest.xml
+++ b/packages/ExternalStorageProvider/AndroidManifest.xml
@@ -3,6 +3,7 @@
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
+ <uses-permission android:name="android.permission.WRITE_MEDIA_STORAGE" />
<application android:label="@string/app_label">
<provider
diff --git a/packages/FusedLocation/res/values-ca/strings.xml b/packages/FusedLocation/res/values-ca/strings.xml
index bdd55dd..9dae512 100644
--- a/packages/FusedLocation/res/values-ca/strings.xml
+++ b/packages/FusedLocation/res/values-ca/strings.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="app_label" msgid="5379477904423203699">"Ubicació unificada"</string>
+ <string name="app_label" msgid="5379477904423203699">"Ubicació combinada"</string>
</resources>
diff --git a/packages/FusedLocation/res/values-de/strings.xml b/packages/FusedLocation/res/values-de/strings.xml
index 0d2cccc..d7e5faa 100644
--- a/packages/FusedLocation/res/values-de/strings.xml
+++ b/packages/FusedLocation/res/values-de/strings.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="app_label" msgid="5379477904423203699">"Fused Location"</string>
+ <string name="app_label" msgid="5379477904423203699">"Kombinierte Standortbestimmung"</string>
</resources>
diff --git a/packages/FusedLocation/res/values-pl/strings.xml b/packages/FusedLocation/res/values-pl/strings.xml
index b3a9e2a..4637034 100644
--- a/packages/FusedLocation/res/values-pl/strings.xml
+++ b/packages/FusedLocation/res/values-pl/strings.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="app_label" msgid="5379477904423203699">"Przybliżona lokalizacja"</string>
+ <string name="app_label" msgid="5379477904423203699">"Uśredniona lokalizacja"</string>
</resources>
diff --git a/packages/FusedLocation/res/values-pt/strings.xml b/packages/FusedLocation/res/values-pt/strings.xml
index cf5f5bf..4f8277a 100644
--- a/packages/FusedLocation/res/values-pt/strings.xml
+++ b/packages/FusedLocation/res/values-pt/strings.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="app_label" msgid="5379477904423203699">"Localização fundida"</string>
+ <string name="app_label" msgid="5379477904423203699">"Localização combinada"</string>
</resources>
diff --git a/packages/Keyguard/AndroidManifest.xml b/packages/Keyguard/AndroidManifest.xml
index 9e296e2..66d1e75 100644
--- a/packages/Keyguard/AndroidManifest.xml
+++ b/packages/Keyguard/AndroidManifest.xml
@@ -38,6 +38,7 @@
<uses-permission android:name="android.permission.BIND_DEVICE_ADMIN" />
<uses-permission android:name="android.permission.CHANGE_COMPONENT_ENABLED_STATE" />
<uses-permission android:name="android.permission.MEDIA_CONTENT_CONTROL" />
+ <uses-permission android:name="android.permission.ACCESS_KEYGUARD_SECURE_STORAGE" />
<application android:label="@string/app_name"
android:process="com.android.systemui"
diff --git a/packages/Keyguard/res/layout/keyguard_presentation.xml b/packages/Keyguard/res/layout/keyguard_presentation.xml
new file mode 100644
index 0000000..7df0b70
--- /dev/null
+++ b/packages/Keyguard/res/layout/keyguard_presentation.xml
@@ -0,0 +1,63 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+**
+** Copyright 2013, 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.
+*/
+-->
+
+<!-- This is a view that shows general status information in Keyguard. -->
+<FrameLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:androidprv="http://schemas.android.com/apk/res/com.android.keyguard"
+ android:id="@+id/presentation"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent">
+
+ <com.android.keyguard.KeyguardStatusView
+ android:id="@+id/clock"
+ android:orientation="vertical"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:contentDescription="@string/keyguard_accessibility_status">
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center_horizontal|top"
+ android:orientation="vertical"
+ android:focusable="true">
+ <TextClock
+ android:id="@+id/clock_view"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center_horizontal|top"
+ android:textColor="@color/clock_white"
+ android:singleLine="true"
+ style="@style/widget_big_thin"
+ android:format12Hour="@string/keyguard_widget_12_hours_format"
+ android:format24Hour="@string/keyguard_widget_24_hours_format"
+ android:baselineAligned="true"
+ android:layout_marginBottom="@dimen/bottom_text_spacing_digital" />
+
+ <include layout="@layout/keyguard_status_area" />
+ <ImageView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="10dip"
+ android:layout_gravity="center_horizontal"
+ android:src="@drawable/kg_security_lock_normal" />
+ </LinearLayout>
+ </com.android.keyguard.KeyguardStatusView>
+
+</FrameLayout>
diff --git a/packages/Keyguard/res/layout/keyguard_status_view.xml b/packages/Keyguard/res/layout/keyguard_status_view.xml
index 5857fc2..a4d298a 100644
--- a/packages/Keyguard/res/layout/keyguard_status_view.xml
+++ b/packages/Keyguard/res/layout/keyguard_status_view.xml
@@ -26,7 +26,7 @@
android:layout_height="match_parent"
androidprv:layout_maxWidth="@dimen/keyguard_security_width"
androidprv:layout_maxHeight="@dimen/keyguard_security_height"
- android:gravity="center_horizontal">
+ android:gravity="center">
<com.android.keyguard.KeyguardStatusView
android:id="@+id/keyguard_status_view_face_palm"
diff --git a/packages/Keyguard/src/com/android/keyguard/CameraWidgetFrame.java b/packages/Keyguard/src/com/android/keyguard/CameraWidgetFrame.java
index 3dc4d5c..74e6f33 100644
--- a/packages/Keyguard/src/com/android/keyguard/CameraWidgetFrame.java
+++ b/packages/Keyguard/src/com/android/keyguard/CameraWidgetFrame.java
@@ -19,7 +19,6 @@
import android.content.Context;
import android.content.pm.PackageManager.NameNotFoundException;
import android.graphics.Color;
-import android.graphics.Paint;
import android.graphics.Point;
import android.graphics.Rect;
import android.os.Handler;
@@ -41,7 +40,7 @@
private static final String TAG = CameraWidgetFrame.class.getSimpleName();
private static final boolean DEBUG = KeyguardHostView.DEBUG;
private static final int WIDGET_ANIMATION_DURATION = 250; // ms
- private static final int WIDGET_WAIT_DURATION = 650; // ms
+ private static final int WIDGET_WAIT_DURATION = 400; // ms
private static final int RECOVERY_DELAY = 1000; // ms
interface Callbacks {
@@ -68,6 +67,7 @@
private FixedSizeFrameLayout mPreview;
private View mFullscreenPreview;
private View mFakeNavBar;
+ private boolean mUseFastTransition;
private final Runnable mTransitionToCameraRunnable = new Runnable() {
@Override
@@ -418,7 +418,8 @@
private void rescheduleTransitionToCamera() {
if (DEBUG) Log.d(TAG, "rescheduleTransitionToCamera at " + SystemClock.uptimeMillis());
mHandler.removeCallbacks(mTransitionToCameraRunnable);
- mHandler.postDelayed(mTransitionToCameraRunnable, WIDGET_WAIT_DURATION);
+ final long duration = mUseFastTransition ? 0 : WIDGET_WAIT_DURATION;
+ mHandler.postDelayed(mTransitionToCameraRunnable, duration);
}
private void cancelTransitionToCamera() {
@@ -513,4 +514,8 @@
if (DEBUG) Log.d(TAG, "setInsets: " + insets);
mInsets.set(insets);
}
+
+ public void setUseFastTransition(boolean useFastTransition) {
+ mUseFastTransition = useFastTransition;
+ }
}
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardDisplayManager.java b/packages/Keyguard/src/com/android/keyguard/KeyguardDisplayManager.java
new file mode 100644
index 0000000..6bcbd6c
--- /dev/null
+++ b/packages/Keyguard/src/com/android/keyguard/KeyguardDisplayManager.java
@@ -0,0 +1,171 @@
+/*
+ * Copyright (C) 2013 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.keyguard;
+
+import android.app.Presentation;
+import android.content.Context;
+import android.content.DialogInterface;
+import android.content.DialogInterface.OnDismissListener;
+import android.graphics.Point;
+import android.media.MediaRouter;
+import android.media.MediaRouter.RouteInfo;
+import android.os.Bundle;
+import android.util.Slog;
+import android.view.Display;
+import android.view.View;
+import android.view.WindowManager;
+
+public class KeyguardDisplayManager {
+ protected static final String TAG = "KeyguardDisplayManager";
+ private static boolean DEBUG = KeyguardViewMediator.DEBUG;
+ Presentation mPresentation;
+ private MediaRouter mMediaRouter;
+ private Context mContext;
+ private boolean mShowing;
+
+ KeyguardDisplayManager(Context context) {
+ mContext = context;
+ mMediaRouter = (MediaRouter) mContext.getSystemService(Context.MEDIA_ROUTER_SERVICE);
+ }
+
+ void show() {
+ if (!mShowing) {
+ if (DEBUG) Slog.v(TAG, "show");
+ mMediaRouter.addCallback(MediaRouter.ROUTE_TYPE_REMOTE_DISPLAY,
+ mMediaRouterCallback, MediaRouter.CALLBACK_FLAG_PASSIVE_DISCOVERY);
+ updateDisplays(true);
+ }
+ mShowing = true;
+ }
+
+ void hide() {
+ if (mShowing) {
+ if (DEBUG) Slog.v(TAG, "hide");
+ mMediaRouter.removeCallback(mMediaRouterCallback);
+ updateDisplays(false);
+ }
+ mShowing = false;
+ }
+
+ private final MediaRouter.SimpleCallback mMediaRouterCallback =
+ new MediaRouter.SimpleCallback() {
+ @Override
+ public void onRouteSelected(MediaRouter router, int type, RouteInfo info) {
+ if (DEBUG) Slog.d(TAG, "onRouteSelected: type=" + type + ", info=" + info);
+ updateDisplays(mShowing);
+ }
+
+ @Override
+ public void onRouteUnselected(MediaRouter router, int type, RouteInfo info) {
+ if (DEBUG) Slog.d(TAG, "onRouteUnselected: type=" + type + ", info=" + info);
+ updateDisplays(mShowing);
+ }
+
+ @Override
+ public void onRoutePresentationDisplayChanged(MediaRouter router, RouteInfo info) {
+ if (DEBUG) Slog.d(TAG, "onRoutePresentationDisplayChanged: info=" + info);
+ updateDisplays(mShowing);
+ }
+ };
+
+ private OnDismissListener mOnDismissListener = new OnDismissListener() {
+
+ @Override
+ public void onDismiss(DialogInterface dialog) {
+ mPresentation = null;
+ }
+ };
+
+ protected void updateDisplays(boolean showing) {
+ if (showing) {
+ MediaRouter.RouteInfo route = mMediaRouter.getSelectedRoute(
+ MediaRouter.ROUTE_TYPE_REMOTE_DISPLAY);
+ boolean useDisplay = route != null
+ && route.getPlaybackType() == MediaRouter.RouteInfo.PLAYBACK_TYPE_REMOTE;
+ Display presentationDisplay = useDisplay ? route.getPresentationDisplay() : null;
+
+ if (mPresentation != null && mPresentation.getDisplay() != presentationDisplay) {
+ if (DEBUG) Slog.v(TAG, "Display gone: " + mPresentation.getDisplay());
+ mPresentation.dismiss();
+ mPresentation = null;
+ }
+
+ if (mPresentation == null && presentationDisplay != null) {
+ if (DEBUG) Slog.i(TAG, "Keyguard enabled on display: " + presentationDisplay);
+ mPresentation = new KeyguardPresentation(mContext, presentationDisplay);
+ mPresentation.setOnDismissListener(mOnDismissListener);
+ try {
+ mPresentation.show();
+ } catch (WindowManager.InvalidDisplayException ex) {
+ Slog.w(TAG, "Invalid display:", ex);
+ mPresentation = null;
+ }
+ }
+ } else {
+ if (mPresentation != null) {
+ mPresentation.dismiss();
+ mPresentation = null;
+ }
+ }
+ }
+
+ private final static class KeyguardPresentation extends Presentation {
+ private static final int VIDEO_SAFE_REGION = 80; // Percentage of display width & height
+ private static final int MOVE_CLOCK_TIMEOUT = 10000; // 10s
+ private View mClock;
+ private int mUsableWidth;
+ private int mUsableHeight;
+ private int mMarginTop;
+ private int mMarginLeft;
+ Runnable mMoveTextRunnable = new Runnable() {
+ @Override
+ public void run() {
+ int x = mMarginLeft + (int) (Math.random() * (mUsableWidth - mClock.getWidth()));
+ int y = mMarginTop + (int) (Math.random() * (mUsableHeight - mClock.getHeight()));
+ mClock.setTranslationX(x);
+ mClock.setTranslationY(y);
+ mClock.postDelayed(mMoveTextRunnable, MOVE_CLOCK_TIMEOUT);
+ }
+ };
+
+ public KeyguardPresentation(Context context, Display display) {
+ super(context, display);
+ getWindow().setType(WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG);
+ }
+
+ public void onDetachedFromWindow() {
+ mClock.removeCallbacks(mMoveTextRunnable);
+ }
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ Point p = new Point();
+ getDisplay().getSize(p);
+ mUsableWidth = VIDEO_SAFE_REGION * p.x/100;
+ mUsableHeight = VIDEO_SAFE_REGION * p.y/100;
+ mMarginLeft = (100 - VIDEO_SAFE_REGION) * p.x / 200;
+ mMarginTop = (100 - VIDEO_SAFE_REGION) * p.y / 200;
+
+ setContentView(R.layout.keyguard_presentation);
+ mClock = findViewById(R.id.clock);
+
+ // Avoid screen burn in
+ mClock.post(mMoveTextRunnable);
+ }
+ }
+}
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardTransportControlView.java b/packages/Keyguard/src/com/android/keyguard/KeyguardTransportControlView.java
index 2719c5c..349078f 100644
--- a/packages/Keyguard/src/com/android/keyguard/KeyguardTransportControlView.java
+++ b/packages/Keyguard/src/com/android/keyguard/KeyguardTransportControlView.java
@@ -60,12 +60,12 @@
*/
public class KeyguardTransportControlView extends FrameLayout {
- private static final int DISPLAY_TIMEOUT_MS = 5000; // 5s
private static final int RESET_TO_METADATA_DELAY = 5000;
protected static final boolean DEBUG = false;
protected static final String TAG = "TransportControlView";
private static final boolean ANIMATE_TRANSITIONS = true;
+ protected static final long QUIESCENT_PLAYBACK_FACTOR = 1000;
private ViewGroup mMetadataContainer;
private ViewGroup mInfoContainer;
@@ -89,11 +89,9 @@
private ImageView mBadge;
private boolean mSeekEnabled;
- private boolean mUserSeeking;
private java.text.DateFormat mFormat;
- private Date mTimeElapsed;
- private Date mTrackDuration;
+ private Date mTempDate = new Date();
/**
* The metadata which should be populated into the view once we've been attached
@@ -111,18 +109,25 @@
@Override
public void onClientPlaybackStateUpdate(int state) {
- setSeekBarsEnabled(false);
updatePlayPauseState(state);
}
@Override
public void onClientPlaybackStateUpdate(int state, long stateChangeTimeMs,
long currentPosMs, float speed) {
- setSeekBarsEnabled(mMetadata != null && mMetadata.duration > 0);
updatePlayPauseState(state);
if (DEBUG) Log.d(TAG, "onClientPlaybackStateUpdate(state=" + state +
", stateChangeTimeMs=" + stateChangeTimeMs + ", currentPosMs=" + currentPosMs +
", speed=" + speed + ")");
+
+ removeCallbacks(mUpdateSeekBars);
+ // Since the music client may be responding to historical events that cause the
+ // playback state to change dramatically, wait until things become quiescent before
+ // resuming automatic scrub position update.
+ if (mTransientSeek.getVisibility() == View.VISIBLE
+ && playbackPositionShouldMove(mCurrentPlayState)) {
+ postDelayed(mUpdateSeekBars, QUIESCENT_PLAYBACK_FACTOR);
+ }
}
@Override
@@ -136,15 +141,21 @@
}
};
- private final Runnable mUpdateSeekBars = new Runnable() {
+ private class UpdateSeekBarRunnable implements Runnable {
public void run() {
- if (updateSeekBars()) {
+ boolean seekAble = updateOnce();
+ if (seekAble) {
removeCallbacks(this);
postDelayed(this, 1000);
}
}
+ public boolean updateOnce() {
+ return updateSeekBars();
+ }
};
+ private final UpdateSeekBarRunnable mUpdateSeekBars = new UpdateSeekBarRunnable();
+
private final Runnable mResetToMetadata = new Runnable() {
public void run() {
resetToMetadata();
@@ -163,6 +174,7 @@
}
if (keyCode != -1) {
sendMediaButtonClick(keyCode);
+ delayResetToMetadata(); // if the scrub bar is showing, keep showing it.
}
}
};
@@ -177,25 +189,67 @@
}
};
+ // This class is here to throttle scrub position updates to the music client
+ class FutureSeekRunnable implements Runnable {
+ private int mProgress;
+ private boolean mPending;
+
+ public void run() {
+ scrubTo(mProgress);
+ mPending = false;
+ }
+
+ void setProgress(int progress) {
+ mProgress = progress;
+ if (!mPending) {
+ mPending = true;
+ postDelayed(this, 30);
+ }
+ }
+ };
+
+ // This is here because RemoteControlClient's method isn't visible :/
+ private final static boolean playbackPositionShouldMove(int playstate) {
+ switch(playstate) {
+ case RemoteControlClient.PLAYSTATE_STOPPED:
+ case RemoteControlClient.PLAYSTATE_PAUSED:
+ case RemoteControlClient.PLAYSTATE_BUFFERING:
+ case RemoteControlClient.PLAYSTATE_ERROR:
+ case RemoteControlClient.PLAYSTATE_SKIPPING_FORWARDS:
+ case RemoteControlClient.PLAYSTATE_SKIPPING_BACKWARDS:
+ return false;
+ case RemoteControlClient.PLAYSTATE_PLAYING:
+ case RemoteControlClient.PLAYSTATE_FAST_FORWARDING:
+ case RemoteControlClient.PLAYSTATE_REWINDING:
+ default:
+ return true;
+ }
+ }
+
+ private final FutureSeekRunnable mFutureSeekRunnable = new FutureSeekRunnable();
+
private final SeekBar.OnSeekBarChangeListener mOnSeekBarChangeListener =
new SeekBar.OnSeekBarChangeListener() {
@Override
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
if (fromUser) {
- scrubTo(progress);
+ mFutureSeekRunnable.setProgress(progress);
delayResetToMetadata();
+ mTempDate.setTime(progress);
+ mTransientSeekTimeElapsed.setText(mFormat.format(mTempDate));
+ } else {
+ updateSeekDisplay();
}
- updateSeekDisplay();
}
@Override
public void onStartTrackingTouch(SeekBar seekBar) {
- mUserSeeking = true;
+ delayResetToMetadata();
+ removeCallbacks(mUpdateSeekBars); // don't update during user interaction
}
@Override
public void onStopTrackingTouch(SeekBar seekBar) {
- mUserSeeking = false;
}
};
@@ -247,17 +301,11 @@
if (enabled == mSeekEnabled) return;
mSeekEnabled = enabled;
- if (mTransientSeek.getVisibility() == VISIBLE) {
+ if (mTransientSeek.getVisibility() == VISIBLE && !enabled) {
mTransientSeek.setVisibility(INVISIBLE);
mMetadataContainer.setVisibility(VISIBLE);
- mUserSeeking = false;
cancelResetToMetadata();
}
- if (enabled) {
- mUpdateSeekBars.run();
- } else {
- removeCallbacks(mUpdateSeekBars);
- }
}
public void setTransportControlCallback(KeyguardHostView.TransportControlCallback
@@ -294,6 +342,8 @@
}
final boolean screenOn = KeyguardUpdateMonitor.getInstance(mContext).isScreenOn();
setEnableMarquee(screenOn);
+ // Allow long-press anywhere else in this view to show the seek bar
+ setOnLongClickListener(mTransportShowSeekBarListener);
}
@Override
@@ -326,7 +376,6 @@
mAudioManager.unregisterRemoteController(mRemoteController);
KeyguardUpdateMonitor.getInstance(mContext).removeCallback(mUpdateMonitor);
mMetadata.clear();
- mUserSeeking = false;
removeCallbacks(mUpdateSeekBars);
}
@@ -484,18 +533,12 @@
void updateSeekDisplay() {
if (mMetadata != null && mRemoteController != null && mFormat != null) {
- if (mTimeElapsed == null) {
- mTimeElapsed = new Date();
- }
- if (mTrackDuration == null) {
- mTrackDuration = new Date();
- }
- mTimeElapsed.setTime(mRemoteController.getEstimatedMediaPosition());
- mTrackDuration.setTime(mMetadata.duration);
- mTransientSeekTimeElapsed.setText(mFormat.format(mTimeElapsed));
- mTransientSeekTimeTotal.setText(mFormat.format(mTrackDuration));
+ mTempDate.setTime(mRemoteController.getEstimatedMediaPosition());
+ mTransientSeekTimeElapsed.setText(mFormat.format(mTempDate));
+ mTempDate.setTime(mMetadata.duration);
+ mTransientSeekTimeTotal.setText(mFormat.format(mTempDate));
- if (DEBUG) Log.d(TAG, "updateSeekDisplay timeElapsed=" + mTimeElapsed +
+ if (DEBUG) Log.d(TAG, "updateSeekDisplay timeElapsed=" + mTempDate +
" duration=" + mMetadata.duration);
}
}
@@ -508,10 +551,16 @@
mTransientSeek.setVisibility(INVISIBLE);
mMetadataContainer.setVisibility(VISIBLE);
cancelResetToMetadata();
+ removeCallbacks(mUpdateSeekBars); // don't update if scrubber isn't visible
} else {
mTransientSeek.setVisibility(VISIBLE);
mMetadataContainer.setVisibility(INVISIBLE);
delayResetToMetadata();
+ if (playbackPositionShouldMove(mCurrentPlayState)) {
+ mUpdateSeekBars.run();
+ } else {
+ mUpdateSeekBars.updateOnce();
+ }
}
mTransportControlCallback.userActivity();
return true;
@@ -573,9 +622,6 @@
case RemoteControlClient.PLAYSTATE_PLAYING:
imageResId = R.drawable.ic_media_pause;
imageDescId = R.string.keyguard_transport_pause_description;
- if (mSeekEnabled) {
- mUpdateSeekBars.run();
- }
break;
case RemoteControlClient.PLAYSTATE_BUFFERING:
@@ -590,10 +636,9 @@
break;
}
- if (state != RemoteControlClient.PLAYSTATE_PLAYING) {
- removeCallbacks(mUpdateSeekBars);
- updateSeekBars();
- }
+ boolean clientSupportsSeek = mMetadata != null && mMetadata.duration > 0;
+ setSeekBarsEnabled(clientSupportsSeek);
+
mBtnPlay.setImageResource(imageResId);
mBtnPlay.setContentDescription(getResources().getString(imageDescId));
mCurrentPlayState = state;
@@ -601,11 +646,9 @@
boolean updateSeekBars() {
final int position = (int) mRemoteController.getEstimatedMediaPosition();
+ if (DEBUG) Log.v(TAG, "Estimated time:" + position);
if (position >= 0) {
- if (DEBUG) Log.v(TAG, "Seek to " + position);
- if (!mUserSeeking) {
- mTransientSeekBar.setProgress(position);
- }
+ mTransientSeekBar.setProgress(position);
return true;
}
Log.w(TAG, "Updating seek bars; received invalid estimated media position (" +
@@ -671,34 +714,4 @@
public boolean providesClock() {
return false;
}
-
- private boolean wasPlayingRecently(int state, long stateChangeTimeMs) {
- switch (state) {
- case RemoteControlClient.PLAYSTATE_PLAYING:
- case RemoteControlClient.PLAYSTATE_FAST_FORWARDING:
- case RemoteControlClient.PLAYSTATE_REWINDING:
- case RemoteControlClient.PLAYSTATE_SKIPPING_FORWARDS:
- case RemoteControlClient.PLAYSTATE_SKIPPING_BACKWARDS:
- case RemoteControlClient.PLAYSTATE_BUFFERING:
- // actively playing or about to play
- return true;
- case RemoteControlClient.PLAYSTATE_NONE:
- return false;
- case RemoteControlClient.PLAYSTATE_STOPPED:
- case RemoteControlClient.PLAYSTATE_PAUSED:
- case RemoteControlClient.PLAYSTATE_ERROR:
- // we have stopped playing, check how long ago
- if (DEBUG) {
- if ((SystemClock.elapsedRealtime() - stateChangeTimeMs) < DISPLAY_TIMEOUT_MS) {
- Log.v(TAG, "wasPlayingRecently: time < TIMEOUT was playing recently");
- } else {
- Log.v(TAG, "wasPlayingRecently: time > TIMEOUT");
- }
- }
- return ((SystemClock.elapsedRealtime() - stateChangeTimeMs) < DISPLAY_TIMEOUT_MS);
- default:
- Log.e(TAG, "Unknown playback state " + state + " in wasPlayingRecently()");
- return false;
- }
- }
}
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardViewManager.java b/packages/Keyguard/src/com/android/keyguard/KeyguardViewManager.java
index fd7cae6..6aa0a4b 100644
--- a/packages/Keyguard/src/com/android/keyguard/KeyguardViewManager.java
+++ b/packages/Keyguard/src/com/android/keyguard/KeyguardViewManager.java
@@ -61,9 +61,11 @@
public class KeyguardViewManager {
private final static boolean DEBUG = KeyguardViewMediator.DEBUG;
private static String TAG = "KeyguardViewManager";
- public static boolean USE_UPPER_CASE = true;
public final static String IS_SWITCHING_USER = "is_switching_user";
+ // Delay dismissing keyguard to allow animations to complete.
+ private static final int HIDE_KEYGUARD_DELAY = 500;
+
// Timeout used for keypresses
static final int DIGIT_PRESS_WAKE_MILLIS = 5000;
@@ -509,9 +511,10 @@
mKeyguardHost.setCustomBackground(null);
updateShowWallpaper(true);
mKeyguardHost.removeView(lastView);
+ mViewMediatorCallback.keyguardGone();
}
}
- }, 500);
+ }, HIDE_KEYGUARD_DELAY);
}
}
}
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardViewMediator.java b/packages/Keyguard/src/com/android/keyguard/KeyguardViewMediator.java
index b92ae90..4086f84 100644
--- a/packages/Keyguard/src/com/android/keyguard/KeyguardViewMediator.java
+++ b/packages/Keyguard/src/com/android/keyguard/KeyguardViewMediator.java
@@ -200,7 +200,7 @@
// cached value of whether we are showing (need to know this to quickly
// answer whether the input should be restricted)
- private boolean mShowing = false;
+ private boolean mShowing;
// true if the keyguard is hidden by another window
private boolean mHidden = false;
@@ -253,6 +253,11 @@
private final float mLockSoundVolume;
/**
+ * For managing external displays
+ */
+ private KeyguardDisplayManager mKeyguardDisplayManager;
+
+ /**
* Cache of avatar drawables, for use by KeyguardMultiUserAvatar.
*/
private static MultiUserAvatarCache sMultiUserAvatarCache = new MultiUserAvatarCache();
@@ -304,6 +309,11 @@
* Report that the keyguard is dismissable, pending the next keyguardDone call.
*/
void keyguardDonePending();
+
+ /**
+ * Report when keyguard is actually gone
+ */
+ void keyguardGone();
}
KeyguardUpdateMonitorCallback mUpdateCallback = new KeyguardUpdateMonitorCallback() {
@@ -457,6 +467,11 @@
public void keyguardDonePending() {
mKeyguardDonePending = true;
}
+
+ @Override
+ public void keyguardGone() {
+ mKeyguardDisplayManager.hide();
+ }
};
private void userActivity() {
@@ -483,6 +498,8 @@
mContext.registerReceiver(mBroadcastReceiver, new IntentFilter(DELAYED_KEYGUARD_ACTION));
+ mKeyguardDisplayManager = new KeyguardDisplayManager(context);
+
mAlarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
mUpdateMonitor = KeyguardUpdateMonitor.getInstance(context);
@@ -491,6 +508,10 @@
? lockPatternUtils : new LockPatternUtils(mContext);
mLockPatternUtils.setCurrentUser(UserHandle.USER_OWNER);
+ // Assume keyguard is showing (unless it's disabled) until we know for sure...
+ mShowing = (mUpdateMonitor.isDeviceProvisioned() || mLockPatternUtils.isSecure())
+ && !mLockPatternUtils.isLockScreenDisabled();
+
WindowManager wm = (WindowManager)context.getSystemService(Context.WINDOW_SERVICE);
mKeyguardViewManager = new KeyguardViewManager(context, wm, mViewMediatorCallback,
@@ -1218,6 +1239,7 @@
mShowKeyguardWakeLock.release();
}
+ mKeyguardDisplayManager.show();
}
/**
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardViewStateManager.java b/packages/Keyguard/src/com/android/keyguard/KeyguardViewStateManager.java
index f0413d6..169899f 100644
--- a/packages/Keyguard/src/com/android/keyguard/KeyguardViewStateManager.java
+++ b/packages/Keyguard/src/com/android/keyguard/KeyguardViewStateManager.java
@@ -154,6 +154,10 @@
public void onPageSwitching(View newPage, int newPageIndex) {
if (mKeyguardWidgetPager != null && mChallengeLayout instanceof SlidingChallengeLayout) {
boolean isCameraPage = newPage instanceof CameraWidgetFrame;
+ if (isCameraPage) {
+ CameraWidgetFrame camera = (CameraWidgetFrame) newPage;
+ camera.setUseFastTransition(mKeyguardWidgetPager.isWarping());
+ }
SlidingChallengeLayout scl = (SlidingChallengeLayout) mChallengeLayout;
scl.setChallengeInteractive(!isCameraPage);
final int currentFlags = mKeyguardWidgetPager.getSystemUiVisibility();
diff --git a/packages/Keyguard/src/com/android/keyguard/PagedView.java b/packages/Keyguard/src/com/android/keyguard/PagedView.java
index b9404d4..53c17a5 100644
--- a/packages/Keyguard/src/com/android/keyguard/PagedView.java
+++ b/packages/Keyguard/src/com/android/keyguard/PagedView.java
@@ -82,13 +82,13 @@
private static final float RETURN_TO_ORIGINAL_PAGE_THRESHOLD = 0.33f;
// The page is moved more than halfway, automatically move to the next page on touch up.
- private static final float SIGNIFICANT_MOVE_THRESHOLD = 0.4f;
+ private static final float SIGNIFICANT_MOVE_THRESHOLD = 0.5f;
// The following constants need to be scaled based on density. The scaled versions will be
// assigned to the corresponding member variables below.
- private static final int FLING_THRESHOLD_VELOCITY = 500;
+ private static final int FLING_THRESHOLD_VELOCITY = 1500;
private static final int MIN_SNAP_VELOCITY = 1500;
- private static final int MIN_FLING_VELOCITY = 250;
+ private static final int MIN_FLING_VELOCITY = 500;
// We are disabling touch interaction of the widget region for factory ROM.
private static final boolean DISABLE_TOUCH_INTERACTION = false;
@@ -1938,10 +1938,12 @@
if (isWarping()) {
dispatchOnPageEndWarp();
+ notifyPageSwitching(whichPage);
resetPageWarp();
+ } else {
+ notifyPageSwitching(whichPage);
}
- notifyPageSwitching(whichPage);
View focusedChild = getFocusedChild();
if (focusedChild != null && whichPage != mCurrentPage &&
focusedChild == getPageAt(mCurrentPage)) {
diff --git a/packages/PrintSpooler/res/layout/print_job_config_activity_content_error.xml b/packages/PrintSpooler/res/layout/print_job_config_activity_content_error.xml
index f573d9d..d9f0a9a 100644
--- a/packages/PrintSpooler/res/layout/print_job_config_activity_content_error.xml
+++ b/packages/PrintSpooler/res/layout/print_job_config_activity_content_error.xml
@@ -35,7 +35,6 @@
android:layout_marginBottom="32dip"
android:layout_gravity="center"
style="?android:attr/buttonBarButtonStyle"
- android:singleLine="true"
android:ellipsize="end"
android:text="@string/print_error_default_message"
android:textColor="@color/important_text"
diff --git a/packages/PrintSpooler/res/values-af/strings.xml b/packages/PrintSpooler/res/values-af/strings.xml
index b8287ae..a10a5a0 100644
--- a/packages/PrintSpooler/res/values-af/strings.xml
+++ b/packages/PrintSpooler/res/values-af/strings.xml
@@ -41,6 +41,8 @@
<string name="print_search_box_shown_utterance" msgid="7967404953901376090">"Soekkassie vertoon"</string>
<string name="print_search_box_hidden_utterance" msgid="5727755169343113351">"Soekkassie weggesteek"</string>
<string name="print_add_printer" msgid="1088656468360653455">"Voeg drukker by"</string>
+ <string name="print_select_printer" msgid="7388760939873368698">"Kies drukker"</string>
+ <string name="print_forget_printer" msgid="5035287497291910766">"Vergeet drukker"</string>
<plurals name="print_search_result_count_utterance">
<item quantity="one" msgid="4484953260685964252">"<xliff:g id="COUNT">%1$s</xliff:g> drukker gekry"</item>
<item quantity="other" msgid="6533817036607128241">"<xliff:g id="COUNT">%1$s</xliff:g> drukkers gekry"</item>
diff --git a/packages/PrintSpooler/res/values-am/strings.xml b/packages/PrintSpooler/res/values-am/strings.xml
index d73cdd9..3b94d6d 100644
--- a/packages/PrintSpooler/res/values-am/strings.xml
+++ b/packages/PrintSpooler/res/values-am/strings.xml
@@ -41,6 +41,8 @@
<string name="print_search_box_shown_utterance" msgid="7967404953901376090">"የፍለጋ ሳጥን ይታያል"</string>
<string name="print_search_box_hidden_utterance" msgid="5727755169343113351">"የፍለጋ ሳጥን ተደብቋል"</string>
<string name="print_add_printer" msgid="1088656468360653455">"አታሚ አክል"</string>
+ <string name="print_select_printer" msgid="7388760939873368698">"አታሚ ምረጥ"</string>
+ <string name="print_forget_printer" msgid="5035287497291910766">"አታሚ እርሳ"</string>
<plurals name="print_search_result_count_utterance">
<item quantity="one" msgid="4484953260685964252">"<xliff:g id="COUNT">%1$s</xliff:g> አታሚ ተገኝቷል"</item>
<item quantity="other" msgid="6533817036607128241">"<xliff:g id="COUNT">%1$s</xliff:g> አታሚዎች ተገኝተዋል"</item>
diff --git a/packages/PrintSpooler/res/values-ar/strings.xml b/packages/PrintSpooler/res/values-ar/strings.xml
index 14b6467..b883f93 100644
--- a/packages/PrintSpooler/res/values-ar/strings.xml
+++ b/packages/PrintSpooler/res/values-ar/strings.xml
@@ -23,7 +23,7 @@
<string name="label_destination" msgid="9132510997381599275">"الوجهة"</string>
<string name="label_copies" msgid="3634531042822968308">"عدد النسخ"</string>
<string name="label_paper_size" msgid="8681895607876809323">"حجم الورق"</string>
- <string name="label_color" msgid="1108690305218188969">"اللون"</string>
+ <string name="label_color" msgid="1108690305218188969">"ألوان"</string>
<string name="label_orientation" msgid="2853142581990496477">"الاتجاه"</string>
<string name="label_pages" msgid="6300874667546617333">"الصفحات (<xliff:g id="PAGE_COUNT">%1$s</xliff:g>)"</string>
<string name="pages_range_example" msgid="8558694453556945172">"على سبيل المثال، 1—5،8،11—13"</string>
@@ -41,6 +41,8 @@
<string name="print_search_box_shown_utterance" msgid="7967404953901376090">"تم إظهار مربع البحث"</string>
<string name="print_search_box_hidden_utterance" msgid="5727755169343113351">"تم إخفاء مربع البحث"</string>
<string name="print_add_printer" msgid="1088656468360653455">"إضافة طابعة"</string>
+ <string name="print_select_printer" msgid="7388760939873368698">"حدد الطابعة"</string>
+ <string name="print_forget_printer" msgid="5035287497291910766">"تجاهل الطابعة"</string>
<plurals name="print_search_result_count_utterance">
<item quantity="one" msgid="4484953260685964252">"تم العثور على <xliff:g id="COUNT">%1$s</xliff:g> طابعة"</item>
<item quantity="other" msgid="6533817036607128241">"تم العثور على <xliff:g id="COUNT">%1$s</xliff:g> من الطابعات"</item>
@@ -64,11 +66,11 @@
<string name="print_error_default_message" msgid="8568506918983980567">"تعذر إنشاء عملية الطباعة"</string>
<string-array name="color_mode_labels">
<item msgid="7602948745415174937">"أبيض وأسود"</item>
- <item msgid="2762241247228983754">"اللون"</item>
+ <item msgid="2762241247228983754">"ملونة"</item>
</string-array>
<string-array name="orientation_labels">
<item msgid="4061931020926489228">"عمودي"</item>
- <item msgid="3199660090246166812">"أفقية"</item>
+ <item msgid="3199660090246166812">"أفقي"</item>
</string-array>
<string-array name="page_options_labels">
<item msgid="7421377442011699994">"الكل"</item>
diff --git a/packages/PrintSpooler/res/values-bg/strings.xml b/packages/PrintSpooler/res/values-bg/strings.xml
index 47f86c6..4009aa2 100644
--- a/packages/PrintSpooler/res/values-bg/strings.xml
+++ b/packages/PrintSpooler/res/values-bg/strings.xml
@@ -41,6 +41,8 @@
<string name="print_search_box_shown_utterance" msgid="7967404953901376090">"Полето за търсене е показано"</string>
<string name="print_search_box_hidden_utterance" msgid="5727755169343113351">"Полето за търсене е скрито"</string>
<string name="print_add_printer" msgid="1088656468360653455">"Добавяне на принтер"</string>
+ <string name="print_select_printer" msgid="7388760939873368698">"Избиране на принтер"</string>
+ <string name="print_forget_printer" msgid="5035287497291910766">"Забравяне на принтера"</string>
<plurals name="print_search_result_count_utterance">
<item quantity="one" msgid="4484953260685964252">"Намерен е <xliff:g id="COUNT">%1$s</xliff:g> принтер"</item>
<item quantity="other" msgid="6533817036607128241">"Намерени са <xliff:g id="COUNT">%1$s</xliff:g> принтера"</item>
diff --git a/packages/PrintSpooler/res/values-ca/strings.xml b/packages/PrintSpooler/res/values-ca/strings.xml
index fc60b0a..a429dd5 100644
--- a/packages/PrintSpooler/res/values-ca/strings.xml
+++ b/packages/PrintSpooler/res/values-ca/strings.xml
@@ -41,6 +41,8 @@
<string name="print_search_box_shown_utterance" msgid="7967404953901376090">"Es mostra el quadre de cerca"</string>
<string name="print_search_box_hidden_utterance" msgid="5727755169343113351">"S\'ha amagat el quadre de cerca"</string>
<string name="print_add_printer" msgid="1088656468360653455">"Afegeix una impressora"</string>
+ <string name="print_select_printer" msgid="7388760939873368698">"Selecciona una impressora"</string>
+ <string name="print_forget_printer" msgid="5035287497291910766">"Oblida la impressora"</string>
<plurals name="print_search_result_count_utterance">
<item quantity="one" msgid="4484953260685964252">"S\'ha trobat <xliff:g id="COUNT">%1$s</xliff:g> impressora"</item>
<item quantity="other" msgid="6533817036607128241">"S\'han trobat <xliff:g id="COUNT">%1$s</xliff:g> impressores"</item>
diff --git a/packages/PrintSpooler/res/values-cs/strings.xml b/packages/PrintSpooler/res/values-cs/strings.xml
index 3f806d6..3ddc701 100644
--- a/packages/PrintSpooler/res/values-cs/strings.xml
+++ b/packages/PrintSpooler/res/values-cs/strings.xml
@@ -41,6 +41,8 @@
<string name="print_search_box_shown_utterance" msgid="7967404953901376090">"Vyhledávací pole se zobrazuje"</string>
<string name="print_search_box_hidden_utterance" msgid="5727755169343113351">"Vyhledávací pole je skryto"</string>
<string name="print_add_printer" msgid="1088656468360653455">"Přidat tiskárnu"</string>
+ <string name="print_select_printer" msgid="7388760939873368698">"Vybrat tiskárnu"</string>
+ <string name="print_forget_printer" msgid="5035287497291910766">"Odstranit tiskárnu"</string>
<plurals name="print_search_result_count_utterance">
<item quantity="one" msgid="4484953260685964252">"Počet nalezených tiskáren: <xliff:g id="COUNT">%1$s</xliff:g>"</item>
<item quantity="other" msgid="6533817036607128241">"Počet nalezených tiskáren: <xliff:g id="COUNT">%1$s</xliff:g>"</item>
diff --git a/packages/PrintSpooler/res/values-da/strings.xml b/packages/PrintSpooler/res/values-da/strings.xml
index 60c22bb..74190b4 100644
--- a/packages/PrintSpooler/res/values-da/strings.xml
+++ b/packages/PrintSpooler/res/values-da/strings.xml
@@ -41,6 +41,8 @@
<string name="print_search_box_shown_utterance" msgid="7967404953901376090">"Søgefeltet vises"</string>
<string name="print_search_box_hidden_utterance" msgid="5727755169343113351">"Søgefeltet er skjult"</string>
<string name="print_add_printer" msgid="1088656468360653455">"Tilføj printer"</string>
+ <string name="print_select_printer" msgid="7388760939873368698">"Vælg printer"</string>
+ <string name="print_forget_printer" msgid="5035287497291910766">"Glem printer"</string>
<plurals name="print_search_result_count_utterance">
<item quantity="one" msgid="4484953260685964252">"Der blev fundet <xliff:g id="COUNT">%1$s</xliff:g> printer"</item>
<item quantity="other" msgid="6533817036607128241">"Der blev fundet <xliff:g id="COUNT">%1$s</xliff:g> printere"</item>
diff --git a/packages/PrintSpooler/res/values-de/strings.xml b/packages/PrintSpooler/res/values-de/strings.xml
index 54c936f..6b83ac3 100644
--- a/packages/PrintSpooler/res/values-de/strings.xml
+++ b/packages/PrintSpooler/res/values-de/strings.xml
@@ -41,6 +41,8 @@
<string name="print_search_box_shown_utterance" msgid="7967404953901376090">"Suchfeld angezeigt"</string>
<string name="print_search_box_hidden_utterance" msgid="5727755169343113351">"Suchfeld ausgeblendet"</string>
<string name="print_add_printer" msgid="1088656468360653455">"Drucker hinzufügen"</string>
+ <string name="print_select_printer" msgid="7388760939873368698">"Drucker auswählen"</string>
+ <string name="print_forget_printer" msgid="5035287497291910766">"Drucker wieder vergessen"</string>
<plurals name="print_search_result_count_utterance">
<item quantity="one" msgid="4484953260685964252">"<xliff:g id="COUNT">%1$s</xliff:g> Drucker gefunden"</item>
<item quantity="other" msgid="6533817036607128241">"<xliff:g id="COUNT">%1$s</xliff:g> Drucker gefunden"</item>
diff --git a/packages/PrintSpooler/res/values-el/strings.xml b/packages/PrintSpooler/res/values-el/strings.xml
index 168f87b..795e730 100644
--- a/packages/PrintSpooler/res/values-el/strings.xml
+++ b/packages/PrintSpooler/res/values-el/strings.xml
@@ -41,6 +41,8 @@
<string name="print_search_box_shown_utterance" msgid="7967404953901376090">"Εμφάνιση πλαισίου αναζήτησης"</string>
<string name="print_search_box_hidden_utterance" msgid="5727755169343113351">"Απόκρυψη πλαισίου αναζήτησης"</string>
<string name="print_add_printer" msgid="1088656468360653455">"Προσθήκη εκτυπωτή"</string>
+ <string name="print_select_printer" msgid="7388760939873368698">"Επιλογή εκτυπωτή"</string>
+ <string name="print_forget_printer" msgid="5035287497291910766">"Διαγραφή εκτυπωτή"</string>
<plurals name="print_search_result_count_utterance">
<item quantity="one" msgid="4484953260685964252">"Βρέθηκε <xliff:g id="COUNT">%1$s</xliff:g> εκτυπωτής"</item>
<item quantity="other" msgid="6533817036607128241">"Βρέθηκαν <xliff:g id="COUNT">%1$s</xliff:g> εκτυπωτές"</item>
diff --git a/packages/PrintSpooler/res/values-en-rGB/strings.xml b/packages/PrintSpooler/res/values-en-rGB/strings.xml
index 98c3688..27372f8 100644
--- a/packages/PrintSpooler/res/values-en-rGB/strings.xml
+++ b/packages/PrintSpooler/res/values-en-rGB/strings.xml
@@ -41,6 +41,8 @@
<string name="print_search_box_shown_utterance" msgid="7967404953901376090">"Search box shown"</string>
<string name="print_search_box_hidden_utterance" msgid="5727755169343113351">"Search box hidden"</string>
<string name="print_add_printer" msgid="1088656468360653455">"Add printer"</string>
+ <string name="print_select_printer" msgid="7388760939873368698">"Select printer"</string>
+ <string name="print_forget_printer" msgid="5035287497291910766">"Forget printer"</string>
<plurals name="print_search_result_count_utterance">
<item quantity="one" msgid="4484953260685964252">"<xliff:g id="COUNT">%1$s</xliff:g> printer found"</item>
<item quantity="other" msgid="6533817036607128241">"<xliff:g id="COUNT">%1$s</xliff:g> printers found"</item>
diff --git a/packages/PrintSpooler/res/values-en-rIN/strings.xml b/packages/PrintSpooler/res/values-en-rIN/strings.xml
index 98c3688..27372f8 100644
--- a/packages/PrintSpooler/res/values-en-rIN/strings.xml
+++ b/packages/PrintSpooler/res/values-en-rIN/strings.xml
@@ -41,6 +41,8 @@
<string name="print_search_box_shown_utterance" msgid="7967404953901376090">"Search box shown"</string>
<string name="print_search_box_hidden_utterance" msgid="5727755169343113351">"Search box hidden"</string>
<string name="print_add_printer" msgid="1088656468360653455">"Add printer"</string>
+ <string name="print_select_printer" msgid="7388760939873368698">"Select printer"</string>
+ <string name="print_forget_printer" msgid="5035287497291910766">"Forget printer"</string>
<plurals name="print_search_result_count_utterance">
<item quantity="one" msgid="4484953260685964252">"<xliff:g id="COUNT">%1$s</xliff:g> printer found"</item>
<item quantity="other" msgid="6533817036607128241">"<xliff:g id="COUNT">%1$s</xliff:g> printers found"</item>
diff --git a/packages/PrintSpooler/res/values-es-rUS/strings.xml b/packages/PrintSpooler/res/values-es-rUS/strings.xml
index bfdf933..c7d12af 100644
--- a/packages/PrintSpooler/res/values-es-rUS/strings.xml
+++ b/packages/PrintSpooler/res/values-es-rUS/strings.xml
@@ -41,6 +41,8 @@
<string name="print_search_box_shown_utterance" msgid="7967404953901376090">"Cuadro de búsqueda visible"</string>
<string name="print_search_box_hidden_utterance" msgid="5727755169343113351">"Cuadro de búsqueda oculto"</string>
<string name="print_add_printer" msgid="1088656468360653455">"Agregar impresora"</string>
+ <string name="print_select_printer" msgid="7388760939873368698">"Seleccionar impresora"</string>
+ <string name="print_forget_printer" msgid="5035287497291910766">"No recordar impresora"</string>
<plurals name="print_search_result_count_utterance">
<item quantity="one" msgid="4484953260685964252">"Se encontró <xliff:g id="COUNT">%1$s</xliff:g> impresora."</item>
<item quantity="other" msgid="6533817036607128241">"Se encontraron <xliff:g id="COUNT">%1$s</xliff:g> impresoras."</item>
diff --git a/packages/PrintSpooler/res/values-es/strings.xml b/packages/PrintSpooler/res/values-es/strings.xml
index 28df5f0..0225cad 100644
--- a/packages/PrintSpooler/res/values-es/strings.xml
+++ b/packages/PrintSpooler/res/values-es/strings.xml
@@ -41,6 +41,8 @@
<string name="print_search_box_shown_utterance" msgid="7967404953901376090">"Cuadro de búsqueda visible"</string>
<string name="print_search_box_hidden_utterance" msgid="5727755169343113351">"Cuadro de búsqueda oculto"</string>
<string name="print_add_printer" msgid="1088656468360653455">"Añadir impresora"</string>
+ <string name="print_select_printer" msgid="7388760939873368698">"Seleccionar impresora"</string>
+ <string name="print_forget_printer" msgid="5035287497291910766">"Borrar impresora"</string>
<plurals name="print_search_result_count_utterance">
<item quantity="one" msgid="4484953260685964252">"Se ha encontrado <xliff:g id="COUNT">%1$s</xliff:g> impresora"</item>
<item quantity="other" msgid="6533817036607128241">"Se han encontrado <xliff:g id="COUNT">%1$s</xliff:g> impresoras"</item>
diff --git a/packages/PrintSpooler/res/values-et-rEE/strings.xml b/packages/PrintSpooler/res/values-et-rEE/strings.xml
index 1114f9f..2b3b352 100644
--- a/packages/PrintSpooler/res/values-et-rEE/strings.xml
+++ b/packages/PrintSpooler/res/values-et-rEE/strings.xml
@@ -41,6 +41,8 @@
<string name="print_search_box_shown_utterance" msgid="7967404953901376090">"Otsingukast on kuvatud"</string>
<string name="print_search_box_hidden_utterance" msgid="5727755169343113351">"Otsingukast on peidetud"</string>
<string name="print_add_printer" msgid="1088656468360653455">"Lisa printer"</string>
+ <string name="print_select_printer" msgid="7388760939873368698">"Printeri valimine"</string>
+ <string name="print_forget_printer" msgid="5035287497291910766">"Printeri unustamine"</string>
<plurals name="print_search_result_count_utterance">
<item quantity="one" msgid="4484953260685964252">"Leiti <xliff:g id="COUNT">%1$s</xliff:g> printer"</item>
<item quantity="other" msgid="6533817036607128241">"Leiti <xliff:g id="COUNT">%1$s</xliff:g> printerit"</item>
diff --git a/packages/PrintSpooler/res/values-fa/strings.xml b/packages/PrintSpooler/res/values-fa/strings.xml
index 950ef92..49bae323 100644
--- a/packages/PrintSpooler/res/values-fa/strings.xml
+++ b/packages/PrintSpooler/res/values-fa/strings.xml
@@ -41,6 +41,8 @@
<string name="print_search_box_shown_utterance" msgid="7967404953901376090">"کادر جستجو نمایان شد"</string>
<string name="print_search_box_hidden_utterance" msgid="5727755169343113351">"کادر جستجو پنهان شد"</string>
<string name="print_add_printer" msgid="1088656468360653455">"افزودن چاپگر"</string>
+ <string name="print_select_printer" msgid="7388760939873368698">"انتخاب چاپگر"</string>
+ <string name="print_forget_printer" msgid="5035287497291910766">"فراموش کردن چاپگر"</string>
<plurals name="print_search_result_count_utterance">
<item quantity="one" msgid="4484953260685964252">"<xliff:g id="COUNT">%1$s</xliff:g> چاپگر یافت شد"</item>
<item quantity="other" msgid="6533817036607128241">"<xliff:g id="COUNT">%1$s</xliff:g> چاپگر یافت شد"</item>
diff --git a/packages/PrintSpooler/res/values-fi/strings.xml b/packages/PrintSpooler/res/values-fi/strings.xml
index 239afcf..8658e04 100644
--- a/packages/PrintSpooler/res/values-fi/strings.xml
+++ b/packages/PrintSpooler/res/values-fi/strings.xml
@@ -41,6 +41,8 @@
<string name="print_search_box_shown_utterance" msgid="7967404953901376090">"Hakukenttä näkyvissä"</string>
<string name="print_search_box_hidden_utterance" msgid="5727755169343113351">"Hakukenttä piilotettu"</string>
<string name="print_add_printer" msgid="1088656468360653455">"Lisää tulostin"</string>
+ <string name="print_select_printer" msgid="7388760939873368698">"Valitse tulostin"</string>
+ <string name="print_forget_printer" msgid="5035287497291910766">"Unohda tulostin"</string>
<plurals name="print_search_result_count_utterance">
<item quantity="one" msgid="4484953260685964252">"Löytyi <xliff:g id="COUNT">%1$s</xliff:g> tulostin"</item>
<item quantity="other" msgid="6533817036607128241">"Löytyi <xliff:g id="COUNT">%1$s</xliff:g> tulostinta"</item>
diff --git a/packages/PrintSpooler/res/values-fr-rCA/strings.xml b/packages/PrintSpooler/res/values-fr-rCA/strings.xml
index 3880745..9a3352c 100644
--- a/packages/PrintSpooler/res/values-fr-rCA/strings.xml
+++ b/packages/PrintSpooler/res/values-fr-rCA/strings.xml
@@ -41,6 +41,8 @@
<string name="print_search_box_shown_utterance" msgid="7967404953901376090">"Champ de recherche affiché"</string>
<string name="print_search_box_hidden_utterance" msgid="5727755169343113351">"Champ de recherche masqué"</string>
<string name="print_add_printer" msgid="1088656468360653455">"Ajouter une imprimante"</string>
+ <string name="print_select_printer" msgid="7388760939873368698">"Sélectionner une imprimante"</string>
+ <string name="print_forget_printer" msgid="5035287497291910766">"Supprimer l\'imprimante"</string>
<plurals name="print_search_result_count_utterance">
<item quantity="one" msgid="4484953260685964252">"<xliff:g id="COUNT">%1$s</xliff:g> imprimante trouvée"</item>
<item quantity="other" msgid="6533817036607128241">"<xliff:g id="COUNT">%1$s</xliff:g> imprimantes trouvées"</item>
diff --git a/packages/PrintSpooler/res/values-fr/strings.xml b/packages/PrintSpooler/res/values-fr/strings.xml
index 961d344..cfb557e 100644
--- a/packages/PrintSpooler/res/values-fr/strings.xml
+++ b/packages/PrintSpooler/res/values-fr/strings.xml
@@ -41,6 +41,8 @@
<string name="print_search_box_shown_utterance" msgid="7967404953901376090">"Champ de recherche affiché."</string>
<string name="print_search_box_hidden_utterance" msgid="5727755169343113351">"Champ de recherche masqué."</string>
<string name="print_add_printer" msgid="1088656468360653455">"Ajouter une imprimante"</string>
+ <string name="print_select_printer" msgid="7388760939873368698">"Sélectionner une imprimante"</string>
+ <string name="print_forget_printer" msgid="5035287497291910766">"Supprimer l\'imprimante"</string>
<plurals name="print_search_result_count_utterance">
<item quantity="one" msgid="4484953260685964252">"<xliff:g id="COUNT">%1$s</xliff:g> imprimante trouvée."</item>
<item quantity="other" msgid="6533817036607128241">"<xliff:g id="COUNT">%1$s</xliff:g> imprimantes trouvées."</item>
diff --git a/packages/PrintSpooler/res/values-hi/strings.xml b/packages/PrintSpooler/res/values-hi/strings.xml
index 4d1ddd8..60406b7 100644
--- a/packages/PrintSpooler/res/values-hi/strings.xml
+++ b/packages/PrintSpooler/res/values-hi/strings.xml
@@ -41,6 +41,8 @@
<string name="print_search_box_shown_utterance" msgid="7967404953901376090">"खोज बॉक्स प्रदर्शित है"</string>
<string name="print_search_box_hidden_utterance" msgid="5727755169343113351">"खोज बॉक्स छिपा हुआ है"</string>
<string name="print_add_printer" msgid="1088656468360653455">"प्रिंटर जोड़ें"</string>
+ <string name="print_select_printer" msgid="7388760939873368698">"प्रिंटर चुनें"</string>
+ <string name="print_forget_printer" msgid="5035287497291910766">"प्रिंटर को भूल जाएं"</string>
<plurals name="print_search_result_count_utterance">
<item quantity="one" msgid="4484953260685964252">"<xliff:g id="COUNT">%1$s</xliff:g> प्रिंटर मिला"</item>
<item quantity="other" msgid="6533817036607128241">"<xliff:g id="COUNT">%1$s</xliff:g> प्रिंटर मिले"</item>
diff --git a/packages/PrintSpooler/res/values-hr/strings.xml b/packages/PrintSpooler/res/values-hr/strings.xml
index 50b56ff..7182cf6 100644
--- a/packages/PrintSpooler/res/values-hr/strings.xml
+++ b/packages/PrintSpooler/res/values-hr/strings.xml
@@ -41,6 +41,8 @@
<string name="print_search_box_shown_utterance" msgid="7967404953901376090">"Okvir za pretraživanje prikazan je"</string>
<string name="print_search_box_hidden_utterance" msgid="5727755169343113351">"Okvir za pretraživanje skriven je"</string>
<string name="print_add_printer" msgid="1088656468360653455">"Dodaj pisač"</string>
+ <string name="print_select_printer" msgid="7388760939873368698">"Odaberite pisač"</string>
+ <string name="print_forget_printer" msgid="5035287497291910766">"Zaboravite pisač"</string>
<plurals name="print_search_result_count_utterance">
<item quantity="one" msgid="4484953260685964252">"Pronađen je <xliff:g id="COUNT">%1$s</xliff:g> pisač"</item>
<item quantity="other" msgid="6533817036607128241">"Pronađen je sljedeći broj pisača: <xliff:g id="COUNT">%1$s</xliff:g>"</item>
diff --git a/packages/PrintSpooler/res/values-hu/strings.xml b/packages/PrintSpooler/res/values-hu/strings.xml
index 79912fc..6a0741b 100644
--- a/packages/PrintSpooler/res/values-hu/strings.xml
+++ b/packages/PrintSpooler/res/values-hu/strings.xml
@@ -41,6 +41,8 @@
<string name="print_search_box_shown_utterance" msgid="7967404953901376090">"Keresőmező megjelenítve"</string>
<string name="print_search_box_hidden_utterance" msgid="5727755169343113351">"Keresőmező elrejtve"</string>
<string name="print_add_printer" msgid="1088656468360653455">"Nyomtató hozzáadása"</string>
+ <string name="print_select_printer" msgid="7388760939873368698">"Nyomtató kiválasztása"</string>
+ <string name="print_forget_printer" msgid="5035287497291910766">"Nyomtató elfelejtése"</string>
<plurals name="print_search_result_count_utterance">
<item quantity="one" msgid="4484953260685964252">"<xliff:g id="COUNT">%1$s</xliff:g> nyomtató észlelve"</item>
<item quantity="other" msgid="6533817036607128241">"<xliff:g id="COUNT">%1$s</xliff:g> nyomtató észlelve"</item>
diff --git a/packages/PrintSpooler/res/values-hy-rAM/strings.xml b/packages/PrintSpooler/res/values-hy-rAM/strings.xml
index 7d95f7b..1423b82 100644
--- a/packages/PrintSpooler/res/values-hy-rAM/strings.xml
+++ b/packages/PrintSpooler/res/values-hy-rAM/strings.xml
@@ -41,6 +41,8 @@
<string name="print_search_box_shown_utterance" msgid="7967404953901376090">"Որոնման վանդակը ցուցադրված է"</string>
<string name="print_search_box_hidden_utterance" msgid="5727755169343113351">"Որոնման վանդակը թաքցվել է"</string>
<string name="print_add_printer" msgid="1088656468360653455">"Ավելացնել տպիչ"</string>
+ <string name="print_select_printer" msgid="7388760939873368698">"Ընտրել տպիչ"</string>
+ <string name="print_forget_printer" msgid="5035287497291910766">"Մոռանալ տպիչը"</string>
<plurals name="print_search_result_count_utterance">
<item quantity="one" msgid="4484953260685964252">"<xliff:g id="COUNT">%1$s</xliff:g> տպիչ է գտնվել"</item>
<item quantity="other" msgid="6533817036607128241">"<xliff:g id="COUNT">%1$s</xliff:g> տպիչ է գտնվել"</item>
diff --git a/packages/PrintSpooler/res/values-in/strings.xml b/packages/PrintSpooler/res/values-in/strings.xml
index 1206676..2b80d07 100644
--- a/packages/PrintSpooler/res/values-in/strings.xml
+++ b/packages/PrintSpooler/res/values-in/strings.xml
@@ -41,6 +41,8 @@
<string name="print_search_box_shown_utterance" msgid="7967404953901376090">"Kotak telusur ditampilkan"</string>
<string name="print_search_box_hidden_utterance" msgid="5727755169343113351">"Kotak telusur disembunyikan"</string>
<string name="print_add_printer" msgid="1088656468360653455">"Tambahkan printer"</string>
+ <string name="print_select_printer" msgid="7388760939873368698">"Pilih printer"</string>
+ <string name="print_forget_printer" msgid="5035287497291910766">"Lupakan printer"</string>
<plurals name="print_search_result_count_utterance">
<item quantity="one" msgid="4484953260685964252">"<xliff:g id="COUNT">%1$s</xliff:g> printer ditemukan"</item>
<item quantity="other" msgid="6533817036607128241">"<xliff:g id="COUNT">%1$s</xliff:g> printer ditemukan"</item>
diff --git a/packages/PrintSpooler/res/values-it/strings.xml b/packages/PrintSpooler/res/values-it/strings.xml
index 4223188..96c3b48 100644
--- a/packages/PrintSpooler/res/values-it/strings.xml
+++ b/packages/PrintSpooler/res/values-it/strings.xml
@@ -41,6 +41,8 @@
<string name="print_search_box_shown_utterance" msgid="7967404953901376090">"Casella di ricerca visualizzata"</string>
<string name="print_search_box_hidden_utterance" msgid="5727755169343113351">"Casella di ricerca nascosta"</string>
<string name="print_add_printer" msgid="1088656468360653455">"Aggiungi stampante"</string>
+ <string name="print_select_printer" msgid="7388760939873368698">"Seleziona stampante"</string>
+ <string name="print_forget_printer" msgid="5035287497291910766">"Elimina stampante"</string>
<plurals name="print_search_result_count_utterance">
<item quantity="one" msgid="4484953260685964252">"<xliff:g id="COUNT">%1$s</xliff:g> stampante trovata"</item>
<item quantity="other" msgid="6533817036607128241">"<xliff:g id="COUNT">%1$s</xliff:g> stampanti trovate"</item>
diff --git a/packages/PrintSpooler/res/values-iw/strings.xml b/packages/PrintSpooler/res/values-iw/strings.xml
index 2a9e0df..3e0e732 100644
--- a/packages/PrintSpooler/res/values-iw/strings.xml
+++ b/packages/PrintSpooler/res/values-iw/strings.xml
@@ -41,6 +41,8 @@
<string name="print_search_box_shown_utterance" msgid="7967404953901376090">"תיבת החיפוש מוצגת"</string>
<string name="print_search_box_hidden_utterance" msgid="5727755169343113351">"תיבת החיפוש מוסתרת"</string>
<string name="print_add_printer" msgid="1088656468360653455">"הוסף מדפסת"</string>
+ <string name="print_select_printer" msgid="7388760939873368698">"בחר מדפסת"</string>
+ <string name="print_forget_printer" msgid="5035287497291910766">"שכח את המדפסת"</string>
<plurals name="print_search_result_count_utterance">
<item quantity="one" msgid="4484953260685964252">"נמצאה מדפסת <xliff:g id="COUNT">%1$s</xliff:g>"</item>
<item quantity="other" msgid="6533817036607128241">"נמצאו <xliff:g id="COUNT">%1$s</xliff:g> מדפסות"</item>
diff --git a/packages/PrintSpooler/res/values-ja/arrays.xml b/packages/PrintSpooler/res/values-ja/arrays.xml
index 57088c8..460bdb2 100644
--- a/packages/PrintSpooler/res/values-ja/arrays.xml
+++ b/packages/PrintSpooler/res/values-ja/arrays.xml
@@ -20,13 +20,13 @@
<item>JIS_B9</item>
<item>JIS_B8</item>
<item>JIS_B7</item>
- <item>JIS_b6</item>
- <item>JIS_b5</item>
- <item>JIS_b4</item>
- <item>JIS_b3</item>
- <item>JIS_b2</item>
- <item>JIS_b1</item>
- <item>JIS_b0</item>
+ <item>JIS_B6</item>
+ <item>JIS_B5</item>
+ <item>JIS_B4</item>
+ <item>JIS_B3</item>
+ <item>JIS_B2</item>
+ <item>JIS_B1</item>
+ <item>JIS_B0</item>
<item>JIS_EXEC</item>
<item>JPN_CHOU4</item>
<item>JPN_CHOU3</item>
diff --git a/packages/PrintSpooler/res/values-ja/strings.xml b/packages/PrintSpooler/res/values-ja/strings.xml
index e6ae97a..94e8441 100644
--- a/packages/PrintSpooler/res/values-ja/strings.xml
+++ b/packages/PrintSpooler/res/values-ja/strings.xml
@@ -41,6 +41,8 @@
<string name="print_search_box_shown_utterance" msgid="7967404953901376090">"検索ボックスは表示されています"</string>
<string name="print_search_box_hidden_utterance" msgid="5727755169343113351">"検索ボックスは表示されていません"</string>
<string name="print_add_printer" msgid="1088656468360653455">"プリンタを追加"</string>
+ <string name="print_select_printer" msgid="7388760939873368698">"プリンタを選択"</string>
+ <string name="print_forget_printer" msgid="5035287497291910766">"プリンタを切断"</string>
<plurals name="print_search_result_count_utterance">
<item quantity="one" msgid="4484953260685964252">"<xliff:g id="COUNT">%1$s</xliff:g>台のプリンタが見つかりました"</item>
<item quantity="other" msgid="6533817036607128241">"<xliff:g id="COUNT">%1$s</xliff:g>台のプリンタが見つかりました"</item>
diff --git a/packages/PrintSpooler/res/values-ka-rGE/strings.xml b/packages/PrintSpooler/res/values-ka-rGE/strings.xml
index 3fc1f3a..d36b7c9 100644
--- a/packages/PrintSpooler/res/values-ka-rGE/strings.xml
+++ b/packages/PrintSpooler/res/values-ka-rGE/strings.xml
@@ -41,6 +41,8 @@
<string name="print_search_box_shown_utterance" msgid="7967404953901376090">"საძიებო ველი ნაჩვენებია"</string>
<string name="print_search_box_hidden_utterance" msgid="5727755169343113351">"საძიებო ველი დამალულია"</string>
<string name="print_add_printer" msgid="1088656468360653455">"პრინტერის დამატება"</string>
+ <string name="print_select_printer" msgid="7388760939873368698">"პრინტერის არჩევა"</string>
+ <string name="print_forget_printer" msgid="5035287497291910766">"პრინტერის დავიწყება"</string>
<plurals name="print_search_result_count_utterance">
<item quantity="one" msgid="4484953260685964252">"ნაპოვნია <xliff:g id="COUNT">%1$s</xliff:g> პრინტერი"</item>
<item quantity="other" msgid="6533817036607128241">"ნაპოვნია <xliff:g id="COUNT">%1$s</xliff:g> პრინტერი"</item>
diff --git a/packages/PrintSpooler/res/values-km-rKH/strings.xml b/packages/PrintSpooler/res/values-km-rKH/strings.xml
index 8ed85273..c89f9bf 100644
--- a/packages/PrintSpooler/res/values-km-rKH/strings.xml
+++ b/packages/PrintSpooler/res/values-km-rKH/strings.xml
@@ -41,6 +41,8 @@
<string name="print_search_box_shown_utterance" msgid="7967404953901376090">"បានបង្ហាញប្រអប់ស្វែងរក"</string>
<string name="print_search_box_hidden_utterance" msgid="5727755169343113351">"បានលាក់ប្រអប់ស្វែងរក"</string>
<string name="print_add_printer" msgid="1088656468360653455">"បន្ថែមម៉ាស៊ីនបោះពុម្ព"</string>
+ <string name="print_select_printer" msgid="7388760939873368698">"ជ្រើសម៉ាស៊ីនបោះពុម្ព"</string>
+ <string name="print_forget_printer" msgid="5035287497291910766">"ភ្លេចម៉ាស៊ីនបោះពុម្ព"</string>
<plurals name="print_search_result_count_utterance">
<item quantity="one" msgid="4484953260685964252">"រកឃើញម៉ាស៊ីនបោះពុម្ព <xliff:g id="COUNT">%1$s</xliff:g>"</item>
<item quantity="other" msgid="6533817036607128241">"រកឃើញម៉ាស៊ីនបោះពុម្ព <xliff:g id="COUNT">%1$s</xliff:g>"</item>
diff --git a/packages/PrintSpooler/res/values-ko/strings.xml b/packages/PrintSpooler/res/values-ko/strings.xml
index 83155fd..3b2fef7 100644
--- a/packages/PrintSpooler/res/values-ko/strings.xml
+++ b/packages/PrintSpooler/res/values-ko/strings.xml
@@ -41,6 +41,8 @@
<string name="print_search_box_shown_utterance" msgid="7967404953901376090">"검색창 표시됨"</string>
<string name="print_search_box_hidden_utterance" msgid="5727755169343113351">"검색창 숨겨짐"</string>
<string name="print_add_printer" msgid="1088656468360653455">"프린터 추가"</string>
+ <string name="print_select_printer" msgid="7388760939873368698">"프린터 선택"</string>
+ <string name="print_forget_printer" msgid="5035287497291910766">"프린터 삭제"</string>
<plurals name="print_search_result_count_utterance">
<item quantity="one" msgid="4484953260685964252">"프린터 <xliff:g id="COUNT">%1$s</xliff:g>대 검색됨"</item>
<item quantity="other" msgid="6533817036607128241">"프린터 <xliff:g id="COUNT">%1$s</xliff:g>대 검색됨"</item>
diff --git a/packages/PrintSpooler/res/values-lo-rLA/strings.xml b/packages/PrintSpooler/res/values-lo-rLA/strings.xml
index 45bb9bc..f954606 100644
--- a/packages/PrintSpooler/res/values-lo-rLA/strings.xml
+++ b/packages/PrintSpooler/res/values-lo-rLA/strings.xml
@@ -41,6 +41,8 @@
<string name="print_search_box_shown_utterance" msgid="7967404953901376090">"ກ່ອງຊອກຫາຖືກສະແດງ"</string>
<string name="print_search_box_hidden_utterance" msgid="5727755169343113351">"ກ່ອງຊອກຫາຖືກເຊື່ອງ"</string>
<string name="print_add_printer" msgid="1088656468360653455">"ເພີ່ມເຄື່ອງພິມ"</string>
+ <string name="print_select_printer" msgid="7388760939873368698">"ເລືອກເຄື່ອງພິມ"</string>
+ <string name="print_forget_printer" msgid="5035287497291910766">"ລືມເຄື່ອງພິມ"</string>
<plurals name="print_search_result_count_utterance">
<item quantity="one" msgid="4484953260685964252">"ພົບ <xliff:g id="COUNT">%1$s</xliff:g> ເຄື່ອງພິມ"</item>
<item quantity="other" msgid="6533817036607128241">"ພົບ <xliff:g id="COUNT">%1$s</xliff:g> ເຄື່ອງພິມ"</item>
diff --git a/packages/PrintSpooler/res/values-lt/strings.xml b/packages/PrintSpooler/res/values-lt/strings.xml
index 1560dce..0c4e386 100644
--- a/packages/PrintSpooler/res/values-lt/strings.xml
+++ b/packages/PrintSpooler/res/values-lt/strings.xml
@@ -41,6 +41,8 @@
<string name="print_search_box_shown_utterance" msgid="7967404953901376090">"Paieškos laukelis rodomas"</string>
<string name="print_search_box_hidden_utterance" msgid="5727755169343113351">"Paieškos laukelis paslėptas"</string>
<string name="print_add_printer" msgid="1088656468360653455">"Pridėti spausdintuvą"</string>
+ <string name="print_select_printer" msgid="7388760939873368698">"Pasirinkti spausdintuvą"</string>
+ <string name="print_forget_printer" msgid="5035287497291910766">"Pamiršti spausdintuvą"</string>
<plurals name="print_search_result_count_utterance">
<item quantity="one" msgid="4484953260685964252">"Rasta spausdintuvų: <xliff:g id="COUNT">%1$s</xliff:g>"</item>
<item quantity="other" msgid="6533817036607128241">"Rasta spausdintuvų: <xliff:g id="COUNT">%1$s</xliff:g>"</item>
diff --git a/packages/PrintSpooler/res/values-lv/strings.xml b/packages/PrintSpooler/res/values-lv/strings.xml
index 3a6049c..3fffdfe 100644
--- a/packages/PrintSpooler/res/values-lv/strings.xml
+++ b/packages/PrintSpooler/res/values-lv/strings.xml
@@ -41,6 +41,8 @@
<string name="print_search_box_shown_utterance" msgid="7967404953901376090">"Meklēšanas lodziņš ir redzams."</string>
<string name="print_search_box_hidden_utterance" msgid="5727755169343113351">"Meklēšanas lodziņš ir paslēpts."</string>
<string name="print_add_printer" msgid="1088656468360653455">"Pievienot printeri"</string>
+ <string name="print_select_printer" msgid="7388760939873368698">"Atlasīt printeri"</string>
+ <string name="print_forget_printer" msgid="5035287497291910766">"Neatcerēties printeri"</string>
<plurals name="print_search_result_count_utterance">
<item quantity="one" msgid="4484953260685964252">"Atrasts <xliff:g id="COUNT">%1$s</xliff:g> printeris"</item>
<item quantity="other" msgid="6533817036607128241">"Atrasti <xliff:g id="COUNT">%1$s</xliff:g> printeri"</item>
diff --git a/packages/PrintSpooler/res/values-mn-rMN/strings.xml b/packages/PrintSpooler/res/values-mn-rMN/strings.xml
index 8062eb1..e429387 100644
--- a/packages/PrintSpooler/res/values-mn-rMN/strings.xml
+++ b/packages/PrintSpooler/res/values-mn-rMN/strings.xml
@@ -41,6 +41,8 @@
<string name="print_search_box_shown_utterance" msgid="7967404953901376090">"Хайлтын нүдийг гаргах"</string>
<string name="print_search_box_hidden_utterance" msgid="5727755169343113351">"Хайлтын нүдийг далдлах"</string>
<string name="print_add_printer" msgid="1088656468360653455">"Принтер нэмэх"</string>
+ <string name="print_select_printer" msgid="7388760939873368698">"Принтер сонгох"</string>
+ <string name="print_forget_printer" msgid="5035287497291910766">"Принтерийг мартах"</string>
<plurals name="print_search_result_count_utterance">
<item quantity="one" msgid="4484953260685964252">"<xliff:g id="COUNT">%1$s</xliff:g> принтер олдсон"</item>
<item quantity="other" msgid="6533817036607128241">"<xliff:g id="COUNT">%1$s</xliff:g> принтер олдсон"</item>
diff --git a/packages/PrintSpooler/res/values-ms-rMY/strings.xml b/packages/PrintSpooler/res/values-ms-rMY/strings.xml
index d113749..cca5d2c 100644
--- a/packages/PrintSpooler/res/values-ms-rMY/strings.xml
+++ b/packages/PrintSpooler/res/values-ms-rMY/strings.xml
@@ -41,6 +41,8 @@
<string name="print_search_box_shown_utterance" msgid="7967404953901376090">"Kotak carian ditunjukkan"</string>
<string name="print_search_box_hidden_utterance" msgid="5727755169343113351">"Kotak carian tersembunyi"</string>
<string name="print_add_printer" msgid="1088656468360653455">"Tambah pencetak"</string>
+ <string name="print_select_printer" msgid="7388760939873368698">"Pilih pencetak"</string>
+ <string name="print_forget_printer" msgid="5035287497291910766">"Lupakan pencetak"</string>
<plurals name="print_search_result_count_utterance">
<item quantity="one" msgid="4484953260685964252">"<xliff:g id="COUNT">%1$s</xliff:g> pencetak ditemui"</item>
<item quantity="other" msgid="6533817036607128241">"<xliff:g id="COUNT">%1$s</xliff:g> pencetak ditemui"</item>
diff --git a/packages/PrintSpooler/res/values-nb/strings.xml b/packages/PrintSpooler/res/values-nb/strings.xml
index abed60d..f6a60c6 100644
--- a/packages/PrintSpooler/res/values-nb/strings.xml
+++ b/packages/PrintSpooler/res/values-nb/strings.xml
@@ -41,6 +41,8 @@
<string name="print_search_box_shown_utterance" msgid="7967404953901376090">"Søkefeltet vises"</string>
<string name="print_search_box_hidden_utterance" msgid="5727755169343113351">"Søkefeltet er skjult"</string>
<string name="print_add_printer" msgid="1088656468360653455">"Legg til skriver"</string>
+ <string name="print_select_printer" msgid="7388760939873368698">"Velg skriver"</string>
+ <string name="print_forget_printer" msgid="5035287497291910766">"Glem skriveren"</string>
<plurals name="print_search_result_count_utterance">
<item quantity="one" msgid="4484953260685964252">"<xliff:g id="COUNT">%1$s</xliff:g> skriver ble funnet"</item>
<item quantity="other" msgid="6533817036607128241">"<xliff:g id="COUNT">%1$s</xliff:g> skrivere ble funnet"</item>
diff --git a/packages/PrintSpooler/res/values-nl/strings.xml b/packages/PrintSpooler/res/values-nl/strings.xml
index 3289d12..dc12508 100644
--- a/packages/PrintSpooler/res/values-nl/strings.xml
+++ b/packages/PrintSpooler/res/values-nl/strings.xml
@@ -41,6 +41,8 @@
<string name="print_search_box_shown_utterance" msgid="7967404953901376090">"Zoekvak weergegeven"</string>
<string name="print_search_box_hidden_utterance" msgid="5727755169343113351">"Zoekvak verborgen"</string>
<string name="print_add_printer" msgid="1088656468360653455">"Printer toevoegen"</string>
+ <string name="print_select_printer" msgid="7388760939873368698">"Printer selecteren"</string>
+ <string name="print_forget_printer" msgid="5035287497291910766">"Printer vergeten"</string>
<plurals name="print_search_result_count_utterance">
<item quantity="one" msgid="4484953260685964252">"<xliff:g id="COUNT">%1$s</xliff:g> printer gevonden"</item>
<item quantity="other" msgid="6533817036607128241">"<xliff:g id="COUNT">%1$s</xliff:g> printers gevonden"</item>
diff --git a/packages/PrintSpooler/res/values-pl/strings.xml b/packages/PrintSpooler/res/values-pl/strings.xml
index 10cb2e7..81acc76 100644
--- a/packages/PrintSpooler/res/values-pl/strings.xml
+++ b/packages/PrintSpooler/res/values-pl/strings.xml
@@ -41,6 +41,8 @@
<string name="print_search_box_shown_utterance" msgid="7967404953901376090">"Pole wyszukiwania jest widoczne"</string>
<string name="print_search_box_hidden_utterance" msgid="5727755169343113351">"Pole wyszukiwania jest ukryte"</string>
<string name="print_add_printer" msgid="1088656468360653455">"Dodaj drukarkę"</string>
+ <string name="print_select_printer" msgid="7388760939873368698">"Wybierz drukarkę"</string>
+ <string name="print_forget_printer" msgid="5035287497291910766">"Nie zapamiętuj drukarki"</string>
<plurals name="print_search_result_count_utterance">
<item quantity="one" msgid="4484953260685964252">"Znaleziono <xliff:g id="COUNT">%1$s</xliff:g> drukarkę"</item>
<item quantity="other" msgid="6533817036607128241">"Znalezione drukarki: <xliff:g id="COUNT">%1$s</xliff:g>"</item>
diff --git a/packages/PrintSpooler/res/values-pt-rPT/strings.xml b/packages/PrintSpooler/res/values-pt-rPT/strings.xml
index 630fe03..6bfc395 100644
--- a/packages/PrintSpooler/res/values-pt-rPT/strings.xml
+++ b/packages/PrintSpooler/res/values-pt-rPT/strings.xml
@@ -41,6 +41,8 @@
<string name="print_search_box_shown_utterance" msgid="7967404953901376090">"Caixa de pesquisa apresentada"</string>
<string name="print_search_box_hidden_utterance" msgid="5727755169343113351">"Caixa de pesquisa ocultada"</string>
<string name="print_add_printer" msgid="1088656468360653455">"Adicionar impressora"</string>
+ <string name="print_select_printer" msgid="7388760939873368698">"Selecionar impressora"</string>
+ <string name="print_forget_printer" msgid="5035287497291910766">"Esquecer impressora"</string>
<plurals name="print_search_result_count_utterance">
<item quantity="one" msgid="4484953260685964252">"<xliff:g id="COUNT">%1$s</xliff:g> impressora encontrada"</item>
<item quantity="other" msgid="6533817036607128241">"<xliff:g id="COUNT">%1$s</xliff:g> impressoras encontradas"</item>
diff --git a/packages/PrintSpooler/res/values-pt/strings.xml b/packages/PrintSpooler/res/values-pt/strings.xml
index 6e5eab1..82c157d 100644
--- a/packages/PrintSpooler/res/values-pt/strings.xml
+++ b/packages/PrintSpooler/res/values-pt/strings.xml
@@ -41,6 +41,8 @@
<string name="print_search_box_shown_utterance" msgid="7967404953901376090">"Caixa de pesquisa exibida"</string>
<string name="print_search_box_hidden_utterance" msgid="5727755169343113351">"Caixa de pesquisa oculta"</string>
<string name="print_add_printer" msgid="1088656468360653455">"Adicionar impressora"</string>
+ <string name="print_select_printer" msgid="7388760939873368698">"Selecionar impressora"</string>
+ <string name="print_forget_printer" msgid="5035287497291910766">"Esquecer impressora"</string>
<plurals name="print_search_result_count_utterance">
<item quantity="one" msgid="4484953260685964252">"<xliff:g id="COUNT">%1$s</xliff:g> impressora encontrada"</item>
<item quantity="other" msgid="6533817036607128241">"<xliff:g id="COUNT">%1$s</xliff:g> impressoras encontradas"</item>
diff --git a/packages/PrintSpooler/res/values-ro/strings.xml b/packages/PrintSpooler/res/values-ro/strings.xml
index c4d9f8e..79c3bdc 100644
--- a/packages/PrintSpooler/res/values-ro/strings.xml
+++ b/packages/PrintSpooler/res/values-ro/strings.xml
@@ -41,6 +41,8 @@
<string name="print_search_box_shown_utterance" msgid="7967404953901376090">"Caseta de căutare este afișată"</string>
<string name="print_search_box_hidden_utterance" msgid="5727755169343113351">"Caseta de căutare este ascunsă"</string>
<string name="print_add_printer" msgid="1088656468360653455">"Adăugați o imprimantă"</string>
+ <string name="print_select_printer" msgid="7388760939873368698">"Selectați imprimanta"</string>
+ <string name="print_forget_printer" msgid="5035287497291910766">"Omiteți imprimanta"</string>
<plurals name="print_search_result_count_utterance">
<item quantity="one" msgid="4484953260685964252">"<xliff:g id="COUNT">%1$s</xliff:g> imprimantă găsită"</item>
<item quantity="other" msgid="6533817036607128241">"<xliff:g id="COUNT">%1$s</xliff:g> (de) imprimante găsite"</item>
diff --git a/packages/PrintSpooler/res/values-ru/strings.xml b/packages/PrintSpooler/res/values-ru/strings.xml
index b1335a0..a27f3c8 100644
--- a/packages/PrintSpooler/res/values-ru/strings.xml
+++ b/packages/PrintSpooler/res/values-ru/strings.xml
@@ -22,8 +22,8 @@
<string name="save_button" msgid="1921310454071758999">"Сохранить"</string>
<string name="label_destination" msgid="9132510997381599275">"Принтер"</string>
<string name="label_copies" msgid="3634531042822968308">"Копии"</string>
- <string name="label_paper_size" msgid="8681895607876809323">"Размер бумаги"</string>
- <string name="label_color" msgid="1108690305218188969">"Цветной"</string>
+ <string name="label_paper_size" msgid="8681895607876809323">"Формат"</string>
+ <string name="label_color" msgid="1108690305218188969">"Печать"</string>
<string name="label_orientation" msgid="2853142581990496477">"Ориентация"</string>
<string name="label_pages" msgid="6300874667546617333">"СТРАНИЦЫ (<xliff:g id="PAGE_COUNT">%1$s</xliff:g>)"</string>
<string name="pages_range_example" msgid="8558694453556945172">"напр., 1–5, 8, 11–13"</string>
@@ -32,7 +32,7 @@
<string name="printing_app_crashed" msgid="854477616686566398">"Сбой приложения печати"</string>
<string name="page_count_unknown" msgid="6058852665954511124">"Количество страниц"</string>
<string name="generating_print_job" msgid="3119608742651698916">"Создание задания печати…"</string>
- <string name="save_as_pdf" msgid="5718454119847596853">"Сохранить как PDF-файл"</string>
+ <string name="save_as_pdf" msgid="5718454119847596853">"Сохранить как PDF"</string>
<string name="all_printers" msgid="5018829726861876202">"Все принтеры"</string>
<string name="print_dialog" msgid="32628687461331979">"Диалоговое окно печати"</string>
<string name="search" msgid="5421724265322228497">"Поиск"</string>
@@ -41,6 +41,8 @@
<string name="print_search_box_shown_utterance" msgid="7967404953901376090">"Окно поиска показано"</string>
<string name="print_search_box_hidden_utterance" msgid="5727755169343113351">"Окно поиска скрыто"</string>
<string name="print_add_printer" msgid="1088656468360653455">"Добавить принтер"</string>
+ <string name="print_select_printer" msgid="7388760939873368698">"Выбрать принтер"</string>
+ <string name="print_forget_printer" msgid="5035287497291910766">"Удалить принтер"</string>
<plurals name="print_search_result_count_utterance">
<item quantity="one" msgid="4484953260685964252">"Найден <xliff:g id="COUNT">%1$s</xliff:g> принтер"</item>
<item quantity="other" msgid="6533817036607128241">"Найдено принтеров: <xliff:g id="COUNT">%1$s</xliff:g>"</item>
@@ -63,12 +65,12 @@
<string name="printer_unavailable" msgid="2434170617003315690">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> – недоступен"</string>
<string name="print_error_default_message" msgid="8568506918983980567">"Не удалось отправить документ на печать."</string>
<string-array name="color_mode_labels">
- <item msgid="7602948745415174937">"Черно-белое"</item>
- <item msgid="2762241247228983754">"Цветное"</item>
+ <item msgid="7602948745415174937">"Черно-белая"</item>
+ <item msgid="2762241247228983754">"Цветная"</item>
</string-array>
<string-array name="orientation_labels">
- <item msgid="4061931020926489228">"Книжная"</item>
- <item msgid="3199660090246166812">"Альбомная"</item>
+ <item msgid="4061931020926489228">"Книга"</item>
+ <item msgid="3199660090246166812">"Альбом"</item>
</string-array>
<string-array name="page_options_labels">
<item msgid="7421377442011699994">"Все"</item>
diff --git a/packages/PrintSpooler/res/values-sk/strings.xml b/packages/PrintSpooler/res/values-sk/strings.xml
index 922a759..39a022d 100644
--- a/packages/PrintSpooler/res/values-sk/strings.xml
+++ b/packages/PrintSpooler/res/values-sk/strings.xml
@@ -41,6 +41,8 @@
<string name="print_search_box_shown_utterance" msgid="7967404953901376090">"Vyhľadávacie pole sa zobrazuje"</string>
<string name="print_search_box_hidden_utterance" msgid="5727755169343113351">"Vyhľadávacie pole je skryté"</string>
<string name="print_add_printer" msgid="1088656468360653455">"Pridať tlačiareň"</string>
+ <string name="print_select_printer" msgid="7388760939873368698">"Vybrať tlačiareň"</string>
+ <string name="print_forget_printer" msgid="5035287497291910766">"Odstrániť tlačiareň"</string>
<plurals name="print_search_result_count_utterance">
<item quantity="one" msgid="4484953260685964252">"Našla sa <xliff:g id="COUNT">%1$s</xliff:g> tlačiareň"</item>
<item quantity="other" msgid="6533817036607128241">"Počet nájdených tlačiarní: <xliff:g id="COUNT">%1$s</xliff:g>"</item>
diff --git a/packages/PrintSpooler/res/values-sl/strings.xml b/packages/PrintSpooler/res/values-sl/strings.xml
index abd07c6..5d4fe94 100644
--- a/packages/PrintSpooler/res/values-sl/strings.xml
+++ b/packages/PrintSpooler/res/values-sl/strings.xml
@@ -41,6 +41,8 @@
<string name="print_search_box_shown_utterance" msgid="7967404953901376090">"Iskalno polje je prikazano"</string>
<string name="print_search_box_hidden_utterance" msgid="5727755169343113351">"Iskalno polje je skrito"</string>
<string name="print_add_printer" msgid="1088656468360653455">"Dodajanje tiskalnika"</string>
+ <string name="print_select_printer" msgid="7388760939873368698">"Izbira tiskalnika"</string>
+ <string name="print_forget_printer" msgid="5035287497291910766">"Odstranitev tiskalnika"</string>
<plurals name="print_search_result_count_utterance">
<item quantity="one" msgid="4484953260685964252">"Najden <xliff:g id="COUNT">%1$s</xliff:g> tiskalnik"</item>
<item quantity="other" msgid="6533817036607128241">"Število najdenih tiskalnikov: <xliff:g id="COUNT">%1$s</xliff:g>"</item>
diff --git a/packages/PrintSpooler/res/values-sr/strings.xml b/packages/PrintSpooler/res/values-sr/strings.xml
index 24f4797..cbab1a6 100644
--- a/packages/PrintSpooler/res/values-sr/strings.xml
+++ b/packages/PrintSpooler/res/values-sr/strings.xml
@@ -41,6 +41,8 @@
<string name="print_search_box_shown_utterance" msgid="7967404953901376090">"Оквир за претрагу је приказан"</string>
<string name="print_search_box_hidden_utterance" msgid="5727755169343113351">"Оквир за претрагу је сакривен"</string>
<string name="print_add_printer" msgid="1088656468360653455">"Додај штампач"</string>
+ <string name="print_select_printer" msgid="7388760939873368698">"Изабери штампач"</string>
+ <string name="print_forget_printer" msgid="5035287497291910766">"Заборави штампач"</string>
<plurals name="print_search_result_count_utterance">
<item quantity="one" msgid="4484953260685964252">"Пронађен је <xliff:g id="COUNT">%1$s</xliff:g> штампач"</item>
<item quantity="other" msgid="6533817036607128241">"Пронађено је <xliff:g id="COUNT">%1$s</xliff:g> штампача"</item>
diff --git a/packages/PrintSpooler/res/values-sv/strings.xml b/packages/PrintSpooler/res/values-sv/strings.xml
index 2d80858..2286fce 100644
--- a/packages/PrintSpooler/res/values-sv/strings.xml
+++ b/packages/PrintSpooler/res/values-sv/strings.xml
@@ -41,6 +41,8 @@
<string name="print_search_box_shown_utterance" msgid="7967404953901376090">"Sökrutan visas"</string>
<string name="print_search_box_hidden_utterance" msgid="5727755169343113351">"Sökrutan är dold"</string>
<string name="print_add_printer" msgid="1088656468360653455">"Lägg till skrivare"</string>
+ <string name="print_select_printer" msgid="7388760939873368698">"Välj en skrivare"</string>
+ <string name="print_forget_printer" msgid="5035287497291910766">"Ta bort en skrivare"</string>
<plurals name="print_search_result_count_utterance">
<item quantity="one" msgid="4484953260685964252">"<xliff:g id="COUNT">%1$s</xliff:g> skrivare hittades"</item>
<item quantity="other" msgid="6533817036607128241">"<xliff:g id="COUNT">%1$s</xliff:g> skrivare hittades"</item>
diff --git a/packages/PrintSpooler/res/values-sw/strings.xml b/packages/PrintSpooler/res/values-sw/strings.xml
index 3873d37..55c8687 100644
--- a/packages/PrintSpooler/res/values-sw/strings.xml
+++ b/packages/PrintSpooler/res/values-sw/strings.xml
@@ -41,6 +41,8 @@
<string name="print_search_box_shown_utterance" msgid="7967404953901376090">"Kisanduku cha kutafutia kimeonyeshwa"</string>
<string name="print_search_box_hidden_utterance" msgid="5727755169343113351">"Kisanduku cha kutafutia kimefichwa"</string>
<string name="print_add_printer" msgid="1088656468360653455">"Ongeza printa"</string>
+ <string name="print_select_printer" msgid="7388760939873368698">"Chagua printa"</string>
+ <string name="print_forget_printer" msgid="5035287497291910766">"Sahau printa"</string>
<plurals name="print_search_result_count_utterance">
<item quantity="one" msgid="4484953260685964252">"Printa <xliff:g id="COUNT">%1$s</xliff:g> imepatikana"</item>
<item quantity="other" msgid="6533817036607128241">"Printa <xliff:g id="COUNT">%1$s</xliff:g> zimepatikana"</item>
diff --git a/packages/PrintSpooler/res/values-th/strings.xml b/packages/PrintSpooler/res/values-th/strings.xml
index 7d6523e..aa01d6f 100644
--- a/packages/PrintSpooler/res/values-th/strings.xml
+++ b/packages/PrintSpooler/res/values-th/strings.xml
@@ -41,6 +41,8 @@
<string name="print_search_box_shown_utterance" msgid="7967404953901376090">"แสดงช่องค้นหาอยู่"</string>
<string name="print_search_box_hidden_utterance" msgid="5727755169343113351">"ซ่อนช่องค้นหาอยู่"</string>
<string name="print_add_printer" msgid="1088656468360653455">"เพิ่มเครื่องพิมพ์"</string>
+ <string name="print_select_printer" msgid="7388760939873368698">"เลือกเครื่องพิมพ์"</string>
+ <string name="print_forget_printer" msgid="5035287497291910766">"ไม่ต้องจำเครื่องพิมพ์"</string>
<plurals name="print_search_result_count_utterance">
<item quantity="one" msgid="4484953260685964252">"พบเครื่องพิมพ์ <xliff:g id="COUNT">%1$s</xliff:g> เครื่อง"</item>
<item quantity="other" msgid="6533817036607128241">"พบเครื่องพิมพ์ <xliff:g id="COUNT">%1$s</xliff:g> เครื่อง"</item>
diff --git a/packages/PrintSpooler/res/values-tl/strings.xml b/packages/PrintSpooler/res/values-tl/strings.xml
index 238c6bc..a72c937 100644
--- a/packages/PrintSpooler/res/values-tl/strings.xml
+++ b/packages/PrintSpooler/res/values-tl/strings.xml
@@ -41,6 +41,8 @@
<string name="print_search_box_shown_utterance" msgid="7967404953901376090">"Ipinapakita ang box para sa paghahanap"</string>
<string name="print_search_box_hidden_utterance" msgid="5727755169343113351">"Nakatago ang box para sa paghahanap"</string>
<string name="print_add_printer" msgid="1088656468360653455">"Magdagdag ng printer"</string>
+ <string name="print_select_printer" msgid="7388760939873368698">"Piliin ang printer"</string>
+ <string name="print_forget_printer" msgid="5035287497291910766">"Kalimutan ang printer"</string>
<plurals name="print_search_result_count_utterance">
<item quantity="one" msgid="4484953260685964252">"<xliff:g id="COUNT">%1$s</xliff:g> printer ang nakita"</item>
<item quantity="other" msgid="6533817036607128241">"<xliff:g id="COUNT">%1$s</xliff:g> (na) printer ang nakita"</item>
diff --git a/packages/PrintSpooler/res/values-tr/strings.xml b/packages/PrintSpooler/res/values-tr/strings.xml
index f851f20..c6e302d 100644
--- a/packages/PrintSpooler/res/values-tr/strings.xml
+++ b/packages/PrintSpooler/res/values-tr/strings.xml
@@ -41,6 +41,8 @@
<string name="print_search_box_shown_utterance" msgid="7967404953901376090">"Arama kutusu gösteriliyor"</string>
<string name="print_search_box_hidden_utterance" msgid="5727755169343113351">"Arama kutusu gizli"</string>
<string name="print_add_printer" msgid="1088656468360653455">"Yazıcı ekle"</string>
+ <string name="print_select_printer" msgid="7388760939873368698">"Yazıcı seç"</string>
+ <string name="print_forget_printer" msgid="5035287497291910766">"Yazıcıyı unut"</string>
<plurals name="print_search_result_count_utterance">
<item quantity="one" msgid="4484953260685964252">"<xliff:g id="COUNT">%1$s</xliff:g> yazıcı bulundu"</item>
<item quantity="other" msgid="6533817036607128241">"<xliff:g id="COUNT">%1$s</xliff:g> yazıcı bulundu"</item>
diff --git a/packages/PrintSpooler/res/values-uk/strings.xml b/packages/PrintSpooler/res/values-uk/strings.xml
index 8a340f1..4f526d0 100644
--- a/packages/PrintSpooler/res/values-uk/strings.xml
+++ b/packages/PrintSpooler/res/values-uk/strings.xml
@@ -41,6 +41,8 @@
<string name="print_search_box_shown_utterance" msgid="7967404953901376090">"Вікно пошуку показано"</string>
<string name="print_search_box_hidden_utterance" msgid="5727755169343113351">"Вікно пошуку сховано"</string>
<string name="print_add_printer" msgid="1088656468360653455">"Додати принтер"</string>
+ <string name="print_select_printer" msgid="7388760939873368698">"Вибрати принтер"</string>
+ <string name="print_forget_printer" msgid="5035287497291910766">"Ігнорувати принтер"</string>
<plurals name="print_search_result_count_utterance">
<item quantity="one" msgid="4484953260685964252">"Знайдено принтерів: <xliff:g id="COUNT">%1$s</xliff:g>"</item>
<item quantity="other" msgid="6533817036607128241">"Знайдено принтерів: <xliff:g id="COUNT">%1$s</xliff:g>"</item>
diff --git a/packages/PrintSpooler/res/values-vi/strings.xml b/packages/PrintSpooler/res/values-vi/strings.xml
index 7d086ad..d21172c 100644
--- a/packages/PrintSpooler/res/values-vi/strings.xml
+++ b/packages/PrintSpooler/res/values-vi/strings.xml
@@ -41,6 +41,8 @@
<string name="print_search_box_shown_utterance" msgid="7967404953901376090">"Hiển thị hộp tìm kiếm"</string>
<string name="print_search_box_hidden_utterance" msgid="5727755169343113351">"Ẩn hộp tìm kiếm"</string>
<string name="print_add_printer" msgid="1088656468360653455">"Thêm máy in"</string>
+ <string name="print_select_printer" msgid="7388760939873368698">"Chọn máy in"</string>
+ <string name="print_forget_printer" msgid="5035287497291910766">"Bỏ qua máy in"</string>
<plurals name="print_search_result_count_utterance">
<item quantity="one" msgid="4484953260685964252">"Đã tìm thấy <xliff:g id="COUNT">%1$s</xliff:g> máy in"</item>
<item quantity="other" msgid="6533817036607128241">"Đã tìm thấy <xliff:g id="COUNT">%1$s</xliff:g> máy in"</item>
diff --git a/packages/PrintSpooler/res/values-zh-rCN/strings.xml b/packages/PrintSpooler/res/values-zh-rCN/strings.xml
index 7e501f1..e43ea60 100644
--- a/packages/PrintSpooler/res/values-zh-rCN/strings.xml
+++ b/packages/PrintSpooler/res/values-zh-rCN/strings.xml
@@ -41,6 +41,8 @@
<string name="print_search_box_shown_utterance" msgid="7967404953901376090">"搜索框已显示"</string>
<string name="print_search_box_hidden_utterance" msgid="5727755169343113351">"搜索框已隐藏"</string>
<string name="print_add_printer" msgid="1088656468360653455">"添加打印机"</string>
+ <string name="print_select_printer" msgid="7388760939873368698">"选择打印机"</string>
+ <string name="print_forget_printer" msgid="5035287497291910766">"取消保存打印机"</string>
<plurals name="print_search_result_count_utterance">
<item quantity="one" msgid="4484953260685964252">"找到<xliff:g id="COUNT">%1$s</xliff:g>台打印机"</item>
<item quantity="other" msgid="6533817036607128241">"找到<xliff:g id="COUNT">%1$s</xliff:g>台打印机"</item>
diff --git a/packages/PrintSpooler/res/values-zh-rHK/strings.xml b/packages/PrintSpooler/res/values-zh-rHK/strings.xml
index 3856c75..2c2422a9 100644
--- a/packages/PrintSpooler/res/values-zh-rHK/strings.xml
+++ b/packages/PrintSpooler/res/values-zh-rHK/strings.xml
@@ -41,6 +41,8 @@
<string name="print_search_box_shown_utterance" msgid="7967404953901376090">"搜尋框已顯示"</string>
<string name="print_search_box_hidden_utterance" msgid="5727755169343113351">"搜尋框已隱藏"</string>
<string name="print_add_printer" msgid="1088656468360653455">"新增打印機"</string>
+ <string name="print_select_printer" msgid="7388760939873368698">"選取打印機"</string>
+ <string name="print_forget_printer" msgid="5035287497291910766">"移除打印機"</string>
<plurals name="print_search_result_count_utterance">
<item quantity="one" msgid="4484953260685964252">"找到 <xliff:g id="COUNT">%1$s</xliff:g> 部打印機"</item>
<item quantity="other" msgid="6533817036607128241">"找到 <xliff:g id="COUNT">%1$s</xliff:g> 部打印機"</item>
diff --git a/packages/PrintSpooler/res/values-zh-rTW/strings.xml b/packages/PrintSpooler/res/values-zh-rTW/strings.xml
index 81e0627..0fe88d9 100644
--- a/packages/PrintSpooler/res/values-zh-rTW/strings.xml
+++ b/packages/PrintSpooler/res/values-zh-rTW/strings.xml
@@ -41,6 +41,8 @@
<string name="print_search_box_shown_utterance" msgid="7967404953901376090">"搜尋框已顯示"</string>
<string name="print_search_box_hidden_utterance" msgid="5727755169343113351">"搜尋框已隱藏"</string>
<string name="print_add_printer" msgid="1088656468360653455">"新增印表機"</string>
+ <string name="print_select_printer" msgid="7388760939873368698">"選取印表機"</string>
+ <string name="print_forget_printer" msgid="5035287497291910766">"移除印表機"</string>
<plurals name="print_search_result_count_utterance">
<item quantity="one" msgid="4484953260685964252">"找到 <xliff:g id="COUNT">%1$s</xliff:g> 台印表機"</item>
<item quantity="other" msgid="6533817036607128241">"找到 <xliff:g id="COUNT">%1$s</xliff:g> 台印表機"</item>
diff --git a/packages/PrintSpooler/res/values-zu/strings.xml b/packages/PrintSpooler/res/values-zu/strings.xml
index 03c499f..08e31e1 100644
--- a/packages/PrintSpooler/res/values-zu/strings.xml
+++ b/packages/PrintSpooler/res/values-zu/strings.xml
@@ -41,6 +41,8 @@
<string name="print_search_box_shown_utterance" msgid="7967404953901376090">"Ibhokisi lokuhlola libonisiwe"</string>
<string name="print_search_box_hidden_utterance" msgid="5727755169343113351">"Ibhokisi lokusesha lifihliwe"</string>
<string name="print_add_printer" msgid="1088656468360653455">"Engeza iphrinta"</string>
+ <string name="print_select_printer" msgid="7388760939873368698">"Khetha iphrinta"</string>
+ <string name="print_forget_printer" msgid="5035287497291910766">"Khohlwa iphrinta"</string>
<plurals name="print_search_result_count_utterance">
<item quantity="one" msgid="4484953260685964252">"<xliff:g id="COUNT">%1$s</xliff:g> iphrinta itholiwe"</item>
<item quantity="other" msgid="6533817036607128241">"<xliff:g id="COUNT">%1$s</xliff:g> amaphrinta atholiwe"</item>
diff --git a/packages/PrintSpooler/src/com/android/printspooler/PrintSpoolerService.java b/packages/PrintSpooler/src/com/android/printspooler/PrintSpoolerService.java
index 778fb4d..615d667 100644
--- a/packages/PrintSpooler/src/com/android/printspooler/PrintSpoolerService.java
+++ b/packages/PrintSpooler/src/com/android/printspooler/PrintSpoolerService.java
@@ -441,6 +441,7 @@
private void removeObsoletePrintJobs() {
synchronized (mLock) {
+ boolean persistState = false;
final int printJobCount = mPrintJobs.size();
for (int i = printJobCount - 1; i >= 0; i--) {
PrintJobInfo printJob = mPrintJobs.get(i);
@@ -450,9 +451,12 @@
Slog.i(LOG_TAG, "[REMOVE] " + printJob.getId().flattenToString());
}
removePrintJobFileLocked(printJob.getId());
+ persistState = true;
}
}
- mPersistanceManager.writeStateLocked();
+ if (persistState) {
+ mPersistanceManager.writeStateLocked();
+ }
}
}
@@ -799,6 +803,10 @@
for (int j = 0; j < printJobCount; j++) {
PrintJobInfo printJob = printJobs.get(j);
+ if (!shouldPersistPrintJob(printJob)) {
+ continue;
+ }
+
serializer.startTag(null, TAG_JOB);
serializer.attribute(null, ATTR_ID, printJob.getId().flattenToString());
diff --git a/packages/SystemUI/AndroidManifest.xml b/packages/SystemUI/AndroidManifest.xml
index 09ac2da..8d6fe41 100644
--- a/packages/SystemUI/AndroidManifest.xml
+++ b/packages/SystemUI/AndroidManifest.xml
@@ -71,6 +71,9 @@
<!-- Keyguard -->
<uses-permission android:name="android.permission.CONTROL_KEYGUARD" />
+ <!-- Wifi Display -->
+ <uses-permission android:name="android.permission.CONFIGURE_WIFI_DISPLAY" />
+
<application
android:persistent="true"
android:allowClearUserData="false"
diff --git a/packages/SystemUI/res/drawable-hdpi/ic_qs_cast_available.png b/packages/SystemUI/res/drawable-hdpi/ic_qs_cast_available.png
new file mode 100644
index 0000000..1c3518a
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/ic_qs_cast_available.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/ic_qs_cast_connected.png b/packages/SystemUI/res/drawable-hdpi/ic_qs_cast_connected.png
new file mode 100644
index 0000000..9dbc65e
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/ic_qs_cast_connected.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/ic_qs_cast_connecting_0.png b/packages/SystemUI/res/drawable-hdpi/ic_qs_cast_connecting_0.png
new file mode 100644
index 0000000..ddb002d
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/ic_qs_cast_connecting_0.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/ic_qs_cast_connecting_1.png b/packages/SystemUI/res/drawable-hdpi/ic_qs_cast_connecting_1.png
new file mode 100644
index 0000000..43b7ef2
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/ic_qs_cast_connecting_1.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/ic_qs_cast_connecting_2.png b/packages/SystemUI/res/drawable-hdpi/ic_qs_cast_connecting_2.png
new file mode 100644
index 0000000..1d8b7ee
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/ic_qs_cast_connecting_2.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/ic_qs_remote_display.png b/packages/SystemUI/res/drawable-hdpi/ic_qs_remote_display.png
deleted file mode 100644
index 02d7fda..0000000
--- a/packages/SystemUI/res/drawable-hdpi/ic_qs_remote_display.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/ic_qs_remote_display_connected.png b/packages/SystemUI/res/drawable-hdpi/ic_qs_remote_display_connected.png
deleted file mode 100644
index 263f07c..0000000
--- a/packages/SystemUI/res/drawable-hdpi/ic_qs_remote_display_connected.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/search_light_land.png b/packages/SystemUI/res/drawable-hdpi/search_light_land.png
new file mode 100644
index 0000000..731f19b5
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/search_light_land.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_qs_cast_available.png b/packages/SystemUI/res/drawable-mdpi/ic_qs_cast_available.png
new file mode 100644
index 0000000..11b2134
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/ic_qs_cast_available.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_qs_cast_connected.png b/packages/SystemUI/res/drawable-mdpi/ic_qs_cast_connected.png
new file mode 100644
index 0000000..a858573
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/ic_qs_cast_connected.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_qs_cast_connecting_0.png b/packages/SystemUI/res/drawable-mdpi/ic_qs_cast_connecting_0.png
new file mode 100644
index 0000000..04de5d7
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/ic_qs_cast_connecting_0.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_qs_cast_connecting_1.png b/packages/SystemUI/res/drawable-mdpi/ic_qs_cast_connecting_1.png
new file mode 100644
index 0000000..caea37e
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/ic_qs_cast_connecting_1.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_qs_cast_connecting_2.png b/packages/SystemUI/res/drawable-mdpi/ic_qs_cast_connecting_2.png
new file mode 100644
index 0000000..b66aa46
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/ic_qs_cast_connecting_2.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_qs_remote_display.png b/packages/SystemUI/res/drawable-mdpi/ic_qs_remote_display.png
deleted file mode 100644
index 09ae409..0000000
--- a/packages/SystemUI/res/drawable-mdpi/ic_qs_remote_display.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_qs_remote_display_connected.png b/packages/SystemUI/res/drawable-mdpi/ic_qs_remote_display_connected.png
deleted file mode 100644
index 780cfc8..0000000
--- a/packages/SystemUI/res/drawable-mdpi/ic_qs_remote_display_connected.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/search_light_land.png b/packages/SystemUI/res/drawable-mdpi/search_light_land.png
new file mode 100644
index 0000000..a4d82f0
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/search_light_land.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_qs_cast_available.png b/packages/SystemUI/res/drawable-xhdpi/ic_qs_cast_available.png
new file mode 100644
index 0000000..10ebcd5
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/ic_qs_cast_available.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_qs_cast_connected.png b/packages/SystemUI/res/drawable-xhdpi/ic_qs_cast_connected.png
new file mode 100644
index 0000000..fef43b8
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/ic_qs_cast_connected.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_qs_cast_connecting_0.png b/packages/SystemUI/res/drawable-xhdpi/ic_qs_cast_connecting_0.png
new file mode 100644
index 0000000..05e3267
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/ic_qs_cast_connecting_0.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_qs_cast_connecting_1.png b/packages/SystemUI/res/drawable-xhdpi/ic_qs_cast_connecting_1.png
new file mode 100644
index 0000000..ef42b27
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/ic_qs_cast_connecting_1.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_qs_cast_connecting_2.png b/packages/SystemUI/res/drawable-xhdpi/ic_qs_cast_connecting_2.png
new file mode 100644
index 0000000..fc1c95e
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/ic_qs_cast_connecting_2.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_qs_remote_display.png b/packages/SystemUI/res/drawable-xhdpi/ic_qs_remote_display.png
deleted file mode 100644
index 48f90ac..0000000
--- a/packages/SystemUI/res/drawable-xhdpi/ic_qs_remote_display.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_qs_remote_display_connected.png b/packages/SystemUI/res/drawable-xhdpi/ic_qs_remote_display_connected.png
deleted file mode 100644
index 621c045..0000000
--- a/packages/SystemUI/res/drawable-xhdpi/ic_qs_remote_display_connected.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/search_light_land.png b/packages/SystemUI/res/drawable-xhdpi/search_light_land.png
new file mode 100644
index 0000000..b62c74e
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/search_light_land.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/ic_qs_cast_available.png b/packages/SystemUI/res/drawable-xxhdpi/ic_qs_cast_available.png
new file mode 100644
index 0000000..68b1b7c
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xxhdpi/ic_qs_cast_available.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/ic_qs_cast_connected.png b/packages/SystemUI/res/drawable-xxhdpi/ic_qs_cast_connected.png
new file mode 100644
index 0000000..8a8f890
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xxhdpi/ic_qs_cast_connected.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/ic_qs_cast_connecting_0.png b/packages/SystemUI/res/drawable-xxhdpi/ic_qs_cast_connecting_0.png
new file mode 100644
index 0000000..12d4a01
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xxhdpi/ic_qs_cast_connecting_0.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/ic_qs_cast_connecting_1.png b/packages/SystemUI/res/drawable-xxhdpi/ic_qs_cast_connecting_1.png
new file mode 100644
index 0000000..3cb4421
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xxhdpi/ic_qs_cast_connecting_1.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/ic_qs_cast_connecting_2.png b/packages/SystemUI/res/drawable-xxhdpi/ic_qs_cast_connecting_2.png
new file mode 100644
index 0000000..4620b3a
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xxhdpi/ic_qs_cast_connecting_2.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/ic_qs_remote_display.png b/packages/SystemUI/res/drawable-xxhdpi/ic_qs_remote_display.png
deleted file mode 100644
index b07be828..0000000
--- a/packages/SystemUI/res/drawable-xxhdpi/ic_qs_remote_display.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/ic_qs_remote_display_connected.png b/packages/SystemUI/res/drawable-xxhdpi/ic_qs_remote_display_connected.png
deleted file mode 100644
index f02d0ab..0000000
--- a/packages/SystemUI/res/drawable-xxhdpi/ic_qs_remote_display_connected.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/search_light_land.png b/packages/SystemUI/res/drawable-xxhdpi/search_light_land.png
new file mode 100644
index 0000000..f364577
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xxhdpi/search_light_land.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable/ic_qs_cast_connecting.xml b/packages/SystemUI/res/drawable/ic_qs_cast_connecting.xml
new file mode 100644
index 0000000..70db2a9
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_qs_cast_connecting.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+ * Copyright 2013, 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.
+ */
+-->
+<animation-list
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:oneshot="false">
+ <item android:drawable="@drawable/ic_qs_cast_connecting_0" android:duration="500" />
+ <item android:drawable="@drawable/ic_qs_cast_connecting_1" android:duration="500" />
+ <item android:drawable="@drawable/ic_qs_cast_connecting_2" android:duration="500" />
+ <item android:drawable="@drawable/ic_qs_cast_connecting_1" android:duration="500" />
+</animation-list>
diff --git a/packages/SystemUI/res/layout/navigation_bar.xml b/packages/SystemUI/res/layout/navigation_bar.xml
index aa365ae..5488a87 100644
--- a/packages/SystemUI/res/layout/navigation_bar.xml
+++ b/packages/SystemUI/res/layout/navigation_bar.xml
@@ -311,7 +311,7 @@
android:layout_height="80dp"
android:layout_width="match_parent"
android:layout_gravity="center_vertical"
- android:src="@drawable/search_light"
+ android:src="@drawable/search_light_land"
android:scaleType="center"
android:visibility="gone"
android:contentDescription="@string/accessibility_search_light"
diff --git a/packages/SystemUI/res/values-af/strings.xml b/packages/SystemUI/res/values-af/strings.xml
index 6f0d857..988d594 100644
--- a/packages/SystemUI/res/values-af/strings.xml
+++ b/packages/SystemUI/res/values-af/strings.xml
@@ -196,8 +196,7 @@
<string name="quick_settings_wifi_not_connected" msgid="7171904845345573431">"Nie gekoppel nie"</string>
<string name="quick_settings_wifi_no_network" msgid="2221993077220856376">"Geen netwerk nie"</string>
<string name="quick_settings_wifi_off_label" msgid="7558778100843885864">"Wi-Fi af"</string>
- <string name="quick_settings_wifi_display_label" msgid="6893592964463624333">"Wi-Fi-skerm"</string>
- <string name="quick_settings_wifi_display_no_connection_label" msgid="2355298740765736918">"Draadlose aansig"</string>
+ <string name="quick_settings_remote_display_no_connection_label" msgid="372107699274391290">"Saai na skerm uit"</string>
<string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"Helderheid"</string>
<string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"OUTO"</string>
<string name="ssl_ca_cert_warning" msgid="9005954106902053641">"Netwerk word\ndalk gemonitor"</string>
diff --git a/packages/SystemUI/res/values-am/strings.xml b/packages/SystemUI/res/values-am/strings.xml
index 686488e..ae0c650 100644
--- a/packages/SystemUI/res/values-am/strings.xml
+++ b/packages/SystemUI/res/values-am/strings.xml
@@ -196,8 +196,7 @@
<string name="quick_settings_wifi_not_connected" msgid="7171904845345573431">"አልተገናኘም"</string>
<string name="quick_settings_wifi_no_network" msgid="2221993077220856376">"ምንም አውታረ መረብ የለም"</string>
<string name="quick_settings_wifi_off_label" msgid="7558778100843885864">"Wi-Fi ጠፍቷል"</string>
- <string name="quick_settings_wifi_display_label" msgid="6893592964463624333">"የWi-Fi ማሳያ"</string>
- <string name="quick_settings_wifi_display_no_connection_label" msgid="2355298740765736918">"ገመድ አልባ ማሳያ"</string>
+ <string name="quick_settings_remote_display_no_connection_label" msgid="372107699274391290">"ማያ ገጽ ውሰድ"</string>
<string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"ብሩህነት"</string>
<string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"ራስ-ሰር"</string>
<string name="ssl_ca_cert_warning" msgid="9005954106902053641">"አውታረ መረብ\nክትትል ሊደረግበት ይችላል"</string>
diff --git a/packages/SystemUI/res/values-ar/strings.xml b/packages/SystemUI/res/values-ar/strings.xml
index 214daae..88b6762 100644
--- a/packages/SystemUI/res/values-ar/strings.xml
+++ b/packages/SystemUI/res/values-ar/strings.xml
@@ -196,8 +196,7 @@
<string name="quick_settings_wifi_not_connected" msgid="7171904845345573431">"ليست متصلة"</string>
<string name="quick_settings_wifi_no_network" msgid="2221993077220856376">"لا تتوفر شبكة"</string>
<string name="quick_settings_wifi_off_label" msgid="7558778100843885864">"إيقاف Wi-Fi"</string>
- <string name="quick_settings_wifi_display_label" msgid="6893592964463624333">"عرض Wi-Fi"</string>
- <string name="quick_settings_wifi_display_no_connection_label" msgid="2355298740765736918">"عرض شاشة لاسلكي"</string>
+ <string name="quick_settings_remote_display_no_connection_label" msgid="372107699274391290">"بث الشاشة"</string>
<string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"السطوع"</string>
<string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"تلقائي"</string>
<string name="ssl_ca_cert_warning" msgid="9005954106902053641">"قد تكون الشبكة\nخاضعة للرقابة"</string>
diff --git a/packages/SystemUI/res/values-be/strings.xml b/packages/SystemUI/res/values-be/strings.xml
index 356e7df..b574e79 100644
--- a/packages/SystemUI/res/values-be/strings.xml
+++ b/packages/SystemUI/res/values-be/strings.xml
@@ -205,8 +205,8 @@
<string name="quick_settings_wifi_not_connected" msgid="7171904845345573431">"Няма падключэння"</string>
<string name="quick_settings_wifi_no_network" msgid="2221993077220856376">"Няма сеткi"</string>
<string name="quick_settings_wifi_off_label" msgid="7558778100843885864">"Wi-Fi адключаны"</string>
- <string name="quick_settings_wifi_display_label" msgid="6893592964463624333">"Дысплей Wi-Fi"</string>
- <string name="quick_settings_wifi_display_no_connection_label" msgid="2355298740765736918">"Бесправадны дысплей"</string>
+ <!-- no translation found for quick_settings_remote_display_no_connection_label (3319785626703585888) -->
+ <skip />
<string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"Яркасць"</string>
<string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"АЎТА"</string>
<!-- no translation found for ssl_ca_cert_warning (9005954106902053641) -->
diff --git a/packages/SystemUI/res/values-bg/strings.xml b/packages/SystemUI/res/values-bg/strings.xml
index c893490..1814c23 100644
--- a/packages/SystemUI/res/values-bg/strings.xml
+++ b/packages/SystemUI/res/values-bg/strings.xml
@@ -196,8 +196,7 @@
<string name="quick_settings_wifi_not_connected" msgid="7171904845345573431">"Няма връзка"</string>
<string name="quick_settings_wifi_no_network" msgid="2221993077220856376">"Няма мрежа"</string>
<string name="quick_settings_wifi_off_label" msgid="7558778100843885864">"Wi-Fi е изключен"</string>
- <string name="quick_settings_wifi_display_label" msgid="6893592964463624333">"Дисплей през Wi-Fi"</string>
- <string name="quick_settings_wifi_display_no_connection_label" msgid="2355298740765736918">"Безжичен дисплей"</string>
+ <string name="quick_settings_remote_display_no_connection_label" msgid="372107699274391290">"Екран за предаване"</string>
<string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"Яркост"</string>
<string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"АВТ."</string>
<string name="ssl_ca_cert_warning" msgid="9005954106902053641">"Мрежата може\nда се наблюдава"</string>
diff --git a/packages/SystemUI/res/values-ca/strings.xml b/packages/SystemUI/res/values-ca/strings.xml
index f29b10e..ad7eb5d 100644
--- a/packages/SystemUI/res/values-ca/strings.xml
+++ b/packages/SystemUI/res/values-ca/strings.xml
@@ -198,8 +198,7 @@
<string name="quick_settings_wifi_not_connected" msgid="7171904845345573431">"Desconnectat"</string>
<string name="quick_settings_wifi_no_network" msgid="2221993077220856376">"No hi ha cap xarxa"</string>
<string name="quick_settings_wifi_off_label" msgid="7558778100843885864">"Wi-Fi desconnectada"</string>
- <string name="quick_settings_wifi_display_label" msgid="6893592964463624333">"Pantalla Wi-Fi"</string>
- <string name="quick_settings_wifi_display_no_connection_label" msgid="2355298740765736918">"Pantalla sense fil"</string>
+ <string name="quick_settings_remote_display_no_connection_label" msgid="372107699274391290">"Pantalla d\'emissió"</string>
<string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"Brillantor"</string>
<string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"AUTOMÀTICA"</string>
<string name="ssl_ca_cert_warning" msgid="9005954106902053641">"És possible que la xarxa\nestigui controlada"</string>
diff --git a/packages/SystemUI/res/values-cs/strings.xml b/packages/SystemUI/res/values-cs/strings.xml
index 76a7201..c74f15c 100644
--- a/packages/SystemUI/res/values-cs/strings.xml
+++ b/packages/SystemUI/res/values-cs/strings.xml
@@ -198,8 +198,7 @@
<string name="quick_settings_wifi_not_connected" msgid="7171904845345573431">"Nepřipojeno"</string>
<string name="quick_settings_wifi_no_network" msgid="2221993077220856376">"Žádná síť"</string>
<string name="quick_settings_wifi_off_label" msgid="7558778100843885864">"Wi-Fi vypnuta"</string>
- <string name="quick_settings_wifi_display_label" msgid="6893592964463624333">"Displej přes Wi-Fi"</string>
- <string name="quick_settings_wifi_display_no_connection_label" msgid="2355298740765736918">"Bezdrátový displej"</string>
+ <string name="quick_settings_remote_display_no_connection_label" msgid="372107699274391290">"Vzdálená obrazovka"</string>
<string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"Jas"</string>
<string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"AUTOMATICKY"</string>
<string name="ssl_ca_cert_warning" msgid="9005954106902053641">"Síť může být\nmonitorována"</string>
diff --git a/packages/SystemUI/res/values-da/strings.xml b/packages/SystemUI/res/values-da/strings.xml
index 3f31217..3da7c6a 100644
--- a/packages/SystemUI/res/values-da/strings.xml
+++ b/packages/SystemUI/res/values-da/strings.xml
@@ -196,8 +196,7 @@
<string name="quick_settings_wifi_not_connected" msgid="7171904845345573431">"Ikke forbundet"</string>
<string name="quick_settings_wifi_no_network" msgid="2221993077220856376">"Intet netværk"</string>
<string name="quick_settings_wifi_off_label" msgid="7558778100843885864">"Wi-Fi slået fra"</string>
- <string name="quick_settings_wifi_display_label" msgid="6893592964463624333">"Wi-Fi Display"</string>
- <string name="quick_settings_wifi_display_no_connection_label" msgid="2355298740765736918">"Trådløs skærm"</string>
+ <string name="quick_settings_remote_display_no_connection_label" msgid="372107699274391290">"Cast-skærm"</string>
<string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"Lysstyrke"</string>
<string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"AUTO"</string>
<string name="ssl_ca_cert_warning" msgid="9005954106902053641">"Netværket kan\nvære overvåget"</string>
diff --git a/packages/SystemUI/res/values-de/strings.xml b/packages/SystemUI/res/values-de/strings.xml
index 444a555..0e1017b 100644
--- a/packages/SystemUI/res/values-de/strings.xml
+++ b/packages/SystemUI/res/values-de/strings.xml
@@ -198,8 +198,7 @@
<string name="quick_settings_wifi_not_connected" msgid="7171904845345573431">"Nicht verbunden"</string>
<string name="quick_settings_wifi_no_network" msgid="2221993077220856376">"Kein Netz"</string>
<string name="quick_settings_wifi_off_label" msgid="7558778100843885864">"WLAN aus"</string>
- <string name="quick_settings_wifi_display_label" msgid="6893592964463624333">"WLAN-Display"</string>
- <string name="quick_settings_wifi_display_no_connection_label" msgid="2355298740765736918">"Kabellose Übertragung (WiDi)"</string>
+ <string name="quick_settings_remote_display_no_connection_label" msgid="372107699274391290">"Bildschirm übertragen"</string>
<string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"Helligkeit"</string>
<string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"AUTO"</string>
<string name="ssl_ca_cert_warning" msgid="9005954106902053641">"Netzwerk wird\neventuell überwacht."</string>
diff --git a/packages/SystemUI/res/values-el/strings.xml b/packages/SystemUI/res/values-el/strings.xml
index 6be551c..1b6929c 100644
--- a/packages/SystemUI/res/values-el/strings.xml
+++ b/packages/SystemUI/res/values-el/strings.xml
@@ -198,8 +198,7 @@
<string name="quick_settings_wifi_not_connected" msgid="7171904845345573431">"Μη συνδεδεμένο"</string>
<string name="quick_settings_wifi_no_network" msgid="2221993077220856376">"Κανένα δίκτυο"</string>
<string name="quick_settings_wifi_off_label" msgid="7558778100843885864">"Wi-Fi ανενεργό"</string>
- <string name="quick_settings_wifi_display_label" msgid="6893592964463624333">"Οθόνη Wi-Fi"</string>
- <string name="quick_settings_wifi_display_no_connection_label" msgid="2355298740765736918">"Ασύρματη οθόνη"</string>
+ <string name="quick_settings_remote_display_no_connection_label" msgid="372107699274391290">"Μετάδοση οθόνης"</string>
<string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"Φωτεινότητα"</string>
<string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"ΑΥΤΟΜΑΤΗ"</string>
<string name="ssl_ca_cert_warning" msgid="9005954106902053641">"Το δίκτυο μπορεί\nνα παρακολουθείται"</string>
diff --git a/packages/SystemUI/res/values-en-rGB/strings.xml b/packages/SystemUI/res/values-en-rGB/strings.xml
index 93efc15..825692d 100644
--- a/packages/SystemUI/res/values-en-rGB/strings.xml
+++ b/packages/SystemUI/res/values-en-rGB/strings.xml
@@ -196,8 +196,7 @@
<string name="quick_settings_wifi_not_connected" msgid="7171904845345573431">"Not Connected"</string>
<string name="quick_settings_wifi_no_network" msgid="2221993077220856376">"No Network"</string>
<string name="quick_settings_wifi_off_label" msgid="7558778100843885864">"Wi-Fi Off"</string>
- <string name="quick_settings_wifi_display_label" msgid="6893592964463624333">"Wi-Fi Display"</string>
- <string name="quick_settings_wifi_display_no_connection_label" msgid="2355298740765736918">"Wireless Display"</string>
+ <string name="quick_settings_remote_display_no_connection_label" msgid="372107699274391290">"Cast Screen"</string>
<string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"Brightness"</string>
<string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"AUTO"</string>
<string name="ssl_ca_cert_warning" msgid="9005954106902053641">"Network may\nbe monitored"</string>
diff --git a/packages/SystemUI/res/values-en-rIN/strings.xml b/packages/SystemUI/res/values-en-rIN/strings.xml
index 93efc15..825692d 100644
--- a/packages/SystemUI/res/values-en-rIN/strings.xml
+++ b/packages/SystemUI/res/values-en-rIN/strings.xml
@@ -196,8 +196,7 @@
<string name="quick_settings_wifi_not_connected" msgid="7171904845345573431">"Not Connected"</string>
<string name="quick_settings_wifi_no_network" msgid="2221993077220856376">"No Network"</string>
<string name="quick_settings_wifi_off_label" msgid="7558778100843885864">"Wi-Fi Off"</string>
- <string name="quick_settings_wifi_display_label" msgid="6893592964463624333">"Wi-Fi Display"</string>
- <string name="quick_settings_wifi_display_no_connection_label" msgid="2355298740765736918">"Wireless Display"</string>
+ <string name="quick_settings_remote_display_no_connection_label" msgid="372107699274391290">"Cast Screen"</string>
<string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"Brightness"</string>
<string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"AUTO"</string>
<string name="ssl_ca_cert_warning" msgid="9005954106902053641">"Network may\nbe monitored"</string>
diff --git a/packages/SystemUI/res/values-es-rUS/strings.xml b/packages/SystemUI/res/values-es-rUS/strings.xml
index 4c795cb..6202baf 100644
--- a/packages/SystemUI/res/values-es-rUS/strings.xml
+++ b/packages/SystemUI/res/values-es-rUS/strings.xml
@@ -198,8 +198,7 @@
<string name="quick_settings_wifi_not_connected" msgid="7171904845345573431">"Sin conexión"</string>
<string name="quick_settings_wifi_no_network" msgid="2221993077220856376">"Sin red"</string>
<string name="quick_settings_wifi_off_label" msgid="7558778100843885864">"Wi-Fi desactivada"</string>
- <string name="quick_settings_wifi_display_label" msgid="6893592964463624333">"Pantalla Wi-Fi"</string>
- <string name="quick_settings_wifi_display_no_connection_label" msgid="2355298740765736918">"Pantalla inalámbrica"</string>
+ <string name="quick_settings_remote_display_no_connection_label" msgid="372107699274391290">"Pantalla de Cast"</string>
<string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"Brillo"</string>
<string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"AUTOMÁTICO"</string>
<string name="ssl_ca_cert_warning" msgid="9005954106902053641">"Es posible que la red\nesté supervisada."</string>
diff --git a/packages/SystemUI/res/values-es/strings.xml b/packages/SystemUI/res/values-es/strings.xml
index 9814ae7..154c0ee 100644
--- a/packages/SystemUI/res/values-es/strings.xml
+++ b/packages/SystemUI/res/values-es/strings.xml
@@ -196,8 +196,7 @@
<string name="quick_settings_wifi_not_connected" msgid="7171904845345573431">"No conectado"</string>
<string name="quick_settings_wifi_no_network" msgid="2221993077220856376">"No hay red."</string>
<string name="quick_settings_wifi_off_label" msgid="7558778100843885864">"Wi-Fi desactivado"</string>
- <string name="quick_settings_wifi_display_label" msgid="6893592964463624333">"Pantalla Wi-Fi"</string>
- <string name="quick_settings_wifi_display_no_connection_label" msgid="2355298740765736918">"Pantalla inalámbrica"</string>
+ <string name="quick_settings_remote_display_no_connection_label" msgid="372107699274391290">"Pantalla de Cast"</string>
<string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"Brillo"</string>
<string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"AUTO"</string>
<string name="ssl_ca_cert_warning" msgid="9005954106902053641">"La red se\npuede supervisar"</string>
diff --git a/packages/SystemUI/res/values-et-rEE/strings.xml b/packages/SystemUI/res/values-et-rEE/strings.xml
index 510cce2..fad777c 100644
--- a/packages/SystemUI/res/values-et-rEE/strings.xml
+++ b/packages/SystemUI/res/values-et-rEE/strings.xml
@@ -196,8 +196,7 @@
<string name="quick_settings_wifi_not_connected" msgid="7171904845345573431">"Ühendus puudub"</string>
<string name="quick_settings_wifi_no_network" msgid="2221993077220856376">"Võrku pole"</string>
<string name="quick_settings_wifi_off_label" msgid="7558778100843885864">"WiFi-ühendus on väljas"</string>
- <string name="quick_settings_wifi_display_label" msgid="6893592964463624333">"WiFi-ekraan"</string>
- <string name="quick_settings_wifi_display_no_connection_label" msgid="2355298740765736918">"Juhtmeta ekraaniühendus"</string>
+ <string name="quick_settings_remote_display_no_connection_label" msgid="372107699274391290">"Cast-ekraan"</string>
<string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"Heledus"</string>
<string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"AUTOMAATNE"</string>
<string name="ssl_ca_cert_warning" msgid="9005954106902053641">"Võrku võidakse\njälgida"</string>
diff --git a/packages/SystemUI/res/values-fa/strings.xml b/packages/SystemUI/res/values-fa/strings.xml
index 4d2b1c4..5782975 100644
--- a/packages/SystemUI/res/values-fa/strings.xml
+++ b/packages/SystemUI/res/values-fa/strings.xml
@@ -196,8 +196,7 @@
<string name="quick_settings_wifi_not_connected" msgid="7171904845345573431">"متصل نیست"</string>
<string name="quick_settings_wifi_no_network" msgid="2221993077220856376">"شبکهای موجود نیست"</string>
<string name="quick_settings_wifi_off_label" msgid="7558778100843885864">"Wi-Fi خاموش است"</string>
- <string name="quick_settings_wifi_display_label" msgid="6893592964463624333">"Wi-Fi Display"</string>
- <string name="quick_settings_wifi_display_no_connection_label" msgid="2355298740765736918">"نمایش بدون سیم"</string>
+ <string name="quick_settings_remote_display_no_connection_label" msgid="372107699274391290">"فرستادن صفحه"</string>
<string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"روشنایی"</string>
<string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"خودکار"</string>
<string name="ssl_ca_cert_warning" msgid="9005954106902053641">"ممکن است شبکه\nتحت نظارت باشد"</string>
diff --git a/packages/SystemUI/res/values-fi/strings.xml b/packages/SystemUI/res/values-fi/strings.xml
index 299a0a5..9a715e8 100644
--- a/packages/SystemUI/res/values-fi/strings.xml
+++ b/packages/SystemUI/res/values-fi/strings.xml
@@ -196,8 +196,7 @@
<string name="quick_settings_wifi_not_connected" msgid="7171904845345573431">"Ei yhteyttä"</string>
<string name="quick_settings_wifi_no_network" msgid="2221993077220856376">"Ei verkkoa"</string>
<string name="quick_settings_wifi_off_label" msgid="7558778100843885864">"Wifi-yhteys pois käytöstä"</string>
- <string name="quick_settings_wifi_display_label" msgid="6893592964463624333">"Wifi-näyttö"</string>
- <string name="quick_settings_wifi_display_no_connection_label" msgid="2355298740765736918">"Langaton näyttö"</string>
+ <string name="quick_settings_remote_display_no_connection_label" msgid="372107699274391290">"Lähetysnäyttö"</string>
<string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"Kirkkaus"</string>
<string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"AUTO"</string>
<string name="ssl_ca_cert_warning" msgid="9005954106902053641">"Verkkoa saatetaan\nvalvoa"</string>
diff --git a/packages/SystemUI/res/values-fr-rCA/strings.xml b/packages/SystemUI/res/values-fr-rCA/strings.xml
index 2a53193..bb1dbf1 100644
--- a/packages/SystemUI/res/values-fr-rCA/strings.xml
+++ b/packages/SystemUI/res/values-fr-rCA/strings.xml
@@ -198,8 +198,7 @@
<string name="quick_settings_wifi_not_connected" msgid="7171904845345573431">"Non connecté"</string>
<string name="quick_settings_wifi_no_network" msgid="2221993077220856376">"Aucun réseau"</string>
<string name="quick_settings_wifi_off_label" msgid="7558778100843885864">"Wi-Fi désactivé"</string>
- <string name="quick_settings_wifi_display_label" msgid="6893592964463624333">"Affichage Wi-Fi"</string>
- <string name="quick_settings_wifi_display_no_connection_label" msgid="2355298740765736918">"Affichage sans fil"</string>
+ <string name="quick_settings_remote_display_no_connection_label" msgid="372107699274391290">"Écran distant"</string>
<string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"Luminosité"</string>
<string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"AUTOMATIQUE"</string>
<string name="ssl_ca_cert_warning" msgid="9005954106902053641">"Le réseau peut\nêtre surveillé."</string>
diff --git a/packages/SystemUI/res/values-fr/strings.xml b/packages/SystemUI/res/values-fr/strings.xml
index 61260fe..a0eee35 100644
--- a/packages/SystemUI/res/values-fr/strings.xml
+++ b/packages/SystemUI/res/values-fr/strings.xml
@@ -198,8 +198,7 @@
<string name="quick_settings_wifi_not_connected" msgid="7171904845345573431">"Non connecté"</string>
<string name="quick_settings_wifi_no_network" msgid="2221993077220856376">"Aucun réseau"</string>
<string name="quick_settings_wifi_off_label" msgid="7558778100843885864">"Wi-Fi désactivé"</string>
- <string name="quick_settings_wifi_display_label" msgid="6893592964463624333">"Wi-Fi Display"</string>
- <string name="quick_settings_wifi_display_no_connection_label" msgid="2355298740765736918">"Affichage sans fil"</string>
+ <string name="quick_settings_remote_display_no_connection_label" msgid="372107699274391290">"Écran sur lequel l\'affichage est diffusé"</string>
<string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"Luminosité"</string>
<string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"AUTOMATIQUE"</string>
<string name="ssl_ca_cert_warning" msgid="9005954106902053641">"Le réseau peut\nêtre surveillé."</string>
diff --git a/packages/SystemUI/res/values-hi/strings.xml b/packages/SystemUI/res/values-hi/strings.xml
index 44273b1..4b1c3bc 100644
--- a/packages/SystemUI/res/values-hi/strings.xml
+++ b/packages/SystemUI/res/values-hi/strings.xml
@@ -196,8 +196,7 @@
<string name="quick_settings_wifi_not_connected" msgid="7171904845345573431">"कनेक्ट नहीं है"</string>
<string name="quick_settings_wifi_no_network" msgid="2221993077220856376">"कोई नेटवर्क नहीं"</string>
<string name="quick_settings_wifi_off_label" msgid="7558778100843885864">"Wi-Fi बंद"</string>
- <string name="quick_settings_wifi_display_label" msgid="6893592964463624333">"Wi-Fi प्रदर्शन"</string>
- <string name="quick_settings_wifi_display_no_connection_label" msgid="2355298740765736918">"वायरलेस डिस्प्ले"</string>
+ <string name="quick_settings_remote_display_no_connection_label" msgid="372107699274391290">"स्क्रीन कास्ट करें"</string>
<string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"स्क्रीन की रोशनी"</string>
<string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"स्वत:"</string>
<string name="ssl_ca_cert_warning" msgid="9005954106902053641">"नेटवर्क को\nमॉनीटर किया जा सकता है"</string>
diff --git a/packages/SystemUI/res/values-hr/strings.xml b/packages/SystemUI/res/values-hr/strings.xml
index 7384dd5..afed35c 100644
--- a/packages/SystemUI/res/values-hr/strings.xml
+++ b/packages/SystemUI/res/values-hr/strings.xml
@@ -196,8 +196,7 @@
<string name="quick_settings_wifi_not_connected" msgid="7171904845345573431">"Nije povezano"</string>
<string name="quick_settings_wifi_no_network" msgid="2221993077220856376">"Nema mreže"</string>
<string name="quick_settings_wifi_off_label" msgid="7558778100843885864">"Wi-Fi isključen"</string>
- <string name="quick_settings_wifi_display_label" msgid="6893592964463624333">"Wi-Fi zaslon"</string>
- <string name="quick_settings_wifi_display_no_connection_label" msgid="2355298740765736918">"Bežični prikaz"</string>
+ <string name="quick_settings_remote_display_no_connection_label" msgid="372107699274391290">"Emitiranje zaslona"</string>
<string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"Svjetlina"</string>
<string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"AUTOMATSKI"</string>
<string name="ssl_ca_cert_warning" msgid="9005954106902053641">"Mreža se\nmožda prati"</string>
diff --git a/packages/SystemUI/res/values-hu/strings.xml b/packages/SystemUI/res/values-hu/strings.xml
index 65605aa..aba5a88 100644
--- a/packages/SystemUI/res/values-hu/strings.xml
+++ b/packages/SystemUI/res/values-hu/strings.xml
@@ -196,8 +196,7 @@
<string name="quick_settings_wifi_not_connected" msgid="7171904845345573431">"Nincs kapcsolat"</string>
<string name="quick_settings_wifi_no_network" msgid="2221993077220856376">"Nincs hálózat"</string>
<string name="quick_settings_wifi_off_label" msgid="7558778100843885864">"Wi-Fi kikapcsolva"</string>
- <string name="quick_settings_wifi_display_label" msgid="6893592964463624333">"Wi-Fi kijelző"</string>
- <string name="quick_settings_wifi_display_no_connection_label" msgid="2355298740765736918">"Vezeték nélküli kijelző"</string>
+ <string name="quick_settings_remote_display_no_connection_label" msgid="372107699274391290">"Képernyő tartalmának átküldése"</string>
<string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"Fényerő"</string>
<string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"automatikus"</string>
<string name="ssl_ca_cert_warning" msgid="9005954106902053641">"Lehet, hogy a\nhálózat felügyelt"</string>
diff --git a/packages/SystemUI/res/values-hy-rAM/strings.xml b/packages/SystemUI/res/values-hy-rAM/strings.xml
index d2f5096..f5793c0 100644
--- a/packages/SystemUI/res/values-hy-rAM/strings.xml
+++ b/packages/SystemUI/res/values-hy-rAM/strings.xml
@@ -196,8 +196,7 @@
<string name="quick_settings_wifi_not_connected" msgid="7171904845345573431">"Միացված չէ"</string>
<string name="quick_settings_wifi_no_network" msgid="2221993077220856376">"Ցանց չկա"</string>
<string name="quick_settings_wifi_off_label" msgid="7558778100843885864">"Wi-Fi-ը անջատված է"</string>
- <string name="quick_settings_wifi_display_label" msgid="6893592964463624333">"Wi-Fi ցուցադրիչ"</string>
- <string name="quick_settings_wifi_display_no_connection_label" msgid="2355298740765736918">"Անլար էկրան"</string>
+ <string name="quick_settings_remote_display_no_connection_label" msgid="372107699274391290">"Հեռակա էկրան"</string>
<string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"Պայծառություն"</string>
<string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"Ինքնաշխատ"</string>
<string name="ssl_ca_cert_warning" msgid="9005954106902053641">"Ցանցը կարող է\nվերահսկվել"</string>
diff --git a/packages/SystemUI/res/values-in/strings.xml b/packages/SystemUI/res/values-in/strings.xml
index 32e7c42..0893599 100644
--- a/packages/SystemUI/res/values-in/strings.xml
+++ b/packages/SystemUI/res/values-in/strings.xml
@@ -176,7 +176,7 @@
<string name="ethernet_label" msgid="7967563676324087464">"Ethernet"</string>
<string name="quick_settings_airplane_mode_label" msgid="5510520633448831350">"Mode pesawat"</string>
<string name="quick_settings_battery_charging_label" msgid="490074774465309209">"Mengisi baterai, <xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>"</string>
- <string name="quick_settings_battery_charged_label" msgid="8865413079414246081">"Ditagih"</string>
+ <string name="quick_settings_battery_charged_label" msgid="8865413079414246081">"Terisi"</string>
<string name="quick_settings_bluetooth_label" msgid="6304190285170721401">"Bluetooth"</string>
<string name="quick_settings_bluetooth_multiple_devices_label" msgid="3912245565613684735">"Bluetooth (<xliff:g id="NUMBER">%d</xliff:g> Perangkat)"</string>
<string name="quick_settings_bluetooth_off_label" msgid="8159652146149219937">"Bluetooth Mati"</string>
@@ -196,8 +196,7 @@
<string name="quick_settings_wifi_not_connected" msgid="7171904845345573431">"Tidak Tersambung"</string>
<string name="quick_settings_wifi_no_network" msgid="2221993077220856376">"Tidak Ada Jaringan"</string>
<string name="quick_settings_wifi_off_label" msgid="7558778100843885864">"Wi-Fi Mati"</string>
- <string name="quick_settings_wifi_display_label" msgid="6893592964463624333">"Tampilan Wi-Fi"</string>
- <string name="quick_settings_wifi_display_no_connection_label" msgid="2355298740765736918">"Layar Nirkabel"</string>
+ <string name="quick_settings_remote_display_no_connection_label" msgid="372107699274391290">"Layar Transmisi"</string>
<string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"Kecerahan"</string>
<string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"OTOMATIS"</string>
<string name="ssl_ca_cert_warning" msgid="9005954106902053641">"Jaringan bisa\ndiawasi"</string>
diff --git a/packages/SystemUI/res/values-it/strings.xml b/packages/SystemUI/res/values-it/strings.xml
index f8790bb..67ae18d 100644
--- a/packages/SystemUI/res/values-it/strings.xml
+++ b/packages/SystemUI/res/values-it/strings.xml
@@ -198,8 +198,7 @@
<string name="quick_settings_wifi_not_connected" msgid="7171904845345573431">"Non connesso"</string>
<string name="quick_settings_wifi_no_network" msgid="2221993077220856376">"Nessuna rete"</string>
<string name="quick_settings_wifi_off_label" msgid="7558778100843885864">"Wi-Fi disattivato"</string>
- <string name="quick_settings_wifi_display_label" msgid="6893592964463624333">"Display Wi-Fi"</string>
- <string name="quick_settings_wifi_display_no_connection_label" msgid="2355298740765736918">"Visualizzazione wireless"</string>
+ <string name="quick_settings_remote_display_no_connection_label" msgid="372107699274391290">"Trasmetti schermo"</string>
<string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"Luminosità"</string>
<string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"AUTO"</string>
<string name="ssl_ca_cert_warning" msgid="9005954106902053641">"La rete potrebbe\nessere monitorata"</string>
diff --git a/packages/SystemUI/res/values-iw/strings.xml b/packages/SystemUI/res/values-iw/strings.xml
index 5dbe432..fe9c458 100644
--- a/packages/SystemUI/res/values-iw/strings.xml
+++ b/packages/SystemUI/res/values-iw/strings.xml
@@ -196,8 +196,7 @@
<string name="quick_settings_wifi_not_connected" msgid="7171904845345573431">"לא מחובר"</string>
<string name="quick_settings_wifi_no_network" msgid="2221993077220856376">"אין רשת"</string>
<string name="quick_settings_wifi_off_label" msgid="7558778100843885864">"Wi-Fi כבוי"</string>
- <string name="quick_settings_wifi_display_label" msgid="6893592964463624333">"תצוגת Wi-Fi"</string>
- <string name="quick_settings_wifi_display_no_connection_label" msgid="2355298740765736918">"תצוגת Wi-Fi"</string>
+ <string name="quick_settings_remote_display_no_connection_label" msgid="372107699274391290">"העבר מסך"</string>
<string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"בהירות"</string>
<string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"אוטומטי"</string>
<string name="ssl_ca_cert_warning" msgid="9005954106902053641">"ייתכן שהרשת\nמנוטרת"</string>
diff --git a/packages/SystemUI/res/values-ja/strings.xml b/packages/SystemUI/res/values-ja/strings.xml
index d1ba2a8..13bea42 100644
--- a/packages/SystemUI/res/values-ja/strings.xml
+++ b/packages/SystemUI/res/values-ja/strings.xml
@@ -198,8 +198,7 @@
<string name="quick_settings_wifi_not_connected" msgid="7171904845345573431">"接続されていません"</string>
<string name="quick_settings_wifi_no_network" msgid="2221993077220856376">"ネットワークなし"</string>
<string name="quick_settings_wifi_off_label" msgid="7558778100843885864">"Wi-Fi OFF"</string>
- <string name="quick_settings_wifi_display_label" msgid="6893592964463624333">"Wi-Fiディスプレイ"</string>
- <string name="quick_settings_wifi_display_no_connection_label" msgid="2355298740765736918">"ワイヤレスディスプレイ"</string>
+ <string name="quick_settings_remote_display_no_connection_label" msgid="372107699274391290">"画面のキャスト"</string>
<string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"画面の明るさ"</string>
<string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"自動"</string>
<string name="ssl_ca_cert_warning" msgid="9005954106902053641">"ネットワークが監視される\n場合があります"</string>
diff --git a/packages/SystemUI/res/values-ka-rGE/strings.xml b/packages/SystemUI/res/values-ka-rGE/strings.xml
index bd6e87f2..67b29d6 100644
--- a/packages/SystemUI/res/values-ka-rGE/strings.xml
+++ b/packages/SystemUI/res/values-ka-rGE/strings.xml
@@ -196,8 +196,7 @@
<string name="quick_settings_wifi_not_connected" msgid="7171904845345573431">"არ არის დაკავშირებული."</string>
<string name="quick_settings_wifi_no_network" msgid="2221993077220856376">"ქსელი არ არის"</string>
<string name="quick_settings_wifi_off_label" msgid="7558778100843885864">"Wi-Fi გამორთულია"</string>
- <string name="quick_settings_wifi_display_label" msgid="6893592964463624333">"Wi-Fi ეკრანი"</string>
- <string name="quick_settings_wifi_display_no_connection_label" msgid="2355298740765736918">"უსადენო ეკრანი"</string>
+ <string name="quick_settings_remote_display_no_connection_label" msgid="372107699274391290">"Cast Screen"</string>
<string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"განათება"</string>
<string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"ავტომატურად"</string>
<string name="ssl_ca_cert_warning" msgid="9005954106902053641">"შესაძლოა ქსელზე\nმონიტორინგი ხორციელდებოდეს"</string>
diff --git a/packages/SystemUI/res/values-km-rKH/strings.xml b/packages/SystemUI/res/values-km-rKH/strings.xml
index 20ee33b..4afc08b 100644
--- a/packages/SystemUI/res/values-km-rKH/strings.xml
+++ b/packages/SystemUI/res/values-km-rKH/strings.xml
@@ -196,8 +196,7 @@
<string name="quick_settings_wifi_not_connected" msgid="7171904845345573431">"មិនបានតភ្ជាប់"</string>
<string name="quick_settings_wifi_no_network" msgid="2221993077220856376">"គ្មានបណ្ដាញ"</string>
<string name="quick_settings_wifi_off_label" msgid="7558778100843885864">"បិទវ៉ាយហ្វាយ"</string>
- <string name="quick_settings_wifi_display_label" msgid="6893592964463624333">"បង្ហាញវ៉ាយហ្វាយ"</string>
- <string name="quick_settings_wifi_display_no_connection_label" msgid="2355298740765736918">"បង្ហាញបណ្ដាញឥតខ្សែ"</string>
+ <string name="quick_settings_remote_display_no_connection_label" msgid="372107699274391290">"ចាត់ថ្នាក់អេក្រង់"</string>
<string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"ពន្លឺ"</string>
<string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"ស្វ័យប្រវត្តិ"</string>
<string name="ssl_ca_cert_warning" msgid="9005954106902053641">"បណ្ដាញអាច\nត្រូវបានត្រួតពិនិត្យ"</string>
diff --git a/packages/SystemUI/res/values-ko/strings.xml b/packages/SystemUI/res/values-ko/strings.xml
index cec56e5..ec8bdc1 100644
--- a/packages/SystemUI/res/values-ko/strings.xml
+++ b/packages/SystemUI/res/values-ko/strings.xml
@@ -196,8 +196,7 @@
<string name="quick_settings_wifi_not_connected" msgid="7171904845345573431">"연결되어 있지 않음"</string>
<string name="quick_settings_wifi_no_network" msgid="2221993077220856376">"네트워크가 연결되지 않음"</string>
<string name="quick_settings_wifi_off_label" msgid="7558778100843885864">"Wi-Fi 꺼짐"</string>
- <string name="quick_settings_wifi_display_label" msgid="6893592964463624333">"Wi-Fi 디스플레이"</string>
- <string name="quick_settings_wifi_display_no_connection_label" msgid="2355298740765736918">"무선 디스플레이"</string>
+ <string name="quick_settings_remote_display_no_connection_label" msgid="372107699274391290">"화면 전송"</string>
<string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"밝기"</string>
<string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"자동"</string>
<string name="ssl_ca_cert_warning" msgid="9005954106902053641">"네트워크가\n모니터링될 수 있음"</string>
diff --git a/packages/SystemUI/res/values-lo-rLA/strings.xml b/packages/SystemUI/res/values-lo-rLA/strings.xml
index f62dea2..766477f 100644
--- a/packages/SystemUI/res/values-lo-rLA/strings.xml
+++ b/packages/SystemUI/res/values-lo-rLA/strings.xml
@@ -196,8 +196,7 @@
<string name="quick_settings_wifi_not_connected" msgid="7171904845345573431">"ບໍ່ໄດ້ເຊື່ອມຕໍ່"</string>
<string name="quick_settings_wifi_no_network" msgid="2221993077220856376">"ບໍ່ມີເຄືອຂ່າຍ"</string>
<string name="quick_settings_wifi_off_label" msgid="7558778100843885864">"Wi-Fi ປິດ"</string>
- <string name="quick_settings_wifi_display_label" msgid="6893592964463624333">"ຈໍສະແດງຜົນ Wi-Fi"</string>
- <string name="quick_settings_wifi_display_no_connection_label" msgid="2355298740765736918">"ການສະແດງຜົນໄຮ້ສາຍ"</string>
+ <string name="quick_settings_remote_display_no_connection_label" msgid="372107699274391290">"ດຶງໜ້າຈໍ"</string>
<string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"ຄວາມແຈ້ງ"</string>
<string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"ອັດຕະໂນມັດ"</string>
<string name="ssl_ca_cert_warning" msgid="9005954106902053641">"ເຄືອຄ່າຍອາດ\nຖືກຕິດຕາມ"</string>
diff --git a/packages/SystemUI/res/values-lt/strings.xml b/packages/SystemUI/res/values-lt/strings.xml
index c38b653..4feeae2 100644
--- a/packages/SystemUI/res/values-lt/strings.xml
+++ b/packages/SystemUI/res/values-lt/strings.xml
@@ -196,8 +196,7 @@
<string name="quick_settings_wifi_not_connected" msgid="7171904845345573431">"Neprisijungta"</string>
<string name="quick_settings_wifi_no_network" msgid="2221993077220856376">"Tinklo nėra"</string>
<string name="quick_settings_wifi_off_label" msgid="7558778100843885864">"„Wi-Fi“ išjungta"</string>
- <string name="quick_settings_wifi_display_label" msgid="6893592964463624333">"„Wi-Fi“ pateiktis"</string>
- <string name="quick_settings_wifi_display_no_connection_label" msgid="2355298740765736918">"Belaidis rodymas"</string>
+ <string name="quick_settings_remote_display_no_connection_label" msgid="372107699274391290">"Perduoti ekraną"</string>
<string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"Skaistis"</string>
<string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"AUTOMATINIS"</string>
<string name="ssl_ca_cert_warning" msgid="9005954106902053641">"Tinklas gali\nbūti stebimas"</string>
diff --git a/packages/SystemUI/res/values-lv/strings.xml b/packages/SystemUI/res/values-lv/strings.xml
index e969920..01d1108 100644
--- a/packages/SystemUI/res/values-lv/strings.xml
+++ b/packages/SystemUI/res/values-lv/strings.xml
@@ -196,8 +196,7 @@
<string name="quick_settings_wifi_not_connected" msgid="7171904845345573431">"Nav izveidots savienojums"</string>
<string name="quick_settings_wifi_no_network" msgid="2221993077220856376">"Nav tīkla"</string>
<string name="quick_settings_wifi_off_label" msgid="7558778100843885864">"Wi-Fi ir izslēgts"</string>
- <string name="quick_settings_wifi_display_label" msgid="6893592964463624333">"Wi-Fi displejs"</string>
- <string name="quick_settings_wifi_display_no_connection_label" msgid="2355298740765736918">"Bezvadu attēlošana"</string>
+ <string name="quick_settings_remote_display_no_connection_label" msgid="372107699274391290">"Apraides ekrāns"</string>
<string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"Spilgtums"</string>
<string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"AUTOMĀTISKI"</string>
<string name="ssl_ca_cert_warning" msgid="9005954106902053641">"Tīkls var\ntikt uzraudzīts"</string>
diff --git a/packages/SystemUI/res/values-mn-rMN/strings.xml b/packages/SystemUI/res/values-mn-rMN/strings.xml
index 72d92b5..d92407c 100644
--- a/packages/SystemUI/res/values-mn-rMN/strings.xml
+++ b/packages/SystemUI/res/values-mn-rMN/strings.xml
@@ -196,8 +196,7 @@
<string name="quick_settings_wifi_not_connected" msgid="7171904845345573431">"Холбогдоогүй"</string>
<string name="quick_settings_wifi_no_network" msgid="2221993077220856376">"Сүлжээгүй"</string>
<string name="quick_settings_wifi_off_label" msgid="7558778100843885864">"Wi-Fi унтарсан"</string>
- <string name="quick_settings_wifi_display_label" msgid="6893592964463624333">"Wi-Fi Дэлгэц"</string>
- <string name="quick_settings_wifi_display_no_connection_label" msgid="2355298740765736918">"Утасгүй дэлгэц"</string>
+ <string name="quick_settings_remote_display_no_connection_label" msgid="372107699274391290">"Дамжуулах дэлгэц"</string>
<string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"Тодрол"</string>
<string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"АВТОМАТ"</string>
<string name="ssl_ca_cert_warning" msgid="9005954106902053641">"Сүлжээ хянагдаж\nбайж болзошгүй"</string>
diff --git a/packages/SystemUI/res/values-ms-rMY/strings.xml b/packages/SystemUI/res/values-ms-rMY/strings.xml
index dff3279..58613fd 100644
--- a/packages/SystemUI/res/values-ms-rMY/strings.xml
+++ b/packages/SystemUI/res/values-ms-rMY/strings.xml
@@ -196,8 +196,7 @@
<string name="quick_settings_wifi_not_connected" msgid="7171904845345573431">"Tidak Disambungkan"</string>
<string name="quick_settings_wifi_no_network" msgid="2221993077220856376">"Tiada Rangkaian"</string>
<string name="quick_settings_wifi_off_label" msgid="7558778100843885864">"Wi-Fi Dimatikan"</string>
- <string name="quick_settings_wifi_display_label" msgid="6893592964463624333">"Paparan Wi-Fi"</string>
- <string name="quick_settings_wifi_display_no_connection_label" msgid="2355298740765736918">"Paparan Wayarles"</string>
+ <string name="quick_settings_remote_display_no_connection_label" msgid="372107699274391290">"Skrin Cast"</string>
<string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"Kecerahan"</string>
<string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"AUTO"</string>
<string name="ssl_ca_cert_warning" msgid="9005954106902053641">"Rangkaian mungkin\nboleh dipantau"</string>
diff --git a/packages/SystemUI/res/values-nb/strings.xml b/packages/SystemUI/res/values-nb/strings.xml
index 66320ce..f75730e 100644
--- a/packages/SystemUI/res/values-nb/strings.xml
+++ b/packages/SystemUI/res/values-nb/strings.xml
@@ -196,8 +196,7 @@
<string name="quick_settings_wifi_not_connected" msgid="7171904845345573431">"Ikke tilkoblet"</string>
<string name="quick_settings_wifi_no_network" msgid="2221993077220856376">"Ingen nettverk"</string>
<string name="quick_settings_wifi_off_label" msgid="7558778100843885864">"Wi-Fi er av"</string>
- <string name="quick_settings_wifi_display_label" msgid="6893592964463624333">"Wi-Fi-skjerm"</string>
- <string name="quick_settings_wifi_display_no_connection_label" msgid="2355298740765736918">"Trådløs skjerm"</string>
+ <string name="quick_settings_remote_display_no_connection_label" msgid="372107699274391290">"Send skjermen"</string>
<string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"Lysstyrke"</string>
<string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"AUTO"</string>
<string name="ssl_ca_cert_warning" msgid="9005954106902053641">"Nettverket kan\nvære overvåket"</string>
diff --git a/packages/SystemUI/res/values-nl/strings.xml b/packages/SystemUI/res/values-nl/strings.xml
index 9aa7e75..a05f9c5 100644
--- a/packages/SystemUI/res/values-nl/strings.xml
+++ b/packages/SystemUI/res/values-nl/strings.xml
@@ -196,8 +196,7 @@
<string name="quick_settings_wifi_not_connected" msgid="7171904845345573431">"Niet verbonden"</string>
<string name="quick_settings_wifi_no_network" msgid="2221993077220856376">"Geen netwerk"</string>
<string name="quick_settings_wifi_off_label" msgid="7558778100843885864">"Wifi uit"</string>
- <string name="quick_settings_wifi_display_label" msgid="6893592964463624333">"Wifi-weergave"</string>
- <string name="quick_settings_wifi_display_no_connection_label" msgid="2355298740765736918">"Draadloze weergave"</string>
+ <string name="quick_settings_remote_display_no_connection_label" msgid="372107699274391290">"Scherm sturen"</string>
<string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"Helderheid"</string>
<string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"AUTOMATISCH"</string>
<string name="ssl_ca_cert_warning" msgid="9005954106902053641">"Netwerk kan\nworden gecontroleerd"</string>
diff --git a/packages/SystemUI/res/values-pl/strings.xml b/packages/SystemUI/res/values-pl/strings.xml
index 3fe07e7..83e3c43 100644
--- a/packages/SystemUI/res/values-pl/strings.xml
+++ b/packages/SystemUI/res/values-pl/strings.xml
@@ -196,8 +196,7 @@
<string name="quick_settings_wifi_not_connected" msgid="7171904845345573431">"Brak połączenia"</string>
<string name="quick_settings_wifi_no_network" msgid="2221993077220856376">"Brak sieci"</string>
<string name="quick_settings_wifi_off_label" msgid="7558778100843885864">"Wyłącz Wi-Fi"</string>
- <string name="quick_settings_wifi_display_label" msgid="6893592964463624333">"Wyświetlacz Wi-Fi"</string>
- <string name="quick_settings_wifi_display_no_connection_label" msgid="2355298740765736918">"Wyświetlacz bezprzewodowy"</string>
+ <string name="quick_settings_remote_display_no_connection_label" msgid="372107699274391290">"Ekran Cast"</string>
<string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"Jasność"</string>
<string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"AUTOMATYCZNA"</string>
<string name="ssl_ca_cert_warning" msgid="9005954106902053641">"Sieć może być\nmonitorowana"</string>
diff --git a/packages/SystemUI/res/values-pt-rPT/strings.xml b/packages/SystemUI/res/values-pt-rPT/strings.xml
index 22eda90..4e318d7 100644
--- a/packages/SystemUI/res/values-pt-rPT/strings.xml
+++ b/packages/SystemUI/res/values-pt-rPT/strings.xml
@@ -196,8 +196,7 @@
<string name="quick_settings_wifi_not_connected" msgid="7171904845345573431">"Não Ligado"</string>
<string name="quick_settings_wifi_no_network" msgid="2221993077220856376">"Sem Rede"</string>
<string name="quick_settings_wifi_off_label" msgid="7558778100843885864">"Wi-Fi Desligado"</string>
- <string name="quick_settings_wifi_display_label" msgid="6893592964463624333">"Visualização Wi-Fi"</string>
- <string name="quick_settings_wifi_display_no_connection_label" msgid="2355298740765736918">"Display Sem Fios"</string>
+ <string name="quick_settings_remote_display_no_connection_label" msgid="372107699274391290">"Transmitir ecrã"</string>
<string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"Brilho"</string>
<string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"AUTOMÁTICO"</string>
<string name="ssl_ca_cert_warning" msgid="9005954106902053641">"A rede pode ser\nmonitorizada"</string>
diff --git a/packages/SystemUI/res/values-pt/strings.xml b/packages/SystemUI/res/values-pt/strings.xml
index 351965f..f97da2f 100644
--- a/packages/SystemUI/res/values-pt/strings.xml
+++ b/packages/SystemUI/res/values-pt/strings.xml
@@ -198,8 +198,7 @@
<string name="quick_settings_wifi_not_connected" msgid="7171904845345573431">"Não conectado"</string>
<string name="quick_settings_wifi_no_network" msgid="2221993077220856376">"Sem rede"</string>
<string name="quick_settings_wifi_off_label" msgid="7558778100843885864">"Wi-Fi desligado"</string>
- <string name="quick_settings_wifi_display_label" msgid="6893592964463624333">"Wi-Fi Display"</string>
- <string name="quick_settings_wifi_display_no_connection_label" msgid="2355298740765736918">"Display sem fio"</string>
+ <string name="quick_settings_remote_display_no_connection_label" msgid="372107699274391290">"Transmitir tela"</string>
<string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"Brilho"</string>
<string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"AUTO"</string>
<string name="ssl_ca_cert_warning" msgid="9005954106902053641">"A rede pode estar\nsob monitoração"</string>
diff --git a/packages/SystemUI/res/values-rm/strings.xml b/packages/SystemUI/res/values-rm/strings.xml
index 9e1c9b8..5bc11e9 100644
--- a/packages/SystemUI/res/values-rm/strings.xml
+++ b/packages/SystemUI/res/values-rm/strings.xml
@@ -362,9 +362,7 @@
<skip />
<!-- no translation found for quick_settings_wifi_off_label (7558778100843885864) -->
<skip />
- <!-- no translation found for quick_settings_wifi_display_label (6893592964463624333) -->
- <skip />
- <!-- no translation found for quick_settings_wifi_display_no_connection_label (2355298740765736918) -->
+ <!-- no translation found for quick_settings_remote_display_no_connection_label (372107699274391290) -->
<skip />
<!-- no translation found for quick_settings_brightness_dialog_title (8599674057673605368) -->
<skip />
diff --git a/packages/SystemUI/res/values-ro/strings.xml b/packages/SystemUI/res/values-ro/strings.xml
index 7415128..168369d 100644
--- a/packages/SystemUI/res/values-ro/strings.xml
+++ b/packages/SystemUI/res/values-ro/strings.xml
@@ -196,8 +196,7 @@
<string name="quick_settings_wifi_not_connected" msgid="7171904845345573431">"Neconectat"</string>
<string name="quick_settings_wifi_no_network" msgid="2221993077220856376">"Nicio reţea"</string>
<string name="quick_settings_wifi_off_label" msgid="7558778100843885864">"Wi-Fi deconectat"</string>
- <string name="quick_settings_wifi_display_label" msgid="6893592964463624333">"Afişaj Wi-Fi"</string>
- <string name="quick_settings_wifi_display_no_connection_label" msgid="2355298740765736918">"Ecran wireless"</string>
+ <string name="quick_settings_remote_display_no_connection_label" msgid="372107699274391290">"Ecran de afișare a transmisiunii"</string>
<string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"Luminozitate"</string>
<string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"AUTOMAT"</string>
<string name="ssl_ca_cert_warning" msgid="9005954106902053641">"Rețeaua poate\nfi monitorizată"</string>
diff --git a/packages/SystemUI/res/values-ru/strings.xml b/packages/SystemUI/res/values-ru/strings.xml
index a587dec..96e6e13 100644
--- a/packages/SystemUI/res/values-ru/strings.xml
+++ b/packages/SystemUI/res/values-ru/strings.xml
@@ -200,8 +200,7 @@
<string name="quick_settings_wifi_not_connected" msgid="7171904845345573431">"Нет соединения"</string>
<string name="quick_settings_wifi_no_network" msgid="2221993077220856376">"Нет сети"</string>
<string name="quick_settings_wifi_off_label" msgid="7558778100843885864">"Wi-Fi выкл."</string>
- <string name="quick_settings_wifi_display_label" msgid="6893592964463624333">"Проектор Wi-Fi"</string>
- <string name="quick_settings_wifi_display_no_connection_label" msgid="2355298740765736918">"Wi-Fi-монитор"</string>
+ <string name="quick_settings_remote_display_no_connection_label" msgid="372107699274391290">"Wi-Fi-монитор"</string>
<string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"Яркость"</string>
<string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"АВТОНАСТРОЙКА"</string>
<string name="ssl_ca_cert_warning" msgid="9005954106902053641">"Действия в сети\nмогут отслеживаться"</string>
diff --git a/packages/SystemUI/res/values-sk/strings.xml b/packages/SystemUI/res/values-sk/strings.xml
index 0b82843..60e4dc2 100644
--- a/packages/SystemUI/res/values-sk/strings.xml
+++ b/packages/SystemUI/res/values-sk/strings.xml
@@ -198,8 +198,7 @@
<string name="quick_settings_wifi_not_connected" msgid="7171904845345573431">"Nepripojené"</string>
<string name="quick_settings_wifi_no_network" msgid="2221993077220856376">"Žiadna sieť"</string>
<string name="quick_settings_wifi_off_label" msgid="7558778100843885864">"Sieť Wi-Fi je vypnutá"</string>
- <string name="quick_settings_wifi_display_label" msgid="6893592964463624333">"Obrazovka Wi-Fi"</string>
- <string name="quick_settings_wifi_display_no_connection_label" msgid="2355298740765736918">"Bezdrôtový displej"</string>
+ <string name="quick_settings_remote_display_no_connection_label" msgid="372107699274391290">"Vzdialená obrazovka"</string>
<string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"Jas"</string>
<string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"AUTOMATICKY"</string>
<string name="ssl_ca_cert_warning" msgid="9005954106902053641">"Sieť môže byť\nmonitorovaná"</string>
diff --git a/packages/SystemUI/res/values-sl/strings.xml b/packages/SystemUI/res/values-sl/strings.xml
index 6699440..2f90aeb 100644
--- a/packages/SystemUI/res/values-sl/strings.xml
+++ b/packages/SystemUI/res/values-sl/strings.xml
@@ -196,8 +196,7 @@
<string name="quick_settings_wifi_not_connected" msgid="7171904845345573431">"Povezava ni vzpostavljena"</string>
<string name="quick_settings_wifi_no_network" msgid="2221993077220856376">"Ni omrežja"</string>
<string name="quick_settings_wifi_off_label" msgid="7558778100843885864">"Wi-Fi izklopljen"</string>
- <string name="quick_settings_wifi_display_label" msgid="6893592964463624333">"Zaslon Wi-Fi"</string>
- <string name="quick_settings_wifi_display_no_connection_label" msgid="2355298740765736918">"Prikaz brezžičnih naprav"</string>
+ <string name="quick_settings_remote_display_no_connection_label" msgid="372107699274391290">"Zaslon za predvajanje"</string>
<string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"Svetlost"</string>
<string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"SAMODEJNO"</string>
<string name="ssl_ca_cert_warning" msgid="9005954106902053641">"Omrežje je\nlahko spremljano"</string>
diff --git a/packages/SystemUI/res/values-sr/strings.xml b/packages/SystemUI/res/values-sr/strings.xml
index 4e990d1..33607f2 100644
--- a/packages/SystemUI/res/values-sr/strings.xml
+++ b/packages/SystemUI/res/values-sr/strings.xml
@@ -196,8 +196,7 @@
<string name="quick_settings_wifi_not_connected" msgid="7171904845345573431">"Веза није успостављена"</string>
<string name="quick_settings_wifi_no_network" msgid="2221993077220856376">"Нема мреже"</string>
<string name="quick_settings_wifi_off_label" msgid="7558778100843885864">"Wi-Fi је искључен"</string>
- <string name="quick_settings_wifi_display_label" msgid="6893592964463624333">"Wi-Fi екран"</string>
- <string name="quick_settings_wifi_display_no_connection_label" msgid="2355298740765736918">"Бежични екран"</string>
+ <string name="quick_settings_remote_display_no_connection_label" msgid="372107699274391290">"Пребаци екран"</string>
<string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"Осветљеност"</string>
<string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"АУТОМАТСКА"</string>
<string name="ssl_ca_cert_warning" msgid="9005954106902053641">"Мрежа се можда\nнадгледа"</string>
diff --git a/packages/SystemUI/res/values-sv/strings.xml b/packages/SystemUI/res/values-sv/strings.xml
index 06eccfc..b49b5c9 100644
--- a/packages/SystemUI/res/values-sv/strings.xml
+++ b/packages/SystemUI/res/values-sv/strings.xml
@@ -196,8 +196,7 @@
<string name="quick_settings_wifi_not_connected" msgid="7171904845345573431">"Ej ansluten"</string>
<string name="quick_settings_wifi_no_network" msgid="2221993077220856376">"Inget nätverk"</string>
<string name="quick_settings_wifi_off_label" msgid="7558778100843885864">"Wi-Fi av"</string>
- <string name="quick_settings_wifi_display_label" msgid="6893592964463624333">"Wi-Fi-skärm"</string>
- <string name="quick_settings_wifi_display_no_connection_label" msgid="2355298740765736918">"Trådlös skärm"</string>
+ <string name="quick_settings_remote_display_no_connection_label" msgid="372107699274391290">"Överför skärmen"</string>
<string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"Ljusstyrka"</string>
<string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"AUTO"</string>
<string name="ssl_ca_cert_warning" msgid="9005954106902053641">"Nätverket kan\nvara övervakat"</string>
diff --git a/packages/SystemUI/res/values-sw/strings.xml b/packages/SystemUI/res/values-sw/strings.xml
index 6bd8632..ac025fd 100644
--- a/packages/SystemUI/res/values-sw/strings.xml
+++ b/packages/SystemUI/res/values-sw/strings.xml
@@ -194,8 +194,7 @@
<string name="quick_settings_wifi_not_connected" msgid="7171904845345573431">"Haijaunganishwa"</string>
<string name="quick_settings_wifi_no_network" msgid="2221993077220856376">"Hakuna Mtandao"</string>
<string name="quick_settings_wifi_off_label" msgid="7558778100843885864">"Wi-Fi Imezimwa"</string>
- <string name="quick_settings_wifi_display_label" msgid="6893592964463624333">"Onyesho la Wi-Fi"</string>
- <string name="quick_settings_wifi_display_no_connection_label" msgid="2355298740765736918">"Uonyeshaji Pasiwaya"</string>
+ <string name="quick_settings_remote_display_no_connection_label" msgid="372107699274391290">"Utumaji wa Skrini"</string>
<string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"Ung\'avu"</string>
<string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"KIOTOMATIKI"</string>
<string name="ssl_ca_cert_warning" msgid="9005954106902053641">"Huenda mtandao\nunafuatiliwa"</string>
diff --git a/packages/SystemUI/res/values-th/strings.xml b/packages/SystemUI/res/values-th/strings.xml
index 6893694..65b075a 100644
--- a/packages/SystemUI/res/values-th/strings.xml
+++ b/packages/SystemUI/res/values-th/strings.xml
@@ -196,8 +196,7 @@
<string name="quick_settings_wifi_not_connected" msgid="7171904845345573431">"ไม่ได้เชื่อมต่อ"</string>
<string name="quick_settings_wifi_no_network" msgid="2221993077220856376">"ไม่มีเครือข่าย"</string>
<string name="quick_settings_wifi_off_label" msgid="7558778100843885864">"ปิด WiFi"</string>
- <string name="quick_settings_wifi_display_label" msgid="6893592964463624333">"การแสดงผล WiFi"</string>
- <string name="quick_settings_wifi_display_no_connection_label" msgid="2355298740765736918">"จอแสดงผลไร้สาย"</string>
+ <string name="quick_settings_remote_display_no_connection_label" msgid="372107699274391290">"ส่งหน้าจอ"</string>
<string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"ความสว่าง"</string>
<string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"อัตโนมัติ"</string>
<string name="ssl_ca_cert_warning" msgid="9005954106902053641">"เครือข่ายอาจ\nถูกตรวจสอบ"</string>
diff --git a/packages/SystemUI/res/values-tl/strings.xml b/packages/SystemUI/res/values-tl/strings.xml
index 6aa4b47..4ac1b53 100644
--- a/packages/SystemUI/res/values-tl/strings.xml
+++ b/packages/SystemUI/res/values-tl/strings.xml
@@ -196,8 +196,7 @@
<string name="quick_settings_wifi_not_connected" msgid="7171904845345573431">"Hindi Nakakonekta"</string>
<string name="quick_settings_wifi_no_network" msgid="2221993077220856376">"Walang Network"</string>
<string name="quick_settings_wifi_off_label" msgid="7558778100843885864">"Naka-off ang Wi-Fi"</string>
- <string name="quick_settings_wifi_display_label" msgid="6893592964463624333">"Display ng Wi-Fi"</string>
- <string name="quick_settings_wifi_display_no_connection_label" msgid="2355298740765736918">"Wireless Display"</string>
+ <string name="quick_settings_remote_display_no_connection_label" msgid="372107699274391290">"I-cast ang Screen"</string>
<string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"Brightness"</string>
<string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"AUTO"</string>
<string name="ssl_ca_cert_warning" msgid="9005954106902053641">"Maaaring\nsinusubaybayan ang network"</string>
diff --git a/packages/SystemUI/res/values-tr/strings.xml b/packages/SystemUI/res/values-tr/strings.xml
index 964371f..a15e375 100644
--- a/packages/SystemUI/res/values-tr/strings.xml
+++ b/packages/SystemUI/res/values-tr/strings.xml
@@ -196,8 +196,7 @@
<string name="quick_settings_wifi_not_connected" msgid="7171904845345573431">"Bağlı Değil"</string>
<string name="quick_settings_wifi_no_network" msgid="2221993077220856376">"Ağ yok"</string>
<string name="quick_settings_wifi_off_label" msgid="7558778100843885864">"Kablosuz Kapalı"</string>
- <string name="quick_settings_wifi_display_label" msgid="6893592964463624333">"Kablosuz Ekran"</string>
- <string name="quick_settings_wifi_display_no_connection_label" msgid="2355298740765736918">"Kablosuz Ekran"</string>
+ <string name="quick_settings_remote_display_no_connection_label" msgid="372107699274391290">"Yayınlama Ekranı"</string>
<string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"Parlaklık"</string>
<string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"OTOMATİK"</string>
<string name="ssl_ca_cert_warning" msgid="9005954106902053641">"Ağ izleniyor\nolabilir"</string>
diff --git a/packages/SystemUI/res/values-uk/strings.xml b/packages/SystemUI/res/values-uk/strings.xml
index f502691..439c3d7 100644
--- a/packages/SystemUI/res/values-uk/strings.xml
+++ b/packages/SystemUI/res/values-uk/strings.xml
@@ -196,8 +196,7 @@
<string name="quick_settings_wifi_not_connected" msgid="7171904845345573431">"Не під’єднано."</string>
<string name="quick_settings_wifi_no_network" msgid="2221993077220856376">"Немає мережі"</string>
<string name="quick_settings_wifi_off_label" msgid="7558778100843885864">"Wi-Fi вимкнено"</string>
- <string name="quick_settings_wifi_display_label" msgid="6893592964463624333">"Відображення Wi-Fi"</string>
- <string name="quick_settings_wifi_display_no_connection_label" msgid="2355298740765736918">"Бездротове відображення"</string>
+ <string name="quick_settings_remote_display_no_connection_label" msgid="372107699274391290">"Транслювати екран"</string>
<string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"Яскравість"</string>
<string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"АВТО"</string>
<string name="ssl_ca_cert_warning" msgid="9005954106902053641">"Мережа може\nвідстежуватися"</string>
diff --git a/packages/SystemUI/res/values-vi/strings.xml b/packages/SystemUI/res/values-vi/strings.xml
index 707f2d8..34d1414 100644
--- a/packages/SystemUI/res/values-vi/strings.xml
+++ b/packages/SystemUI/res/values-vi/strings.xml
@@ -196,8 +196,7 @@
<string name="quick_settings_wifi_not_connected" msgid="7171904845345573431">"Chưa được kết nối"</string>
<string name="quick_settings_wifi_no_network" msgid="2221993077220856376">"Không có mạng nào"</string>
<string name="quick_settings_wifi_off_label" msgid="7558778100843885864">"Tắt Wi-Fi"</string>
- <string name="quick_settings_wifi_display_label" msgid="6893592964463624333">"Hiển thị Wi-Fi"</string>
- <string name="quick_settings_wifi_display_no_connection_label" msgid="2355298740765736918">"Hiển thị không dây"</string>
+ <string name="quick_settings_remote_display_no_connection_label" msgid="372107699274391290">"Truyền màn hình"</string>
<string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"Độ sáng"</string>
<string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"TỰ ĐỘNG"</string>
<string name="ssl_ca_cert_warning" msgid="9005954106902053641">"Mạng có thể\nđược giám sát"</string>
diff --git a/packages/SystemUI/res/values-zh-rCN/strings.xml b/packages/SystemUI/res/values-zh-rCN/strings.xml
index 87f1893..f759662 100644
--- a/packages/SystemUI/res/values-zh-rCN/strings.xml
+++ b/packages/SystemUI/res/values-zh-rCN/strings.xml
@@ -198,8 +198,7 @@
<string name="quick_settings_wifi_not_connected" msgid="7171904845345573431">"未连接"</string>
<string name="quick_settings_wifi_no_network" msgid="2221993077220856376">"无网络"</string>
<string name="quick_settings_wifi_off_label" msgid="7558778100843885864">"WLAN 已关闭"</string>
- <string name="quick_settings_wifi_display_label" msgid="6893592964463624333">"WLAN 显示"</string>
- <string name="quick_settings_wifi_display_no_connection_label" msgid="2355298740765736918">"无线显示"</string>
+ <string name="quick_settings_remote_display_no_connection_label" msgid="372107699274391290">"投射屏幕"</string>
<string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"亮度"</string>
<string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"自动"</string>
<string name="ssl_ca_cert_warning" msgid="9005954106902053641">"网络可能会\n受到监控"</string>
diff --git a/packages/SystemUI/res/values-zh-rHK/strings.xml b/packages/SystemUI/res/values-zh-rHK/strings.xml
index 1007f85..bf5ae35 100644
--- a/packages/SystemUI/res/values-zh-rHK/strings.xml
+++ b/packages/SystemUI/res/values-zh-rHK/strings.xml
@@ -198,8 +198,7 @@
<string name="quick_settings_wifi_not_connected" msgid="7171904845345573431">"未連線"</string>
<string name="quick_settings_wifi_no_network" msgid="2221993077220856376">"沒有網絡"</string>
<string name="quick_settings_wifi_off_label" msgid="7558778100843885864">"Wi-Fi 關閉"</string>
- <string name="quick_settings_wifi_display_label" msgid="6893592964463624333">"Wi-Fi Display"</string>
- <string name="quick_settings_wifi_display_no_connection_label" msgid="2355298740765736918">"無線顯示"</string>
+ <string name="quick_settings_remote_display_no_connection_label" msgid="372107699274391290">"放送螢幕"</string>
<string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"亮度"</string>
<string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"自動"</string>
<string name="ssl_ca_cert_warning" msgid="9005954106902053641">"網絡可能會\n受到監控"</string>
diff --git a/packages/SystemUI/res/values-zh-rTW/strings.xml b/packages/SystemUI/res/values-zh-rTW/strings.xml
index edd6fd2..b1f99f5 100644
--- a/packages/SystemUI/res/values-zh-rTW/strings.xml
+++ b/packages/SystemUI/res/values-zh-rTW/strings.xml
@@ -198,8 +198,7 @@
<string name="quick_settings_wifi_not_connected" msgid="7171904845345573431">"未連線"</string>
<string name="quick_settings_wifi_no_network" msgid="2221993077220856376">"沒有網路"</string>
<string name="quick_settings_wifi_off_label" msgid="7558778100843885864">"關閉 Wi-Fi"</string>
- <string name="quick_settings_wifi_display_label" msgid="6893592964463624333">"Wi-Fi 顯示裝置"</string>
- <string name="quick_settings_wifi_display_no_connection_label" msgid="2355298740765736918">"無線螢幕分享"</string>
+ <string name="quick_settings_remote_display_no_connection_label" msgid="372107699274391290">"投放螢幕"</string>
<string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"亮度"</string>
<string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"自動"</string>
<string name="ssl_ca_cert_warning" msgid="9005954106902053641">"網路可能\n受到監控"</string>
diff --git a/packages/SystemUI/res/values-zu/strings.xml b/packages/SystemUI/res/values-zu/strings.xml
index d43ccfc..f284b7c 100644
--- a/packages/SystemUI/res/values-zu/strings.xml
+++ b/packages/SystemUI/res/values-zu/strings.xml
@@ -196,8 +196,7 @@
<string name="quick_settings_wifi_not_connected" msgid="7171904845345573431">"Akuxhunyiwe"</string>
<string name="quick_settings_wifi_no_network" msgid="2221993077220856376">"Ayikho inethiwekhi"</string>
<string name="quick_settings_wifi_off_label" msgid="7558778100843885864">"I-Wi-Fi icimile"</string>
- <string name="quick_settings_wifi_display_label" msgid="6893592964463624333">"Ukuboniswa kwe-Wi-"</string>
- <string name="quick_settings_wifi_display_no_connection_label" msgid="2355298740765736918">"Ukubonisa okungenazintambo"</string>
+ <string name="quick_settings_remote_display_no_connection_label" msgid="372107699274391290">"Isikrini sabalingisi"</string>
<string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"Ukugqama"</string>
<string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"OKUZENZAKALELAYO"</string>
<string name="ssl_ca_cert_warning" msgid="9005954106902053641">"Kungenzeka inethiwekhi\niqashiwe"</string>
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index e6fcdff..e36ca8e 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -490,10 +490,8 @@
<string name="quick_settings_wifi_no_network">No Network</string>
<!-- QuickSettings: Wifi (Off) [CHAR LIMIT=NONE] -->
<string name="quick_settings_wifi_off_label">Wi-Fi Off</string>
- <!-- QuickSettings: Wifi display [CHAR LIMIT=NONE] -->
- <string name="quick_settings_wifi_display_label">Wi-Fi Display</string>
- <!-- QuickSettings: Wifi display [CHAR LIMIT=NONE] -->
- <string name="quick_settings_wifi_display_no_connection_label">Wireless Display</string>
+ <!-- QuickSettings: Remote display [CHAR LIMIT=NONE] -->
+ <string name="quick_settings_remote_display_no_connection_label">Cast Screen</string>
<!-- QuickSettings: Brightness dialog title [CHAR LIMIT=NONE] -->
<string name="quick_settings_brightness_dialog_title">Brightness</string>
<!-- QuickSettings: Brightness dialog auto brightness button [CHAR LIMIT=NONE] -->
diff --git a/packages/SystemUI/src/com/android/systemui/DessertCase.java b/packages/SystemUI/src/com/android/systemui/DessertCase.java
index dd4c018..d797e38 100644
--- a/packages/SystemUI/src/com/android/systemui/DessertCase.java
+++ b/packages/SystemUI/src/com/android/systemui/DessertCase.java
@@ -36,7 +36,8 @@
if (pm.getComponentEnabledSetting(cn) != PackageManager.COMPONENT_ENABLED_STATE_ENABLED) {
Slog.v("DessertCase", "ACHIEVEMENT UNLOCKED");
pm.setComponentEnabledSetting(cn,
- PackageManager.COMPONENT_ENABLED_STATE_ENABLED, 0);
+ PackageManager.COMPONENT_ENABLED_STATE_ENABLED,
+ PackageManager.DONT_KILL_APP);
}
mView = new DessertCaseView(this);
diff --git a/packages/SystemUI/src/com/android/systemui/DessertCaseView.java b/packages/SystemUI/src/com/android/systemui/DessertCaseView.java
index 6fce732..4147155 100644
--- a/packages/SystemUI/src/com/android/systemui/DessertCaseView.java
+++ b/packages/SystemUI/src/com/android/systemui/DessertCaseView.java
@@ -496,7 +496,6 @@
}
public static class RescalingContainer extends FrameLayout {
- private static final int SYSTEM_UI_MODE_800 = 0x00000800;
private DessertCaseView mView;
private float mDarkness;
@@ -509,7 +508,7 @@
| View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
| View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
| View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
- | SYSTEM_UI_MODE_800
+ | View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY
);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/AnimatedImageView.java b/packages/SystemUI/src/com/android/systemui/statusbar/AnimatedImageView.java
index 9839fe9..7d3e870 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/AnimatedImageView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/AnimatedImageView.java
@@ -38,7 +38,7 @@
}
private void updateAnim() {
- Drawable drawable = getDrawable();
+ Drawable drawable = mAttached ? getDrawable() : null;
if (mAttached && mAnim != null) {
mAnim.stop();
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
index 607ce41..bbac4ef 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
@@ -2105,9 +2105,12 @@
}
public void tickerHalting() {
- mStatusBarContents.setVisibility(View.VISIBLE);
+ if (mStatusBarContents.getVisibility() != View.VISIBLE) {
+ mStatusBarContents.setVisibility(View.VISIBLE);
+ mStatusBarContents
+ .startAnimation(loadAnim(com.android.internal.R.anim.fade_in, null));
+ }
mTickerView.setVisibility(View.GONE);
- mStatusBarContents.startAnimation(loadAnim(com.android.internal.R.anim.fade_in, null));
// we do not animate the ticker away at this point, just get rid of it (b/6992707)
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickSettings.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickSettings.java
index 37504fb..e7b8fa1 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickSettings.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickSettings.java
@@ -37,9 +37,8 @@
import android.graphics.Bitmap;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
-import android.graphics.drawable.LevelListDrawable;
import android.hardware.display.DisplayManager;
-import android.hardware.display.WifiDisplayStatus;
+import android.media.MediaRouter;
import android.net.wifi.WifiManager;
import android.os.AsyncTask;
import android.os.Handler;
@@ -62,6 +61,7 @@
import android.widget.ImageView;
import android.widget.TextView;
+import com.android.internal.app.MediaRouteDialogPresenter;
import com.android.systemui.R;
import com.android.systemui.statusbar.phone.QuickSettingsModel.ActivityState;
import com.android.systemui.statusbar.phone.QuickSettingsModel.BluetoothState;
@@ -92,9 +92,7 @@
private QuickSettingsModel mModel;
private ViewGroup mContainerView;
- private DisplayManager mDisplayManager;
private DevicePolicyManager mDevicePolicyManager;
- private WifiDisplayStatus mWifiDisplayStatus;
private PhoneStatusBar mStatusBarService;
private BluetoothState mBluetoothState;
private BluetoothAdapter mBluetoothAdapter;
@@ -118,13 +116,11 @@
new ArrayList<QuickSettingsTileView>();
public QuickSettings(Context context, QuickSettingsContainerView container) {
- mDisplayManager = (DisplayManager) context.getSystemService(Context.DISPLAY_SERVICE);
mDevicePolicyManager
= (DevicePolicyManager) context.getSystemService(Context.DEVICE_POLICY_SERVICE);
mContext = context;
mContainerView = container;
mModel = new QuickSettingsModel(context);
- mWifiDisplayStatus = new WifiDisplayStatus();
mBluetoothState = new QuickSettingsModel.BluetoothState();
mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
mWifiManager = (WifiManager) context.getSystemService(Context.WIFI_SERVICE);
@@ -171,7 +167,6 @@
mLocationController = locationController;
setupQuickSettings();
- updateWifiDisplayStatus();
updateResources();
applyLocationEnabledStatus();
@@ -314,11 +309,19 @@
collapsePanels();
final UserManager um = UserManager.get(mContext);
if (um.getUsers(true).size() > 1) {
- try {
- WindowManagerGlobal.getWindowManagerService().lockNow(null);
- } catch (RemoteException e) {
- Log.e(TAG, "Couldn't show user switcher", e);
- }
+ // Since keyguard and systemui were merged into the same process to save
+ // memory, they share the same Looper and graphics context. As a result,
+ // there's no way to allow concurrent animation while keyguard inflates.
+ // The workaround is to add a slight delay to allow the animation to finish.
+ mHandler.postDelayed(new Runnable() {
+ public void run() {
+ try {
+ WindowManagerGlobal.getWindowManagerService().lockNow(null);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Couldn't show user switcher", e);
+ }
+ }
+ }, 400); // TODO: ideally this would be tied to the collapse of the panel
} else {
Intent intent = ContactsContract.QuickContact.composeQuickContactsIntent(
mContext, v, ContactsContract.Profile.CONTENT_URI,
@@ -668,20 +671,33 @@
});
parent.addView(alarmTile);
- // Wifi Display
- QuickSettingsBasicTile wifiDisplayTile
+ // Remote Display
+ QuickSettingsBasicTile remoteDisplayTile
= new QuickSettingsBasicTile(mContext);
- wifiDisplayTile.setImageResource(R.drawable.ic_qs_remote_display);
- wifiDisplayTile.setOnClickListener(new View.OnClickListener() {
+ remoteDisplayTile.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
- startSettingsActivity(android.provider.Settings.ACTION_WIFI_DISPLAY_SETTINGS);
+ collapsePanels();
+
+ final Dialog[] dialog = new Dialog[1];
+ dialog[0] = MediaRouteDialogPresenter.createDialog(mContext,
+ MediaRouter.ROUTE_TYPE_REMOTE_DISPLAY,
+ new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ dialog[0].dismiss();
+ startSettingsActivity(
+ android.provider.Settings.ACTION_WIFI_DISPLAY_SETTINGS);
+ }
+ });
+ dialog[0].getWindow().setType(WindowManager.LayoutParams.TYPE_VOLUME_OVERLAY);
+ dialog[0].show();
}
});
- mModel.addWifiDisplayTile(wifiDisplayTile,
- new QuickSettingsModel.BasicRefreshCallback(wifiDisplayTile)
+ mModel.addRemoteDisplayTile(remoteDisplayTile,
+ new QuickSettingsModel.BasicRefreshCallback(remoteDisplayTile)
.setShowWhenEnabled(true));
- parent.addView(wifiDisplayTile);
+ parent.addView(remoteDisplayTile);
if (SHOW_IME_TILE || DEBUG_GONE_TILES) {
// IME
@@ -816,15 +832,6 @@
dialog.show();
}
- private void updateWifiDisplayStatus() {
- mWifiDisplayStatus = mDisplayManager.getWifiDisplayStatus();
- applyWifiDisplayStatus();
- }
-
- private void applyWifiDisplayStatus() {
- mModel.onWifiDisplayStateChanged(mWifiDisplayStatus);
- }
-
private void applyBluetoothStatus() {
mModel.onBluetoothStateChange(mBluetoothState);
}
@@ -848,12 +855,7 @@
@Override
public void onReceive(Context context, Intent intent) {
final String action = intent.getAction();
- if (DisplayManager.ACTION_WIFI_DISPLAY_STATUS_CHANGED.equals(action)) {
- WifiDisplayStatus status = (WifiDisplayStatus)intent.getParcelableExtra(
- DisplayManager.EXTRA_WIFI_DISPLAY_STATUS);
- mWifiDisplayStatus = status;
- applyWifiDisplayStatus();
- } else if (BluetoothAdapter.ACTION_STATE_CHANGED.equals(action)) {
+ if (BluetoothAdapter.ACTION_STATE_CHANGED.equals(action)) {
int state = intent.getIntExtra(BluetoothAdapter.EXTRA_STATE,
BluetoothAdapter.ERROR);
mBluetoothState.enabled = (state == BluetoothAdapter.STATE_ON);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickSettingsModel.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickSettingsModel.java
index 15d655c..e1a20ec 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickSettingsModel.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickSettingsModel.java
@@ -27,7 +27,8 @@
import android.content.res.Resources;
import android.database.ContentObserver;
import android.graphics.drawable.Drawable;
-import android.hardware.display.WifiDisplayStatus;
+import android.media.MediaRouter;
+import android.media.MediaRouter.RouteInfo;
import android.net.ConnectivityManager;
import android.os.Handler;
import android.os.UserHandle;
@@ -57,7 +58,6 @@
BrightnessStateChangeCallback,
RotationLockControllerCallback,
LocationSettingsChangeCallback {
-
// Sett InputMethoManagerService
private static final String TAG_TRY_SUPPRESSING_IME_SWITCHER = "TrySuppressingImeSwitcher";
@@ -199,6 +199,30 @@
}
}
+ /** Callback for changes to remote display routes. */
+ private class RemoteDisplayRouteCallback extends MediaRouter.SimpleCallback {
+ @Override
+ public void onRouteAdded(MediaRouter router, RouteInfo route) {
+ updateRemoteDisplays();
+ }
+ @Override
+ public void onRouteChanged(MediaRouter router, RouteInfo route) {
+ updateRemoteDisplays();
+ }
+ @Override
+ public void onRouteRemoved(MediaRouter router, RouteInfo route) {
+ updateRemoteDisplays();
+ }
+ @Override
+ public void onRouteSelected(MediaRouter router, int type, RouteInfo route) {
+ updateRemoteDisplays();
+ }
+ @Override
+ public void onRouteUnselected(MediaRouter router, int type, RouteInfo route) {
+ updateRemoteDisplays();
+ }
+ }
+
private final Context mContext;
private final Handler mHandler;
private final CurrentUserTracker mUserTracker;
@@ -206,6 +230,9 @@
private final BugreportObserver mBugreportObserver;
private final BrightnessObserver mBrightnessObserver;
+ private final MediaRouter mMediaRouter;
+ private final RemoteDisplayRouteCallback mRemoteDisplayRouteCallback;
+
private final boolean mHasMobileData;
private QuickSettingsTileView mUserTile;
@@ -228,9 +255,9 @@
private RefreshCallback mWifiCallback;
private WifiState mWifiState = new WifiState();
- private QuickSettingsTileView mWifiDisplayTile;
- private RefreshCallback mWifiDisplayCallback;
- private State mWifiDisplayState = new State();
+ private QuickSettingsTileView mRemoteDisplayTile;
+ private RefreshCallback mRemoteDisplayCallback;
+ private State mRemoteDisplayState = new State();
private QuickSettingsTileView mRSSITile;
private RefreshCallback mRSSICallback;
@@ -278,12 +305,14 @@
mContext = context;
mHandler = new Handler();
mUserTracker = new CurrentUserTracker(mContext) {
+ @Override
public void onUserSwitched(int newUserId) {
mBrightnessObserver.startObserving();
refreshRotationLockTile();
onBrightnessLevelChanged();
onNextAlarmChanged();
onBugreportChanged();
+ rebindMediaRouterAsCurrentUser();
}
};
@@ -294,6 +323,11 @@
mBrightnessObserver = new BrightnessObserver(mHandler);
mBrightnessObserver.startObserving();
+ mMediaRouter = (MediaRouter)context.getSystemService(Context.MEDIA_ROUTER_SERVICE);
+ rebindMediaRouterAsCurrentUser();
+
+ mRemoteDisplayRouteCallback = new RemoteDisplayRouteCallback();
+
ConnectivityManager cm = (ConnectivityManager)
context.getSystemService(Context.CONNECTIVITY_SERVICE);
mHasMobileData = cm.isNetworkSupported(ConnectivityManager.TYPE_MOBILE);
@@ -621,24 +655,64 @@
mBugreportCallback.refreshView(mBugreportTile, mBugreportState);
}
- // Wifi Display
- void addWifiDisplayTile(QuickSettingsTileView view, RefreshCallback cb) {
- mWifiDisplayTile = view;
- mWifiDisplayCallback = cb;
- }
- public void onWifiDisplayStateChanged(WifiDisplayStatus status) {
- mWifiDisplayState.enabled =
- (status.getFeatureState() == WifiDisplayStatus.FEATURE_STATE_ON);
- if (status.getActiveDisplay() != null) {
- mWifiDisplayState.label = status.getActiveDisplay().getFriendlyDisplayName();
- mWifiDisplayState.iconId = R.drawable.ic_qs_remote_display_connected;
- } else {
- mWifiDisplayState.label = mContext.getString(
- R.string.quick_settings_wifi_display_no_connection_label);
- mWifiDisplayState.iconId = R.drawable.ic_qs_remote_display;
- }
- mWifiDisplayCallback.refreshView(mWifiDisplayTile, mWifiDisplayState);
+ // Remote Display
+ void addRemoteDisplayTile(QuickSettingsTileView view, RefreshCallback cb) {
+ mRemoteDisplayTile = view;
+ mRemoteDisplayCallback = cb;
+ final int[] count = new int[1];
+ mRemoteDisplayTile.setOnPrepareListener(new QuickSettingsTileView.OnPrepareListener() {
+ @Override
+ public void onPrepare() {
+ mMediaRouter.addCallback(MediaRouter.ROUTE_TYPE_REMOTE_DISPLAY,
+ mRemoteDisplayRouteCallback,
+ MediaRouter.CALLBACK_FLAG_REQUEST_DISCOVERY);
+ updateRemoteDisplays();
+ }
+ @Override
+ public void onUnprepare() {
+ mMediaRouter.removeCallback(mRemoteDisplayRouteCallback);
+ }
+ });
+ updateRemoteDisplays();
+ }
+
+ private void rebindMediaRouterAsCurrentUser() {
+ mMediaRouter.rebindAsUser(mUserTracker.getCurrentUserId());
+ }
+
+ private void updateRemoteDisplays() {
+ MediaRouter.RouteInfo connectedRoute = mMediaRouter.getSelectedRoute(
+ MediaRouter.ROUTE_TYPE_REMOTE_DISPLAY);
+ boolean enabled = connectedRoute != null
+ && connectedRoute.matchesTypes(MediaRouter.ROUTE_TYPE_REMOTE_DISPLAY);
+ boolean connecting;
+ if (enabled) {
+ connecting = connectedRoute.isConnecting();
+ } else {
+ connectedRoute = null;
+ connecting = false;
+ final int count = mMediaRouter.getRouteCount();
+ for (int i = 0; i < count; i++) {
+ MediaRouter.RouteInfo route = mMediaRouter.getRouteAt(i);
+ if (route.matchesTypes(MediaRouter.ROUTE_TYPE_REMOTE_DISPLAY)) {
+ enabled = true;
+ break;
+ }
+ }
+ }
+
+ mRemoteDisplayState.enabled = enabled;
+ if (connectedRoute != null) {
+ mRemoteDisplayState.label = connectedRoute.getName().toString();
+ mRemoteDisplayState.iconId = connecting ?
+ R.drawable.ic_qs_cast_connecting : R.drawable.ic_qs_cast_connected;
+ } else {
+ mRemoteDisplayState.label = mContext.getString(
+ R.string.quick_settings_remote_display_no_connection_label);
+ mRemoteDisplayState.iconId = R.drawable.ic_qs_cast_available;
+ }
+ mRemoteDisplayCallback.refreshView(mRemoteDisplayTile, mRemoteDisplayState);
}
// IME
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickSettingsTileView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickSettingsTileView.java
index 3d520f7..ad18294 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickSettingsTileView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickSettingsTileView.java
@@ -21,6 +21,7 @@
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
+import android.view.ViewParent;
import android.widget.FrameLayout;
/**
@@ -31,14 +32,14 @@
private int mContentLayoutId;
private int mColSpan;
- private int mRowSpan;
+ private boolean mPrepared;
+ private OnPrepareListener mOnPrepareListener;
public QuickSettingsTileView(Context context, AttributeSet attrs) {
super(context, attrs);
mContentLayoutId = -1;
mColSpan = 1;
- mRowSpan = 1;
}
void setColumnSpan(int span) {
@@ -77,4 +78,72 @@
}
super.setVisibility(vis);
}
+
+ public void setOnPrepareListener(OnPrepareListener listener) {
+ if (mOnPrepareListener != listener) {
+ mOnPrepareListener = listener;
+ mPrepared = false;
+ post(new Runnable() {
+ @Override
+ public void run() {
+ updatePreparedState();
+ }
+ });
+ }
+ }
+
+ @Override
+ protected void onVisibilityChanged(View changedView, int visibility) {
+ super.onVisibilityChanged(changedView, visibility);
+ updatePreparedState();
+ }
+
+ @Override
+ protected void onAttachedToWindow() {
+ super.onAttachedToWindow();
+ updatePreparedState();
+ }
+
+ @Override
+ protected void onDetachedFromWindow() {
+ super.onDetachedFromWindow();
+ updatePreparedState();
+ }
+
+ private void updatePreparedState() {
+ if (mOnPrepareListener != null) {
+ if (isParentVisible()) {
+ if (!mPrepared) {
+ mPrepared = true;
+ mOnPrepareListener.onPrepare();
+ }
+ } else if (mPrepared) {
+ mPrepared = false;
+ mOnPrepareListener.onUnprepare();
+ }
+ }
+ }
+
+ private boolean isParentVisible() {
+ if (!isAttachedToWindow()) {
+ return false;
+ }
+ for (ViewParent current = getParent(); current instanceof View;
+ current = current.getParent()) {
+ View view = (View)current;
+ if (view.getVisibility() != VISIBLE) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ /**
+ * Called when the view's parent becomes visible or invisible to provide
+ * an opportunity for the client to provide new content.
+ */
+ public interface OnPrepareListener {
+ void onPrepare();
+ void onUnprepare();
+ }
}
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/DeadZone.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/DeadZone.java
index dca5e41..6eb88be 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/DeadZone.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/DeadZone.java
@@ -22,7 +22,7 @@
import android.graphics.Canvas;
import android.os.SystemClock;
import android.util.AttributeSet;
-import android.util.Log;
+import android.util.Slog;
import android.view.MotionEvent;
import android.view.View;
@@ -75,7 +75,7 @@
mVertical = (index == VERTICAL);
if (DEBUG)
- Log.v(TAG, this + " size=[" + mSizeMin + "-" + mSizeMax + "] hold=" + mHold
+ Slog.v(TAG, this + " size=[" + mSizeMin + "-" + mSizeMax + "] hold=" + mHold
+ (mVertical ? " vertical" : " horizontal"));
setFlashOnTouchCapture(context.getResources().getBoolean(R.bool.config_dead_zone_flash));
@@ -106,7 +106,7 @@
@Override
public boolean onTouchEvent(MotionEvent event) {
if (DEBUG) {
- Log.v(TAG, this + " onTouch: " + MotionEvent.actionToString(event.getAction()));
+ Slog.v(TAG, this + " onTouch: " + MotionEvent.actionToString(event.getAction()));
}
final int action = event.getAction();
@@ -114,12 +114,12 @@
poke(event);
} else if (action == MotionEvent.ACTION_DOWN) {
if (DEBUG) {
- Log.v(TAG, this + " ACTION_DOWN: " + event.getX() + "," + event.getY());
+ Slog.v(TAG, this + " ACTION_DOWN: " + event.getX() + "," + event.getY());
}
int size = (int) getSize(event.getEventTime());
if ((mVertical && event.getX() < size) || event.getY() < size) {
if (CHATTY) {
- Log.v(TAG, "consuming errant click: (" + event.getX() + "," + event.getY() + ")");
+ Slog.v(TAG, "consuming errant click: (" + event.getX() + "," + event.getY() + ")");
}
if (mShouldFlash) {
post(mDebugFlash);
@@ -134,7 +134,7 @@
public void poke(MotionEvent event) {
mLastPokeTime = event.getEventTime();
if (DEBUG)
- Log.v(TAG, "poked! size=" + getSize(mLastPokeTime));
+ Slog.v(TAG, "poked! size=" + getSize(mLastPokeTime));
if (mShouldFlash) postInvalidate();
}
diff --git a/policy/src/com/android/internal/policy/impl/BarController.java b/policy/src/com/android/internal/policy/impl/BarController.java
index c38ad04..0ce4b12 100644
--- a/policy/src/com/android/internal/policy/impl/BarController.java
+++ b/policy/src/com/android/internal/policy/impl/BarController.java
@@ -37,8 +37,9 @@
private static final boolean DEBUG = false;
private static final int TRANSIENT_BAR_NONE = 0;
- private static final int TRANSIENT_BAR_SHOWING = 1;
- private static final int TRANSIENT_BAR_HIDING = 2;
+ private static final int TRANSIENT_BAR_SHOW_REQUESTED = 1;
+ private static final int TRANSIENT_BAR_SHOWING = 2;
+ private static final int TRANSIENT_BAR_HIDING = 3;
private static final int TRANSLUCENT_ANIMATION_DELAY_MS = 1000;
@@ -73,13 +74,9 @@
mWin = win;
}
- public boolean isHidden() {
- return mState == StatusBarManager.WINDOW_STATE_HIDDEN;
- }
-
public void showTransient() {
if (mWin != null) {
- setTransientBarState(TRANSIENT_BAR_SHOWING);
+ setTransientBarState(TRANSIENT_BAR_SHOW_REQUESTED);
}
}
@@ -87,6 +84,10 @@
return mTransientBarState == TRANSIENT_BAR_SHOWING;
}
+ public boolean isTransientShowRequested() {
+ return mTransientBarState == TRANSIENT_BAR_SHOW_REQUESTED;
+ }
+
public boolean wasRecentlyTranslucent() {
return (SystemClock.uptimeMillis() - mLastTranslucent) < TRANSLUCENT_ANIMATION_DELAY_MS;
}
@@ -198,6 +199,9 @@
if (mTransientBarState == TRANSIENT_BAR_SHOWING) {
if (DEBUG) Slog.d(mTag, "Not showing transient bar, already shown");
return false;
+ } else if (mTransientBarState == TRANSIENT_BAR_SHOW_REQUESTED) {
+ if (DEBUG) Slog.d(mTag, "Not showing transient bar, already requested");
+ return false;
} else if (mWin == null) {
if (DEBUG) Slog.d(mTag, "Not showing transient bar, bar doesn't exist");
return false;
@@ -211,12 +215,13 @@
public int updateVisibilityLw(boolean transientAllowed, int oldVis, int vis) {
if (mWin == null) return vis;
- if (mTransientBarState == TRANSIENT_BAR_SHOWING) { // transient bar requested
+ if (isTransientShowing() || isTransientShowRequested()) { // transient bar requested
if (transientAllowed) {
vis |= mTransientFlag;
if ((oldVis & mTransientFlag) == 0) {
vis |= mUnhideFlag; // tell sysui we're ready to unhide
}
+ setTransientBarState(TRANSIENT_BAR_SHOWING); // request accepted
} else {
setTransientBarState(TRANSIENT_BAR_NONE); // request denied
}
@@ -254,6 +259,7 @@
private static String transientBarStateToString(int state) {
if (state == TRANSIENT_BAR_HIDING) return "TRANSIENT_BAR_HIDING";
if (state == TRANSIENT_BAR_SHOWING) return "TRANSIENT_BAR_SHOWING";
+ if (state == TRANSIENT_BAR_SHOW_REQUESTED) return "TRANSIENT_BAR_SHOW_REQUESTED";
if (state == TRANSIENT_BAR_NONE) return "TRANSIENT_BAR_NONE";
throw new IllegalArgumentException("Unknown state " + state);
}
diff --git a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
index faca949..c33bd35 100644
--- a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
+++ b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
@@ -3468,6 +3468,11 @@
}
// Maintain fullscreen layout until incoming animation is complete.
topIsFullscreen = mTopIsFullscreen && mStatusBar.isAnimatingLw();
+ // Transient status bar on the lockscreen is not allowed
+ if (mForceStatusBarFromKeyguard && mStatusBarController.isTransientShowing()) {
+ mStatusBarController.updateVisibilityLw(false /*transientAllowed*/,
+ mLastSystemUiFlags, mLastSystemUiFlags);
+ }
} else if (mTopFullscreenOpaqueWindowState != null) {
if (localLOGV) {
Slog.d(TAG, "frame: " + mTopFullscreenOpaqueWindowState.getFrameLw()
@@ -5158,9 +5163,9 @@
mNavigationBar != null &&
hideNavBarSysui && immersiveSticky;
- boolean denyTransientStatus = mStatusBarController.isTransientShowing()
+ boolean denyTransientStatus = mStatusBarController.isTransientShowRequested()
&& !transientStatusBarAllowed && hideStatusBarSysui;
- boolean denyTransientNav = mNavigationBarController.isTransientShowing()
+ boolean denyTransientNav = mNavigationBarController.isTransientShowRequested()
&& !transientNavBarAllowed;
if (denyTransientStatus || denyTransientNav) {
// clear the clearable flags instead
diff --git a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardServiceDelegate.java b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardServiceDelegate.java
index bf22e2f..1357462 100644
--- a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardServiceDelegate.java
+++ b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardServiceDelegate.java
@@ -40,6 +40,14 @@
private KeyguardState mKeyguardState = new KeyguardState();
/* package */ static final class KeyguardState {
+ KeyguardState() {
+ // Assume keyguard is showing and secure until we know for sure. This is here in
+ // the event something checks before the service is actually started.
+ // KeyguardService itself should default to this state until the real state is known.
+ showing = true;
+ showingAndNotHidden = true;
+ secure = true;
+ }
boolean showing;
boolean showingAndNotHidden;
boolean inputRestricted;
diff --git a/services/java/com/android/server/BackupManagerService.java b/services/java/com/android/server/BackupManagerService.java
index a04ee14..baef607 100644
--- a/services/java/com/android/server/BackupManagerService.java
+++ b/services/java/com/android/server/BackupManagerService.java
@@ -46,6 +46,8 @@
import android.content.pm.IPackageManager;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
+import android.content.pm.ServiceInfo;
import android.content.pm.Signature;
import android.content.pm.PackageManager.NameNotFoundException;
import android.database.ContentObserver;
@@ -146,6 +148,7 @@
static final boolean COMPRESS_FULL_BACKUPS = true; // should be true in production
static final String SHARED_BACKUP_AGENT_PACKAGE = "com.android.sharedstoragebackup";
+ static final String SERVICE_ACTION_TRANSPORT_HOST = "android.backup.TRANSPORT_HOST";
// How often we perform a backup pass. Privileged external callers can
// trigger an immediate pass.
@@ -251,10 +254,13 @@
volatile boolean mClearingData;
// Transport bookkeeping
+ final HashMap<String,String> mTransportNames
+ = new HashMap<String,String>(); // component name -> registration name
final HashMap<String,IBackupTransport> mTransports
- = new HashMap<String,IBackupTransport>();
+ = new HashMap<String,IBackupTransport>(); // registration name -> binder
+ final ArrayList<TransportConnection> mTransportConnections
+ = new ArrayList<TransportConnection>();
String mCurrentTransport;
- IBackupTransport mLocalTransport, mGoogleTransport;
ActiveRestoreSession mActiveRestoreSession;
// Watch the device provisioning operation during setup
@@ -815,13 +821,7 @@
}
// Set up our transport options and initialize the default transport
- // TODO: Have transports register themselves somehow?
// TODO: Don't create transports that we don't need to?
- mLocalTransport = new LocalTransport(context); // This is actually pretty cheap
- ComponentName localName = new ComponentName(context, LocalTransport.class);
- registerTransport(localName.flattenToShortString(), mLocalTransport);
-
- mGoogleTransport = null;
mCurrentTransport = Settings.Secure.getString(context.getContentResolver(),
Settings.Secure.BACKUP_TRANSPORT);
if ("".equals(mCurrentTransport)) {
@@ -829,28 +829,43 @@
}
if (DEBUG) Slog.v(TAG, "Starting with transport " + mCurrentTransport);
- // Attach to the Google backup transport. When this comes up, it will set
- // itself as the current transport because we explicitly reset mCurrentTransport
- // to null.
- ComponentName transportComponent = new ComponentName("com.google.android.backup",
- "com.google.android.backup.BackupTransportService");
- try {
- // If there's something out there that is supposed to be the Google
- // backup transport, make sure it's legitimately part of the OS build
- // and not an app lying about its package name.
- ApplicationInfo info = mPackageManager.getApplicationInfo(
- transportComponent.getPackageName(), 0);
- if ((info.flags & ApplicationInfo.FLAG_SYSTEM) != 0) {
- if (DEBUG) Slog.v(TAG, "Binding to Google transport");
- Intent intent = new Intent().setComponent(transportComponent);
- context.bindServiceAsUser(intent, mGoogleConnection, Context.BIND_AUTO_CREATE,
- UserHandle.OWNER);
- } else {
- Slog.w(TAG, "Possible Google transport spoof: ignoring " + info);
+ // Find transport hosts and bind to their services
+ Intent transportServiceIntent = new Intent(SERVICE_ACTION_TRANSPORT_HOST);
+ List<ResolveInfo> hosts = mPackageManager.queryIntentServicesAsUser(
+ transportServiceIntent, 0, UserHandle.USER_OWNER);
+ if (DEBUG) {
+ Slog.v(TAG, "Found transports: " + ((hosts == null) ? "null" : hosts.size()));
+ }
+ if (hosts != null) {
+ if (MORE_DEBUG) {
+ for (int i = 0; i < hosts.size(); i++) {
+ ServiceInfo info = hosts.get(i).serviceInfo;
+ Slog.v(TAG, " " + info.packageName + "/" + info.name);
+ }
}
- } catch (PackageManager.NameNotFoundException nnf) {
- // No such package? No binding.
- if (DEBUG) Slog.v(TAG, "Google transport not present");
+ for (int i = 0; i < hosts.size(); i++) {
+ try {
+ ServiceInfo info = hosts.get(i).serviceInfo;
+ PackageInfo packInfo = mPackageManager.getPackageInfo(info.packageName, 0);
+ if ((packInfo.applicationInfo.flags & ApplicationInfo.FLAG_PRIVILEGED) != 0) {
+ ComponentName svcName = new ComponentName(info.packageName, info.name);
+ if (DEBUG) {
+ Slog.i(TAG, "Binding to transport host " + svcName);
+ }
+ Intent intent = new Intent(transportServiceIntent);
+ intent.setComponent(svcName);
+ TransportConnection connection = new TransportConnection();
+ mTransportConnections.add(connection);
+ context.bindServiceAsUser(intent,
+ connection, Context.BIND_AUTO_CREATE,
+ UserHandle.OWNER);
+ } else {
+ Slog.w(TAG, "Transport package not privileged: " + info.packageName);
+ }
+ } catch (Exception e) {
+ Slog.e(TAG, "Problem resolving transport service: " + e.getMessage());
+ }
+ }
}
// Now that we know about valid backup participants, parse any
@@ -1298,13 +1313,16 @@
// Add a transport to our set of available backends. If 'transport' is null, this
// is an unregistration, and the transport's entry is removed from our bookkeeping.
- private void registerTransport(String name, IBackupTransport transport) {
+ private void registerTransport(String name, String component, IBackupTransport transport) {
synchronized (mTransports) {
- if (DEBUG) Slog.v(TAG, "Registering transport " + name + " = " + transport);
+ if (DEBUG) Slog.v(TAG, "Registering transport "
+ + component + "::" + name + " = " + transport);
if (transport != null) {
mTransports.put(name, transport);
+ mTransportNames.put(component, name);
} else {
- mTransports.remove(name);
+ mTransports.remove(mTransportNames.get(component));
+ mTransportNames.remove(component);
// Nothing further to do in the unregistration case
return;
}
@@ -1390,18 +1408,23 @@
}
};
- // ----- Track connection to GoogleBackupTransport service -----
- ServiceConnection mGoogleConnection = new ServiceConnection() {
- public void onServiceConnected(ComponentName name, IBinder service) {
- if (DEBUG) Slog.v(TAG, "Connected to Google transport");
- mGoogleTransport = IBackupTransport.Stub.asInterface(service);
- registerTransport(name.flattenToShortString(), mGoogleTransport);
+ // ----- Track connection to transports service -----
+ class TransportConnection implements ServiceConnection {
+ @Override
+ public void onServiceConnected(ComponentName component, IBinder service) {
+ if (DEBUG) Slog.v(TAG, "Connected to transport " + component);
+ try {
+ IBackupTransport transport = IBackupTransport.Stub.asInterface(service);
+ registerTransport(transport.name(), component.flattenToShortString(), transport);
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Unable to register transport " + component);
+ }
}
- public void onServiceDisconnected(ComponentName name) {
- if (DEBUG) Slog.v(TAG, "Disconnected from Google transport");
- mGoogleTransport = null;
- registerTransport(name.flattenToShortString(), null);
+ @Override
+ public void onServiceDisconnected(ComponentName component) {
+ if (DEBUG) Slog.v(TAG, "Disconnected from transport " + component);
+ registerTransport(null, component.flattenToShortString(), null);
}
};
diff --git a/services/java/com/android/server/ConnectivityService.java b/services/java/com/android/server/ConnectivityService.java
index 594f683..baff661 100644
--- a/services/java/com/android/server/ConnectivityService.java
+++ b/services/java/com/android/server/ConnectivityService.java
@@ -3380,6 +3380,11 @@
String pacFileUrl = "";
if (proxyProperties != null && (!TextUtils.isEmpty(proxyProperties.getHost()) ||
!TextUtils.isEmpty(proxyProperties.getPacFileUrl()))) {
+ if (!proxyProperties.isValid()) {
+ if (DBG)
+ log("Invalid proxy properties, ignoring: " + proxyProperties.toString());
+ return;
+ }
mGlobalProxy = new ProxyProperties(proxyProperties);
host = mGlobalProxy.getHost();
port = mGlobalProxy.getPort();
@@ -3423,6 +3428,11 @@
} else {
proxyProperties = new ProxyProperties(host, port, exclList);
}
+ if (!proxyProperties.isValid()) {
+ if (DBG) log("Invalid proxy properties, ignoring: " + proxyProperties.toString());
+ return;
+ }
+
synchronized (mProxyLock) {
mGlobalProxy = proxyProperties;
}
@@ -3447,6 +3457,10 @@
synchronized (mProxyLock) {
if (mDefaultProxy != null && mDefaultProxy.equals(proxy)) return;
if (mDefaultProxy == proxy) return; // catches repeated nulls
+ if (proxy != null && !proxy.isValid()) {
+ if (DBG) log("Invalid proxy properties, ignoring: " + proxy.toString());
+ return;
+ }
mDefaultProxy = proxy;
if (mGlobalProxy != null) return;
diff --git a/services/java/com/android/server/DevicePolicyManagerService.java b/services/java/com/android/server/DevicePolicyManagerService.java
index 8cc80f7..2bb99d6 100644
--- a/services/java/com/android/server/DevicePolicyManagerService.java
+++ b/services/java/com/android/server/DevicePolicyManagerService.java
@@ -56,6 +56,7 @@
import android.content.pm.PackageManager.NameNotFoundException;
import android.content.pm.ResolveInfo;
import android.content.pm.UserInfo;
+import android.net.ProxyProperties;
import android.net.Uri;
import android.os.AsyncTask;
import android.os.Binder;
@@ -522,6 +523,7 @@
|| pm.getReceiverInfo(aa.info.getComponent(), 0, userHandle) == null) {
removed = true;
policy.mAdminList.remove(i);
+ policy.mAdminMap.remove(aa.info.getComponent());
}
} catch (RemoteException re) {
// Shouldn't happen
@@ -2463,6 +2465,12 @@
}
exclusionList = exclusionList.trim();
ContentResolver res = mContext.getContentResolver();
+
+ ProxyProperties proxyProperties = new ProxyProperties(data[0], proxyPort, exclusionList);
+ if (!proxyProperties.isValid()) {
+ Slog.e(TAG, "Invalid proxy properties, ignoring: " + proxyProperties.toString());
+ return;
+ }
Settings.Global.putString(res, Settings.Global.GLOBAL_HTTP_PROXY_HOST, data[0]);
Settings.Global.putInt(res, Settings.Global.GLOBAL_HTTP_PROXY_PORT, proxyPort);
Settings.Global.putString(res, Settings.Global.GLOBAL_HTTP_PROXY_EXCLUSION_LIST,
diff --git a/services/java/com/android/server/EventLogTags.logtags b/services/java/com/android/server/EventLogTags.logtags
index 8eaa91d..399e7d1 100644
--- a/services/java/com/android/server/EventLogTags.logtags
+++ b/services/java/com/android/server/EventLogTags.logtags
@@ -123,6 +123,18 @@
# ---------------------------
# Out of memory for surfaces.
31000 wm_no_surface_memory (Window|3),(PID|1|5),(Operation|3)
+# Task created.
+31001 wm_task_created (TaskId|1|5),(StackId|1|5)
+# Task moved to top (1) or bottom (0).
+31002 wm_task_moved (TaskId|1|5),(ToTop|1),(Index|1)
+# Task removed with source explanation.
+31003 wm_task_removed (TaskId|1|5),(Reason|3)
+# Stack created.
+31004 wm_stack_created (StackId|1|5),(RelativeBoxId|1|5),(Position|1),(Weight|1|6)
+# Home stack moved to top (1) or bottom (0).
+31005 wm_home_stack_moved (ToTop|1)
+# Stack removed.
+31006 wm_stack_removed (StackId|1|5)
# ---------------------------
diff --git a/services/java/com/android/server/LockSettingsService.java b/services/java/com/android/server/LockSettingsService.java
index cd746cf..35e7afa 100644
--- a/services/java/com/android/server/LockSettingsService.java
+++ b/services/java/com/android/server/LockSettingsService.java
@@ -154,11 +154,11 @@
}
private final void checkWritePermission(int userId) {
- mContext.checkCallingOrSelfPermission(PERMISSION);
+ mContext.enforceCallingOrSelfPermission(PERMISSION, "LockSettingsWrite");
}
private final void checkPasswordReadPermission(int userId) {
- mContext.checkCallingOrSelfPermission(PERMISSION);
+ mContext.enforceCallingOrSelfPermission(PERMISSION, "LockSettingsRead");
}
private final void checkReadPermission(String requestedKey, int userId) {
diff --git a/services/java/com/android/server/NsdService.java b/services/java/com/android/server/NsdService.java
index e0f415b..16d2468 100644
--- a/services/java/com/android/server/NsdService.java
+++ b/services/java/com/android/server/NsdService.java
@@ -483,10 +483,14 @@
clientInfo.mResolvedService.setPort(Integer.parseInt(cooked[4]));
stopResolveService(id);
- if (!getAddrInfo(id, cooked[3])) {
+ removeRequestMap(clientId, id, clientInfo);
+
+ int id2 = getUniqueId();
+ if (getAddrInfo(id2, cooked[3])) {
+ storeRequestMap(clientId, id2, clientInfo);
+ } else {
clientInfo.mChannel.sendMessage(NsdManager.RESOLVE_SERVICE_FAILED,
NsdManager.FAILURE_INTERNAL_ERROR, clientId);
- removeRequestMap(clientId, id, clientInfo);
clientInfo.mResolvedService = null;
}
break;
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index bb14259..a42cbcf 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -55,6 +55,7 @@
import com.android.server.display.DisplayManagerService;
import com.android.server.dreams.DreamManagerService;
import com.android.server.input.InputManagerService;
+import com.android.server.media.MediaRouterService;
import com.android.server.net.NetworkPolicyManagerService;
import com.android.server.net.NetworkStatsService;
import com.android.server.os.SchedulingPolicyService;
@@ -356,6 +357,7 @@
DreamManagerService dreamy = null;
AssetAtlasService atlas = null;
PrintManagerService printManager = null;
+ MediaRouterService mediaRouter = null;
// Bring up services needed for UI.
if (factoryTest != SystemServer.FACTORY_TEST_LOW_LEVEL) {
@@ -804,6 +806,16 @@
} catch (Throwable e) {
reportWtf("starting Print Service", e);
}
+
+ if (!disableNonCoreServices) {
+ try {
+ Slog.i(TAG, "Media Router Service");
+ mediaRouter = new MediaRouterService(context);
+ ServiceManager.addService(Context.MEDIA_ROUTER_SERVICE, mediaRouter);
+ } catch (Throwable e) {
+ reportWtf("starting MediaRouterService", e);
+ }
+ }
}
// Before things start rolling, be sure we have decided whether
@@ -916,6 +928,7 @@
final InputManagerService inputManagerF = inputManager;
final TelephonyRegistry telephonyRegistryF = telephonyRegistry;
final PrintManagerService printManagerF = printManager;
+ final MediaRouterService mediaRouterF = mediaRouter;
// We now tell the activity manager it is okay to run third party
// code. It will call back into us once it has gotten to the state
@@ -1063,6 +1076,12 @@
} catch (Throwable e) {
reportWtf("Notifying PrintManagerService running", e);
}
+
+ try {
+ if (mediaRouterF != null) mediaRouterF.systemRunning();
+ } catch (Throwable e) {
+ reportWtf("Notifying MediaRouterService running", e);
+ }
}
});
diff --git a/services/java/com/android/server/WallpaperManagerService.java b/services/java/com/android/server/WallpaperManagerService.java
index c1a60ee..e6b6b93 100644
--- a/services/java/com/android/server/WallpaperManagerService.java
+++ b/services/java/com/android/server/WallpaperManagerService.java
@@ -40,6 +40,7 @@
import android.content.pm.PackageManager.NameNotFoundException;
import android.content.pm.UserInfo;
import android.content.res.Resources;
+import android.graphics.Point;
import android.os.Binder;
import android.os.Bundle;
import android.os.Environment;
@@ -637,6 +638,14 @@
return false;
}
+ private Point getDefaultDisplaySize() {
+ Point p = new Point();
+ WindowManager wm = (WindowManager)mContext.getSystemService(Context.WINDOW_SERVICE);
+ Display d = wm.getDefaultDisplay();
+ d.getRealSize(p);
+ return p;
+ }
+
public void setDimensionHints(int width, int height) throws RemoteException {
checkPermission(android.Manifest.permission.SET_WALLPAPER_HINTS);
synchronized (mLock) {
@@ -648,10 +657,10 @@
if (width <= 0 || height <= 0) {
throw new IllegalArgumentException("width and height must be > 0");
}
- // Make sure it is at least as large as the display's maximum size.
- int maxSizeDimension = getMaximumSizeDimension();
- width = Math.max(width, maxSizeDimension);
- height = Math.max(height, maxSizeDimension);
+ // Make sure it is at least as large as the display.
+ Point displaySize = getDefaultDisplaySize();
+ width = Math.max(width, displaySize.x);
+ height = Math.max(height, displaySize.y);
if (width != wallpaper.width || height != wallpaper.height) {
wallpaper.width = width;
diff --git a/services/java/com/android/server/accounts/AccountManagerService.java b/services/java/com/android/server/accounts/AccountManagerService.java
index f972f70..aa9849e 100644
--- a/services/java/com/android/server/accounts/AccountManagerService.java
+++ b/services/java/com/android/server/accounts/AccountManagerService.java
@@ -190,10 +190,10 @@
private final HashMap<String, Account[]> accountCache =
new LinkedHashMap<String, Account[]>();
/** protected by the {@link #cacheLock} */
- private HashMap<Account, HashMap<String, String>> userDataCache =
+ private final HashMap<Account, HashMap<String, String>> userDataCache =
new HashMap<Account, HashMap<String, String>>();
/** protected by the {@link #cacheLock} */
- private HashMap<Account, HashMap<String, String>> authTokenCache =
+ private final HashMap<Account, HashMap<String, String>> authTokenCache =
new HashMap<Account, HashMap<String, String>>();
UserAccounts(Context context, int userId) {
@@ -475,6 +475,7 @@
validateAccountsInternal(getUserAccounts(userId), false /* invalidateAuthenticatorCache */);
}
+ @Override
public String getPassword(Account account) {
if (Log.isLoggable(TAG, Log.VERBOSE)) {
Log.v(TAG, "getPassword: " + account
@@ -514,6 +515,7 @@
}
}
+ @Override
public String getUserData(Account account, String key) {
if (Log.isLoggable(TAG, Log.VERBOSE)) {
Log.v(TAG, "getUserData: " + account
@@ -533,6 +535,7 @@
}
}
+ @Override
public AuthenticatorDescription[] getAuthenticatorTypes() {
if (Log.isLoggable(TAG, Log.VERBOSE)) {
Log.v(TAG, "getAuthenticatorTypes: "
@@ -763,6 +766,7 @@
return db.insert(TABLE_EXTRAS, EXTRAS_KEY, values);
}
+ @Override
public void hasFeatures(IAccountManagerResponse response,
Account account, String[] features) {
if (Log.isLoggable(TAG, Log.VERBOSE)) {
@@ -840,6 +844,7 @@
}
}
+ @Override
public void removeAccount(IAccountManagerResponse response, Account account) {
if (Log.isLoggable(TAG, Log.VERBOSE)) {
Log.v(TAG, "removeAccount: " + account
@@ -1049,6 +1054,7 @@
}
}
+ @Override
public String peekAuthToken(Account account, String authTokenType) {
if (Log.isLoggable(TAG, Log.VERBOSE)) {
Log.v(TAG, "peekAuthToken: " + account
@@ -1068,6 +1074,7 @@
}
}
+ @Override
public void setAuthToken(Account account, String authTokenType, String authToken) {
if (Log.isLoggable(TAG, Log.VERBOSE)) {
Log.v(TAG, "setAuthToken: " + account
@@ -1087,6 +1094,7 @@
}
}
+ @Override
public void setPassword(Account account, String password) {
if (Log.isLoggable(TAG, Log.VERBOSE)) {
Log.v(TAG, "setAuthToken: " + account
@@ -1135,6 +1143,7 @@
mContext.sendBroadcastAsUser(ACCOUNTS_CHANGED_INTENT, new UserHandle(userId));
}
+ @Override
public void clearPassword(Account account) {
if (Log.isLoggable(TAG, Log.VERBOSE)) {
Log.v(TAG, "clearPassword: " + account
@@ -1152,6 +1161,7 @@
}
}
+ @Override
public void setUserData(Account account, String key, String value) {
if (Log.isLoggable(TAG, Log.VERBOSE)) {
Log.v(TAG, "setUserData: " + account
@@ -1225,6 +1235,7 @@
}
}
+ @Override
public void getAuthTokenLabel(IAccountManagerResponse response, final String accountType,
final String authTokenType)
throws RemoteException {
@@ -1271,6 +1282,7 @@
}
}
+ @Override
public void getAuthToken(IAccountManagerResponse response, final Account account,
final String authTokenType, final boolean notifyOnAuthFailure,
final boolean expectActivityLaunch, Bundle loginOptionsIn) {
@@ -1284,8 +1296,22 @@
+ ", pid " + Binder.getCallingPid());
}
if (response == null) throw new IllegalArgumentException("response is null");
- if (account == null) throw new IllegalArgumentException("account is null");
- if (authTokenType == null) throw new IllegalArgumentException("authTokenType is null");
+ try {
+ if (account == null) {
+ Slog.w(TAG, "getAuthToken called with null account");
+ response.onError(AccountManager.ERROR_CODE_BAD_ARGUMENTS, "account is null");
+ return;
+ }
+ if (authTokenType == null) {
+ Slog.w(TAG, "getAuthToken called with null authTokenType");
+ response.onError(AccountManager.ERROR_CODE_BAD_ARGUMENTS, "authTokenType is null");
+ return;
+ }
+ } catch (RemoteException e) {
+ Slog.w(TAG, "Failed to report error back to the client." + e);
+ return;
+ }
+
checkBinderPermission(Manifest.permission.USE_CREDENTIALS);
final UserAccounts accounts = getUserAccountsForCaller();
final RegisteredServicesCache.ServiceInfo<AuthenticatorDescription> authenticatorInfo;
@@ -1294,11 +1320,6 @@
final boolean customTokens =
authenticatorInfo != null && authenticatorInfo.type.customTokens;
- // Check to see that the app is authorized to access the account, in case it's a
- // restricted account.
- if (!ArrayUtils.contains(getAccounts((String) null), account)) {
- throw new IllegalArgumentException("no such account");
- }
// skip the check if customTokens
final int callerUid = Binder.getCallingUid();
final boolean permissionGranted = customTokens ||
@@ -1472,6 +1493,7 @@
return id;
}
+ @Override
public void addAccount(final IAccountManagerResponse response, final String accountType,
final String authTokenType, final String[] requiredFeatures,
final boolean expectActivityLaunch, final Bundle optionsIn) {
@@ -1582,6 +1604,7 @@
}
}
+ @Override
public void updateCredentials(IAccountManagerResponse response, final Account account,
final String authTokenType, final boolean expectActivityLaunch,
final Bundle loginOptions) {
@@ -1620,6 +1643,7 @@
}
}
+ @Override
public void editProperties(IAccountManagerResponse response, final String accountType,
final boolean expectActivityLaunch) {
if (Log.isLoggable(TAG, Log.VERBOSE)) {
@@ -1657,7 +1681,7 @@
private volatile Account[] mAccountsOfType = null;
private volatile ArrayList<Account> mAccountsWithFeatures = null;
private volatile int mCurrentAccount = 0;
- private int mCallingUid;
+ private final int mCallingUid;
public GetAccountsByTypeAndFeatureSession(UserAccounts accounts,
IAccountManagerResponse response, String type, String[] features, int callingUid) {
@@ -1941,6 +1965,7 @@
return getAccountsAsUser(type, UserHandle.getCallingUserId(), packageName, packageUid);
}
+ @Override
public void getAccountsByFeatures(IAccountManagerResponse response,
String type, String[] features) {
if (Log.isLoggable(TAG, Log.VERBOSE)) {
@@ -2069,6 +2094,7 @@
unbind();
}
+ @Override
public void binderDied() {
mResponse = null;
close();
@@ -2112,6 +2138,7 @@
mMessageHandler.removeMessages(MESSAGE_TIMED_OUT, this);
}
+ @Override
public void onServiceConnected(ComponentName name, IBinder service) {
mAuthenticator = IAccountAuthenticator.Stub.asInterface(service);
try {
@@ -2122,6 +2149,7 @@
}
}
+ @Override
public void onServiceDisconnected(ComponentName name) {
mAuthenticator = null;
IAccountManagerResponse response = getResponseAndClose();
@@ -2217,7 +2245,14 @@
Log.v(TAG, getClass().getSimpleName()
+ " calling onResult() on response " + response);
}
- response.onResult(result);
+ if ((result.getInt(AccountManager.KEY_ERROR_CODE, -1) > 0) &&
+ (intent == null)) {
+ // All AccountManager error codes are greater than 0
+ response.onError(result.getInt(AccountManager.KEY_ERROR_CODE),
+ result.getString(AccountManager.KEY_ERROR_MESSAGE));
+ } else {
+ response.onResult(result);
+ }
}
} catch (RemoteException e) {
// if the caller is dead then there is no one to care about remote exceptions
@@ -2228,10 +2263,12 @@
}
}
+ @Override
public void onRequestContinued() {
mNumRequestContinued++;
}
+ @Override
public void onError(int errorCode, String errorMessage) {
mNumErrors++;
IAccountManagerResponse response = getResponseAndClose();
@@ -2731,6 +2768,7 @@
return true;
}
+ @Override
public void updateAppPermission(Account account, String authTokenType, int uid, boolean value)
throws RemoteException {
final int callingUid = getCallingUid();
diff --git a/services/java/com/android/server/am/ActiveServices.java b/services/java/com/android/server/am/ActiveServices.java
index ea0b978a..933247e 100644
--- a/services/java/com/android/server/am/ActiveServices.java
+++ b/services/java/com/android/server/am/ActiveServices.java
@@ -307,7 +307,7 @@
ServiceRecord r = res.record;
NeededUriGrants neededGrants = mAm.checkGrantUriPermissionFromIntentLocked(
callingUid, r.packageName, service, service.getFlags(), null);
- if (unscheduleServiceRestartLocked(r, callingUid)) {
+ if (unscheduleServiceRestartLocked(r, callingUid, false)) {
if (DEBUG_SERVICE) Slog.v(TAG, "START SERVICE WHILE RESTART PENDING: " + r);
}
r.lastActivity = SystemClock.uptimeMillis();
@@ -701,7 +701,7 @@
final long origId = Binder.clearCallingIdentity();
try {
- if (unscheduleServiceRestartLocked(s, callerApp.info.uid)) {
+ if (unscheduleServiceRestartLocked(s, callerApp.info.uid, false)) {
if (DEBUG_SERVICE) Slog.v(TAG, "BIND SERVICE WHILE RESTART PENDING: "
+ s);
}
@@ -1002,14 +1002,11 @@
smap.mServicesByIntent.put(filter, r);
// Make sure this component isn't in the pending list.
- int N = mPendingServices.size();
- for (int i=0; i<N; i++) {
+ for (int i=mPendingServices.size()-1; i>=0; i--) {
ServiceRecord pr = mPendingServices.get(i);
if (pr.serviceInfo.applicationInfo.uid == sInfo.applicationInfo.uid
&& pr.name.equals(name)) {
mPendingServices.remove(i);
- i--;
- N--;
}
}
}
@@ -1101,6 +1098,14 @@
boolean allowCancel) {
boolean canceled = false;
+ ServiceMap smap = getServiceMap(r.userId);
+ if (smap.mServicesByName.get(r.name) != r) {
+ ServiceRecord cur = smap.mServicesByName.get(r.name);
+ Slog.wtf(TAG, "Attempting to schedule restart of " + r
+ + " when found in map: " + cur);
+ return false;
+ }
+
final long now = SystemClock.uptimeMillis();
if ((r.serviceInfo.applicationInfo.flags
@@ -1187,6 +1192,7 @@
if (!mRestartingServices.contains(r)) {
r.createdFromFg = false;
mRestartingServices.add(r);
+ r.makeRestarting(mAm.mProcessStats.getMemFactorLocked(), now);
}
r.cancelNotification();
@@ -1209,8 +1215,9 @@
bringUpServiceLocked(r, r.intent.getIntent().getFlags(), r.createdFromFg, true);
}
- private final boolean unscheduleServiceRestartLocked(ServiceRecord r, int callingUid) {
- if (r.restartDelay == 0) {
+ private final boolean unscheduleServiceRestartLocked(ServiceRecord r, int callingUid,
+ boolean force) {
+ if (!force && r.restartDelay == 0) {
return false;
}
// Remove from the restarting list; if the service is currently on the
@@ -1220,10 +1227,32 @@
if (removed || callingUid != r.appInfo.uid) {
r.resetRestartCounter();
}
+ if (removed) {
+ clearRestartingIfNeededLocked(r);
+ }
mAm.mHandler.removeCallbacks(r.restarter);
return true;
}
+ private void clearRestartingIfNeededLocked(ServiceRecord r) {
+ if (r.restartTracker != null) {
+ // If this is the last restarting record with this tracker, then clear
+ // the tracker's restarting state.
+ boolean stillTracking = false;
+ for (int i=mRestartingServices.size()-1; i>=0; i--) {
+ if (mRestartingServices.get(i).restartTracker == r.restartTracker) {
+ stillTracking = true;
+ break;
+ }
+ }
+ if (!stillTracking) {
+ r.restartTracker.setRestarting(false, mAm.mProcessStats.getMemFactorLocked(),
+ SystemClock.uptimeMillis());
+ r.restartTracker = null;
+ }
+ }
+ }
+
private final String bringUpServiceLocked(ServiceRecord r,
int intentFlags, boolean execInFg, boolean whileRestarting) {
//Slog.i(TAG, "Bring up service:");
@@ -1243,7 +1272,9 @@
// We are now bringing the service up, so no longer in the
// restarting state.
- mRestartingServices.remove(r);
+ if (mRestartingServices.remove(r)) {
+ clearRestartingIfNeededLocked(r);
+ }
// Make sure this service is no longer considered delayed, we are starting it now.
if (r.delayed) {
@@ -1383,6 +1414,7 @@
} finally {
if (!created) {
app.services.remove(r);
+ r.app = null;
scheduleServiceRestartLocked(r, false);
}
}
@@ -1553,16 +1585,13 @@
smap.mServicesByName.remove(r.name);
smap.mServicesByIntent.remove(r.intent);
r.totalRestartCount = 0;
- unscheduleServiceRestartLocked(r, 0);
+ unscheduleServiceRestartLocked(r, 0, true);
// Also make sure it is not on the pending list.
- int N = mPendingServices.size();
- for (int i=0; i<N; i++) {
+ for (int i=mPendingServices.size()-1; i>=0; i--) {
if (mPendingServices.get(i) == r) {
mPendingServices.remove(i);
if (DEBUG_SERVICE) Slog.v(TAG, "Removed pending: " + r);
- i--;
- N--;
}
}
@@ -1581,6 +1610,7 @@
}
r.app.services.remove(r);
if (r.app.thread != null) {
+ updateServiceForegroundLocked(r.app, false);
try {
bumpServiceExecutingLocked(r, false, "destroy");
mDestroyingServices.add(r);
@@ -1591,7 +1621,6 @@
+ r.shortName, e);
serviceProcessGoneLocked(r);
}
- updateServiceForegroundLocked(r.app, false);
} else {
if (DEBUG_SERVICE) Slog.v(
TAG, "Removed service that has no process: " + r);
@@ -1769,6 +1798,7 @@
long now = SystemClock.uptimeMillis();
r.tracker.setExecuting(false, memFactor, now);
r.tracker.setBound(false, memFactor, now);
+ r.tracker.setStarted(false, memFactor, now);
}
serviceDoneExecutingLocked(r, true, true);
}
@@ -1816,6 +1846,12 @@
r.tracker = null;
}
}
+ if (finishing) {
+ if (r.app != null) {
+ r.app.services.remove(r);
+ }
+ r.app = null;
+ }
}
}
@@ -1894,6 +1930,7 @@
Slog.i(TAG, " Force stopping service " + service);
if (service.app != null) {
service.app.removed = true;
+ service.app.services.remove(service);
}
service.app = null;
service.isolatedProc = null;
@@ -1960,8 +1997,7 @@
}
}
- final void killServicesLocked(ProcessRecord app,
- boolean allowRestart) {
+ final void killServicesLocked(ProcessRecord app, boolean allowRestart) {
// Report disconnected services.
if (false) {
// XXX we are letting the client link to the service for
@@ -1990,20 +2026,15 @@
}
}
- // Clean up any connections this application has to other services.
- for (int i=app.connections.size()-1; i>=0; i--) {
- ConnectionRecord r = app.connections.valueAt(i);
- removeConnectionLocked(r, app, null);
- }
- app.connections.clear();
-
+ // First clear app state from services.
for (int i=app.services.size()-1; i>=0; i--) {
- // Any services running in the application need to be placed
- // back in the pending list.
ServiceRecord sr = app.services.valueAt(i);
synchronized (sr.stats.getBatteryStats()) {
sr.stats.stopLaunchedLocked();
}
+ if (sr.app != null) {
+ sr.app.services.remove(sr);
+ }
sr.app = null;
sr.isolatedProc = null;
sr.executeNesting = 0;
@@ -2020,8 +2051,33 @@
b.binder = null;
b.requested = b.received = b.hasBound = false;
}
+ }
- if (sr.crashCount >= 2 && (sr.serviceInfo.applicationInfo.flags
+ // Clean up any connections this application has to other services.
+ for (int i=app.connections.size()-1; i>=0; i--) {
+ ConnectionRecord r = app.connections.valueAt(i);
+ removeConnectionLocked(r, app, null);
+ }
+ app.connections.clear();
+
+ ServiceMap smap = getServiceMap(app.userId);
+
+ // Now do remaining service cleanup.
+ for (int i=app.services.size()-1; i>=0; i--) {
+ ServiceRecord sr = app.services.valueAt(i);
+ // Sanity check: if the service listed for the app is not one
+ // we actually are maintaining, drop it.
+ if (smap.mServicesByName.get(sr.name) != sr) {
+ ServiceRecord cur = smap.mServicesByName.get(sr.name);
+ Slog.wtf(TAG, "Service " + sr + " in process " + app
+ + " not same as in map: " + cur);
+ app.services.removeAt(i);
+ continue;
+ }
+
+ // Any services running in the application may need to be placed
+ // back in the pending list.
+ if (allowRestart && sr.crashCount >= 2 && (sr.serviceInfo.applicationInfo.flags
&ApplicationInfo.FLAG_PERSISTENT) == 0) {
Slog.w(TAG, "Service crashed " + sr.crashCount
+ " times, stopping: " + sr);
@@ -2054,6 +2110,23 @@
if (!allowRestart) {
app.services.clear();
+
+ // Make sure there are no more restarting services for this process.
+ for (int i=mRestartingServices.size()-1; i>=0; i--) {
+ ServiceRecord r = mRestartingServices.get(i);
+ if (r.processName.equals(app.processName) &&
+ r.serviceInfo.applicationInfo.uid == app.info.uid) {
+ mRestartingServices.remove(i);
+ clearRestartingIfNeededLocked(r);
+ }
+ }
+ for (int i=mPendingServices.size()-1; i>=0; i--) {
+ ServiceRecord r = mPendingServices.get(i);
+ if (r.processName.equals(app.processName) &&
+ r.serviceInfo.applicationInfo.uid == app.info.uid) {
+ mPendingServices.remove(i);
+ }
+ }
}
// Make sure we have no more records on the stopping list.
diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java
index 164e7b7..9201b1d 100644
--- a/services/java/com/android/server/am/ActivityManagerService.java
+++ b/services/java/com/android/server/am/ActivityManagerService.java
@@ -2149,7 +2149,8 @@
totalUTime += otherUTime;
totalSTime += otherSTime;
if (pr != null) {
- BatteryStatsImpl.Uid.Proc ps = pr.batteryStats;
+ BatteryStatsImpl.Uid.Proc ps = bstats.getProcessStatsLocked(
+ st.name, st.pid);
ps.addCpuTimeLocked(st.rel_utime-otherUTime,
st.rel_stime-otherSTime);
ps.addSpeedStepTimes(cpuSpeedTimes);
@@ -2769,10 +2770,10 @@
app.processName, uid, uid, gids, debugFlags, mountExternal,
app.info.targetSdkVersion, app.info.seinfo, null);
- BatteryStatsImpl bs = app.batteryStats.getBatteryStats();
+ BatteryStatsImpl bs = mBatteryStatsService.getActiveStatistics();
synchronized (bs) {
if (bs.isOnBattery()) {
- app.batteryStats.incStartsLocked();
+ bs.getProcessStatsLocked(app.uid, app.processName).incStartsLocked();
}
}
@@ -8150,10 +8151,7 @@
}
}
}
- synchronized (stats) {
- ps = stats.getProcessStatsLocked(info.uid, proc);
- }
- return new ProcessRecord(ps, info, proc, uid);
+ return new ProcessRecord(stats, info, proc, uid);
}
final ProcessRecord addAppLocked(ApplicationInfo info, boolean isolated) {
@@ -11901,6 +11899,7 @@
boolean dumpDalvik = false;
boolean oomOnly = false;
boolean isCompact = false;
+ boolean localOnly = false;
int opti = 0;
while (opti < args.length) {
@@ -11919,12 +11918,15 @@
isCompact = true;
} else if ("--oom".equals(opt)) {
oomOnly = true;
+ } else if ("--local".equals(opt)) {
+ localOnly = true;
} else if ("-h".equals(opt)) {
pw.println("meminfo dump options: [-a] [-d] [-c] [--oom] [process]");
pw.println(" -a: include all available information for each process.");
pw.println(" -d: include dalvik details when dumping process details.");
pw.println(" -c: dump in a compact machine-parseable representation.");
pw.println(" --oom: only show processes organized by oom adj.");
+ pw.println(" --local: only collect details locally, don't call process.");
pw.println("If [process] is specified it can be the name or ");
pw.println("pid of a specific process to dump.");
return;
@@ -12041,14 +12043,22 @@
mi.dalvikPrivateDirty = (int)tmpLong[0];
}
if (dumpDetails) {
- try {
- pw.flush();
- thread.dumpMemInfo(fd, mi, isCheckinRequest, dumpFullDetails,
- dumpDalvik, innerArgs);
- } catch (RemoteException e) {
- if (!isCheckinRequest) {
- pw.println("Got RemoteException!");
+ if (localOnly) {
+ ActivityThread.dumpMemInfoTable(pw, mi, isCheckinRequest, dumpFullDetails,
+ dumpDalvik, pid, r.processName, 0, 0, 0, 0, 0, 0);
+ if (isCheckinRequest) {
+ pw.println();
+ }
+ } else {
+ try {
pw.flush();
+ thread.dumpMemInfo(fd, mi, isCheckinRequest, dumpFullDetails,
+ dumpDalvik, innerArgs);
+ } catch (RemoteException e) {
+ if (!isCheckinRequest) {
+ pw.println("Got RemoteException!");
+ pw.flush();
+ }
}
}
}
diff --git a/services/java/com/android/server/am/ActivityStack.java b/services/java/com/android/server/am/ActivityStack.java
index 809452c..0e152611 100644
--- a/services/java/com/android/server/am/ActivityStack.java
+++ b/services/java/com/android/server/am/ActivityStack.java
@@ -36,7 +36,6 @@
import static com.android.server.am.ActivityStackSupervisor.DEBUG_STATES;
import static com.android.server.am.ActivityStackSupervisor.HOME_STACK_ID;
-import android.os.Trace;
import com.android.internal.os.BatteryStatsImpl;
import com.android.internal.util.Objects;
import com.android.server.Watchdog;
@@ -64,12 +63,14 @@
import android.net.Uri;
import android.os.Binder;
import android.os.Bundle;
+import android.os.Debug;
import android.os.Handler;
import android.os.IBinder;
import android.os.Looper;
import android.os.Message;
import android.os.RemoteException;
import android.os.SystemClock;
+import android.os.Trace;
import android.os.UserHandle;
import android.util.EventLog;
import android.util.Slog;
@@ -1143,7 +1144,7 @@
} else if (isActivityOverHome(r)) {
if (DEBUG_VISBILITY) Slog.v(TAG, "Showing home: at " + r);
showHomeBehindStack = true;
- behindFullscreen = true;
+ behindFullscreen = !isHomeStack();
}
} else {
if (DEBUG_VISBILITY) Slog.v(
@@ -1716,7 +1717,7 @@
mWindowManager.addAppToken(task.mActivities.indexOf(r), r.appToken,
r.task.taskId, mStackId, r.info.screenOrientation, r.fullscreen,
(r.info.flags & ActivityInfo.FLAG_SHOW_ON_LOCK_SCREEN) != 0,
- r.userId);
+ r.userId, r.info.configChanges);
if (VALIDATE_TOKENS) {
validateAppTokensLocked();
}
@@ -1777,7 +1778,8 @@
r.updateOptionsLocked(options);
mWindowManager.addAppToken(task.mActivities.indexOf(r),
r.appToken, r.task.taskId, mStackId, r.info.screenOrientation, r.fullscreen,
- (r.info.flags & ActivityInfo.FLAG_SHOW_ON_LOCK_SCREEN) != 0, r.userId);
+ (r.info.flags & ActivityInfo.FLAG_SHOW_ON_LOCK_SCREEN) != 0, r.userId,
+ r.info.configChanges);
boolean doShow = true;
if (newTask) {
// Even though this activity is starting fresh, we still need
@@ -1820,7 +1822,8 @@
// because there is nothing for it to animate on top of.
mWindowManager.addAppToken(task.mActivities.indexOf(r), r.appToken,
r.task.taskId, mStackId, r.info.screenOrientation, r.fullscreen,
- (r.info.flags & ActivityInfo.FLAG_SHOW_ON_LOCK_SCREEN) != 0, r.userId);
+ (r.info.flags & ActivityInfo.FLAG_SHOW_ON_LOCK_SCREEN) != 0, r.userId,
+ r.info.configChanges);
ActivityOptions.abort(options);
}
if (VALIDATE_TOKENS) {
@@ -1910,26 +1913,38 @@
// bottom of the activity stack. This also keeps it
// correctly ordered with any activities we previously
// moved.
+ final ThumbnailHolder newThumbHolder;
+ final TaskRecord targetTask;
final ActivityRecord bottom =
!mTaskHistory.isEmpty() && !mTaskHistory.get(0).mActivities.isEmpty() ?
- mTaskHistory.get(0).mActivities.get(0) : null;
+ mTaskHistory.get(0).mActivities.get(0) : null;
if (bottom != null && target.taskAffinity != null
&& target.taskAffinity.equals(bottom.task.affinity)) {
// If the activity currently at the bottom has the
// same task affinity as the one we are moving,
// then merge it into the same task.
- target.setTask(bottom.task, bottom.thumbHolder, false);
+ targetTask = bottom.task;
+ newThumbHolder = bottom.thumbHolder == null ? targetTask : bottom.thumbHolder;
if (DEBUG_TASKS) Slog.v(TAG, "Start pushing activity " + target
+ " out to bottom task " + bottom.task);
} else {
- target.setTask(createTaskRecord(mStackSupervisor.getNextTaskId(), target.info,
- null, false), null, false);
- target.task.affinityIntent = target.intent;
+ targetTask = createTaskRecord(mStackSupervisor.getNextTaskId(), target.info,
+ null, false);
+ newThumbHolder = targetTask;
+ targetTask.affinityIntent = target.intent;
if (DEBUG_TASKS) Slog.v(TAG, "Start pushing activity " + target
+ " out to new task " + target.task);
}
- final TaskRecord targetTask = target.task;
+ if (clearWhenTaskReset) {
+ // This is the start of a new sub-task.
+ if (target.thumbHolder == null) {
+ target.thumbHolder = new ThumbnailHolder();
+ }
+ } else {
+ target.thumbHolder = newThumbHolder;
+ }
+
final int targetTaskId = targetTask.taskId;
mWindowManager.setAppGroupId(target.appToken, targetTaskId);
@@ -1950,8 +1965,8 @@
}
}
if (DEBUG_ADD_REMOVE) Slog.i(TAG, "Removing activity " + p + " from task="
- + task + " adding to task=" + targetTask,
- new RuntimeException("here").fillInStackTrace());
+ + task + " adding to task=" + targetTask
+ + " Callers=" + Debug.getCallers(4));
if (DEBUG_TASKS) Slog.v(TAG, "Pushing next activity " + p
+ " out to target's task " + target.task);
p.setTask(targetTask, curThumbHolder, false);
@@ -3145,7 +3160,9 @@
final TaskRecord task = mResumedActivity != null ? mResumedActivity.task : null;
if (task == tr && task.mOnTopOfHome || numTasks <= 1) {
- task.mOnTopOfHome = false;
+ if (task != null) {
+ task.mOnTopOfHome = false;
+ }
return mStackSupervisor.resumeHomeActivity(null);
}
diff --git a/services/java/com/android/server/am/ActivityStackSupervisor.java b/services/java/com/android/server/am/ActivityStackSupervisor.java
index 8251364..483b4a0 100644
--- a/services/java/com/android/server/am/ActivityStackSupervisor.java
+++ b/services/java/com/android/server/am/ActivityStackSupervisor.java
@@ -1386,17 +1386,22 @@
launchFlags |= Intent.FLAG_ACTIVITY_NEW_TASK;
}
+ ActivityInfo newTaskInfo = null;
+ Intent newTaskIntent = null;
final ActivityStack sourceStack;
if (sourceRecord != null) {
if (sourceRecord.finishing) {
// If the source is finishing, we can't further count it as our source. This
// is because the task it is associated with may now be empty and on its way out,
// so we don't want to blindly throw it in to that task. Instead we will take
- // the NEW_TASK flow and try to find a task for it.
+ // the NEW_TASK flow and try to find a task for it. But save the task information
+ // so it can be used when creating the new task.
if ((launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) == 0) {
Slog.w(TAG, "startActivity called from finishing " + sourceRecord
+ "; forcing " + "Intent.FLAG_ACTIVITY_NEW_TASK for: " + intent);
launchFlags |= Intent.FLAG_ACTIVITY_NEW_TASK;
+ newTaskInfo = sourceRecord.info;
+ newTaskIntent = sourceRecord.task.intent;
}
sourceRecord = null;
sourceStack = null;
@@ -1668,8 +1673,10 @@
targetStack = adjustStackFocus(r);
moveHomeStack(targetStack.isHomeStack());
if (reuseTask == null) {
- r.setTask(targetStack.createTaskRecord(getNextTaskId(), r.info, intent, true),
- null, true);
+ r.setTask(targetStack.createTaskRecord(getNextTaskId(),
+ newTaskInfo != null ? newTaskInfo : r.info,
+ newTaskIntent != null ? newTaskIntent : intent,
+ true), null, true);
if (DEBUG_TASKS) Slog.v(TAG, "Starting new activity " + r + " in new task " +
r.task);
} else {
diff --git a/services/java/com/android/server/am/BatteryStatsService.java b/services/java/com/android/server/am/BatteryStatsService.java
index 0dd950e..2d59678 100644
--- a/services/java/com/android/server/am/BatteryStatsService.java
+++ b/services/java/com/android/server/am/BatteryStatsService.java
@@ -419,6 +419,20 @@
}
}
+ public void noteWifiBatchedScanStartedFromSource(WorkSource ws, int csph) {
+ enforceCallingPermission();
+ synchronized (mStats) {
+ mStats.noteWifiBatchedScanStartedFromSourceLocked(ws, csph);
+ }
+ }
+
+ public void noteWifiBatchedScanStoppedFromSource(WorkSource ws) {
+ enforceCallingPermission();
+ synchronized (mStats) {
+ mStats.noteWifiBatchedScanStoppedFromSourceLocked(ws);
+ }
+ }
+
public void noteWifiMulticastEnabledFromSource(WorkSource ws) {
enforceCallingPermission();
synchronized (mStats) {
diff --git a/services/java/com/android/server/am/BroadcastQueue.java b/services/java/com/android/server/am/BroadcastQueue.java
index dd3d8aa..bfb667f 100644
--- a/services/java/com/android/server/am/BroadcastQueue.java
+++ b/services/java/com/android/server/am/BroadcastQueue.java
@@ -27,6 +27,7 @@
import android.content.IIntentReceiver;
import android.content.Intent;
import android.content.pm.ActivityInfo;
+import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.os.Bundle;
@@ -814,6 +815,26 @@
+ " to " + r.curApp + ": process crashing");
skip = true;
}
+ if (!skip) {
+ boolean isAvailable = false;
+ try {
+ isAvailable = AppGlobals.getPackageManager().isPackageAvailable(
+ info.activityInfo.packageName,
+ UserHandle.getUserId(info.activityInfo.applicationInfo.uid));
+ } catch (Exception e) {
+ // all such failures mean we skip this receiver
+ Slog.w(TAG, "Exception getting recipient info for "
+ + info.activityInfo.packageName, e);
+ }
+ if (!isAvailable) {
+ if (DEBUG_BROADCAST) {
+ Slog.v(TAG, "Skipping delivery to " + info.activityInfo.packageName
+ + " / " + info.activityInfo.applicationInfo.uid
+ + " : package no longer available");
+ }
+ skip = true;
+ }
+ }
if (skip) {
if (DEBUG_BROADCAST) Slog.v(TAG,
diff --git a/services/java/com/android/server/am/ConnectionRecord.java b/services/java/com/android/server/am/ConnectionRecord.java
index 576adc2..423e540 100644
--- a/services/java/com/android/server/am/ConnectionRecord.java
+++ b/services/java/com/android/server/am/ConnectionRecord.java
@@ -27,7 +27,7 @@
*/
final class ConnectionRecord {
final AppBindRecord binding; // The application/service binding.
- final ActivityRecord activity; // If non-null, the owning activity.
+ final ActivityRecord activity; // If non-null, the owning activity.
final IServiceConnection conn; // The client connection.
final int flags; // Binding options.
final int clientLabel; // String resource labeling this client.
diff --git a/services/java/com/android/server/am/ProcessRecord.java b/services/java/com/android/server/am/ProcessRecord.java
index 187cd44..217a8d61 100644
--- a/services/java/com/android/server/am/ProcessRecord.java
+++ b/services/java/com/android/server/am/ProcessRecord.java
@@ -46,7 +46,7 @@
* is currently running.
*/
final class ProcessRecord {
- final BatteryStatsImpl.Uid.Proc batteryStats; // where to collect runtime statistics
+ private final BatteryStatsImpl mBatteryStats; // where to collect runtime statistics
final ApplicationInfo info; // all about the first app in the process
final boolean isolated; // true if this is a special isolated process
final int uid; // uid of process; may be different from 'info' if isolated
@@ -273,8 +273,8 @@
}
if (!keeping) {
long wtime;
- synchronized (batteryStats.getBatteryStats()) {
- wtime = batteryStats.getBatteryStats().getProcessWakeTime(info.uid,
+ synchronized (mBatteryStats) {
+ wtime = mBatteryStats.getProcessWakeTime(info.uid,
pid, SystemClock.elapsedRealtime());
}
long timeUsed = wtime - lastWakeTime;
@@ -359,9 +359,9 @@
}
}
- ProcessRecord(BatteryStatsImpl.Uid.Proc _batteryStats, ApplicationInfo _info,
+ ProcessRecord(BatteryStatsImpl _batteryStats, ApplicationInfo _info,
String _processName, int _uid) {
- batteryStats = _batteryStats;
+ mBatteryStats = _batteryStats;
info = _info;
isolated = _info.uid != _uid;
uid = _uid;
diff --git a/services/java/com/android/server/am/ProcessStatsService.java b/services/java/com/android/server/am/ProcessStatsService.java
index 8d16880..e05fcda 100644
--- a/services/java/com/android/server/am/ProcessStatsService.java
+++ b/services/java/com/android/server/am/ProcessStatsService.java
@@ -750,23 +750,12 @@
return;
} else {
// Not an option, last argument must be a package name.
- try {
- IPackageManager pm = AppGlobals.getPackageManager();
- if (pm.getPackageUid(arg, UserHandle.getCallingUserId()) >= 0) {
- reqPackage = arg;
- // Include all details, since we know we are only going to
- // be dumping a smaller set of data. In fact only the details
- // container per-package data, so that are needed to be able
- // to dump anything at all when filtering by package.
- dumpDetails = true;
- }
- } catch (RemoteException e) {
- }
- if (reqPackage == null) {
- pw.println("Unknown package: " + arg);
- dumpHelp(pw);
- return;
- }
+ reqPackage = arg;
+ // Include all details, since we know we are only going to
+ // be dumping a smaller set of data. In fact only the details
+ // container per-package data, so that are needed to be able
+ // to dump anything at all when filtering by package.
+ dumpDetails = true;
}
}
}
@@ -816,13 +805,14 @@
}
return;
} else if (aggregateHours != 0) {
+ pw.print("AGGREGATED OVER LAST "); pw.print(aggregateHours); pw.println(" HOURS:");
dumpAggregatedStats(pw, aggregateHours, now, reqPackage, isCompact,
dumpDetails, dumpFullDetails, dumpAll, activeOnly);
return;
}
boolean sepNeeded = false;
- if (!currentOnly || isCheckin) {
+ if (dumpAll || isCheckin) {
mWriteLock.lock();
try {
ArrayList<String> files = getCommittedFiles(0, false, !isCheckin);
@@ -882,11 +872,11 @@
}
}
if (!isCheckin) {
- if (dumpAll) {
+ if (!currentOnly) {
if (sepNeeded) {
pw.println();
- pw.println("AGGREGATED OVER LAST 24 HOURS:");
}
+ pw.println("AGGREGATED OVER LAST 24 HOURS:");
dumpAggregatedStats(pw, 24, now, reqPackage, isCompact,
dumpDetails, dumpFullDetails, dumpAll, activeOnly);
pw.println();
@@ -901,8 +891,8 @@
} else {
if (sepNeeded) {
pw.println();
- pw.println("CURRENT STATS:");
}
+ pw.println("CURRENT STATS:");
if (dumpDetails || dumpFullDetails) {
mProcessStats.dumpLocked(pw, reqPackage, now, !dumpFullDetails, dumpAll,
activeOnly);
diff --git a/services/java/com/android/server/am/ServiceRecord.java b/services/java/com/android/server/am/ServiceRecord.java
index cc1172a..80e6e94 100644
--- a/services/java/com/android/server/am/ServiceRecord.java
+++ b/services/java/com/android/server/am/ServiceRecord.java
@@ -85,6 +85,7 @@
ProcessRecord app; // where this service is running or null.
ProcessRecord isolatedProc; // keep track of isolated process, if requested
ProcessStats.ServiceState tracker; // tracking service execution, may be null
+ ProcessStats.ServiceState restartTracker; // tracking service restart
boolean delayed; // are we waiting to start this service in the background?
boolean isForeground; // is service currently in foreground mode?
int foregroundId; // Notification ID of last foreground req.
@@ -340,6 +341,19 @@
}
}
+ public void makeRestarting(int memFactor, long now) {
+ if (restartTracker == null) {
+ if ((serviceInfo.applicationInfo.flags&ApplicationInfo.FLAG_PERSISTENT) == 0) {
+ restartTracker = ams.mProcessStats.getServiceStateLocked(serviceInfo.packageName,
+ serviceInfo.applicationInfo.uid, serviceInfo.processName, serviceInfo.name);
+ }
+ if (restartTracker == null) {
+ return;
+ }
+ }
+ restartTracker.setRestarting(true, memFactor, now);
+ }
+
public AppBindRecord retrieveAppBindingLocked(Intent intent,
ProcessRecord app) {
Intent.FilterComparison filter = new Intent.FilterComparison(intent);
diff --git a/services/java/com/android/server/content/ContentService.java b/services/java/com/android/server/content/ContentService.java
index cb35ef1..023bf2b 100644
--- a/services/java/com/android/server/content/ContentService.java
+++ b/services/java/com/android/server/content/ContentService.java
@@ -660,7 +660,7 @@
int userId = UserHandle.getCallingUserId();
long identityToken = clearCallingIdentity();
try {
- return getSyncManager().getSyncStorageEngine().getCurrentSyncs(userId);
+ return getSyncManager().getSyncStorageEngine().getCurrentSyncsCopy(userId);
} finally {
restoreCallingIdentity(identityToken);
}
diff --git a/services/java/com/android/server/content/SyncStorageEngine.java b/services/java/com/android/server/content/SyncStorageEngine.java
index 41ef229..5ebf9ea 100644
--- a/services/java/com/android/server/content/SyncStorageEngine.java
+++ b/services/java/com/android/server/content/SyncStorageEngine.java
@@ -1295,21 +1295,41 @@
}
/**
- * Return a list of the currently active syncs. Note that the returned items are the
- * real, live active sync objects, so be careful what you do with it.
+ * Return a list of the currently active syncs. Note that the returned
+ * items are the real, live active sync objects, so be careful what you do
+ * with it.
*/
- public List<SyncInfo> getCurrentSyncs(int userId) {
+ private List<SyncInfo> getCurrentSyncs(int userId) {
synchronized (mAuthorities) {
- ArrayList<SyncInfo> syncs = mCurrentSyncs.get(userId);
- if (syncs == null) {
- syncs = new ArrayList<SyncInfo>();
- mCurrentSyncs.put(userId, syncs);
- }
- return syncs;
+ return getCurrentSyncsLocked(userId);
}
}
/**
+ * @return a copy of the current syncs data structure. Will not return
+ * null.
+ */
+ public List<SyncInfo> getCurrentSyncsCopy(int userId) {
+ synchronized (mAuthorities) {
+ final List<SyncInfo> syncs = getCurrentSyncsLocked(userId);
+ final List<SyncInfo> syncsCopy = new ArrayList<SyncInfo>();
+ for (SyncInfo sync : syncs) {
+ syncsCopy.add(new SyncInfo(sync));
+ }
+ return syncsCopy;
+ }
+ }
+
+ private List<SyncInfo> getCurrentSyncsLocked(int userId) {
+ ArrayList<SyncInfo> syncs = mCurrentSyncs.get(userId);
+ if (syncs == null) {
+ syncs = new ArrayList<SyncInfo>();
+ mCurrentSyncs.put(userId, syncs);
+ }
+ return syncs;
+ }
+
+ /**
* Return an array of the current sync status for all authorities. Note
* that the objects inside the array are the real, live status objects,
* so be careful what you do with them.
diff --git a/services/java/com/android/server/display/DisplayManagerService.java b/services/java/com/android/server/display/DisplayManagerService.java
index 249c8b0..02f26b3 100644
--- a/services/java/com/android/server/display/DisplayManagerService.java
+++ b/services/java/com/android/server/display/DisplayManagerService.java
@@ -466,6 +466,9 @@
@Override // Binder call
public void scanWifiDisplays() {
+ mContext.enforceCallingOrSelfPermission(Manifest.permission.CONFIGURE_WIFI_DISPLAY,
+ "Permission required to scan wifi displays");
+
final long token = Binder.clearCallingIdentity();
try {
synchronized (mSyncRoot) {
@@ -483,13 +486,14 @@
if (address == null) {
throw new IllegalArgumentException("address must not be null");
}
+ mContext.enforceCallingOrSelfPermission(Manifest.permission.CONFIGURE_WIFI_DISPLAY,
+ "Permission required to connect to a wifi display");
- final boolean trusted = canCallerConfigureWifiDisplay();
final long token = Binder.clearCallingIdentity();
try {
synchronized (mSyncRoot) {
if (mWifiDisplayAdapter != null) {
- mWifiDisplayAdapter.requestConnectLocked(address, trusted);
+ mWifiDisplayAdapter.requestConnectLocked(address);
}
}
} finally {
@@ -499,12 +503,8 @@
@Override
public void pauseWifiDisplay() {
- if (mContext.checkCallingPermission(
- android.Manifest.permission.CONFIGURE_WIFI_DISPLAY)
- != PackageManager.PERMISSION_GRANTED) {
- throw new SecurityException("Requires CONFIGURE_WIFI_DISPLAY"
- + "permission to pause a wifi display session.");
- }
+ mContext.enforceCallingOrSelfPermission(Manifest.permission.CONFIGURE_WIFI_DISPLAY,
+ "Permission required to pause a wifi display session");
final long token = Binder.clearCallingIdentity();
try {
@@ -520,12 +520,8 @@
@Override
public void resumeWifiDisplay() {
- if (mContext.checkCallingPermission(
- android.Manifest.permission.CONFIGURE_WIFI_DISPLAY)
- != PackageManager.PERMISSION_GRANTED) {
- throw new SecurityException("Requires CONFIGURE_WIFI_DISPLAY"
- + "permission to resume a wifi display session.");
- }
+ mContext.enforceCallingOrSelfPermission(Manifest.permission.CONFIGURE_WIFI_DISPLAY,
+ "Permission required to resume a wifi display session");
final long token = Binder.clearCallingIdentity();
try {
@@ -541,6 +537,11 @@
@Override // Binder call
public void disconnectWifiDisplay() {
+ // This request does not require special permissions.
+ // Any app can request disconnection from the currently active wifi display.
+ // This exception should no longer be needed once wifi display control moves
+ // to the media router service.
+
final long token = Binder.clearCallingIdentity();
try {
synchronized (mSyncRoot) {
@@ -558,10 +559,8 @@
if (address == null) {
throw new IllegalArgumentException("address must not be null");
}
- if (!canCallerConfigureWifiDisplay()) {
- throw new SecurityException("Requires CONFIGURE_WIFI_DISPLAY permission to "
- + "rename a wifi display.");
- }
+ mContext.enforceCallingOrSelfPermission(Manifest.permission.CONFIGURE_WIFI_DISPLAY,
+ "Permission required to rename to a wifi display");
final long token = Binder.clearCallingIdentity();
try {
@@ -580,10 +579,8 @@
if (address == null) {
throw new IllegalArgumentException("address must not be null");
}
- if (!canCallerConfigureWifiDisplay()) {
- throw new SecurityException("Requires CONFIGURE_WIFI_DISPLAY permission to "
- + "forget a wifi display.");
- }
+ mContext.enforceCallingOrSelfPermission(Manifest.permission.CONFIGURE_WIFI_DISPLAY,
+ "Permission required to forget to a wifi display");
final long token = Binder.clearCallingIdentity();
try {
@@ -599,6 +596,9 @@
@Override // Binder call
public WifiDisplayStatus getWifiDisplayStatus() {
+ // This request does not require special permissions.
+ // Any app can get information about available wifi displays.
+
final long token = Binder.clearCallingIdentity();
try {
synchronized (mSyncRoot) {
@@ -612,11 +612,6 @@
}
}
- private boolean canCallerConfigureWifiDisplay() {
- return mContext.checkCallingPermission(android.Manifest.permission.CONFIGURE_WIFI_DISPLAY)
- == PackageManager.PERMISSION_GRANTED;
- }
-
@Override // Binder call
public int createVirtualDisplay(IBinder appToken, String packageName,
String name, int width, int height, int densityDpi, Surface surface, int flags) {
diff --git a/services/java/com/android/server/display/WifiDisplayAdapter.java b/services/java/com/android/server/display/WifiDisplayAdapter.java
index f7bbdf8..fdef039 100644
--- a/services/java/com/android/server/display/WifiDisplayAdapter.java
+++ b/services/java/com/android/server/display/WifiDisplayAdapter.java
@@ -172,19 +172,9 @@
});
}
- public void requestConnectLocked(final String address, final boolean trusted) {
+ public void requestConnectLocked(final String address) {
if (DEBUG) {
- Slog.d(TAG, "requestConnectLocked: address=" + address + ", trusted=" + trusted);
- }
-
- if (!trusted) {
- synchronized (getSyncRoot()) {
- if (!isRememberedDisplayLocked(address)) {
- Slog.w(TAG, "Ignoring request by an untrusted client to connect to "
- + "an unknown wifi display: " + address);
- return;
- }
- }
+ Slog.d(TAG, "requestConnectLocked: address=" + address);
}
getHandler().post(new Runnable() {
@@ -400,8 +390,6 @@
mDisplayDevice = new WifiDisplayDevice(displayToken, name, width, height,
refreshRate, deviceFlags, address, surface);
sendDisplayDeviceEventLocked(mDisplayDevice, DISPLAY_DEVICE_EVENT_ADDED);
-
- scheduleUpdateNotificationLocked();
}
private void removeDisplayDeviceLocked() {
@@ -409,8 +397,6 @@
mDisplayDevice.destroyLocked();
sendDisplayDeviceEventLocked(mDisplayDevice, DISPLAY_DEVICE_EVENT_REMOVED);
mDisplayDevice = null;
-
- scheduleUpdateNotificationLocked();
}
}
@@ -457,21 +443,24 @@
// Runs on the handler.
private void handleUpdateNotification() {
- final boolean isConnected;
+ final int state;
+ final WifiDisplay display;
synchronized (getSyncRoot()) {
if (!mPendingNotificationUpdate) {
return;
}
mPendingNotificationUpdate = false;
- isConnected = (mDisplayDevice != null);
+ state = mActiveDisplayState;
+ display = mActiveDisplay;
}
// Cancel the old notification if there is one.
mNotificationManager.cancelAsUser(null,
- R.string.wifi_display_notification_title, UserHandle.ALL);
+ R.string.wifi_display_notification_disconnect, UserHandle.ALL);
- if (isConnected) {
+ if (state == WifiDisplayStatus.DISPLAY_STATE_CONNECTING
+ || state == WifiDisplayStatus.DISPLAY_STATE_CONNECTED) {
Context context = getContext();
// Initialize pending intents for the notification outside of the lock because
@@ -493,20 +482,38 @@
// Post the notification.
Resources r = context.getResources();
- Notification notification = new Notification.Builder(context)
- .setContentTitle(r.getString(
- R.string.wifi_display_notification_title))
- .setContentText(r.getString(
- R.string.wifi_display_notification_message))
- .setContentIntent(mSettingsPendingIntent)
- .setSmallIcon(R.drawable.ic_notify_wifidisplay)
- .setOngoing(true)
- .addAction(android.R.drawable.ic_menu_close_clear_cancel,
- r.getString(R.string.wifi_display_notification_disconnect),
- mDisconnectPendingIntent)
- .build();
+ Notification notification;
+ if (state == WifiDisplayStatus.DISPLAY_STATE_CONNECTING) {
+ notification = new Notification.Builder(context)
+ .setContentTitle(r.getString(
+ R.string.wifi_display_notification_connecting_title))
+ .setContentText(r.getString(
+ R.string.wifi_display_notification_connecting_message,
+ display.getFriendlyDisplayName()))
+ .setContentIntent(mSettingsPendingIntent)
+ .setSmallIcon(R.drawable.ic_notification_cast_connecting)
+ .setOngoing(true)
+ .addAction(android.R.drawable.ic_menu_close_clear_cancel,
+ r.getString(R.string.wifi_display_notification_disconnect),
+ mDisconnectPendingIntent)
+ .build();
+ } else {
+ notification = new Notification.Builder(context)
+ .setContentTitle(r.getString(
+ R.string.wifi_display_notification_connected_title))
+ .setContentText(r.getString(
+ R.string.wifi_display_notification_connected_message,
+ display.getFriendlyDisplayName()))
+ .setContentIntent(mSettingsPendingIntent)
+ .setSmallIcon(R.drawable.ic_notification_cast_on)
+ .setOngoing(true)
+ .addAction(android.R.drawable.ic_menu_close_clear_cancel,
+ r.getString(R.string.wifi_display_notification_disconnect),
+ mDisconnectPendingIntent)
+ .build();
+ }
mNotificationManager.notifyAsUser(null,
- R.string.wifi_display_notification_title,
+ R.string.wifi_display_notification_disconnect,
notification, UserHandle.ALL);
}
}
@@ -578,6 +585,7 @@
mActiveDisplayState = WifiDisplayStatus.DISPLAY_STATE_CONNECTING;
mActiveDisplay = display;
scheduleStatusChangedBroadcastLocked();
+ scheduleUpdateNotificationLocked();
}
}
}
@@ -590,6 +598,7 @@
mActiveDisplayState = WifiDisplayStatus.DISPLAY_STATE_NOT_CONNECTED;
mActiveDisplay = null;
scheduleStatusChangedBroadcastLocked();
+ scheduleUpdateNotificationLocked();
}
}
}
@@ -607,6 +616,7 @@
mActiveDisplayState = WifiDisplayStatus.DISPLAY_STATE_CONNECTED;
mActiveDisplay = display;
scheduleStatusChangedBroadcastLocked();
+ scheduleUpdateNotificationLocked();
}
}
}
@@ -629,6 +639,7 @@
mActiveDisplay = display;
renameDisplayDeviceLocked(display.getFriendlyDisplayName());
scheduleStatusChangedBroadcastLocked();
+ scheduleUpdateNotificationLocked();
}
}
}
@@ -644,6 +655,7 @@
mActiveDisplayState = WifiDisplayStatus.DISPLAY_STATE_NOT_CONNECTED;
mActiveDisplay = null;
scheduleStatusChangedBroadcastLocked();
+ scheduleUpdateNotificationLocked();
}
}
}
diff --git a/services/java/com/android/server/display/WifiDisplayController.java b/services/java/com/android/server/display/WifiDisplayController.java
index 9a4cfb7..b2939fe 100644
--- a/services/java/com/android/server/display/WifiDisplayController.java
+++ b/services/java/com/android/server/display/WifiDisplayController.java
@@ -76,7 +76,7 @@
private static final int DEFAULT_CONTROL_PORT = 7236;
private static final int MAX_THROUGHPUT = 50;
private static final int CONNECTION_TIMEOUT_SECONDS = 60;
- private static final int RTSP_TIMEOUT_SECONDS = 15;
+ private static final int RTSP_TIMEOUT_SECONDS = 30;
private static final int RTSP_TIMEOUT_SECONDS_CERT_MODE = 120;
private static final int DISCOVER_PEERS_MAX_RETRIES = 10;
diff --git a/services/java/com/android/server/input/InputManagerService.java b/services/java/com/android/server/input/InputManagerService.java
index d749e6c..3145805 100644
--- a/services/java/com/android/server/input/InputManagerService.java
+++ b/services/java/com/android/server/input/InputManagerService.java
@@ -294,6 +294,7 @@
IntentFilter filter = new IntentFilter(Intent.ACTION_PACKAGE_ADDED);
filter.addAction(Intent.ACTION_PACKAGE_REMOVED);
filter.addAction(Intent.ACTION_PACKAGE_CHANGED);
+ filter.addAction(Intent.ACTION_PACKAGE_REPLACED);
filter.addDataScheme("package");
mContext.registerReceiver(new BroadcastReceiver() {
@Override
diff --git a/services/java/com/android/server/media/MediaRouterService.java b/services/java/com/android/server/media/MediaRouterService.java
new file mode 100644
index 0000000..a31695b
--- /dev/null
+++ b/services/java/com/android/server/media/MediaRouterService.java
@@ -0,0 +1,1423 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.media;
+
+import com.android.internal.util.Objects;
+import com.android.server.Watchdog;
+
+import android.Manifest;
+import android.app.ActivityManager;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.pm.PackageManager;
+import android.media.AudioSystem;
+import android.media.IMediaRouterClient;
+import android.media.IMediaRouterService;
+import android.media.MediaRouter;
+import android.media.MediaRouterClientState;
+import android.media.RemoteDisplayState;
+import android.media.RemoteDisplayState.RemoteDisplayInfo;
+import android.os.Binder;
+import android.os.Handler;
+import android.os.IBinder;
+import android.os.Looper;
+import android.os.Message;
+import android.os.RemoteException;
+import android.os.SystemClock;
+import android.text.TextUtils;
+import android.util.ArrayMap;
+import android.util.Log;
+import android.util.Slog;
+import android.util.SparseArray;
+import android.util.TimeUtils;
+
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+/**
+ * Provides a mechanism for discovering media routes and manages media playback
+ * behalf of applications.
+ * <p>
+ * Currently supports discovering remote displays via remote display provider
+ * services that have been registered by applications.
+ * </p>
+ */
+public final class MediaRouterService extends IMediaRouterService.Stub
+ implements Watchdog.Monitor {
+ private static final String TAG = "MediaRouterService";
+ private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
+
+ /**
+ * Timeout in milliseconds for a selected route to transition from a
+ * disconnected state to a connecting state. If we don't observe any
+ * progress within this interval, then we will give up and unselect the route.
+ */
+ static final long CONNECTING_TIMEOUT = 5000;
+
+ /**
+ * Timeout in milliseconds for a selected route to transition from a
+ * connecting state to a connected state. If we don't observe any
+ * progress within this interval, then we will give up and unselect the route.
+ */
+ static final long CONNECTED_TIMEOUT = 60000;
+
+ private final Context mContext;
+
+ // State guarded by mLock.
+ private final Object mLock = new Object();
+ private final SparseArray<UserRecord> mUserRecords = new SparseArray<UserRecord>();
+ private final ArrayMap<IBinder, ClientRecord> mAllClientRecords =
+ new ArrayMap<IBinder, ClientRecord>();
+ private int mCurrentUserId = -1;
+
+ public MediaRouterService(Context context) {
+ mContext = context;
+ Watchdog.getInstance().addMonitor(this);
+ }
+
+ public void systemRunning() {
+ IntentFilter filter = new IntentFilter(Intent.ACTION_USER_SWITCHED);
+ mContext.registerReceiver(new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ if (intent.getAction().equals(Intent.ACTION_USER_SWITCHED)) {
+ switchUser();
+ }
+ }
+ }, filter);
+
+ switchUser();
+ }
+
+ @Override
+ public void monitor() {
+ synchronized (mLock) { /* check for deadlock */ }
+ }
+
+ // Binder call
+ @Override
+ public void registerClientAsUser(IMediaRouterClient client, String packageName, int userId) {
+ if (client == null) {
+ throw new IllegalArgumentException("client must not be null");
+ }
+
+ final int uid = Binder.getCallingUid();
+ if (!validatePackageName(uid, packageName)) {
+ throw new SecurityException("packageName must match the calling uid");
+ }
+
+ final int pid = Binder.getCallingPid();
+ final int resolvedUserId = ActivityManager.handleIncomingUser(pid, uid, userId,
+ false /*allowAll*/, true /*requireFull*/, "registerClientAsUser", packageName);
+ final boolean trusted = mContext.checkCallingOrSelfPermission(
+ android.Manifest.permission.CONFIGURE_WIFI_DISPLAY) ==
+ PackageManager.PERMISSION_GRANTED;
+ final long token = Binder.clearCallingIdentity();
+ try {
+ synchronized (mLock) {
+ registerClientLocked(client, pid, packageName, resolvedUserId, trusted);
+ }
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
+ }
+
+ // Binder call
+ @Override
+ public void unregisterClient(IMediaRouterClient client) {
+ if (client == null) {
+ throw new IllegalArgumentException("client must not be null");
+ }
+
+ final long token = Binder.clearCallingIdentity();
+ try {
+ synchronized (mLock) {
+ unregisterClientLocked(client, false);
+ }
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
+ }
+
+ // Binder call
+ @Override
+ public MediaRouterClientState getState(IMediaRouterClient client) {
+ if (client == null) {
+ throw new IllegalArgumentException("client must not be null");
+ }
+
+ final long token = Binder.clearCallingIdentity();
+ try {
+ synchronized (mLock) {
+ return getStateLocked(client);
+ }
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
+ }
+
+ // Binder call
+ @Override
+ public void setDiscoveryRequest(IMediaRouterClient client,
+ int routeTypes, boolean activeScan) {
+ if (client == null) {
+ throw new IllegalArgumentException("client must not be null");
+ }
+
+ final long token = Binder.clearCallingIdentity();
+ try {
+ synchronized (mLock) {
+ setDiscoveryRequestLocked(client, routeTypes, activeScan);
+ }
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
+ }
+
+ // Binder call
+ // A null routeId means that the client wants to unselect its current route.
+ // The explicit flag indicates whether the change was explicitly requested by the
+ // user or the application which may cause changes to propagate out to the rest
+ // of the system. Should be false when the change is in response to a new globally
+ // selected route or a default selection.
+ @Override
+ public void setSelectedRoute(IMediaRouterClient client, String routeId, boolean explicit) {
+ if (client == null) {
+ throw new IllegalArgumentException("client must not be null");
+ }
+
+ final long token = Binder.clearCallingIdentity();
+ try {
+ synchronized (mLock) {
+ setSelectedRouteLocked(client, routeId, explicit);
+ }
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
+ }
+
+ // Binder call
+ @Override
+ public void requestSetVolume(IMediaRouterClient client, String routeId, int volume) {
+ if (client == null) {
+ throw new IllegalArgumentException("client must not be null");
+ }
+ if (routeId == null) {
+ throw new IllegalArgumentException("routeId must not be null");
+ }
+
+ final long token = Binder.clearCallingIdentity();
+ try {
+ synchronized (mLock) {
+ requestSetVolumeLocked(client, routeId, volume);
+ }
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
+ }
+
+ // Binder call
+ @Override
+ public void requestUpdateVolume(IMediaRouterClient client, String routeId, int direction) {
+ if (client == null) {
+ throw new IllegalArgumentException("client must not be null");
+ }
+ if (routeId == null) {
+ throw new IllegalArgumentException("routeId must not be null");
+ }
+
+ final long token = Binder.clearCallingIdentity();
+ try {
+ synchronized (mLock) {
+ requestUpdateVolumeLocked(client, routeId, direction);
+ }
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
+ }
+
+ // Binder call
+ @Override
+ public void dump(FileDescriptor fd, final PrintWriter pw, String[] args) {
+ if (mContext.checkCallingOrSelfPermission(Manifest.permission.DUMP)
+ != PackageManager.PERMISSION_GRANTED) {
+ pw.println("Permission Denial: can't dump MediaRouterService from from pid="
+ + Binder.getCallingPid()
+ + ", uid=" + Binder.getCallingUid());
+ return;
+ }
+
+ pw.println("MEDIA ROUTER SERVICE (dumpsys media_router)");
+ pw.println();
+ pw.println("Global state");
+ pw.println(" mCurrentUserId=" + mCurrentUserId);
+
+ synchronized (mLock) {
+ final int count = mUserRecords.size();
+ for (int i = 0; i < count; i++) {
+ UserRecord userRecord = mUserRecords.valueAt(i);
+ pw.println();
+ userRecord.dump(pw, "");
+ }
+ }
+ }
+
+ void switchUser() {
+ synchronized (mLock) {
+ int userId = ActivityManager.getCurrentUser();
+ if (mCurrentUserId != userId) {
+ final int oldUserId = mCurrentUserId;
+ mCurrentUserId = userId; // do this first
+
+ UserRecord oldUser = mUserRecords.get(oldUserId);
+ if (oldUser != null) {
+ oldUser.mHandler.sendEmptyMessage(UserHandler.MSG_STOP);
+ disposeUserIfNeededLocked(oldUser); // since no longer current user
+ }
+
+ UserRecord newUser = mUserRecords.get(userId);
+ if (newUser != null) {
+ newUser.mHandler.sendEmptyMessage(UserHandler.MSG_START);
+ }
+ }
+ }
+ }
+
+ void clientDied(ClientRecord clientRecord) {
+ synchronized (mLock) {
+ unregisterClientLocked(clientRecord.mClient, true);
+ }
+ }
+
+ private void registerClientLocked(IMediaRouterClient client,
+ int pid, String packageName, int userId, boolean trusted) {
+ final IBinder binder = client.asBinder();
+ ClientRecord clientRecord = mAllClientRecords.get(binder);
+ if (clientRecord == null) {
+ boolean newUser = false;
+ UserRecord userRecord = mUserRecords.get(userId);
+ if (userRecord == null) {
+ userRecord = new UserRecord(userId);
+ newUser = true;
+ }
+ clientRecord = new ClientRecord(userRecord, client, pid, packageName, trusted);
+ try {
+ binder.linkToDeath(clientRecord, 0);
+ } catch (RemoteException ex) {
+ throw new RuntimeException("Media router client died prematurely.", ex);
+ }
+
+ if (newUser) {
+ mUserRecords.put(userId, userRecord);
+ initializeUserLocked(userRecord);
+ }
+
+ userRecord.mClientRecords.add(clientRecord);
+ mAllClientRecords.put(binder, clientRecord);
+ initializeClientLocked(clientRecord);
+ }
+ }
+
+ private void unregisterClientLocked(IMediaRouterClient client, boolean died) {
+ ClientRecord clientRecord = mAllClientRecords.remove(client.asBinder());
+ if (clientRecord != null) {
+ UserRecord userRecord = clientRecord.mUserRecord;
+ userRecord.mClientRecords.remove(clientRecord);
+ disposeClientLocked(clientRecord, died);
+ disposeUserIfNeededLocked(userRecord); // since client removed from user
+ }
+ }
+
+ private MediaRouterClientState getStateLocked(IMediaRouterClient client) {
+ ClientRecord clientRecord = mAllClientRecords.get(client.asBinder());
+ if (clientRecord != null) {
+ return clientRecord.getState();
+ }
+ return null;
+ }
+
+ private void setDiscoveryRequestLocked(IMediaRouterClient client,
+ int routeTypes, boolean activeScan) {
+ final IBinder binder = client.asBinder();
+ ClientRecord clientRecord = mAllClientRecords.get(binder);
+ if (clientRecord != null) {
+ // Only let the system discover remote display routes for now.
+ if (!clientRecord.mTrusted) {
+ routeTypes &= ~MediaRouter.ROUTE_TYPE_REMOTE_DISPLAY;
+ }
+
+ if (clientRecord.mRouteTypes != routeTypes
+ || clientRecord.mActiveScan != activeScan) {
+ if (DEBUG) {
+ Slog.d(TAG, clientRecord + ": Set discovery request, routeTypes=0x"
+ + Integer.toHexString(routeTypes) + ", activeScan=" + activeScan);
+ }
+ clientRecord.mRouteTypes = routeTypes;
+ clientRecord.mActiveScan = activeScan;
+ clientRecord.mUserRecord.mHandler.sendEmptyMessage(
+ UserHandler.MSG_UPDATE_DISCOVERY_REQUEST);
+ }
+ }
+ }
+
+ private void setSelectedRouteLocked(IMediaRouterClient client,
+ String routeId, boolean explicit) {
+ ClientRecord clientRecord = mAllClientRecords.get(client.asBinder());
+ if (clientRecord != null) {
+ final String oldRouteId = clientRecord.mSelectedRouteId;
+ if (!Objects.equal(routeId, oldRouteId)) {
+ if (DEBUG) {
+ Slog.d(TAG, clientRecord + ": Set selected route, routeId=" + routeId
+ + ", oldRouteId=" + oldRouteId
+ + ", explicit=" + explicit);
+ }
+
+ clientRecord.mSelectedRouteId = routeId;
+ if (explicit) {
+ // Any app can disconnect from the globally selected route.
+ if (oldRouteId != null) {
+ clientRecord.mUserRecord.mHandler.obtainMessage(
+ UserHandler.MSG_UNSELECT_ROUTE, oldRouteId).sendToTarget();
+ }
+ // Only let the system connect to new global routes for now.
+ // A similar check exists in the display manager for wifi display.
+ if (routeId != null && clientRecord.mTrusted) {
+ clientRecord.mUserRecord.mHandler.obtainMessage(
+ UserHandler.MSG_SELECT_ROUTE, routeId).sendToTarget();
+ }
+ }
+ }
+ }
+ }
+
+ private void requestSetVolumeLocked(IMediaRouterClient client,
+ String routeId, int volume) {
+ final IBinder binder = client.asBinder();
+ ClientRecord clientRecord = mAllClientRecords.get(binder);
+ if (clientRecord != null) {
+ clientRecord.mUserRecord.mHandler.obtainMessage(
+ UserHandler.MSG_REQUEST_SET_VOLUME, volume, 0, routeId).sendToTarget();
+ }
+ }
+
+ private void requestUpdateVolumeLocked(IMediaRouterClient client,
+ String routeId, int direction) {
+ final IBinder binder = client.asBinder();
+ ClientRecord clientRecord = mAllClientRecords.get(binder);
+ if (clientRecord != null) {
+ clientRecord.mUserRecord.mHandler.obtainMessage(
+ UserHandler.MSG_REQUEST_UPDATE_VOLUME, direction, 0, routeId).sendToTarget();
+ }
+ }
+
+ private void initializeUserLocked(UserRecord userRecord) {
+ if (DEBUG) {
+ Slog.d(TAG, userRecord + ": Initialized");
+ }
+ if (userRecord.mUserId == mCurrentUserId) {
+ userRecord.mHandler.sendEmptyMessage(UserHandler.MSG_START);
+ }
+ }
+
+ private void disposeUserIfNeededLocked(UserRecord userRecord) {
+ // If there are no records left and the user is no longer current then go ahead
+ // and purge the user record and all of its associated state. If the user is current
+ // then leave it alone since we might be connected to a route or want to query
+ // the same route information again soon.
+ if (userRecord.mUserId != mCurrentUserId
+ && userRecord.mClientRecords.isEmpty()) {
+ if (DEBUG) {
+ Slog.d(TAG, userRecord + ": Disposed");
+ }
+ mUserRecords.remove(userRecord.mUserId);
+ // Note: User already stopped (by switchUser) so no need to send stop message here.
+ }
+ }
+
+ private void initializeClientLocked(ClientRecord clientRecord) {
+ if (DEBUG) {
+ Slog.d(TAG, clientRecord + ": Registered");
+ }
+ }
+
+ private void disposeClientLocked(ClientRecord clientRecord, boolean died) {
+ if (DEBUG) {
+ if (died) {
+ Slog.d(TAG, clientRecord + ": Died!");
+ } else {
+ Slog.d(TAG, clientRecord + ": Unregistered");
+ }
+ }
+ if (clientRecord.mRouteTypes != 0 || clientRecord.mActiveScan) {
+ clientRecord.mUserRecord.mHandler.sendEmptyMessage(
+ UserHandler.MSG_UPDATE_DISCOVERY_REQUEST);
+ }
+ clientRecord.dispose();
+ }
+
+ private boolean validatePackageName(int uid, String packageName) {
+ if (packageName != null) {
+ String[] packageNames = mContext.getPackageManager().getPackagesForUid(uid);
+ if (packageNames != null) {
+ for (String n : packageNames) {
+ if (n.equals(packageName)) {
+ return true;
+ }
+ }
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Information about a particular client of the media router.
+ * The contents of this object is guarded by mLock.
+ */
+ final class ClientRecord implements DeathRecipient {
+ public final UserRecord mUserRecord;
+ public final IMediaRouterClient mClient;
+ public final int mPid;
+ public final String mPackageName;
+ public final boolean mTrusted;
+
+ public int mRouteTypes;
+ public boolean mActiveScan;
+ public String mSelectedRouteId;
+
+ public ClientRecord(UserRecord userRecord, IMediaRouterClient client,
+ int pid, String packageName, boolean trusted) {
+ mUserRecord = userRecord;
+ mClient = client;
+ mPid = pid;
+ mPackageName = packageName;
+ mTrusted = trusted;
+ }
+
+ public void dispose() {
+ mClient.asBinder().unlinkToDeath(this, 0);
+ }
+
+ @Override
+ public void binderDied() {
+ clientDied(this);
+ }
+
+ MediaRouterClientState getState() {
+ return mTrusted ? mUserRecord.mTrustedState : mUserRecord.mUntrustedState;
+ }
+
+ public void dump(PrintWriter pw, String prefix) {
+ pw.println(prefix + this);
+
+ final String indent = prefix + " ";
+ pw.println(indent + "mTrusted=" + mTrusted);
+ pw.println(indent + "mRouteTypes=0x" + Integer.toHexString(mRouteTypes));
+ pw.println(indent + "mActiveScan=" + mActiveScan);
+ pw.println(indent + "mSelectedRouteId=" + mSelectedRouteId);
+ }
+
+ @Override
+ public String toString() {
+ return "Client " + mPackageName + " (pid " + mPid + ")";
+ }
+ }
+
+ /**
+ * Information about a particular user.
+ * The contents of this object is guarded by mLock.
+ */
+ final class UserRecord {
+ public final int mUserId;
+ public final ArrayList<ClientRecord> mClientRecords = new ArrayList<ClientRecord>();
+ public final UserHandler mHandler;
+ public MediaRouterClientState mTrustedState;
+ public MediaRouterClientState mUntrustedState;
+
+ public UserRecord(int userId) {
+ mUserId = userId;
+ mHandler = new UserHandler(MediaRouterService.this, this);
+ }
+
+ public void dump(final PrintWriter pw, String prefix) {
+ pw.println(prefix + this);
+
+ final String indent = prefix + " ";
+ final int clientCount = mClientRecords.size();
+ if (clientCount != 0) {
+ for (int i = 0; i < clientCount; i++) {
+ mClientRecords.get(i).dump(pw, indent);
+ }
+ } else {
+ pw.println(indent + "<no clients>");
+ }
+
+ pw.println(indent + "State");
+ pw.println(indent + "mTrustedState=" + mTrustedState);
+ pw.println(indent + "mUntrustedState=" + mUntrustedState);
+
+ if (!mHandler.runWithScissors(new Runnable() {
+ @Override
+ public void run() {
+ mHandler.dump(pw, indent);
+ }
+ }, 1000)) {
+ pw.println(indent + "<could not dump handler state>");
+ }
+ }
+
+ @Override
+ public String toString() {
+ return "User " + mUserId;
+ }
+ }
+
+ /**
+ * Media router handler
+ * <p>
+ * Since remote display providers are designed to be single-threaded by nature,
+ * this class encapsulates all of the associated functionality and exports state
+ * to the service as it evolves.
+ * </p><p>
+ * One important task of this class is to keep track of the current globally selected
+ * route id for certain routes that have global effects, such as remote displays.
+ * Global route selections override local selections made within apps. The change
+ * is propagated to all apps so that they are all in sync. Synchronization works
+ * both ways. Whenever the globally selected route is explicitly unselected by any
+ * app, then it becomes unselected globally and all apps are informed.
+ * </p><p>
+ * This class is currently hardcoded to work with remote display providers but
+ * it is intended to be eventually extended to support more general route providers
+ * similar to the support library media router.
+ * </p>
+ */
+ static final class UserHandler extends Handler
+ implements RemoteDisplayProviderWatcher.Callback,
+ RemoteDisplayProviderProxy.Callback {
+ public static final int MSG_START = 1;
+ public static final int MSG_STOP = 2;
+ public static final int MSG_UPDATE_DISCOVERY_REQUEST = 3;
+ public static final int MSG_SELECT_ROUTE = 4;
+ public static final int MSG_UNSELECT_ROUTE = 5;
+ public static final int MSG_REQUEST_SET_VOLUME = 6;
+ public static final int MSG_REQUEST_UPDATE_VOLUME = 7;
+ private static final int MSG_UPDATE_CLIENT_STATE = 8;
+ private static final int MSG_CONNECTION_TIMED_OUT = 9;
+
+ private static final int TIMEOUT_REASON_NOT_AVAILABLE = 1;
+ private static final int TIMEOUT_REASON_CONNECTION_LOST = 2;
+ private static final int TIMEOUT_REASON_WAITING_FOR_CONNECTING = 3;
+ private static final int TIMEOUT_REASON_WAITING_FOR_CONNECTED = 4;
+
+ // The relative order of these constants is important and expresses progress
+ // through the process of connecting to a route.
+ private static final int PHASE_NOT_AVAILABLE = -1;
+ private static final int PHASE_NOT_CONNECTED = 0;
+ private static final int PHASE_CONNECTING = 1;
+ private static final int PHASE_CONNECTED = 2;
+
+ private final MediaRouterService mService;
+ private final UserRecord mUserRecord;
+ private final RemoteDisplayProviderWatcher mWatcher;
+ private final ArrayList<ProviderRecord> mProviderRecords =
+ new ArrayList<ProviderRecord>();
+ private final ArrayList<IMediaRouterClient> mTempClients =
+ new ArrayList<IMediaRouterClient>();
+
+ private boolean mRunning;
+ private int mDiscoveryMode = RemoteDisplayState.DISCOVERY_MODE_NONE;
+ private RouteRecord mGloballySelectedRouteRecord;
+ private int mConnectionPhase = PHASE_NOT_AVAILABLE;
+ private int mConnectionTimeoutReason;
+ private long mConnectionTimeoutStartTime;
+ private boolean mClientStateUpdateScheduled;
+
+ public UserHandler(MediaRouterService service, UserRecord userRecord) {
+ super(Looper.getMainLooper(), null, true);
+ mService = service;
+ mUserRecord = userRecord;
+ mWatcher = new RemoteDisplayProviderWatcher(service.mContext, this,
+ this, mUserRecord.mUserId);
+ }
+
+ @Override
+ public void handleMessage(Message msg) {
+ switch (msg.what) {
+ case MSG_START: {
+ start();
+ break;
+ }
+ case MSG_STOP: {
+ stop();
+ break;
+ }
+ case MSG_UPDATE_DISCOVERY_REQUEST: {
+ updateDiscoveryRequest();
+ break;
+ }
+ case MSG_SELECT_ROUTE: {
+ selectRoute((String)msg.obj);
+ break;
+ }
+ case MSG_UNSELECT_ROUTE: {
+ unselectRoute((String)msg.obj);
+ break;
+ }
+ case MSG_REQUEST_SET_VOLUME: {
+ requestSetVolume((String)msg.obj, msg.arg1);
+ break;
+ }
+ case MSG_REQUEST_UPDATE_VOLUME: {
+ requestUpdateVolume((String)msg.obj, msg.arg1);
+ break;
+ }
+ case MSG_UPDATE_CLIENT_STATE: {
+ updateClientState();
+ break;
+ }
+ case MSG_CONNECTION_TIMED_OUT: {
+ connectionTimedOut();
+ break;
+ }
+ }
+ }
+
+ public void dump(PrintWriter pw, String prefix) {
+ pw.println(prefix + "Handler");
+
+ final String indent = prefix + " ";
+ pw.println(indent + "mRunning=" + mRunning);
+ pw.println(indent + "mDiscoveryMode=" + mDiscoveryMode);
+ pw.println(indent + "mGloballySelectedRouteRecord=" + mGloballySelectedRouteRecord);
+ pw.println(indent + "mConnectionPhase=" + mConnectionPhase);
+ pw.println(indent + "mConnectionTimeoutReason=" + mConnectionTimeoutReason);
+ pw.println(indent + "mConnectionTimeoutStartTime=" + (mConnectionTimeoutReason != 0 ?
+ TimeUtils.formatUptime(mConnectionTimeoutStartTime) : "<n/a>"));
+
+ mWatcher.dump(pw, prefix);
+
+ final int providerCount = mProviderRecords.size();
+ if (providerCount != 0) {
+ for (int i = 0; i < providerCount; i++) {
+ mProviderRecords.get(i).dump(pw, prefix);
+ }
+ } else {
+ pw.println(indent + "<no providers>");
+ }
+ }
+
+ private void start() {
+ if (!mRunning) {
+ mRunning = true;
+ mWatcher.start(); // also starts all providers
+ }
+ }
+
+ private void stop() {
+ if (mRunning) {
+ mRunning = false;
+ unselectGloballySelectedRoute();
+ mWatcher.stop(); // also stops all providers
+ }
+ }
+
+ private void updateDiscoveryRequest() {
+ int routeTypes = 0;
+ boolean activeScan = false;
+ synchronized (mService.mLock) {
+ final int count = mUserRecord.mClientRecords.size();
+ for (int i = 0; i < count; i++) {
+ ClientRecord clientRecord = mUserRecord.mClientRecords.get(i);
+ routeTypes |= clientRecord.mRouteTypes;
+ activeScan |= clientRecord.mActiveScan;
+ }
+ }
+
+ final int newDiscoveryMode;
+ if ((routeTypes & MediaRouter.ROUTE_TYPE_REMOTE_DISPLAY) != 0) {
+ if (activeScan) {
+ newDiscoveryMode = RemoteDisplayState.DISCOVERY_MODE_ACTIVE;
+ } else {
+ newDiscoveryMode = RemoteDisplayState.DISCOVERY_MODE_PASSIVE;
+ }
+ } else {
+ newDiscoveryMode = RemoteDisplayState.DISCOVERY_MODE_NONE;
+ }
+
+ if (mDiscoveryMode != newDiscoveryMode) {
+ mDiscoveryMode = newDiscoveryMode;
+ final int count = mProviderRecords.size();
+ for (int i = 0; i < count; i++) {
+ mProviderRecords.get(i).getProvider().setDiscoveryMode(mDiscoveryMode);
+ }
+ }
+ }
+
+ private void selectRoute(String routeId) {
+ if (routeId != null
+ && (mGloballySelectedRouteRecord == null
+ || !routeId.equals(mGloballySelectedRouteRecord.getUniqueId()))) {
+ RouteRecord routeRecord = findRouteRecord(routeId);
+ if (routeRecord != null) {
+ unselectGloballySelectedRoute();
+
+ Slog.i(TAG, "Selected global route:" + routeRecord);
+ mGloballySelectedRouteRecord = routeRecord;
+ checkGloballySelectedRouteState();
+ routeRecord.getProvider().setSelectedDisplay(routeRecord.getDescriptorId());
+
+ scheduleUpdateClientState();
+ }
+ }
+ }
+
+ private void unselectRoute(String routeId) {
+ if (routeId != null
+ && mGloballySelectedRouteRecord != null
+ && routeId.equals(mGloballySelectedRouteRecord.getUniqueId())) {
+ unselectGloballySelectedRoute();
+ }
+ }
+
+ private void unselectGloballySelectedRoute() {
+ if (mGloballySelectedRouteRecord != null) {
+ Slog.i(TAG, "Unselected global route:" + mGloballySelectedRouteRecord);
+ mGloballySelectedRouteRecord.getProvider().setSelectedDisplay(null);
+ mGloballySelectedRouteRecord = null;
+ checkGloballySelectedRouteState();
+
+ scheduleUpdateClientState();
+ }
+ }
+
+ private void requestSetVolume(String routeId, int volume) {
+ if (mGloballySelectedRouteRecord != null
+ && routeId.equals(mGloballySelectedRouteRecord.getUniqueId())) {
+ mGloballySelectedRouteRecord.getProvider().setDisplayVolume(volume);
+ }
+ }
+
+ private void requestUpdateVolume(String routeId, int direction) {
+ if (mGloballySelectedRouteRecord != null
+ && routeId.equals(mGloballySelectedRouteRecord.getUniqueId())) {
+ mGloballySelectedRouteRecord.getProvider().adjustDisplayVolume(direction);
+ }
+ }
+
+ @Override
+ public void addProvider(RemoteDisplayProviderProxy provider) {
+ provider.setCallback(this);
+ provider.setDiscoveryMode(mDiscoveryMode);
+ provider.setSelectedDisplay(null); // just to be safe
+
+ ProviderRecord providerRecord = new ProviderRecord(provider);
+ mProviderRecords.add(providerRecord);
+ providerRecord.updateDescriptor(provider.getDisplayState());
+
+ scheduleUpdateClientState();
+ }
+
+ @Override
+ public void removeProvider(RemoteDisplayProviderProxy provider) {
+ int index = findProviderRecord(provider);
+ if (index >= 0) {
+ ProviderRecord providerRecord = mProviderRecords.remove(index);
+ providerRecord.updateDescriptor(null); // mark routes invalid
+ provider.setCallback(null);
+ provider.setDiscoveryMode(RemoteDisplayState.DISCOVERY_MODE_NONE);
+
+ checkGloballySelectedRouteState();
+ scheduleUpdateClientState();
+ }
+ }
+
+ @Override
+ public void onDisplayStateChanged(RemoteDisplayProviderProxy provider,
+ RemoteDisplayState state) {
+ updateProvider(provider, state);
+ }
+
+ private void updateProvider(RemoteDisplayProviderProxy provider,
+ RemoteDisplayState state) {
+ int index = findProviderRecord(provider);
+ if (index >= 0) {
+ ProviderRecord providerRecord = mProviderRecords.get(index);
+ if (providerRecord.updateDescriptor(state)) {
+ checkGloballySelectedRouteState();
+ scheduleUpdateClientState();
+ }
+ }
+ }
+
+ /**
+ * This function is called whenever the state of the globally selected route
+ * may have changed. It checks the state and updates timeouts or unselects
+ * the route as appropriate.
+ */
+ private void checkGloballySelectedRouteState() {
+ // Unschedule timeouts when the route is unselected.
+ if (mGloballySelectedRouteRecord == null) {
+ mConnectionPhase = PHASE_NOT_AVAILABLE;
+ updateConnectionTimeout(0);
+ return;
+ }
+
+ // Ensure that the route is still present and enabled.
+ if (!mGloballySelectedRouteRecord.isValid()
+ || !mGloballySelectedRouteRecord.isEnabled()) {
+ updateConnectionTimeout(TIMEOUT_REASON_NOT_AVAILABLE);
+ return;
+ }
+
+ // Make sure we haven't lost our connection.
+ final int oldPhase = mConnectionPhase;
+ mConnectionPhase = getConnectionPhase(mGloballySelectedRouteRecord.getStatus());
+ if (oldPhase >= PHASE_CONNECTING && mConnectionPhase < PHASE_CONNECTING) {
+ updateConnectionTimeout(TIMEOUT_REASON_CONNECTION_LOST);
+ return;
+ }
+
+ // Check the route status.
+ switch (mConnectionPhase) {
+ case PHASE_CONNECTED:
+ if (oldPhase != PHASE_CONNECTED) {
+ Slog.i(TAG, "Connected to global route: "
+ + mGloballySelectedRouteRecord);
+ }
+ updateConnectionTimeout(0);
+ break;
+ case PHASE_CONNECTING:
+ if (oldPhase != PHASE_CONNECTING) {
+ Slog.i(TAG, "Connecting to global route: "
+ + mGloballySelectedRouteRecord);
+ }
+ updateConnectionTimeout(TIMEOUT_REASON_WAITING_FOR_CONNECTED);
+ break;
+ case PHASE_NOT_CONNECTED:
+ updateConnectionTimeout(TIMEOUT_REASON_WAITING_FOR_CONNECTING);
+ break;
+ case PHASE_NOT_AVAILABLE:
+ default:
+ updateConnectionTimeout(TIMEOUT_REASON_NOT_AVAILABLE);
+ break;
+ }
+ }
+
+ private void updateConnectionTimeout(int reason) {
+ if (reason != mConnectionTimeoutReason) {
+ if (mConnectionTimeoutReason != 0) {
+ removeMessages(MSG_CONNECTION_TIMED_OUT);
+ }
+ mConnectionTimeoutReason = reason;
+ mConnectionTimeoutStartTime = SystemClock.uptimeMillis();
+ switch (reason) {
+ case TIMEOUT_REASON_NOT_AVAILABLE:
+ case TIMEOUT_REASON_CONNECTION_LOST:
+ // Route became unavailable or connection lost.
+ // Unselect it immediately.
+ sendEmptyMessage(MSG_CONNECTION_TIMED_OUT);
+ break;
+ case TIMEOUT_REASON_WAITING_FOR_CONNECTING:
+ // Waiting for route to start connecting.
+ sendEmptyMessageDelayed(MSG_CONNECTION_TIMED_OUT, CONNECTING_TIMEOUT);
+ break;
+ case TIMEOUT_REASON_WAITING_FOR_CONNECTED:
+ // Waiting for route to complete connection.
+ sendEmptyMessageDelayed(MSG_CONNECTION_TIMED_OUT, CONNECTED_TIMEOUT);
+ break;
+ }
+ }
+ }
+
+ private void connectionTimedOut() {
+ if (mConnectionTimeoutReason == 0 || mGloballySelectedRouteRecord == null) {
+ // Shouldn't get here. There must be a bug somewhere.
+ Log.wtf(TAG, "Handled connection timeout for no reason.");
+ return;
+ }
+
+ switch (mConnectionTimeoutReason) {
+ case TIMEOUT_REASON_NOT_AVAILABLE:
+ Slog.i(TAG, "Global route no longer available: "
+ + mGloballySelectedRouteRecord);
+ break;
+ case TIMEOUT_REASON_CONNECTION_LOST:
+ Slog.i(TAG, "Global route connection lost: "
+ + mGloballySelectedRouteRecord);
+ break;
+ case TIMEOUT_REASON_WAITING_FOR_CONNECTING:
+ Slog.i(TAG, "Global route timed out while waiting for "
+ + "connection attempt to begin after "
+ + (SystemClock.uptimeMillis() - mConnectionTimeoutStartTime)
+ + " ms: " + mGloballySelectedRouteRecord);
+ break;
+ case TIMEOUT_REASON_WAITING_FOR_CONNECTED:
+ Slog.i(TAG, "Global route timed out while connecting after "
+ + (SystemClock.uptimeMillis() - mConnectionTimeoutStartTime)
+ + " ms: " + mGloballySelectedRouteRecord);
+ break;
+ }
+ mConnectionTimeoutReason = 0;
+
+ unselectGloballySelectedRoute();
+ }
+
+ private void scheduleUpdateClientState() {
+ if (!mClientStateUpdateScheduled) {
+ mClientStateUpdateScheduled = true;
+ sendEmptyMessage(MSG_UPDATE_CLIENT_STATE);
+ }
+ }
+
+ private void updateClientState() {
+ mClientStateUpdateScheduled = false;
+
+ final String globallySelectedRouteId = mGloballySelectedRouteRecord != null ?
+ mGloballySelectedRouteRecord.getUniqueId() : null;
+
+ // Build a new client state for trusted clients.
+ MediaRouterClientState trustedState = new MediaRouterClientState();
+ trustedState.globallySelectedRouteId = globallySelectedRouteId;
+ final int providerCount = mProviderRecords.size();
+ for (int i = 0; i < providerCount; i++) {
+ mProviderRecords.get(i).appendClientState(trustedState);
+ }
+
+ // Build a new client state for untrusted clients that can only see
+ // the currently selected route.
+ MediaRouterClientState untrustedState = new MediaRouterClientState();
+ untrustedState.globallySelectedRouteId = globallySelectedRouteId;
+ if (globallySelectedRouteId != null) {
+ untrustedState.routes.add(trustedState.getRoute(globallySelectedRouteId));
+ }
+
+ try {
+ synchronized (mService.mLock) {
+ // Update the UserRecord.
+ mUserRecord.mTrustedState = trustedState;
+ mUserRecord.mUntrustedState = untrustedState;
+
+ // Collect all clients.
+ final int count = mUserRecord.mClientRecords.size();
+ for (int i = 0; i < count; i++) {
+ mTempClients.add(mUserRecord.mClientRecords.get(i).mClient);
+ }
+ }
+
+ // Notify all clients (outside of the lock).
+ final int count = mTempClients.size();
+ for (int i = 0; i < count; i++) {
+ try {
+ mTempClients.get(i).onStateChanged();
+ } catch (RemoteException ex) {
+ // ignore errors, client probably died
+ }
+ }
+ } finally {
+ // Clear the list in preparation for the next time.
+ mTempClients.clear();
+ }
+ }
+
+ private int findProviderRecord(RemoteDisplayProviderProxy provider) {
+ final int count = mProviderRecords.size();
+ for (int i = 0; i < count; i++) {
+ ProviderRecord record = mProviderRecords.get(i);
+ if (record.getProvider() == provider) {
+ return i;
+ }
+ }
+ return -1;
+ }
+
+ private RouteRecord findRouteRecord(String uniqueId) {
+ final int count = mProviderRecords.size();
+ for (int i = 0; i < count; i++) {
+ RouteRecord record = mProviderRecords.get(i).findRouteByUniqueId(uniqueId);
+ if (record != null) {
+ return record;
+ }
+ }
+ return null;
+ }
+
+ private static int getConnectionPhase(int status) {
+ switch (status) {
+ case MediaRouter.RouteInfo.STATUS_NONE:
+ case MediaRouter.RouteInfo.STATUS_CONNECTED:
+ return PHASE_CONNECTED;
+ case MediaRouter.RouteInfo.STATUS_CONNECTING:
+ return PHASE_CONNECTING;
+ case MediaRouter.RouteInfo.STATUS_SCANNING:
+ case MediaRouter.RouteInfo.STATUS_AVAILABLE:
+ return PHASE_NOT_CONNECTED;
+ case MediaRouter.RouteInfo.STATUS_NOT_AVAILABLE:
+ case MediaRouter.RouteInfo.STATUS_IN_USE:
+ default:
+ return PHASE_NOT_AVAILABLE;
+ }
+ }
+
+ static final class ProviderRecord {
+ private final RemoteDisplayProviderProxy mProvider;
+ private final String mUniquePrefix;
+ private final ArrayList<RouteRecord> mRoutes = new ArrayList<RouteRecord>();
+ private RemoteDisplayState mDescriptor;
+
+ public ProviderRecord(RemoteDisplayProviderProxy provider) {
+ mProvider = provider;
+ mUniquePrefix = provider.getFlattenedComponentName() + ":";
+ }
+
+ public RemoteDisplayProviderProxy getProvider() {
+ return mProvider;
+ }
+
+ public String getUniquePrefix() {
+ return mUniquePrefix;
+ }
+
+ public boolean updateDescriptor(RemoteDisplayState descriptor) {
+ boolean changed = false;
+ if (mDescriptor != descriptor) {
+ mDescriptor = descriptor;
+
+ // Update all existing routes and reorder them to match
+ // the order of their descriptors.
+ int targetIndex = 0;
+ if (descriptor != null) {
+ if (descriptor.isValid()) {
+ final List<RemoteDisplayInfo> routeDescriptors = descriptor.displays;
+ final int routeCount = routeDescriptors.size();
+ for (int i = 0; i < routeCount; i++) {
+ final RemoteDisplayInfo routeDescriptor =
+ routeDescriptors.get(i);
+ final String descriptorId = routeDescriptor.id;
+ final int sourceIndex = findRouteByDescriptorId(descriptorId);
+ if (sourceIndex < 0) {
+ // Add the route to the provider.
+ String uniqueId = assignRouteUniqueId(descriptorId);
+ RouteRecord route =
+ new RouteRecord(this, descriptorId, uniqueId);
+ mRoutes.add(targetIndex++, route);
+ route.updateDescriptor(routeDescriptor);
+ changed = true;
+ } else if (sourceIndex < targetIndex) {
+ // Ignore route with duplicate id.
+ Slog.w(TAG, "Ignoring route descriptor with duplicate id: "
+ + routeDescriptor);
+ } else {
+ // Reorder existing route within the list.
+ RouteRecord route = mRoutes.get(sourceIndex);
+ Collections.swap(mRoutes, sourceIndex, targetIndex++);
+ changed |= route.updateDescriptor(routeDescriptor);
+ }
+ }
+ } else {
+ Slog.w(TAG, "Ignoring invalid descriptor from media route provider: "
+ + mProvider.getFlattenedComponentName());
+ }
+ }
+
+ // Dispose all remaining routes that do not have matching descriptors.
+ for (int i = mRoutes.size() - 1; i >= targetIndex; i--) {
+ RouteRecord route = mRoutes.remove(i);
+ route.updateDescriptor(null); // mark route invalid
+ changed = true;
+ }
+ }
+ return changed;
+ }
+
+ public void appendClientState(MediaRouterClientState state) {
+ final int routeCount = mRoutes.size();
+ for (int i = 0; i < routeCount; i++) {
+ state.routes.add(mRoutes.get(i).getInfo());
+ }
+ }
+
+ public RouteRecord findRouteByUniqueId(String uniqueId) {
+ final int routeCount = mRoutes.size();
+ for (int i = 0; i < routeCount; i++) {
+ RouteRecord route = mRoutes.get(i);
+ if (route.getUniqueId().equals(uniqueId)) {
+ return route;
+ }
+ }
+ return null;
+ }
+
+ private int findRouteByDescriptorId(String descriptorId) {
+ final int routeCount = mRoutes.size();
+ for (int i = 0; i < routeCount; i++) {
+ RouteRecord route = mRoutes.get(i);
+ if (route.getDescriptorId().equals(descriptorId)) {
+ return i;
+ }
+ }
+ return -1;
+ }
+
+ public void dump(PrintWriter pw, String prefix) {
+ pw.println(prefix + this);
+
+ final String indent = prefix + " ";
+ mProvider.dump(pw, indent);
+
+ final int routeCount = mRoutes.size();
+ if (routeCount != 0) {
+ for (int i = 0; i < routeCount; i++) {
+ mRoutes.get(i).dump(pw, indent);
+ }
+ } else {
+ pw.println(indent + "<no routes>");
+ }
+ }
+
+ @Override
+ public String toString() {
+ return "Provider " + mProvider.getFlattenedComponentName();
+ }
+
+ private String assignRouteUniqueId(String descriptorId) {
+ return mUniquePrefix + descriptorId;
+ }
+ }
+
+ static final class RouteRecord {
+ private final ProviderRecord mProviderRecord;
+ private final String mDescriptorId;
+ private final MediaRouterClientState.RouteInfo mMutableInfo;
+ private MediaRouterClientState.RouteInfo mImmutableInfo;
+ private RemoteDisplayInfo mDescriptor;
+
+ public RouteRecord(ProviderRecord providerRecord,
+ String descriptorId, String uniqueId) {
+ mProviderRecord = providerRecord;
+ mDescriptorId = descriptorId;
+ mMutableInfo = new MediaRouterClientState.RouteInfo(uniqueId);
+ }
+
+ public RemoteDisplayProviderProxy getProvider() {
+ return mProviderRecord.getProvider();
+ }
+
+ public ProviderRecord getProviderRecord() {
+ return mProviderRecord;
+ }
+
+ public String getDescriptorId() {
+ return mDescriptorId;
+ }
+
+ public String getUniqueId() {
+ return mMutableInfo.id;
+ }
+
+ public MediaRouterClientState.RouteInfo getInfo() {
+ if (mImmutableInfo == null) {
+ mImmutableInfo = new MediaRouterClientState.RouteInfo(mMutableInfo);
+ }
+ return mImmutableInfo;
+ }
+
+ public boolean isValid() {
+ return mDescriptor != null;
+ }
+
+ public boolean isEnabled() {
+ return mMutableInfo.enabled;
+ }
+
+ public int getStatus() {
+ return mMutableInfo.statusCode;
+ }
+
+ public boolean updateDescriptor(RemoteDisplayInfo descriptor) {
+ boolean changed = false;
+ if (mDescriptor != descriptor) {
+ mDescriptor = descriptor;
+ if (descriptor != null) {
+ final String name = computeName(descriptor);
+ if (!Objects.equal(mMutableInfo.name, name)) {
+ mMutableInfo.name = name;
+ changed = true;
+ }
+ final String description = computeDescription(descriptor);
+ if (!Objects.equal(mMutableInfo.description, description)) {
+ mMutableInfo.description = description;
+ changed = true;
+ }
+ final int supportedTypes = computeSupportedTypes(descriptor);
+ if (mMutableInfo.supportedTypes != supportedTypes) {
+ mMutableInfo.supportedTypes = supportedTypes;
+ changed = true;
+ }
+ final boolean enabled = computeEnabled(descriptor);
+ if (mMutableInfo.enabled != enabled) {
+ mMutableInfo.enabled = enabled;
+ changed = true;
+ }
+ final int statusCode = computeStatusCode(descriptor);
+ if (mMutableInfo.statusCode != statusCode) {
+ mMutableInfo.statusCode = statusCode;
+ changed = true;
+ }
+ final int playbackType = computePlaybackType(descriptor);
+ if (mMutableInfo.playbackType != playbackType) {
+ mMutableInfo.playbackType = playbackType;
+ changed = true;
+ }
+ final int playbackStream = computePlaybackStream(descriptor);
+ if (mMutableInfo.playbackStream != playbackStream) {
+ mMutableInfo.playbackStream = playbackStream;
+ changed = true;
+ }
+ final int volume = computeVolume(descriptor);
+ if (mMutableInfo.volume != volume) {
+ mMutableInfo.volume = volume;
+ changed = true;
+ }
+ final int volumeMax = computeVolumeMax(descriptor);
+ if (mMutableInfo.volumeMax != volumeMax) {
+ mMutableInfo.volumeMax = volumeMax;
+ changed = true;
+ }
+ final int volumeHandling = computeVolumeHandling(descriptor);
+ if (mMutableInfo.volumeHandling != volumeHandling) {
+ mMutableInfo.volumeHandling = volumeHandling;
+ changed = true;
+ }
+ final int presentationDisplayId = computePresentationDisplayId(descriptor);
+ if (mMutableInfo.presentationDisplayId != presentationDisplayId) {
+ mMutableInfo.presentationDisplayId = presentationDisplayId;
+ changed = true;
+ }
+ }
+ }
+ if (changed) {
+ mImmutableInfo = null;
+ }
+ return changed;
+ }
+
+ public void dump(PrintWriter pw, String prefix) {
+ pw.println(prefix + this);
+
+ final String indent = prefix + " ";
+ pw.println(indent + "mMutableInfo=" + mMutableInfo);
+ pw.println(indent + "mDescriptorId=" + mDescriptorId);
+ pw.println(indent + "mDescriptor=" + mDescriptor);
+ }
+
+ @Override
+ public String toString() {
+ return "Route " + mMutableInfo.name + " (" + mMutableInfo.id + ")";
+ }
+
+ private static String computeName(RemoteDisplayInfo descriptor) {
+ // Note that isValid() already ensures the name is non-empty.
+ return descriptor.name;
+ }
+
+ private static String computeDescription(RemoteDisplayInfo descriptor) {
+ final String description = descriptor.description;
+ return TextUtils.isEmpty(description) ? null : description;
+ }
+
+ private static int computeSupportedTypes(RemoteDisplayInfo descriptor) {
+ return MediaRouter.ROUTE_TYPE_LIVE_AUDIO
+ | MediaRouter.ROUTE_TYPE_LIVE_VIDEO
+ | MediaRouter.ROUTE_TYPE_REMOTE_DISPLAY;
+ }
+
+ private static boolean computeEnabled(RemoteDisplayInfo descriptor) {
+ switch (descriptor.status) {
+ case RemoteDisplayInfo.STATUS_CONNECTED:
+ case RemoteDisplayInfo.STATUS_CONNECTING:
+ case RemoteDisplayInfo.STATUS_AVAILABLE:
+ return true;
+ default:
+ return false;
+ }
+ }
+
+ private static int computeStatusCode(RemoteDisplayInfo descriptor) {
+ switch (descriptor.status) {
+ case RemoteDisplayInfo.STATUS_NOT_AVAILABLE:
+ return MediaRouter.RouteInfo.STATUS_NOT_AVAILABLE;
+ case RemoteDisplayInfo.STATUS_AVAILABLE:
+ return MediaRouter.RouteInfo.STATUS_AVAILABLE;
+ case RemoteDisplayInfo.STATUS_IN_USE:
+ return MediaRouter.RouteInfo.STATUS_IN_USE;
+ case RemoteDisplayInfo.STATUS_CONNECTING:
+ return MediaRouter.RouteInfo.STATUS_CONNECTING;
+ case RemoteDisplayInfo.STATUS_CONNECTED:
+ return MediaRouter.RouteInfo.STATUS_CONNECTED;
+ default:
+ return MediaRouter.RouteInfo.STATUS_NONE;
+ }
+ }
+
+ private static int computePlaybackType(RemoteDisplayInfo descriptor) {
+ return MediaRouter.RouteInfo.PLAYBACK_TYPE_REMOTE;
+ }
+
+ private static int computePlaybackStream(RemoteDisplayInfo descriptor) {
+ return AudioSystem.STREAM_MUSIC;
+ }
+
+ private static int computeVolume(RemoteDisplayInfo descriptor) {
+ final int volume = descriptor.volume;
+ final int volumeMax = descriptor.volumeMax;
+ if (volume < 0) {
+ return 0;
+ } else if (volume > volumeMax) {
+ return volumeMax;
+ }
+ return volume;
+ }
+
+ private static int computeVolumeMax(RemoteDisplayInfo descriptor) {
+ final int volumeMax = descriptor.volumeMax;
+ return volumeMax > 0 ? volumeMax : 0;
+ }
+
+ private static int computeVolumeHandling(RemoteDisplayInfo descriptor) {
+ final int volumeHandling = descriptor.volumeHandling;
+ switch (volumeHandling) {
+ case RemoteDisplayInfo.PLAYBACK_VOLUME_VARIABLE:
+ return MediaRouter.RouteInfo.PLAYBACK_VOLUME_VARIABLE;
+ case RemoteDisplayInfo.PLAYBACK_VOLUME_FIXED:
+ default:
+ return MediaRouter.RouteInfo.PLAYBACK_VOLUME_FIXED;
+ }
+ }
+
+ private static int computePresentationDisplayId(RemoteDisplayInfo descriptor) {
+ // The MediaRouter class validates that the id corresponds to an extant
+ // presentation display. So all we do here is canonicalize the null case.
+ final int displayId = descriptor.presentationDisplayId;
+ return displayId < 0 ? -1 : displayId;
+ }
+ }
+ }
+}
diff --git a/services/java/com/android/server/media/RemoteDisplayProviderProxy.java b/services/java/com/android/server/media/RemoteDisplayProviderProxy.java
new file mode 100644
index 0000000..b248ee0
--- /dev/null
+++ b/services/java/com/android/server/media/RemoteDisplayProviderProxy.java
@@ -0,0 +1,443 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.media;
+
+import com.android.internal.util.Objects;
+
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.ServiceConnection;
+import android.media.IRemoteDisplayCallback;
+import android.media.IRemoteDisplayProvider;
+import android.media.RemoteDisplayState;
+import android.os.Handler;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.os.IBinder.DeathRecipient;
+import android.os.UserHandle;
+import android.util.Log;
+import android.util.Slog;
+
+import java.io.PrintWriter;
+import java.lang.ref.WeakReference;
+
+/**
+ * Maintains a connection to a particular remote display provider service.
+ */
+final class RemoteDisplayProviderProxy implements ServiceConnection {
+ private static final String TAG = "RemoteDisplayProvider"; // max. 23 chars
+ private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
+
+ private final Context mContext;
+ private final ComponentName mComponentName;
+ private final int mUserId;
+ private final Handler mHandler;
+
+ private Callback mDisplayStateCallback;
+
+ // Connection state
+ private boolean mRunning;
+ private boolean mBound;
+ private Connection mActiveConnection;
+ private boolean mConnectionReady;
+
+ // Logical state
+ private int mDiscoveryMode;
+ private String mSelectedDisplayId;
+ private RemoteDisplayState mDisplayState;
+ private boolean mScheduledDisplayStateChangedCallback;
+
+ public RemoteDisplayProviderProxy(Context context, ComponentName componentName,
+ int userId) {
+ mContext = context;
+ mComponentName = componentName;
+ mUserId = userId;
+ mHandler = new Handler();
+ }
+
+ public void dump(PrintWriter pw, String prefix) {
+ pw.println(prefix + "Proxy");
+ pw.println(prefix + " mUserId=" + mUserId);
+ pw.println(prefix + " mRunning=" + mRunning);
+ pw.println(prefix + " mBound=" + mBound);
+ pw.println(prefix + " mActiveConnection=" + mActiveConnection);
+ pw.println(prefix + " mConnectionReady=" + mConnectionReady);
+ pw.println(prefix + " mDiscoveryMode=" + mDiscoveryMode);
+ pw.println(prefix + " mSelectedDisplayId=" + mSelectedDisplayId);
+ pw.println(prefix + " mDisplayState=" + mDisplayState);
+ }
+
+ public void setCallback(Callback callback) {
+ mDisplayStateCallback = callback;
+ }
+
+ public RemoteDisplayState getDisplayState() {
+ return mDisplayState;
+ }
+
+ public void setDiscoveryMode(int mode) {
+ if (mDiscoveryMode != mode) {
+ mDiscoveryMode = mode;
+ if (mConnectionReady) {
+ mActiveConnection.setDiscoveryMode(mode);
+ }
+ updateBinding();
+ }
+ }
+
+ public void setSelectedDisplay(String id) {
+ if (!Objects.equal(mSelectedDisplayId, id)) {
+ if (mConnectionReady && mSelectedDisplayId != null) {
+ mActiveConnection.disconnect(mSelectedDisplayId);
+ }
+ mSelectedDisplayId = id;
+ if (mConnectionReady && id != null) {
+ mActiveConnection.connect(id);
+ }
+ updateBinding();
+ }
+ }
+
+ public void setDisplayVolume(int volume) {
+ if (mConnectionReady && mSelectedDisplayId != null) {
+ mActiveConnection.setVolume(mSelectedDisplayId, volume);
+ }
+ }
+
+ public void adjustDisplayVolume(int delta) {
+ if (mConnectionReady && mSelectedDisplayId != null) {
+ mActiveConnection.adjustVolume(mSelectedDisplayId, delta);
+ }
+ }
+
+ public boolean hasComponentName(String packageName, String className) {
+ return mComponentName.getPackageName().equals(packageName)
+ && mComponentName.getClassName().equals(className);
+ }
+
+ public String getFlattenedComponentName() {
+ return mComponentName.flattenToShortString();
+ }
+
+ public void start() {
+ if (!mRunning) {
+ if (DEBUG) {
+ Slog.d(TAG, this + ": Starting");
+ }
+
+ mRunning = true;
+ updateBinding();
+ }
+ }
+
+ public void stop() {
+ if (mRunning) {
+ if (DEBUG) {
+ Slog.d(TAG, this + ": Stopping");
+ }
+
+ mRunning = false;
+ updateBinding();
+ }
+ }
+
+ public void rebindIfDisconnected() {
+ if (mActiveConnection == null && shouldBind()) {
+ unbind();
+ bind();
+ }
+ }
+
+ private void updateBinding() {
+ if (shouldBind()) {
+ bind();
+ } else {
+ unbind();
+ }
+ }
+
+ private boolean shouldBind() {
+ if (mRunning) {
+ // Bind whenever there is a discovery request or selected display.
+ if (mDiscoveryMode != RemoteDisplayState.DISCOVERY_MODE_NONE
+ || mSelectedDisplayId != null) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ private void bind() {
+ if (!mBound) {
+ if (DEBUG) {
+ Slog.d(TAG, this + ": Binding");
+ }
+
+ Intent service = new Intent(RemoteDisplayState.SERVICE_INTERFACE);
+ service.setComponent(mComponentName);
+ try {
+ mBound = mContext.bindServiceAsUser(service, this, Context.BIND_AUTO_CREATE,
+ new UserHandle(mUserId));
+ if (!mBound && DEBUG) {
+ Slog.d(TAG, this + ": Bind failed");
+ }
+ } catch (SecurityException ex) {
+ if (DEBUG) {
+ Slog.d(TAG, this + ": Bind failed", ex);
+ }
+ }
+ }
+ }
+
+ private void unbind() {
+ if (mBound) {
+ if (DEBUG) {
+ Slog.d(TAG, this + ": Unbinding");
+ }
+
+ mBound = false;
+ disconnect();
+ mContext.unbindService(this);
+ }
+ }
+
+ @Override
+ public void onServiceConnected(ComponentName name, IBinder service) {
+ if (DEBUG) {
+ Slog.d(TAG, this + ": Connected");
+ }
+
+ if (mBound) {
+ disconnect();
+
+ IRemoteDisplayProvider provider = IRemoteDisplayProvider.Stub.asInterface(service);
+ if (provider != null) {
+ Connection connection = new Connection(provider);
+ if (connection.register()) {
+ mActiveConnection = connection;
+ } else {
+ if (DEBUG) {
+ Slog.d(TAG, this + ": Registration failed");
+ }
+ }
+ } else {
+ Slog.e(TAG, this + ": Service returned invalid remote display provider binder");
+ }
+ }
+ }
+
+ @Override
+ public void onServiceDisconnected(ComponentName name) {
+ if (DEBUG) {
+ Slog.d(TAG, this + ": Service disconnected");
+ }
+ disconnect();
+ }
+
+ private void onConnectionReady(Connection connection) {
+ if (mActiveConnection == connection) {
+ mConnectionReady = true;
+
+ if (mDiscoveryMode != RemoteDisplayState.DISCOVERY_MODE_NONE) {
+ mActiveConnection.setDiscoveryMode(mDiscoveryMode);
+ }
+ if (mSelectedDisplayId != null) {
+ mActiveConnection.connect(mSelectedDisplayId);
+ }
+ }
+ }
+
+ private void onConnectionDied(Connection connection) {
+ if (mActiveConnection == connection) {
+ if (DEBUG) {
+ Slog.d(TAG, this + ": Service connection died");
+ }
+ disconnect();
+ }
+ }
+
+ private void onDisplayStateChanged(Connection connection, RemoteDisplayState state) {
+ if (mActiveConnection == connection) {
+ if (DEBUG) {
+ Slog.d(TAG, this + ": State changed, state=" + state);
+ }
+ setDisplayState(state);
+ }
+ }
+
+ private void disconnect() {
+ if (mActiveConnection != null) {
+ if (mSelectedDisplayId != null) {
+ mActiveConnection.disconnect(mSelectedDisplayId);
+ }
+ mConnectionReady = false;
+ mActiveConnection.dispose();
+ mActiveConnection = null;
+ setDisplayState(null);
+ }
+ }
+
+ private void setDisplayState(RemoteDisplayState state) {
+ if (!Objects.equal(mDisplayState, state)) {
+ mDisplayState = state;
+ if (!mScheduledDisplayStateChangedCallback) {
+ mScheduledDisplayStateChangedCallback = true;
+ mHandler.post(mDisplayStateChanged);
+ }
+ }
+ }
+
+ @Override
+ public String toString() {
+ return "Service connection " + mComponentName.flattenToShortString();
+ }
+
+ private final Runnable mDisplayStateChanged = new Runnable() {
+ @Override
+ public void run() {
+ mScheduledDisplayStateChangedCallback = false;
+ if (mDisplayStateCallback != null) {
+ mDisplayStateCallback.onDisplayStateChanged(
+ RemoteDisplayProviderProxy.this, mDisplayState);
+ }
+ }
+ };
+
+ public interface Callback {
+ void onDisplayStateChanged(RemoteDisplayProviderProxy provider, RemoteDisplayState state);
+ }
+
+ private final class Connection implements DeathRecipient {
+ private final IRemoteDisplayProvider mProvider;
+ private final ProviderCallback mCallback;
+
+ public Connection(IRemoteDisplayProvider provider) {
+ mProvider = provider;
+ mCallback = new ProviderCallback(this);
+ }
+
+ public boolean register() {
+ try {
+ mProvider.asBinder().linkToDeath(this, 0);
+ mProvider.setCallback(mCallback);
+ mHandler.post(new Runnable() {
+ @Override
+ public void run() {
+ onConnectionReady(Connection.this);
+ }
+ });
+ return true;
+ } catch (RemoteException ex) {
+ binderDied();
+ }
+ return false;
+ }
+
+ public void dispose() {
+ mProvider.asBinder().unlinkToDeath(this, 0);
+ mCallback.dispose();
+ }
+
+ public void setDiscoveryMode(int mode) {
+ try {
+ mProvider.setDiscoveryMode(mode);
+ } catch (RemoteException ex) {
+ Slog.e(TAG, "Failed to deliver request to set discovery mode.", ex);
+ }
+ }
+
+ public void connect(String id) {
+ try {
+ mProvider.connect(id);
+ } catch (RemoteException ex) {
+ Slog.e(TAG, "Failed to deliver request to connect to display.", ex);
+ }
+ }
+
+ public void disconnect(String id) {
+ try {
+ mProvider.disconnect(id);
+ } catch (RemoteException ex) {
+ Slog.e(TAG, "Failed to deliver request to disconnect from display.", ex);
+ }
+ }
+
+ public void setVolume(String id, int volume) {
+ try {
+ mProvider.setVolume(id, volume);
+ } catch (RemoteException ex) {
+ Slog.e(TAG, "Failed to deliver request to set display volume.", ex);
+ }
+ }
+
+ public void adjustVolume(String id, int volume) {
+ try {
+ mProvider.adjustVolume(id, volume);
+ } catch (RemoteException ex) {
+ Slog.e(TAG, "Failed to deliver request to adjust display volume.", ex);
+ }
+ }
+
+ @Override
+ public void binderDied() {
+ mHandler.post(new Runnable() {
+ @Override
+ public void run() {
+ onConnectionDied(Connection.this);
+ }
+ });
+ }
+
+ void postStateChanged(final RemoteDisplayState state) {
+ mHandler.post(new Runnable() {
+ @Override
+ public void run() {
+ onDisplayStateChanged(Connection.this, state);
+ }
+ });
+ }
+ }
+
+ /**
+ * Receives callbacks from the service.
+ * <p>
+ * This inner class is static and only retains a weak reference to the connection
+ * to prevent the client from being leaked in case the service is holding an
+ * active reference to the client's callback.
+ * </p>
+ */
+ private static final class ProviderCallback extends IRemoteDisplayCallback.Stub {
+ private final WeakReference<Connection> mConnectionRef;
+
+ public ProviderCallback(Connection connection) {
+ mConnectionRef = new WeakReference<Connection>(connection);
+ }
+
+ public void dispose() {
+ mConnectionRef.clear();
+ }
+
+ @Override
+ public void onStateChanged(RemoteDisplayState state) throws RemoteException {
+ Connection connection = mConnectionRef.get();
+ if (connection != null) {
+ connection.postStateChanged(state);
+ }
+ }
+ }
+}
diff --git a/services/java/com/android/server/media/RemoteDisplayProviderWatcher.java b/services/java/com/android/server/media/RemoteDisplayProviderWatcher.java
new file mode 100644
index 0000000..6a5f563
--- /dev/null
+++ b/services/java/com/android/server/media/RemoteDisplayProviderWatcher.java
@@ -0,0 +1,219 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.media;
+
+import android.Manifest;
+import android.content.BroadcastReceiver;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
+import android.content.pm.ServiceInfo;
+import android.media.RemoteDisplayState;
+import android.os.Handler;
+import android.os.UserHandle;
+import android.util.Log;
+import android.util.Slog;
+
+import java.io.PrintWriter;
+import java.util.ArrayList;
+import java.util.Collections;
+
+/**
+ * Watches for remote display provider services to be installed.
+ * Adds a provider to the media router for each registered service.
+ *
+ * @see RemoteDisplayProviderProxy
+ */
+public final class RemoteDisplayProviderWatcher {
+ private static final String TAG = "RemoteDisplayProvider"; // max. 23 chars
+ private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
+
+ private final Context mContext;
+ private final Callback mCallback;
+ private final Handler mHandler;
+ private final int mUserId;
+ private final PackageManager mPackageManager;
+
+ private final ArrayList<RemoteDisplayProviderProxy> mProviders =
+ new ArrayList<RemoteDisplayProviderProxy>();
+ private boolean mRunning;
+
+ public RemoteDisplayProviderWatcher(Context context,
+ Callback callback, Handler handler, int userId) {
+ mContext = context;
+ mCallback = callback;
+ mHandler = handler;
+ mUserId = userId;
+ mPackageManager = context.getPackageManager();
+ }
+
+ public void dump(PrintWriter pw, String prefix) {
+ pw.println(prefix + "Watcher");
+ pw.println(prefix + " mUserId=" + mUserId);
+ pw.println(prefix + " mRunning=" + mRunning);
+ pw.println(prefix + " mProviders.size()=" + mProviders.size());
+ }
+
+ public void start() {
+ if (!mRunning) {
+ mRunning = true;
+
+ IntentFilter filter = new IntentFilter();
+ filter.addAction(Intent.ACTION_PACKAGE_ADDED);
+ filter.addAction(Intent.ACTION_PACKAGE_REMOVED);
+ filter.addAction(Intent.ACTION_PACKAGE_CHANGED);
+ filter.addAction(Intent.ACTION_PACKAGE_REPLACED);
+ filter.addAction(Intent.ACTION_PACKAGE_RESTARTED);
+ filter.addDataScheme("package");
+ mContext.registerReceiverAsUser(mScanPackagesReceiver,
+ new UserHandle(mUserId), filter, null, mHandler);
+
+ // Scan packages.
+ // Also has the side-effect of restarting providers if needed.
+ mHandler.post(mScanPackagesRunnable);
+ }
+ }
+
+ public void stop() {
+ if (mRunning) {
+ mRunning = false;
+
+ mContext.unregisterReceiver(mScanPackagesReceiver);
+ mHandler.removeCallbacks(mScanPackagesRunnable);
+
+ // Stop all providers.
+ for (int i = mProviders.size() - 1; i >= 0; i--) {
+ mProviders.get(i).stop();
+ }
+ }
+ }
+
+ private void scanPackages() {
+ if (!mRunning) {
+ return;
+ }
+
+ // Add providers for all new services.
+ // Reorder the list so that providers left at the end will be the ones to remove.
+ int targetIndex = 0;
+ Intent intent = new Intent(RemoteDisplayState.SERVICE_INTERFACE);
+ for (ResolveInfo resolveInfo : mPackageManager.queryIntentServicesAsUser(
+ intent, 0, mUserId)) {
+ ServiceInfo serviceInfo = resolveInfo.serviceInfo;
+ if (serviceInfo != null && verifyServiceTrusted(serviceInfo)) {
+ int sourceIndex = findProvider(serviceInfo.packageName, serviceInfo.name);
+ if (sourceIndex < 0) {
+ RemoteDisplayProviderProxy provider =
+ new RemoteDisplayProviderProxy(mContext,
+ new ComponentName(serviceInfo.packageName, serviceInfo.name),
+ mUserId);
+ provider.start();
+ mProviders.add(targetIndex++, provider);
+ mCallback.addProvider(provider);
+ } else if (sourceIndex >= targetIndex) {
+ RemoteDisplayProviderProxy provider = mProviders.get(sourceIndex);
+ provider.start(); // restart the provider if needed
+ provider.rebindIfDisconnected();
+ Collections.swap(mProviders, sourceIndex, targetIndex++);
+ }
+ }
+ }
+
+ // Remove providers for missing services.
+ if (targetIndex < mProviders.size()) {
+ for (int i = mProviders.size() - 1; i >= targetIndex; i--) {
+ RemoteDisplayProviderProxy provider = mProviders.get(i);
+ mCallback.removeProvider(provider);
+ mProviders.remove(provider);
+ provider.stop();
+ }
+ }
+ }
+
+ private boolean verifyServiceTrusted(ServiceInfo serviceInfo) {
+ if (serviceInfo.permission == null || !serviceInfo.permission.equals(
+ Manifest.permission.BIND_REMOTE_DISPLAY)) {
+ // If the service does not require this permission then any app could
+ // potentially bind to it and cause the remote display service to
+ // misbehave. So we only want to trust providers that require the
+ // correct permissions.
+ Slog.w(TAG, "Ignoring remote display provider service because it did not "
+ + "require the BIND_REMOTE_DISPLAY permission in its manifest: "
+ + serviceInfo.packageName + "/" + serviceInfo.name);
+ return false;
+ }
+ if (!hasCaptureVideoPermission(serviceInfo.packageName)) {
+ // If the service does not have permission to capture video then it
+ // isn't going to be terribly useful as a remote display, is it?
+ // Kind of makes you wonder what it's doing there in the first place.
+ Slog.w(TAG, "Ignoring remote display provider service because it does not "
+ + "have the CAPTURE_VIDEO_OUTPUT or CAPTURE_SECURE_VIDEO_OUTPUT "
+ + "permission: " + serviceInfo.packageName + "/" + serviceInfo.name);
+ return false;
+ }
+ // Looks good.
+ return true;
+ }
+
+ private boolean hasCaptureVideoPermission(String packageName) {
+ if (mPackageManager.checkPermission(Manifest.permission.CAPTURE_VIDEO_OUTPUT,
+ packageName) == PackageManager.PERMISSION_GRANTED) {
+ return true;
+ }
+ if (mPackageManager.checkPermission(Manifest.permission.CAPTURE_SECURE_VIDEO_OUTPUT,
+ packageName) == PackageManager.PERMISSION_GRANTED) {
+ return true;
+ }
+ return false;
+ }
+
+ private int findProvider(String packageName, String className) {
+ int count = mProviders.size();
+ for (int i = 0; i < count; i++) {
+ RemoteDisplayProviderProxy provider = mProviders.get(i);
+ if (provider.hasComponentName(packageName, className)) {
+ return i;
+ }
+ }
+ return -1;
+ }
+
+ private final BroadcastReceiver mScanPackagesReceiver = new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ if (DEBUG) {
+ Slog.d(TAG, "Received package manager broadcast: " + intent);
+ }
+ scanPackages();
+ }
+ };
+
+ private final Runnable mScanPackagesRunnable = new Runnable() {
+ @Override
+ public void run() {
+ scanPackages();
+ }
+ };
+
+ public interface Callback {
+ void addProvider(RemoteDisplayProviderProxy provider);
+ void removeProvider(RemoteDisplayProviderProxy provider);
+ }
+}
diff --git a/services/java/com/android/server/pm/PackageManagerService.java b/services/java/com/android/server/pm/PackageManagerService.java
index 7291dd4..5450fd0 100755
--- a/services/java/com/android/server/pm/PackageManagerService.java
+++ b/services/java/com/android/server/pm/PackageManagerService.java
@@ -1278,7 +1278,8 @@
frameworkDir.getPath(), OBSERVER_EVENTS, true, false);
mFrameworkInstallObserver.startWatching();
scanDirLI(frameworkDir, PackageParser.PARSE_IS_SYSTEM
- | PackageParser.PARSE_IS_SYSTEM_DIR,
+ | PackageParser.PARSE_IS_SYSTEM_DIR
+ | PackageParser.PARSE_IS_PRIVILEGED,
scanMode | SCAN_NO_DEX, 0);
// Collected privileged system packages.
@@ -1771,6 +1772,24 @@
state, userId);
}
+ public boolean isPackageAvailable(String packageName, int userId) {
+ if (!sUserManager.exists(userId)) return false;
+ enforceCrossUserPermission(Binder.getCallingUid(), userId, false, "is package available");
+ synchronized (mPackages) {
+ PackageParser.Package p = mPackages.get(packageName);
+ if (p != null) {
+ final PackageSetting ps = (PackageSetting) p.mExtras;
+ if (ps != null) {
+ final PackageUserState state = ps.readUserState(userId);
+ if (state != null) {
+ return PackageParser.isAvailable(state);
+ }
+ }
+ }
+ }
+ return false;
+ }
+
@Override
public PackageInfo getPackageInfo(String packageName, int flags, int userId) {
if (!sUserManager.exists(userId)) return null;
@@ -10011,11 +10030,11 @@
}
if (filter.countDataAuthorities() != 0
|| filter.countDataPaths() != 0
- || filter.countDataSchemes() != 0
+ || filter.countDataSchemes() > 1
|| filter.countDataTypes() != 0) {
throw new IllegalArgumentException(
"replacePreferredActivity expects filter to have no data authorities, " +
- "paths, schemes or types.");
+ "paths, or types; and at most one scheme.");
}
synchronized (mPackages) {
if (mContext.checkCallingOrSelfPermission(
@@ -10032,33 +10051,27 @@
}
final int callingUserId = UserHandle.getCallingUserId();
- ArrayList<PreferredActivity> removed = null;
PreferredIntentResolver pir = mSettings.mPreferredActivities.get(callingUserId);
if (pir != null) {
- Iterator<PreferredActivity> it = pir.filterIterator();
- String action = filter.getAction(0);
- String category = filter.getCategory(0);
- while (it.hasNext()) {
- PreferredActivity pa = it.next();
- if ((pa.countActions() == 0) || (pa.countCategories() == 0)
- || (pa.getAction(0).equals(action)
- && pa.getCategory(0).equals(category))) {
- if (removed == null) {
- removed = new ArrayList<PreferredActivity>();
- }
- removed.add(pa);
- if (DEBUG_PREFERRED) {
- Slog.i(TAG, "Removing preferred activity "
- + pa.mPref.mComponent + ":");
- filter.dump(new LogPrinter(Log.INFO, TAG), " ");
- }
- }
+ Intent intent = new Intent(filter.getAction(0)).addCategory(filter.getCategory(0));
+ if (filter.countDataSchemes() == 1) {
+ Uri.Builder builder = new Uri.Builder();
+ builder.scheme(filter.getDataScheme(0));
+ intent.setData(builder.build());
}
- if (removed != null) {
- for (int i=0; i<removed.size(); i++) {
- PreferredActivity pa = removed.get(i);
- pir.removeFilter(pa);
+ List<PreferredActivity> matches = pir.queryIntent(
+ intent, null, true, callingUserId);
+ if (DEBUG_PREFERRED) {
+ Slog.i(TAG, matches.size() + " preferred matches for " + intent);
+ }
+ for (int i = 0; i < matches.size(); i++) {
+ PreferredActivity pa = matches.get(i);
+ if (DEBUG_PREFERRED) {
+ Slog.i(TAG, "Removing preferred activity "
+ + pa.mPref.mComponent + ":");
+ filter.dump(new LogPrinter(Log.INFO, TAG), " ");
}
+ pir.removeFilter(pa);
}
}
addPreferredActivityInternal(filter, match, set, activity, true, callingUserId);
diff --git a/services/java/com/android/server/wifi/WifiService.java b/services/java/com/android/server/wifi/WifiService.java
index d471b57..f2efde1 100644
--- a/services/java/com/android/server/wifi/WifiService.java
+++ b/services/java/com/android/server/wifi/WifiService.java
@@ -369,15 +369,17 @@
}
private class BatchedScanRequest extends DeathRecipient {
- BatchedScanSettings settings;
- int uid;
- int pid;
+ final BatchedScanSettings settings;
+ final int uid;
+ final int pid;
+ final WorkSource workSource;
- BatchedScanRequest(BatchedScanSettings settings, IBinder binder) {
+ BatchedScanRequest(BatchedScanSettings settings, IBinder binder, WorkSource ws) {
super(0, null, binder, null);
this.settings = settings;
this.uid = getCallingUid();
this.pid = getCallingPid();
+ workSource = ws;
}
public void binderDied() {
stopBatchedScan(settings, uid, pid);
@@ -406,12 +408,19 @@
/**
* see {@link android.net.wifi.WifiManager#requestBatchedScan()}
*/
- public boolean requestBatchedScan(BatchedScanSettings requested, IBinder binder) {
+ public boolean requestBatchedScan(BatchedScanSettings requested, IBinder binder,
+ WorkSource workSource) {
enforceChangePermission();
+ if (workSource != null) {
+ enforceWorkSourcePermission();
+ // WifiManager currently doesn't use names, so need to clear names out of the
+ // supplied WorkSource to allow future WorkSource combining.
+ workSource.clearNames();
+ }
if (mBatchedScanSupported == false) return false;
requested = new BatchedScanSettings(requested);
if (requested.isInvalid()) return false;
- BatchedScanRequest r = new BatchedScanRequest(requested, binder);
+ BatchedScanRequest r = new BatchedScanRequest(requested, binder, workSource);
synchronized(mBatchedScanners) {
mBatchedScanners.add(r);
resolveBatchedScannersLocked();
@@ -468,18 +477,48 @@
private void resolveBatchedScannersLocked() {
BatchedScanSettings setting = new BatchedScanSettings();
+ WorkSource responsibleWorkSource = null;
int responsibleUid = 0;
+ double responsibleCsph = 0; // Channel Scans Per Hour
if (mBatchedScanners.size() == 0) {
- mWifiStateMachine.setBatchedScanSettings(null, 0);
+ mWifiStateMachine.setBatchedScanSettings(null, 0, 0, null);
return;
}
for (BatchedScanRequest r : mBatchedScanners) {
BatchedScanSettings s = r.settings;
+
+ // evaluate responsibility
+ int currentChannelCount;
+ int currentScanInterval;
+ double currentCsph;
+
+ if (s.channelSet == null || s.channelSet.isEmpty()) {
+ // all channels - 11 B and 9 A channels roughly.
+ currentChannelCount = 9 + 11;
+ } else {
+ currentChannelCount = s.channelSet.size();
+ // these are rough est - no real need to correct for reg-domain;
+ if (s.channelSet.contains("A")) currentChannelCount += (9 - 1);
+ if (s.channelSet.contains("B")) currentChannelCount += (11 - 1);
+
+ }
+ if (s.scanIntervalSec == BatchedScanSettings.UNSPECIFIED) {
+ currentScanInterval = BatchedScanSettings.DEFAULT_INTERVAL_SEC;
+ } else {
+ currentScanInterval = s.scanIntervalSec;
+ }
+ currentCsph = 60 * 60 * currentChannelCount / currentScanInterval;
+
+ if (currentCsph > responsibleCsph) {
+ responsibleUid = r.uid;
+ responsibleWorkSource = r.workSource;
+ responsibleCsph = currentCsph;
+ }
+
if (s.maxScansPerBatch != BatchedScanSettings.UNSPECIFIED &&
s.maxScansPerBatch < setting.maxScansPerBatch) {
setting.maxScansPerBatch = s.maxScansPerBatch;
- responsibleUid = r.uid;
}
if (s.maxApPerScan != BatchedScanSettings.UNSPECIFIED &&
(setting.maxApPerScan == BatchedScanSettings.UNSPECIFIED ||
@@ -489,7 +528,6 @@
if (s.scanIntervalSec != BatchedScanSettings.UNSPECIFIED &&
s.scanIntervalSec < setting.scanIntervalSec) {
setting.scanIntervalSec = s.scanIntervalSec;
- responsibleUid = r.uid;
}
if (s.maxApForDistance != BatchedScanSettings.UNSPECIFIED &&
(setting.maxApForDistance == BatchedScanSettings.UNSPECIFIED ||
@@ -511,7 +549,8 @@
}
setting.constrain();
- mWifiStateMachine.setBatchedScanSettings(setting, responsibleUid);
+ mWifiStateMachine.setBatchedScanSettings(setting, responsibleUid, (int)responsibleCsph,
+ responsibleWorkSource);
}
private void enforceAccessPermission() {
diff --git a/services/java/com/android/server/wm/AppWindowToken.java b/services/java/com/android/server/wm/AppWindowToken.java
index 8cc1d02..e98014b 100644
--- a/services/java/com/android/server/wm/AppWindowToken.java
+++ b/services/java/com/android/server/wm/AppWindowToken.java
@@ -53,6 +53,7 @@
int groupId = -1;
boolean appFullscreen;
int requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
+ boolean layoutConfigChanges;
boolean showWhenLocked;
// The input dispatching timeout for this application token in nanoseconds.
diff --git a/services/java/com/android/server/wm/DisplayContent.java b/services/java/com/android/server/wm/DisplayContent.java
index 52f2325..d358b4c 100644
--- a/services/java/com/android/server/wm/DisplayContent.java
+++ b/services/java/com/android/server/wm/DisplayContent.java
@@ -25,9 +25,11 @@
import android.graphics.Rect;
import android.graphics.Region;
import android.os.Debug;
+import android.util.EventLog;
import android.util.Slog;
import android.view.Display;
import android.view.DisplayInfo;
+import com.android.server.EventLogTags;
import java.io.PrintWriter;
import java.util.ArrayList;
@@ -97,9 +99,6 @@
/** True when the home StackBox is at the top of mStackBoxes, false otherwise. */
private TaskStack mHomeStack = null;
- /** Sorted most recent at top, oldest at [0]. */
- ArrayList<TaskStack> mStackHistory = new ArrayList<TaskStack>();
-
/** Detect user tapping outside of current focused stack bounds .*/
StackTapPointerEventListener mTapDetector;
@@ -107,7 +106,7 @@
Region mTouchExcludeRegion = new Region();
/** Save allocating when retrieving tasks */
- ArrayList<Task> mTaskHistory = new ArrayList<Task>();
+ private ArrayList<Task> mTaskHistory = new ArrayList<Task>();
/** Save allocating when calculating rects */
Rect mTmpRect = new Rect();
@@ -160,12 +159,6 @@
return mStackBoxes.get(0).mStack != mHomeStack;
}
- void moveStack(TaskStack stack, boolean toTop) {
- mStackHistory.remove(stack);
- mStackHistory.add(toTop ? mStackHistory.size() : 0, stack);
- mService.moveStackWindowsLocked(this);
- }
-
public boolean isPrivate() {
return (mDisplay.getFlags() & Display.FLAG_PRIVATE) != 0;
}
@@ -200,6 +193,7 @@
}
mTaskHistory.add(taskNdx, task);
+ EventLog.writeEvent(EventLogTags.WM_TASK_MOVED, task.taskId, toTop ? 1 : 0, taskNdx);
}
void removeTask(Task task) {
@@ -277,6 +271,8 @@
if (newStack != null) {
layoutNeeded = true;
}
+ EventLog.writeEvent(EventLogTags.WM_STACK_CREATED, stackId, relativeStackBoxId, position,
+ (int)(weight * 100 + 0.5));
return newStack;
}
@@ -345,6 +341,7 @@
boolean moveHomeStackBox(boolean toTop) {
if (DEBUG_STACK) Slog.d(TAG, "moveHomeStackBox: toTop=" + toTop + " Callers=" +
Debug.getCallers(4));
+ EventLog.writeEvent(EventLogTags.WM_HOME_STACK_MOVED, toTop ? 1 : 0);
switch (mStackBoxes.size()) {
case 0: throw new RuntimeException("moveHomeStackBox: No home StackBox!");
case 1: return false; // Only the home StackBox exists.
diff --git a/services/java/com/android/server/wm/StackBox.java b/services/java/com/android/server/wm/StackBox.java
index d054e9a..d351925 100644
--- a/services/java/com/android/server/wm/StackBox.java
+++ b/services/java/com/android/server/wm/StackBox.java
@@ -243,10 +243,6 @@
/** Remove this box and propagate its sibling's content up to their parent.
* @return The first stackId of the resulting StackBox. */
int remove() {
- if (mStack != null) {
- if (DEBUG_STACK) Slog.i(TAG, "StackBox.remove: removing stackId=" + mStack.mStackId);
- mDisplayContent.mStackHistory.remove(mStack);
- }
mDisplayContent.layoutNeeded = true;
if (mParent == null) {
diff --git a/services/java/com/android/server/wm/Task.java b/services/java/com/android/server/wm/Task.java
index d9acbb9..13fdbc8 100644
--- a/services/java/com/android/server/wm/Task.java
+++ b/services/java/com/android/server/wm/Task.java
@@ -16,6 +16,9 @@
package com.android.server.wm;
+import android.util.EventLog;
+import com.android.server.EventLogTags;
+
class Task {
// private final String TAG = "TaskGroup";
TaskStack mStack;
@@ -41,6 +44,8 @@
boolean removeAppToken(AppWindowToken wtoken) {
mAppTokens.remove(wtoken);
if (mAppTokens.size() == 0) {
+ EventLog.writeEvent(com.android.server.EventLogTags.WM_TASK_REMOVED, taskId,
+ "removeAppToken: last token");
mStack.removeTask(this);
return true;
}
diff --git a/services/java/com/android/server/wm/TaskStack.java b/services/java/com/android/server/wm/TaskStack.java
index 34bef68..cb29df4 100644
--- a/services/java/com/android/server/wm/TaskStack.java
+++ b/services/java/com/android/server/wm/TaskStack.java
@@ -21,8 +21,10 @@
import android.graphics.Rect;
import android.os.Debug;
+import android.util.EventLog;
import android.util.Slog;
import android.util.TypedValue;
+import com.android.server.EventLogTags;
import static com.android.server.am.ActivityStackSupervisor.HOME_STACK_ID;
@@ -45,7 +47,7 @@
/** The Tasks that define this stack. Oldest Tasks are at the bottom. The ordering must match
* mTaskHistory in the ActivityStack with the same mStackId */
- private ArrayList<Task> mTasks = new ArrayList<Task>();
+ private final ArrayList<Task> mTasks = new ArrayList<Task>();
/** The StackBox this sits in. */
StackBox mStackBox;
@@ -70,7 +72,6 @@
mService = service;
mStackId = stackId;
mDisplayContent = displayContent;
- final int displayId = displayContent.getDisplayId();
mDimLayer = new DimLayer(service, this);
mAnimationBackgroundSurface = new DimLayer(service, this);
}
@@ -152,6 +153,7 @@
int remove() {
mAnimationBackgroundSurface.destroySurface();
mDimLayer.destroySurface();
+ EventLog.writeEvent(EventLogTags.WM_STACK_REMOVED, mStackId);
return mStackBox.remove();
}
@@ -269,6 +271,8 @@
for (int winNdx = windows.size() - 1; winNdx >= 0; --winNdx) {
final WindowState win = windows.get(winNdx);
if (!resizingWindows.contains(win)) {
+ if (WindowManagerService.DEBUG_RESIZE) Slog.d(TAG,
+ "setBounds: Resizing " + win);
resizingWindows.add(win);
}
win.mUnderStatusBar = underStatusBar;
diff --git a/services/java/com/android/server/wm/WindowAnimator.java b/services/java/com/android/server/wm/WindowAnimator.java
index cd46bb8..91f15f3 100644
--- a/services/java/com/android/server/wm/WindowAnimator.java
+++ b/services/java/com/android/server/wm/WindowAnimator.java
@@ -245,7 +245,7 @@
mForceHiding = KEYGUARD_ANIMATING_OUT;
}
} else {
- mForceHiding = KEYGUARD_SHOWN;
+ mForceHiding = win.isDrawnLw() ? KEYGUARD_SHOWN : KEYGUARD_NOT_SHOWN;
}
}
if (WindowManagerService.DEBUG_VISIBILITY) Slog.v(TAG,
diff --git a/services/java/com/android/server/wm/WindowManagerService.java b/services/java/com/android/server/wm/WindowManagerService.java
index e1e9f5c..3ed5076 100644
--- a/services/java/com/android/server/wm/WindowManagerService.java
+++ b/services/java/com/android/server/wm/WindowManagerService.java
@@ -578,10 +578,13 @@
private boolean mUpdateRotation = false;
boolean mWallpaperActionPending = false;
- private static final int DISPLAY_CONTENT_UNKNOWN = 0;
- private static final int DISPLAY_CONTENT_MIRROR = 1;
- private static final int DISPLAY_CONTENT_UNIQUE = 2;
- private int mDisplayHasContent = DISPLAY_CONTENT_UNKNOWN;
+ // Set to true when the display contains content to show the user.
+ // When false, the display manager may choose to mirror or blank the display.
+ boolean mDisplayHasContent = false;
+
+ // Only set while traversing the default display based on its content.
+ // Affects the behavior of mirroring on secondary displays.
+ boolean mObscureApplicationContentOnSecondaryDisplays = false;
}
final LayoutFields mInnerFields = new LayoutFields();
@@ -3394,16 +3397,17 @@
if (stack == null) {
throw new IllegalArgumentException("addAppToken: invalid stackId=" + stackId);
}
+ EventLog.writeEvent(EventLogTags.WM_TASK_CREATED, taskId, stackId);
Task task = new Task(atoken, stack, userId);
mTaskIdToTask.put(taskId, task);
stack.addTask(task, true);
- stack.getDisplayContent().moveStack(stack, true);
return task;
}
@Override
public void addAppToken(int addPos, IApplicationToken token, int taskId, int stackId,
- int requestedOrientation, boolean fullscreen, boolean showWhenLocked, int userId) {
+ int requestedOrientation, boolean fullscreen, boolean showWhenLocked, int userId,
+ int configChanges) {
if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS,
"addAppToken()")) {
throw new SecurityException("Requires MANAGE_APP_TOKENS permission");
@@ -3435,6 +3439,8 @@
atoken.appFullscreen = fullscreen;
atoken.showWhenLocked = showWhenLocked;
atoken.requestedOrientation = requestedOrientation;
+ atoken.layoutConfigChanges = (configChanges &
+ (ActivityInfo.CONFIG_SCREEN_SIZE | ActivityInfo.CONFIG_ORIENTATION)) != 0;
if (DEBUG_TOKEN_MOVEMENT || DEBUG_ADD_REMOVE) Slog.v(TAG, "addAppToken: " + atoken
+ " to stack=" + stackId + " task=" + taskId + " at " + addPos);
@@ -4303,10 +4309,6 @@
// If we are preparing an app transition, then delay changing
// the visibility of this token until we execute that transition.
if (okToDisplay() && mAppTransition.isTransitionSet()) {
- // Already in requested state, don't do anything more.
- if (wtoken.hiddenRequested != visible) {
- return;
- }
wtoken.hiddenRequested = !visible;
if (!wtoken.startingDisplayed) {
@@ -4792,7 +4794,6 @@
displayContent.moveHomeStackBox(isHomeStackTask);
}
stack.moveTaskToTop(task);
- displayContent.moveStack(stack, true);
}
} finally {
Binder.restoreCallingIdentity(origId);
@@ -4846,7 +4847,6 @@
weight);
if (stack != null) {
mStackIdToStack.put(stackId, stack);
- displayContent.moveStack(stack, true);
performLayoutAndPlaceSurfacesLocked();
return;
}
@@ -4878,6 +4878,7 @@
return;
}
final TaskStack stack = task.mStack;
+ EventLog.writeEvent(EventLogTags.WM_TASK_REMOVED, taskId, "removeTask");
stack.removeTask(task);
stack.getDisplayContent().layoutNeeded = true;
}
@@ -8269,8 +8270,9 @@
// windows, since that means "perform layout as normal,
// just don't display").
if (!gone || !win.mHaveFrame || win.mLayoutNeeded
- || win.mAttrs.type == TYPE_KEYGUARD && win.isConfigChanged()
- || mOpeningApps.contains(win.mAppToken)
+ || ((win.isConfigChanged() || win.setInsetsChanged()) &&
+ (win.mAttrs.type == TYPE_KEYGUARD ||
+ win.mAppToken != null && win.mAppToken.layoutConfigChanges))
|| win.mAttrs.type == TYPE_UNIVERSE_BACKGROUND) {
if (!win.mLayoutAttached) {
if (initial) {
@@ -8704,12 +8706,7 @@
private void updateResizingWindows(final WindowState w) {
final WindowStateAnimator winAnimator = w.mWinAnimator;
if (w.mHasSurface && w.mLayoutSeq == mLayoutSeq) {
- w.mOverscanInsetsChanged |=
- !w.mLastOverscanInsets.equals(w.mOverscanInsets);
- w.mContentInsetsChanged |=
- !w.mLastContentInsets.equals(w.mContentInsets);
- w.mVisibleInsetsChanged |=
- !w.mLastVisibleInsets.equals(w.mVisibleInsets);
+ w.setInsetsChanged();
boolean configChanged = w.isConfigChanged();
if (DEBUG_CONFIGURATION && configChanged) {
Slog.v(TAG, "Win " + w + " config changed: "
@@ -8784,6 +8781,14 @@
final WindowManager.LayoutParams attrs = w.mAttrs;
final int attrFlags = attrs.flags;
final boolean canBeSeen = w.isDisplayedLw();
+ final boolean opaqueDrawn = canBeSeen && w.isOpaqueDrawn();
+
+ if (opaqueDrawn && w.isFullscreen(innerDw, innerDh)) {
+ // This window completely covers everything behind it,
+ // so we want to leave all of them as undimmed (for
+ // performance reasons).
+ mInnerFields.mObscured = true;
+ }
if (w.mHasSurface) {
if ((attrFlags&FLAG_KEEP_SCREEN_ON) != 0) {
@@ -8812,22 +8817,24 @@
}
if (canBeSeen) {
- if (type == TYPE_DREAM || type == TYPE_KEYGUARD) {
- mInnerFields.mDisplayHasContent = LayoutFields.DISPLAY_CONTENT_MIRROR;
- } else if (mInnerFields.mDisplayHasContent
- == LayoutFields.DISPLAY_CONTENT_UNKNOWN) {
- mInnerFields.mDisplayHasContent = LayoutFields.DISPLAY_CONTENT_UNIQUE;
+ // This function assumes that the contents of the default display are
+ // processed first before secondary displays.
+ if (w.mDisplayContent.isDefaultDisplay) {
+ // While a dream or keyguard is showing, obscure ordinary application
+ // content on secondary displays (by forcibly enabling mirroring unless
+ // there is other content we want to show) but still allow opaque
+ // keyguard dialogs to be shown.
+ if (type == TYPE_DREAM || type == TYPE_KEYGUARD) {
+ mInnerFields.mObscureApplicationContentOnSecondaryDisplays = true;
+ }
+ mInnerFields.mDisplayHasContent = true;
+ } else if (!mInnerFields.mObscureApplicationContentOnSecondaryDisplays
+ || (mInnerFields.mObscured && type == TYPE_KEYGUARD_DIALOG)) {
+ // Allow full screen keyguard presentation dialogs to be seen.
+ mInnerFields.mDisplayHasContent = true;
}
}
}
-
- boolean opaqueDrawn = canBeSeen && w.isOpaqueDrawn();
- if (opaqueDrawn && w.isFullscreen(innerDw, innerDh)) {
- // This window completely covers everything behind it,
- // so we want to leave all of them as undimmed (for
- // performance reasons).
- mInnerFields.mObscured = true;
- }
}
private void handleFlagDimBehind(WindowState w, int innerDw, int innerDh) {
@@ -8905,7 +8912,7 @@
mInnerFields.mScreenBrightness = -1;
mInnerFields.mButtonBrightness = -1;
mInnerFields.mUserActivityTimeout = -1;
- mInnerFields.mDisplayHasContent = LayoutFields.DISPLAY_CONTENT_UNKNOWN;
+ mInnerFields.mObscureApplicationContentOnSecondaryDisplays = false;
mTransactionSequence++;
@@ -8940,10 +8947,8 @@
final int innerDh = displayInfo.appHeight;
final boolean isDefaultDisplay = (displayId == Display.DEFAULT_DISPLAY);
- // Reset for each display unless we are forcing mirroring.
- if (mInnerFields.mDisplayHasContent != LayoutFields.DISPLAY_CONTENT_MIRROR) {
- mInnerFields.mDisplayHasContent = LayoutFields.DISPLAY_CONTENT_UNKNOWN;
- }
+ // Reset for each display.
+ mInnerFields.mDisplayHasContent = false;
int repeats = 0;
do {
@@ -9152,20 +9157,8 @@
updateResizingWindows(w);
}
- final boolean hasUniqueContent;
- switch (mInnerFields.mDisplayHasContent) {
- case LayoutFields.DISPLAY_CONTENT_MIRROR:
- hasUniqueContent = isDefaultDisplay;
- break;
- case LayoutFields.DISPLAY_CONTENT_UNIQUE:
- hasUniqueContent = true;
- break;
- case LayoutFields.DISPLAY_CONTENT_UNKNOWN:
- default:
- hasUniqueContent = false;
- break;
- }
- mDisplayManagerService.setDisplayHasContent(displayId, hasUniqueContent,
+ mDisplayManagerService.setDisplayHasContent(displayId,
+ mInnerFields.mDisplayHasContent,
true /* inTraversal, must call performTraversalInTrans... below */);
getDisplayContentLocked(displayId).stopDimmingIfNeeded();
diff --git a/services/java/com/android/server/wm/WindowState.java b/services/java/com/android/server/wm/WindowState.java
index 2d08792..4d53cea 100644
--- a/services/java/com/android/server/wm/WindowState.java
+++ b/services/java/com/android/server/wm/WindowState.java
@@ -701,6 +701,13 @@
return mAppToken != null ? mAppToken.appToken : null;
}
+ boolean setInsetsChanged() {
+ mOverscanInsetsChanged |= !mLastOverscanInsets.equals(mOverscanInsets);
+ mContentInsetsChanged |= !mLastContentInsets.equals(mContentInsets);
+ mVisibleInsetsChanged |= !mLastVisibleInsets.equals(mVisibleInsets);
+ return mOverscanInsetsChanged || mContentInsetsChanged || mVisibleInsetsChanged;
+ }
+
public int getDisplayId() {
return mDisplayContent.getDisplayId();
}
diff --git a/tests/RemoteDisplayProvider/Android.mk b/tests/RemoteDisplayProvider/Android.mk
new file mode 100644
index 0000000..2f4b343
--- /dev/null
+++ b/tests/RemoteDisplayProvider/Android.mk
@@ -0,0 +1,26 @@
+# Copyright (C) 2013 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)
+
+# Build the application.
+include $(CLEAR_VARS)
+LOCAL_PACKAGE_NAME := RemoteDisplayProviderTest
+LOCAL_MODULE_TAGS := tests
+LOCAL_SDK_VERSION := current
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
+LOCAL_RESOURCE_DIR = $(LOCAL_PATH)/res
+LOCAL_JAVA_LIBRARIES := com.android.media.remotedisplay
+LOCAL_CERTIFICATE := platform
+include $(BUILD_PACKAGE)
diff --git a/tests/RemoteDisplayProvider/AndroidManifest.xml b/tests/RemoteDisplayProvider/AndroidManifest.xml
new file mode 100644
index 0000000..afb7c78
--- /dev/null
+++ b/tests/RemoteDisplayProvider/AndroidManifest.xml
@@ -0,0 +1,38 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2013 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.media.remotedisplay.test" >
+
+ <uses-sdk android:minSdkVersion="19" />
+ <uses-permission android:name="android.permission.CAPTURE_VIDEO_OUTPUT"/>
+
+ <application android:label="@string/app_name"
+ android:icon="@drawable/ic_app">
+ <uses-library android:name="com.android.media.remotedisplay"
+ android:required="true" />
+
+ <service android:name=".RemoteDisplayProviderService"
+ android:label="@string/app_name"
+ android:exported="true"
+ android:permission="android.permission.BIND_REMOTE_DISPLAY">
+ <intent-filter>
+ <action android:name="com.android.media.remotedisplay.RemoteDisplayProvider"/>
+ </intent-filter>
+ </service>
+
+ </application>
+</manifest>
diff --git a/tests/RemoteDisplayProvider/README b/tests/RemoteDisplayProvider/README
new file mode 100644
index 0000000..8bf0130
--- /dev/null
+++ b/tests/RemoteDisplayProvider/README
@@ -0,0 +1,16 @@
+This directory contains sample code to test system integration with
+remote display providers using the API declared by the
+com.android.media.remotedisplay.jar library.
+
+--- DESCRIPTION ---
+
+The application registers a service that publishes a few different
+remote display routes. Behavior can be controlled by modifying the
+code.
+
+To exercise the provider, use System UI features for connecting to
+wireless displays or launch an activity that uses the MediaRouter,
+such as the PresentationWithMediaRouterActivity in ApiDemos.
+
+This code is mainly intended for development and not meant to be
+used as an example implementation of a robust remote display provider.
diff --git a/tests/RemoteDisplayProvider/res/drawable-hdpi/ic_app.png b/tests/RemoteDisplayProvider/res/drawable-hdpi/ic_app.png
new file mode 100755
index 0000000..66a1984
--- /dev/null
+++ b/tests/RemoteDisplayProvider/res/drawable-hdpi/ic_app.png
Binary files differ
diff --git a/tests/RemoteDisplayProvider/res/drawable-mdpi/ic_app.png b/tests/RemoteDisplayProvider/res/drawable-mdpi/ic_app.png
new file mode 100644
index 0000000..5ae7701
--- /dev/null
+++ b/tests/RemoteDisplayProvider/res/drawable-mdpi/ic_app.png
Binary files differ
diff --git a/tests/RemoteDisplayProvider/res/values/strings.xml b/tests/RemoteDisplayProvider/res/values/strings.xml
new file mode 100644
index 0000000..dd82d2c
--- /dev/null
+++ b/tests/RemoteDisplayProvider/res/values/strings.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2013 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="app_name">Remote Display Provider Test</string>
+</resources>
diff --git a/tests/RemoteDisplayProvider/src/com/android/media/remotedisplay/test/RemoteDisplayProviderService.java b/tests/RemoteDisplayProvider/src/com/android/media/remotedisplay/test/RemoteDisplayProviderService.java
new file mode 100644
index 0000000..611d7e4
--- /dev/null
+++ b/tests/RemoteDisplayProvider/src/com/android/media/remotedisplay/test/RemoteDisplayProviderService.java
@@ -0,0 +1,321 @@
+/*
+ * Copyright (C) 2013 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.media.remotedisplay.test;
+
+import com.android.media.remotedisplay.RemoteDisplay;
+import com.android.media.remotedisplay.RemoteDisplayProvider;
+
+import android.app.Service;
+import android.content.Intent;
+import android.os.Handler;
+import android.os.IBinder;
+import android.util.Log;
+
+/**
+ * Remote display provider implementation that publishes working routes.
+ */
+public class RemoteDisplayProviderService extends Service {
+ private static final String TAG = "RemoteDisplayProviderTest";
+
+ private Provider mProvider;
+
+ @Override
+ public IBinder onBind(Intent intent) {
+ if (intent.getAction().equals(RemoteDisplayProvider.SERVICE_INTERFACE)) {
+ if (mProvider == null) {
+ mProvider = new Provider();
+ return mProvider.getBinder();
+ }
+ }
+ return null;
+ }
+
+ final class Provider extends RemoteDisplayProvider {
+ private RemoteDisplay mTestDisplay1; // variable volume
+ private RemoteDisplay mTestDisplay2; // fixed volume
+ private RemoteDisplay mTestDisplay3; // not available
+ private RemoteDisplay mTestDisplay4; // in use
+ private RemoteDisplay mTestDisplay5; // available but ignores request to connect
+ private RemoteDisplay mTestDisplay6; // available but never finishes connecting
+ private RemoteDisplay mTestDisplay7; // blinks in and out of existence
+ private RemoteDisplay mTestDisplay8; // available but connecting attempt flakes out
+ private RemoteDisplay mTestDisplay9; // available but connection flakes out
+ private RemoteDisplay mTestDisplay10; // available and reconnects periodically
+
+ private final Handler mHandler;
+ private boolean mBlinking;
+
+ public Provider() {
+ super(RemoteDisplayProviderService.this);
+ mHandler = new Handler(getMainLooper());
+ }
+
+ @Override
+ public void onDiscoveryModeChanged(int mode) {
+ Log.d(TAG, "onDiscoveryModeChanged: mode=" + mode);
+
+ if (mode != DISCOVERY_MODE_NONE) {
+ // When discovery begins, go find all of the routes.
+ if (mTestDisplay1 == null) {
+ mTestDisplay1 = new RemoteDisplay("testDisplay1",
+ "Test Display 1 (variable)");
+ mTestDisplay1.setDescription("Variable volume");
+ mTestDisplay1.setStatus(RemoteDisplay.STATUS_AVAILABLE);
+ mTestDisplay1.setVolume(10);
+ mTestDisplay1.setVolumeHandling(RemoteDisplay.PLAYBACK_VOLUME_VARIABLE);
+ mTestDisplay1.setVolumeMax(15);
+ addDisplay(mTestDisplay1);
+ }
+ if (mTestDisplay2 == null) {
+ mTestDisplay2 = new RemoteDisplay("testDisplay2",
+ "Test Display 2 (fixed)");
+ mTestDisplay2.setDescription("Fixed volume");
+ mTestDisplay2.setStatus(RemoteDisplay.STATUS_AVAILABLE);
+ addDisplay(mTestDisplay2);
+ }
+ if (mTestDisplay3 == null) {
+ mTestDisplay3 = new RemoteDisplay("testDisplay3",
+ "Test Display 3 (unavailable)");
+ mTestDisplay3.setDescription("Always unavailable");
+ mTestDisplay3.setStatus(RemoteDisplay.STATUS_NOT_AVAILABLE);
+ addDisplay(mTestDisplay3);
+ }
+ if (mTestDisplay4 == null) {
+ mTestDisplay4 = new RemoteDisplay("testDisplay4",
+ "Test Display 4 (in-use)");
+ mTestDisplay4.setDescription("Always in-use");
+ mTestDisplay4.setStatus(RemoteDisplay.STATUS_IN_USE);
+ addDisplay(mTestDisplay4);
+ }
+ if (mTestDisplay5 == null) {
+ mTestDisplay5 = new RemoteDisplay("testDisplay5",
+ "Test Display 5 (connect ignored)");
+ mTestDisplay5.setDescription("Ignores connect");
+ mTestDisplay5.setStatus(RemoteDisplay.STATUS_AVAILABLE);
+ addDisplay(mTestDisplay5);
+ }
+ if (mTestDisplay6 == null) {
+ mTestDisplay6 = new RemoteDisplay("testDisplay6",
+ "Test Display 6 (connect hangs)");
+ mTestDisplay6.setDescription("Never finishes connecting");
+ mTestDisplay6.setStatus(RemoteDisplay.STATUS_AVAILABLE);
+ addDisplay(mTestDisplay6);
+ }
+ if (mTestDisplay8 == null) {
+ mTestDisplay8 = new RemoteDisplay("testDisplay8",
+ "Test Display 8 (flaky when connecting)");
+ mTestDisplay8.setDescription("Aborts spontaneously while connecting");
+ mTestDisplay8.setStatus(RemoteDisplay.STATUS_AVAILABLE);
+ addDisplay(mTestDisplay8);
+ }
+ if (mTestDisplay9 == null) {
+ mTestDisplay9 = new RemoteDisplay("testDisplay9",
+ "Test Display 9 (flaky when connected)");
+ mTestDisplay9.setDescription("Aborts spontaneously while connected");
+ mTestDisplay9.setStatus(RemoteDisplay.STATUS_AVAILABLE);
+ addDisplay(mTestDisplay9);
+ }
+ if (mTestDisplay10 == null) {
+ mTestDisplay10 = new RemoteDisplay("testDisplay10",
+ "Test Display 10 (reconnects periodically)");
+ mTestDisplay10.setDescription("Reconnects spontaneously");
+ mTestDisplay10.setStatus(RemoteDisplay.STATUS_AVAILABLE);
+ addDisplay(mTestDisplay10);
+ }
+ } else {
+ // When discovery ends, go hide some of the routes we can't actually use.
+ // This isn't something a normal route provider would do though.
+ // The routes will usually stay published.
+ if (mTestDisplay3 != null) {
+ removeDisplay(mTestDisplay3);
+ mTestDisplay3 = null;
+ }
+ if (mTestDisplay4 != null) {
+ removeDisplay(mTestDisplay4);
+ mTestDisplay4 = null;
+ }
+ }
+
+ // When active discovery is on, pretend there's a route that we can't quite
+ // reach that blinks in and out of existence.
+ if (mode == DISCOVERY_MODE_ACTIVE) {
+ if (!mBlinking) {
+ mBlinking = true;
+ mHandler.post(mBlink);
+ }
+ } else {
+ mBlinking = false;
+ }
+ }
+
+ @Override
+ public void onConnect(final RemoteDisplay display) {
+ Log.d(TAG, "onConnect: display.getId()=" + display.getId());
+
+ if (display == mTestDisplay1 || display == mTestDisplay2) {
+ display.setStatus(RemoteDisplay.STATUS_CONNECTING);
+ updateDisplay(display);
+ mHandler.postDelayed(new Runnable() {
+ @Override
+ public void run() {
+ if ((display == mTestDisplay1 || display == mTestDisplay2)
+ && display.getStatus() == RemoteDisplay.STATUS_CONNECTING) {
+ display.setStatus(RemoteDisplay.STATUS_CONNECTED);
+ updateDisplay(display);
+ }
+ }
+ }, 2000);
+ } else if (display == mTestDisplay6 || display == mTestDisplay7) {
+ // never finishes connecting
+ display.setStatus(RemoteDisplay.STATUS_CONNECTING);
+ updateDisplay(display);
+ } else if (display == mTestDisplay8) {
+ // flakes out while connecting
+ display.setStatus(RemoteDisplay.STATUS_CONNECTING);
+ updateDisplay(display);
+ mHandler.postDelayed(new Runnable() {
+ @Override
+ public void run() {
+ if ((display == mTestDisplay8)
+ && display.getStatus() == RemoteDisplay.STATUS_CONNECTING) {
+ display.setStatus(RemoteDisplay.STATUS_AVAILABLE);
+ updateDisplay(display);
+ }
+ }
+ }, 2000);
+ } else if (display == mTestDisplay9) {
+ // flakes out when connected
+ display.setStatus(RemoteDisplay.STATUS_CONNECTING);
+ updateDisplay(display);
+ mHandler.postDelayed(new Runnable() {
+ @Override
+ public void run() {
+ if ((display == mTestDisplay9)
+ && display.getStatus() == RemoteDisplay.STATUS_CONNECTING) {
+ display.setStatus(RemoteDisplay.STATUS_CONNECTED);
+ updateDisplay(display);
+ }
+ }
+ }, 2000);
+ mHandler.postDelayed(new Runnable() {
+ @Override
+ public void run() {
+ if ((display == mTestDisplay9)
+ && display.getStatus() == RemoteDisplay.STATUS_CONNECTED) {
+ display.setStatus(RemoteDisplay.STATUS_AVAILABLE);
+ updateDisplay(display);
+ }
+ }
+ }, 5000);
+ } else if (display == mTestDisplay10) {
+ display.setStatus(RemoteDisplay.STATUS_CONNECTING);
+ updateDisplay(display);
+ mHandler.postDelayed(new Runnable() {
+ @Override
+ public void run() {
+ if (display == mTestDisplay10) {
+ if (display.getStatus() == RemoteDisplay.STATUS_CONNECTING) {
+ display.setStatus(RemoteDisplay.STATUS_CONNECTED);
+ updateDisplay(display);
+ mHandler.postDelayed(this, 7000);
+ } else if (display.getStatus() == RemoteDisplay.STATUS_CONNECTED) {
+ display.setStatus(RemoteDisplay.STATUS_CONNECTING);
+ updateDisplay(display);
+ mHandler.postDelayed(this, 2000);
+ }
+ }
+ }
+ }, 2000);
+ }
+ }
+
+ @Override
+ public void onDisconnect(RemoteDisplay display) {
+ Log.d(TAG, "onDisconnect: display.getId()=" + display.getId());
+
+ if (display == mTestDisplay1 || display == mTestDisplay2
+ || display == mTestDisplay6 || display == mTestDisplay8
+ || display == mTestDisplay9 || display == mTestDisplay10) {
+ display.setStatus(RemoteDisplay.STATUS_AVAILABLE);
+ updateDisplay(display);
+ }
+ }
+
+ @Override
+ public void onSetVolume(RemoteDisplay display, int volume) {
+ Log.d(TAG, "onSetVolume: display.getId()=" + display.getId()
+ + ", volume=" + volume);
+
+ if (display == mTestDisplay1) {
+ display.setVolume(Math.max(0, Math.min(display.getVolumeMax(), volume)));
+ updateDisplay(display);
+ }
+ }
+
+ @Override
+ public void onAdjustVolume(RemoteDisplay display, int delta) {
+ Log.d(TAG, "onAdjustVolume: display.getId()=" + display.getId()
+ + ", delta=" + delta);
+
+ if (display == mTestDisplay1) {
+ display.setVolume(Math.max(0, Math.min(display.getVolumeMax(),
+ display .getVolume() + delta)));
+ updateDisplay(display);
+ }
+ }
+
+ @Override
+ public void addDisplay(RemoteDisplay display) {
+ Log.d(TAG, "addDisplay: display=" + display);
+ super.addDisplay(display);
+ }
+
+ @Override
+ public void removeDisplay(RemoteDisplay display) {
+ Log.d(TAG, "removeDisplay: display=" + display);
+ super.removeDisplay(display);
+ }
+
+ @Override
+ public void updateDisplay(RemoteDisplay display) {
+ Log.d(TAG, "updateDisplay: display=" + display);
+ super.updateDisplay(display);
+ }
+
+ private final Runnable mBlink = new Runnable() {
+ @Override
+ public void run() {
+ if (mTestDisplay7 == null) {
+ if (mBlinking) {
+ mTestDisplay7 = new RemoteDisplay("testDisplay7",
+ "Test Display 7 (blinky)");
+ mTestDisplay7.setDescription("Comes and goes but can't connect");
+ mTestDisplay7.setStatus(RemoteDisplay.STATUS_AVAILABLE);
+ addDisplay(mTestDisplay7);
+ mHandler.postDelayed(this, 7000);
+ }
+ } else {
+ removeDisplay(mTestDisplay7);
+ mTestDisplay7 = null;
+ if (mBlinking) {
+ mHandler.postDelayed(this, 4000);
+ }
+ }
+ }
+ };
+ }
+}
diff --git a/tests/permission/src/com/android/framework/permission/tests/WindowManagerPermissionTests.java b/tests/permission/src/com/android/framework/permission/tests/WindowManagerPermissionTests.java
index e4c4214..df32ee1 100644
--- a/tests/permission/src/com/android/framework/permission/tests/WindowManagerPermissionTests.java
+++ b/tests/permission/src/com/android/framework/permission/tests/WindowManagerPermissionTests.java
@@ -93,7 +93,7 @@
}
try {
- mWm.addAppToken(0, null, 0, 0, 0, false, false, 0);
+ mWm.addAppToken(0, null, 0, 0, 0, false, false, 0, 0);
fail("IWindowManager.addAppToken did not throw SecurityException as"
+ " expected");
} catch (SecurityException e) {
diff --git a/tools/layoutlib/Android.mk b/tools/layoutlib/Android.mk
index 4e73568..ed497a5 100644
--- a/tools/layoutlib/Android.mk
+++ b/tools/layoutlib/Android.mk
@@ -31,6 +31,9 @@
built_core_dep := $(call java-lib-deps,core)
built_core_classes := $(call java-lib-files,core)
+built_ext_dep := $(call java-lib-deps,ext)
+built_ext_classes := $(call java-lib-files,ext)
+
built_layoutlib_create_jar := $(call intermediates-dir-for, \
JAVA_LIBRARIES,layoutlib_create,HOST)/javalib.jar
@@ -47,6 +50,7 @@
$(LOCAL_BUILT_MODULE): $(built_core_dep) \
$(built_framework_dep) \
+ $(built_ext_dep) \
$(built_layoutlib_create_jar)
$(hide) echo "host layoutlib_create: $@"
$(hide) mkdir -p $(dir $@)
@@ -55,7 +59,8 @@
$(hide) java -jar $(built_layoutlib_create_jar) \
$@ \
$(built_core_classes) \
- $(built_framework_classes)
+ $(built_framework_classes) \
+ $(built_ext_classes)
$(hide) ls -l $(built_framework_classes)
diff --git a/tools/layoutlib/bridge/src/android/graphics/Bitmap_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/Bitmap_Delegate.java
index ec284ac..93284db 100644
--- a/tools/layoutlib/bridge/src/android/graphics/Bitmap_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/graphics/Bitmap_Delegate.java
@@ -308,8 +308,9 @@
}
@LayoutlibDelegate
- /*package*/ static void nativeRecycle(int nativeBitmap) {
+ /*package*/ static boolean nativeRecycle(int nativeBitmap) {
sManager.removeJavaReferenceFor(nativeBitmap);
+ return true;
}
@LayoutlibDelegate
diff --git a/tools/layoutlib/bridge/src/android/view/IWindowManagerImpl.java b/tools/layoutlib/bridge/src/android/view/IWindowManagerImpl.java
index fd153af..dd2cbc1 100644
--- a/tools/layoutlib/bridge/src/android/view/IWindowManagerImpl.java
+++ b/tools/layoutlib/bridge/src/android/view/IWindowManagerImpl.java
@@ -81,7 +81,7 @@
@Override
public void addAppToken(int arg0, IApplicationToken arg1, int arg2, int arg3, int arg4,
- boolean arg5, boolean arg6, int arg7)
+ boolean arg5, boolean arg6, int arg7, int arg8)
throws RemoteException {
// TODO Auto-generated method stub
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/CustomBar.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/CustomBar.java
index 17b0eb6..bcd08eb4 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/CustomBar.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/CustomBar.java
@@ -290,7 +290,7 @@
TypedValue out = new TypedValue();
if (ResourceHelper.parseFloatAttribute("textSize", textSize.getValue(), out,
true /*requireUnit*/)) {
- textView.setTextSize(
+ textView.setTextSize(TypedValue.COMPLEX_UNIT_PX,
out.getDimension(bridgeContext.getResources().getDisplayMetrics()));
}
}
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/RenderAction.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/RenderAction.java
index 23d08e3..60f5331 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/RenderAction.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/RenderAction.java
@@ -273,7 +273,6 @@
mContext.getRenderResources().setLogger(null);
}
- mContext = null;
}
public static BridgeContext getCurrentContext() {
diff --git a/tools/layoutlib/bridge/src/libcore/icu/ICU_Delegate.java b/tools/layoutlib/bridge/src/libcore/icu/ICU_Delegate.java
index 06ae804..ad4103b 100644
--- a/tools/layoutlib/bridge/src/libcore/icu/ICU_Delegate.java
+++ b/tools/layoutlib/bridge/src/libcore/icu/ICU_Delegate.java
@@ -46,7 +46,7 @@
// --- Native methods accessing ICU's database.
@LayoutlibDelegate
- /*package*/ static String getBestDateTimePattern(String skeleton, String localeName) {
+ /*package*/ static String getBestDateTimePatternNative(String skeleton, String localeName) {
return DateTimePatternGenerator.getInstance(new ULocale(localeName))
.getBestPattern(skeleton);
}
@@ -167,7 +167,7 @@
}
@LayoutlibDelegate
- /*package*/ static boolean initLocaleDataImpl(String locale, LocaleData result) {
+ /*package*/ static boolean initLocaleDataNative(String locale, LocaleData result) {
// Used by Calendar.
result.firstDayOfWeek = Integer.valueOf(1);
diff --git a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/Main.java b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/Main.java
index ba23048..ee501d2 100644
--- a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/Main.java
+++ b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/Main.java
@@ -113,6 +113,7 @@
"android.pim.*", // for datepicker
"android.os.*", // for android.os.Handler
"android.database.ContentObserver", // for Digital clock
+ "com.android.i18n.phonenumbers.*", // for TextView with autolink attribute
},
excludeClasses);
aa.analyze();
diff --git a/wifi/java/android/net/wifi/IWifiManager.aidl b/wifi/java/android/net/wifi/IWifiManager.aidl
index 5a1928c..149bda6 100644
--- a/wifi/java/android/net/wifi/IWifiManager.aidl
+++ b/wifi/java/android/net/wifi/IWifiManager.aidl
@@ -117,7 +117,7 @@
void enableTdlsWithMacAddress(String remoteMacAddress, boolean enable);
- boolean requestBatchedScan(in BatchedScanSettings requested, IBinder binder);
+ boolean requestBatchedScan(in BatchedScanSettings requested, IBinder binder, in WorkSource ws);
void stopBatchedScan(in BatchedScanSettings requested);
diff --git a/wifi/java/android/net/wifi/SupplicantStateTracker.java b/wifi/java/android/net/wifi/SupplicantStateTracker.java
index f6a621f..e76eb17 100644
--- a/wifi/java/android/net/wifi/SupplicantStateTracker.java
+++ b/wifi/java/android/net/wifi/SupplicantStateTracker.java
@@ -55,7 +55,7 @@
private static final int MAX_RETRIES_ON_AUTHENTICATION_FAILURE = 2;
/* Maximum retries on assoc rejection events */
- private static final int MAX_RETRIES_ON_ASSOCIATION_REJECT = 4;
+ private static final int MAX_RETRIES_ON_ASSOCIATION_REJECT = 16;
/* Tracks if networks have been disabled during a connection */
private boolean mNetworksDisabledDuringConnect = false;
diff --git a/wifi/java/android/net/wifi/WifiManager.java b/wifi/java/android/net/wifi/WifiManager.java
index 7fc8bef..3b47e63 100644
--- a/wifi/java/android/net/wifi/WifiManager.java
+++ b/wifi/java/android/net/wifi/WifiManager.java
@@ -799,7 +799,13 @@
*/
public boolean requestBatchedScan(BatchedScanSettings requested) {
try {
- return mService.requestBatchedScan(requested, new Binder());
+ return mService.requestBatchedScan(requested, new Binder(), null);
+ } catch (RemoteException e) { return false; }
+ }
+ /** @hide */
+ public boolean requestBatchedScan(BatchedScanSettings requested, WorkSource workSource) {
+ try {
+ return mService.requestBatchedScan(requested, new Binder(), workSource);
} catch (RemoteException e) { return false; }
}
diff --git a/wifi/java/android/net/wifi/WifiNative.java b/wifi/java/android/net/wifi/WifiNative.java
index 520668e..c2f278a 100644
--- a/wifi/java/android/net/wifi/WifiNative.java
+++ b/wifi/java/android/net/wifi/WifiNative.java
@@ -39,7 +39,6 @@
public class WifiNative {
private static final boolean DBG = false;
- private static final boolean VDBG = false;
private final String mTAG;
private static final int DEFAULT_GROUP_OWNER_INTENT = 6;
@@ -118,12 +117,12 @@
public boolean connectToSupplicant() {
// No synchronization necessary .. it is implemented in WifiMonitor
- if (VDBG) localLog(mInterfacePrefix + "connectToSupplicant");
+ localLog(mInterfacePrefix + "connectToSupplicant");
return connectToSupplicantNative();
}
public void closeSupplicantConnection() {
- if (VDBG) localLog(mInterfacePrefix + "closeSupplicantConnection");
+ localLog(mInterfacePrefix + "closeSupplicantConnection");
closeSupplicantConnectionNative();
}
@@ -136,9 +135,9 @@
if (DBG) Log.d(mTAG, "doBoolean: " + command);
synchronized (mLock) {
int cmdId = getNewCmdIdLocked();
- if (VDBG) localLog(cmdId + "->" + mInterfacePrefix + command);
+ localLog(cmdId + "->" + mInterfacePrefix + command);
boolean result = doBooleanCommandNative(mInterfacePrefix + command);
- if (VDBG) localLog(cmdId + "<-" + result);
+ localLog(cmdId + "<-" + result);
if (DBG) Log.d(mTAG, " returned " + result);
return result;
}
@@ -148,9 +147,9 @@
if (DBG) Log.d(mTAG, "doInt: " + command);
synchronized (mLock) {
int cmdId = getNewCmdIdLocked();
- if (VDBG) localLog(cmdId + "->" + mInterfacePrefix + command);
+ localLog(cmdId + "->" + mInterfacePrefix + command);
int result = doIntCommandNative(mInterfacePrefix + command);
- if (VDBG) localLog(cmdId + "<-" + result);
+ localLog(cmdId + "<-" + result);
if (DBG) Log.d(mTAG, " returned " + result);
return result;
}
@@ -160,9 +159,9 @@
if (DBG) Log.d(mTAG, "doString: " + command);
synchronized (mLock) {
int cmdId = getNewCmdIdLocked();
- if (VDBG) localLog(cmdId + "->" + mInterfacePrefix + command);
+ localLog(cmdId + "->" + mInterfacePrefix + command);
String result = doStringCommandNative(mInterfacePrefix + command);
- if (VDBG) localLog(cmdId + "<-" + result);
+ localLog(cmdId + "<-" + result);
if (DBG) Log.d(mTAG, " returned " + result);
return result;
}
@@ -298,7 +297,9 @@
* the firmware can remember before it runs out of buffer space or -1 on error
*/
public String setBatchedScanSettings(BatchedScanSettings settings) {
- if (settings == null) return doStringCommand("DRIVER WLS_BATCHING STOP");
+ if (settings == null) {
+ return doStringCommand("DRIVER WLS_BATCHING STOP");
+ }
String cmd = "DRIVER WLS_BATCHING SET SCANFREQ=" + settings.scanIntervalSec;
cmd += " MSCAN=" + settings.maxScansPerBatch;
if (settings.maxApPerScan != BatchedScanSettings.UNSPECIFIED) {
diff --git a/wifi/java/android/net/wifi/WifiStateMachine.java b/wifi/java/android/net/wifi/WifiStateMachine.java
index 78da7e7..eedd66f 100644
--- a/wifi/java/android/net/wifi/WifiStateMachine.java
+++ b/wifi/java/android/net/wifi/WifiStateMachine.java
@@ -57,6 +57,7 @@
import android.net.wifi.p2p.WifiP2pService;
import android.os.BatteryStats;
import android.os.Binder;
+import android.os.Bundle;
import android.os.IBinder;
import android.os.INetworkManagementService;
import android.os.Message;
@@ -416,7 +417,8 @@
/* change the batch scan settings.
* arg1 = responsible UID
- * obj = the new settings
+ * arg2 = csph (channel scans per hour)
+ * obj = bundle with the new settings and the optional worksource
*/
public static final int CMD_SET_BATCHED_SCAN = BASE + 135;
public static final int CMD_START_NEXT_BATCHED_SCAN = BASE + 136;
@@ -628,6 +630,15 @@
private BatchedScanSettings mBatchedScanSettings = null;
+ /**
+ * Track the worksource/cost of the current settings and track what's been noted
+ * to the battery stats, so we can mark the end of the previous when changing.
+ */
+ private WorkSource mBatchedScanWorkSource = null;
+ private int mBatchedScanCsph = 0;
+ private WorkSource mNotedBatchedScanWorkSource = null;
+ private int mNotedBatchedScanCsph = 0;
+
public WifiStateMachine(Context context, String wlanInterface) {
super("WifiStateMachine");
@@ -841,8 +852,14 @@
/**
* start or stop batched scanning using the given settings
*/
- public void setBatchedScanSettings(BatchedScanSettings settings, int callingUid) {
- sendMessage(CMD_SET_BATCHED_SCAN, callingUid, 0, settings);
+ private static final String BATCHED_SETTING = "batched_settings";
+ private static final String BATCHED_WORKSOURCE = "batched_worksource";
+ public void setBatchedScanSettings(BatchedScanSettings settings, int callingUid, int csph,
+ WorkSource workSource) {
+ Bundle bundle = new Bundle();
+ bundle.putParcelable(BATCHED_SETTING, settings);
+ bundle.putParcelable(BATCHED_WORKSOURCE, workSource);
+ sendMessage(CMD_SET_BATCHED_SCAN, callingUid, csph, bundle);
}
public List<BatchedScanResult> syncGetBatchedScanResultsList() {
@@ -861,6 +878,8 @@
}
private void startBatchedScan() {
+ if (mBatchedScanSettings == null) return;
+
if (mDhcpActive) {
if (DBG) log("not starting Batched Scans due to DHCP");
return;
@@ -872,10 +891,10 @@
mAlarmManager.cancel(mBatchedScanIntervalIntent);
String scansExpected = mWifiNative.setBatchedScanSettings(mBatchedScanSettings);
-
try {
mExpectedBatchedScans = Integer.parseInt(scansExpected);
setNextBatchedAlarm(mExpectedBatchedScans);
+ if (mExpectedBatchedScans > 0) noteBatchedScanStart();
} catch (NumberFormatException e) {
stopBatchedScan();
loge("Exception parsing WifiNative.setBatchedScanSettings response " + e);
@@ -918,25 +937,31 @@
}
// return true if new/different
- private boolean recordBatchedScanSettings(BatchedScanSettings settings) {
- if (DBG) log("set batched scan to " + settings);
+ private boolean recordBatchedScanSettings(int responsibleUid, int csph, Bundle bundle) {
+ BatchedScanSettings settings = bundle.getParcelable(BATCHED_SETTING);
+ WorkSource responsibleWorkSource = bundle.getParcelable(BATCHED_WORKSOURCE);
+
+ if (DBG) {
+ log("set batched scan to " + settings + " for uid=" + responsibleUid +
+ ", worksource=" + responsibleWorkSource);
+ }
if (settings != null) {
- // TODO - noteBatchedScanStart(message.arg1);
if (settings.equals(mBatchedScanSettings)) return false;
} else {
if (mBatchedScanSettings == null) return false;
- // TODO - noteBatchedScanStop(message.arg1);
}
mBatchedScanSettings = settings;
+ if (responsibleWorkSource == null) responsibleWorkSource = new WorkSource(responsibleUid);
+ mBatchedScanWorkSource = responsibleWorkSource;
+ mBatchedScanCsph = csph;
return true;
}
private void stopBatchedScan() {
mAlarmManager.cancel(mBatchedScanIntervalIntent);
- if (mBatchedScanSettings != null) {
- retrieveBatchedScanData();
- mWifiNative.setBatchedScanSettings(null);
- }
+ retrieveBatchedScanData();
+ mWifiNative.setBatchedScanSettings(null);
+ noteBatchedScanStop();
}
private void setNextBatchedAlarm(int scansExpected) {
@@ -1164,6 +1189,44 @@
}
}
+ private void noteBatchedScanStart() {
+ // note the end of a previous scan set
+ if (mNotedBatchedScanWorkSource != null &&
+ (mNotedBatchedScanWorkSource.equals(mBatchedScanWorkSource) == false ||
+ mNotedBatchedScanCsph != mBatchedScanCsph)) {
+ try {
+ mBatteryStats.noteWifiBatchedScanStoppedFromSource(mNotedBatchedScanWorkSource);
+ } catch (RemoteException e) {
+ log(e.toString());
+ } finally {
+ mNotedBatchedScanWorkSource = null;
+ mNotedBatchedScanCsph = 0;
+ }
+ }
+ // note the start of the new
+ try {
+ mBatteryStats.noteWifiBatchedScanStartedFromSource(mBatchedScanWorkSource,
+ mBatchedScanCsph);
+ mNotedBatchedScanWorkSource = mBatchedScanWorkSource;
+ mNotedBatchedScanCsph = mBatchedScanCsph;
+ } catch (RemoteException e) {
+ log(e.toString());
+ }
+ }
+
+ private void noteBatchedScanStop() {
+ if (mNotedBatchedScanWorkSource != null) {
+ try {
+ mBatteryStats.noteWifiBatchedScanStoppedFromSource(mNotedBatchedScanWorkSource);
+ } catch (RemoteException e) {
+ log(e.toString());
+ } finally {
+ mNotedBatchedScanWorkSource = null;
+ mNotedBatchedScanCsph = 0;
+ }
+ }
+ }
+
private void startScanNative(int type) {
mWifiNative.scan(type);
mScanResultIsPending = true;
@@ -1868,6 +1931,9 @@
return;
}
+ // note that all these splits and substrings keep references to the original
+ // huge string buffer while the amount we really want is generally pretty small
+ // so make copies instead (one example b/11087956 wasted 400k of heap here).
synchronized(mScanResultCache) {
mScanResults = new ArrayList<ScanResult>();
String[] lines = scanResults.split("\n");
@@ -2307,9 +2373,7 @@
mDhcpActive = false;
- if (mBatchedScanSettings != null) {
- startBatchedScan();
- }
+ startBatchedScan();
}
private void handleSuccessfulIpConfiguration(DhcpResults dhcpResults) {
@@ -2447,7 +2511,7 @@
}
break;
case CMD_SET_BATCHED_SCAN:
- recordBatchedScanSettings((BatchedScanSettings)message.obj);
+ recordBatchedScanSettings(message.arg1, message.arg2, (Bundle)message.obj);
break;
case CMD_POLL_BATCHED_SCAN:
handleBatchedScanPollRequest();
@@ -2960,9 +3024,7 @@
mDhcpActive = false;
- if (mBatchedScanSettings != null) {
- startBatchedScan();
- }
+ startBatchedScan();
if (mOperationalMode != CONNECT_MODE) {
mWifiNative.disconnect();
@@ -3021,8 +3083,10 @@
startScanNative(WifiNative.SCAN_WITH_CONNECTION_SETUP);
break;
case CMD_SET_BATCHED_SCAN:
- recordBatchedScanSettings((BatchedScanSettings)message.obj);
- startBatchedScan();
+ if (recordBatchedScanSettings(message.arg1, message.arg2,
+ (Bundle)message.obj)) {
+ startBatchedScan();
+ }
break;
case CMD_SET_COUNTRY_CODE:
String country = (String) message.obj;
@@ -3160,9 +3224,7 @@
updateBatteryWorkSource(null);
mScanResults = new ArrayList<ScanResult>();
- if (mBatchedScanSettings != null) {
- stopBatchedScan();
- }
+ stopBatchedScan();
final Intent intent = new Intent(WifiManager.WIFI_SCAN_AVAILABLE);
intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);