diff options
199 files changed, 1884 insertions, 411 deletions
@@ -193,11 +193,12 @@ LOCAL_SRC_FILES += \ location/java/android/location/INetInitiatedListener.aidl \ media/java/android/media/IAudioService.aidl \ media/java/android/media/IAudioFocusDispatcher.aidl \ - media/java/android/media/IAudioRoutesObserver.aidl \ + media/java/android/media/IAudioRoutesObserver.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/IRemoteVolumeObserver.aidl \ media/java/android/media/IRingtonePlayer.aidl \ telephony/java/com/android/internal/telephony/IPhoneStateListener.aidl \ telephony/java/com/android/internal/telephony/IPhoneSubInfo.aidl \ diff --git a/api/current.txt b/api/current.txt index 4a23046..3069221 100644 --- a/api/current.txt +++ b/api/current.txt @@ -676,6 +676,7 @@ package android { field public static final int measureAllChildren = 16843018; // 0x101010a field public static final int measureWithLargestChild = 16843476; // 0x10102d4 field public static final int mediaRouteButtonStyle = 16843693; // 0x10103ad + field public static final int mediaRouteTypes = 16843694; // 0x10103ae field public static final int menuCategory = 16843230; // 0x10101de field public static final int mimeType = 16842790; // 0x1010026 field public static final int minDate = 16843583; // 0x101033f @@ -11564,10 +11565,19 @@ package android.media { method public android.graphics.drawable.Drawable getIconDrawable(); method public java.lang.CharSequence getName(); method public java.lang.CharSequence getName(android.content.Context); + method public int getPlaybackStream(); + method public int getPlaybackType(); method public java.lang.CharSequence getStatus(); method public int getSupportedTypes(); method public java.lang.Object getTag(); + method public int getVolume(); + method public int getVolumeHandling(); + method public int getVolumeMax(); method public void setTag(java.lang.Object); + field public static final int PLAYBACK_TYPE_LOCAL = 0; // 0x0 + field public static final int PLAYBACK_TYPE_REMOTE = 1; // 0x1 + field public static final int PLAYBACK_VOLUME_FIXED = 0; // 0x0 + field public static final int PLAYBACK_VOLUME_VARIABLE = 1; // 0x1 } public static class MediaRouter.SimpleCallback extends android.media.MediaRouter.Callback { @@ -11587,8 +11597,20 @@ package android.media { method public void setIconResource(int); method public void setName(java.lang.CharSequence); method public void setName(int); + method public void setPlaybackStream(int); + method public void setPlaybackType(int); method public void setRemoteControlClient(android.media.RemoteControlClient); method public void setStatus(java.lang.CharSequence); + method public void setVolume(int); + method public void setVolumeCallback(android.media.MediaRouter.VolumeCallback); + method public void setVolumeHandling(int); + method public void setVolumeMax(int); + } + + public static abstract class MediaRouter.VolumeCallback { + ctor public MediaRouter.VolumeCallback(); + method public abstract void onVolumeSetRequest(android.media.MediaRouter.RouteInfo, int); + method public abstract void onVolumeUpdateRequest(android.media.MediaRouter.RouteInfo, int); } public class MediaScannerConnection implements android.content.ServiceConnection { diff --git a/cmds/bootanimation/BootAnimation.cpp b/cmds/bootanimation/BootAnimation.cpp index 225be9c..6b50486 100644 --- a/cmds/bootanimation/BootAnimation.cpp +++ b/cmds/bootanimation/BootAnimation.cpp @@ -54,6 +54,7 @@ #define USER_BOOTANIMATION_FILE "/data/local/bootanimation.zip" #define SYSTEM_BOOTANIMATION_FILE "/system/media/bootanimation.zip" #define SYSTEM_ENCRYPTED_BOOTANIMATION_FILE "/system/media/bootanimation-encrypted.zip" +#define EXIT_PROP_NAME "service.bootanim.exit" extern "C" int clock_nanosleep(clockid_t clock_id, int flags, const struct timespec *request, @@ -297,6 +298,9 @@ bool BootAnimation::threadLoop() r = movie(); } + // No need to force exit anymore + property_set(EXIT_PROP_NAME, "0"); + eglMakeCurrent(mDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); eglDestroyContext(mDisplay, mContext); eglDestroySurface(mDisplay, mSurface); @@ -363,6 +367,8 @@ bool BootAnimation::android() const nsecs_t sleepTime = 83333 - ns2us(systemTime() - now); if (sleepTime > 0) usleep(sleepTime); + + checkExit(); } while (!exitPending()); glDeleteTextures(1, &mAndroid[0].name); @@ -371,6 +377,16 @@ bool BootAnimation::android() } +void BootAnimation::checkExit() { + // Allow surface flinger to gracefully request shutdown + char value[PROPERTY_VALUE_MAX]; + property_get(EXIT_PROP_NAME, value, "0"); + int exitnow = atoi(value); + if (exitnow) { + requestExit(); + } +} + bool BootAnimation::movie() { ZipFileRO& zip(mZip); @@ -397,20 +413,23 @@ bool BootAnimation::movie() const char* l = line.string(); int fps, width, height, count, pause; char path[256]; + char pathType; if (sscanf(l, "%d %d %d", &width, &height, &fps) == 3) { - //ALOGD("> w=%d, h=%d, fps=%d", fps, width, height); + //LOGD("> w=%d, h=%d, fps=%d", width, height, fps); animation.width = width; animation.height = height; animation.fps = fps; } - if (sscanf(l, "p %d %d %s", &count, &pause, path) == 3) { - //ALOGD("> count=%d, pause=%d, path=%s", count, pause, path); + else if (sscanf(l, " %c %d %d %s", &pathType, &count, &pause, path) == 4) { + //LOGD("> type=%c, count=%d, pause=%d, path=%s", pathType, count, pause, path); Animation::Part part; + part.playUntilComplete = pathType == 'c'; part.count = count; part.pause = pause; part.path = path; animation.parts.add(part); } + s = ++endl; } @@ -472,13 +491,17 @@ bool BootAnimation::movie() Region clearReg(Rect(mWidth, mHeight)); clearReg.subtractSelf(Rect(xc, yc, xc+animation.width, yc+animation.height)); - for (int i=0 ; i<pcount && !exitPending() ; i++) { + for (int i=0 ; i<pcount ; i++) { const Animation::Part& part(animation.parts[i]); const size_t fcount = part.frames.size(); glBindTexture(GL_TEXTURE_2D, 0); for (int r=0 ; !part.count || r<part.count ; r++) { - for (int j=0 ; j<fcount && !exitPending(); j++) { + // Exit any non playuntil complete parts immediately + if(exitPending() && !part.playUntilComplete) + break; + + for (int j=0 ; j<fcount && (!exitPending() || part.playUntilComplete) ; j++) { const Animation::Frame& frame(part.frames[j]); nsecs_t lastFrame = systemTime(); @@ -525,8 +548,15 @@ bool BootAnimation::movie() err = clock_nanosleep(CLOCK_MONOTONIC, TIMER_ABSTIME, &spec, NULL); } while (err<0 && errno == EINTR); } + + checkExit(); } + usleep(part.pause * ns2us(frameDuration)); + + // For infinite parts, we've now played them at least once, so perhaps exit + if(exitPending() && !part.count) + break; } // free the textures for this part diff --git a/cmds/bootanimation/BootAnimation.h b/cmds/bootanimation/BootAnimation.h index 62da82f..fa908eb 100644 --- a/cmds/bootanimation/BootAnimation.h +++ b/cmds/bootanimation/BootAnimation.h @@ -70,6 +70,7 @@ private: int pause; String8 path; SortedVector<Frame> frames; + bool playUntilComplete; }; int fps; int width; @@ -82,6 +83,8 @@ private: bool android(); bool movie(); + void checkExit(); + sp<SurfaceComposerClient> mSession; AssetManager mAssets; Texture mAndroid[2]; diff --git a/core/java/android/animation/LayoutTransition.java b/core/java/android/animation/LayoutTransition.java index 4d3a519..d8f9e49 100644 --- a/core/java/android/animation/LayoutTransition.java +++ b/core/java/android/animation/LayoutTransition.java @@ -942,8 +942,10 @@ public class LayoutTransition { @Override public void onAnimationStart(Animator animator) { - if (mListeners != null) { - for (TransitionListener listener : mListeners) { + if (hasListeners()) { + ArrayList<TransitionListener> listeners = + (ArrayList<TransitionListener>) mListeners.clone(); + for (TransitionListener listener : listeners) { listener.startTransition(LayoutTransition.this, parent, child, changeReason == APPEARING ? CHANGE_APPEARING : changeReason == DISAPPEARING ? @@ -961,8 +963,10 @@ public class LayoutTransition { @Override public void onAnimationEnd(Animator animator) { currentChangingAnimations.remove(child); - if (mListeners != null) { - for (TransitionListener listener : mListeners) { + if (hasListeners()) { + ArrayList<TransitionListener> listeners = + (ArrayList<TransitionListener>) mListeners.clone(); + for (TransitionListener listener : listeners) { listener.endTransition(LayoutTransition.this, parent, child, changeReason == APPEARING ? CHANGE_APPEARING : changeReason == DISAPPEARING ? @@ -1131,8 +1135,10 @@ public class LayoutTransition { currentAnimation.cancel(); } if (mAppearingAnim == null) { - if (mListeners != null) { - for (TransitionListener listener : mListeners) { + if (hasListeners()) { + ArrayList<TransitionListener> listeners = + (ArrayList<TransitionListener>) mListeners.clone(); + for (TransitionListener listener : listeners) { listener.endTransition(LayoutTransition.this, parent, child, APPEARING); } } @@ -1149,8 +1155,10 @@ public class LayoutTransition { @Override public void onAnimationEnd(Animator anim) { currentAppearingAnimations.remove(child); - if (mListeners != null) { - for (TransitionListener listener : mListeners) { + if (hasListeners()) { + ArrayList<TransitionListener> listeners = + (ArrayList<TransitionListener>) mListeners.clone(); + for (TransitionListener listener : listeners) { listener.endTransition(LayoutTransition.this, parent, child, APPEARING); } } @@ -1172,8 +1180,10 @@ public class LayoutTransition { currentAnimation.cancel(); } if (mDisappearingAnim == null) { - if (mListeners != null) { - for (TransitionListener listener : mListeners) { + if (hasListeners()) { + ArrayList<TransitionListener> listeners = + (ArrayList<TransitionListener>) mListeners.clone(); + for (TransitionListener listener : listeners) { listener.endTransition(LayoutTransition.this, parent, child, DISAPPEARING); } } @@ -1189,8 +1199,10 @@ public class LayoutTransition { public void onAnimationEnd(Animator anim) { currentDisappearingAnimations.remove(child); child.setAlpha(preAnimAlpha); - if (mListeners != null) { - for (TransitionListener listener : mListeners) { + if (hasListeners()) { + ArrayList<TransitionListener> listeners = + (ArrayList<TransitionListener>) mListeners.clone(); + for (TransitionListener listener : listeners) { listener.endTransition(LayoutTransition.this, parent, child, DISAPPEARING); } } @@ -1228,8 +1240,10 @@ public class LayoutTransition { cancel(CHANGE_APPEARING); cancel(CHANGING); } - if (mListeners != null && (mTransitionTypes & FLAG_APPEARING) == FLAG_APPEARING) { - for (TransitionListener listener : mListeners) { + if (hasListeners() && (mTransitionTypes & FLAG_APPEARING) == FLAG_APPEARING) { + ArrayList<TransitionListener> listeners = + (ArrayList<TransitionListener>) mListeners.clone(); + for (TransitionListener listener : listeners) { listener.startTransition(this, parent, child, APPEARING); } } @@ -1241,6 +1255,10 @@ public class LayoutTransition { } } + private boolean hasListeners() { + return mListeners != null && mListeners.size() > 0; + } + /** * This method is called by ViewGroup when there is a call to layout() on the container * with this LayoutTransition. If the CHANGING transition is enabled and if there is no other @@ -1328,8 +1346,10 @@ public class LayoutTransition { cancel(CHANGE_DISAPPEARING); cancel(CHANGING); } - if (mListeners != null && (mTransitionTypes & FLAG_DISAPPEARING) == FLAG_DISAPPEARING) { - for (TransitionListener listener : mListeners) { + if (hasListeners() && (mTransitionTypes & FLAG_DISAPPEARING) == FLAG_DISAPPEARING) { + ArrayList<TransitionListener> listeners = (ArrayList<TransitionListener>) mListeners + .clone(); + for (TransitionListener listener : listeners) { listener.startTransition(this, parent, child, DISAPPEARING); } } diff --git a/core/java/android/app/FragmentManager.java b/core/java/android/app/FragmentManager.java index 9ba5305..39e2423 100644 --- a/core/java/android/app/FragmentManager.java +++ b/core/java/android/app/FragmentManager.java @@ -1118,7 +1118,9 @@ final class FragmentManagerImpl extends FragmentManager { if (DEBUG) Log.v(TAG, "remove: " + fragment + " nesting=" + fragment.mBackStackNesting); final boolean inactive = !fragment.isInBackStack(); if (!fragment.mDetached || inactive) { - mAdded.remove(fragment); + if (mAdded != null) { + mAdded.remove(fragment); + } if (fragment.mHasMenu && fragment.mMenuVisible) { mNeedMenuInvalidate = true; } @@ -1187,7 +1189,9 @@ final class FragmentManagerImpl extends FragmentManager { fragment.mDetached = true; if (fragment.mAdded) { // We are not already in back stack, so need to remove the fragment. - mAdded.remove(fragment); + if (mAdded != null) { + mAdded.remove(fragment); + } if (fragment.mHasMenu && fragment.mMenuVisible) { mNeedMenuInvalidate = true; } @@ -1202,6 +1206,9 @@ final class FragmentManagerImpl extends FragmentManager { if (fragment.mDetached) { fragment.mDetached = false; if (!fragment.mAdded) { + if (mAdded == null) { + mAdded = new ArrayList<Fragment>(); + } mAdded.add(fragment); fragment.mAdded = true; if (fragment.mHasMenu && fragment.mMenuVisible) { @@ -1213,7 +1220,7 @@ final class FragmentManagerImpl extends FragmentManager { } public Fragment findFragmentById(int id) { - if (mActive != null) { + if (mAdded != null) { // First look through added fragments. for (int i=mAdded.size()-1; i>=0; i--) { Fragment f = mAdded.get(i); @@ -1221,6 +1228,8 @@ final class FragmentManagerImpl extends FragmentManager { return f; } } + } + if (mActive != null) { // Now for any known fragment. for (int i=mActive.size()-1; i>=0; i--) { Fragment f = mActive.get(i); @@ -1233,7 +1242,7 @@ final class FragmentManagerImpl extends FragmentManager { } public Fragment findFragmentByTag(String tag) { - if (mActive != null && tag != null) { + if (mAdded != null && tag != null) { // First look through added fragments. for (int i=mAdded.size()-1; i>=0; i--) { Fragment f = mAdded.get(i); @@ -1241,6 +1250,8 @@ final class FragmentManagerImpl extends FragmentManager { return f; } } + } + if (mActive != null && tag != null) { // Now for any known fragment. for (int i=mActive.size()-1; i>=0; i--) { Fragment f = mActive.get(i); @@ -1817,7 +1828,7 @@ final class FragmentManagerImpl extends FragmentManager { } public void dispatchConfigurationChanged(Configuration newConfig) { - if (mActive != null) { + if (mAdded != null) { for (int i=0; i<mAdded.size(); i++) { Fragment f = mAdded.get(i); if (f != null) { @@ -1828,7 +1839,7 @@ final class FragmentManagerImpl extends FragmentManager { } public void dispatchLowMemory() { - if (mActive != null) { + if (mAdded != null) { for (int i=0; i<mAdded.size(); i++) { Fragment f = mAdded.get(i); if (f != null) { @@ -1839,7 +1850,7 @@ final class FragmentManagerImpl extends FragmentManager { } public void dispatchTrimMemory(int level) { - if (mActive != null) { + if (mAdded != null) { for (int i=0; i<mAdded.size(); i++) { Fragment f = mAdded.get(i); if (f != null) { @@ -1852,7 +1863,7 @@ final class FragmentManagerImpl extends FragmentManager { public boolean dispatchCreateOptionsMenu(Menu menu, MenuInflater inflater) { boolean show = false; ArrayList<Fragment> newMenus = null; - if (mActive != null) { + if (mAdded != null) { for (int i=0; i<mAdded.size(); i++) { Fragment f = mAdded.get(i); if (f != null && !f.mHidden && f.mHasMenu && f.mMenuVisible) { @@ -1882,7 +1893,7 @@ final class FragmentManagerImpl extends FragmentManager { public boolean dispatchPrepareOptionsMenu(Menu menu) { boolean show = false; - if (mActive != null) { + if (mAdded != null) { for (int i=0; i<mAdded.size(); i++) { Fragment f = mAdded.get(i); if (f != null && !f.mHidden && f.mHasMenu && f.mMenuVisible) { @@ -1895,7 +1906,7 @@ final class FragmentManagerImpl extends FragmentManager { } public boolean dispatchOptionsItemSelected(MenuItem item) { - if (mActive != null) { + if (mAdded != null) { for (int i=0; i<mAdded.size(); i++) { Fragment f = mAdded.get(i); if (f != null && !f.mHidden && f.mHasMenu && f.mMenuVisible) { @@ -1909,7 +1920,7 @@ final class FragmentManagerImpl extends FragmentManager { } public boolean dispatchContextItemSelected(MenuItem item) { - if (mActive != null) { + if (mAdded != null) { for (int i=0; i<mAdded.size(); i++) { Fragment f = mAdded.get(i); if (f != null && !f.mHidden && f.mUserVisibleHint) { @@ -1923,7 +1934,7 @@ final class FragmentManagerImpl extends FragmentManager { } public void dispatchOptionsMenuClosed(Menu menu) { - if (mActive != null) { + if (mAdded != null) { for (int i=0; i<mAdded.size(); i++) { Fragment f = mAdded.get(i); if (f != null && !f.mHidden && f.mHasMenu && f.mMenuVisible) { diff --git a/core/java/android/app/MediaRouteButton.java b/core/java/android/app/MediaRouteButton.java index 018b25d..18713f5 100644 --- a/core/java/android/app/MediaRouteButton.java +++ b/core/java/android/app/MediaRouteButton.java @@ -73,9 +73,14 @@ public class MediaRouteButton extends View { com.android.internal.R.styleable.MediaRouteButton_minWidth, 0); mMinHeight = a.getDimensionPixelSize( com.android.internal.R.styleable.MediaRouteButton_minHeight, 0); + final int routeTypes = a.getInteger( + com.android.internal.R.styleable.MediaRouteButton_mediaRouteTypes, + MediaRouter.ROUTE_TYPE_LIVE_AUDIO); a.recycle(); setClickable(true); + + setRouteTypes(routeTypes); } private void setRemoteIndicatorDrawable(Drawable d) { @@ -110,7 +115,7 @@ public class MediaRouteButton extends View { final RouteInfo route = mRouter.getRouteAt(i); if ((route.getSupportedTypes() & mRouteTypes) != 0 && route != mRouter.getSystemAudioRoute()) { - mRouter.selectRoute(mRouteTypes, route); + mRouter.selectRouteInt(mRouteTypes, route); } } } diff --git a/core/java/android/app/SearchManager.java b/core/java/android/app/SearchManager.java index e8bd546..d1d5131 100644 --- a/core/java/android/app/SearchManager.java +++ b/core/java/android/app/SearchManager.java @@ -840,29 +840,17 @@ public class SearchManager } /** - * Returns true if the global assist activity is available. - * @return True if the assistant is available. - * - * @hide - */ - public final boolean isAssistantAvailable() { - Intent intent = getAssistIntent(); - return intent != null - && mContext.getPackageManager().queryIntentActivities(intent, - PackageManager.MATCH_DEFAULT_ONLY).size() > 0; - } - - /** - * Gets an intent to launch the global assist activity, or null if not available. + * Gets an intent for launching installed assistant activity, or null if not available. * @return The assist intent. * * @hide */ - public final Intent getAssistIntent() { - ComponentName globalSearchActivity = getGlobalSearchActivity(); - if (globalSearchActivity != null) { - Intent intent = new Intent(Intent.ACTION_ASSIST); - intent.setPackage(globalSearchActivity.getPackageName()); + public static final Intent getAssistIntent(Context context) { + PackageManager pm = context.getPackageManager(); + Intent intent = new Intent(Intent.ACTION_ASSIST); + ComponentName component = intent.resolveActivity(pm); + if (component != null) { + intent.setComponent(component); return intent; } return null; diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java index edd509b..76dfac4 100644 --- a/core/java/android/content/Intent.java +++ b/core/java/android/content/Intent.java @@ -27,6 +27,7 @@ import android.content.pm.ResolveInfo; import android.content.res.Resources; import android.content.res.TypedArray; import android.graphics.Rect; +import android.media.RemoteControlClient; import android.net.Uri; import android.os.Bundle; import android.os.IBinder; @@ -2839,6 +2840,7 @@ public class Intent implements Parcelable, Cloneable { */ public static final String EXTRA_USERID = "android.intent.extra.user_id"; + // --------------------------------------------------------------------- // --------------------------------------------------------------------- // Intent flags (see mFlags variable). diff --git a/core/java/android/preference/PreferenceActivity.java b/core/java/android/preference/PreferenceActivity.java index 1029161..140bff0 100644 --- a/core/java/android/preference/PreferenceActivity.java +++ b/core/java/android/preference/PreferenceActivity.java @@ -651,6 +651,14 @@ public abstract class PreferenceActivity extends ListActivity implements } /** + * Returns the Header list + * @hide + */ + public List<Header> getHeaders() { + return mHeaders; + } + + /** * Returns true if this activity is showing multiple panes -- the headers * and a preference fragment. */ diff --git a/core/java/android/util/DisplayMetrics.java b/core/java/android/util/DisplayMetrics.java index a43d36c..80da0b2 100644 --- a/core/java/android/util/DisplayMetrics.java +++ b/core/java/android/util/DisplayMetrics.java @@ -38,11 +38,21 @@ public class DisplayMetrics { public static final int DENSITY_MEDIUM = 160; /** - * Standard quantized DPI for 720p TV screens. Applications should - * generally not worry about this density, instead targeting - * {@link #DENSITY_XHIGH} for 1080p TV screens. For situations where - * output is needed for a 720p screen, the UI elements can be scaled - * automatically by the platform. + * This is a secondary density, added for some common screen configurations. + * It is recommended that applications not generally target this as a first + * class density -- that is, don't supply specific graphics for this + * density, instead allow the platform to scale from other densities + * (typically {@link #DENSITY_HIGH}) as + * appropriate. In most cases (such as using bitmaps in + * {@link android.graphics.drawable.Drawable}) the platform + * can perform this scaling at load time, so the only cost is some slight + * startup runtime overhead. + * + * <p>This density was original introduced to correspond with a + * 720p TV screen: the density for 1080p televisions is + * {@link #DENSITY_XHIGH}, and the value here provides the same UI + * size for a TV running at 720p. It has also found use in 7" tablets, + * when these devices have 1280x720 displays. */ public static final int DENSITY_TV = 213; diff --git a/core/java/android/view/HardwareRenderer.java b/core/java/android/view/HardwareRenderer.java index cb5a5e7..dab48b1 100644 --- a/core/java/android/view/HardwareRenderer.java +++ b/core/java/android/view/HardwareRenderer.java @@ -27,6 +27,7 @@ import android.os.Handler; import android.os.Looper; import android.os.SystemClock; import android.os.SystemProperties; +import android.os.Trace; import android.util.Log; import com.google.android.gles_jni.EGLImpl; @@ -40,6 +41,7 @@ import javax.microedition.khronos.opengles.GL; import java.io.File; import java.io.PrintWriter; +import java.util.concurrent.locks.ReentrantLock; import static javax.microedition.khronos.egl.EGL10.*; @@ -623,6 +625,7 @@ public abstract class HardwareRenderer { final boolean mProfileEnabled; final float[] mProfileData; + final ReentrantLock mProfileLock; int mProfileCurrentFrame = -PROFILE_FRAME_DATA_COUNT; final boolean mDebugDirtyRegions; @@ -663,8 +666,11 @@ public abstract class HardwareRenderer { for (int i = 0; i < mProfileData.length; i += PROFILE_FRAME_DATA_COUNT) { mProfileData[i] = mProfileData[i + 1] = mProfileData[i + 2] = -1; } + + mProfileLock = new ReentrantLock(); } else { mProfileData = null; + mProfileLock = null; } property = SystemProperties.get(DEBUG_DIRTY_REGIONS_PROPERTY, "false"); @@ -678,15 +684,21 @@ public abstract class HardwareRenderer { void dumpGfxInfo(PrintWriter pw) { if (mProfileEnabled) { pw.printf("\n\tDraw\tProcess\tExecute\n"); - for (int i = 0; i < mProfileData.length; i += PROFILE_FRAME_DATA_COUNT) { - if (mProfileData[i] < 0) { - break; + + mProfileLock.lock(); + try { + for (int i = 0; i < mProfileData.length; i += PROFILE_FRAME_DATA_COUNT) { + if (mProfileData[i] < 0) { + break; + } + pw.printf("\t%3.2f\t%3.2f\t%3.2f\n", mProfileData[i], mProfileData[i + 1], + mProfileData[i + 2]); + mProfileData[i] = mProfileData[i + 1] = mProfileData[i + 2] = -1; } - pw.printf("\t%3.2f\t%3.2f\t%3.2f\n", mProfileData[i], mProfileData[i + 1], - mProfileData[i + 2]); - mProfileData[i] = mProfileData[i + 1] = mProfileData[i + 2] = -1; + mProfileCurrentFrame = mProfileData.length; + } finally { + mProfileLock.unlock(); } - mProfileCurrentFrame = mProfileData.length; } } @@ -1083,7 +1095,11 @@ public abstract class HardwareRenderer { if (surfaceState != SURFACE_STATE_ERROR) { HardwareCanvas canvas = mCanvas; attachInfo.mHardwareCanvas = canvas; - + + if (mProfileEnabled) { + mProfileLock.lock(); + } + // We had to change the current surface and/or context, redraw everything if (surfaceState == SURFACE_STATE_UPDATED) { dirty = null; @@ -1121,7 +1137,14 @@ public abstract class HardwareRenderer { getDisplayListStartTime = System.nanoTime(); } - DisplayList displayList = view.getDisplayList(); + DisplayList displayList; + + Trace.traceBegin(Trace.TRACE_TAG_VIEW, "getDisplayList"); + try { + displayList = view.getDisplayList(); + } finally { + Trace.traceEnd(Trace.TRACE_TAG_VIEW); + } if (mProfileEnabled) { long now = System.nanoTime(); @@ -1136,8 +1159,13 @@ public abstract class HardwareRenderer { drawDisplayListStartTime = System.nanoTime(); } - status |= canvas.drawDisplayList(displayList, mRedrawClip, - DisplayList.FLAG_CLIP_CHILDREN); + Trace.traceBegin(Trace.TRACE_TAG_VIEW, "drawDisplayList"); + try { + status |= canvas.drawDisplayList(displayList, mRedrawClip, + DisplayList.FLAG_CLIP_CHILDREN); + } finally { + Trace.traceEnd(Trace.TRACE_TAG_VIEW); + } if (mProfileEnabled) { long now = System.nanoTime(); @@ -1174,7 +1202,6 @@ public abstract class HardwareRenderer { attachInfo.mIgnoreDirtyState = false; if ((status & DisplayList.STATUS_DREW) == DisplayList.STATUS_DREW) { - long eglSwapBuffersStartTime = 0; if (mProfileEnabled) { eglSwapBuffersStartTime = System.nanoTime(); @@ -1191,6 +1218,10 @@ public abstract class HardwareRenderer { checkEglErrors(); } + if (mProfileEnabled) { + mProfileLock.unlock(); + } + return dirty == null; } } diff --git a/core/java/android/view/ViewGroup.java b/core/java/android/view/ViewGroup.java index e7b0e78..044627c 100644 --- a/core/java/android/view/ViewGroup.java +++ b/core/java/android/view/ViewGroup.java @@ -997,13 +997,13 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager mTransition.showChild(this, child, oldVisibility); } else { mTransition.hideChild(this, child, newVisibility); - // Only track this on disappearing views - appearing views are already visible - // and don't need special handling during drawChild() - if (mVisibilityChangingChildren == null) { - mVisibilityChangingChildren = new ArrayList<View>(); - } - mVisibilityChangingChildren.add(child); if (mTransitioningViews != null && mTransitioningViews.contains(child)) { + // Only track this on disappearing views - appearing views are already visible + // and don't need special handling during drawChild() + if (mVisibilityChangingChildren == null) { + mVisibilityChangingChildren = new ArrayList<View>(); + } + mVisibilityChangingChildren.add(child); addDisappearingView(child); } } diff --git a/core/java/android/view/VolumePanel.java b/core/java/android/view/VolumePanel.java index 5ffc2c3..cf9bcdd 100644 --- a/core/java/android/view/VolumePanel.java +++ b/core/java/android/view/VolumePanel.java @@ -34,10 +34,7 @@ import android.media.ToneGenerator; import android.net.Uri; import android.os.Handler; import android.os.Message; -import android.os.RemoteException; import android.os.Vibrator; -import android.provider.Settings; -import android.provider.Settings.System; import android.util.Log; import android.view.WindowManager.LayoutParams; import android.widget.ImageView; @@ -92,9 +89,13 @@ public class VolumePanel extends Handler implements OnSeekBarChangeListener, Vie private static final int MSG_TIMEOUT = 5; private static final int MSG_RINGER_MODE_CHANGED = 6; private static final int MSG_MUTE_CHANGED = 7; + private static final int MSG_REMOTE_VOLUME_CHANGED = 8; + private static final int MSG_REMOTE_VOLUME_UPDATE_IF_SHOWN = 9; + private static final int MSG_SLIDER_VISIBILITY_CHANGED = 10; // Pseudo stream type for master volume private static final int STREAM_MASTER = -100; + // Pseudo stream type for remote volume is defined in AudioService.STREAM_REMOTE_MUSIC protected Context mContext; private AudioManager mAudioManager; @@ -155,10 +156,15 @@ public class VolumePanel extends Handler implements OnSeekBarChangeListener, Vie true), // for now, use media resources for master volume MasterStream(STREAM_MASTER, - R.string.volume_icon_description_media, + R.string.volume_icon_description_media, //FIXME should have its own description R.drawable.ic_audio_vol, R.drawable.ic_audio_vol_mute, - false); + false), + RemoteStream(AudioService.STREAM_REMOTE_MUSIC, + R.string.volume_icon_description_media, //FIXME should have its own description + R.drawable.ic_media_route_on_holo_dark, + R.drawable.ic_media_route_disabled_holo_dark, + false);// will be dynamically updated int streamType; int descRes; @@ -184,7 +190,8 @@ public class VolumePanel extends Handler implements OnSeekBarChangeListener, Vie StreamResources.MediaStream, StreamResources.NotificationStream, StreamResources.AlarmStream, - StreamResources.MasterStream + StreamResources.MasterStream, + StreamResources.RemoteStream }; /** Object that contains data for each slider */ @@ -297,6 +304,8 @@ public class VolumePanel extends Handler implements OnSeekBarChangeListener, Vie private boolean isMuted(int streamType) { if (streamType == STREAM_MASTER) { return mAudioManager.isMasterMute(); + } else if (streamType == AudioService.STREAM_REMOTE_MUSIC) { + return (mAudioService.getRemoteStreamVolume() <= 0); } else { return mAudioManager.isStreamMute(streamType); } @@ -305,6 +314,8 @@ public class VolumePanel extends Handler implements OnSeekBarChangeListener, Vie private int getStreamMaxVolume(int streamType) { if (streamType == STREAM_MASTER) { return mAudioManager.getMasterMaxVolume(); + } else if (streamType == AudioService.STREAM_REMOTE_MUSIC) { + return mAudioService.getRemoteStreamMaxVolume(); } else { return mAudioManager.getStreamMaxVolume(streamType); } @@ -313,6 +324,8 @@ public class VolumePanel extends Handler implements OnSeekBarChangeListener, Vie private int getStreamVolume(int streamType) { if (streamType == STREAM_MASTER) { return mAudioManager.getMasterVolume(); + } else if (streamType == AudioService.STREAM_REMOTE_MUSIC) { + return mAudioService.getRemoteStreamVolume(); } else { return mAudioManager.getStreamVolume(streamType); } @@ -321,6 +334,8 @@ public class VolumePanel extends Handler implements OnSeekBarChangeListener, Vie private void setStreamVolume(int streamType, int index, int flags) { if (streamType == STREAM_MASTER) { mAudioManager.setMasterVolume(index, flags); + } else if (streamType == AudioService.STREAM_REMOTE_MUSIC) { + mAudioService.setRemoteStreamVolume(index); } else { mAudioManager.setStreamVolume(streamType, index, flags); } @@ -398,7 +413,11 @@ public class VolumePanel extends Handler implements OnSeekBarChangeListener, Vie mAudioManager.getRingerMode() == AudioManager.RINGER_MODE_VIBRATE) { sc.icon.setImageResource(R.drawable.ic_audio_ring_notif_vibrate); } - if (sc.streamType != mAudioManager.getMasterStreamType() && muted) { + if (sc.streamType == AudioService.STREAM_REMOTE_MUSIC) { + // never disable touch interactions for remote playback, the muting is not tied to + // the state of the phone. + sc.seekbarView.setEnabled(true); + } else if (sc.streamType != mAudioManager.getMasterStreamType() && muted) { sc.seekbarView.setEnabled(false); } else { sc.seekbarView.setEnabled(true); @@ -446,6 +465,40 @@ public class VolumePanel extends Handler implements OnSeekBarChangeListener, Vie obtainMessage(MSG_VOLUME_CHANGED, streamType, flags).sendToTarget(); } + public void postRemoteVolumeChanged(int streamType, int flags) { + if (hasMessages(MSG_REMOTE_VOLUME_CHANGED)) return; + synchronized (this) { + if (mStreamControls == null) { + createSliders(); + } + } + removeMessages(MSG_FREE_RESOURCES); + obtainMessage(MSG_REMOTE_VOLUME_CHANGED, streamType, flags).sendToTarget(); + } + + public void postRemoteSliderVisibility(boolean visible) { + obtainMessage(MSG_SLIDER_VISIBILITY_CHANGED, + AudioService.STREAM_REMOTE_MUSIC, visible ? 1 : 0).sendToTarget(); + } + + /** + * Called by AudioService when it has received new remote playback information that + * would affect the VolumePanel display (mainly volumes). The difference with + * {@link #postRemoteVolumeChanged(int, int)} is that the handling of the posted message + * (MSG_REMOTE_VOLUME_UPDATE_IF_SHOWN) will only update the volume slider if it is being + * displayed. + * This special code path is due to the fact that remote volume updates arrive to AudioService + * asynchronously. So after AudioService has sent the volume update (which should be treated + * as a request to update the volume), the application will likely set a new volume. If the UI + * is still up, we need to refresh the display to show this new value. + */ + public void postHasNewRemotePlaybackInfo() { + if (hasMessages(MSG_REMOTE_VOLUME_UPDATE_IF_SHOWN)) return; + // don't create or prevent resources to be freed, if they disappear, this update came too + // late and shouldn't warrant the panel to be displayed longer + obtainMessage(MSG_REMOTE_VOLUME_UPDATE_IF_SHOWN).sendToTarget(); + } + public void postMasterVolumeChanged(int flags) { postVolumeChanged(STREAM_MASTER, flags); } @@ -585,6 +638,11 @@ public class VolumePanel extends Handler implements OnSeekBarChangeListener, Vie max++; break; } + + case AudioService.STREAM_REMOTE_MUSIC: { + if (LOGD) { Log.d(TAG, "showing remote volume "+index+" over "+ max); } + break; + } } StreamControl sc = mStreamControls.get(streamType); @@ -593,7 +651,8 @@ public class VolumePanel extends Handler implements OnSeekBarChangeListener, Vie sc.seekbarView.setMax(max); } sc.seekbarView.setProgress(index); - if (streamType != mAudioManager.getMasterStreamType() && isMuted(streamType)) { + if (streamType != mAudioManager.getMasterStreamType() + && streamType != AudioService.STREAM_REMOTE_MUSIC && isMuted(streamType)) { sc.seekbarView.setEnabled(false); } else { sc.seekbarView.setEnabled(true); @@ -601,7 +660,9 @@ public class VolumePanel extends Handler implements OnSeekBarChangeListener, Vie } if (!mDialog.isShowing()) { - mAudioManager.forceVolumeControlStream(streamType); + int stream = (streamType == AudioService.STREAM_REMOTE_MUSIC) ? -1 : streamType; + // when the stream is for remote playback, use -1 to reset the stream type evaluation + mAudioManager.forceVolumeControlStream(stream); mDialog.setContentView(mView); // Showing dialog - use collapsed state if (mShowCombinedVolumes) { @@ -611,7 +672,8 @@ public class VolumePanel extends Handler implements OnSeekBarChangeListener, Vie } // Do a little vibrate if applicable (only when going into vibrate mode) - if ((flags & AudioManager.FLAG_VIBRATE) != 0 && + if ((streamType != AudioService.STREAM_REMOTE_MUSIC) && + ((flags & AudioManager.FLAG_VIBRATE) != 0) && mAudioService.isStreamAffectedByRingerMode(streamType) && mAudioManager.getRingerMode() == AudioManager.RINGER_MODE_VIBRATE) { sendMessageDelayed(obtainMessage(MSG_VIBRATE), VIBRATE_DELAY); @@ -658,6 +720,72 @@ public class VolumePanel extends Handler implements OnSeekBarChangeListener, Vie mVibrator.vibrate(VIBRATE_DURATION); } + protected void onRemoteVolumeChanged(int streamType, int flags) { + // streamType is the real stream type being affected, but for the UI sliders, we + // refer to AudioService.STREAM_REMOTE_MUSIC. We still play the beeps on the real + // stream type. + if (LOGD) Log.d(TAG, "onRemoteVolumeChanged(stream:"+streamType+", flags: " + flags + ")"); + + if (((flags & AudioManager.FLAG_SHOW_UI) != 0) || mDialog.isShowing()) { + synchronized (this) { + if (mActiveStreamType != AudioService.STREAM_REMOTE_MUSIC) { + reorderSliders(AudioService.STREAM_REMOTE_MUSIC); + } + onShowVolumeChanged(AudioService.STREAM_REMOTE_MUSIC, flags); + } + } else { + if (LOGD) Log.d(TAG, "not calling onShowVolumeChanged(), no FLAG_SHOW_UI or no UI"); + } + + if ((flags & AudioManager.FLAG_PLAY_SOUND) != 0 && ! mRingIsSilent) { + removeMessages(MSG_PLAY_SOUND); + sendMessageDelayed(obtainMessage(MSG_PLAY_SOUND, streamType, flags), PLAY_SOUND_DELAY); + } + + if ((flags & AudioManager.FLAG_REMOVE_SOUND_AND_VIBRATE) != 0) { + removeMessages(MSG_PLAY_SOUND); + removeMessages(MSG_VIBRATE); + onStopSounds(); + } + + removeMessages(MSG_FREE_RESOURCES); + sendMessageDelayed(obtainMessage(MSG_FREE_RESOURCES), FREE_DELAY); + + resetTimeout(); + } + + protected void onRemoteVolumeUpdateIfShown() { + if (LOGD) Log.d(TAG, "onRemoteVolumeUpdateIfShown()"); + if (mDialog.isShowing() + && (mActiveStreamType == AudioService.STREAM_REMOTE_MUSIC) + && (mStreamControls != null)) { + onShowVolumeChanged(AudioService.STREAM_REMOTE_MUSIC, 0); + } + } + + + /** + * Handler for MSG_SLIDER_VISIBILITY_CHANGED + * Hide or show a slider + * @param streamType can be a valid stream type value, or VolumePanel.STREAM_MASTER, + * or AudioService.STREAM_REMOTE_MUSIC + * @param visible + */ + synchronized protected void onSliderVisibilityChanged(int streamType, int visible) { + if (LOGD) Log.d(TAG, "onSliderVisibilityChanged(stream="+streamType+", visi="+visible+")"); + boolean isVisible = (visible == 1); + for (int i = STREAMS.length - 1 ; i >= 0 ; i--) { + StreamResources streamRes = STREAMS[i]; + if (streamRes.streamType == streamType) { + streamRes.show = isVisible; + if (!isVisible && (mActiveStreamType == streamType)) { + mActiveStreamType = -1; + } + break; + } + } + } + /** * Lock on this VolumePanel instance as long as you use the returned ToneGenerator. */ @@ -750,6 +878,19 @@ public class VolumePanel extends Handler implements OnSeekBarChangeListener, Vie } break; } + + case MSG_REMOTE_VOLUME_CHANGED: { + onRemoteVolumeChanged(msg.arg1, msg.arg2); + break; + } + + case MSG_REMOTE_VOLUME_UPDATE_IF_SHOWN: + onRemoteVolumeUpdateIfShown(); + break; + + case MSG_SLIDER_VISIBILITY_CHANGED: + onSliderVisibilityChanged(msg.arg1, msg.arg2); + break; } } @@ -779,6 +920,17 @@ public class VolumePanel extends Handler implements OnSeekBarChangeListener, Vie } public void onStopTrackingTouch(SeekBar seekBar) { + final Object tag = seekBar.getTag(); + if (tag instanceof StreamControl) { + StreamControl sc = (StreamControl) tag; + // because remote volume updates are asynchronous, AudioService might have received + // a new remote volume value since the finger adjusted the slider. So when the + // progress of the slider isn't being tracked anymore, adjust the slider to the last + // "published" remote volume value, so the UI reflects the actual volume. + if (sc.streamType == AudioService.STREAM_REMOTE_MUSIC) { + seekBar.setProgress(getStreamVolume(AudioService.STREAM_REMOTE_MUSIC)); + } + } } public void onClick(View v) { diff --git a/core/java/com/android/internal/widget/multiwaveview/GlowPadView.java b/core/java/com/android/internal/widget/multiwaveview/GlowPadView.java index adea586..4e60b75 100644 --- a/core/java/com/android/internal/widget/multiwaveview/GlowPadView.java +++ b/core/java/com/android/internal/widget/multiwaveview/GlowPadView.java @@ -29,7 +29,6 @@ import android.content.pm.PackageManager.NameNotFoundException; import android.content.res.Resources; import android.content.res.TypedArray; import android.graphics.Canvas; -import android.graphics.RectF; import android.graphics.drawable.Drawable; import android.os.Bundle; import android.os.Vibrator; @@ -361,7 +360,6 @@ public class GlowPadView extends View { mHandleDrawable.setAlpha(0.0f); deactivateTargets(); showTargets(true); - ping(); startBackgroundAnimation(INITIAL_SHOW_HANDLE_DURATION, 1.0f); setGrabbedState(OnTriggerListener.CENTER_HANDLE); if (AccessibilityManager.getInstance(mContext).isEnabled()) { @@ -485,11 +483,7 @@ public class GlowPadView extends View { final int duration = animate ? HIDE_ANIMATION_DURATION : 0; final int delay = animate ? HIDE_ANIMATION_DELAY : 0; - // TODO: add an attribute for this. For now we'll show the expand for navbar, but not - // keyguard. - final boolean expandDisabled = !mAlwaysTrackFinger; - - final float targetScale = (expanded || expandDisabled) ? + final float targetScale = expanded ? TARGET_SCALE_EXPANDED : TARGET_SCALE_COLLAPSED; final int length = mTargetDrawables.size(); final TimeInterpolator interpolator = Ease.Cubic.easeOut; @@ -505,7 +499,7 @@ public class GlowPadView extends View { "onUpdate", mUpdateListener)); } - final float ringScaleTarget = (expanded || expandDisabled) ? + final float ringScaleTarget = expanded ? RING_SCALE_EXPANDED : RING_SCALE_COLLAPSED; mTargetAnimations.add(Tweener.to(mOuterRing, duration, "ease", interpolator, @@ -887,7 +881,7 @@ public class GlowPadView extends View { } if (AccessibilityManager.getInstance(mContext).isEnabled()) { String targetContentDescription = getTargetDescription(activeTarget); - announceText(targetContentDescription); + announceForAccessibility(targetContentDescription); } } } @@ -1095,16 +1089,10 @@ public class GlowPadView extends View { String text = String.format(directionDescription, targetDescription); utterance.append(text); } - if (utterance.length() > 0) { - announceText(utterance.toString()); - } } - } - - private void announceText(String text) { - setContentDescription(text); - sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_FOCUSED); - setContentDescription(null); + if (utterance.length() > 0) { + announceForAccessibility(utterance.toString()); + } } private String getTargetDescription(int index) { @@ -1209,25 +1197,32 @@ public class GlowPadView extends View { int existingResId) { if (existingResId == 0) return false; - try { - PackageManager packageManager = mContext.getPackageManager(); - // Look for the search icon specified in the activity meta-data - Bundle metaData = packageManager.getActivityInfo( - component, PackageManager.GET_META_DATA).metaData; - if (metaData != null) { - int iconResId = metaData.getInt(name); - if (iconResId != 0) { - Resources res = packageManager.getResourcesForActivity(component); - return replaceTargetDrawables(res, existingResId, iconResId); + boolean replaced = false; + if (component != null) { + try { + PackageManager packageManager = mContext.getPackageManager(); + // Look for the search icon specified in the activity meta-data + Bundle metaData = packageManager.getActivityInfo( + component, PackageManager.GET_META_DATA).metaData; + if (metaData != null) { + int iconResId = metaData.getInt(name); + if (iconResId != 0) { + Resources res = packageManager.getResourcesForActivity(component); + replaced = replaceTargetDrawables(res, existingResId, iconResId); + } } + } catch (NameNotFoundException e) { + Log.w(TAG, "Failed to swap drawable; " + + component.flattenToShortString() + " not found", e); + } catch (Resources.NotFoundException nfe) { + Log.w(TAG, "Failed to swap drawable from " + + component.flattenToShortString(), nfe); } - } catch (NameNotFoundException e) { - Log.w(TAG, "Failed to swap drawable; " - + component.flattenToShortString() + " not found", e); - } catch (Resources.NotFoundException nfe) { - Log.w(TAG, "Failed to swap drawable from " - + component.flattenToShortString(), nfe); } - return false; + if (!replaced) { + // Restore the original drawable + replaceTargetDrawables(mContext.getResources(), existingResId, existingResId); + } + return replaced; } } diff --git a/core/java/com/android/internal/widget/multiwaveview/PointCloud.java b/core/java/com/android/internal/widget/multiwaveview/PointCloud.java index 1a5a9a2..bbd1276 100644 --- a/core/java/com/android/internal/widget/multiwaveview/PointCloud.java +++ b/core/java/com/android/internal/widget/multiwaveview/PointCloud.java @@ -202,25 +202,25 @@ public class PointCloud { public void draw(Canvas canvas) { ArrayList<Point> points = mPointCloud; - final float cx = mDrawable != null ? (-mDrawable.getIntrinsicWidth() / 2) : 0; - final float cy = mDrawable != null ? (-mDrawable.getIntrinsicHeight() / 2) : 0; canvas.save(Canvas.MATRIX_SAVE_FLAG); canvas.scale(mScale, mScale, mCenterX, mCenterY); for (int i = 0; i < points.size(); i++) { Point point = points.get(i); final float pointSize = interp(MAX_POINT_SIZE, MIN_POINT_SIZE, point.radius / mOuterRadius); - final float px = point.x + cx + mCenterX; - final float py = point.y + cy + mCenterY; + final float px = point.x + mCenterX; + final float py = point.y + mCenterY; int alpha = getAlphaForPoint(point); if (alpha == 0) continue; if (mDrawable != null) { canvas.save(Canvas.MATRIX_SAVE_FLAG); - float s = pointSize / MAX_POINT_SIZE; + final float cx = mDrawable.getIntrinsicWidth() * 0.5f; + final float cy = mDrawable.getIntrinsicHeight() * 0.5f; + final float s = pointSize / MAX_POINT_SIZE; canvas.scale(s, s, px, py); - canvas.translate(px, py); + canvas.translate(px - cx, py - cy); mDrawable.setAlpha(alpha); mDrawable.draw(canvas); canvas.restore(); diff --git a/core/res/res/drawable-hdpi/ic_find_next_holo_light.png b/core/res/res/drawable-hdpi/ic_find_next_holo_light.png Binary files differnew file mode 100644 index 0000000..3748169 --- /dev/null +++ b/core/res/res/drawable-hdpi/ic_find_next_holo_light.png diff --git a/core/res/res/drawable-hdpi/ic_find_previous_holo_light.png b/core/res/res/drawable-hdpi/ic_find_previous_holo_light.png Binary files differnew file mode 100644 index 0000000..e4834a2 --- /dev/null +++ b/core/res/res/drawable-hdpi/ic_find_previous_holo_light.png diff --git a/core/res/res/drawable-mdpi/ic_find_next_holo_light.png b/core/res/res/drawable-mdpi/ic_find_next_holo_light.png Binary files differnew file mode 100644 index 0000000..4eea3c3 --- /dev/null +++ b/core/res/res/drawable-mdpi/ic_find_next_holo_light.png diff --git a/core/res/res/drawable-mdpi/ic_find_previous_holo_light.png b/core/res/res/drawable-mdpi/ic_find_previous_holo_light.png Binary files differnew file mode 100644 index 0000000..786e1d6 --- /dev/null +++ b/core/res/res/drawable-mdpi/ic_find_previous_holo_light.png diff --git a/core/res/res/drawable-xhdpi/ic_find_next_holo_light.png b/core/res/res/drawable-xhdpi/ic_find_next_holo_light.png Binary files differnew file mode 100644 index 0000000..5b6890d --- /dev/null +++ b/core/res/res/drawable-xhdpi/ic_find_next_holo_light.png diff --git a/core/res/res/drawable-xhdpi/ic_find_previous_holo_light.png b/core/res/res/drawable-xhdpi/ic_find_previous_holo_light.png Binary files differnew file mode 100644 index 0000000..73976c7 --- /dev/null +++ b/core/res/res/drawable-xhdpi/ic_find_previous_holo_light.png diff --git a/core/res/res/drawable/ic_lockscreen_outerring.xml b/core/res/res/drawable/ic_lockscreen_outerring.xml index 3886bb4..75bea70 100644 --- a/core/res/res/drawable/ic_lockscreen_outerring.xml +++ b/core/res/res/drawable/ic_lockscreen_outerring.xml @@ -20,5 +20,5 @@ <size android:height="@dimen/keyguard_lockscreen_outerring_diameter" android:width="@dimen/keyguard_lockscreen_outerring_diameter" /> <solid android:color="#00000000" /> - <stroke android:color="#00000000" android:width="2dp" /> + <stroke android:color="#1affffff" android:width="2dp" /> </shape> diff --git a/core/res/res/layout-sw600dp/keyguard_screen_tab_unlock.xml b/core/res/res/layout-sw600dp/keyguard_screen_tab_unlock.xml index 356e7cf..af7d011 100644 --- a/core/res/res/layout-sw600dp/keyguard_screen_tab_unlock.xml +++ b/core/res/res/layout-sw600dp/keyguard_screen_tab_unlock.xml @@ -89,6 +89,7 @@ android:layout_height="wrap_content" android:layout_gravity="center_horizontal" android:gravity="center" + android:focusable="true" android:targetDrawables="@array/lockscreen_targets_with_camera" android:targetDescriptions="@array/lockscreen_target_descriptions_with_camera" diff --git a/core/res/res/layout-sw600dp/keyguard_screen_tab_unlock_land.xml b/core/res/res/layout-sw600dp/keyguard_screen_tab_unlock_land.xml index cb1cb21..9c18b7e 100644 --- a/core/res/res/layout-sw600dp/keyguard_screen_tab_unlock_land.xml +++ b/core/res/res/layout-sw600dp/keyguard_screen_tab_unlock_land.xml @@ -89,6 +89,7 @@ android:layout_rowSpan="7" android:layout_gravity="center_vertical|right" android:gravity="center" + android:focusable="true" android:targetDrawables="@array/lockscreen_targets_with_camera" android:targetDescriptions="@array/lockscreen_target_descriptions_with_camera" diff --git a/core/res/res/layout/keyguard_screen_tab_unlock.xml b/core/res/res/layout/keyguard_screen_tab_unlock.xml index 91f65e9..81166222 100644 --- a/core/res/res/layout/keyguard_screen_tab_unlock.xml +++ b/core/res/res/layout/keyguard_screen_tab_unlock.xml @@ -130,6 +130,7 @@ android:layout_height="match_parent" android:layout_alignParentBottom="true" android:gravity="top" + android:focusable="true" android:targetDrawables="@array/lockscreen_targets_with_camera" android:targetDescriptions="@array/lockscreen_target_descriptions_with_camera" diff --git a/core/res/res/layout/keyguard_screen_tab_unlock_land.xml b/core/res/res/layout/keyguard_screen_tab_unlock_land.xml index 8b9d8e4..35e4d11 100644 --- a/core/res/res/layout/keyguard_screen_tab_unlock_land.xml +++ b/core/res/res/layout/keyguard_screen_tab_unlock_land.xml @@ -135,6 +135,7 @@ android:layout_height="match_parent" android:layout_rowSpan="7" android:gravity="left|center_vertical" + android:focusable="true" android:targetDrawables="@array/lockscreen_targets_with_camera" android:targetDescriptions="@array/lockscreen_target_descriptions_with_camera" diff --git a/core/res/res/menu/webview_find.xml b/core/res/res/menu/webview_find.xml index 526b346..1770bd9 100644 --- a/core/res/res/menu/webview_find.xml +++ b/core/res/res/menu/webview_find.xml @@ -16,11 +16,11 @@ <menu xmlns:android="http://schemas.android.com/apk/res/android"> <item android:id="@+id/find_prev" - android:icon="@drawable/ic_find_previous_holo_dark" + android:icon="?android:attr/findOnPagePreviousDrawable" android:showAsAction="always" /> <item android:id="@+id/find_next" - android:icon="@drawable/ic_find_next_holo_dark" + android:icon="?android:attr/findOnPageNextDrawable" android:showAsAction="always" /> </menu> diff --git a/core/res/res/values-af/strings.xml b/core/res/res/values-af/strings.xml index 3d63e84..7002578 100644 --- a/core/res/res/values-af/strings.xml +++ b/core/res/res/values-af/strings.xml @@ -934,10 +934,8 @@ <string name="deleteText" msgid="7070985395199629156">"vee uit"</string> <string name="inputMethod" msgid="1653630062304567879">"Invoermetode"</string> <string name="editTextMenuTitle" msgid="4909135564941815494">"Teksaksies"</string> - <!-- no translation found for low_internal_storage_view_title (5576272496365684834) --> - <skip /> - <!-- no translation found for low_internal_storage_view_text (6640505817617414371) --> - <skip /> + <string name="low_internal_storage_view_title" msgid="5576272496365684834">"Bergingspasie word min"</string> + <string name="low_internal_storage_view_text" msgid="6640505817617414371">"Sommige stelselfunksies werk moontlik nie"</string> <string name="ok" msgid="5970060430562524910">"OK"</string> <string name="cancel" msgid="6442560571259935130">"Kanselleer"</string> <string name="yes" msgid="5362982303337969312">"OK"</string> @@ -1291,6 +1289,5 @@ <string name="default_audio_route_name_hdmi" msgid="7986404173839007682">"HDMI-klank"</string> <string name="default_audio_route_category_name" msgid="3722811174003886946">"Stelsel"</string> <string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Bluetooth-oudio"</string> - <!-- no translation found for media_route_chooser_grouping_done (7966438307723317169) --> - <skip /> + <string name="media_route_chooser_grouping_done" msgid="7966438307723317169">"Klaar"</string> </resources> diff --git a/core/res/res/values-be/strings.xml b/core/res/res/values-be/strings.xml index 8e01697..ec18743 100644 --- a/core/res/res/values-be/strings.xml +++ b/core/res/res/values-be/strings.xml @@ -1288,7 +1288,6 @@ <string name="default_audio_route_name_dock_speakers" msgid="6240602982276591864">"Дынамікі станцыi"</string> <string name="default_audio_route_name_hdmi" msgid="7986404173839007682">"HDMI-аўдыёвыхад"</string> <string name="default_audio_route_category_name" msgid="3722811174003886946">"Сістэма"</string> - <!-- no translation found for bluetooth_a2dp_audio_route_name (8575624030406771015) --> - <skip /> + <string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Bluetooth-аўдыё"</string> <string name="media_route_chooser_grouping_done" msgid="7966438307723317169">"Гатова"</string> </resources> diff --git a/core/res/res/values-bg/strings.xml b/core/res/res/values-bg/strings.xml index 902cee5..a123a48 100644 --- a/core/res/res/values-bg/strings.xml +++ b/core/res/res/values-bg/strings.xml @@ -1288,7 +1288,6 @@ <string name="default_audio_route_name_dock_speakers" msgid="6240602982276591864">"Докинг станц.: Високогов."</string> <string name="default_audio_route_name_hdmi" msgid="7986404173839007682">"HDMI аудио"</string> <string name="default_audio_route_category_name" msgid="3722811174003886946">"Система"</string> - <!-- no translation found for bluetooth_a2dp_audio_route_name (8575624030406771015) --> - <skip /> + <string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Звук през Bluetooth"</string> <string name="media_route_chooser_grouping_done" msgid="7966438307723317169">"Готово"</string> </resources> diff --git a/core/res/res/values-ca/strings.xml b/core/res/res/values-ca/strings.xml index 3340d0c..94e9729 100644 --- a/core/res/res/values-ca/strings.xml +++ b/core/res/res/values-ca/strings.xml @@ -942,8 +942,8 @@ <string name="no" msgid="5141531044935541497">"Cancel·la"</string> <string name="dialog_alert_title" msgid="2049658708609043103">"Atenció"</string> <string name="loading" msgid="7933681260296021180">"S\'està carregant…"</string> - <string name="capital_on" msgid="1544682755514494298">"ACTIVAT"</string> - <string name="capital_off" msgid="6815870386972805832">"DESACTIVAT"</string> + <string name="capital_on" msgid="1544682755514494298">"Activa"</string> + <string name="capital_off" msgid="6815870386972805832">"Desactiva"</string> <string name="whichApplication" msgid="4533185947064773386">"Completa l\'acció mitjançant"</string> <string name="alwaysUse" msgid="4583018368000610438">"Utilitza-ho de manera predeterminada per a aquesta acció."</string> <string name="clearDefaultHintMsg" msgid="3252584689512077257">"Esborra els paràmetres predeterminats a Configuració del sistema > Aplicacions > Baixades."</string> diff --git a/core/res/res/values-cs/strings.xml b/core/res/res/values-cs/strings.xml index 4697a2d..6320ec1 100644 --- a/core/res/res/values-cs/strings.xml +++ b/core/res/res/values-cs/strings.xml @@ -1288,7 +1288,6 @@ <string name="default_audio_route_name_dock_speakers" msgid="6240602982276591864">"Reproduktory doku"</string> <string name="default_audio_route_name_hdmi" msgid="7986404173839007682">"Zvuk HDMI"</string> <string name="default_audio_route_category_name" msgid="3722811174003886946">"Systém"</string> - <!-- no translation found for bluetooth_a2dp_audio_route_name (8575624030406771015) --> - <skip /> + <string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Bluetooth Audio"</string> <string name="media_route_chooser_grouping_done" msgid="7966438307723317169">"Hotovo"</string> </resources> diff --git a/core/res/res/values-da/strings.xml b/core/res/res/values-da/strings.xml index 25cba5f..63456c0 100644 --- a/core/res/res/values-da/strings.xml +++ b/core/res/res/values-da/strings.xml @@ -1288,7 +1288,6 @@ <string name="default_audio_route_name_dock_speakers" msgid="6240602982276591864">"Dockstationens højttalere"</string> <string name="default_audio_route_name_hdmi" msgid="7986404173839007682">"HDMI-lyd"</string> <string name="default_audio_route_category_name" msgid="3722811174003886946">"System"</string> - <!-- no translation found for bluetooth_a2dp_audio_route_name (8575624030406771015) --> - <skip /> + <string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Bluetooth-lyd"</string> <string name="media_route_chooser_grouping_done" msgid="7966438307723317169">"Udfør"</string> </resources> diff --git a/core/res/res/values-el/strings.xml b/core/res/res/values-el/strings.xml index 481b6cb..922013d 100644 --- a/core/res/res/values-el/strings.xml +++ b/core/res/res/values-el/strings.xml @@ -942,8 +942,8 @@ <string name="no" msgid="5141531044935541497">"Ακύρωση"</string> <string name="dialog_alert_title" msgid="2049658708609043103">"Προσοχή"</string> <string name="loading" msgid="7933681260296021180">"Φόρτωση…"</string> - <string name="capital_on" msgid="1544682755514494298">"Ενεργοποιημένο"</string> - <string name="capital_off" msgid="6815870386972805832">"Απενεργοποίηση"</string> + <string name="capital_on" msgid="1544682755514494298">"Ενεργό"</string> + <string name="capital_off" msgid="6815870386972805832">"Ανενεργό"</string> <string name="whichApplication" msgid="4533185947064773386">"Ολοκλήρωση ενέργειας με τη χρήση"</string> <string name="alwaysUse" msgid="4583018368000610438">"Χρήση από προεπιλογή για αυτήν την ενέργεια."</string> <string name="clearDefaultHintMsg" msgid="3252584689512077257">"Εκκθάριση προεπιλογής στις Ρυθμίσεις συστήματος > Εφαρμογές > Ληφθείσες."</string> diff --git a/core/res/res/values-es-rUS/strings.xml b/core/res/res/values-es-rUS/strings.xml index 76a7dfd..9971e8d 100644 --- a/core/res/res/values-es-rUS/strings.xml +++ b/core/res/res/values-es-rUS/strings.xml @@ -1288,7 +1288,6 @@ <string name="default_audio_route_name_dock_speakers" msgid="6240602982276591864">"Altavoces del conector"</string> <string name="default_audio_route_name_hdmi" msgid="7986404173839007682">"Audio HDMI"</string> <string name="default_audio_route_category_name" msgid="3722811174003886946">"Sistema"</string> - <!-- no translation found for bluetooth_a2dp_audio_route_name (8575624030406771015) --> - <skip /> + <string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Audio Bluetooth"</string> <string name="media_route_chooser_grouping_done" msgid="7966438307723317169">"Listo"</string> </resources> diff --git a/core/res/res/values-es/strings.xml b/core/res/res/values-es/strings.xml index b0dd12f..59e34f0 100644 --- a/core/res/res/values-es/strings.xml +++ b/core/res/res/values-es/strings.xml @@ -1288,7 +1288,6 @@ <string name="default_audio_route_name_dock_speakers" msgid="6240602982276591864">"Altavoces del conector"</string> <string name="default_audio_route_name_hdmi" msgid="7986404173839007682">"Audio HDMI"</string> <string name="default_audio_route_category_name" msgid="3722811174003886946">"Sistema"</string> - <!-- no translation found for bluetooth_a2dp_audio_route_name (8575624030406771015) --> - <skip /> + <string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Audio Bluetooth"</string> <string name="media_route_chooser_grouping_done" msgid="7966438307723317169">"Fin"</string> </resources> diff --git a/core/res/res/values-fa/strings.xml b/core/res/res/values-fa/strings.xml index b633542..d9df2a2 100644 --- a/core/res/res/values-fa/strings.xml +++ b/core/res/res/values-fa/strings.xml @@ -934,10 +934,8 @@ <string name="deleteText" msgid="7070985395199629156">"حذف"</string> <string name="inputMethod" msgid="1653630062304567879">"روش ورودی"</string> <string name="editTextMenuTitle" msgid="4909135564941815494">"عملکردهای متنی"</string> - <!-- no translation found for low_internal_storage_view_title (5576272496365684834) --> - <skip /> - <!-- no translation found for low_internal_storage_view_text (6640505817617414371) --> - <skip /> + <string name="low_internal_storage_view_title" msgid="5576272496365684834">"فضای ذخیرهسازی رو به اتمام است"</string> + <string name="low_internal_storage_view_text" msgid="6640505817617414371">"برخی از عملکردهای سیستم ممکن است کار نکنند"</string> <string name="ok" msgid="5970060430562524910">"تأیید"</string> <string name="cancel" msgid="6442560571259935130">"لغو"</string> <string name="yes" msgid="5362982303337969312">"تأیید"</string> @@ -1290,8 +1288,6 @@ <string name="default_audio_route_name_dock_speakers" msgid="6240602982276591864">"بلندگوهای جایگاه اتصال"</string> <string name="default_audio_route_name_hdmi" msgid="7986404173839007682">"صدای HDMI"</string> <string name="default_audio_route_category_name" msgid="3722811174003886946">"سیستم"</string> - <!-- no translation found for bluetooth_a2dp_audio_route_name (8575624030406771015) --> - <skip /> - <!-- no translation found for media_route_chooser_grouping_done (7966438307723317169) --> - <skip /> + <string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"بلوتوثهای صوتی"</string> + <string name="media_route_chooser_grouping_done" msgid="7966438307723317169">"انجام شد"</string> </resources> diff --git a/core/res/res/values-fr/strings.xml b/core/res/res/values-fr/strings.xml index 5b13636..4a7a9c7 100644 --- a/core/res/res/values-fr/strings.xml +++ b/core/res/res/values-fr/strings.xml @@ -1288,7 +1288,6 @@ <string name="default_audio_route_name_dock_speakers" msgid="6240602982276591864">"Haut-parleurs de la station d\'accueil"</string> <string name="default_audio_route_name_hdmi" msgid="7986404173839007682">"Audio HDMI"</string> <string name="default_audio_route_category_name" msgid="3722811174003886946">"Système"</string> - <!-- no translation found for bluetooth_a2dp_audio_route_name (8575624030406771015) --> - <skip /> + <string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Audio Bluetooth"</string> <string name="media_route_chooser_grouping_done" msgid="7966438307723317169">"OK"</string> </resources> diff --git a/core/res/res/values-hi/strings.xml b/core/res/res/values-hi/strings.xml index 5128132..56a29bf 100644 --- a/core/res/res/values-hi/strings.xml +++ b/core/res/res/values-hi/strings.xml @@ -1288,7 +1288,6 @@ <string name="default_audio_route_name_dock_speakers" msgid="6240602982276591864">"डॉक स्पीकर"</string> <string name="default_audio_route_name_hdmi" msgid="7986404173839007682">"HDMI ऑडियो"</string> <string name="default_audio_route_category_name" msgid="3722811174003886946">"सिस्टम"</string> - <!-- no translation found for bluetooth_a2dp_audio_route_name (8575624030406771015) --> - <skip /> + <string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Bluetooth ऑडियो"</string> <string name="media_route_chooser_grouping_done" msgid="7966438307723317169">"पूर्ण"</string> </resources> diff --git a/core/res/res/values-hr/strings.xml b/core/res/res/values-hr/strings.xml index 967e3e1..a144b97 100644 --- a/core/res/res/values-hr/strings.xml +++ b/core/res/res/values-hr/strings.xml @@ -942,8 +942,8 @@ <string name="no" msgid="5141531044935541497">"Odustani"</string> <string name="dialog_alert_title" msgid="2049658708609043103">"Pažnja"</string> <string name="loading" msgid="7933681260296021180">"Učitavanje…"</string> - <string name="capital_on" msgid="1544682755514494298">"Uključeno"</string> - <string name="capital_off" msgid="6815870386972805832">"Isključeno"</string> + <string name="capital_on" msgid="1544682755514494298">"Uklj."</string> + <string name="capital_off" msgid="6815870386972805832">"Isklj."</string> <string name="whichApplication" msgid="4533185947064773386">"Radnju dovrši pomoću stavke"</string> <string name="alwaysUse" msgid="4583018368000610438">"Koristi se kao zadana postavka za ovu lokaciju."</string> <string name="clearDefaultHintMsg" msgid="3252584689512077257">"Izbrisati zadano u Postavkama sustava > Aplikacije > Preuzimanja."</string> @@ -1288,7 +1288,6 @@ <string name="default_audio_route_name_dock_speakers" msgid="6240602982276591864">"Zvučnici postolja"</string> <string name="default_audio_route_name_hdmi" msgid="7986404173839007682">"HDMI audio"</string> <string name="default_audio_route_category_name" msgid="3722811174003886946">"Sustav"</string> - <!-- no translation found for bluetooth_a2dp_audio_route_name (8575624030406771015) --> - <skip /> + <string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Bluetooth zvuk"</string> <string name="media_route_chooser_grouping_done" msgid="7966438307723317169">"Gotovo"</string> </resources> diff --git a/core/res/res/values-hu/strings.xml b/core/res/res/values-hu/strings.xml index a6ab456..dad7dc6 100644 --- a/core/res/res/values-hu/strings.xml +++ b/core/res/res/values-hu/strings.xml @@ -1288,7 +1288,6 @@ <string name="default_audio_route_name_dock_speakers" msgid="6240602982276591864">"Dokkolóegység hangszórója"</string> <string name="default_audio_route_name_hdmi" msgid="7986404173839007682">"HDMI audió"</string> <string name="default_audio_route_category_name" msgid="3722811174003886946">"Rendszer"</string> - <!-- no translation found for bluetooth_a2dp_audio_route_name (8575624030406771015) --> - <skip /> + <string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Bluetooth hang"</string> <string name="media_route_chooser_grouping_done" msgid="7966438307723317169">"Kész"</string> </resources> diff --git a/core/res/res/values-ja/strings.xml b/core/res/res/values-ja/strings.xml index f58fe5d..303db08 100644 --- a/core/res/res/values-ja/strings.xml +++ b/core/res/res/values-ja/strings.xml @@ -1288,7 +1288,6 @@ <string name="default_audio_route_name_dock_speakers" msgid="6240602982276591864">"ホルダーのスピーカー"</string> <string name="default_audio_route_name_hdmi" msgid="7986404173839007682">"HDMIオーディオ"</string> <string name="default_audio_route_category_name" msgid="3722811174003886946">"システム"</string> - <!-- no translation found for bluetooth_a2dp_audio_route_name (8575624030406771015) --> - <skip /> + <string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Bluetooth音声"</string> <string name="media_route_chooser_grouping_done" msgid="7966438307723317169">"完了"</string> </resources> diff --git a/core/res/res/values-ko/strings.xml b/core/res/res/values-ko/strings.xml index b1dd2d9..f95546b 100644 --- a/core/res/res/values-ko/strings.xml +++ b/core/res/res/values-ko/strings.xml @@ -220,7 +220,7 @@ <string name="permlab_getDetailedTasks" msgid="6229468674753529501">"실행 중인 앱 세부정보 검색"</string> <string name="permdesc_getDetailedTasks" msgid="153824741440717599">"앱이 현재 실행 중이거나 최근에 실행된 작업에 대한 상세한 정보를 검색할 수 있도록 허용합니다. 이 경우 악성 앱이 다른 앱에 대한 개인 정보를 검색할 수 있습니다."</string> <string name="permlab_reorderTasks" msgid="2018575526934422779">"실행 중인 앱 순서 재지정"</string> - <string name="permdesc_reorderTasks" msgid="7734217754877439351">"앱이 작업을 포그라운드나 백그라운드로 이동할 수 있도록 허용합니다. 이 경우 악성 앱이 사용자의 조작 없이 앞으로 이동할 수 있습니다. 사용자의 입력 없이 이를 수행할 수 있습니다."</string> + <string name="permdesc_reorderTasks" msgid="7734217754877439351">"앱이 사용자의 입력 없이 작업을 포그라운드나 백그라운드로 이동할 수 있도록 허용합니다."</string> <string name="permlab_removeTasks" msgid="6821513401870377403">"실행 중인 앱 중지"</string> <string name="permdesc_removeTasks" msgid="1394714352062635493">"애플리케이션이 작업을 삭제하거나 다른 애플리케이션을 중지시킬 수 있도록 허용합니다. 이 경우 악성 애플리케이션이 다른 애플리케이션의 동작을 멈추게 할 수 있습니다."</string> <string name="permlab_startAnyActivity" msgid="2918768238045206456">"원하는 활동 시작"</string> @@ -234,7 +234,7 @@ <string name="permlab_enableCarMode" msgid="5684504058192921098">"운전모드 사용"</string> <string name="permdesc_enableCarMode" msgid="4853187425751419467">"앱이 운전모드를 사용할 수 있도록 허용합니다."</string> <string name="permlab_killBackgroundProcesses" msgid="3914026687420177202">"다른 앱 종료"</string> - <string name="permdesc_killBackgroundProcesses" msgid="4593353235959733119">"앱이 다른 앱의 백그라운드 프로세스를 종료할 수 있도록 허용합니다. 이 경우 해당 앱이 실행 중지될 수 있습니다."</string> + <string name="permdesc_killBackgroundProcesses" msgid="4593353235959733119">"앱이 다른 앱의 백그라운드 프로세스를 종료할 수 있도록 허용합니다. 이 경우 다른 앱이 실행 중지될 수 있습니다."</string> <string name="permlab_forceStopPackages" msgid="2329627428832067700">"다른 앱 강제 종료"</string> <string name="permdesc_forceStopPackages" msgid="5253157296183940812">"앱이 다른 앱을 강제로 종료할 수 있도록 허용합니다."</string> <string name="permlab_forceBack" msgid="652935204072584616">"앱 강제 종료"</string> @@ -368,8 +368,8 @@ <string name="permdesc_readCalendar" product="tablet" msgid="4216462049057658723">"앱이 친구나 동료의 일정을 포함하여 태블릿에 저장된 모든 캘린더 일정을 읽을 수 있도록 허용합니다. 이 경우 앱이 비밀유지 또는 기밀성을 무시하고 캘린더 데이터를 공유 또는 저장할 수도 있습니다."</string> <string name="permdesc_readCalendar" product="default" msgid="7434548682470851583">"앱이 친구나 동료의 일정을 포함하여 휴대전화에 저장된 모든 캘린더 일정을 읽을 수 있도록 허용합니다. 이 경우 앱이 비밀유지 또는 기밀성과 관계 없이 캘린더 데이터를 공유 또는 저장할 수도 있습니다."</string> <string name="permlab_writeCalendar" msgid="8438874755193825647">"소유자 몰래 캘린더 일정을 추가 또는 수정하고 참석자에게 이메일 전송"</string> - <string name="permdesc_writeCalendar" product="tablet" msgid="6679035520113668528">"앱이 친구나 동료의 일정을 포함하여 태블릿에서 수정할 수 있는 일정을 추가, 삭제, 변경할 수 있도록 허용합니다. 이 경우 앱이 캘린더 소유자로부터 온 것으로 보이는 메시지를 전송하거나 소유자 모르게 일정을 수정할 수도 있습니다."</string> - <string name="permdesc_writeCalendar" product="default" msgid="2324469496327249376">"앱이 친구나 동료의 일정을 포함하여 휴대전화에서 수정할 수 있는 일정을 추가, 삭제, 변경할 수 있도록 허용합니다. 이 경우 앱이 캘린더 소유자로부터 온 것으로 보이는 메시지를 전송하거나 소유자 모르게 일정을 수정할 수도 있습니다."</string> + <string name="permdesc_writeCalendar" product="tablet" msgid="6679035520113668528">"앱이 친구나 동료의 일정을 포함하여 태블릿에서 수정할 수 있는 일정을 추가, 삭제, 변경할 수 있도록 허용합니다. 이 경우 앱이 캘린더 소유자가 보내는 것처럼 메시지를 전송하거나 소유자 모르게 일정을 수정할 수도 있습니다."</string> + <string name="permdesc_writeCalendar" product="default" msgid="2324469496327249376">"앱이 친구나 동료의 일정을 포함하여 휴대전화에서 수정할 수 있는 일정을 추가, 삭제, 변경할 수 있도록 허용합니다. 이 경우 앱이 캘린더 소유자가 보내는 것처럼 메시지를 전송하거나 소유자 모르게 일정을 수정할 수도 있습니다."</string> <string name="permlab_accessMockLocation" msgid="8688334974036823330">"테스트를 위해 위치 정보제공자로 가장"</string> <string name="permdesc_accessMockLocation" msgid="5808711039482051824">"테스트용 가상 위치 소스를 만들거나 새로운 위치 정보 제공업체를 설치합니다. 이 경우 앱이 GPS 또는 위치 정보 제공업체 등 기타 위치 소스가 반환한 위치 또는 상태를 덮어쓸 수 있습니다."</string> <string name="permlab_accessLocationExtraCommands" msgid="2836308076720553837">"추가 위치 제공업체 명령에 액세스"</string> @@ -468,8 +468,8 @@ <string name="permlab_accountManagerService" msgid="4829262349691386986">"AccountManagerService로 활동"</string> <string name="permdesc_accountManagerService" msgid="1948455552333615954">"애플리케이션이 AccountAuthenticators를 호출할 수 있도록 허용합니다."</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="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> @@ -493,8 +493,8 @@ <string name="permlab_changeWifiState" msgid="6550641188749128035">"Wi-Fi 연결 및 연결 해제"</string> <string name="permdesc_changeWifiState" msgid="7137950297386127533">"앱이 Wi-Fi 액세스 포인트에 연결하거나 연결을 끊고, Wi-Fi 네트워크의 기기 설정을 변경할 수 있도록 허용합니다."</string> <string name="permlab_changeWifiMulticastState" msgid="1368253871483254784">"Wi-Fi 멀티캐스트 수신 허용"</string> - <string name="permdesc_changeWifiMulticastState" product="tablet" msgid="7969774021256336548">"앱이 사용자의 태블릿뿐 아니라 여러 주소를 사용하여 Wi-Fi 네트워크에서 모든 기기로 전송된 패킷을 받도록 허용합니다. 이 경우 비멀티캐스트 모드보다 전력을 더 많이 소비합니다."</string> - <string name="permdesc_changeWifiMulticastState" product="default" msgid="6851949706025349926">"앱이 사용자의 휴대전화뿐 아니라 여러 주소를 사용하여 Wi-Fi 네트워크에서 모든 기기로 전송된 패킷을 받을 수 있도록 허용합니다. 이 경우 비멀티캐스트 모드보다 전력을 더 많이 소비합니다."</string> + <string name="permdesc_changeWifiMulticastState" product="tablet" msgid="7969774021256336548">"앱이 사용자의 태블릿뿐 아니라 멀티캐스트 주소를 사용하여 Wi-Fi 네트워크에서 모든 기기로 전송된 패킷을 받도록 허용합니다. 이 경우 비멀티캐스트 모드보다 전력을 더 많이 소비합니다."</string> + <string name="permdesc_changeWifiMulticastState" product="default" msgid="6851949706025349926">"앱이 사용자의 휴대전화뿐 아니라 멀티캐스트 주소를 사용하여 Wi-Fi 네트워크에서 모든 기기로 전송된 패킷을 받을 수 있도록 허용합니다. 이 경우 비멀티캐스트 모드보다 전력을 더 많이 소비합니다."</string> <string name="permlab_bluetoothAdmin" msgid="6006967373935926659">"블루투스 설정에 액세스"</string> <string name="permdesc_bluetoothAdmin" product="tablet" msgid="6921177471748882137">"앱이 로컬 블루투스 태블릿을 설정한 다음 원격 기기를 검색하여 페어링할 수 있도록 허용합니다."</string> <string name="permdesc_bluetoothAdmin" product="default" msgid="8931682159331542137">"앱이 로컬 블루투스 휴대전화를 설정한 다음 원격 기기를 검색하여 페어링할 수 있도록 허용합니다."</string> @@ -511,9 +511,9 @@ <string name="permlab_disableKeyguard" msgid="3598496301486439258">"화면 잠금 사용 중지"</string> <string name="permdesc_disableKeyguard" msgid="6034203065077122992">"앱이 키 잠금 및 관련 비밀번호 보안을 사용중지할 수 있도록 허용합니다. 예를 들어, 휴대전화가 수신전화를 받을 때 키 잠금을 사용중지했다가 통화가 끝나면 키 잠금을 다시 사용할 수 있습니다."</string> <string name="permlab_readSyncSettings" msgid="6201810008230503052">"동기화 설정 읽기"</string> - <string name="permdesc_readSyncSettings" msgid="2706745674569678644">"앱이 계정의 동기화 설정을 읽을 수 있도록 허용합니다. 예를 들어, 계정에서 피플 앱(People app)을 동기화할지 여부를 확인할 수 있습니다."</string> + <string name="permdesc_readSyncSettings" msgid="2706745674569678644">"앱이 계정의 동기화 설정을 읽을 수 있도록 허용합니다. 예를 들어, 계정에서 피플 앱을 동기화할지 여부를 확인할 수 있습니다."</string> <string name="permlab_writeSyncSettings" msgid="5408694875793945314">"동기화 사용 및 사용 중지 전환"</string> - <string name="permdesc_writeSyncSettings" msgid="8956262591306369868">"앱이 계정의 동기화 설정을 수정할 수 있도록 허용합니다. 예를 들어, 계정에서 피플 앱 동기화를 사용하도록 설정할 목적으로 앱이 사용될 수 있습니다."</string> + <string name="permdesc_writeSyncSettings" msgid="8956262591306369868">"앱이 계정의 동기화 설정을 수정할 수 있도록 허용합니다. 예를 들어, 계정에서 피플 앱을 동기화할 목적으로 앱이 사용될 수 있습니다."</string> <string name="permlab_readSyncStats" msgid="7396577451360202448">"동기화 통계 읽기"</string> <string name="permdesc_readSyncStats" msgid="1510143761757606156">"앱이 동기화된 일정의 기록이나 동기화된 데이터의 양 등을 포함하여 계정의 동기화 통계를 읽을 수 있도록 허용합니다."</string> <string name="permlab_subscribedFeedsRead" msgid="4756609637053353318">"가입된 피드 읽기"</string> @@ -1118,7 +1118,7 @@ <string name="permdesc_pkgUsageStats" msgid="1106612424254277630">"앱이 수집된 구성요소 사용 통계를 수정하도록 합니다. 일반 앱에서는 사용하지 않습니다."</string> <string name="permlab_copyProtectedData" msgid="4341036311211406692">"콘텐츠 복사"</string> <string name="permdesc_copyProtectedData" msgid="4390697124288317831">"기본 컨테이너 서비스를 호출하여 콘텐츠를 복사할 수 있도록 허용합니다. 일반 앱에서는 사용하지 않습니다."</string> - <string name="permlab_route_media_output" msgid="1642024455750414694">"미디어 출력을 연결"</string> + <string name="permlab_route_media_output" msgid="1642024455750414694">"미디어 출력 연결"</string> <string name="permdesc_route_media_output" msgid="4932818749547244346">"앱이 미디어 출력을 기타 외부 기기에 연결할 수 있도록 허용합니다."</string> <string name="tutorial_double_tap_to_zoom_message_short" msgid="4070433208160063538">"확대/축소하려면 두 번 터치하세요."</string> <string name="gadget_host_error_inflating" msgid="4882004314906466162">"위젯을 추가할 수 없습니다."</string> @@ -1288,7 +1288,6 @@ <string name="default_audio_route_name_dock_speakers" msgid="6240602982276591864">"도크 스피커"</string> <string name="default_audio_route_name_hdmi" msgid="7986404173839007682">"HDMI 오디오"</string> <string name="default_audio_route_category_name" msgid="3722811174003886946">"시스템"</string> - <!-- no translation found for bluetooth_a2dp_audio_route_name (8575624030406771015) --> - <skip /> + <string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"블루투스 오디오"</string> <string name="media_route_chooser_grouping_done" msgid="7966438307723317169">"완료"</string> </resources> diff --git a/core/res/res/values-lt/strings.xml b/core/res/res/values-lt/strings.xml index b6a4b23..c911e14 100644 --- a/core/res/res/values-lt/strings.xml +++ b/core/res/res/values-lt/strings.xml @@ -942,8 +942,8 @@ <string name="no" msgid="5141531044935541497">"Atšaukti"</string> <string name="dialog_alert_title" msgid="2049658708609043103">"Dėmesio"</string> <string name="loading" msgid="7933681260296021180">"Įkeliama..."</string> - <string name="capital_on" msgid="1544682755514494298">"ĮJUNGTA"</string> - <string name="capital_off" msgid="6815870386972805832">"IŠJUNGTA"</string> + <string name="capital_on" msgid="1544682755514494298">"ĮJ."</string> + <string name="capital_off" msgid="6815870386972805832">"IŠJ."</string> <string name="whichApplication" msgid="4533185947064773386">"Užbaigti veiksmą naudojant"</string> <string name="alwaysUse" msgid="4583018368000610438">"Šiam veiksmui tai naudoti pagal numatytuosius nustatymus."</string> <string name="clearDefaultHintMsg" msgid="3252584689512077257">"Numatytuosius nustatymus išvalykite nuėję į „Sistemos nustatymai“ > „Programos“ > „Atsisiųsta“."</string> diff --git a/core/res/res/values-lv/strings.xml b/core/res/res/values-lv/strings.xml index f497083..f28217c 100644 --- a/core/res/res/values-lv/strings.xml +++ b/core/res/res/values-lv/strings.xml @@ -934,7 +934,7 @@ <string name="deleteText" msgid="7070985395199629156">"dzēst"</string> <string name="inputMethod" msgid="1653630062304567879">"Ievades metode"</string> <string name="editTextMenuTitle" msgid="4909135564941815494">"Teksta darbības"</string> - <string name="low_internal_storage_view_title" msgid="5576272496365684834">"Brīvās krātuves apjoms samazinās"</string> + <string name="low_internal_storage_view_title" msgid="5576272496365684834">"Paliek maz brīvas vietas"</string> <string name="low_internal_storage_view_text" msgid="6640505817617414371">"Dažas sistēmas funkcijas var nedarboties."</string> <string name="ok" msgid="5970060430562524910">"Labi"</string> <string name="cancel" msgid="6442560571259935130">"Atcelt"</string> diff --git a/core/res/res/values-ms/strings.xml b/core/res/res/values-ms/strings.xml index 426da6b..e861fdd 100644 --- a/core/res/res/values-ms/strings.xml +++ b/core/res/res/values-ms/strings.xml @@ -1288,7 +1288,6 @@ <string name="default_audio_route_name_dock_speakers" msgid="6240602982276591864">"Pembesar suara dok"</string> <string name="default_audio_route_name_hdmi" msgid="7986404173839007682">"Audio HDMI"</string> <string name="default_audio_route_category_name" msgid="3722811174003886946">"Sistem"</string> - <!-- no translation found for bluetooth_a2dp_audio_route_name (8575624030406771015) --> - <skip /> + <string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Audio Bluetooth"</string> <string name="media_route_chooser_grouping_done" msgid="7966438307723317169">"Selesai"</string> </resources> diff --git a/core/res/res/values-nl/strings.xml b/core/res/res/values-nl/strings.xml index d840532..ac6ec6c 100644 --- a/core/res/res/values-nl/strings.xml +++ b/core/res/res/values-nl/strings.xml @@ -1288,7 +1288,6 @@ <string name="default_audio_route_name_dock_speakers" msgid="6240602982276591864">"Dockluidsprekers"</string> <string name="default_audio_route_name_hdmi" msgid="7986404173839007682">"HDMI-audio"</string> <string name="default_audio_route_category_name" msgid="3722811174003886946">"Systeem"</string> - <!-- no translation found for bluetooth_a2dp_audio_route_name (8575624030406771015) --> - <skip /> + <string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Bluetooth-audio"</string> <string name="media_route_chooser_grouping_done" msgid="7966438307723317169">"Gereed"</string> </resources> diff --git a/core/res/res/values-ro/strings.xml b/core/res/res/values-ro/strings.xml index a2afc72..ff66810 100644 --- a/core/res/res/values-ro/strings.xml +++ b/core/res/res/values-ro/strings.xml @@ -934,10 +934,8 @@ <string name="deleteText" msgid="7070985395199629156">"ştergeţi"</string> <string name="inputMethod" msgid="1653630062304567879">"Metodă de intrare"</string> <string name="editTextMenuTitle" msgid="4909135564941815494">"Acţiuni pentru text"</string> - <!-- no translation found for low_internal_storage_view_title (5576272496365684834) --> - <skip /> - <!-- no translation found for low_internal_storage_view_text (6640505817617414371) --> - <skip /> + <string name="low_internal_storage_view_title" msgid="5576272496365684834">"Spaţiul de stocare aproape ocupat"</string> + <string name="low_internal_storage_view_text" msgid="6640505817617414371">"Este posibil ca unele funcţii de sistem să nu funcţioneze"</string> <string name="ok" msgid="5970060430562524910">"OK"</string> <string name="cancel" msgid="6442560571259935130">"Anulaţi"</string> <string name="yes" msgid="5362982303337969312">"OK"</string> @@ -1290,8 +1288,6 @@ <string name="default_audio_route_name_dock_speakers" msgid="6240602982276591864">"Difuz. dispozit. andocare"</string> <string name="default_audio_route_name_hdmi" msgid="7986404173839007682">"Ieşire audio HDMI"</string> <string name="default_audio_route_category_name" msgid="3722811174003886946">"Sistem"</string> - <!-- no translation found for bluetooth_a2dp_audio_route_name (8575624030406771015) --> - <skip /> - <!-- no translation found for media_route_chooser_grouping_done (7966438307723317169) --> - <skip /> + <string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Audio Bluetooth"</string> + <string name="media_route_chooser_grouping_done" msgid="7966438307723317169">"Terminat"</string> </resources> diff --git a/core/res/res/values-ru/strings.xml b/core/res/res/values-ru/strings.xml index ed8cd7f..c86082d 100644 --- a/core/res/res/values-ru/strings.xml +++ b/core/res/res/values-ru/strings.xml @@ -934,7 +934,7 @@ <string name="deleteText" msgid="7070985395199629156">"удалить"</string> <string name="inputMethod" msgid="1653630062304567879">"Способ ввода"</string> <string name="editTextMenuTitle" msgid="4909135564941815494">"Операции с текстом"</string> - <string name="low_internal_storage_view_title" msgid="5576272496365684834">"Заканчивается пространство"</string> + <string name="low_internal_storage_view_title" msgid="5576272496365684834">"Заканчивается свободное место"</string> <string name="low_internal_storage_view_text" msgid="6640505817617414371">"Некоторые системные функции могут не работать"</string> <string name="ok" msgid="5970060430562524910">"ОК"</string> <string name="cancel" msgid="6442560571259935130">"Отмена"</string> @@ -1288,7 +1288,6 @@ <string name="default_audio_route_name_dock_speakers" msgid="6240602982276591864">"Динамики док-станции"</string> <string name="default_audio_route_name_hdmi" msgid="7986404173839007682">"HDMI-аудио"</string> <string name="default_audio_route_category_name" msgid="3722811174003886946">"Система"</string> - <!-- no translation found for bluetooth_a2dp_audio_route_name (8575624030406771015) --> - <skip /> + <string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Воспроизведение звука через Bluetooth"</string> <string name="media_route_chooser_grouping_done" msgid="7966438307723317169">"Готово"</string> </resources> diff --git a/core/res/res/values-sk/strings.xml b/core/res/res/values-sk/strings.xml index dc240b4..86fc758 100644 --- a/core/res/res/values-sk/strings.xml +++ b/core/res/res/values-sk/strings.xml @@ -1288,7 +1288,6 @@ <string name="default_audio_route_name_dock_speakers" msgid="6240602982276591864">"Reproduktory doku"</string> <string name="default_audio_route_name_hdmi" msgid="7986404173839007682">"Zvuk HDMI"</string> <string name="default_audio_route_category_name" msgid="3722811174003886946">"Systém"</string> - <!-- no translation found for bluetooth_a2dp_audio_route_name (8575624030406771015) --> - <skip /> + <string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Bluetooth audio"</string> <string name="media_route_chooser_grouping_done" msgid="7966438307723317169">"Hotovo"</string> </resources> diff --git a/core/res/res/values-sl/strings.xml b/core/res/res/values-sl/strings.xml index 4d543c7..a0a6e49 100644 --- a/core/res/res/values-sl/strings.xml +++ b/core/res/res/values-sl/strings.xml @@ -1079,7 +1079,7 @@ <string name="extmedia_format_message" product="nosdcard" msgid="3934016853425761078">"Vse datoteke, shranjene v v pomnilniku USB, bodo izbrisane. Tega dejanja ni mogoče razveljaviti!"</string> <string name="extmedia_format_message" product="default" msgid="14131895027543830">"Vsi podatki v napravi bodo izgubljeni."</string> <string name="extmedia_format_button_format" msgid="4131064560127478695">"Formatiraj"</string> - <string name="adb_active_notification_title" msgid="6729044778949189918">"iskanje in odpravljanje napak USB je povezano"</string> + <string name="adb_active_notification_title" msgid="6729044778949189918">"Iskanje in odpravljanje napak USB je povezano"</string> <string name="adb_active_notification_message" msgid="1016654627626476142">"Dotaknite se, če želite onemogočiti iskanje in odpravljanje napak prek vrat USB."</string> <string name="select_input_method" msgid="4653387336791222978">"Izberite način vnosa"</string> <string name="configure_input_methods" msgid="9091652157722495116">"Nastavi načine vnosa"</string> @@ -1288,7 +1288,6 @@ <string name="default_audio_route_name_dock_speakers" msgid="6240602982276591864">"Zvočniki stojala"</string> <string name="default_audio_route_name_hdmi" msgid="7986404173839007682">"Zvok HDMI"</string> <string name="default_audio_route_category_name" msgid="3722811174003886946">"Sistem"</string> - <!-- no translation found for bluetooth_a2dp_audio_route_name (8575624030406771015) --> - <skip /> + <string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Zvok prek Bluetootha"</string> <string name="media_route_chooser_grouping_done" msgid="7966438307723317169">"Končano"</string> </resources> diff --git a/core/res/res/values-sr/strings.xml b/core/res/res/values-sr/strings.xml index dfe26b5..79ab8ca 100644 --- a/core/res/res/values-sr/strings.xml +++ b/core/res/res/values-sr/strings.xml @@ -934,7 +934,7 @@ <string name="deleteText" msgid="7070985395199629156">"избриши"</string> <string name="inputMethod" msgid="1653630062304567879">"Метод уноса"</string> <string name="editTextMenuTitle" msgid="4909135564941815494">"Радње у вези са текстом"</string> - <string name="low_internal_storage_view_title" msgid="5576272496365684834">"Недовољно простора за складиштење"</string> + <string name="low_internal_storage_view_title" msgid="5576272496365684834">"Простор за складиштење је на измаку"</string> <string name="low_internal_storage_view_text" msgid="6640505817617414371">"Неке системске функције можда не функционишу"</string> <string name="ok" msgid="5970060430562524910">"Потврди"</string> <string name="cancel" msgid="6442560571259935130">"Откажи"</string> @@ -942,8 +942,8 @@ <string name="no" msgid="5141531044935541497">"Откажи"</string> <string name="dialog_alert_title" msgid="2049658708609043103">"Пажња"</string> <string name="loading" msgid="7933681260296021180">"Учитавање…"</string> - <string name="capital_on" msgid="1544682755514494298">"УКЉУЧЕНО"</string> - <string name="capital_off" msgid="6815870386972805832">"ИСКЉУЧЕНО"</string> + <string name="capital_on" msgid="1544682755514494298">"ДА"</string> + <string name="capital_off" msgid="6815870386972805832">"НЕ"</string> <string name="whichApplication" msgid="4533185947064773386">"Довршавање радње помоћу"</string> <string name="alwaysUse" msgid="4583018368000610438">"Подразумевано користи за ову радњу."</string> <string name="clearDefaultHintMsg" msgid="3252584689512077257">"Обришите подразумевано подешавање у менију Подешавања система > Апликације > Преузето."</string> @@ -1288,7 +1288,6 @@ <string name="default_audio_route_name_dock_speakers" msgid="6240602982276591864">"Звучници базне станице"</string> <string name="default_audio_route_name_hdmi" msgid="7986404173839007682">"HDMI аудио"</string> <string name="default_audio_route_category_name" msgid="3722811174003886946">"Систем"</string> - <!-- no translation found for bluetooth_a2dp_audio_route_name (8575624030406771015) --> - <skip /> + <string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Bluetooth аудио"</string> <string name="media_route_chooser_grouping_done" msgid="7966438307723317169">"Готово"</string> </resources> diff --git a/core/res/res/values-sv/strings.xml b/core/res/res/values-sv/strings.xml index f94fe3f..4e10801 100644 --- a/core/res/res/values-sv/strings.xml +++ b/core/res/res/values-sv/strings.xml @@ -1288,7 +1288,6 @@ <string name="default_audio_route_name_dock_speakers" msgid="6240602982276591864">"Dockningsstationens högtalare"</string> <string name="default_audio_route_name_hdmi" msgid="7986404173839007682">"HDMI-ljud"</string> <string name="default_audio_route_category_name" msgid="3722811174003886946">"System"</string> - <!-- no translation found for bluetooth_a2dp_audio_route_name (8575624030406771015) --> - <skip /> + <string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Bluetooth-ljud"</string> <string name="media_route_chooser_grouping_done" msgid="7966438307723317169">"Klar"</string> </resources> diff --git a/core/res/res/values-sw/strings.xml b/core/res/res/values-sw/strings.xml index cf0f69f..5701a00 100644 --- a/core/res/res/values-sw/strings.xml +++ b/core/res/res/values-sw/strings.xml @@ -934,10 +934,8 @@ <string name="deleteText" msgid="7070985395199629156">"futa"</string> <string name="inputMethod" msgid="1653630062304567879">"Mbinu ya uingizaji"</string> <string name="editTextMenuTitle" msgid="4909135564941815494">"Vitendo vya maandishi"</string> - <!-- no translation found for low_internal_storage_view_title (5576272496365684834) --> - <skip /> - <!-- no translation found for low_internal_storage_view_text (6640505817617414371) --> - <skip /> + <string name="low_internal_storage_view_title" msgid="5576272496365684834">"Nafasi ya kuhafadhi inakwisha"</string> + <string name="low_internal_storage_view_text" msgid="6640505817617414371">"Baadhi ya vipengee vya mfumo huenda visifanye kazi"</string> <string name="ok" msgid="5970060430562524910">"Sawa"</string> <string name="cancel" msgid="6442560571259935130">"Ghairi"</string> <string name="yes" msgid="5362982303337969312">"Sawa"</string> @@ -1291,6 +1289,5 @@ <string name="default_audio_route_name_hdmi" msgid="7986404173839007682">"Sauti ya HDMI"</string> <string name="default_audio_route_category_name" msgid="3722811174003886946">"Mfumo"</string> <string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Sauti ya Bluetooth"</string> - <!-- no translation found for media_route_chooser_grouping_done (7966438307723317169) --> - <skip /> + <string name="media_route_chooser_grouping_done" msgid="7966438307723317169">"Kwisha"</string> </resources> diff --git a/core/res/res/values-th/strings.xml b/core/res/res/values-th/strings.xml index 008ceb5..b6b3c88 100644 --- a/core/res/res/values-th/strings.xml +++ b/core/res/res/values-th/strings.xml @@ -1288,7 +1288,6 @@ <string name="default_audio_route_name_dock_speakers" msgid="6240602982276591864">"ลำโพงแท่นชาร์จ"</string> <string name="default_audio_route_name_hdmi" msgid="7986404173839007682">"เสียง HDMI"</string> <string name="default_audio_route_category_name" msgid="3722811174003886946">"ระบบ"</string> - <!-- no translation found for bluetooth_a2dp_audio_route_name (8575624030406771015) --> - <skip /> + <string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"เสียงบลูทูธ"</string> <string name="media_route_chooser_grouping_done" msgid="7966438307723317169">"เสร็จสิ้น"</string> </resources> diff --git a/core/res/res/values-tl/strings.xml b/core/res/res/values-tl/strings.xml index 615d013..85ea80b 100644 --- a/core/res/res/values-tl/strings.xml +++ b/core/res/res/values-tl/strings.xml @@ -1288,7 +1288,6 @@ <string name="default_audio_route_name_dock_speakers" msgid="6240602982276591864">"Mga speaker ng dock"</string> <string name="default_audio_route_name_hdmi" msgid="7986404173839007682">"HDMI audio"</string> <string name="default_audio_route_category_name" msgid="3722811174003886946">"System"</string> - <!-- no translation found for bluetooth_a2dp_audio_route_name (8575624030406771015) --> - <skip /> + <string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Audio sa Bluetooth"</string> <string name="media_route_chooser_grouping_done" msgid="7966438307723317169">"Tapos na"</string> </resources> diff --git a/core/res/res/values-tr/strings.xml b/core/res/res/values-tr/strings.xml index 7bafbe2..697bce6 100644 --- a/core/res/res/values-tr/strings.xml +++ b/core/res/res/values-tr/strings.xml @@ -1288,7 +1288,6 @@ <string name="default_audio_route_name_dock_speakers" msgid="6240602982276591864">"Yuva hoparlörleri"</string> <string name="default_audio_route_name_hdmi" msgid="7986404173839007682">"HDMI ses"</string> <string name="default_audio_route_category_name" msgid="3722811174003886946">"Sistem"</string> - <!-- no translation found for bluetooth_a2dp_audio_route_name (8575624030406771015) --> - <skip /> + <string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Bluetooth ses"</string> <string name="media_route_chooser_grouping_done" msgid="7966438307723317169">"Tamamlandı"</string> </resources> diff --git a/core/res/res/values-vi/strings.xml b/core/res/res/values-vi/strings.xml index a9a8a93..925d06b 100644 --- a/core/res/res/values-vi/strings.xml +++ b/core/res/res/values-vi/strings.xml @@ -1288,7 +1288,6 @@ <string name="default_audio_route_name_dock_speakers" msgid="6240602982276591864">"Loa đế"</string> <string name="default_audio_route_name_hdmi" msgid="7986404173839007682">"Âm thanh HDMI"</string> <string name="default_audio_route_category_name" msgid="3722811174003886946">"Hệ thống"</string> - <!-- no translation found for bluetooth_a2dp_audio_route_name (8575624030406771015) --> - <skip /> + <string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Âm thanh Bluetooth"</string> <string name="media_route_chooser_grouping_done" msgid="7966438307723317169">"Xong"</string> </resources> diff --git a/core/res/res/values-zh-rCN/strings.xml b/core/res/res/values-zh-rCN/strings.xml index aa0fb65..6b915ae 100644 --- a/core/res/res/values-zh-rCN/strings.xml +++ b/core/res/res/values-zh-rCN/strings.xml @@ -1288,7 +1288,6 @@ <string name="default_audio_route_name_dock_speakers" msgid="6240602982276591864">"基座扬声器"</string> <string name="default_audio_route_name_hdmi" msgid="7986404173839007682">"HDMI 音频"</string> <string name="default_audio_route_category_name" msgid="3722811174003886946">"系统"</string> - <!-- no translation found for bluetooth_a2dp_audio_route_name (8575624030406771015) --> - <skip /> + <string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"蓝牙音频"</string> <string name="media_route_chooser_grouping_done" msgid="7966438307723317169">"完成"</string> </resources> diff --git a/core/res/res/values-zh-rTW/strings.xml b/core/res/res/values-zh-rTW/strings.xml index 345a149..546d039 100644 --- a/core/res/res/values-zh-rTW/strings.xml +++ b/core/res/res/values-zh-rTW/strings.xml @@ -1288,7 +1288,6 @@ <string name="default_audio_route_name_dock_speakers" msgid="6240602982276591864">"座架喇叭"</string> <string name="default_audio_route_name_hdmi" msgid="7986404173839007682">"HDMI 音訊"</string> <string name="default_audio_route_category_name" msgid="3722811174003886946">"系統"</string> - <!-- no translation found for bluetooth_a2dp_audio_route_name (8575624030406771015) --> - <skip /> + <string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"藍牙音訊"</string> <string name="media_route_chooser_grouping_done" msgid="7966438307723317169">"完成"</string> </resources> diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml index 3a7253b..9cd04e4 100755 --- a/core/res/res/values/attrs.xml +++ b/core/res/res/values/attrs.xml @@ -842,6 +842,12 @@ <!-- The drawable for accessibility focused views. --> <attr name="accessibilityFocusedDrawable" format="reference" /> + <!-- Drawable for WebView find-on-page dialogue's "next" button. @hide --> + <attr name="findOnPageNextDrawable" format="reference" /> + + <!-- Drawable for WebView find-on-page dialogue's "previous" button. @hide --> + <attr name="findOnPagePreviousDrawable" format="reference" /> + </declare-styleable> <!-- **************************************************************** --> @@ -5697,6 +5703,15 @@ @hide --> <attr name="externalRouteEnabledDrawable" format="reference" /> + <!-- The types of media routes the button and its resulting + chooser will filter by. --> + <attr name="mediaRouteTypes" format="integer"> + <!-- Allow selection of live audio routes. --> + <enum name="liveAudio" value="0x1" /> + <!-- Allow selection of user (app-specified) routes. --> + <enum name="user" value="0x800000" /> + </attr> + <attr name="minWidth" /> <attr name="minHeight" /> </declare-styleable> diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml index 244aec8..303cf78 100644 --- a/core/res/res/values/public.xml +++ b/core/res/res/values/public.xml @@ -1024,6 +1024,8 @@ <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_lockscreen_unlock_phantom" /> + <java-symbol type="drawable" name="ic_media_route_on_holo_dark" /> + <java-symbol type="drawable" name="ic_media_route_disabled_holo_dark" /> <java-symbol type="layout" name="action_bar_home" /> <java-symbol type="layout" name="action_bar_title_item" /> @@ -3642,6 +3644,7 @@ <public type="attr" name="fontFamily" id="0x010103ac" /> <public type="attr" name="mediaRouteButtonStyle" id="0x010103ad" /> + <public type="attr" name="mediaRouteTypes" id="0x010103ae" /> <public type="style" name="Widget.Holo.MediaRouteButton" id="0x010301d5" /> <public type="style" name="Widget.Holo.Light.MediaRouteButton" id="0x010301d6" /> <public type="style" name="Widget.DeviceDefault.MediaRouteButton" id="0x010301d7" /> diff --git a/core/res/res/values/themes.xml b/core/res/res/values/themes.xml index 83d0f63..2f18944 100644 --- a/core/res/res/values/themes.xml +++ b/core/res/res/values/themes.xml @@ -153,6 +153,8 @@ please see themes_device_defaults.xml. ?android:attr/expandableListPreferredItemIndicatorLeft</item> <item name="expandableListPreferredChildIndicatorRight"> ?android:attr/expandableListPreferredItemIndicatorRight</item> + <item name="findOnPageNextDrawable">@android:drawable/ic_find_next_holo_dark</item> + <item name="findOnPagePreviousDrawable">@android:drawable/ic_find_previous_holo_dark</item> <!-- Gallery attributes --> <item name="galleryItemBackground">@android:drawable/gallery_item_background</item> @@ -467,6 +469,8 @@ please see themes_device_defaults.xml. <item name="detailsElementBackground">@android:drawable/panel_bg_holo_light</item> <item name="mediaRouteButtonStyle">@android:style/Widget.DeviceDefault.Light.MediaRouteButton</item> + <item name="findOnPageNextDrawable">@android:drawable/ic_find_next_holo_light</item> + <item name="findOnPagePreviousDrawable">@android:drawable/ic_find_previous_holo_light</item> </style> <!-- Variant of {@link #Theme_Light} with no title bar --> @@ -980,6 +984,8 @@ please see themes_device_defaults.xml. <item name="expandableListPreferredItemIndicatorRight">0dip</item> <item name="expandableListPreferredChildIndicatorLeft">?android:attr/expandableListPreferredItemIndicatorLeft</item> <item name="expandableListPreferredChildIndicatorRight">?android:attr/expandableListPreferredItemIndicatorRight</item> + <item name="findOnPageNextDrawable">@android:drawable/ic_find_next_holo_dark</item> + <item name="findOnPagePreviousDrawable">@android:drawable/ic_find_previous_holo_dark</item> <!-- Gallery attributes --> <item name="galleryItemBackground">@android:drawable/gallery_item_background</item> @@ -1283,6 +1289,8 @@ please see themes_device_defaults.xml. <item name="expandableListPreferredChildIndicatorRight">?android:attr/expandableListPreferredItemIndicatorRight</item> <item name="listDividerAlertDialog">@android:drawable/list_divider_holo_light</item> + <item name="findOnPageNextDrawable">@android:drawable/ic_find_next_holo_light</item> + <item name="findOnPagePreviousDrawable">@android:drawable/ic_find_previous_holo_light</item> <!-- Gallery attributes --> <item name="galleryItemBackground">@android:drawable/gallery_item_background</item> diff --git a/docs/html/design/building-blocks/buttons.jd b/docs/html/design/building-blocks/buttons.jd index 18beab0..1c28cbe 100644 --- a/docs/html/design/building-blocks/buttons.jd +++ b/docs/html/design/building-blocks/buttons.jd @@ -5,9 +5,7 @@ page.title=Buttons user touches it. Android supports two different types of buttons: <em>basic buttons</em> and <em>borderless buttons</em>. Both can contain text labels and/or images.</p> -<div style="text-align: center"> - <img src="{@docRoot}design/media/buttons_basic.png"> -</div> +<img src="{@docRoot}design/media/buttons_basic.png"> <h2 id="basic">Basic Buttons</h2> diff --git a/docs/html/design/building-blocks/pickers.jd b/docs/html/design/building-blocks/pickers.jd index 85f2187..e3cf642 100644 --- a/docs/html/design/building-blocks/pickers.jd +++ b/docs/html/design/building-blocks/pickers.jd @@ -6,13 +6,12 @@ up/down arrow buttons, it's possible to set the desired value from the keyboard gesture.</p> <div class="layout-content-row"> - <div class="layout-content-col span-2"> </div> <div class="layout-content-col span-6"> <img src="{@docRoot}design/media/picker_space.png"> </div> - <div class="layout-content-col span-5"> + <div class="layout-content-col span-6"> <h4>Space considerations</h4> <p>Pickers can be used inline on a form, but their relatively large footprint is best suited for diff --git a/docs/html/design/building-blocks/switches.jd b/docs/html/design/building-blocks/switches.jd index 607e0b6..c4dfc4b 100644 --- a/docs/html/design/building-blocks/switches.jd +++ b/docs/html/design/building-blocks/switches.jd @@ -8,9 +8,7 @@ buttons, and on/off switches.</p> <p>Checkboxes allow the user to select multiple options from a set. Avoid using a single checkbox to turn an option off or on. Instead, use an on/off switch.</p> -<div style="text-align: center"> <img src="{@docRoot}design/media/switches_checkboxes.png"> -</div> <h2 id="radio-buttons">Radio Buttons</h2> @@ -18,14 +16,10 @@ turn an option off or on. Instead, use an on/off switch.</p> selection if you think that the user needs to see all available options side-by-side. Otherwise, consider a spinner, which uses less space.</p> -<div style="text-align: center"> <img src="{@docRoot}design/media/switches_radios.png"> -</div> <h2 id="switches">On/off Switches</h2> <p>On/off switches toggle the state of a single settings option.</p> -<div style="text-align: center"> <img src="{@docRoot}design/media/switches_switches.png"> -</div> diff --git a/docs/html/design/media/action_bar_basics.png b/docs/html/design/media/action_bar_basics.png Binary files differindex 0bf3d56..4b4e987 100644 --- a/docs/html/design/media/action_bar_basics.png +++ b/docs/html/design/media/action_bar_basics.png diff --git a/docs/html/design/media/action_bar_cab.png b/docs/html/design/media/action_bar_cab.png Binary files differindex aa629b9..405b494 100644 --- a/docs/html/design/media/action_bar_cab.png +++ b/docs/html/design/media/action_bar_cab.png diff --git a/docs/html/design/media/action_bar_pattern_considerations.png b/docs/html/design/media/action_bar_pattern_considerations.png Binary files differindex 977e7f2..022288c 100644 --- a/docs/html/design/media/action_bar_pattern_considerations.png +++ b/docs/html/design/media/action_bar_pattern_considerations.png diff --git a/docs/html/design/media/action_bar_pattern_default_tabs.png b/docs/html/design/media/action_bar_pattern_default_tabs.png Binary files differindex 69df289..a6d0d90 100644 --- a/docs/html/design/media/action_bar_pattern_default_tabs.png +++ b/docs/html/design/media/action_bar_pattern_default_tabs.png diff --git a/docs/html/design/media/action_bar_pattern_share_pack.png b/docs/html/design/media/action_bar_pattern_share_pack.png Binary files differindex 7ae8a0a..dde18f3 100644 --- a/docs/html/design/media/action_bar_pattern_share_pack.png +++ b/docs/html/design/media/action_bar_pattern_share_pack.png diff --git a/docs/html/design/media/action_bar_pattern_spinner.png b/docs/html/design/media/action_bar_pattern_spinner.png Binary files differindex 9c054b5..9aff412 100644 --- a/docs/html/design/media/action_bar_pattern_spinner.png +++ b/docs/html/design/media/action_bar_pattern_spinner.png diff --git a/docs/html/design/media/action_bar_pattern_table.png b/docs/html/design/media/action_bar_pattern_table.png Binary files differindex dac7e21..6a8c371 100644 --- a/docs/html/design/media/action_bar_pattern_table.png +++ b/docs/html/design/media/action_bar_pattern_table.png diff --git a/docs/html/design/media/action_bar_pattern_up_app_icon.png b/docs/html/design/media/action_bar_pattern_up_app_icon.png Binary files differindex 11b8aa9..cfc0333 100644 --- a/docs/html/design/media/action_bar_pattern_up_app_icon.png +++ b/docs/html/design/media/action_bar_pattern_up_app_icon.png diff --git a/docs/html/design/media/app_structure_book_detail_page_flip.png b/docs/html/design/media/app_structure_book_detail_page_flip.png Binary files differindex 13c9c52..0cca587 100644 --- a/docs/html/design/media/app_structure_book_detail_page_flip.png +++ b/docs/html/design/media/app_structure_book_detail_page_flip.png diff --git a/docs/html/design/media/app_structure_fixedtabs.png b/docs/html/design/media/app_structure_fixedtabs.png Binary files differindex e41f97e..6d1c63b 100644 --- a/docs/html/design/media/app_structure_fixedtabs.png +++ b/docs/html/design/media/app_structure_fixedtabs.png diff --git a/docs/html/design/media/app_structure_gallery_filmstrip.png b/docs/html/design/media/app_structure_gallery_filmstrip.png Binary files differindex deed672..483bafa 100644 --- a/docs/html/design/media/app_structure_gallery_filmstrip.png +++ b/docs/html/design/media/app_structure_gallery_filmstrip.png diff --git a/docs/html/design/media/app_structure_gmail.png b/docs/html/design/media/app_structure_gmail.png Binary files differindex 862ac75..33ae092 100644 --- a/docs/html/design/media/app_structure_gmail.png +++ b/docs/html/design/media/app_structure_gmail.png diff --git a/docs/html/design/media/app_structure_gmail_swipe.png b/docs/html/design/media/app_structure_gmail_swipe.png Binary files differindex 21da4ac..8f6f71c 100644 --- a/docs/html/design/media/app_structure_gmail_swipe.png +++ b/docs/html/design/media/app_structure_gmail_swipe.png diff --git a/docs/html/design/media/app_structure_market.png b/docs/html/design/media/app_structure_market.png Binary files differindex 5aa595e..7ab0189 100644 --- a/docs/html/design/media/app_structure_market.png +++ b/docs/html/design/media/app_structure_market.png diff --git a/docs/html/design/media/app_structure_music_lndscp.png b/docs/html/design/media/app_structure_music_lndscp.png Binary files differindex 67354de..f6aaf3b 100644 --- a/docs/html/design/media/app_structure_music_lndscp.png +++ b/docs/html/design/media/app_structure_music_lndscp.png diff --git a/docs/html/design/media/app_structure_people_detail.png b/docs/html/design/media/app_structure_people_detail.png Binary files differindex b870796..de54e82 100644 --- a/docs/html/design/media/app_structure_people_detail.png +++ b/docs/html/design/media/app_structure_people_detail.png diff --git a/docs/html/design/media/app_structure_scrolltabs.png b/docs/html/design/media/app_structure_scrolltabs.png Binary files differindex ea742c2..3c20436 100644 --- a/docs/html/design/media/app_structure_scrolltabs.png +++ b/docs/html/design/media/app_structure_scrolltabs.png diff --git a/docs/html/design/media/app_structure_shortcut_on_item.png b/docs/html/design/media/app_structure_shortcut_on_item.png Binary files differindex 1341f1f..3b10cb9 100644 --- a/docs/html/design/media/app_structure_shortcut_on_item.png +++ b/docs/html/design/media/app_structure_shortcut_on_item.png diff --git a/docs/html/design/media/buttons_basic.png b/docs/html/design/media/buttons_basic.png Binary files differindex 7fa3d09..d91ab5c 100644 --- a/docs/html/design/media/buttons_basic.png +++ b/docs/html/design/media/buttons_basic.png diff --git a/docs/html/design/media/color_spectrum.png b/docs/html/design/media/color_spectrum.png Binary files differindex 3fd7a57..7d2c023 100644 --- a/docs/html/design/media/color_spectrum.png +++ b/docs/html/design/media/color_spectrum.png diff --git a/docs/html/design/media/creative_vision_main.png b/docs/html/design/media/creative_vision_main.png Binary files differindex c9d31cb..2b3bb2f 100644 --- a/docs/html/design/media/creative_vision_main.png +++ b/docs/html/design/media/creative_vision_main.png diff --git a/docs/html/design/media/devices_displays_density.png b/docs/html/design/media/devices_displays_density.png Binary files differindex a21b482..7ddad31 100644 --- a/docs/html/design/media/devices_displays_density.png +++ b/docs/html/design/media/devices_displays_density.png diff --git a/docs/html/design/media/devices_displays_main.png b/docs/html/design/media/devices_displays_main.png Binary files differindex fd1c645..1b0b16c 100644 --- a/docs/html/design/media/devices_displays_main.png +++ b/docs/html/design/media/devices_displays_main.png diff --git a/docs/html/design/media/dialogs_popups_example.png b/docs/html/design/media/dialogs_popups_example.png Binary files differindex c2a66f6..2deb00d 100644 --- a/docs/html/design/media/dialogs_popups_example.png +++ b/docs/html/design/media/dialogs_popups_example.png diff --git a/docs/html/design/media/dialogs_w_no_title.png b/docs/html/design/media/dialogs_w_no_title.png Binary files differindex 47e2dbf..a4abebc 100644 --- a/docs/html/design/media/dialogs_w_no_title.png +++ b/docs/html/design/media/dialogs_w_no_title.png diff --git a/docs/html/design/media/dialogs_w_title.png b/docs/html/design/media/dialogs_w_title.png Binary files differindex 4f2b81f..24428fe 100644 --- a/docs/html/design/media/dialogs_w_title.png +++ b/docs/html/design/media/dialogs_w_title.png diff --git a/docs/html/design/media/gesture_doubletouch.png b/docs/html/design/media/gesture_doubletouch.png Binary files differindex 693a593..4c68ae6 100644 --- a/docs/html/design/media/gesture_doubletouch.png +++ b/docs/html/design/media/gesture_doubletouch.png diff --git a/docs/html/design/media/gesture_drag.png b/docs/html/design/media/gesture_drag.png Binary files differindex 6262644..cb0d72c 100644 --- a/docs/html/design/media/gesture_drag.png +++ b/docs/html/design/media/gesture_drag.png diff --git a/docs/html/design/media/gesture_longtouch.png b/docs/html/design/media/gesture_longtouch.png Binary files differindex 3eb3cbc..30d13d4 100644 --- a/docs/html/design/media/gesture_longtouch.png +++ b/docs/html/design/media/gesture_longtouch.png diff --git a/docs/html/design/media/gesture_pinchclose.png b/docs/html/design/media/gesture_pinchclose.png Binary files differindex 471251f..daf2905 100644 --- a/docs/html/design/media/gesture_pinchclose.png +++ b/docs/html/design/media/gesture_pinchclose.png diff --git a/docs/html/design/media/gesture_pinchopen.png b/docs/html/design/media/gesture_pinchopen.png Binary files differindex b7c3ee3..c05b633 100644 --- a/docs/html/design/media/gesture_pinchopen.png +++ b/docs/html/design/media/gesture_pinchopen.png diff --git a/docs/html/design/media/gesture_swipe.png b/docs/html/design/media/gesture_swipe.png Binary files differindex f8e8a26..6f47df6 100644 --- a/docs/html/design/media/gesture_swipe.png +++ b/docs/html/design/media/gesture_swipe.png diff --git a/docs/html/design/media/gesture_touch.png b/docs/html/design/media/gesture_touch.png Binary files differindex 5c49b17..365c352 100644 --- a/docs/html/design/media/gesture_touch.png +++ b/docs/html/design/media/gesture_touch.png diff --git a/docs/html/design/media/lists_main.png b/docs/html/design/media/lists_main.png Binary files differindex d89ac79..3762ba5 100644 --- a/docs/html/design/media/lists_main.png +++ b/docs/html/design/media/lists_main.png diff --git a/docs/html/design/media/metrics_48.png b/docs/html/design/media/metrics_48.png Binary files differindex 5e6c57e..d1fbc82 100644 --- a/docs/html/design/media/metrics_48.png +++ b/docs/html/design/media/metrics_48.png diff --git a/docs/html/design/media/metrics_diagram.png b/docs/html/design/media/metrics_diagram.png Binary files differindex b5e6cd2..3cdc5e6 100644 --- a/docs/html/design/media/metrics_diagram.png +++ b/docs/html/design/media/metrics_diagram.png diff --git a/docs/html/design/media/migrating_intents.png b/docs/html/design/media/migrating_intents.png Binary files differindex 65fc1a5..9ec5da8 100644 --- a/docs/html/design/media/migrating_intents.png +++ b/docs/html/design/media/migrating_intents.png diff --git a/docs/html/design/media/migrating_ios_dialers.png b/docs/html/design/media/migrating_ios_dialers.png Binary files differindex 27751d8..a9230bc 100644 --- a/docs/html/design/media/migrating_ios_dialers.png +++ b/docs/html/design/media/migrating_ios_dialers.png diff --git a/docs/html/design/media/migrating_ios_galleries.png b/docs/html/design/media/migrating_ios_galleries.png Binary files differindex 04472fe..6bc1351 100644 --- a/docs/html/design/media/migrating_ios_galleries.png +++ b/docs/html/design/media/migrating_ios_galleries.png diff --git a/docs/html/design/media/migrating_ios_settings.png b/docs/html/design/media/migrating_ios_settings.png Binary files differindex b17cb72..5b335fe 100644 --- a/docs/html/design/media/migrating_ios_settings.png +++ b/docs/html/design/media/migrating_ios_settings.png diff --git a/docs/html/design/media/multipane_expand.png b/docs/html/design/media/multipane_expand.png Binary files differindex bb4f371..f761e5f 100644 --- a/docs/html/design/media/multipane_expand.png +++ b/docs/html/design/media/multipane_expand.png diff --git a/docs/html/design/media/multipane_show.png b/docs/html/design/media/multipane_show.png Binary files differindex 0231adb..b10c91c 100644 --- a/docs/html/design/media/multipane_show.png +++ b/docs/html/design/media/multipane_show.png diff --git a/docs/html/design/media/multipane_stack.png b/docs/html/design/media/multipane_stack.png Binary files differindex 7769f0c..567099e 100644 --- a/docs/html/design/media/multipane_stack.png +++ b/docs/html/design/media/multipane_stack.png diff --git a/docs/html/design/media/multipane_stretch.png b/docs/html/design/media/multipane_stretch.png Binary files differindex 5075af6..b2dca02 100644 --- a/docs/html/design/media/multipane_stretch.png +++ b/docs/html/design/media/multipane_stretch.png diff --git a/docs/html/design/media/multipane_view_tablet.png b/docs/html/design/media/multipane_view_tablet.png Binary files differindex 56a6718..f116b6f 100644 --- a/docs/html/design/media/multipane_view_tablet.png +++ b/docs/html/design/media/multipane_view_tablet.png diff --git a/docs/html/design/media/multipane_views.png b/docs/html/design/media/multipane_views.png Binary files differindex 9fdfcfd..40b8af6 100644 --- a/docs/html/design/media/multipane_views.png +++ b/docs/html/design/media/multipane_views.png diff --git a/docs/html/design/media/navigation_between_apps_back.png b/docs/html/design/media/navigation_between_apps_back.png Binary files differindex ded5d0a..d5cd979 100755 --- a/docs/html/design/media/navigation_between_apps_back.png +++ b/docs/html/design/media/navigation_between_apps_back.png diff --git a/docs/html/design/media/navigation_between_apps_inward.png b/docs/html/design/media/navigation_between_apps_inward.png Binary files differindex 1f5e401..7394b1c 100755 --- a/docs/html/design/media/navigation_between_apps_inward.png +++ b/docs/html/design/media/navigation_between_apps_inward.png diff --git a/docs/html/design/media/navigation_between_apps_up.png b/docs/html/design/media/navigation_between_apps_up.png Binary files differindex f192c88..99c3112 100755 --- a/docs/html/design/media/navigation_between_apps_up.png +++ b/docs/html/design/media/navigation_between_apps_up.png diff --git a/docs/html/design/media/navigation_between_siblings_gmail.png b/docs/html/design/media/navigation_between_siblings_gmail.png Binary files differindex fe01ed3..64f06c6 100644 --- a/docs/html/design/media/navigation_between_siblings_gmail.png +++ b/docs/html/design/media/navigation_between_siblings_gmail.png diff --git a/docs/html/design/media/navigation_between_siblings_market1.png b/docs/html/design/media/navigation_between_siblings_market1.png Binary files differindex 8f2b3dc..b12a432 100755 --- a/docs/html/design/media/navigation_between_siblings_market1.png +++ b/docs/html/design/media/navigation_between_siblings_market1.png diff --git a/docs/html/design/media/navigation_between_siblings_market2.png b/docs/html/design/media/navigation_between_siblings_market2.png Binary files differindex 33b654c..a09d9d7 100755 --- a/docs/html/design/media/navigation_between_siblings_market2.png +++ b/docs/html/design/media/navigation_between_siblings_market2.png diff --git a/docs/html/design/media/navigation_from_outside_back.png b/docs/html/design/media/navigation_from_outside_back.png Binary files differindex 971ee57..a94e9c3 100644 --- a/docs/html/design/media/navigation_from_outside_back.png +++ b/docs/html/design/media/navigation_from_outside_back.png diff --git a/docs/html/design/media/navigation_indirect_notification.png b/docs/html/design/media/navigation_indirect_notification.png Binary files differindex 6f99267..ca9a1b5 100644 --- a/docs/html/design/media/navigation_indirect_notification.png +++ b/docs/html/design/media/navigation_indirect_notification.png diff --git a/docs/html/design/media/navigation_popup_notification.png b/docs/html/design/media/navigation_popup_notification.png Binary files differindex a0a3ee7..76ed984 100644 --- a/docs/html/design/media/navigation_popup_notification.png +++ b/docs/html/design/media/navigation_popup_notification.png diff --git a/docs/html/design/media/navigation_up_vs_back_gmail.png b/docs/html/design/media/navigation_up_vs_back_gmail.png Binary files differindex ff7adfe..fdeeb90 100644 --- a/docs/html/design/media/navigation_up_vs_back_gmail.png +++ b/docs/html/design/media/navigation_up_vs_back_gmail.png diff --git a/docs/html/design/media/navigation_with_back_and_up.png b/docs/html/design/media/navigation_with_back_and_up.png Binary files differindex 5440220..af2de78 100644 --- a/docs/html/design/media/navigation_with_back_and_up.png +++ b/docs/html/design/media/navigation_with_back_and_up.png diff --git a/docs/html/design/media/notifications_pattern_additional_fail.png b/docs/html/design/media/notifications_pattern_additional_fail.png Binary files differindex 3945ffb..707c98c 100644 --- a/docs/html/design/media/notifications_pattern_additional_fail.png +++ b/docs/html/design/media/notifications_pattern_additional_fail.png diff --git a/docs/html/design/media/notifications_pattern_additional_win.png b/docs/html/design/media/notifications_pattern_additional_win.png Binary files differindex 74472c3..eb193d8 100644 --- a/docs/html/design/media/notifications_pattern_additional_win.png +++ b/docs/html/design/media/notifications_pattern_additional_win.png diff --git a/docs/html/design/media/notifications_pattern_real_time_people.png b/docs/html/design/media/notifications_pattern_real_time_people.png Binary files differindex 32e62eb..2af40b8 100644 --- a/docs/html/design/media/notifications_pattern_real_time_people.png +++ b/docs/html/design/media/notifications_pattern_real_time_people.png diff --git a/docs/html/design/media/picker_datetime.png b/docs/html/design/media/picker_datetime.png Binary files differindex 9876ab2..fb495ee 100644 --- a/docs/html/design/media/picker_datetime.png +++ b/docs/html/design/media/picker_datetime.png diff --git a/docs/html/design/media/picker_space.png b/docs/html/design/media/picker_space.png Binary files differindex 024776f..8b8e3b3 100644 --- a/docs/html/design/media/picker_space.png +++ b/docs/html/design/media/picker_space.png diff --git a/docs/html/design/media/progress_activity.png b/docs/html/design/media/progress_activity.png Binary files differindex 32cf1f5..f4dffab 100644 --- a/docs/html/design/media/progress_activity.png +++ b/docs/html/design/media/progress_activity.png diff --git a/docs/html/design/media/progress_activity2.png b/docs/html/design/media/progress_activity2.png Binary files differindex ec3df99..07205f5 100644 --- a/docs/html/design/media/progress_activity2.png +++ b/docs/html/design/media/progress_activity2.png diff --git a/docs/html/design/media/seekbar_example.png b/docs/html/design/media/seekbar_example.png Binary files differindex 70b7e5e..4c0790a 100644 --- a/docs/html/design/media/seekbar_example.png +++ b/docs/html/design/media/seekbar_example.png diff --git a/docs/html/design/media/selection_cab_big.png b/docs/html/design/media/selection_cab_big.png Binary files differindex 72567cb..ee21fa4 100644 --- a/docs/html/design/media/selection_cab_big.png +++ b/docs/html/design/media/selection_cab_big.png diff --git a/docs/html/design/media/selection_context_menu.png b/docs/html/design/media/selection_context_menu.png Binary files differindex c711546..93b00b0 100644 --- a/docs/html/design/media/selection_context_menu.png +++ b/docs/html/design/media/selection_context_menu.png diff --git a/docs/html/design/media/settings_flowchart.png b/docs/html/design/media/settings_flowchart.png Binary files differindex 7e8623c..d92cfa0 100644 --- a/docs/html/design/media/settings_flowchart.png +++ b/docs/html/design/media/settings_flowchart.png diff --git a/docs/html/design/media/settings_overflow.png b/docs/html/design/media/settings_overflow.png Binary files differindex 9000bec..c13b9fc 100644 --- a/docs/html/design/media/settings_overflow.png +++ b/docs/html/design/media/settings_overflow.png diff --git a/docs/html/design/media/spinners_form.png b/docs/html/design/media/spinners_form.png Binary files differindex 79ee4e4..5556e2b 100644 --- a/docs/html/design/media/spinners_form.png +++ b/docs/html/design/media/spinners_form.png diff --git a/docs/html/design/media/spinners_hololightanddark.png b/docs/html/design/media/spinners_hololightanddark.png Binary files differindex 9b0601e..cea5ec2 100644 --- a/docs/html/design/media/spinners_hololightanddark.png +++ b/docs/html/design/media/spinners_hololightanddark.png diff --git a/docs/html/design/media/swipe_tabs.png b/docs/html/design/media/swipe_tabs.png Binary files differindex f25f061..1f6b5e6 100644 --- a/docs/html/design/media/swipe_tabs.png +++ b/docs/html/design/media/swipe_tabs.png diff --git a/docs/html/design/media/swipe_views.png b/docs/html/design/media/swipe_views.png Binary files differindex 3b6ecaf..ea1e635 100644 --- a/docs/html/design/media/swipe_views.png +++ b/docs/html/design/media/swipe_views.png diff --git a/docs/html/design/media/swipe_views2.png b/docs/html/design/media/swipe_views2.png Binary files differindex 2ed366c..6479a2f 100644 --- a/docs/html/design/media/swipe_views2.png +++ b/docs/html/design/media/swipe_views2.png diff --git a/docs/html/design/media/text_input_holodarkandlight.png b/docs/html/design/media/text_input_holodarkandlight.png Binary files differindex aff61fc..5ef20ee 100644 --- a/docs/html/design/media/text_input_holodarkandlight.png +++ b/docs/html/design/media/text_input_holodarkandlight.png diff --git a/docs/html/design/media/text_input_singlevsmultiline.png b/docs/html/design/media/text_input_singlevsmultiline.png Binary files differindex 7bb9a5c..4890a83 100644 --- a/docs/html/design/media/text_input_singlevsmultiline.png +++ b/docs/html/design/media/text_input_singlevsmultiline.png diff --git a/docs/html/design/media/text_input_textselection.png b/docs/html/design/media/text_input_textselection.png Binary files differindex 85689cf..f2ede0d 100644 --- a/docs/html/design/media/text_input_textselection.png +++ b/docs/html/design/media/text_input_textselection.png diff --git a/docs/html/design/media/text_input_typesandtypedown.png b/docs/html/design/media/text_input_typesandtypedown.png Binary files differindex 32f761c..1feac28 100644 --- a/docs/html/design/media/text_input_typesandtypedown.png +++ b/docs/html/design/media/text_input_typesandtypedown.png diff --git a/docs/html/design/media/themes_holo_dark.png b/docs/html/design/media/themes_holo_dark.png Binary files differindex 916ad27..0a5876a 100644 --- a/docs/html/design/media/themes_holo_dark.png +++ b/docs/html/design/media/themes_holo_dark.png diff --git a/docs/html/design/media/themes_holo_inverse.png b/docs/html/design/media/themes_holo_inverse.png Binary files differindex 72c0244..50be4fb 100644 --- a/docs/html/design/media/themes_holo_inverse.png +++ b/docs/html/design/media/themes_holo_inverse.png diff --git a/docs/html/design/media/themes_holo_light.png b/docs/html/design/media/themes_holo_light.png Binary files differindex d4b0861..edc7f77 100644 --- a/docs/html/design/media/themes_holo_light.png +++ b/docs/html/design/media/themes_holo_light.png diff --git a/docs/html/design/media/touch_feedback_communication.png b/docs/html/design/media/touch_feedback_communication.png Binary files differindex bb27250..6388b77 100644 --- a/docs/html/design/media/touch_feedback_communication.png +++ b/docs/html/design/media/touch_feedback_communication.png diff --git a/docs/html/design/media/touch_feedback_states.png b/docs/html/design/media/touch_feedback_states.png Binary files differindex 972198c..9e306bb 100644 --- a/docs/html/design/media/touch_feedback_states.png +++ b/docs/html/design/media/touch_feedback_states.png diff --git a/docs/html/design/media/typography_sizes.png b/docs/html/design/media/typography_sizes.png Binary files differindex eda1d99..fe6cdce 100644 --- a/docs/html/design/media/typography_sizes.png +++ b/docs/html/design/media/typography_sizes.png diff --git a/docs/html/design/media/ui_overview_all_apps.png b/docs/html/design/media/ui_overview_all_apps.png Binary files differindex 17e7ece..d44e5a4 100644 --- a/docs/html/design/media/ui_overview_all_apps.png +++ b/docs/html/design/media/ui_overview_all_apps.png diff --git a/docs/html/design/media/ui_overview_home_screen.png b/docs/html/design/media/ui_overview_home_screen.png Binary files differindex ee0e4d6..d1376b5 100644 --- a/docs/html/design/media/ui_overview_home_screen.png +++ b/docs/html/design/media/ui_overview_home_screen.png diff --git a/docs/html/design/media/ui_overview_notifications.png b/docs/html/design/media/ui_overview_notifications.png Binary files differindex fd7438a..bc0513f 100644 --- a/docs/html/design/media/ui_overview_notifications.png +++ b/docs/html/design/media/ui_overview_notifications.png diff --git a/docs/html/design/media/ui_overview_recents.png b/docs/html/design/media/ui_overview_recents.png Binary files differindex 4ea0583..aabd7c7 100644 --- a/docs/html/design/media/ui_overview_recents.png +++ b/docs/html/design/media/ui_overview_recents.png diff --git a/docs/html/design/media/ui_overview_system_ui.png b/docs/html/design/media/ui_overview_system_ui.png Binary files differindex ecc4b7d..8993fff 100644 --- a/docs/html/design/media/ui_overview_system_ui.png +++ b/docs/html/design/media/ui_overview_system_ui.png diff --git a/docs/html/design/media/whats_new_action_bar.png b/docs/html/design/media/whats_new_action_bar.png Binary files differindex 713187e..7bb89d1 100644 --- a/docs/html/design/media/whats_new_action_bar.png +++ b/docs/html/design/media/whats_new_action_bar.png diff --git a/docs/html/design/media/whats_new_multipanel.png b/docs/html/design/media/whats_new_multipanel.png Binary files differindex 8e9c2f0..fbe2d56 100644 --- a/docs/html/design/media/whats_new_multipanel.png +++ b/docs/html/design/media/whats_new_multipanel.png diff --git a/docs/html/design/media/whats_new_multiselect.png b/docs/html/design/media/whats_new_multiselect.png Binary files differindex ab34b24..6d97939 100644 --- a/docs/html/design/media/whats_new_multiselect.png +++ b/docs/html/design/media/whats_new_multiselect.png diff --git a/docs/html/design/media/whats_new_nav_bar.png b/docs/html/design/media/whats_new_nav_bar.png Binary files differindex 46239e5..b0c490c 100644 --- a/docs/html/design/media/whats_new_nav_bar.png +++ b/docs/html/design/media/whats_new_nav_bar.png diff --git a/docs/html/design/patterns/actionbar.jd b/docs/html/design/patterns/actionbar.jd index 2226fec..fe77e79 100644 --- a/docs/html/design/patterns/actionbar.jd +++ b/docs/html/design/patterns/actionbar.jd @@ -34,15 +34,13 @@ if you wish. Important: If the app is currently not displaying the top-level screen, be sure to display the Up caret to the left of the app icon, so the user can navigate up the hierarchy. For more discussion of Up navigation, see the <a href="{@docRoot}design/patterns/navigation.html">Navigation</a> pattern. + </p> -<div class="figure"> - <img src="{@docRoot}design/media/action_bar_pattern_up_app_icon.png"> - <div class="figure-caption"> - App icon with and without "up" affordance. - </div> +<img src="{@docRoot}design/media/action_bar_pattern_up_app_icon.png"> +<div class="figure-caption"> + App icon with and without "up" affordance. </div> - </p> </li> </ol> @@ -114,7 +112,7 @@ the top bar.</p> <p>To display actions and, if necessary, the action overflow, use the bottom bar.</p> </div> - <div class="layout-content-col span-3"> + <div class="layout-content-col span-5"> <img src="{@docRoot}design/media/action_bar_pattern_considerations.png"> diff --git a/docs/html/design/patterns/gestures.jd b/docs/html/design/patterns/gestures.jd index 9868df2..e579cee 100644 --- a/docs/html/design/patterns/gestures.jd +++ b/docs/html/design/patterns/gestures.jd @@ -82,7 +82,7 @@ following table shows the core gesture set that is supported in Android.</p> </div> <div class="layout-content-col span-4"> - <img src="{@docRoot}design/media/gesture_pinchopen.png"> + <img src="{@docRoot}design/media/gesture_pinchopen.png" style="margin-left:-4px"> <h4>Pinch open</h4> <p>Zooms into content.</p> diff --git a/docs/html/design/style/color.jd b/docs/html/design/style/color.jd index e25f7c6..9c7b6b6 100644 --- a/docs/html/design/style/color.jd +++ b/docs/html/design/style/color.jd @@ -3,9 +3,8 @@ page.title=Color <style> .color-row { - width: 740px; - margin-left: 10px !important; - margin-right: 10px !important; + width: 760px; + margin:0; display: -webkit-box; display: -moz-box; diff --git a/docs/html/design/style/devices-displays.jd b/docs/html/design/style/devices-displays.jd index e5fe26d..df77c1b 100644 --- a/docs/html/design/style/devices-displays.jd +++ b/docs/html/design/style/devices-displays.jd @@ -32,9 +32,7 @@ ensure that your app looks great on any device.</p> </div> </div> -<div style="text-align:center"> <img src="{@docRoot}design/media/devices_displays_density.png"> -</div> <h4>Strategies</h4> <p>So where do you begin when designing for multiple screens? One approach is to work in the base diff --git a/docs/html/design/style/iconography.jd b/docs/html/design/style/iconography.jd index 775e45d..c4e8bd6 100644 --- a/docs/html/design/style/iconography.jd +++ b/docs/html/design/style/iconography.jd @@ -139,7 +139,7 @@ files for further customization. <ul> <li class="no-bullet with-icon tablet"> - <p>Action bar icons for phones should be <strong>32x32 <acronym title="Density-independent pixels. One dp is one pixel on a 160 dpi screen.">dp</acronym></strong>.</p></li> + <p>Action bar icons for phones and tablets should be <strong>32x32 <acronym title="Density-independent pixels. One dp is one pixel on a 160 dpi screen.">dp</acronym></strong>.</p></li> </ul> </div> diff --git a/media/java/android/media/AudioManager.java b/media/java/android/media/AudioManager.java index e88c535..b6e4659 100644 --- a/media/java/android/media/AudioManager.java +++ b/media/java/android/media/AudioManager.java @@ -98,7 +98,10 @@ public class AudioManager { /** * @hide Broadcast intent when the volume for a particular stream type changes. - * Includes the stream, the new volume and previous volumes + * Includes the stream, the new volume and previous volumes. + * Notes: + * - for internal platform use only, do not make public, + * - never used for "remote" volume changes * * @see #EXTRA_VOLUME_STREAM_TYPE * @see #EXTRA_VOLUME_STREAM_VALUE @@ -1498,6 +1501,24 @@ public class AudioManager { return AudioSystem.isStreamActive(STREAM_MUSIC, 0); } + /** + * @hide + * If the stream is active locally or remotely, adjust its volume according to the enforced + * priority rules. + * Note: only AudioManager.STREAM_MUSIC is supported at the moment + */ + public void adjustLocalOrRemoteStreamVolume(int streamType, int direction) { + if (streamType != STREAM_MUSIC) { + Log.w(TAG, "adjustLocalOrRemoteStreamVolume() doesn't support stream " + streamType); + } + IAudioService service = getService(); + try { + service.adjustLocalOrRemoteStreamVolume(streamType, direction); + } catch (RemoteException e) { + Log.e(TAG, "Dead object in adjustLocalOrRemoteStreamVolume", e); + } + } + /* * Sets a generic audio configuration parameter. The use of these parameters * are platform dependant, see libaudio @@ -2074,10 +2095,12 @@ public class AudioManager { } IAudioService service = getService(); try { - service.registerRemoteControlClient(rcClient.getRcMediaIntent(), /* mediaIntent */ - rcClient.getIRemoteControlClient(), /* rcClient */ + int rcseId = service.registerRemoteControlClient( + rcClient.getRcMediaIntent(), /* mediaIntent */ + rcClient.getIRemoteControlClient(),/* rcClient */ // used to match media button event receiver and audio focus - mContext.getPackageName()); /* packageName */ + mContext.getPackageName()); /* packageName */ + rcClient.setRcseId(rcseId); } catch (RemoteException e) { Log.e(TAG, "Dead object in registerRemoteControlClient"+e); } diff --git a/media/java/android/media/AudioService.java b/media/java/android/media/AudioService.java index 27dc6e3..2e153dd 100644 --- a/media/java/android/media/AudioService.java +++ b/media/java/android/media/AudioService.java @@ -101,6 +101,8 @@ public class AudioService extends IAudioService.Stub implements OnFinished { /** Debug remote control client/display feature */ protected static final boolean DEBUG_RC = false; + /** Debug volumes */ + protected static final boolean DEBUG_VOL = false; /** How long to delay before persisting a change in volume/ringer mode. */ private static final int PERSIST_DELAY = 500; @@ -120,7 +122,7 @@ public class AudioService extends IAudioService.Stub implements OnFinished { /** If the msg is already queued, queue this one and leave the old. */ private static final int SENDMSG_QUEUE = 2; - // AudioHandler message.whats + // AudioHandler messages private static final int MSG_SET_DEVICE_VOLUME = 0; private static final int MSG_PERSIST_VOLUME = 1; private static final int MSG_PERSIST_MASTER_VOLUME = 2; @@ -138,11 +140,15 @@ public class AudioService extends IAudioService.Stub implements OnFinished { private static final int MSG_SET_ALL_VOLUMES = 14; private static final int MSG_PERSIST_MASTER_VOLUME_MUTE = 15; private static final int MSG_REPORT_NEW_ROUTES = 16; - // messages handled under wakelock, can only be queued, i.e. sent with queueMsgUnderWakeLock(), + private static final int MSG_REEVALUATE_REMOTE = 17; + private static final int MSG_RCC_NEW_PLAYBACK_INFO = 18; + private static final int MSG_RCC_NEW_VOLUME_OBS = 19; + // start of messages handled under wakelock + // these messages can only be queued, i.e. sent with queueMsgUnderWakeLock(), // and not with sendMsg(..., ..., SENDMSG_QUEUE, ...) - private static final int MSG_SET_WIRED_DEVICE_CONNECTION_STATE = 17; - private static final int MSG_SET_A2DP_CONNECTION_STATE = 18; - + private static final int MSG_SET_WIRED_DEVICE_CONNECTION_STATE = 20; + private static final int MSG_SET_A2DP_CONNECTION_STATE = 21; + // end of messages handled under wakelock // flags for MSG_PERSIST_VOLUME indicating if current and/or last audible volume should be // persisted @@ -405,6 +411,11 @@ public class AudioService extends IAudioService.Stub implements OnFinished { final RemoteCallbackList<IAudioRoutesObserver> mRoutesObservers = new RemoteCallbackList<IAudioRoutesObserver>(); + /** + * A fake stream type to match the notion of remote media playback + */ + public final static int STREAM_REMOTE_MUSIC = -200; + /////////////////////////////////////////////////////////////////////////// // Construction /////////////////////////////////////////////////////////////////////////// @@ -488,6 +499,11 @@ public class AudioService extends IAudioService.Stub implements OnFinished { mMasterVolumeRamp = context.getResources().getIntArray( com.android.internal.R.array.config_masterVolumeRamp); + mMainRemote = new RemotePlaybackState(-1, MAX_STREAM_VOLUME[AudioManager.STREAM_MUSIC], + MAX_STREAM_VOLUME[AudioManager.STREAM_MUSIC]); + mHasRemotePlayback = false; + mMainRemoteIsActive = false; + postReevaluateRemote(); } private void createAudioSystemThread() { @@ -657,9 +673,20 @@ public class AudioService extends IAudioService.Stub implements OnFinished { adjustSuggestedStreamVolume(direction, AudioManager.USE_DEFAULT_STREAM_TYPE, flags); } + /** @see AudioManager#adjustLocalOrRemoteStreamVolume(int, int) with current assumption + * on streamType: fixed to STREAM_MUSIC */ + public void adjustLocalOrRemoteStreamVolume(int streamType, int direction) { + if (DEBUG_VOL) Log.d(TAG, "adjustLocalOrRemoteStreamVolume(dir="+direction+")"); + if (checkUpdateRemoteStateIfActive(AudioSystem.STREAM_MUSIC)) { + adjustRemoteVolume(AudioSystem.STREAM_MUSIC, direction, 0); + } else if (AudioSystem.isStreamActive(AudioSystem.STREAM_MUSIC, 0)) { + adjustStreamVolume(AudioSystem.STREAM_MUSIC, direction, 0); + } + } + /** @see AudioManager#adjustVolume(int, int, int) */ public void adjustSuggestedStreamVolume(int direction, int suggestedStreamType, int flags) { - + if (DEBUG_VOL) Log.d(TAG, "adjustSuggestedStreamVolume() stream="+suggestedStreamType); int streamType; if (mVolumeControlStream != -1) { streamType = mVolumeControlStream; @@ -668,17 +695,27 @@ public class AudioService extends IAudioService.Stub implements OnFinished { } // Play sounds on STREAM_RING only and if lock screen is not on. - if ((flags & AudioManager.FLAG_PLAY_SOUND) != 0 && + if ((streamType != STREAM_REMOTE_MUSIC) && + (flags & AudioManager.FLAG_PLAY_SOUND) != 0 && ((mStreamVolumeAlias[streamType] != AudioSystem.STREAM_RING) || (mKeyguardManager != null && mKeyguardManager.isKeyguardLocked()))) { flags &= ~AudioManager.FLAG_PLAY_SOUND; } - adjustStreamVolume(streamType, direction, flags); + if (streamType == STREAM_REMOTE_MUSIC) { + // don't play sounds for remote + flags &= ~AudioManager.FLAG_PLAY_SOUND; + //if (DEBUG_VOL) Log.i(TAG, "Need to adjust remote volume: calling adjustRemoteVolume()"); + adjustRemoteVolume(AudioSystem.STREAM_MUSIC, direction, flags); + } else { + adjustStreamVolume(streamType, direction, flags); + } } /** @see AudioManager#adjustStreamVolume(int, int, int) */ public void adjustStreamVolume(int streamType, int direction, int flags) { + if (DEBUG_VOL) Log.d(TAG, "adjustStreamVolume() stream="+streamType+", dir="+direction); + ensureValidDirection(direction); ensureValidStreamType(streamType); @@ -1370,6 +1407,10 @@ public class AudioService extends IAudioService.Stub implements OnFinished { } } int streamType = getActiveStreamType(AudioManager.USE_DEFAULT_STREAM_TYPE); + if (streamType == STREAM_REMOTE_MUSIC) { + // here handle remote media playback the same way as local playback + streamType = AudioManager.STREAM_MUSIC; + } int device = getDeviceForStream(streamType); int index = mStreamStates[mStreamVolumeAlias[streamType]].getIndex(device, false); setStreamVolumeInt(mStreamVolumeAlias[streamType], index, device, true, false); @@ -2169,40 +2210,61 @@ public class AudioService extends IAudioService.Stub implements OnFinished { // Log.v(TAG, "getActiveStreamType: Forcing STREAM_VOICE_CALL..."); return AudioSystem.STREAM_VOICE_CALL; } + } else if (suggestedStreamType == AudioManager.USE_DEFAULT_STREAM_TYPE) { + // Having the suggested stream be USE_DEFAULT_STREAM_TYPE is how remote control + // volume can have priority over STREAM_MUSIC + if (checkUpdateRemoteStateIfActive(AudioSystem.STREAM_MUSIC)) { + if (DEBUG_VOL) + Log.v(TAG, "getActiveStreamType: Forcing STREAM_REMOTE_MUSIC"); + return STREAM_REMOTE_MUSIC; + } else if (AudioSystem.isStreamActive(AudioSystem.STREAM_MUSIC, 0)) { + if (DEBUG_VOL) + Log.v(TAG, "getActiveStreamType: Forcing STREAM_MUSIC stream active"); + return AudioSystem.STREAM_MUSIC; + } else { + if (DEBUG_VOL) + Log.v(TAG, "getActiveStreamType: Forcing STREAM_RING b/c default"); + return AudioSystem.STREAM_RING; + } } else if (AudioSystem.isStreamActive(AudioSystem.STREAM_MUSIC, 0)) { - // Log.v(TAG, "getActiveStreamType: Forcing STREAM_MUSIC..."); + if (DEBUG_VOL) + Log.v(TAG, "getActiveStreamType: Forcing STREAM_MUSIC stream active"); return AudioSystem.STREAM_MUSIC; - } else if (suggestedStreamType == AudioManager.USE_DEFAULT_STREAM_TYPE) { - // Log.v(TAG, "getActiveStreamType: Forcing STREAM_RING..." - // + " b/c USE_DEFAULT_STREAM_TYPE..."); - return AudioSystem.STREAM_RING; } else { - // Log.v(TAG, "getActiveStreamType: Returning suggested type " + suggestedStreamType); + if (DEBUG_VOL) Log.v(TAG, "getActiveStreamType: Returning suggested type " + + suggestedStreamType); return suggestedStreamType; } } else { if (isInCommunication()) { if (AudioSystem.getForceUse(AudioSystem.FOR_COMMUNICATION) == AudioSystem.FORCE_BT_SCO) { - // Log.v(TAG, "getActiveStreamType: Forcing STREAM_BLUETOOTH_SCO..."); + if (DEBUG_VOL) Log.v(TAG, "getActiveStreamType: Forcing STREAM_BLUETOOTH_SCO"); return AudioSystem.STREAM_BLUETOOTH_SCO; } else { - // Log.v(TAG, "getActiveStreamType: Forcing STREAM_VOICE_CALL..."); + if (DEBUG_VOL) Log.v(TAG, "getActiveStreamType: Forcing STREAM_VOICE_CALL"); return AudioSystem.STREAM_VOICE_CALL; } } else if (AudioSystem.isStreamActive(AudioSystem.STREAM_NOTIFICATION, - NOTIFICATION_VOLUME_DELAY_MS) || - AudioSystem.isStreamActive(AudioSystem.STREAM_RING, + NOTIFICATION_VOLUME_DELAY_MS) || + AudioSystem.isStreamActive(AudioSystem.STREAM_RING, NOTIFICATION_VOLUME_DELAY_MS)) { - // Log.v(TAG, "getActiveStreamType: Forcing STREAM_NOTIFICATION..."); + if (DEBUG_VOL) Log.v(TAG, "getActiveStreamType: Forcing STREAM_NOTIFICATION"); return AudioSystem.STREAM_NOTIFICATION; - } else if (AudioSystem.isStreamActive(AudioSystem.STREAM_MUSIC, 0) || - (suggestedStreamType == AudioManager.USE_DEFAULT_STREAM_TYPE)) { - // Log.v(TAG, "getActiveStreamType: Forcing STREAM_MUSIC " - // + " b/c USE_DEFAULT_STREAM_TYPE..."); - return AudioSystem.STREAM_MUSIC; + } else if (suggestedStreamType == AudioManager.USE_DEFAULT_STREAM_TYPE) { + if (checkUpdateRemoteStateIfActive(AudioSystem.STREAM_MUSIC)) { + // Having the suggested stream be USE_DEFAULT_STREAM_TYPE is how remote control + // volume can have priority over STREAM_MUSIC + if (DEBUG_VOL) Log.v(TAG, "getActiveStreamType: Forcing STREAM_REMOTE_MUSIC"); + return STREAM_REMOTE_MUSIC; + } else { + if (DEBUG_VOL) + Log.v(TAG, "getActiveStreamType: using STREAM_MUSIC as default"); + return AudioSystem.STREAM_MUSIC; + } } else { - // Log.v(TAG, "getActiveStreamType: Returning suggested type " + suggestedStreamType); + if (DEBUG_VOL) Log.v(TAG, "getActiveStreamType: Returning suggested type " + + suggestedStreamType); return suggestedStreamType; } } @@ -3036,6 +3098,19 @@ public class AudioService extends IAudioService.Stub implements OnFinished { mRoutesObservers.finishBroadcast(); break; } + + case MSG_REEVALUATE_REMOTE: + onReevaluateRemote(); + break; + + case MSG_RCC_NEW_PLAYBACK_INFO: + onNewPlaybackInfoForRcc(msg.arg1 /* rccId */, msg.arg2 /* key */, + ((Integer)msg.obj).intValue() /* value */); + break; + case MSG_RCC_NEW_VOLUME_OBS: + onRegisterVolumeObserverForRcc(msg.arg1 /* rccId */, + (IRemoteVolumeObserver)msg.obj /* rvo */); + break; } } } @@ -4103,6 +4178,8 @@ public class AudioService extends IAudioService.Stub implements OnFinished { // remote control client died, make sure the displays don't use it anymore // by setting its remote control client to null registerRemoteControlClient(mMediaIntent, null/*rcClient*/, null/*ignored*/); + // the dead client was maybe handling remote playback, reevaluate + postReevaluateRemote(); } public IBinder getBinder() { @@ -4110,7 +4187,46 @@ public class AudioService extends IAudioService.Stub implements OnFinished { } } + /** + * A global counter for RemoteControlClient identifiers + */ + private static int sLastRccId = 0; + + private class RemotePlaybackState { + int mRccId; + int mVolume; + int mVolumeMax; + int mVolumeHandling; + + private RemotePlaybackState(int id, int vol, int volMax) { + mRccId = id; + mVolume = vol; + mVolumeMax = volMax; + mVolumeHandling = RemoteControlClient.DEFAULT_PLAYBACK_VOLUME_HANDLING; + } + } + + /** + * Internal cache for the playback information of the RemoteControlClient whose volume gets to + * be controlled by the volume keys ("main"), so we don't have to iterate over the RC stack + * every time we need this info. + */ + private RemotePlaybackState mMainRemote; + /** + * Indicates whether the "main" RemoteControlClient is considered active. + * Use synchronized on mMainRemote. + */ + private boolean mMainRemoteIsActive; + /** + * Indicates whether there is remote playback going on. True even if there is no "active" + * remote playback (mMainRemoteIsActive is false), but a RemoteControlClient has declared it + * handles remote playback. + * Use synchronized on mMainRemote. + */ + private boolean mHasRemotePlayback; + private static class RemoteControlStackEntry { + public int mRccId = RemoteControlClient.RCSE_ID_UNREGISTERED; /** * The target for the ACTION_MEDIA_BUTTON events. * Always non null. @@ -4129,6 +4245,26 @@ public class AudioService extends IAudioService.Stub implements OnFinished { * but no remote control client has been registered) */ public IRemoteControlClient mRcClient; public RcClientDeathHandler mRcClientDeathHandler; + /** + * Information only used for non-local playback + */ + public int mPlaybackType; + public int mPlaybackVolume; + public int mPlaybackVolumeMax; + public int mPlaybackVolumeHandling; + public int mPlaybackStream; + public int mPlaybackState; + public IRemoteVolumeObserver mRemoteVolumeObs; + + public void resetPlaybackInfo() { + mPlaybackType = RemoteControlClient.PLAYBACK_TYPE_LOCAL; + mPlaybackVolume = RemoteControlClient.DEFAULT_PLAYBACK_VOLUME; + mPlaybackVolumeMax = RemoteControlClient.DEFAULT_PLAYBACK_VOLUME; + mPlaybackVolumeHandling = RemoteControlClient.DEFAULT_PLAYBACK_VOLUME_HANDLING; + mPlaybackStream = AudioManager.STREAM_MUSIC; + mPlaybackState = RemoteControlClient.PLAYSTATE_STOPPED; + mRemoteVolumeObs = null; + } /** precondition: mediaIntent != null, eventReceiver != null */ public RemoteControlStackEntry(PendingIntent mediaIntent, ComponentName eventReceiver) { @@ -4136,6 +4272,9 @@ public class AudioService extends IAudioService.Stub implements OnFinished { mReceiverComponent = eventReceiver; mCallingUid = -1; mRcClient = null; + mRccId = ++sLastRccId; + + resetPlaybackInfo(); } public void unlinkToRcClientDeath() { @@ -4185,13 +4324,50 @@ public class AudioService extends IAudioService.Stub implements OnFinished { pw.println(" pi: " + rcse.mMediaIntent + " -- ercvr: " + rcse.mReceiverComponent + " -- client: " + rcse.mRcClient + - " -- uid: " + rcse.mCallingUid); + " -- uid: " + rcse.mCallingUid + + " -- type: " + rcse.mPlaybackType + + " state: " + rcse.mPlaybackState); } } } /** * Helper function: + * Display in the log the current entries in the remote control stack, focusing + * on RemoteControlClient data + */ + private void dumpRCCStack(PrintWriter pw) { + pw.println("\nRemote Control Client stack entries:"); + synchronized(mRCStack) { + Iterator<RemoteControlStackEntry> stackIterator = mRCStack.iterator(); + while(stackIterator.hasNext()) { + RemoteControlStackEntry rcse = stackIterator.next(); + pw.println(" uid: " + rcse.mCallingUid + + " -- id: " + rcse.mRccId + + " -- type: " + rcse.mPlaybackType + + " -- state: " + rcse.mPlaybackState + + " -- vol handling: " + rcse.mPlaybackVolumeHandling + + " -- vol: " + rcse.mPlaybackVolume + + " -- volMax: " + rcse.mPlaybackVolumeMax + + " -- volObs: " + rcse.mRemoteVolumeObs); + + } + } + synchronized (mMainRemote) { + pw.println("\nRemote Volume State:"); + pw.println(" has remote: " + mHasRemotePlayback); + pw.println(" is remote active: " + mMainRemoteIsActive); + pw.println(" rccId: " + mMainRemote.mRccId); + pw.println(" volume handling: " + + ((mMainRemote.mVolumeHandling == RemoteControlClient.PLAYBACK_VOLUME_FIXED) ? + "PLAYBACK_VOLUME_FIXED(0)" : "PLAYBACK_VOLUME_VARIABLE(1)")); + pw.println(" volume: " + mMainRemote.mVolume); + pw.println(" volume steps: " + mMainRemote.mVolumeMax); + } + } + + /** + * Helper function: * Remove any entry in the remote control stack that has the same package name as packageName * Pre-condition: packageName != null */ @@ -4556,13 +4732,15 @@ public class AudioService extends IAudioService.Stub implements OnFinished { /** * see AudioManager.registerRemoteControlClient(ComponentName eventReceiver, ...) + * @return the unique ID of the RemoteControlStackEntry associated with the RemoteControlClient * Note: using this method with rcClient == null is a way to "disable" the IRemoteControlClient * without modifying the RC stack, but while still causing the display to refresh (will * become blank as a result of this) */ - public void registerRemoteControlClient(PendingIntent mediaIntent, + public int registerRemoteControlClient(PendingIntent mediaIntent, IRemoteControlClient rcClient, String callingPackageName) { if (DEBUG_RC) Log.i(TAG, "Register remote control client rcClient="+rcClient); + int rccId = RemoteControlClient.RCSE_ID_UNREGISTERED; synchronized(mAudioFocusLock) { synchronized(mRCStack) { // store the new display information @@ -4581,8 +4759,10 @@ public class AudioService extends IAudioService.Stub implements OnFinished { rcse.mCallingUid = Binder.getCallingUid(); if (rcClient == null) { // here rcse.mRcClientDeathHandler is null; + rcse.resetPlaybackInfo(); break; } + rccId = rcse.mRccId; // there is a new (non-null) client: // 1/ give the new client the current display (if any) @@ -4616,6 +4796,7 @@ public class AudioService extends IAudioService.Stub implements OnFinished { } } } + return rccId; } /** @@ -4790,6 +4971,275 @@ public class AudioService extends IAudioService.Stub implements OnFinished { } } + public void setPlaybackInfoForRcc(int rccId, int what, int value) { + sendMsg(mAudioHandler, MSG_RCC_NEW_PLAYBACK_INFO, SENDMSG_QUEUE, + rccId /* arg1 */, what /* arg2 */, Integer.valueOf(value) /* obj */, 0 /* delay */); + } + + // handler for MSG_RCC_NEW_PLAYBACK_INFO + private void onNewPlaybackInfoForRcc(int rccId, int key, int value) { + if(DEBUG_RC) Log.d(TAG, "onNewPlaybackInfoForRcc(id=" + rccId + + ", what=" + key + ",val=" + value + ")"); + synchronized(mRCStack) { + Iterator<RemoteControlStackEntry> stackIterator = mRCStack.iterator(); + while(stackIterator.hasNext()) { + RemoteControlStackEntry rcse = stackIterator.next(); + if (rcse.mRccId == rccId) { + switch (key) { + case RemoteControlClient.PLAYBACKINFO_PLAYBACK_TYPE: + rcse.mPlaybackType = value; + postReevaluateRemote(); + break; + case RemoteControlClient.PLAYBACKINFO_VOLUME: + rcse.mPlaybackVolume = value; + synchronized (mMainRemote) { + if (rccId == mMainRemote.mRccId) { + mMainRemote.mVolume = value; + mVolumePanel.postHasNewRemotePlaybackInfo(); + } + } + break; + case RemoteControlClient.PLAYBACKINFO_VOLUME_MAX: + rcse.mPlaybackVolumeMax = value; + synchronized (mMainRemote) { + if (rccId == mMainRemote.mRccId) { + mMainRemote.mVolumeMax = value; + mVolumePanel.postHasNewRemotePlaybackInfo(); + } + } + break; + case RemoteControlClient.PLAYBACKINFO_VOLUME_HANDLING: + rcse.mPlaybackVolumeHandling = value; + synchronized (mMainRemote) { + if (rccId == mMainRemote.mRccId) { + mMainRemote.mVolumeHandling = value; + mVolumePanel.postHasNewRemotePlaybackInfo(); + } + } + break; + case RemoteControlClient.PLAYBACKINFO_USES_STREAM: + rcse.mPlaybackStream = value; + break; + case RemoteControlClient.PLAYBACKINFO_PLAYSTATE: + rcse.mPlaybackState = value; + synchronized (mMainRemote) { + if (rccId == mMainRemote.mRccId) { + mMainRemoteIsActive = isPlaystateActive(value); + postReevaluateRemote(); + } + } + break; + default: + Log.e(TAG, "unhandled key " + key + " for RCC " + rccId); + break; + } + return; + } + } + } + } + + public void registerRemoteVolumeObserverForRcc(int rccId, IRemoteVolumeObserver rvo) { + sendMsg(mAudioHandler, MSG_RCC_NEW_VOLUME_OBS, SENDMSG_QUEUE, + rccId /* arg1 */, 0, rvo /* obj */, 0 /* delay */); + } + + // handler for MSG_RCC_NEW_VOLUME_OBS + private void onRegisterVolumeObserverForRcc(int rccId, IRemoteVolumeObserver rvo) { + synchronized(mRCStack) { + Iterator<RemoteControlStackEntry> stackIterator = mRCStack.iterator(); + while(stackIterator.hasNext()) { + RemoteControlStackEntry rcse = stackIterator.next(); + if (rcse.mRccId == rccId) { + rcse.mRemoteVolumeObs = rvo; + break; + } + } + } + } + + /** + * Checks if a remote client is active on the supplied stream type. Update the remote stream + * volume state if found and playing + * @param streamType + * @return false if no remote playing is currently playing + */ + private boolean checkUpdateRemoteStateIfActive(int streamType) { + synchronized(mRCStack) { + Iterator<RemoteControlStackEntry> stackIterator = mRCStack.iterator(); + while(stackIterator.hasNext()) { + RemoteControlStackEntry rcse = stackIterator.next(); + if ((rcse.mPlaybackType == RemoteControlClient.PLAYBACK_TYPE_REMOTE) + && isPlaystateActive(rcse.mPlaybackState) + && (rcse.mPlaybackStream == streamType)) { + if (DEBUG_RC) Log.d(TAG, "remote playback active on stream " + streamType + + ", vol =" + rcse.mPlaybackVolume); + synchronized (mMainRemote) { + mMainRemote.mRccId = rcse.mRccId; + mMainRemote.mVolume = rcse.mPlaybackVolume; + mMainRemote.mVolumeMax = rcse.mPlaybackVolumeMax; + mMainRemote.mVolumeHandling = rcse.mPlaybackVolumeHandling; + mMainRemoteIsActive = true; + } + return true; + } + } + } + synchronized (mMainRemote) { + mMainRemoteIsActive = false; + } + return false; + } + + /** + * Returns true if the given playback state is considered "active", i.e. it describes a state + * where playback is happening, or about to + * @param playState the playback state to evaluate + * @return true if active, false otherwise (inactive or unknown) + */ + private static boolean isPlaystateActive(int playState) { + switch (playState) { + case RemoteControlClient.PLAYSTATE_PLAYING: + case RemoteControlClient.PLAYSTATE_BUFFERING: + case RemoteControlClient.PLAYSTATE_FAST_FORWARDING: + case RemoteControlClient.PLAYSTATE_REWINDING: + case RemoteControlClient.PLAYSTATE_SKIPPING_BACKWARDS: + case RemoteControlClient.PLAYSTATE_SKIPPING_FORWARDS: + return true; + default: + return false; + } + } + + private void adjustRemoteVolume(int streamType, int direction, int flags) { + int rccId = RemoteControlClient.RCSE_ID_UNREGISTERED; + boolean volFixed = false; + synchronized (mMainRemote) { + if (!mMainRemoteIsActive) { + if (DEBUG_VOL) Log.w(TAG, "adjustRemoteVolume didn't find an active client"); + return; + } + rccId = mMainRemote.mRccId; + volFixed = (mMainRemote.mVolumeHandling == + RemoteControlClient.PLAYBACK_VOLUME_FIXED); + } + // unlike "local" stream volumes, we can't compute the new volume based on the direction, + // we can only notify the remote that volume needs to be updated, and we'll get an async' + // update through setPlaybackInfoForRcc() + if (!volFixed) { + sendVolumeUpdateToRemote(rccId, direction); + } + + // fire up the UI + mVolumePanel.postRemoteVolumeChanged(streamType, flags); + } + + private void sendVolumeUpdateToRemote(int rccId, int direction) { + if (DEBUG_VOL) { Log.d(TAG, "sendVolumeUpdateToRemote(rccId="+rccId+" , dir="+direction); } + if (direction == 0) { + // only handling discrete events + return; + } + IRemoteVolumeObserver rvo = null; + synchronized (mRCStack) { + Iterator<RemoteControlStackEntry> stackIterator = mRCStack.iterator(); + while(stackIterator.hasNext()) { + RemoteControlStackEntry rcse = stackIterator.next(); + //FIXME OPTIMIZE store this info in mMainRemote so we don't have to iterate? + if (rcse.mRccId == rccId) { + rvo = rcse.mRemoteVolumeObs; + break; + } + } + } + if (rvo != null) { + try { + rvo.dispatchRemoteVolumeUpdate(direction, -1); + } catch (RemoteException e) { + Log.e(TAG, "Error dispatching relative volume update", e); + } + } + } + + public int getRemoteStreamMaxVolume() { + synchronized (mMainRemote) { + if (mMainRemote.mRccId == RemoteControlClient.RCSE_ID_UNREGISTERED) { + return 0; + } + return mMainRemote.mVolumeMax; + } + } + + public int getRemoteStreamVolume() { + synchronized (mMainRemote) { + if (mMainRemote.mRccId == RemoteControlClient.RCSE_ID_UNREGISTERED) { + return 0; + } + return mMainRemote.mVolume; + } + } + + public void setRemoteStreamVolume(int vol) { + if (DEBUG_VOL) { Log.d(TAG, "setRemoteStreamVolume(vol="+vol+")"); } + int rccId = RemoteControlClient.RCSE_ID_UNREGISTERED; + synchronized (mMainRemote) { + if (mMainRemote.mRccId == RemoteControlClient.RCSE_ID_UNREGISTERED) { + return; + } + rccId = mMainRemote.mRccId; + } + IRemoteVolumeObserver rvo = null; + synchronized (mRCStack) { + Iterator<RemoteControlStackEntry> stackIterator = mRCStack.iterator(); + while(stackIterator.hasNext()) { + RemoteControlStackEntry rcse = stackIterator.next(); + if (rcse.mRccId == rccId) { + //FIXME OPTIMIZE store this info in mMainRemote so we don't have to iterate? + rvo = rcse.mRemoteVolumeObs; + break; + } + } + } + if (rvo != null) { + try { + rvo.dispatchRemoteVolumeUpdate(0, vol); + } catch (RemoteException e) { + Log.e(TAG, "Error dispatching absolute volume update", e); + } + } + } + + /** + * Call to make AudioService reevaluate whether it's in a mode where remote players should + * have their volume controlled. In this implementation this is only to reset whether + * VolumePanel should display remote volumes + */ + private void postReevaluateRemote() { + sendMsg(mAudioHandler, MSG_REEVALUATE_REMOTE, SENDMSG_QUEUE, 0, 0, null, 0); + } + + private void onReevaluateRemote() { + if (DEBUG_VOL) { Log.w(TAG, "onReevaluateRemote()"); } + // is there a registered RemoteControlClient that is handling remote playback + boolean hasRemotePlayback = false; + synchronized (mRCStack) { + Iterator<RemoteControlStackEntry> stackIterator = mRCStack.iterator(); + while(stackIterator.hasNext()) { + RemoteControlStackEntry rcse = stackIterator.next(); + if (rcse.mPlaybackType == RemoteControlClient.PLAYBACK_TYPE_REMOTE) { + hasRemotePlayback = true; + break; + } + } + } + synchronized (mMainRemote) { + if (mHasRemotePlayback != hasRemotePlayback) { + mHasRemotePlayback = hasRemotePlayback; + mVolumePanel.postRemoteSliderVisibility(hasRemotePlayback); + } + } + } + //========================================================================================== // Device orientation //========================================================================================== @@ -4871,9 +5321,9 @@ public class AudioService extends IAudioService.Stub implements OnFinished { protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) { mContext.enforceCallingOrSelfPermission(android.Manifest.permission.DUMP, TAG); - // TODO probably a lot more to do here than just the audio focus and remote control stacks dumpFocusStack(pw); dumpRCStack(pw); + dumpRCCStack(pw); dumpStreamStates(pw); pw.println("\nAudio routes:"); pw.print(" mMainType=0x"); pw.println(Integer.toHexString(mCurAudioRoutes.mMainType)); diff --git a/media/java/android/media/IAudioService.aidl b/media/java/android/media/IAudioService.aidl index fc5b8f1..854eb3f 100644 --- a/media/java/android/media/IAudioService.aidl +++ b/media/java/android/media/IAudioService.aidl @@ -24,6 +24,7 @@ import android.media.IAudioFocusDispatcher; import android.media.IAudioRoutesObserver; import android.media.IRemoteControlClient; import android.media.IRemoteControlDisplay; +import android.media.IRemoteVolumeObserver; import android.media.IRingtonePlayer; import android.net.Uri; import android.view.KeyEvent; @@ -35,6 +36,8 @@ interface IAudioService { void adjustVolume(int direction, int flags); + oneway void adjustLocalOrRemoteStreamVolume(int streamType, int direction); + void adjustSuggestedStreamVolume(int direction, int suggestedStreamType, int flags); void adjustStreamVolume(int streamType, int direction, int flags); @@ -43,6 +46,8 @@ interface IAudioService { void setStreamVolume(int streamType, int index, int flags); + oneway void setRemoteStreamVolume(int index); + void setMasterVolume(int index, int flags); void setStreamSolo(int streamType, boolean state, IBinder cb); @@ -119,7 +124,7 @@ interface IAudioService { oneway void registerMediaButtonEventReceiverForCalls(in ComponentName c); oneway void unregisterMediaButtonEventReceiverForCalls(); - oneway void registerRemoteControlClient(in PendingIntent mediaIntent, + int registerRemoteControlClient(in PendingIntent mediaIntent, in IRemoteControlClient rcClient, in String callingPackageName); oneway void unregisterRemoteControlClient(in PendingIntent mediaIntent, in IRemoteControlClient rcClient); @@ -128,6 +133,11 @@ interface IAudioService { oneway void unregisterRemoteControlDisplay(in IRemoteControlDisplay rcd); oneway void remoteControlDisplayUsesBitmapSize(in IRemoteControlDisplay rcd, int w, int h); + oneway void setPlaybackInfoForRcc(int rccId, int what, int value); + int getRemoteStreamMaxVolume(); + int getRemoteStreamVolume(); + oneway void registerRemoteVolumeObserverForRcc(int rccId, in IRemoteVolumeObserver rvo); + void startBluetoothSco(IBinder cb); void stopBluetoothSco(IBinder cb); diff --git a/media/java/android/media/IRemoteVolumeObserver.aidl b/media/java/android/media/IRemoteVolumeObserver.aidl new file mode 100644 index 0000000..7ff0c06 --- /dev/null +++ b/media/java/android/media/IRemoteVolumeObserver.aidl @@ -0,0 +1,26 @@ +/* + * 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 android.media; + + +/** + * AIDL for the AudioService to report requests for remote volume update requests. + * @hide + */ +oneway interface IRemoteVolumeObserver { + void dispatchRemoteVolumeUpdate(int direction, int value); +} diff --git a/media/java/android/media/MediaRouter.java b/media/java/android/media/MediaRouter.java index a9e6e3d..b6187da 100644 --- a/media/java/android/media/MediaRouter.java +++ b/media/java/android/media/MediaRouter.java @@ -589,9 +589,42 @@ public class MediaRouter { RouteGroup mGroup; final RouteCategory mCategory; Drawable mIcon; + // playback information + int mPlaybackType = PLAYBACK_TYPE_LOCAL; + int mVolumeMax = RemoteControlClient.DEFAULT_PLAYBACK_VOLUME; + int mVolume = RemoteControlClient.DEFAULT_PLAYBACK_VOLUME; + int mVolumeHandling = RemoteControlClient.DEFAULT_PLAYBACK_VOLUME_HANDLING; + int mPlaybackStream = AudioManager.STREAM_MUSIC; + VolumeCallbackInfo mVcb; 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) + */ + 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) + */ + public final static int PLAYBACK_TYPE_REMOTE = 1; + /** + * Playback information indicating the playback volume is fixed, i.e. it cannot be + * 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) + */ + public final static int PLAYBACK_VOLUME_FIXED = 0; + /** + * Playback information indicating the playback volume is variable and can be controlled + * from this object. + */ + public final static int PLAYBACK_VOLUME_VARIABLE = 1; + RouteInfo(RouteCategory category) { mCategory = category; } @@ -685,6 +718,66 @@ public class MediaRouter { return mTag; } + /** + * @return the type of playback associated with this route + * @see UserRouteInfo#setPlaybackType(int) + */ + public int getPlaybackType() { + return mPlaybackType; + } + + /** + * @return the stream over which the playback associated with this route is performed + * @see UserRouteInfo#setPlaybackStream(int) + */ + public int getPlaybackStream() { + return mPlaybackStream; + } + + /** + * @return the volume at which the playback associated with this route is performed + * @see UserRouteInfo#setVolume(int) + */ + public int getVolume() { + if (mPlaybackType == PLAYBACK_TYPE_LOCAL) { + int vol = 0; + try { + vol = sStatic.mAudioService.getStreamVolume(mPlaybackStream); + } catch (RemoteException e) { + Log.e(TAG, "Error getting local stream volume", e); + } + return vol; + } else { + return mVolume; + } + } + + /** + * @return the maximum volume at which the playback associated with this route is performed + * @see UserRouteInfo#setVolumeMax(int) + */ + public int getVolumeMax() { + if (mPlaybackType == PLAYBACK_TYPE_LOCAL) { + int volMax = 0; + try { + volMax = sStatic.mAudioService.getStreamMaxVolume(mPlaybackStream); + } catch (RemoteException e) { + Log.e(TAG, "Error getting local stream volume", e); + } + return volMax; + } else { + return mVolumeMax; + } + } + + /** + * @return how volume is handling on the route + * @see UserRouteInfo#setVolumeHandling(int) + */ + public int getVolumeHandling() { + return mVolumeHandling; + } + void setStatusInt(CharSequence status) { if (!status.equals(mStatus)) { mStatus = status; @@ -695,6 +788,24 @@ public class MediaRouter { } } + final IRemoteVolumeObserver.Stub mRemoteVolObserver = new IRemoteVolumeObserver.Stub() { + public void dispatchRemoteVolumeUpdate(final int direction, final int value) { + sStatic.mHandler.post(new Runnable() { + @Override + public void run() { + //Log.d(TAG, "dispatchRemoteVolumeUpdate dir=" + direction + " val=" + value); + if (mVcb != null) { + if (direction != 0) { + mVcb.vcb.onVolumeUpdateRequest(mVcb.route, direction); + } else { + mVcb.vcb.onVolumeSetRequest(mVcb.route, value); + } + } + } + }); + } + }; + void routeUpdated() { updateRoute(this); } @@ -757,10 +868,14 @@ public class MediaRouter { * RemoteControlClient will be used to reflect and update information * such as route volume info in related UIs.</p> * + * <p>The RemoteControlClient must have been previously registered with + * {@link AudioManager#registerRemoteControlClient(RemoteControlClient)}.</p> + * * @param rcc RemoteControlClient associated with this route */ public void setRemoteControlClient(RemoteControlClient rcc) { mRcc = rcc; + updatePlaybackInfoOnRcc(); } /** @@ -792,6 +907,105 @@ public class MediaRouter { public void setIconResource(int resId) { setIconDrawable(sStatic.mResources.getDrawable(resId)); } + + /** + * Set a callback to be notified of volume update requests + * @param vcb + */ + public void setVolumeCallback(VolumeCallback vcb) { + mVcb = new VolumeCallbackInfo(vcb, this); + } + + /** + * Defines whether playback associated with this route is "local" + * ({@link RouteInfo#PLAYBACK_TYPE_LOCAL}) or "remote" + * ({@link RouteInfo#PLAYBACK_TYPE_REMOTE}). + * @param type + */ + public void setPlaybackType(int type) { + if (mPlaybackType != type) { + mPlaybackType = type; + setPlaybackInfoOnRcc(RemoteControlClient.PLAYBACKINFO_PLAYBACK_TYPE, type); + } + } + + /** + * Defines whether volume for the playback associated with this route is fixed + * ({@link RouteInfo#PLAYBACK_VOLUME_FIXED}) or can modified + * ({@link RouteInfo#PLAYBACK_VOLUME_VARIABLE}). + * @param volumeHandling + */ + public void setVolumeHandling(int volumeHandling) { + if (mVolumeHandling != volumeHandling) { + mVolumeHandling = volumeHandling; + setPlaybackInfoOnRcc( + RemoteControlClient.PLAYBACKINFO_VOLUME_HANDLING, volumeHandling); + } + } + + /** + * Defines at what volume the playback associated with this route is performed (for user + * feedback purposes). This information is only used when the playback is not local. + * @param volume + */ + public void setVolume(int volume) { + if (mVolume != volume) { + mVolume = volume; + setPlaybackInfoOnRcc(RemoteControlClient.PLAYBACKINFO_VOLUME, volume); + } + } + + /** + * Defines the maximum volume at which the playback associated with this route is performed + * (for user feedback purposes). This information is only used when the playback is not + * local. + * @param volumeMax + */ + public void setVolumeMax(int volumeMax) { + if (mVolumeMax != volumeMax) { + mVolumeMax = volumeMax; + setPlaybackInfoOnRcc(RemoteControlClient.PLAYBACKINFO_VOLUME_MAX, volumeMax); + } + } + + /** + * Defines over what stream type the media is presented. + * @param stream + */ + public void setPlaybackStream(int stream) { + if (mPlaybackStream != stream) { + mPlaybackStream = stream; + setPlaybackInfoOnRcc(RemoteControlClient.PLAYBACKINFO_USES_STREAM, stream); + } + } + + private void updatePlaybackInfoOnRcc() { + if ((mRcc != null) && (mRcc.getRcseId() != RemoteControlClient.RCSE_ID_UNREGISTERED)) { + mRcc.setPlaybackInformation( + RemoteControlClient.PLAYBACKINFO_VOLUME_MAX, mVolumeMax); + mRcc.setPlaybackInformation( + RemoteControlClient.PLAYBACKINFO_VOLUME, mVolume); + mRcc.setPlaybackInformation( + RemoteControlClient.PLAYBACKINFO_VOLUME_HANDLING, mVolumeHandling); + mRcc.setPlaybackInformation( + RemoteControlClient.PLAYBACKINFO_USES_STREAM, mPlaybackStream); + mRcc.setPlaybackInformation( + RemoteControlClient.PLAYBACKINFO_PLAYBACK_TYPE, mPlaybackType); + // let AudioService know whom to call when remote volume needs to be updated + try { + sStatic.mAudioService.registerRemoteVolumeObserverForRcc( + mRcc.getRcseId() /* rccId */, mRemoteVolObserver /* rvo */); + } catch (RemoteException e) { + Log.e(TAG, "Error registering remote volume observer", e); + } + } + } + + private void setPlaybackInfoOnRcc(int what, int value) { + if (mRcc != null) { + mRcc.setPlaybackInformation(what, value); + } + } } /** @@ -1206,4 +1420,43 @@ public class MediaRouter { } } + + static class VolumeCallbackInfo { + public final VolumeCallback vcb; + public final RouteInfo route; + + public VolumeCallbackInfo(VolumeCallback vcb, RouteInfo route) { + this.vcb = vcb; + this.route = route; + } + } + + /** + * Interface for receiving events about volume changes. + * All methods of this interface will be called from the application's main thread. + * + * <p>A VolumeCallback will only receive events relevant to routes that the callback + * was registered for.</p> + * + * @see UserRouteInfo#setVolumeCallback(VolumeCallback) + */ + public static abstract class VolumeCallback { + /** + * Called when the volume for the route should be increased or decreased. + * @param info the route affected by this event + * @param direction an integer indicating whether the volume is to be increased + * (positive value) or decreased (negative value). + * For bundled changes, the absolute value indicates the number of changes + * in the same direction, e.g. +3 corresponds to three "volume up" changes. + */ + public abstract void onVolumeUpdateRequest(RouteInfo info, int direction); + /** + * Called when the volume for the route should be set to the given value + * @param info the route affected by this event + * @param volume an integer indicating the new volume value that should be used, always + * between 0 and the value set by {@link UserRouteInfo#setVolumeMax(int)}. + */ + public abstract void onVolumeSetRequest(RouteInfo info, int volume); + } + } diff --git a/media/java/android/media/RemoteControlClient.java b/media/java/android/media/RemoteControlClient.java index f1c4d34..4c71ace 100644 --- a/media/java/android/media/RemoteControlClient.java +++ b/media/java/android/media/RemoteControlClient.java @@ -18,6 +18,7 @@ package android.media; import android.app.PendingIntent; import android.content.ComponentName; +import android.content.Context; import android.content.Intent; import android.graphics.Bitmap; import android.graphics.Canvas; @@ -26,9 +27,11 @@ import android.graphics.RectF; import android.media.MediaMetadataRetriever; import android.os.Bundle; import android.os.Handler; +import android.os.IBinder; import android.os.Looper; import android.os.Message; import android.os.RemoteException; +import android.os.ServiceManager; import android.os.SystemClock; import android.util.Log; @@ -131,6 +134,88 @@ public class RemoteControlClient public final static int PLAYSTATE_NONE = 0; /** + * @hide + * 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. + */ + public final static int PLAYBACK_TYPE_LOCAL = 0; + /** + * @hide + * 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. + */ + public final static int PLAYBACK_TYPE_REMOTE = 1; + private final static int PLAYBACK_TYPE_MIN = PLAYBACK_TYPE_LOCAL; + private final static int PLAYBACK_TYPE_MAX = PLAYBACK_TYPE_REMOTE; + /** + * @hide + * Playback information indicating the playback volume is fixed, i.e. it cannot be controlled + * from this object. An example of fixed playback volume is a remote player, playing over HDMI + * where the user prefer to control the volume on the HDMI sink, rather than attenuate at the + * source. + * @see #PLAYBACKINFO_VOLUME_HANDLING. + */ + public final static int PLAYBACK_VOLUME_FIXED = 0; + /** + * @hide + * Playback information indicating the playback volume is variable and can be controlled from + * this object. + * @see #PLAYBACKINFO_VOLUME_HANDLING. + */ + public final static int PLAYBACK_VOLUME_VARIABLE = 1; + /** + * @hide (to be un-hidden) + * The playback information value indicating the value of a given information type is invalid. + * @see #PLAYBACKINFO_VOLUME_HANDLING. + */ + public final static int PLAYBACKINFO_INVALID_VALUE = Integer.MIN_VALUE; + + //========================================== + // Public keys for playback information + /** + * @hide + * Playback information that defines the type of playback associated with this + * RemoteControlClient. See {@link #PLAYBACK_TYPE_LOCAL} and {@link #PLAYBACK_TYPE_REMOTE}. + */ + public final static int PLAYBACKINFO_PLAYBACK_TYPE = 1; + /** + * @hide + * Playback information that defines at what volume the playback associated with this + * RemoteControlClient is performed. This information is only used when the playback type is not + * local (see {@link #PLAYBACKINFO_PLAYBACK_TYPE}). + */ + public final static int PLAYBACKINFO_VOLUME = 2; + /** + * @hide + * Playback information that defines the maximum volume volume value that is supported + * by the playback associated with this RemoteControlClient. This information is only used + * when the playback type is not local (see {@link #PLAYBACKINFO_PLAYBACK_TYPE}). + */ + public final static int PLAYBACKINFO_VOLUME_MAX = 3; + /** + * @hide + * Playback information that defines how volume is handled for the presentation of the media. + * @see #PLAYBACK_VOLUME_FIXED + * @see #PLAYBACK_VOLUME_VARIABLE + */ + public final static int PLAYBACKINFO_VOLUME_HANDLING = 4; + /** + * @hide + * Playback information that defines over what stream type the media is presented. + */ + public final static int PLAYBACKINFO_USES_STREAM = 5; + + //========================================== + // Private keys for playback information + /** + * @hide + * Used internally to relay playback state (set by the application with + * {@link #setPlaybackState(int)}) to AudioService + */ + public final static int PLAYBACKINFO_PLAYSTATE = 255; + + + /** * Flag indicating a RemoteControlClient makes use of the "previous" media key. * * @see #setTransportControlFlags(int) @@ -516,6 +601,8 @@ public class RemoteControlClient // send to remote control display if conditions are met sendPlaybackState_syncCacheLock(); + // update AudioService + sendAudioServiceNewPlaybackInfo_syncCacheLock(PLAYBACKINFO_PLAYSTATE, state); } } } @@ -542,6 +629,122 @@ public class RemoteControlClient } } + /** @hide */ + public final static int DEFAULT_PLAYBACK_VOLUME_HANDLING = PLAYBACK_VOLUME_VARIABLE; + /** @hide */ + // hard-coded to the same number of steps as AudioService.MAX_STREAM_VOLUME[STREAM_MUSIC] + public final static int DEFAULT_PLAYBACK_VOLUME = 15; + + private int mPlaybackType = PLAYBACK_TYPE_LOCAL; + private int mPlaybackVolumeMax = DEFAULT_PLAYBACK_VOLUME; + private int mPlaybackVolume = DEFAULT_PLAYBACK_VOLUME; + private int mPlaybackVolumeHandling = DEFAULT_PLAYBACK_VOLUME_HANDLING; + private int mPlaybackStream = AudioManager.STREAM_MUSIC; + + /** + * @hide + * Set information describing information related to the playback of media so the system + * can implement additional behavior to handle non-local playback usecases. + * @param what a key to specify the type of information to set. Valid keys are + * {@link #PLAYBACKINFO_PLAYBACK_TYPE}, + * {@link #PLAYBACKINFO_USES_STREAM}, + * {@link #PLAYBACKINFO_VOLUME}, + * {@link #PLAYBACKINFO_VOLUME_MAX}, + * and {@link #PLAYBACKINFO_VOLUME_HANDLING}. + * @param value the value for the supplied information to set. + */ + public void setPlaybackInformation(int what, int value) { + synchronized(mCacheLock) { + switch (what) { + case PLAYBACKINFO_PLAYBACK_TYPE: + if ((value >= PLAYBACK_TYPE_MIN) && (value <= PLAYBACK_TYPE_MAX)) { + if (mPlaybackType != value) { + mPlaybackType = value; + sendAudioServiceNewPlaybackInfo_syncCacheLock(what, value); + } + } else { + Log.w(TAG, "using invalid value for PLAYBACKINFO_PLAYBACK_TYPE"); + } + break; + case PLAYBACKINFO_VOLUME: + if ((value > -1) && (value <= mPlaybackVolumeMax)) { + if (mPlaybackVolume != value) { + mPlaybackVolume = value; + sendAudioServiceNewPlaybackInfo_syncCacheLock(what, value); + } + } else { + Log.w(TAG, "using invalid value for PLAYBACKINFO_VOLUME"); + } + break; + case PLAYBACKINFO_VOLUME_MAX: + if (value > 0) { + if (mPlaybackVolumeMax != value) { + mPlaybackVolumeMax = value; + sendAudioServiceNewPlaybackInfo_syncCacheLock(what, value); + } + } else { + Log.w(TAG, "using invalid value for PLAYBACKINFO_VOLUME_MAX"); + } + break; + case PLAYBACKINFO_USES_STREAM: + if ((value >= 0) && (value < AudioSystem.getNumStreamTypes())) { + mPlaybackStream = value; + } else { + Log.w(TAG, "using invalid value for PLAYBACKINFO_USES_STREAM"); + } + break; + case PLAYBACKINFO_VOLUME_HANDLING: + if ((value >= PLAYBACK_VOLUME_FIXED) && (value <= PLAYBACK_VOLUME_VARIABLE)) { + if (mPlaybackVolumeHandling != value) { + mPlaybackVolumeHandling = value; + sendAudioServiceNewPlaybackInfo_syncCacheLock(what, value); + } + } else { + Log.w(TAG, "using invalid value for PLAYBACKINFO_VOLUME_HANDLING"); + } + break; + default: + // not throwing an exception or returning an error if more keys are to be + // supported in the future + Log.w(TAG, "setPlaybackInformation() ignoring unknown key " + what); + break; + } + } + } + + /** + * @hide + * Return playback information represented as an integer value. + * @param what a key to specify the type of information to retrieve. Valid keys are + * {@link #PLAYBACKINFO_PLAYBACK_TYPE}, + * {@link #PLAYBACKINFO_USES_STREAM}, + * {@link #PLAYBACKINFO_VOLUME}, + * {@link #PLAYBACKINFO_VOLUME_MAX}, + * and {@link #PLAYBACKINFO_VOLUME_HANDLING}. + * @return the current value for the given information type, or + * {@link #PLAYBACKINFO_INVALID_VALUE} if an error occurred or the request is invalid, or + * the value is unknown. + */ + public int getIntPlaybackInformation(int what) { + synchronized(mCacheLock) { + switch (what) { + case PLAYBACKINFO_PLAYBACK_TYPE: + return mPlaybackType; + case PLAYBACKINFO_VOLUME: + return mPlaybackVolume; + case PLAYBACKINFO_VOLUME_MAX: + return mPlaybackVolumeMax; + case PLAYBACKINFO_USES_STREAM: + return mPlaybackStream; + case PLAYBACKINFO_VOLUME_HANDLING: + return mPlaybackVolumeHandling; + default: + Log.e(TAG, "getIntPlaybackInformation() unknown key " + what); + return PLAYBACKINFO_INVALID_VALUE; + } + } + } + /** * Lock for all cached data */ @@ -675,6 +878,34 @@ public class RemoteControlClient } }; + /** + * @hide + * Default value for the unique identifier + */ + public final static int RCSE_ID_UNREGISTERED = -1; + /** + * Unique identifier of the RemoteControlStackEntry in AudioService with which + * this RemoteControlClient is associated. + */ + private int mRcseId = RCSE_ID_UNREGISTERED; + /** + * @hide + * To be only used by AudioManager after it has received the unique id from + * IAudioService.registerRemoteControlClient() + * @param id the unique identifier of the RemoteControlStackEntry in AudioService with which + * this RemoteControlClient is associated. + */ + public void setRcseId(int id) { + mRcseId = id; + } + + /** + * @hide + */ + public int getRcseId() { + return mRcseId; + } + private EventHandler mEventHandler; private final static int MSG_REQUEST_PLAYBACK_STATE = 1; private final static int MSG_REQUEST_METADATA = 2; @@ -731,6 +962,9 @@ public class RemoteControlClient } } + //=========================================================== + // Communication with IRemoteControlDisplay + private void detachFromDisplay_syncCacheLock() { mRcDisplay = null; mArtworkExpectedWidth = ARTWORK_INVALID_SIZE; @@ -802,6 +1036,37 @@ public class RemoteControlClient } } + //=========================================================== + // Communication with AudioService + + private static IAudioService sService; + + private static IAudioService getService() + { + if (sService != null) { + return sService; + } + IBinder b = ServiceManager.getService(Context.AUDIO_SERVICE); + sService = IAudioService.Stub.asInterface(b); + return sService; + } + + private void sendAudioServiceNewPlaybackInfo_syncCacheLock(int what, int value) { + if (mRcseId == RCSE_ID_UNREGISTERED) { + return; + } + //Log.d(TAG, "sending to AudioService key=" + what + ", value=" + value); + IAudioService service = getService(); + try { + service.setPlaybackInfoForRcc(mRcseId, what, value); + } catch (RemoteException e) { + Log.e(TAG, "Dead object in sendAudioServiceNewPlaybackInfo_syncCacheLock", e); + } + } + + //=========================================================== + // Message handlers + private void onNewInternalClientGen(Integer clientGeneration, int artWidth, int artHeight) { synchronized (mCacheLock) { // this remote control client is told it is the "focused" one: @@ -836,6 +1101,9 @@ public class RemoteControlClient } } + //=========================================================== + // Internal utilities + /** * Scale a bitmap to fit the smallest dimension by uniformly scaling the incoming bitmap. * If the bitmap fits, then do nothing and return the original. diff --git a/packages/SystemUI/res/drawable/navbar_search_outerring.xml b/packages/SystemUI/res/drawable/navbar_search_outerring.xml index 8a8785f..689dbf0 100644 --- a/packages/SystemUI/res/drawable/navbar_search_outerring.xml +++ b/packages/SystemUI/res/drawable/navbar_search_outerring.xml @@ -19,5 +19,5 @@ <size android:height="@dimen/navbar_search_outerring_diameter" android:width="@dimen/navbar_search_outerring_diameter" /> <solid android:color="#00000000" /> - <stroke android:color="#00000000" android:width="2dp" /> + <stroke android:color="#40ffffff" android:width="2dp" /> </shape> diff --git a/packages/SystemUI/res/layout-land/status_bar_search_panel.xml b/packages/SystemUI/res/layout-land/status_bar_search_panel.xml index f91e5d6..c8a120d 100644 --- a/packages/SystemUI/res/layout-land/status_bar_search_panel.xml +++ b/packages/SystemUI/res/layout-land/status_bar_search_panel.xml @@ -54,7 +54,7 @@ prvandroid:outerRadius="@dimen/navbar_search_outerring_radius" prvandroid:innerRadius="@*android:dimen/glowpadview_inner_radius" prvandroid:snapMargin="@dimen/navbar_search_snap_margin" - prvandroid:feedbackCount="1" + prvandroid:feedbackCount="0" prvandroid:vibrationDuration="@integer/config_vibration_duration" prvandroid:alwaysTrackFinger="true" prvandroid:glowRadius="@*android:dimen/glowpadview_glow_radius" diff --git a/packages/SystemUI/res/layout-port/status_bar_search_panel.xml b/packages/SystemUI/res/layout-port/status_bar_search_panel.xml index 2556aca..1e4bb57 100644 --- a/packages/SystemUI/res/layout-port/status_bar_search_panel.xml +++ b/packages/SystemUI/res/layout-port/status_bar_search_panel.xml @@ -54,7 +54,7 @@ prvandroid:outerRadius="@dimen/navbar_search_outerring_radius" prvandroid:innerRadius="@*android:dimen/glowpadview_inner_radius" prvandroid:snapMargin="@dimen/navbar_search_snap_margin" - prvandroid:feedbackCount="1" + prvandroid:feedbackCount="0" prvandroid:vibrationDuration="@integer/config_vibration_duration" prvandroid:alwaysTrackFinger="true" prvandroid:glowRadius="@*android:dimen/glowpadview_glow_radius" diff --git a/packages/SystemUI/res/layout-sw600dp/status_bar_search_panel.xml b/packages/SystemUI/res/layout-sw600dp/status_bar_search_panel.xml index 459fac9..3b6c52e 100644 --- a/packages/SystemUI/res/layout-sw600dp/status_bar_search_panel.xml +++ b/packages/SystemUI/res/layout-sw600dp/status_bar_search_panel.xml @@ -40,7 +40,7 @@ prvandroid:outerRadius="@dimen/navbar_search_outerring_radius" prvandroid:innerRadius="@*android:dimen/glowpadview_inner_radius" prvandroid:snapMargin="@dimen/navbar_search_snap_margin" - prvandroid:feedbackCount="1" + prvandroid:feedbackCount="0" prvandroid:vibrationDuration="@integer/config_vibration_duration" prvandroid:alwaysTrackFinger="true" prvandroid:glowRadius="@*android:dimen/glowpadview_glow_radius" diff --git a/packages/SystemUI/res/layout-sw720dp/status_bar_search_panel.xml b/packages/SystemUI/res/layout-sw720dp/status_bar_search_panel.xml index d2e26db..8c2360e 100644 --- a/packages/SystemUI/res/layout-sw720dp/status_bar_search_panel.xml +++ b/packages/SystemUI/res/layout-sw720dp/status_bar_search_panel.xml @@ -41,7 +41,7 @@ prvandroid:outerRadius="@dimen/navbar_search_outerring_radius" prvandroid:innerRadius="@*android:dimen/glowpadview_inner_radius" prvandroid:snapMargin="@dimen/navbar_search_snap_margin" - prvandroid:feedbackCount="1" + prvandroid:feedbackCount="0" prvandroid:vibrationDuration="@integer/config_vibration_duration" prvandroid:alwaysTrackFinger="true" prvandroid:glowRadius="@*android:dimen/glowpadview_glow_radius" diff --git a/packages/SystemUI/src/com/android/systemui/SearchPanelView.java b/packages/SystemUI/src/com/android/systemui/SearchPanelView.java index acab41e..475fb6d 100644 --- a/packages/SystemUI/src/com/android/systemui/SearchPanelView.java +++ b/packages/SystemUI/src/com/android/systemui/SearchPanelView.java @@ -53,7 +53,6 @@ public class SearchPanelView extends FrameLayout implements private static final String ASSIST_ICON_METADATA_NAME = "com.android.systemui.action_assist_icon"; private final Context mContext; - private final SearchManager mSearchManager; private BaseStatusBar mBar; private StatusBarTouchProxy mStatusBarTouchProxy; @@ -68,25 +67,13 @@ public class SearchPanelView extends FrameLayout implements public SearchPanelView(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); mContext = context; - mSearchManager = (SearchManager) mContext.getSystemService(Context.SEARCH_SERVICE); - if (mSearchManager == null) { - Slog.w(TAG, "Search manager not available"); - } - } - - public boolean isAssistantAvailable() { - return mSearchManager != null && mSearchManager.isAssistantAvailable(); - } - - private Intent getAssistIntent() { - return mSearchManager != null ? mSearchManager.getAssistIntent() : null; } private void startAssistActivity() { // Close Recent Apps if needed mBar.animateCollapse(CommandQueue.FLAG_EXCLUDE_SEARCH_PANEL); // Launch Assist - Intent intent = getAssistIntent(); + Intent intent = SearchManager.getAssistIntent(mContext); if (intent == null) return; try { ActivityOptions opts = ActivityOptions.makeCustomAnimation(mContext, @@ -150,19 +137,17 @@ public class SearchPanelView extends FrameLayout implements // TODO: fetch views mGlowPadView = (GlowPadView) findViewById(R.id.glow_pad_view); mGlowPadView.setOnTriggerListener(mGlowPadViewListener); - if (mSearchManager != null) { - ComponentName component = mSearchManager.getGlobalSearchActivity(); - if (component != null) { - if (!mGlowPadView.replaceTargetDrawablesIfPresent(component, - ASSIST_ICON_METADATA_NAME, - com.android.internal.R.drawable.ic_action_assist_generic)) { - Slog.w(TAG, "Couldn't grab icon from component " + component); - } - } else { - Slog.w(TAG, "No search icon specified in component " + component); + } + + private void maybeSwapSearchIcon() { + Intent intent = SearchManager.getAssistIntent(mContext); + if (intent != null) { + ComponentName component = intent.getComponent(); + if (component == null || !mGlowPadView.replaceTargetDrawablesIfPresent(component, + ASSIST_ICON_METADATA_NAME, + com.android.internal.R.drawable.ic_action_assist_generic)) { + if (DEBUG) Slog.v(TAG, "Couldn't grab icon for component " + component); } - } else { - Slog.w(TAG, "No SearchManager"); } } @@ -210,6 +195,7 @@ public class SearchPanelView extends FrameLayout implements } mShowing = show; if (show) { + maybeSwapSearchIcon(); if (getVisibility() != View.VISIBLE) { setVisibility(View.VISIBLE); // Don't start the animation until we've created the layer, which is done @@ -289,4 +275,8 @@ public class SearchPanelView extends FrameLayout implements transitioner.setAnimator(LayoutTransition.DISAPPEARING, null); return transitioner; } + + public boolean isAssistantAvailable() { + return SearchManager.getAssistIntent(mContext) != null; + } } diff --git a/policy/src/com/android/internal/policy/impl/KeyguardViewBase.java b/policy/src/com/android/internal/policy/impl/KeyguardViewBase.java index 5aa764b..29a5573 100644 --- a/policy/src/com/android/internal/policy/impl/KeyguardViewBase.java +++ b/policy/src/com/android/internal/policy/impl/KeyguardViewBase.java @@ -213,16 +213,13 @@ public abstract class KeyguardViewBase extends FrameLayout { Context.AUDIO_SERVICE); } } - // Volume buttons should only function for music. - if (mAudioManager.isMusicActive()) { - // TODO: Actually handle MUTE. - mAudioManager.adjustStreamVolume( - AudioManager.STREAM_MUSIC, - keyCode == KeyEvent.KEYCODE_VOLUME_UP - ? AudioManager.ADJUST_RAISE - : AudioManager.ADJUST_LOWER, - 0); - } + // Volume buttons should only function for music (local or remote). + // TODO: Actually handle MUTE. + mAudioManager.adjustLocalOrRemoteStreamVolume( + AudioManager.STREAM_MUSIC, + keyCode == KeyEvent.KEYCODE_VOLUME_UP + ? AudioManager.ADJUST_RAISE + : AudioManager.ADJUST_LOWER); // Don't execute default volume behavior return true; } else { diff --git a/policy/src/com/android/internal/policy/impl/LockScreen.java b/policy/src/com/android/internal/policy/impl/LockScreen.java index 33dda09..ec954fe 100644 --- a/policy/src/com/android/internal/policy/impl/LockScreen.java +++ b/policy/src/com/android/internal/policy/impl/LockScreen.java @@ -83,7 +83,6 @@ class LockScreen extends LinearLayout implements KeyguardScreen { private View mUnlockWidget; private boolean mCameraDisabled; private boolean mSearchDisabled; - private SearchManager mSearchManager; // Is there a vibrator private final boolean mHasVibrator; @@ -253,23 +252,6 @@ class LockScreen extends LinearLayout implements KeyguardScreen { } } - private boolean isAssistantAvailable() { - SearchManager searchManager = getSearchManager(); - return searchManager != null && searchManager.isAssistantAvailable(); - } - - private Intent getAssistIntent() { - SearchManager searchManager = getSearchManager(); - return searchManager != null ? searchManager.getAssistIntent() : null; - } - - private SearchManager getSearchManager() { - if (mSearchManager == null) { - mSearchManager = (SearchManager) mContext.getSystemService(Context.SEARCH_SERVICE); - } - return mSearchManager; - } - class GlowPadViewMethods implements GlowPadView.OnTriggerListener, UnlockWidgetCommonMethods { private final GlowPadView mGlowPadView; @@ -297,27 +279,21 @@ class LockScreen extends LinearLayout implements KeyguardScreen { // Update the search icon with drawable from the search .apk if (!mSearchDisabled) { - SearchManager searchManager = getSearchManager(); - if (searchManager != null) { - ComponentName component = searchManager.getGlobalSearchActivity(); - if (component != null) { - // XXX Hack. We need to substitute the icon here but haven't formalized - // the public API. The "_google" metadata will be going away, so - // DON'T USE IT! - boolean replaced = mGlowPadView.replaceTargetDrawablesIfPresent(component, - ASSIST_ICON_METADATA_NAME + "_google", - com.android.internal.R.drawable.ic_action_assist_generic); - - if (!replaced && !mGlowPadView.replaceTargetDrawablesIfPresent(component, - ASSIST_ICON_METADATA_NAME, - com.android.internal.R.drawable.ic_action_assist_generic)) { - Slog.w(TAG, "Couldn't grab icon from package " + component); - } - } else { - Slog.w(TAG, "No search icon specified in package " + component); + Intent intent = SearchManager.getAssistIntent(mContext); + if (intent != null) { + // XXX Hack. We need to substitute the icon here but haven't formalized + // the public API. The "_google" metadata will be going away, so + // DON'T USE IT! + ComponentName component = intent.getComponent(); + boolean replaced = mGlowPadView.replaceTargetDrawablesIfPresent(component, + ASSIST_ICON_METADATA_NAME + "_google", + com.android.internal.R.drawable.ic_action_assist_generic); + + if (!replaced && !mGlowPadView.replaceTargetDrawablesIfPresent(component, + ASSIST_ICON_METADATA_NAME, + com.android.internal.R.drawable.ic_action_assist_generic)) { + Slog.w(TAG, "Couldn't grab icon from package " + component); } - } else { - Slog.w(TAG, "No SearchManager"); } } @@ -337,7 +313,7 @@ class LockScreen extends LinearLayout implements KeyguardScreen { final int resId = mGlowPadView.getResourceIdForTarget(target); switch (resId) { case com.android.internal.R.drawable.ic_action_assist_generic: - Intent assistIntent = getAssistIntent(); + Intent assistIntent = SearchManager.getAssistIntent(mContext); if (assistIntent != null) { launchActivity(assistIntent); } else { @@ -550,7 +526,7 @@ class LockScreen extends LinearLayout implements KeyguardScreen { } else if (disabledBySimState) { Log.v(TAG, "Camera disabled by Sim State"); } - boolean searchActionAvailable = isAssistantAvailable(); + boolean searchActionAvailable = SearchManager.getAssistIntent(mContext) != null; mCameraDisabled = disabledByAdmin || disabledBySimState || !cameraTargetPresent; mSearchDisabled = disabledBySimState || !searchActionAvailable || !searchTargetPresent; mUnlockWidgetMethods.updateResources(); diff --git a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java index 35f71ec..beeea8e 100755 --- a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java +++ b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java @@ -2081,6 +2081,8 @@ public class PhoneWindowManager implements WindowManagerPolicy { Intent intent = new Intent(Intent.ACTION_SEARCH_LONG_PRESS); intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); try { + // TODO: This only stops the factory-installed search manager. + // Need to formalize an API to handle others SearchManager searchManager = getSearchManager(); if (searchManager != null) { searchManager.stopSearch(); @@ -2093,19 +2095,15 @@ public class PhoneWindowManager implements WindowManagerPolicy { private void launchAssistAction() { sendCloseSystemWindows(SYSTEM_DIALOG_REASON_ASSIST); - - SearchManager searchManager = getSearchManager(); - if (searchManager != null) { - Intent intent = searchManager.getAssistIntent(); - if (intent != null) { - intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK - | Intent.FLAG_ACTIVITY_SINGLE_TOP - | Intent.FLAG_ACTIVITY_CLEAR_TOP); - try { - mContext.startActivity(intent); - } catch (ActivityNotFoundException e) { - Slog.w(TAG, "No activity to handle assist action.", e); - } + Intent intent = SearchManager.getAssistIntent(mContext); + if (intent != null) { + intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK + | Intent.FLAG_ACTIVITY_SINGLE_TOP + | Intent.FLAG_ACTIVITY_CLEAR_TOP); + try { + mContext.startActivity(intent); + } catch (ActivityNotFoundException e) { + Slog.w(TAG, "No activity to handle assist action.", e); } } } @@ -4397,7 +4395,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { pw.print(prefix); pw.print("mUserRotationMode="); pw.print(mUserRotationMode); pw.print(" mUserRotation="); pw.print(mUserRotation); pw.print(" mAllowAllRotations="); pw.println(mAllowAllRotations); - pw.print(prefix); pw.print(" mCurrentAppOrientation="); pw.println(mCurrentAppOrientation); + pw.print(prefix); pw.print("mCurrentAppOrientation="); pw.println(mCurrentAppOrientation); pw.print(prefix); pw.print("mCarDockEnablesAccelerometer="); pw.print(mCarDockEnablesAccelerometer); pw.print(" mDeskDockEnablesAccelerometer="); @@ -4405,12 +4403,13 @@ public class PhoneWindowManager implements WindowManagerPolicy { pw.print(prefix); pw.print("mLidKeyboardAccessibility="); pw.print(mLidKeyboardAccessibility); pw.print(" mLidNavigationAccessibility="); pw.print(mLidNavigationAccessibility); - pw.print(" mLidControlsSleep="); pw.print(mLidControlsSleep); - pw.print(" mLongPressOnPowerBehavior="); pw.println(mLongPressOnPowerBehavior); + pw.print(" mLidControlsSleep="); pw.println(mLidControlsSleep); + pw.print(prefix); pw.print("mLongPressOnPowerBehavior="); + pw.print(mLongPressOnPowerBehavior); + pw.print(" mHasSoftInput="); pw.println(mHasSoftInput); pw.print(prefix); pw.print("mScreenOnEarly="); pw.print(mScreenOnEarly); pw.print(" mScreenOnFully="); pw.print(mScreenOnFully); - pw.print(" mOrientationSensorEnabled="); pw.print(mOrientationSensorEnabled); - pw.print(" mHasSoftInput="); pw.println(mHasSoftInput); + pw.print(" mOrientationSensorEnabled="); pw.println(mOrientationSensorEnabled); pw.print(prefix); pw.print("mUnrestrictedScreen=("); pw.print(mUnrestrictedScreenLeft); pw.print(","); pw.print(mUnrestrictedScreenTop); pw.print(") "); pw.print(mUnrestrictedScreenWidth); diff --git a/services/java/com/android/server/InputMethodManagerService.java b/services/java/com/android/server/InputMethodManagerService.java index 2d41f43..fdb278d 100644 --- a/services/java/com/android/server/InputMethodManagerService.java +++ b/services/java/com/android/server/InputMethodManagerService.java @@ -2668,7 +2668,16 @@ public class InputMethodManagerService extends IInputMethodManager.Stub } } - if (!setSubtypeOnly) { + // Workaround. + // ASEC is not ready in the IMMS constructor. Accordingly, forward-locked + // IMEs are not recognized and considered uninstalled. + // Actually, we can't move everything after SystemReady because + // IMMS needs to run in the encryption lock screen. So, we just skip changing + // the default IME here and try cheking the default IME again in systemReady(). + // TODO: Do nothing before system ready and implement a separated logic for + // the encryption lock screen. + // TODO: ASEC should be ready before IMMS is instantiated. + if (mSystemReady && !setSubtypeOnly) { // Set InputMethod here mSettings.putSelectedInputMethod(imi != null ? imi.getId() : ""); } diff --git a/services/java/com/android/server/accessibility/TouchExplorer.java b/services/java/com/android/server/accessibility/TouchExplorer.java index 152e188..48c6b2a 100644 --- a/services/java/com/android/server/accessibility/TouchExplorer.java +++ b/services/java/com/android/server/accessibility/TouchExplorer.java @@ -21,6 +21,7 @@ import android.gesture.Gesture; import android.gesture.GestureLibraries; import android.gesture.GestureLibrary; import android.gesture.GesturePoint; +import android.gesture.GestureStore; import android.gesture.GestureStroke; import android.gesture.Prediction; import android.graphics.Rect; @@ -220,7 +221,8 @@ public class TouchExplorer { mPerformLongPressDelayed = new PerformLongPressDelayed(); mExitGestureDetectionModeDelayed = new ExitGestureDetectionModeDelayed(); mGestureLibrary = GestureLibraries.fromRawResource(context, R.raw.accessibility_gestures); - mGestureLibrary.setOrientationStyle(4); + mGestureLibrary.setOrientationStyle(8); + mGestureLibrary.setSequenceType(GestureStore.SEQUENCE_SENSITIVE); mGestureLibrary.load(); mSendHoverEnterDelayed = new SendHoverDelayed(MotionEvent.ACTION_HOVER_ENTER, true); mSendHoverExitDelayed = new SendHoverDelayed(MotionEvent.ACTION_HOVER_EXIT, false); diff --git a/services/java/com/android/server/net/NetworkPolicyManagerService.java b/services/java/com/android/server/net/NetworkPolicyManagerService.java index d4e9cbc..fe43d11 100644 --- a/services/java/com/android/server/net/NetworkPolicyManagerService.java +++ b/services/java/com/android/server/net/NetworkPolicyManagerService.java @@ -225,6 +225,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { private static final int MSG_LIMIT_REACHED = 5; private static final int MSG_RESTRICT_BACKGROUND_CHANGED = 6; private static final int MSG_ADVISE_PERSIST_THRESHOLD = 7; + private static final int MSG_SCREEN_ON_CHANGED = 8; private final Context mContext; private final IActivityManager mActivityManager; @@ -349,7 +350,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { final IntentFilter screenFilter = new IntentFilter(); screenFilter.addAction(Intent.ACTION_SCREEN_ON); screenFilter.addAction(Intent.ACTION_SCREEN_OFF); - mContext.registerReceiver(mScreenReceiver, screenFilter, null, mHandler); + mContext.registerReceiver(mScreenReceiver, screenFilter); // watch for network interfaces to be claimed final IntentFilter connFilter = new IntentFilter(CONNECTIVITY_ACTION_IMMEDIATE); @@ -411,7 +412,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { synchronized (mRulesLock) { // screen-related broadcasts are protected by system, no need // for permissions check. - updateScreenOn(); + mHandler.obtainMessage(MSG_SCREEN_ON_CHANGED).sendToTarget(); } } }; @@ -1878,6 +1879,10 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { } return true; } + case MSG_SCREEN_ON_CHANGED: { + updateScreenOn(); + return true; + } default: { return false; } diff --git a/services/java/com/android/server/wm/WindowManagerService.java b/services/java/com/android/server/wm/WindowManagerService.java index 5efbe2c..5cd4beb 100755 --- a/services/java/com/android/server/wm/WindowManagerService.java +++ b/services/java/com/android/server/wm/WindowManagerService.java @@ -8257,6 +8257,9 @@ public class WindowManagerService extends IWindowManager.Stub mAppTransitionRunning = false; // Restore window app tokens to the ActivityManager views + for (int i = mAnimatingAppTokens.size() - 1; i >= 0; i--) { + mAnimatingAppTokens.get(i).sendingToBottom = false; + } mAnimatingAppTokens.clear(); mAnimatingAppTokens.addAll(mAppTokens); rebuildAppWindowListLocked(); @@ -9120,6 +9123,8 @@ public class WindowManagerService extends IWindowManager.Stub // If this window's application has been removed, just skip it. if (thisApp != null && (thisApp.removed || thisApp.sendingToBottom)) { + if (DEBUG_FOCUS) Slog.v(TAG, "Skipping app because " + (thisApp.removed + ? "removed" : "sendingToBottom")); continue; } @@ -9537,12 +9542,14 @@ public class WindowManagerService extends IWindowManager.Stub } } } - pw.println(); - if (mOpeningApps.size() > 0) { - pw.print(" mOpeningApps="); pw.println(mOpeningApps); - } - if (mClosingApps.size() > 0) { - pw.print(" mClosingApps="); pw.println(mClosingApps); + if (mOpeningApps.size() > 0 || mClosingApps.size() > 0) { + pw.println(); + if (mOpeningApps.size() > 0) { + pw.print(" mOpeningApps="); pw.println(mOpeningApps); + } + if (mClosingApps.size() > 0) { + pw.print(" mClosingApps="); pw.println(mClosingApps); + } } } @@ -9756,7 +9763,7 @@ public class WindowManagerService extends IWindowManager.Stub pw.print(" mTransitionWindowAnimationScale="); pw.print(mTransitionAnimationScale); pw.print(" mAnimatorDurationScale="); pw.println(mAnimatorDurationScale); pw.print(" mTraversalScheduled="); pw.print(mTraversalScheduled); - pw.print(" mNextAppTransition=0x"); + pw.print(" mNextAppTransition=0x"); pw.print(Integer.toHexString(mNextAppTransition)); pw.print(" mAppTransitionReady="); pw.println(mAppTransitionReady); pw.print(" mAppTransitionRunning="); pw.print(mAppTransitionRunning); @@ -9798,7 +9805,7 @@ public class WindowManagerService extends IWindowManager.Stub pw.println(mNextAppTransitionCallback); } pw.print(" mStartingIconInTransition="); pw.print(mStartingIconInTransition); - pw.print(", mSkipAppTransitionAnimation="); pw.println(mSkipAppTransitionAnimation); + pw.print(" mSkipAppTransitionAnimation="); pw.println(mSkipAppTransitionAnimation); } } @@ -9966,30 +9973,31 @@ public class WindowManagerService extends IWindowManager.Stub } synchronized(mWindowMap) { + pw.println(); if (dumpAll) { pw.println("-------------------------------------------------------------------------------"); } - dumpPolicyLocked(pw, args, dumpAll); + dumpLastANRLocked(pw); pw.println(); if (dumpAll) { pw.println("-------------------------------------------------------------------------------"); } - dumpSessionsLocked(pw, dumpAll); + dumpPolicyLocked(pw, args, dumpAll); pw.println(); if (dumpAll) { pw.println("-------------------------------------------------------------------------------"); } - dumpTokensLocked(pw, dumpAll); + dumpSessionsLocked(pw, dumpAll); pw.println(); if (dumpAll) { pw.println("-------------------------------------------------------------------------------"); } - dumpWindowsLocked(pw, dumpAll, null); + dumpTokensLocked(pw, dumpAll); pw.println(); if (dumpAll) { pw.println("-------------------------------------------------------------------------------"); } - dumpLastANRLocked(pw); + dumpWindowsLocked(pw, dumpAll, null); } } diff --git a/services/java/com/android/server/wm/WindowState.java b/services/java/com/android/server/wm/WindowState.java index 8f2ef76..f94bacd 100644 --- a/services/java/com/android/server/wm/WindowState.java +++ b/services/java/com/android/server/wm/WindowState.java @@ -719,6 +719,28 @@ final class WindowState implements WindowManagerPolicy.WindowState { } /** + * Like isReadyForDisplay(), but ignores any force hiding of the window due + * to the keyguard. + */ + boolean isReadyForDisplayIgnoringKeyguard() { + if (mRootToken.waitingToShow && + mService.mNextAppTransition != WindowManagerPolicy.TRANSIT_UNSET) { + return false; + } + final AppWindowToken atoken = mAppToken; + if (atoken == null && !mPolicyVisibility) { + // If this is not an app window, and the policy has asked to force + // hide, then we really do want to hide. + return false; + } + return mHasSurface && !mDestroying + && ((!mAttachedHidden && mViewVisibility == View.VISIBLE + && !mRootToken.hidden) + || mWinAnimator.mAnimation != null + || ((atoken != null) && (atoken.mAppAnimator.animation != null))); + } + + /** * Like isOnScreen, but returns false if the surface hasn't yet * been drawn. */ diff --git a/services/java/com/android/server/wm/WindowStateAnimator.java b/services/java/com/android/server/wm/WindowStateAnimator.java index 579cbb7..f2dd335 100644 --- a/services/java/com/android/server/wm/WindowStateAnimator.java +++ b/services/java/com/android/server/wm/WindowStateAnimator.java @@ -1218,10 +1218,10 @@ class WindowStateAnimator { } Slog.v(TAG, "performShow on " + this + ": mDrawState=" + mDrawState + " readyForDisplay=" - + mWin.isReadyForDisplay() + + mWin.isReadyForDisplayIgnoringKeyguard() + " starting=" + (mWin.mAttrs.type == TYPE_APPLICATION_STARTING), e); } - if (mDrawState == READY_TO_SHOW && mWin.isReadyForDisplay()) { + if (mDrawState == READY_TO_SHOW && mWin.isReadyForDisplayIgnoringKeyguard()) { if (SHOW_TRANSACTIONS || DEBUG_ORIENTATION) WindowManagerService.logSurface(mWin, "SHOW (performShowLocked)", null); if (DEBUG_VISIBILITY) Slog.v(TAG, "Showing " + this diff --git a/tests/Assistant/Android.mk b/tests/Assistant/Android.mk new file mode 100644 index 0000000..bf8cc29 --- /dev/null +++ b/tests/Assistant/Android.mk @@ -0,0 +1,11 @@ +LOCAL_PATH:= $(call my-dir) +include $(CLEAR_VARS) + +LOCAL_SRC_FILES := $(call all-subdir-java-files) + +LOCAL_PACKAGE_NAME := Assistant + +LOCAL_MODULE_TAGS := tests +LOCAL_CERTIFICATE := platform + +include $(BUILD_PACKAGE) diff --git a/tests/Assistant/AndroidManifest.xml b/tests/Assistant/AndroidManifest.xml new file mode 100644 index 0000000..b5d4d51 --- /dev/null +++ b/tests/Assistant/AndroidManifest.xml @@ -0,0 +1,39 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Copyright (C) 2008 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> + +<manifest xmlns:android="http://schemas.android.com/apk/res/android" + package="com.google.android.test.assistant"> + + <application android:label="@string/activity_title"> + + <activity android:name=".AssistActivity" + android:theme="@android:style/Theme.NoTitleBar"> + + <!-- Handle assist intent --> + <intent-filter> + <action android:name="android.intent.action.ASSIST" /> + <category android:name="android.intent.category.DEFAULT" /> + </intent-filter> + + <!-- Provide icon for search --> + <meta-data android:name="com.android.systemui.action_assist_icon" + android:resource="@drawable/ic_action_assist" /> + + </activity> + + </application> + +</manifest> diff --git a/tests/Assistant/res/drawable-hdpi/ic_action_assist_activated.png b/tests/Assistant/res/drawable-hdpi/ic_action_assist_activated.png Binary files differnew file mode 100644 index 0000000..cea8ac4 --- /dev/null +++ b/tests/Assistant/res/drawable-hdpi/ic_action_assist_activated.png diff --git a/tests/Assistant/res/drawable-hdpi/ic_action_assist_normal.png b/tests/Assistant/res/drawable-hdpi/ic_action_assist_normal.png Binary files differnew file mode 100644 index 0000000..bb7702d --- /dev/null +++ b/tests/Assistant/res/drawable-hdpi/ic_action_assist_normal.png diff --git a/tests/Assistant/res/drawable-mdpi/ic_action_assist_activated.png b/tests/Assistant/res/drawable-mdpi/ic_action_assist_activated.png Binary files differnew file mode 100644 index 0000000..5841d82 --- /dev/null +++ b/tests/Assistant/res/drawable-mdpi/ic_action_assist_activated.png diff --git a/tests/Assistant/res/drawable-mdpi/ic_action_assist_normal.png b/tests/Assistant/res/drawable-mdpi/ic_action_assist_normal.png Binary files differnew file mode 100644 index 0000000..3851f03 --- /dev/null +++ b/tests/Assistant/res/drawable-mdpi/ic_action_assist_normal.png diff --git a/tests/Assistant/res/drawable-xhdpi/ic_action_assist_activated.png b/tests/Assistant/res/drawable-xhdpi/ic_action_assist_activated.png Binary files differnew file mode 100644 index 0000000..778db19 --- /dev/null +++ b/tests/Assistant/res/drawable-xhdpi/ic_action_assist_activated.png diff --git a/tests/Assistant/res/drawable-xhdpi/ic_action_assist_normal.png b/tests/Assistant/res/drawable-xhdpi/ic_action_assist_normal.png Binary files differnew file mode 100644 index 0000000..ad49125 --- /dev/null +++ b/tests/Assistant/res/drawable-xhdpi/ic_action_assist_normal.png diff --git a/tests/Assistant/res/drawable/ic_action_assist.xml b/tests/Assistant/res/drawable/ic_action_assist.xml new file mode 100644 index 0000000..05c4bf5 --- /dev/null +++ b/tests/Assistant/res/drawable/ic_action_assist.xml @@ -0,0 +1,36 @@ +<?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. +--> +<selector xmlns:android="http://schemas.android.com/apk/res/android"> + + <item + android:state_enabled="true" + android:state_active="false" + android:state_focused="false" + android:drawable="@drawable/ic_action_assist_normal" /> + + <item + android:state_enabled="true" + android:state_active="true" + android:state_focused="false" + android:drawable="@drawable/ic_action_assist_activated" /> + + <item + android:state_enabled="true" + android:state_active="false" + android:state_focused="true" + android:drawable="@drawable/ic_action_assist_activated" /> + +</selector> diff --git a/tests/Assistant/res/layout/assist_intent_activity.xml b/tests/Assistant/res/layout/assist_intent_activity.xml new file mode 100644 index 0000000..49785bc --- /dev/null +++ b/tests/Assistant/res/layout/assist_intent_activity.xml @@ -0,0 +1,43 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- +** +** Copyright 2009, 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 the general lock screen which shows information about the + state of the device, as well as instructions on how to get past it + depending on the state of the device. It is the same for landscape + and portrait.--> +<LinearLayout + xmlns:android="http://schemas.android.com/apk/res/android" + android:orientation="vertical" + android:layout_width="match_parent" + android:layout_height="match_parent" + android:gravity="center"> + + <TextView android:id="@+id/label" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:text="@string/search_label" + /> + + <EditText android:id="@+id/search_input" + android:layout_width="match_parent" + android:layout_height="wrap_content" + /> + +</LinearLayout> + diff --git a/tests/Assistant/res/values/strings.xml b/tests/Assistant/res/values/strings.xml new file mode 100644 index 0000000..a59c1ef --- /dev/null +++ b/tests/Assistant/res/values/strings.xml @@ -0,0 +1,20 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Copyright (C) 2007 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> + <string name="activity_title">Assistant</string> + <string name="search_label">Orilla Search Engine</string> +</resources> diff --git a/tests/Assistant/src/com/google/android/test/assistant/AssistActivity.java b/tests/Assistant/src/com/google/android/test/assistant/AssistActivity.java new file mode 100644 index 0000000..51894a1 --- /dev/null +++ b/tests/Assistant/src/com/google/android/test/assistant/AssistActivity.java @@ -0,0 +1,31 @@ +/* + * 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.google.android.test.assistant; + +import android.app.Activity; +import android.os.Bundle; +import com.google.android.test.assistant.R; + +public class AssistActivity extends Activity { + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.assist_intent_activity); + } + +} diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/Bridge.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/Bridge.java index 66481fd..daf520b 100644 --- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/Bridge.java +++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/Bridge.java @@ -470,7 +470,7 @@ public final class Bridge extends com.android.ide.common.rendering.api.Bridge { if (pair == null) { pair = sDynamicIds.resolveId(value); if (pair == null) { - System.out.println(String.format("Missing id: %1$08X (%1$d)", value)); + //System.out.println(String.format("Missing id: %1$08X (%1$d)", value)); } } return pair; |