diff options
38 files changed, 1215 insertions, 658 deletions
diff --git a/api/system-current.txt b/api/system-current.txt index 4dcfd39..263d17a 100644 --- a/api/system-current.txt +++ b/api/system-current.txt @@ -8367,6 +8367,7 @@ package android.content { field public static final java.lang.String ACTION_MANAGE_APP_PERMISSIONS = "android.intent.action.MANAGE_APP_PERMISSIONS"; field public static final java.lang.String ACTION_MANAGE_NETWORK_USAGE = "android.intent.action.MANAGE_NETWORK_USAGE"; field public static final java.lang.String ACTION_MANAGE_PACKAGE_STORAGE = "android.intent.action.MANAGE_PACKAGE_STORAGE"; + field public static final java.lang.String ACTION_MANAGE_PERMISSIONS = "android.intent.action.MANAGE_PERMISSIONS"; field public static final java.lang.String ACTION_MANAGE_PERMISSION_APPS = "android.intent.action.MANAGE_PERMISSION_APPS"; field public static final java.lang.String ACTION_MEDIA_BAD_REMOVAL = "android.intent.action.MEDIA_BAD_REMOVAL"; field public static final java.lang.String ACTION_MEDIA_BUTTON = "android.intent.action.MEDIA_BUTTON"; diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java index 7d76760..2db623b 100644 --- a/core/java/android/content/Intent.java +++ b/core/java/android/content/Intent.java @@ -1535,6 +1535,22 @@ public class Intent implements Parcelable, Cloneable { "android.intent.action.MANAGE_APP_PERMISSIONS"; /** + * Activity action: Launch UI to manage permissions. + * <p> + * Input: Nothing. + * </p> + * <p> + * Output: Nothing. + * </p> + * + * @hide + */ + @SystemApi + @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION) + public static final String ACTION_MANAGE_PERMISSIONS = + "android.intent.action.MANAGE_PERMISSIONS"; + + /** * Intent extra: An app package name. * <p> * Type: String diff --git a/core/java/android/webkit/WebViewFactory.java b/core/java/android/webkit/WebViewFactory.java index 9782d72..b7d529e 100644 --- a/core/java/android/webkit/WebViewFactory.java +++ b/core/java/android/webkit/WebViewFactory.java @@ -40,7 +40,10 @@ import com.android.server.LocalServices; import dalvik.system.VMRuntime; import java.io.File; +import java.io.IOException; import java.util.Arrays; +import java.util.zip.ZipEntry; +import java.util.zip.ZipFile; /** * Top level factory, used creating all the main WebView implementation classes. @@ -323,15 +326,30 @@ public final class WebViewFactory { long newVmSize = 0L; for (String path : nativeLibs) { + if (path == null || TextUtils.isEmpty(path)) continue; if (DEBUG) Log.d(LOGTAG, "Checking file size of " + path); - if (path == null) continue; File f = new File(path); if (f.exists()) { - long length = f.length(); - if (length > newVmSize) { - newVmSize = length; + newVmSize = Math.max(newVmSize, f.length()); + continue; + } + if (path.contains("!")) { + String[] split = TextUtils.split(path, "!"); + if (split.length == 2) { + try { + ZipFile z = new ZipFile(split[0]); + ZipEntry e = z.getEntry(split[1]); + if (e != null && e.getMethod() == ZipEntry.STORED) { + newVmSize = Math.max(newVmSize, e.getSize()); + continue; + } + } + catch (IOException e) { + Log.e(LOGTAG, "error reading APK file " + split[0] + ", ", e); + } } } + Log.e(LOGTAG, "error sizing load for " + path); } if (DEBUG) { @@ -355,6 +373,27 @@ public final class WebViewFactory { } // throws MissingWebViewPackageException + private static String getLoadFromApkPath(String apkPath, + String[] abiList, + String nativeLibFileName) { + // Search the APK for a native library conforming to a listed ABI. + try { + ZipFile z = new ZipFile(apkPath); + for (String abi : abiList) { + final String entry = "lib/" + abi + "/" + nativeLibFileName; + ZipEntry e = z.getEntry(entry); + if (e != null && e.getMethod() == ZipEntry.STORED) { + // Return a path formatted for dlopen() load from APK. + return apkPath + "!" + entry; + } + } + } catch (IOException e) { + throw new MissingWebViewPackageException(e); + } + return ""; + } + + // throws MissingWebViewPackageException private static String[] getWebViewNativeLibraryPaths() { ApplicationInfo ai = getWebViewApplicationInfo(); final String NATIVE_LIB_FILE_NAME = getWebViewLibrary(ai); @@ -382,8 +421,29 @@ public final class WebViewFactory { path32 = ai.nativeLibraryDir; path64 = ""; } - if (!TextUtils.isEmpty(path32)) path32 += "/" + NATIVE_LIB_FILE_NAME; - if (!TextUtils.isEmpty(path64)) path64 += "/" + NATIVE_LIB_FILE_NAME; + + // Form the full paths to the extracted native libraries. + // If libraries were not extracted, try load from APK paths instead. + if (!TextUtils.isEmpty(path32)) { + path32 += "/" + NATIVE_LIB_FILE_NAME; + File f = new File(path32); + if (!f.exists()) { + path32 = getLoadFromApkPath(ai.sourceDir, + Build.SUPPORTED_32_BIT_ABIS, + NATIVE_LIB_FILE_NAME); + } + } + if (!TextUtils.isEmpty(path64)) { + path64 += "/" + NATIVE_LIB_FILE_NAME; + File f = new File(path64); + if (!f.exists()) { + path64 = getLoadFromApkPath(ai.sourceDir, + Build.SUPPORTED_64_BIT_ABIS, + NATIVE_LIB_FILE_NAME); + } + } + + if (DEBUG) Log.v(LOGTAG, "Native 32-bit lib: " + path32 + ", 64-bit lib: " + path64); return new String[] { path32, path64 }; } diff --git a/core/java/android/widget/Editor.java b/core/java/android/widget/Editor.java index 1d6f6dc..c829783 100644 --- a/core/java/android/widget/Editor.java +++ b/core/java/android/widget/Editor.java @@ -3426,9 +3426,13 @@ public class Editor { protected void updateDrawable() { final int offset = getCurrentCursorOffset(); final boolean isRtlCharAtOffset = mTextView.getLayout().isRtlCharAt(offset); + final Drawable oldDrawable = mDrawable; mDrawable = isRtlCharAtOffset ? mDrawableRtl : mDrawableLtr; mHotspotX = getHotspotX(mDrawable, isRtlCharAtOffset); mHorizontalGravity = getHorizontalGravity(isRtlCharAtOffset); + if (oldDrawable != mDrawable) { + postInvalidate(); + } } protected abstract int getHotspotX(Drawable drawable, boolean isRtlRun); diff --git a/core/java/com/android/internal/widget/FloatingToolbar.java b/core/java/com/android/internal/widget/FloatingToolbar.java index f98fbfc..fdc3547 100644 --- a/core/java/com/android/internal/widget/FloatingToolbar.java +++ b/core/java/com/android/internal/widget/FloatingToolbar.java @@ -79,7 +79,6 @@ public final class FloatingToolbar { private final FloatingToolbarPopup mPopup; private final Rect mContentRect = new Rect(); - private final Point mCoordinates = new Point(); private Menu mMenu; private List<CharSequence> mShowingTitles = new ArrayList<CharSequence>(); @@ -87,7 +86,6 @@ public final class FloatingToolbar { private int mSuggestedWidth; private boolean mWidthChanged = true; - private int mOverflowDirection; /** * Initializes a floating toolbar. @@ -157,11 +155,9 @@ public final class FloatingToolbar { mPopup.layoutMenuItems(menuItems, mMenuItemClickListener, mSuggestedWidth); mShowingTitles = getMenuItemTitles(menuItems); } - refreshCoordinates(); - mPopup.setOverflowDirection(mOverflowDirection); - mPopup.updateCoordinates(mCoordinates.x, mCoordinates.y); + mPopup.updateCoordinates(mContentRect); if (!mPopup.isShowing()) { - mPopup.show(mCoordinates.x, mCoordinates.y); + mPopup.show(mContentRect); } mWidthChanged = false; return this; @@ -209,25 +205,6 @@ public final class FloatingToolbar { } /** - * Refreshes {@link #mCoordinates} with values based on {@link #mContentRect}. - */ - private void refreshCoordinates() { - int x = mContentRect.centerX() - mPopup.getWidth() / 2; - int y; - if (mContentRect.top > mPopup.getHeight()) { - y = mContentRect.top - mPopup.getHeight(); - mOverflowDirection = FloatingToolbarPopup.OVERFLOW_DIRECTION_UP; - } else if (mContentRect.top > mPopup.getToolbarHeightWithVerticalMargin()) { - y = mContentRect.top - mPopup.getToolbarHeightWithVerticalMargin(); - mOverflowDirection = FloatingToolbarPopup.OVERFLOW_DIRECTION_DOWN; - } else { - y = mContentRect.bottom; - mOverflowDirection = FloatingToolbarPopup.OVERFLOW_DIRECTION_DOWN; - } - mCoordinates.set(x, y); - } - - /** * Returns true if this floating toolbar is currently showing the specified menu items. */ private boolean isCurrentlyShowing(List<MenuItem> menuItems) { @@ -345,6 +322,8 @@ public final class FloatingToolbar { } }; + private final Point mCoords = new Point(); + private final Region mTouchableRegion = new Region(); private final ViewTreeObserver.OnComputeInternalInsetsListener mInsetsComputer = new ViewTreeObserver.OnComputeInternalInsetsListener() { @@ -378,6 +357,7 @@ public final class FloatingToolbar { mShowAnimation = createGrowFadeInFromBottom(mContentContainer); mDismissAnimation = createShrinkFadeOutFromBottomAnimation( mContentContainer, + 0, new AnimatorListenerAdapter() { @Override public void onAnimationEnd(Animator animation) { @@ -387,6 +367,7 @@ public final class FloatingToolbar { }); mHideAnimation = createShrinkFadeOutFromBottomAnimation( mContentContainer, + 150, new AnimatorListenerAdapter() { @Override public void onAnimationEnd(Animator animation) { @@ -404,6 +385,8 @@ public final class FloatingToolbar { */ public void layoutMenuItems(List<MenuItem> menuItems, MenuItem.OnMenuItemClickListener menuItemClickListener, int suggestedWidth) { + Preconditions.checkNotNull(menuItems); + mContentContainer.removeAllViews(); if (mMainPanel == null) { mMainPanel = new FloatingToolbarMainPanel(mParent.getContext(), mOpenOverflow); @@ -426,7 +409,9 @@ public final class FloatingToolbar { * Shows this popup at the specified coordinates. * The specified coordinates may be adjusted to make sure the popup is entirely on-screen. */ - public void show(int x, int y) { + public void show(Rect contentRect) { + Preconditions.checkNotNull(contentRect); + if (isShowing()) { return; } @@ -435,6 +420,7 @@ public final class FloatingToolbar { mDismissed = false; cancelDismissAndHideAnimations(); cancelOverflowAnimations(); + // Make sure a panel is set as the content. if (mContentContainer.getChildCount() == 0) { setMainPanelAsContent(); @@ -442,8 +428,10 @@ public final class FloatingToolbar { // The "show" animation will make this visible. mContentContainer.setAlpha(0); } + updateOverflowHeight(contentRect.top - (mMarginVertical * 2)); + refreshCoordinatesAndOverflowDirection(contentRect); preparePopupContent(); - mPopupWindow.showAtLocation(mParent, Gravity.NO_GRAVITY, x, y); + mPopupWindow.showAtLocation(mParent, Gravity.NO_GRAVITY, mCoords.x, mCoords.y); setTouchableSurfaceInsetsComputer(); runShowAnimation(); } @@ -496,27 +484,17 @@ public final class FloatingToolbar { * The specified coordinates may be adjusted to make sure the popup is entirely on-screen. * This is a no-op if this popup is not showing. */ - public void updateCoordinates(int x, int y) { + public void updateCoordinates(Rect contentRect) { + Preconditions.checkNotNull(contentRect); + if (!isShowing() || !mPopupWindow.isShowing()) { return; } cancelOverflowAnimations(); + refreshCoordinatesAndOverflowDirection(contentRect); preparePopupContent(); - mPopupWindow.update(x, y, getWidth(), getHeight()); - } - - /** - * Sets the direction in which the overflow will open. i.e. up or down. - * - * @param overflowDirection Either {@link #OVERFLOW_DIRECTION_UP} - * or {@link #OVERFLOW_DIRECTION_DOWN}. - */ - public void setOverflowDirection(int overflowDirection) { - mOverflowDirection = overflowDirection; - if (mOverflowPanel != null) { - mOverflowPanel.setOverflowDirection(mOverflowDirection); - } + mPopupWindow.update(mCoords.x, mCoords.y, getWidth(), getHeight()); } /** @@ -540,7 +518,26 @@ public final class FloatingToolbar { return mContentContainer.getContext(); } - int getToolbarHeightWithVerticalMargin() { + private void refreshCoordinatesAndOverflowDirection(Rect contentRect) { + int x = contentRect.centerX() - getWidth() / 2; + int y; + if (contentRect.top > getHeight()) { + y = contentRect.top - getHeight(); + mOverflowDirection = FloatingToolbarPopup.OVERFLOW_DIRECTION_UP; + } else if (contentRect.top > getToolbarHeightWithVerticalMargin()) { + y = contentRect.top - getToolbarHeightWithVerticalMargin(); + mOverflowDirection = FloatingToolbarPopup.OVERFLOW_DIRECTION_DOWN; + } else { + y = contentRect.bottom; + mOverflowDirection = FloatingToolbarPopup.OVERFLOW_DIRECTION_DOWN; + } + mCoords.set(x, y); + if (mOverflowPanel != null) { + mOverflowPanel.setOverflowDirection(mOverflowDirection); + } + } + + private int getToolbarHeightWithVerticalMargin() { return getEstimatedToolbarHeight(mParent.getContext()) + mMarginVertical * 2; } @@ -693,16 +690,24 @@ public final class FloatingToolbar { } // Reset position. - if (mMainPanel != null - && mContentContainer.getChildAt(0) == mMainPanel.getView()) { + if (isMainPanelContent()) { positionMainPanel(); } - if (mOverflowPanel != null - && mContentContainer.getChildAt(0) == mOverflowPanel.getView()) { + if (isOverflowPanelContent()) { positionOverflowPanel(); } } + private boolean isMainPanelContent() { + return mMainPanel != null + && mContentContainer.getChildAt(0) == mMainPanel.getView(); + } + + private boolean isOverflowPanelContent() { + return mOverflowPanel != null + && mContentContainer.getChildAt(0) == mOverflowPanel.getView(); + } + /** * Sets the current content to be the main view panel. */ @@ -765,6 +770,25 @@ public final class FloatingToolbar { setContentAreaAsTouchableSurface(); } + private void updateOverflowHeight(int height) { + if (mOverflowPanel != null) { + mOverflowPanel.setSuggestedHeight(height); + + // Re-measure the popup and it's contents. + boolean mainPanelContent = isMainPanelContent(); + boolean overflowPanelContent = isOverflowPanelContent(); + mContentContainer.removeAllViews(); // required to update popup size. + updatePopupSize(); + // Reset the appropriate content. + if (mainPanelContent) { + setMainPanelAsContent(); + } + if (overflowPanelContent) { + setOverflowPanelAsContent(); + } + } + } + private void updatePopupSize() { int width = 0; int height = 0; @@ -864,6 +888,8 @@ public final class FloatingToolbar { * @return The menu items that are not included in this main panel. */ public List<MenuItem> layoutMenuItems(List<MenuItem> menuItems, int suggestedWidth) { + Preconditions.checkNotNull(menuItems); + final int toolbarWidth = getAdjustedToolbarWidth(mContext, suggestedWidth) // Reserve space for the "open overflow" button. - getEstimatedOpenOverflowButtonWidth(mContext); @@ -972,6 +998,7 @@ public final class FloatingToolbar { private MenuItem.OnMenuItemClickListener mOnMenuItemClickListener; private int mOverflowWidth = 0; + private int mSuggestedHeight; /** * Initializes a floating toolbar popup overflow view panel. @@ -981,6 +1008,7 @@ public final class FloatingToolbar { */ public FloatingToolbarOverflowPanel(Context context, Runnable closeOverflow) { mCloseOverflow = Preconditions.checkNotNull(closeOverflow); + mSuggestedHeight = getScreenHeight(context); mContentView = new LinearLayout(context); mContentView.setOrientation(LinearLayout.VERTICAL); @@ -1043,6 +1071,11 @@ public final class FloatingToolbar { mContentView.addView(mBackButtonContainer, index); } + public void setSuggestedHeight(int height) { + mSuggestedHeight = height; + setListViewHeight(); + } + /** * Returns the content view of the overflow. */ @@ -1074,9 +1107,17 @@ public final class FloatingToolbar { int itemHeight = getEstimatedToolbarHeight(mContentView.getContext()); int height = mListView.getAdapter().getCount() * itemHeight; int maxHeight = mContentView.getContext().getResources(). + getDimensionPixelSize(R.dimen.floating_toolbar_maximum_overflow_height); + int minHeight = mContentView.getContext().getResources(). getDimensionPixelSize(R.dimen.floating_toolbar_minimum_overflow_height); + int availableHeight = mSuggestedHeight - (mSuggestedHeight % itemHeight) + - itemHeight; // reserve space for the back button. ViewGroup.LayoutParams params = mListView.getLayoutParams(); - params.height = Math.min(height, maxHeight); + if (availableHeight >= minHeight) { + params.height = Math.min(Math.min(availableHeight, maxHeight), height); + } else { + params.height = Math.min(maxHeight, height); + } mListView.setLayoutParams(params); } @@ -1224,15 +1265,16 @@ public final class FloatingToolbar { * Creates a "shrink and fade out from bottom" animation for the specified view. * * @param view The view to animate + * @param startDelay The start delay of the animation * @param listener The animation listener */ private static AnimatorSet createShrinkFadeOutFromBottomAnimation( - View view, Animator.AnimatorListener listener) { + View view, int startDelay, Animator.AnimatorListener listener) { AnimatorSet shrinkFadeOutFromBottomAnimation = new AnimatorSet(); shrinkFadeOutFromBottomAnimation.playTogether( ObjectAnimator.ofFloat(view, View.SCALE_Y, 1, 0.5f).setDuration(125), ObjectAnimator.ofFloat(view, View.ALPHA, 1, 0).setDuration(75)); - shrinkFadeOutFromBottomAnimation.setStartDelay(150); + shrinkFadeOutFromBottomAnimation.setStartDelay(startDelay); shrinkFadeOutFromBottomAnimation.addListener(listener); return shrinkFadeOutFromBottomAnimation; } @@ -1271,16 +1313,4 @@ public final class FloatingToolbar { private static int getScreenHeight(Context context) { return context.getResources().getDisplayMetrics().heightPixels; } - - /** - * Returns value, restricted to the range min->max (inclusive). - * If maximum is less than minimum, the result is undefined. - * - * @param value The value to clamp. - * @param minimum The minimum value in the range. - * @param maximum The maximum value in the range. Must not be less than minimum. - */ - private static int clamp(int value, int minimum, int maximum) { - return Math.max(minimum, Math.min(value, maximum)); - } } diff --git a/core/jni/android/graphics/Region.cpp b/core/jni/android/graphics/Region.cpp index 90a020e..cf02e39 100644 --- a/core/jni/android/graphics/Region.cpp +++ b/core/jni/android/graphics/Region.cpp @@ -206,15 +206,20 @@ static jstring Region_toString(JNIEnv* env, jobject clazz, jlong regionHandle) { static jlong Region_createFromParcel(JNIEnv* env, jobject clazz, jobject parcel) { - if (parcel == NULL) { - return NULL; + if (parcel == nullptr) { + return 0; } android::Parcel* p = android::parcelForJavaObject(env, parcel); SkRegion* region = new SkRegion; size_t size = p->readInt32(); - region->readFromMemory(p->readInplace(size), size); + size_t actualSize = region->readFromMemory(p->readInplace(size), size); + + if (size != actualSize) { + delete region; + return 0; + } return reinterpret_cast<jlong>(region); } diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml index 79532e4..608d718 100644 --- a/core/res/AndroidManifest.xml +++ b/core/res/AndroidManifest.xml @@ -678,6 +678,7 @@ <!-- Allows an app to use fingerprint hardware. --> <permission android:name="android.permission.USE_FINGERPRINT" + android:permissionGroup="android.permission-group.SENSORS" android:label="@string/permlab_useFingerprint" android:description="@string/permdesc_useFingerprint" android:protectionLevel="dangerous" /> diff --git a/core/res/res/values/dimens.xml b/core/res/res/values/dimens.xml index 84747f1..813591b 100644 --- a/core/res/res/values/dimens.xml +++ b/core/res/res/values/dimens.xml @@ -392,7 +392,8 @@ <dimen name="floating_toolbar_text_size">14sp</dimen> <dimen name="floating_toolbar_menu_button_minimum_width">48dp</dimen> <dimen name="floating_toolbar_preferred_width">328dp</dimen> - <dimen name="floating_toolbar_minimum_overflow_height">144dp</dimen> + <dimen name="floating_toolbar_minimum_overflow_height">96dp</dimen> + <dimen name="floating_toolbar_maximum_overflow_height">192dp</dimen> <dimen name="floating_toolbar_horizontal_margin">16dp</dimen> <dimen name="floating_toolbar_vertical_margin">8dp</dimen> diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml index 0d306c6..64e3964 100755 --- a/core/res/res/values/symbols.xml +++ b/core/res/res/values/symbols.xml @@ -2256,6 +2256,7 @@ <java-symbol type="dimen" name="floating_toolbar_menu_button_minimum_width" /> <java-symbol type="dimen" name="floating_toolbar_preferred_width" /> <java-symbol type="dimen" name="floating_toolbar_minimum_overflow_height" /> + <java-symbol type="dimen" name="floating_toolbar_maximum_overflow_height" /> <java-symbol type="dimen" name="floating_toolbar_horizontal_margin" /> <java-symbol type="dimen" name="floating_toolbar_vertical_margin" /> diff --git a/media/java/android/media/MediaPlayer.java b/media/java/android/media/MediaPlayer.java index 3ee1959..f148606 100644 --- a/media/java/android/media/MediaPlayer.java +++ b/media/java/android/media/MediaPlayer.java @@ -40,6 +40,7 @@ import android.provider.Settings; import android.system.ErrnoException; import android.system.OsConstants; import android.util.Log; +import android.util.Pair; import android.view.Surface; import android.view.SurfaceHolder; import android.widget.VideoView; @@ -70,6 +71,8 @@ import java.lang.Runnable; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.net.InetSocketAddress; +import java.util.BitSet; +import java.util.HashSet; import java.util.Map; import java.util.Scanner; import java.util.Set; @@ -639,9 +642,7 @@ public class MediaPlayer implements SubtitleController.Listener } mTimeProvider = new TimeProvider(this); - mOutOfBandSubtitleTracks = new Vector<SubtitleTrack>(); mOpenSubtitleSources = new Vector<InputStream>(); - mInbandSubtitleTracks = new SubtitleTrack[0]; IBinder b = ServiceManager.getService(Context.APP_OPS_SERVICE); mAppOps = IAppOpsService.Stub.asInterface(b); @@ -1693,8 +1694,6 @@ public class MediaPlayer implements SubtitleController.Listener } mOpenSubtitleSources.clear(); } - mOutOfBandSubtitleTracks.clear(); - mInbandSubtitleTracks = new SubtitleTrack[0]; if (mSubtitleController != null) { mSubtitleController.reset(); } @@ -1709,6 +1708,11 @@ public class MediaPlayer implements SubtitleController.Listener if (mEventHandler != null) { mEventHandler.removeCallbacksAndMessages(null); } + + synchronized (mIndexTrackPairs) { + mIndexTrackPairs.clear(); + mInbandTrackIndices.clear(); + }; } private native void _reset(); @@ -2050,6 +2054,16 @@ public class MediaPlayer implements SubtitleController.Listener }; + // We would like domain specific classes with more informative names than the `first` and `second` + // in generic Pair, but we would also like to avoid creating new/trivial classes. As a compromise + // we document the meanings of `first` and `second` here: + // + // Pair.first - inband track index; non-null iff representing an inband track. + // Pair.second - a SubtitleTrack registered with mSubtitleController; non-null iff representing + // an inband subtitle track or any out-of-band track (subtitle or timedtext). + private Vector<Pair<Integer, SubtitleTrack>> mIndexTrackPairs = new Vector<>(); + private BitSet mInbandTrackIndices = new BitSet(); + /** * Returns an array of track information. * @@ -2061,17 +2075,20 @@ public class MediaPlayer implements SubtitleController.Listener public TrackInfo[] getTrackInfo() throws IllegalStateException { TrackInfo trackInfo[] = getInbandTrackInfo(); // add out-of-band tracks - TrackInfo allTrackInfo[] = new TrackInfo[trackInfo.length + mOutOfBandSubtitleTracks.size()]; - System.arraycopy(trackInfo, 0, allTrackInfo, 0, trackInfo.length); - int i = trackInfo.length; - for (SubtitleTrack track: mOutOfBandSubtitleTracks) { - int type = track.isTimedText() - ? TrackInfo.MEDIA_TRACK_TYPE_TIMEDTEXT - : TrackInfo.MEDIA_TRACK_TYPE_SUBTITLE; - allTrackInfo[i] = new TrackInfo(type, track.getFormat()); - ++i; + synchronized (mIndexTrackPairs) { + TrackInfo allTrackInfo[] = new TrackInfo[mIndexTrackPairs.size()]; + for (int i = 0; i < allTrackInfo.length; i++) { + Pair<Integer, SubtitleTrack> p = mIndexTrackPairs.get(i); + if (p.first != null) { + // inband track + allTrackInfo[i] = trackInfo[p.first]; + } else { + SubtitleTrack track = p.second; + allTrackInfo[i] = new TrackInfo(track.getTrackType(), track.getFormat()); + } + } + return allTrackInfo; } - return allTrackInfo; } private TrackInfo[] getInbandTrackInfo() throws IllegalStateException { @@ -2167,22 +2184,21 @@ public class MediaPlayer implements SubtitleController.Listener } } - private final Object mInbandSubtitleLock = new Object(); - private SubtitleTrack[] mInbandSubtitleTracks; private int mSelectedSubtitleTrackIndex = -1; - private Vector<SubtitleTrack> mOutOfBandSubtitleTracks; private Vector<InputStream> mOpenSubtitleSources; private OnSubtitleDataListener mSubtitleDataListener = new OnSubtitleDataListener() { @Override public void onSubtitleData(MediaPlayer mp, SubtitleData data) { int index = data.getTrackIndex(); - if (index >= mInbandSubtitleTracks.length) { - return; - } - SubtitleTrack track = mInbandSubtitleTracks[index]; - if (track != null) { - track.onData(data); + synchronized (mIndexTrackPairs) { + for (Pair<Integer, SubtitleTrack> p : mIndexTrackPairs) { + if (p.first != null && p.first == index && p.second != null) { + // inband subtitle track that owns data + SubtitleTrack track = p.second; + track.onData(data); + } + } } } }; @@ -2201,18 +2217,24 @@ public class MediaPlayer implements SubtitleController.Listener if (track == null) { return; } - for (int i = 0; i < mInbandSubtitleTracks.length; i++) { - if (mInbandSubtitleTracks[i] == track) { - Log.v(TAG, "Selecting subtitle track " + i); - mSelectedSubtitleTrackIndex = i; - try { - selectOrDeselectInbandTrack(mSelectedSubtitleTrackIndex, true); - } catch (IllegalStateException e) { + + synchronized (mIndexTrackPairs) { + for (Pair<Integer, SubtitleTrack> p : mIndexTrackPairs) { + if (p.first != null && p.second == track) { + // inband subtitle track that is selected + mSelectedSubtitleTrackIndex = p.first; + break; } - setOnSubtitleDataListener(mSubtitleDataListener); - break; } } + + if (mSelectedSubtitleTrackIndex >= 0) { + try { + selectOrDeselectInbandTrack(mSelectedSubtitleTrackIndex, true); + } catch (IllegalStateException e) { + } + setOnSubtitleDataListener(mSubtitleDataListener); + } // no need to select out-of-band tracks } @@ -2252,7 +2274,9 @@ public class MediaPlayer implements SubtitleController.Listener mOpenSubtitleSources.remove(fIs); } scanner.close(); - mOutOfBandSubtitleTracks.add(track); + synchronized (mIndexTrackPairs) { + mIndexTrackPairs.add(Pair.<Integer, SubtitleTrack>create(null, track)); + } track.onData(contents.getBytes(), true /* eos */, ~0 /* runID: keep forever */); return MEDIA_INFO_EXTERNAL_METADATA_UPDATE; } @@ -2274,23 +2298,33 @@ public class MediaPlayer implements SubtitleController.Listener setSubtitleAnchor(); } + populateInbandTracks(); + + if (mSubtitleController != null) { + mSubtitleController.selectDefaultTrack(); + } + } + + private void populateInbandTracks() { TrackInfo[] tracks = getInbandTrackInfo(); - synchronized (mInbandSubtitleLock) { - SubtitleTrack[] inbandTracks = new SubtitleTrack[tracks.length]; - for (int i=0; i < tracks.length; i++) { + synchronized (mIndexTrackPairs) { + for (int i = 0; i < tracks.length; i++) { + if (mInbandTrackIndices.get(i)) { + continue; + } else { + mInbandTrackIndices.set(i); + } + + // newly appeared inband track if (tracks[i].getTrackType() == TrackInfo.MEDIA_TRACK_TYPE_SUBTITLE) { - if (i < mInbandSubtitleTracks.length) { - inbandTracks[i] = mInbandSubtitleTracks[i]; - } else { - SubtitleTrack track = mSubtitleController.addTrack( - tracks[i].getFormat()); - inbandTracks[i] = track; - } + SubtitleTrack track = mSubtitleController.addTrack( + tracks[i].getFormat()); + mIndexTrackPairs.add(Pair.create(i, track)); + } else { + mIndexTrackPairs.add(Pair.<Integer, SubtitleTrack>create(i, null)); } } - mInbandSubtitleTracks = inbandTracks; } - mSubtitleController.selectDefaultTrack(); } /* TODO: Limit the total number of external timed text source to a reasonable number. @@ -2438,7 +2472,9 @@ public class MediaPlayer implements SubtitleController.Listener mSubtitleController.registerRenderer(new SRTRenderer(context, mEventHandler)); } final SubtitleTrack track = mSubtitleController.addTrack(fFormat); - mOutOfBandSubtitleTracks.add(track); + synchronized (mIndexTrackPairs) { + mIndexTrackPairs.add(Pair.<Integer, SubtitleTrack>create(null, track)); + } final FileDescriptor fd3 = fd2; final long offset2 = offset; @@ -2510,12 +2546,18 @@ public class MediaPlayer implements SubtitleController.Listener * @see #deselectTrack(int) */ public int getSelectedTrack(int trackType) throws IllegalStateException { - if (trackType == TrackInfo.MEDIA_TRACK_TYPE_SUBTITLE && mSubtitleController != null) { + if (mSubtitleController != null + && (trackType == TrackInfo.MEDIA_TRACK_TYPE_SUBTITLE + || trackType == TrackInfo.MEDIA_TRACK_TYPE_TIMEDTEXT)) { SubtitleTrack subtitleTrack = mSubtitleController.getSelectedTrack(); if (subtitleTrack != null) { - int index = mOutOfBandSubtitleTracks.indexOf(subtitleTrack); - if (index >= 0) { - return mInbandSubtitleTracks.length + index; + synchronized (mIndexTrackPairs) { + for (int i = 0; i < mIndexTrackPairs.size(); i++) { + Pair<Integer, SubtitleTrack> p = mIndexTrackPairs.get(i); + if (p.second == subtitleTrack && subtitleTrack.getTrackType() == trackType) { + return i; + } + } } } } @@ -2527,8 +2569,16 @@ public class MediaPlayer implements SubtitleController.Listener request.writeInt(INVOKE_ID_GET_SELECTED_TRACK); request.writeInt(trackType); invoke(request, reply); - int selectedTrack = reply.readInt(); - return selectedTrack; + int inbandTrackIndex = reply.readInt(); + synchronized (mIndexTrackPairs) { + for (int i = 0; i < mIndexTrackPairs.size(); i++) { + Pair<Integer, SubtitleTrack> p = mIndexTrackPairs.get(i); + if (p.first != null && p.first == inbandTrackIndex) { + return i; + } + } + } + return -1; } finally { request.recycle(); reply.recycle(); @@ -2588,36 +2638,30 @@ public class MediaPlayer implements SubtitleController.Listener private void selectOrDeselectTrack(int index, boolean select) throws IllegalStateException { // handle subtitle track through subtitle controller - SubtitleTrack track = null; - synchronized (mInbandSubtitleLock) { - if (mInbandSubtitleTracks.length == 0) { - TrackInfo[] tracks = getInbandTrackInfo(); - mInbandSubtitleTracks = new SubtitleTrack[tracks.length]; - for (int i=0; i < tracks.length; i++) { - if (tracks[i].getTrackType() == TrackInfo.MEDIA_TRACK_TYPE_SUBTITLE) { - mInbandSubtitleTracks[i] = mSubtitleController.addTrack(tracks[i].getFormat()); - } - } - } + populateInbandTracks(); + + Pair<Integer,SubtitleTrack> p = null; + try { + p = mIndexTrackPairs.get(index); + } catch (ArrayIndexOutOfBoundsException e) { + // ignore bad index + return; } - if (index < mInbandSubtitleTracks.length) { - track = mInbandSubtitleTracks[index]; - } else if (index < mInbandSubtitleTracks.length + mOutOfBandSubtitleTracks.size()) { - track = mOutOfBandSubtitleTracks.get(index - mInbandSubtitleTracks.length); + SubtitleTrack track = p.second; + if (track == null) { + // inband (de)select + selectOrDeselectInbandTrack(p.first, select); + return; } - if (mSubtitleController != null && track != null) { - if (select) { - if (track.isTimedText()) { - int ttIndex = getSelectedTrack(TrackInfo.MEDIA_TRACK_TYPE_TIMEDTEXT); - if (ttIndex >= 0 && ttIndex < mInbandSubtitleTracks.length) { - // deselect inband counterpart - selectOrDeselectInbandTrack(ttIndex, false); - } - } - mSubtitleController.selectTrack(track); - } else if (mSubtitleController.getSelectedTrack() == track) { + if (mSubtitleController == null) { + return; + } + + if (!select) { + // out-of-band deselect + if (mSubtitleController.getSelectedTrack() == track) { mSubtitleController.selectTrack(null); } else { Log.w(TAG, "trying to deselect track that was not selected"); @@ -2625,7 +2669,20 @@ public class MediaPlayer implements SubtitleController.Listener return; } - selectOrDeselectInbandTrack(index, select); + // out-of-band select + if (track.getTrackType() == TrackInfo.MEDIA_TRACK_TYPE_TIMEDTEXT) { + int ttIndex = getSelectedTrack(TrackInfo.MEDIA_TRACK_TYPE_TIMEDTEXT); + synchronized (mIndexTrackPairs) { + if (ttIndex >= 0 && ttIndex < mIndexTrackPairs.size()) { + Pair<Integer,SubtitleTrack> p2 = mIndexTrackPairs.get(ttIndex); + if (p2.first != null && p2.second == null) { + // deselect inband counterpart + selectOrDeselectInbandTrack(p2.first, false); + } + } + } + } + mSubtitleController.selectTrack(track); } private void selectOrDeselectInbandTrack(int index, boolean select) diff --git a/media/java/android/media/PlaybackParams.java b/media/java/android/media/PlaybackParams.java index 8810ac5..021dbf2 100644 --- a/media/java/android/media/PlaybackParams.java +++ b/media/java/android/media/PlaybackParams.java @@ -174,8 +174,12 @@ public final class PlaybackParams implements Parcelable { * Sets the pitch factor. * @param pitch * @return this <code>PlaybackParams</code> instance. + * @throws InvalidArgumentException if the pitch is negative */ public PlaybackParams setPitch(float pitch) { + if (pitch < 0.f) { + throw new IllegalArgumentException("pitch must not be negative"); + } mPitch = pitch; mSet |= SET_PITCH; return this; diff --git a/media/java/android/media/SubtitleController.java b/media/java/android/media/SubtitleController.java index f82dbe0..fd72b39 100644 --- a/media/java/android/media/SubtitleController.java +++ b/media/java/android/media/SubtitleController.java @@ -20,6 +20,7 @@ import java.util.Locale; import java.util.Vector; import android.content.Context; +import android.media.MediaPlayer.TrackInfo; import android.media.SubtitleTrack.RenderingWidget; import android.os.Handler; import android.os.Looper; @@ -275,7 +276,8 @@ public class SubtitleController { mSelectedTrack.getFormat().getInteger( MediaFormat.KEY_IS_FORCED_SUBTITLE, 0) != 0)) { show(); - } else if (mSelectedTrack != null && !mSelectedTrack.isTimedText()) { + } else if (mSelectedTrack != null + && mSelectedTrack.getTrackType() == TrackInfo.MEDIA_TRACK_TYPE_SUBTITLE) { hide(); } mVisibilityIsExplicit = false; diff --git a/media/java/android/media/SubtitleTrack.java b/media/java/android/media/SubtitleTrack.java index c760810..6c8e323 100644 --- a/media/java/android/media/SubtitleTrack.java +++ b/media/java/android/media/SubtitleTrack.java @@ -17,6 +17,7 @@ package android.media; import android.graphics.Canvas; +import android.media.MediaPlayer.TrackInfo; import android.os.Handler; import android.util.Log; import android.util.LongSparseArray; @@ -609,8 +610,10 @@ public abstract class SubtitleTrack implements MediaTimeProvider.OnMediaTimeList } /** @hide whether this is a text track who fires events instead getting rendered */ - public boolean isTimedText() { - return getRenderingWidget() == null; + public int getTrackType() { + return getRenderingWidget() == null + ? TrackInfo.MEDIA_TRACK_TYPE_TIMEDTEXT + : TrackInfo.MEDIA_TRACK_TYPE_SUBTITLE; } diff --git a/media/java/android/media/SyncParams.java b/media/java/android/media/SyncParams.java index 00a8dc0..319eacb 100644 --- a/media/java/android/media/SyncParams.java +++ b/media/java/android/media/SyncParams.java @@ -51,9 +51,9 @@ import android.annotation.IntDef; * </ul> * <p> <strong>tolerance:</strong> specifies the amount of allowed playback rate * change to keep media in sync with the sync source. The handling of this depends - * on the sync source. + * on the sync source, but must not be negative, and must be less than one. * <p> <strong>frameRate:</strong> initial hint for video frame rate. Used when - * sync source is vsync. + * sync source is vsync. Negative values can be used to clear a previous hint. */ public final class SyncParams { /** @hide */ @@ -163,7 +163,7 @@ public final class SyncParams { private int mSet = 0; // params - private int mAudioAdjustMode = AUDIO_ADJUST_MODE_STRETCH; + private int mAudioAdjustMode = AUDIO_ADJUST_MODE_DEFAULT; private int mSyncSource = SYNC_SOURCE_DEFAULT; private float mTolerance = 0.f; private float mFrameRate = 0.f; @@ -227,13 +227,17 @@ public final class SyncParams { } /** - * Sets the tolerance. The default tolerance is 0. + * Sets the tolerance. The default tolerance is platform specific, but is never more than 1/24. * @param tolerance A non-negative number representing * the maximum deviation of the playback rate from the playback rate * set. ({@code abs(actual_rate - set_rate) / set_rate}) * @return this <code>SyncParams</code> instance. + * @throws InvalidArgumentException if the tolerance is negative, or not less than one */ public SyncParams setTolerance(float tolerance) { + if (tolerance < 0.f || tolerance >= 1.f) { + throw new IllegalArgumentException("tolerance must be less than one and non-negative"); + } mTolerance = tolerance; mSet |= SET_TOLERANCE; return this; @@ -256,7 +260,8 @@ public final class SyncParams { /** * Sets the video frame rate hint to be used. By default the frame rate is unspecified. * @param frameRate A non-negative number used as an initial hint on - * the video frame rate to be used when using vsync as the sync source. + * the video frame rate to be used when using vsync as the sync source. A negative + * number is used to clear a previous hint. * @return this <code>SyncParams</code> instance. */ public SyncParams setFrameRate(float frameRate) { @@ -269,7 +274,8 @@ public final class SyncParams { * Retrieves the video frame rate hint. * @return frame rate factor. A non-negative number representing * the maximum deviation of the playback rate from the playback rate - * set. ({@code abs(actual_rate - set_rate) / set_rate}) + * set. ({@code abs(actual_rate - set_rate) / set_rate}), or a negative + * number representing the desire to clear a previous hint using these params. * @throws IllegalStateException if frame rate is not set. */ public float getFrameRate() { diff --git a/packages/SystemUI/docs/demo_mode.md b/packages/SystemUI/docs/demo_mode.md index 18ae4cb..258c76b 100644 --- a/packages/SystemUI/docs/demo_mode.md +++ b/packages/SystemUI/docs/demo_mode.md @@ -38,6 +38,8 @@ Command | Subcommand | Argument | Description | | ```datatype``` | Values: ```1x```, ```3g```, ```4g```, ```e```, ```g```, ```h```, ```lte```, ```roam```, any other value to hide | | ```level``` | Sets mobile signal strength level (null or 0-4) | ```carriernetworkchange``` | | Sets mobile signal icon to carrier network change UX when disconnected (```show``` to show icon, any other value to hide) + | ```sims``` | | Sets the number of sims (1-8) + | ```nosim``` | | ```show``` to show icon, any other value to hide ```bars``` | | | Control the visual style of the bars (opaque, translucent, etc) | ```mode``` | | Sets the bars visual style (opaque, translucent, semi-transparent) ```status``` | | | Control the system status icons diff --git a/packages/SystemUI/res/layout/zen_mode_panel.xml b/packages/SystemUI/res/layout/zen_mode_panel.xml index 2160ca3..731d4c1 100644 --- a/packages/SystemUI/res/layout/zen_mode_panel.xml +++ b/packages/SystemUI/res/layout/zen_mode_panel.xml @@ -61,6 +61,7 @@ android:layout_height="wrap_content" android:layout_marginTop="12dp" android:layout_marginStart="24dp" + android:textDirection="locale" android:lineSpacingMultiplier="1.20029" android:layout_toStartOf="@id/zen_introduction_confirm" android:textAppearance="@style/TextAppearance.QS.Introduction" /> diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSTile.java b/packages/SystemUI/src/com/android/systemui/qs/QSTile.java index 3b217df..72bb136 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/QSTile.java +++ b/packages/SystemUI/src/com/android/systemui/qs/QSTile.java @@ -24,23 +24,21 @@ import android.graphics.drawable.Drawable; import android.os.Handler; import android.os.Looper; import android.os.Message; -import android.text.TextUtils; import android.util.Log; import android.util.SparseArray; import android.view.View; import android.view.ViewGroup; -import com.android.internal.logging.MetricsLogger; import com.android.systemui.qs.QSTile.State; import com.android.systemui.statusbar.policy.BluetoothController; import com.android.systemui.statusbar.policy.CastController; import com.android.systemui.statusbar.policy.FlashlightController; +import com.android.systemui.statusbar.policy.HotspotController; import com.android.systemui.statusbar.policy.KeyguardMonitor; import com.android.systemui.statusbar.policy.Listenable; import com.android.systemui.statusbar.policy.LocationController; import com.android.systemui.statusbar.policy.NetworkController; import com.android.systemui.statusbar.policy.RotationLockController; -import com.android.systemui.statusbar.policy.HotspotController; import com.android.systemui.statusbar.policy.ZenModeController; import java.util.Collection; diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/CellularTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/CellularTile.java index 1721335..dcf0438 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/CellularTile.java +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/CellularTile.java @@ -30,9 +30,11 @@ import com.android.systemui.qs.QSTile; import com.android.systemui.qs.QSTileView; import com.android.systemui.qs.SignalTileView; import com.android.systemui.statusbar.policy.NetworkController; +import com.android.systemui.statusbar.policy.NetworkController.IconState; import com.android.systemui.statusbar.policy.NetworkController.MobileDataController; import com.android.systemui.statusbar.policy.NetworkController.MobileDataController.DataUsageInfo; -import com.android.systemui.statusbar.policy.NetworkController.NetworkSignalChangedCallback; +import com.android.systemui.statusbar.policy.NetworkController.SignalCallback; +import com.android.systemui.statusbar.policy.SignalCallbackAdapter; /** Quick settings tile: Cellular **/ public class CellularTile extends QSTile<QSTile.SignalState> { @@ -63,9 +65,9 @@ public class CellularTile extends QSTile<QSTile.SignalState> { @Override public void setListening(boolean listening) { if (listening) { - mController.addNetworkSignalChangedCallback(mCallback); + mController.addSignalCallback(mSignalCallback); } else { - mController.removeNetworkSignalChangedCallback(mCallback); + mController.removeSignalCallback(mSignalCallback); } } @@ -138,7 +140,6 @@ public class CellularTile extends QSTile<QSTile.SignalState> { private static final class CallbackInfo { boolean enabled; boolean wifiEnabled; - boolean wifiConnected; boolean airplaneModeEnabled; int mobileSignalIconId; String signalContentDescription; @@ -151,40 +152,39 @@ public class CellularTile extends QSTile<QSTile.SignalState> { boolean isDataTypeIconWide; } - private final NetworkSignalChangedCallback mCallback = new NetworkSignalChangedCallback() { + private final SignalCallback mSignalCallback = new SignalCallbackAdapter() { private final CallbackInfo mInfo = new CallbackInfo(); - @Override - public void onWifiSignalChanged(boolean enabled, boolean connected, int wifiSignalIconId, - boolean activityIn, boolean activityOut, - String wifiSignalContentDescriptionId, String description) { + public void setWifiIndicators(boolean enabled, IconState statusIcon, IconState qsIcon, + boolean activityIn, boolean activityOut, String description) { mInfo.wifiEnabled = enabled; - mInfo.wifiConnected = connected; refreshState(mInfo); } @Override - public void onMobileDataSignalChanged(boolean enabled, - int mobileSignalIconId, - String mobileSignalContentDescriptionId, int dataTypeIconId, - boolean activityIn, boolean activityOut, - String dataTypeContentDescriptionId, String description, - boolean isDataTypeIconWide) { - mInfo.enabled = enabled; - mInfo.mobileSignalIconId = mobileSignalIconId; - mInfo.signalContentDescription = mobileSignalContentDescriptionId; - mInfo.dataTypeIconId = dataTypeIconId; - mInfo.dataContentDescription = dataTypeContentDescriptionId; + public void setMobileDataIndicators(IconState statusIcon, IconState qsIcon, + int darkStatusIcon, int statusType, int qsType, boolean activityIn, + boolean activityOut, String typeContentDescription, String description, + boolean isWide, int subId) { + if (qsIcon == null) { + // Not data sim, don't display. + return; + } + mInfo.enabled = qsIcon.visible; + mInfo.mobileSignalIconId = qsIcon.icon; + mInfo.signalContentDescription = qsIcon.contentDescription; + mInfo.dataTypeIconId = qsType; + mInfo.dataContentDescription = typeContentDescription; mInfo.activityIn = activityIn; mInfo.activityOut = activityOut; mInfo.enabledDesc = description; - mInfo.isDataTypeIconWide = isDataTypeIconWide; + mInfo.isDataTypeIconWide = qsType != 0 && isWide; refreshState(mInfo); } @Override - public void onNoSimVisibleChanged(boolean visible) { - mInfo.noSim = visible; + public void setNoSims(boolean show) { + mInfo.noSim = show; if (mInfo.noSim) { // Make sure signal gets cleared out when no sims. mInfo.mobileSignalIconId = 0; @@ -199,12 +199,13 @@ public class CellularTile extends QSTile<QSTile.SignalState> { } @Override - public void onAirplaneModeChanged(boolean enabled) { - mInfo.airplaneModeEnabled = enabled; + public void setIsAirplaneMode(IconState icon) { + mInfo.airplaneModeEnabled = icon.visible; refreshState(mInfo); } - public void onMobileDataEnabled(boolean enabled) { + @Override + public void setMobileDataEnabled(boolean enabled) { mDetailAdapter.setMobileDataEnabled(enabled); } }; diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/WifiTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/WifiTile.java index c3f9e33..9504ea3 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/WifiTile.java +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/WifiTile.java @@ -16,8 +16,6 @@ package com.android.systemui.qs.tiles; -import java.util.List; - import android.content.Context; import android.content.Intent; import android.content.res.Resources; @@ -36,7 +34,11 @@ import com.android.systemui.qs.QSTileView; import com.android.systemui.qs.SignalTileView; import com.android.systemui.statusbar.policy.NetworkController; import com.android.systemui.statusbar.policy.NetworkController.AccessPointController; -import com.android.systemui.statusbar.policy.NetworkController.NetworkSignalChangedCallback; +import com.android.systemui.statusbar.policy.NetworkController.IconState; +import com.android.systemui.statusbar.policy.NetworkController.SignalCallback; +import com.android.systemui.statusbar.policy.SignalCallbackAdapter; + +import java.util.List; /** Quick settings tile: Wifi **/ public class WifiTile extends QSTile<QSTile.SignalState> { @@ -67,9 +69,9 @@ public class WifiTile extends QSTile<QSTile.SignalState> { @Override public void setListening(boolean listening) { if (listening) { - mController.addNetworkSignalChangedCallback(mCallback); + mController.addSignalCallback(mSignalCallback); } else { - mController.removeNetworkSignalChangedCallback(mCallback); + mController.removeSignalCallback(mSignalCallback); } } @@ -211,46 +213,21 @@ public class WifiTile extends QSTile<QSTile.SignalState> { } } - private final NetworkSignalChangedCallback mCallback = new NetworkSignalChangedCallback() { + private final SignalCallback mSignalCallback = new SignalCallbackAdapter() { @Override - public void onWifiSignalChanged(boolean enabled, boolean connected, int wifiSignalIconId, - boolean activityIn, boolean activityOut, - String wifiSignalContentDescriptionId, String description) { + public void setWifiIndicators(boolean enabled, IconState statusIcon, IconState qsIcon, + boolean activityIn, boolean activityOut, String description) { if (DEBUG) Log.d(TAG, "onWifiSignalChanged enabled=" + enabled); final CallbackInfo info = new CallbackInfo(); info.enabled = enabled; - info.connected = connected; - info.wifiSignalIconId = wifiSignalIconId; + info.connected = qsIcon.visible; + info.wifiSignalIconId = qsIcon.icon; info.enabledDesc = description; info.activityIn = activityIn; info.activityOut = activityOut; - info.wifiSignalContentDescription = wifiSignalContentDescriptionId; + info.wifiSignalContentDescription = qsIcon.contentDescription; refreshState(info); } - - @Override - public void onMobileDataSignalChanged(boolean enabled, - int mobileSignalIconId, - String mobileSignalContentDescriptionId, int dataTypeIconId, - boolean activityIn, boolean activityOut, - String dataTypeContentDescriptionId, String description, - boolean isDataTypeIconWide) { - // noop - } - - public void onNoSimVisibleChanged(boolean noSims) { - // noop - } - - @Override - public void onAirplaneModeChanged(boolean enabled) { - // noop - } - - @Override - public void onMobileDataEnabled(boolean enabled) { - // noop - } }; private final class WifiDetailAdapter implements DetailAdapter, diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/SignalClusterView.java b/packages/SystemUI/src/com/android/systemui/statusbar/SignalClusterView.java index f6629dd..14e491b 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/SignalClusterView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/SignalClusterView.java @@ -33,6 +33,7 @@ import android.widget.ImageView; import android.widget.LinearLayout; import com.android.systemui.R; +import com.android.systemui.statusbar.policy.NetworkController.IconState; import com.android.systemui.statusbar.policy.NetworkControllerImpl; import com.android.systemui.statusbar.policy.SecurityController; @@ -42,7 +43,7 @@ import java.util.List; // Intimately tied to the design of res/layout/signal_cluster_view.xml public class SignalClusterView extends LinearLayout - implements NetworkControllerImpl.SignalCluster, + implements NetworkControllerImpl.SignalCallback, SecurityController.SecurityControllerCallback { static final String TAG = "SignalClusterView"; @@ -59,7 +60,7 @@ public class SignalClusterView private int mWifiStrengthId = 0; private boolean mIsAirplaneMode = false; private int mAirplaneIconId = 0; - private int mAirplaneContentDescription; + private String mAirplaneContentDescription; private String mWifiDescription; private String mEthernetDescription; private ArrayList<PhoneState> mPhoneStates = new ArrayList<PhoneState>(); @@ -166,35 +167,36 @@ public class SignalClusterView } @Override - public void setWifiIndicators(boolean visible, int strengthIcon, String contentDescription) { - mWifiVisible = visible; - mWifiStrengthId = strengthIcon; - mWifiDescription = contentDescription; + public void setWifiIndicators(boolean enabled, IconState statusIcon, IconState qsIcon, + boolean activityIn, boolean activityOut, String description) { + mWifiVisible = statusIcon.visible; + mWifiStrengthId = statusIcon.icon; + mWifiDescription = statusIcon.contentDescription; apply(); } @Override - public void setMobileDataIndicators(boolean visible, int strengthIcon, int darkStrengthIcon, - int typeIcon, String contentDescription, String typeContentDescription, - boolean isTypeIconWide, int subId) { + public void setMobileDataIndicators(IconState statusIcon, IconState qsIcon, int darkStatusIcon, + int statusType, int qsType, boolean activityIn, boolean activityOut, + String typeContentDescription, String description, boolean isWide, int subId) { PhoneState state = getOrInflateState(subId); - state.mMobileVisible = visible; - state.mMobileStrengthId = strengthIcon; - state.mMobileDarkStrengthId = darkStrengthIcon; - state.mMobileTypeId = typeIcon; - state.mMobileDescription = contentDescription; + state.mMobileVisible = statusIcon.visible; + state.mMobileStrengthId = statusIcon.icon; + state.mMobileDarkStrengthId = darkStatusIcon; + state.mMobileTypeId = statusType; + state.mMobileDescription = statusIcon.contentDescription; state.mMobileTypeDescription = typeContentDescription; - state.mIsMobileTypeIconWide = isTypeIconWide; + state.mIsMobileTypeIconWide = statusType != 0 && isWide; apply(); } @Override - public void setEthernetIndicators(boolean visible, int icon, String contentDescription) { - mEthernetVisible = visible; - mEthernetIconId = icon; - mEthernetDescription = contentDescription; + public void setEthernetIndicators(IconState state) { + mEthernetVisible = state.visible; + mEthernetIconId = state.icon; + mEthernetDescription = state.contentDescription; apply(); } @@ -239,15 +241,20 @@ public class SignalClusterView } @Override - public void setIsAirplaneMode(boolean is, int airplaneIconId, int contentDescription) { - mIsAirplaneMode = is; - mAirplaneIconId = airplaneIconId; - mAirplaneContentDescription = contentDescription; + public void setIsAirplaneMode(IconState icon) { + mIsAirplaneMode = icon.visible; + mAirplaneIconId = icon.icon; + mAirplaneContentDescription = icon.contentDescription; apply(); } @Override + public void setMobileDataEnabled(boolean enabled) { + // Don't care. + } + + @Override public boolean dispatchPopulateAccessibilityEventInternal(AccessibilityEvent event) { // Standard group layout onPopulateAccessibilityEvent() implementations // ignore content description, so populate manually @@ -343,8 +350,7 @@ public class SignalClusterView if (mIsAirplaneMode) { mAirplane.setImageResource(mAirplaneIconId); - mAirplane.setContentDescription(mAirplaneContentDescription != 0 ? - mContext.getString(mAirplaneContentDescription) : null); + mAirplane.setContentDescription(mAirplaneContentDescription); mAirplane.setVisibility(View.VISIBLE); } else { mAirplane.setVisibility(View.GONE); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java index 887b8f4..2a9df19 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java @@ -779,9 +779,9 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode, (SignalClusterView) mKeyguardStatusBar.findViewById(R.id.signal_cluster); final SignalClusterView signalClusterQs = (SignalClusterView) mHeader.findViewById(R.id.signal_cluster); - mNetworkController.addSignalCluster(signalCluster); - mNetworkController.addSignalCluster(signalClusterKeyguard); - mNetworkController.addSignalCluster(signalClusterQs); + mNetworkController.addSignalCallback(signalCluster); + mNetworkController.addSignalCallback(signalClusterKeyguard); + mNetworkController.addSignalCallback(signalClusterQs); signalCluster.setSecurityController(mSecurityController); signalCluster.setNetworkController(mNetworkController); signalClusterKeyguard.setSecurityController(mSecurityController); @@ -3087,6 +3087,16 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode, } mContext.unregisterReceiver(mBroadcastReceiver); mAssistManager.destroy(); + + final SignalClusterView signalCluster = + (SignalClusterView) mStatusBarView.findViewById(R.id.signal_cluster); + final SignalClusterView signalClusterKeyguard = + (SignalClusterView) mKeyguardStatusBar.findViewById(R.id.signal_cluster); + final SignalClusterView signalClusterQs = + (SignalClusterView) mHeader.findViewById(R.id.signal_cluster); + mNetworkController.addSignalCallback(signalCluster); + mNetworkController.addSignalCallback(signalClusterKeyguard); + mNetworkController.addSignalCallback(signalClusterQs); } private boolean mDemoModeAllowed; diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/CallbackHandler.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/CallbackHandler.java new file mode 100644 index 0000000..7f52191 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/CallbackHandler.java @@ -0,0 +1,181 @@ +/* + * Copyright (C) 2015 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.android.systemui.statusbar.policy; + +import android.os.Handler; +import android.os.Looper; +import android.os.Message; +import android.telephony.SubscriptionInfo; + +import com.android.internal.annotations.VisibleForTesting; +import com.android.systemui.statusbar.policy.NetworkController.IconState; +import com.android.systemui.statusbar.policy.NetworkController.SignalCallback; +import com.android.systemui.statusbar.policy.NetworkControllerImpl.EmergencyListener; + +import java.util.ArrayList; +import java.util.List; + + +/** + * Implements network listeners and forwards the calls along onto other listeners but on + * the current or specified Looper. + */ +public class CallbackHandler extends Handler implements EmergencyListener, SignalCallback { + private static final int MSG_EMERGENCE_CHANGED = 0; + private static final int MSG_SUBS_CHANGED = 1; + private static final int MSG_NO_SIM_VISIBLE_CHANGED = 2; + private static final int MSG_ETHERNET_CHANGED = 3; + private static final int MSG_AIRPLANE_MODE_CHANGED = 4; + private static final int MSG_MOBILE_DATA_ENABLED_CHANGED = 5; + private static final int MSG_ADD_REMOVE_EMERGENCY = 6; + private static final int MSG_ADD_REMOVE_SIGNAL = 7; + + // All the callbacks. + private final ArrayList<EmergencyListener> mEmergencyListeners = new ArrayList<>(); + private final ArrayList<SignalCallback> mSignalCallbacks = new ArrayList<>(); + + public CallbackHandler() { + super(); + } + + @VisibleForTesting + CallbackHandler(Looper looper) { + super(looper); + } + + @Override + @SuppressWarnings("unchecked") + public void handleMessage(Message msg) { + switch (msg.what) { + case MSG_EMERGENCE_CHANGED: + for (EmergencyListener listener : mEmergencyListeners) { + listener.setEmergencyCallsOnly(msg.arg1 != 0); + } + break; + case MSG_SUBS_CHANGED: + for (SignalCallback signalCluster : mSignalCallbacks) { + signalCluster.setSubs((List<SubscriptionInfo>) msg.obj); + } + break; + case MSG_NO_SIM_VISIBLE_CHANGED: + for (SignalCallback signalCluster : mSignalCallbacks) { + signalCluster.setNoSims(msg.arg1 != 0); + } + break; + case MSG_ETHERNET_CHANGED: + for (SignalCallback signalCluster : mSignalCallbacks) { + signalCluster.setEthernetIndicators((IconState) msg.obj); + } + break; + case MSG_AIRPLANE_MODE_CHANGED: + for (SignalCallback signalCluster : mSignalCallbacks) { + signalCluster.setIsAirplaneMode((IconState) msg.obj); + } + break; + case MSG_MOBILE_DATA_ENABLED_CHANGED: + for (SignalCallback signalCluster : mSignalCallbacks) { + signalCluster.setMobileDataEnabled(msg.arg1 != 0); + } + break; + case MSG_ADD_REMOVE_EMERGENCY: + if (msg.arg1 != 0) { + mEmergencyListeners.add((EmergencyListener) msg.obj); + } else { + mEmergencyListeners.remove((EmergencyListener) msg.obj); + } + break; + case MSG_ADD_REMOVE_SIGNAL: + if (msg.arg1 != 0) { + mSignalCallbacks.add((SignalCallback) msg.obj); + } else { + mSignalCallbacks.remove((SignalCallback) msg.obj); + } + break; + } + } + + @Override + public void setWifiIndicators(final boolean enabled, final IconState statusIcon, + final IconState qsIcon, final boolean activityIn, final boolean activityOut, + final String description) { + post(new Runnable() { + @Override + public void run() { + for (SignalCallback callback : mSignalCallbacks) { + callback.setWifiIndicators(enabled, statusIcon, qsIcon, activityIn, activityOut, + description); + } + } + }); + } + + @Override + public void setMobileDataIndicators(final IconState statusIcon, final IconState qsIcon, + final int darkStatusIcon, final int statusType, final int qsType, + final boolean activityIn, final boolean activityOut, + final String typeContentDescription, final String description, final boolean isWide, + final int subId) { + post(new Runnable() { + @Override + public void run() { + for (SignalCallback signalCluster : mSignalCallbacks) { + signalCluster.setMobileDataIndicators(statusIcon, qsIcon, darkStatusIcon, + statusType, qsType, activityIn, activityOut, typeContentDescription, + description, isWide, subId); + } + } + }); + } + + @Override + public void setSubs(List<SubscriptionInfo> subs) { + obtainMessage(MSG_SUBS_CHANGED, subs).sendToTarget(); + } + + @Override + public void setNoSims(boolean show) { + obtainMessage(MSG_NO_SIM_VISIBLE_CHANGED, show ? 1 : 0, 0).sendToTarget(); + } + + @Override + public void setMobileDataEnabled(boolean enabled) { + obtainMessage(MSG_MOBILE_DATA_ENABLED_CHANGED, enabled ? 1 : 0, 0).sendToTarget(); + } + + @Override + public void setEmergencyCallsOnly(boolean emergencyOnly) { + obtainMessage(MSG_EMERGENCE_CHANGED, emergencyOnly ? 1 : 0, 0).sendToTarget(); + } + + @Override + public void setEthernetIndicators(IconState icon) { + obtainMessage(MSG_ETHERNET_CHANGED, icon).sendToTarget();; + } + + @Override + public void setIsAirplaneMode(IconState icon) { + obtainMessage(MSG_AIRPLANE_MODE_CHANGED, icon).sendToTarget();; + } + + public void setListening(EmergencyListener listener, boolean listening) { + obtainMessage(MSG_ADD_REMOVE_EMERGENCY, listening ? 1 : 0, 0, listener).sendToTarget(); + } + + public void setListening(SignalCallback listener, boolean listening) { + obtainMessage(MSG_ADD_REMOVE_SIGNAL, listening ? 1 : 0, 0, listener).sendToTarget(); + } + +} diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/EthernetSignalController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/EthernetSignalController.java index 9c044c4..bd36462 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/EthernetSignalController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/EthernetSignalController.java @@ -18,22 +18,18 @@ package com.android.systemui.statusbar.policy; import android.content.Context; import android.net.NetworkCapabilities; -import com.android.internal.annotations.VisibleForTesting; -import com.android.systemui.statusbar.policy.NetworkController.NetworkSignalChangedCallback; -import com.android.systemui.statusbar.policy.NetworkControllerImpl.SignalCluster; +import com.android.systemui.statusbar.policy.NetworkController.IconState; -import java.util.List; -import java.util.Objects; +import java.util.BitSet; public class EthernetSignalController extends SignalController<SignalController.State, SignalController.IconGroup> { public EthernetSignalController(Context context, - List<NetworkSignalChangedCallback> signalCallbacks, - List<SignalCluster> signalClusters, NetworkControllerImpl networkController) { + CallbackHandler callbackHandler, NetworkControllerImpl networkController) { super("EthernetSignalController", context, NetworkCapabilities.TRANSPORT_ETHERNET, - signalCallbacks, signalClusters, networkController); + callbackHandler, networkController); mCurrentState.iconGroup = mLastState.iconGroup = new IconGroup( "Ethernet Icons", EthernetIcons.ETHERNET_ICONS, @@ -44,25 +40,23 @@ public class EthernetSignalController extends } @Override + public void updateConnectivity(BitSet connectedTransports, BitSet validatedTransports) { + mCurrentState.connected = connectedTransports.get(mTransportType); + super.updateConnectivity(connectedTransports, validatedTransports); + } + + @Override public void notifyListeners() { boolean ethernetVisible = mCurrentState.connected; String contentDescription = getStringIfExists(getContentDescription()); // TODO: wire up data transfer using WifiSignalPoller. - int signalClustersLength = mSignalClusters.size(); - for (int i = 0; i < signalClustersLength; i++) { - mSignalClusters.get(i).setEthernetIndicators(ethernetVisible, getCurrentIconId(), - contentDescription); - } + mCallbackHandler.setEthernetIndicators(new IconState(ethernetVisible, getCurrentIconId(), + contentDescription)); } @Override public SignalController.State cleanState() { return new SignalController.State(); } - - public void setConnected(boolean connected) { - mCurrentState.connected = connected; - notifyListenersIfNecessary(); - } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java index 22bf47c..0d59953 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java @@ -18,6 +18,7 @@ package com.android.systemui.statusbar.policy; import android.content.Context; import android.content.Intent; import android.net.NetworkCapabilities; +import android.os.Looper; import android.telephony.PhoneStateListener; import android.telephony.ServiceState; import android.telephony.SignalStrength; @@ -31,12 +32,11 @@ import com.android.internal.annotations.VisibleForTesting; import com.android.internal.telephony.TelephonyIntents; import com.android.internal.telephony.cdma.EriInfo; import com.android.systemui.R; -import com.android.systemui.statusbar.policy.NetworkController.NetworkSignalChangedCallback; +import com.android.systemui.statusbar.policy.NetworkController.IconState; import com.android.systemui.statusbar.policy.NetworkControllerImpl.Config; -import com.android.systemui.statusbar.policy.NetworkControllerImpl.SignalCluster; import java.io.PrintWriter; -import java.util.List; +import java.util.BitSet; import java.util.Objects; @@ -66,17 +66,17 @@ public class MobileSignalController extends SignalController< // TODO: Reduce number of vars passed in, if we have the NetworkController, probably don't // need listener lists anymore. public MobileSignalController(Context context, Config config, boolean hasMobileData, - TelephonyManager phone, List<NetworkSignalChangedCallback> signalCallbacks, - List<SignalCluster> signalClusters, NetworkControllerImpl networkController, - SubscriptionInfo info) { + TelephonyManager phone, CallbackHandler callbackHandler, + NetworkControllerImpl networkController, SubscriptionInfo info, Looper receiverLooper) { super("MobileSignalController(" + info.getSubscriptionId() + ")", context, - NetworkCapabilities.TRANSPORT_CELLULAR, signalCallbacks, signalClusters, + NetworkCapabilities.TRANSPORT_CELLULAR, callbackHandler, networkController); mNetworkToIconLookup = new SparseArray<>(); mConfig = config; mPhone = phone; mSubscriptionInfo = info; - mPhoneStateListener = new MobilePhoneStateListener(info.getSubscriptionId()); + mPhoneStateListener = new MobilePhoneStateListener(info.getSubscriptionId(), + receiverLooper); mNetworkNameSeparator = getStringIfExists(R.string.status_bar_network_name_separator); mNetworkNameDefault = getStringIfExists( com.android.internal.R.string.lockscreen_carrier_default); @@ -106,13 +106,13 @@ public class MobileSignalController extends SignalController< notifyListenersIfNecessary(); } - public void setInetCondition(int inetCondition, int inetConditionForNetwork) { - // For mobile data, use general inet condition for phone signal indexing, - // and network specific for data indexing (I think this might be a bug, but - // keeping for now). - // TODO: Update with explanation of why. - mCurrentState.inetForNetwork = inetConditionForNetwork; - setInetCondition(inetCondition); + @Override + public void updateConnectivity(BitSet connectedTransports, BitSet validatedTransports) { + boolean isValidated = validatedTransports.get(mTransportType); + mCurrentState.isDefault = connectedTransports.get(mTransportType); + // Only show this as not having connectivity if we are default. + mCurrentState.inetCondition = (isValidated || !mCurrentState.isDefault) ? 1 : 0; + notifyListenersIfNecessary(); } public void setCarrierNetworkChangeMode(boolean carrierNetworkChangeMode) { @@ -196,44 +196,33 @@ public class MobileSignalController extends SignalController< String contentDescription = getStringIfExists(getContentDescription()); String dataContentDescription = getStringIfExists(icons.mDataContentDescription); - boolean showDataIcon = mCurrentState.dataConnected && mCurrentState.inetForNetwork != 0 + // Show icon in QS when we are connected or need to show roaming. + boolean showDataIcon = mCurrentState.dataConnected || mCurrentState.iconGroup == TelephonyIcons.ROAMING; + IconState statusIcon = new IconState(mCurrentState.enabled && !mCurrentState.airplaneMode, + getCurrentIconId(), contentDescription); + int qsTypeIcon = 0; + IconState qsIcon = null; + String description = null; // Only send data sim callbacks to QS. if (mCurrentState.dataSim) { - int qsTypeIcon = showDataIcon ? icons.mQsDataType[mCurrentState.inetForNetwork] : 0; - int length = mSignalsChangedCallbacks.size(); - for (int i = 0; i < length; i++) { - mSignalsChangedCallbacks.get(i).onMobileDataSignalChanged(mCurrentState.enabled - && !mCurrentState.isEmergency, - getQsCurrentIconId(), contentDescription, - qsTypeIcon, - mCurrentState.dataConnected - && !mCurrentState.carrierNetworkChangeMode - && mCurrentState.activityIn, - mCurrentState.dataConnected - && !mCurrentState.carrierNetworkChangeMode - && mCurrentState.activityOut, - dataContentDescription, - mCurrentState.isEmergency ? null : mCurrentState.networkName, - // Only wide if actually showing something. - icons.mIsWide && qsTypeIcon != 0); - } - } + qsTypeIcon = showDataIcon ? icons.mQsDataType : 0; + qsIcon = new IconState(mCurrentState.enabled + && !mCurrentState.isEmergency, getQsCurrentIconId(), contentDescription); + description = mCurrentState.isEmergency ? null : mCurrentState.networkName; + } + boolean activityIn = mCurrentState.dataConnected + && !mCurrentState.carrierNetworkChangeMode + && mCurrentState.activityIn; + boolean activityOut = mCurrentState.dataConnected + && !mCurrentState.carrierNetworkChangeMode + && mCurrentState.activityOut; + showDataIcon &= mCurrentState.isDefault; int typeIcon = showDataIcon ? icons.mDataType : 0; - int signalClustersLength = mSignalClusters.size(); - for (int i = 0; i < signalClustersLength; i++) { - mSignalClusters.get(i).setMobileDataIndicators( - mCurrentState.enabled && !mCurrentState.airplaneMode, - getCurrentIconId(), - getCurrentDarkIconId(), - typeIcon, - contentDescription, - dataContentDescription, - // Only wide if actually showing something. - icons.mIsWide && typeIcon != 0, - mSubscriptionInfo.getSubscriptionId()); - } + mCallbackHandler.setMobileDataIndicators(statusIcon, qsIcon, getCurrentDarkIconId(), + typeIcon, qsTypeIcon, activityIn, activityOut, dataContentDescription, description, + icons.mIsWide, mSubscriptionInfo.getSubscriptionId()); } private int getCurrentDarkIconId() { @@ -425,8 +414,8 @@ public class MobileSignalController extends SignalController< } class MobilePhoneStateListener extends PhoneStateListener { - public MobilePhoneStateListener(int subId) { - super(subId); + public MobilePhoneStateListener(int subId, Looper looper) { + super(subId, looper); } @Override @@ -483,12 +472,12 @@ public class MobileSignalController extends SignalController< final int mDataContentDescription; // mContentDescriptionDataType final int mDataType; final boolean mIsWide; - final int[] mQsDataType; + final int mQsDataType; public MobileIconGroup(String name, int[][] sbIcons, int[][] qsIcons, int[] contentDesc, int sbNullState, int qsNullState, int sbDiscState, int qsDiscState, int discContentDesc, int dataContentDesc, int dataType, boolean isWide, - int[] qsDataType) { + int qsDataType) { this(name, sbIcons, sbIcons, qsIcons, contentDesc, sbNullState, qsNullState, sbDiscState, sbDiscState, qsDiscState, discContentDesc, dataContentDesc, dataType, isWide, qsDataType); @@ -497,7 +486,7 @@ public class MobileSignalController extends SignalController< public MobileIconGroup(String name, int[][] sbIcons, int[][] sbDarkIcons, int[][] qsIcons, int[] contentDesc, int sbNullState, int qsNullState, int sbDiscState, int sbDarkDiscState, int qsDiscState, int discContentDesc, int dataContentDesc, - int dataType, boolean isWide, int[] qsDataType) { + int dataType, boolean isWide, int qsDataType) { super(name, sbIcons, sbDarkIcons, qsIcons, contentDesc, sbNullState, qsNullState, sbDiscState, sbDarkDiscState, qsDiscState, discContentDesc); mDataContentDescription = dataContentDesc; @@ -515,7 +504,7 @@ public class MobileSignalController extends SignalController< boolean isEmergency; boolean airplaneMode; boolean carrierNetworkChangeMode; - int inetForNetwork; + boolean isDefault; @Override public void copyFrom(State s) { @@ -525,7 +514,7 @@ public class MobileSignalController extends SignalController< networkName = state.networkName; networkNameData = state.networkNameData; dataConnected = state.dataConnected; - inetForNetwork = state.inetForNetwork; + isDefault = state.isDefault; isEmergency = state.isEmergency; airplaneMode = state.airplaneMode; carrierNetworkChangeMode = state.carrierNetworkChangeMode; @@ -539,7 +528,7 @@ public class MobileSignalController extends SignalController< builder.append("networkName=").append(networkName).append(','); builder.append("networkNameData=").append(networkNameData).append(','); builder.append("dataConnected=").append(dataConnected).append(','); - builder.append("inetForNetwork=").append(inetForNetwork).append(','); + builder.append("isDefault=").append(isDefault).append(','); builder.append("isEmergency=").append(isEmergency).append(','); builder.append("airplaneMode=").append(airplaneMode).append(','); builder.append("carrierNetworkChangeMode=").append(carrierNetworkChangeMode); @@ -555,7 +544,7 @@ public class MobileSignalController extends SignalController< && ((MobileState) o).isEmergency == isEmergency && ((MobileState) o).airplaneMode == airplaneMode && ((MobileState) o).carrierNetworkChangeMode == carrierNetworkChangeMode - && ((MobileState) o).inetForNetwork == inetForNetwork; + && ((MobileState) o).isDefault == isDefault; } } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkController.java index 9212837..070ca63 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkController.java @@ -16,7 +16,9 @@ package com.android.systemui.statusbar.policy; +import android.content.Context; import android.content.Intent; +import android.telephony.SubscriptionInfo; import com.android.settingslib.wifi.AccessPoint; @@ -25,25 +27,45 @@ import java.util.List; public interface NetworkController { boolean hasMobileDataFeature(); - void addNetworkSignalChangedCallback(NetworkSignalChangedCallback cb); - void removeNetworkSignalChangedCallback(NetworkSignalChangedCallback cb); + void addSignalCallback(SignalCallback cb); + void removeSignalCallback(SignalCallback cb); void setWifiEnabled(boolean enabled); void onUserSwitched(int newUserId); AccessPointController getAccessPointController(); MobileDataController getMobileDataController(); - public interface NetworkSignalChangedCallback { - void onWifiSignalChanged(boolean enabled, boolean connected, int wifiSignalIconId, - boolean activityIn, boolean activityOut, - String wifiSignalContentDescriptionId, String description); - void onMobileDataSignalChanged(boolean enabled, int mobileSignalIconId, - String mobileSignalContentDescriptionId, int dataTypeIconId, - boolean activityIn, boolean activityOut, - String dataTypeContentDescriptionId, String description, - boolean isDataTypeIconWide); - void onNoSimVisibleChanged(boolean visible); - void onAirplaneModeChanged(boolean enabled); - void onMobileDataEnabled(boolean enabled); + public interface SignalCallback { + void setWifiIndicators(boolean enabled, IconState statusIcon, IconState qsIcon, + boolean activityIn, boolean activityOut, String description); + + void setMobileDataIndicators(IconState statusIcon, IconState qsIcon, int darkStatusIcon, + int statusType, int qsType, boolean activityIn, boolean activityOut, + String typeContentDescription, String description, boolean isWide, int subId); + void setSubs(List<SubscriptionInfo> subs); + void setNoSims(boolean show); + + void setEthernetIndicators(IconState icon); + + void setIsAirplaneMode(IconState icon); + + void setMobileDataEnabled(boolean enabled); + } + + public static class IconState { + public final boolean visible; + public final int icon; + public final String contentDescription; + + public IconState(boolean visible, int icon, String contentDescription) { + this.visible = visible; + this.icon = icon; + this.contentDescription = contentDescription; + } + + public IconState(boolean visible, int icon, int contentDescription, + Context context) { + this(visible, icon, context.getString(contentDescription)); + } } /** diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java index 92e0365..e8957f9 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java @@ -28,6 +28,7 @@ import android.net.NetworkCapabilities; import android.net.wifi.WifiManager; import android.os.AsyncTask; import android.os.Bundle; +import android.os.Handler; import android.os.Looper; import android.provider.Settings; import android.telephony.SubscriptionInfo; @@ -36,6 +37,7 @@ import android.telephony.SubscriptionManager.OnSubscriptionsChangedListener; import android.telephony.TelephonyManager; import android.text.TextUtils; import android.util.Log; +import android.util.MathUtils; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.telephony.PhoneConstants; @@ -61,7 +63,7 @@ public class NetworkControllerImpl extends BroadcastReceiver static final String TAG = "NetworkController"; static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG); // additional diagnostics, but not logspew - static final boolean CHATTY = Log.isLoggable(TAG + ".Chat", Log.DEBUG); + static final boolean CHATTY = Log.isLoggable(TAG + "Chat", Log.DEBUG); private final Context mContext; private final TelephonyManager mPhone; @@ -99,20 +101,19 @@ public class NetworkControllerImpl extends BroadcastReceiver private boolean mHasNoSims; private Locale mLocale = null; // This list holds our ordering. - private List<SubscriptionInfo> mCurrentSubscriptions - = new ArrayList<SubscriptionInfo>(); - - // All the callbacks. - private ArrayList<EmergencyListener> mEmergencyListeners = new ArrayList<EmergencyListener>(); - private ArrayList<SignalCluster> mSignalClusters = new ArrayList<SignalCluster>(); - private ArrayList<NetworkSignalChangedCallback> mSignalsChangedCallbacks = - new ArrayList<NetworkSignalChangedCallback>(); + private List<SubscriptionInfo> mCurrentSubscriptions = new ArrayList<>(); + @VisibleForTesting boolean mListening; // The current user ID. private int mCurrentUserId; + // Handler that all broadcasts are received on. + private final Handler mReceiverHandler; + // Handler that all callbacks are made on. + private final CallbackHandler mCallbackHandler; + /** * Construct this controller object and register for updates. */ @@ -120,20 +121,24 @@ public class NetworkControllerImpl extends BroadcastReceiver this(context, (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE), (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE), (WifiManager) context.getSystemService(Context.WIFI_SERVICE), - SubscriptionManager.from(context), Config.readConfig(context), + SubscriptionManager.from(context), Config.readConfig(context), bgLooper, + new CallbackHandler(), new AccessPointControllerImpl(context, bgLooper), new MobileDataControllerImpl(context)); - registerListeners(); + mReceiverHandler.post(mRegisterListeners); } @VisibleForTesting NetworkControllerImpl(Context context, ConnectivityManager connectivityManager, TelephonyManager telephonyManager, WifiManager wifiManager, - SubscriptionManager subManager, Config config, + SubscriptionManager subManager, Config config, Looper bgLooper, + CallbackHandler callbackHandler, AccessPointControllerImpl accessPointController, MobileDataControllerImpl mobileDataController) { mContext = context; mConfig = config; + mReceiverHandler = new Handler(bgLooper); + mCallbackHandler = callbackHandler; mSubscriptionManager = subManager; mConnectivityManager = connectivityManager; @@ -141,7 +146,7 @@ public class NetworkControllerImpl extends BroadcastReceiver mConnectivityManager.isNetworkSupported(ConnectivityManager.TYPE_MOBILE); // telephony - mPhone = (TelephonyManager) mContext.getSystemService(Context.TELEPHONY_SERVICE); + mPhone = telephonyManager; // wifi mWifiManager = wifiManager; @@ -154,14 +159,13 @@ public class NetworkControllerImpl extends BroadcastReceiver mMobileDataController.setCallback(new MobileDataControllerImpl.Callback() { @Override public void onMobileDataEnabled(boolean enabled) { - notifyMobileDataEnabled(enabled); + mCallbackHandler.setMobileDataEnabled(enabled); } }); mWifiSignalController = new WifiSignalController(mContext, mHasMobileDataFeature, - mSignalsChangedCallbacks, mSignalClusters, this); + mCallbackHandler, this); - mEthernetSignalController = new EthernetSignalController(mContext, mSignalsChangedCallbacks, - mSignalClusters, this); + mEthernetSignalController = new EthernetSignalController(mContext, mCallbackHandler, this); // AIRPLANE_MODE_CHANGED is sent at boot; we've probably already missed it updateAirplaneMode(true /* force callback */); @@ -186,7 +190,7 @@ public class NetworkControllerImpl extends BroadcastReceiver filter.addAction(ConnectivityManager.INET_CONDITION_ACTION); filter.addAction(Intent.ACTION_CONFIGURATION_CHANGED); filter.addAction(Intent.ACTION_AIRPLANE_MODE_CHANGED); - mContext.registerReceiver(this, filter); + mContext.registerReceiver(this, filter, null, mReceiverHandler); mListening = true; updateMobileControllers(); @@ -216,15 +220,8 @@ public class NetworkControllerImpl extends BroadcastReceiver } public void addEmergencyListener(EmergencyListener listener) { - mEmergencyListeners.add(listener); - listener.setEmergencyCallsOnly(isEmergencyOnly()); - } - - private void notifyMobileDataEnabled(boolean enabled) { - final int length = mSignalsChangedCallbacks.size(); - for (int i = 0; i < length; i++) { - mSignalsChangedCallbacks.get(i).onMobileDataEnabled(enabled); - } + mCallbackHandler.setListening(listener, true); + mCallbackHandler.setEmergencyCallsOnly(isEmergencyOnly()); } public boolean hasMobileDataFeature() { @@ -276,19 +273,15 @@ public class NetworkControllerImpl extends BroadcastReceiver * so we should recheck and send out the state to listeners. */ void recalculateEmergency() { - final boolean emergencyOnly = isEmergencyOnly(); - final int length = mEmergencyListeners.size(); - for (int i = 0; i < length; i++) { - mEmergencyListeners.get(i).setEmergencyCallsOnly(emergencyOnly); - } + mCallbackHandler.setEmergencyCallsOnly(isEmergencyOnly()); } - public void addSignalCluster(SignalCluster cluster) { - mSignalClusters.add(cluster); - cluster.setSubs(mCurrentSubscriptions); - cluster.setIsAirplaneMode(mAirplaneMode, TelephonyIcons.FLIGHT_MODE_ICON, - R.string.accessibility_airplane_mode); - cluster.setNoSims(mHasNoSims); + public void addSignalCallback(SignalCallback cb) { + mCallbackHandler.setListening(cb, true); + mCallbackHandler.setSubs(mCurrentSubscriptions); + mCallbackHandler.setIsAirplaneMode(new IconState(mAirplaneMode, + TelephonyIcons.FLIGHT_MODE_ICON, R.string.accessibility_airplane_mode, mContext)); + mCallbackHandler.setNoSims(mHasNoSims); mWifiSignalController.notifyListeners(); mEthernetSignalController.notifyListeners(); for (MobileSignalController mobileSignalController : mMobileSignalControllers.values()) { @@ -296,19 +289,9 @@ public class NetworkControllerImpl extends BroadcastReceiver } } - public void addNetworkSignalChangedCallback(NetworkSignalChangedCallback cb) { - mSignalsChangedCallbacks.add(cb); - cb.onAirplaneModeChanged(mAirplaneMode); - cb.onNoSimVisibleChanged(mHasNoSims); - mWifiSignalController.notifyListeners(); - mEthernetSignalController.notifyListeners(); - for (MobileSignalController mobileSignalController : mMobileSignalControllers.values()) { - mobileSignalController.notifyListeners(); - } - } - - public void removeNetworkSignalChangedCallback(NetworkSignalChangedCallback cb) { - mSignalsChangedCallbacks.remove(cb); + @Override + public void removeSignalCallback(SignalCallback cb) { + mCallbackHandler.setListening(cb, false); } @Override @@ -427,10 +410,7 @@ public class NetworkControllerImpl extends BroadcastReceiver : lhs.getSimSlotIndex() - rhs.getSimSlotIndex(); } }); - final int length = mSignalClusters.size(); - for (int i = 0; i < length; i++) { - mSignalClusters.get(i).setSubs(subscriptions); - } + mCallbackHandler.setSubs(subscriptions); mCurrentSubscriptions = subscriptions; HashMap<Integer, MobileSignalController> cachedControllers = @@ -444,8 +424,8 @@ public class NetworkControllerImpl extends BroadcastReceiver mMobileSignalControllers.put(subId, cachedControllers.remove(subId)); } else { MobileSignalController controller = new MobileSignalController(mContext, mConfig, - mHasMobileDataFeature, mPhone, mSignalsChangedCallbacks, mSignalClusters, - this, subscriptions.get(i)); + mHasMobileDataFeature, mPhone, mCallbackHandler, + this, subscriptions.get(i), mReceiverHandler.getLooper()); mMobileSignalControllers.put(subId, controller); if (subscriptions.get(i).getSimSlotIndex() == 0) { mDefaultSignalController = controller; @@ -521,17 +501,9 @@ public class NetworkControllerImpl extends BroadcastReceiver * notifyAllListeners. */ private void notifyListeners() { - int length = mSignalClusters.size(); - for (int i = 0; i < length; i++) { - mSignalClusters.get(i).setIsAirplaneMode(mAirplaneMode, TelephonyIcons.FLIGHT_MODE_ICON, - R.string.accessibility_airplane_mode); - mSignalClusters.get(i).setNoSims(mHasNoSims); - } - int signalsChangedLength = mSignalsChangedCallbacks.size(); - for (int i = 0; i < signalsChangedLength; i++) { - mSignalsChangedCallbacks.get(i).onAirplaneModeChanged(mAirplaneMode); - mSignalsChangedCallbacks.get(i).onNoSimVisibleChanged(mHasNoSims); - } + mCallbackHandler.setIsAirplaneMode(new IconState(mAirplaneMode, + TelephonyIcons.FLIGHT_MODE_ICON, R.string.accessibility_airplane_mode, mContext)); + mCallbackHandler.setNoSims(mHasNoSims); } /** @@ -566,17 +538,10 @@ public class NetworkControllerImpl extends BroadcastReceiver private void pushConnectivityToSignals() { // We want to update all the icons, all at once, for any condition change for (MobileSignalController mobileSignalController : mMobileSignalControllers.values()) { - mobileSignalController.setInetCondition( - mInetCondition ? 1 : 0, - mValidatedTransports.get(mobileSignalController.getTransportType()) ? 1 : 0); + mobileSignalController.updateConnectivity(mConnectedTransports, mValidatedTransports); } - mWifiSignalController.setInetCondition( - mValidatedTransports.get(mWifiSignalController.getTransportType()) ? 1 : 0); - - mEthernetSignalController.setConnected( - mConnectedTransports.get(mEthernetSignalController.getTransportType())); - mEthernetSignalController.setInetCondition( - mValidatedTransports.get(mEthernetSignalController.getTransportType()) ? 1 : 0); + mWifiSignalController.updateConnectivity(mConnectedTransports, mValidatedTransports); + mEthernetSignalController.updateConnectivity(mConnectedTransports, mValidatedTransports); } public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { @@ -609,7 +574,7 @@ public class NetworkControllerImpl extends BroadcastReceiver } private boolean mDemoMode; - private int mDemoInetCondition; + private boolean mDemoInetCondition; private WifiSignalController.WifiState mDemoWifiState; @Override @@ -618,7 +583,7 @@ public class NetworkControllerImpl extends BroadcastReceiver if (DEBUG) Log.d(TAG, "Entering demo mode"); unregisterListeners(); mDemoMode = true; - mDemoInetCondition = mInetCondition ? 1 : 0; + mDemoInetCondition = mInetCondition; mDemoWifiState = mWifiSignalController.getState(); } else if (mDemoMode && command.equals(COMMAND_EXIT)) { if (DEBUG) Log.d(TAG, "Exiting demo mode"); @@ -630,24 +595,30 @@ public class NetworkControllerImpl extends BroadcastReceiver controller.resetLastState(); } mWifiSignalController.resetLastState(); - registerListeners(); + mReceiverHandler.post(mRegisterListeners); notifyAllListeners(); } else if (mDemoMode && command.equals(COMMAND_NETWORK)) { String airplane = args.getString("airplane"); if (airplane != null) { boolean show = airplane.equals("show"); - int length = mSignalClusters.size(); - for (int i = 0; i < length; i++) { - mSignalClusters.get(i).setIsAirplaneMode(show, TelephonyIcons.FLIGHT_MODE_ICON, - R.string.accessibility_airplane_mode); - } + mCallbackHandler.setIsAirplaneMode(new IconState(show, + TelephonyIcons.FLIGHT_MODE_ICON, R.string.accessibility_airplane_mode, + mContext)); } String fully = args.getString("fully"); if (fully != null) { - mDemoInetCondition = Boolean.parseBoolean(fully) ? 1 : 0; - mWifiSignalController.setInetCondition(mDemoInetCondition); + mDemoInetCondition = Boolean.parseBoolean(fully); + BitSet connected = new BitSet(); + + if (mDemoInetCondition) { + connected.set(mWifiSignalController.mTransportType); + } + mWifiSignalController.updateConnectivity(connected, connected); for (MobileSignalController controller : mMobileSignalControllers.values()) { - controller.setInetCondition(mDemoInetCondition, mDemoInetCondition); + if (mDemoInetCondition) { + connected.set(controller.mTransportType); + } + controller.updateConnectivity(connected, connected); } } String wifi = args.getString("wifi"); @@ -664,32 +635,21 @@ public class NetworkControllerImpl extends BroadcastReceiver } String sims = args.getString("sims"); if (sims != null) { - int num = Integer.parseInt(sims); - List<SubscriptionInfo> subs = new ArrayList<SubscriptionInfo>(); + int num = MathUtils.constrain(Integer.parseInt(sims), 1, 8); + List<SubscriptionInfo> subs = new ArrayList<>(); if (num != mMobileSignalControllers.size()) { mMobileSignalControllers.clear(); int start = mSubscriptionManager.getActiveSubscriptionInfoCountMax(); for (int i = start /* get out of normal index range */; i < start + num; i++) { - SubscriptionInfo info = new SubscriptionInfo(i, "", i, "", "", 0, 0, "", 0, - null, 0, 0, ""); - subs.add(info); - mMobileSignalControllers.put(i, new MobileSignalController(mContext, - mConfig, mHasMobileDataFeature, mPhone, mSignalsChangedCallbacks, - mSignalClusters, this, info)); + subs.add(addSignalController(i, i)); } } - final int n = mSignalClusters.size(); - for (int i = 0; i < n; i++) { - mSignalClusters.get(i).setSubs(subs); - } + mCallbackHandler.setSubs(subs); } String nosim = args.getString("nosim"); if (nosim != null) { boolean show = nosim.equals("show"); - final int n = mSignalClusters.size(); - for (int i = 0; i < n; i++) { - mSignalClusters.get(i).setNoSims(show); - } + mCallbackHandler.setNoSims(show); } String mobile = args.getString("mobile"); if (mobile != null) { @@ -697,6 +657,16 @@ public class NetworkControllerImpl extends BroadcastReceiver String datatype = args.getString("datatype"); String slotString = args.getString("slot"); int slot = TextUtils.isEmpty(slotString) ? 0 : Integer.parseInt(slotString); + slot = MathUtils.constrain(slot, 0, 8); + // Ensure we have enough sim slots + List<SubscriptionInfo> subs = new ArrayList<>(); + while (mMobileSignalControllers.size() <= slot) { + int nextSlot = mMobileSignalControllers.size(); + subs.add(addSignalController(nextSlot, nextSlot)); + } + if (!subs.isEmpty()) { + mCallbackHandler.setSubs(subs); + } // Hack to index linearly for easy use. MobileSignalController controller = mMobileSignalControllers .values().toArray(new MobileSignalController[0])[slot]; @@ -733,6 +703,15 @@ public class NetworkControllerImpl extends BroadcastReceiver } } + private SubscriptionInfo addSignalController(int id, int simSlotIndex) { + SubscriptionInfo info = new SubscriptionInfo(id, "", simSlotIndex, "", "", 0, 0, "", 0, + null, 0, 0, ""); + mMobileSignalControllers.put(id, new MobileSignalController(mContext, + mConfig, mHasMobileDataFeature, mPhone, mCallbackHandler, this, info, + mReceiverHandler.getLooper())); + return info; + } + private final OnSubscriptionsChangedListener mSubscriptionListener = new OnSubscriptionsChangedListener() { @Override @@ -741,28 +720,21 @@ public class NetworkControllerImpl extends BroadcastReceiver }; }; - public interface SignalCluster { - void setWifiIndicators(boolean visible, int strengthIcon, String contentDescription); - - void setMobileDataIndicators(boolean visible, int strengthIcon, int darkStrengthIcon, - int typeIcon, String contentDescription, String typeContentDescription, - boolean isTypeIconWide, int subId); - void setSubs(List<SubscriptionInfo> subs); - void setNoSims(boolean show); - - void setEthernetIndicators(boolean visible, int icon, String contentDescription); - - void setIsAirplaneMode(boolean is, int airplaneIcon, int contentDescription); - } + /** + * Used to register listeners from the BG Looper, this way the PhoneStateListeners that + * get created will also run on the BG Looper. + */ + private final Runnable mRegisterListeners = new Runnable() { + @Override + public void run() { + registerListeners(); + } + }; public interface EmergencyListener { void setEmergencyCallsOnly(boolean emergencyOnly); } - public interface CarrierLabelListener { - void setCarrierLabel(String label); - } - @VisibleForTesting static class Config { boolean showAtLeast3G = false; diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/SignalCallbackAdapter.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/SignalCallbackAdapter.java new file mode 100644 index 0000000..83a7d3d --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/SignalCallbackAdapter.java @@ -0,0 +1,64 @@ +/* + * Copyright (C) 2015 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.android.systemui.statusbar.policy; + +import android.telephony.SubscriptionInfo; + +import com.android.systemui.statusbar.policy.NetworkController.IconState; +import com.android.systemui.statusbar.policy.NetworkController.SignalCallback; + +import java.util.List; + + +/** + * Provides empty implementations of SignalCallback for those that only want some of + * the callbacks. + */ +public class SignalCallbackAdapter implements SignalCallback { + + @Override + public void setWifiIndicators(boolean enabled, IconState statusIcon, IconState qsIcon, + boolean activityIn, boolean activityOut, String description) { + } + + @Override + public void setMobileDataIndicators(IconState statusIcon, IconState qsIcon, + int darkStatusIcon, int statusType, int qsType, boolean activityIn, + boolean activityOut, String typeContentDescription, String description, + boolean isWide, int subId) { + } + + @Override + public void setSubs(List<SubscriptionInfo> subs) { + } + + @Override + public void setNoSims(boolean show) { + } + + @Override + public void setEthernetIndicators(IconState icon) { + } + + @Override + public void setIsAirplaneMode(IconState icon) { + } + + @Override + public void setMobileDataEnabled(boolean enabled) { + } + +} diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/SignalController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/SignalController.java index f3322a1..e6ca646 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/SignalController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/SignalController.java @@ -21,11 +21,8 @@ import android.content.Context; import android.text.format.DateFormat; import android.util.Log; -import com.android.systemui.statusbar.policy.NetworkController.NetworkSignalChangedCallback; -import com.android.systemui.statusbar.policy.NetworkControllerImpl.SignalCluster; - import java.io.PrintWriter; -import java.util.List; +import java.util.BitSet; /** @@ -49,24 +46,22 @@ public abstract class SignalController<T extends SignalController.State, // The owner of the SignalController (i.e. NetworkController will maintain the following // lists and call notifyListeners whenever the list has changed to ensure everyone // is aware of current state. - protected final List<NetworkSignalChangedCallback> mSignalsChangedCallbacks; - protected final List<SignalCluster> mSignalClusters; protected final NetworkControllerImpl mNetworkController; + protected final CallbackHandler mCallbackHandler; + // Save the previous HISTORY_SIZE states for logging. private final State[] mHistory; // Where to copy the next state into. private int mHistoryIndex; - public SignalController(String tag, Context context, int type, - List<NetworkSignalChangedCallback> signalCallbacks, - List<SignalCluster> signalClusters, NetworkControllerImpl networkController) { + public SignalController(String tag, Context context, int type, CallbackHandler callbackHandler, + NetworkControllerImpl networkController) { mTag = TAG + "." + tag; mNetworkController = networkController; mTransportType = type; mContext = context; - mSignalsChangedCallbacks = signalCallbacks; - mSignalClusters = signalClusters; + mCallbackHandler = callbackHandler; mCurrentState = cleanState(); mLastState = cleanState(); if (RECORD_HISTORY) { @@ -81,12 +76,8 @@ public abstract class SignalController<T extends SignalController.State, return mCurrentState; } - public int getTransportType() { - return mTransportType; - } - - public void setInetCondition(int inetCondition) { - mCurrentState.inetCondition = inetCondition; + public void updateConnectivity(BitSet connectedTransports, BitSet validatedTransports) { + mCurrentState.inetCondition = validatedTransports.get(mTransportType) ? 1 : 0; notifyListenersIfNecessary(); } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/TelephonyIcons.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/TelephonyIcons.java index 053feb12..fa4d464 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/TelephonyIcons.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/TelephonyIcons.java @@ -104,10 +104,7 @@ class TelephonyIcons { R.drawable.ic_qs_signal_carrier_network_change_animation } }; - static final int[] QS_DATA_R = { - R.drawable.ic_qs_signal_r, - R.drawable.ic_qs_signal_r - }; + static final int QS_DATA_R = R.drawable.ic_qs_signal_r; //***** Data connection icons @@ -123,10 +120,7 @@ class TelephonyIcons { R.drawable.stat_sys_data_fully_connected_g } }; - static final int[] QS_DATA_G = { - R.drawable.ic_qs_signal_g, - R.drawable.ic_qs_signal_g - }; + static final int QS_DATA_G = R.drawable.ic_qs_signal_g; static final int[][] DATA_3G = { { R.drawable.stat_sys_data_fully_connected_3g, @@ -139,10 +133,7 @@ class TelephonyIcons { R.drawable.stat_sys_data_fully_connected_3g } }; - static final int[] QS_DATA_3G = { - R.drawable.ic_qs_signal_3g, - R.drawable.ic_qs_signal_3g - }; + static final int QS_DATA_3G = R.drawable.ic_qs_signal_3g; static final int[][] DATA_E = { { R.drawable.stat_sys_data_fully_connected_e, @@ -155,10 +146,7 @@ class TelephonyIcons { R.drawable.stat_sys_data_fully_connected_e } }; - static final int[] QS_DATA_E = { - R.drawable.ic_qs_signal_e, - R.drawable.ic_qs_signal_e - }; + static final int QS_DATA_E = R.drawable.ic_qs_signal_e; //3.5G static final int[][] DATA_H = { @@ -172,10 +160,7 @@ class TelephonyIcons { R.drawable.stat_sys_data_fully_connected_h } }; - static final int[] QS_DATA_H = { - R.drawable.ic_qs_signal_h, - R.drawable.ic_qs_signal_h - }; + static final int QS_DATA_H = R.drawable.ic_qs_signal_h; //CDMA // Use 3G icons for EVDO data and 1x icons for 1XRTT data @@ -190,10 +175,7 @@ class TelephonyIcons { R.drawable.stat_sys_data_fully_connected_1x } }; - static final int[] QS_DATA_1X = { - R.drawable.ic_qs_signal_1x, - R.drawable.ic_qs_signal_1x - }; + static final int QS_DATA_1X = R.drawable.ic_qs_signal_1x; // LTE and eHRPD static final int[][] DATA_4G = { @@ -207,10 +189,7 @@ class TelephonyIcons { R.drawable.stat_sys_data_fully_connected_4g } }; - static final int[] QS_DATA_4G = { - R.drawable.ic_qs_signal_4g, - R.drawable.ic_qs_signal_4g - }; + static final int QS_DATA_4G = R.drawable.ic_qs_signal_4g; // LTE branded "LTE" static final int[][] DATA_LTE = { @@ -224,10 +203,7 @@ class TelephonyIcons { R.drawable.stat_sys_data_fully_connected_lte } }; - static final int[] QS_DATA_LTE = { - R.drawable.ic_qs_signal_lte, - R.drawable.ic_qs_signal_lte - }; + static final int QS_DATA_LTE = R.drawable.ic_qs_signal_lte; static final int FLIGHT_MODE_ICON = R.drawable.stat_sys_airplane_mode; static final int ROAMING_ICON = R.drawable.stat_sys_data_fully_connected_roam; @@ -264,7 +240,7 @@ class TelephonyIcons { R.string.accessibility_carrier_network_change_mode, 0, false, - null + 0 ); static final MobileIconGroup THREE_G = new MobileIconGroup( @@ -291,7 +267,7 @@ class TelephonyIcons { TelephonyIcons.TELEPHONY_NO_NETWORK, TelephonyIcons.QS_TELEPHONY_NO_NETWORK, AccessibilityContentDescriptions.PHONE_SIGNAL_STRENGTH[0], - 0, 0, false, new int[2] + 0, 0, false, 0 ); static final MobileIconGroup E = new MobileIconGroup( diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/WifiSignalController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/WifiSignalController.java index a97ca50..9b1e72a 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/WifiSignalController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/WifiSignalController.java @@ -29,8 +29,7 @@ import android.util.Log; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.util.AsyncChannel; -import com.android.systemui.statusbar.policy.NetworkController.NetworkSignalChangedCallback; -import com.android.systemui.statusbar.policy.NetworkControllerImpl.SignalCluster; +import com.android.systemui.statusbar.policy.NetworkController.IconState; import java.util.List; import java.util.Objects; @@ -43,10 +42,9 @@ public class WifiSignalController extends private final boolean mHasMobileData; public WifiSignalController(Context context, boolean hasMobileData, - List<NetworkSignalChangedCallback> signalCallbacks, - List<SignalCluster> signalClusters, NetworkControllerImpl networkController) { + CallbackHandler callbackHandler, NetworkControllerImpl networkController) { super("WifiSignalController", context, NetworkCapabilities.TRANSPORT_WIFI, - signalCallbacks, signalClusters, networkController); + callbackHandler, networkController); mWifiManager = (WifiManager) context.getSystemService(Context.WIFI_SERVICE); mHasMobileData = hasMobileData; Handler handler = new WifiHandler(); @@ -82,19 +80,13 @@ public class WifiSignalController extends String wifiDesc = wifiVisible ? mCurrentState.ssid : null; boolean ssidPresent = wifiVisible && mCurrentState.ssid != null; String contentDescription = getStringIfExists(getContentDescription()); - int length = mSignalsChangedCallbacks.size(); - for (int i = 0; i < length; i++) { - mSignalsChangedCallbacks.get(i).onWifiSignalChanged(mCurrentState.enabled, - mCurrentState.connected, getQsCurrentIconId(), - ssidPresent && mCurrentState.activityIn, - ssidPresent && mCurrentState.activityOut, contentDescription, wifiDesc); - } - int signalClustersLength = mSignalClusters.size(); - for (int i = 0; i < signalClustersLength; i++) { - mSignalClusters.get(i).setWifiIndicators(wifiVisible, getCurrentIconId(), - contentDescription); - } + IconState statusIcon = new IconState(wifiVisible, getCurrentIconId(), contentDescription); + IconState qsIcon = new IconState(mCurrentState.connected, getQsCurrentIconId(), + contentDescription); + mCallbackHandler.setWifiIndicators(mCurrentState.enabled, statusIcon, qsIcon, + ssidPresent && mCurrentState.activityIn, ssidPresent && mCurrentState.activityOut, + wifiDesc); } /** diff --git a/packages/SystemUI/src/com/android/systemui/volume/ZenModePanel.java b/packages/SystemUI/src/com/android/systemui/volume/ZenModePanel.java index 8dfa9b0..ec24d75 100644 --- a/packages/SystemUI/src/com/android/systemui/volume/ZenModePanel.java +++ b/packages/SystemUI/src/com/android/systemui/volume/ZenModePanel.java @@ -23,6 +23,7 @@ import android.content.Context; import android.content.Intent; import android.content.SharedPreferences; import android.content.SharedPreferences.OnSharedPreferenceChangeListener; +import android.content.res.Configuration; import android.net.Uri; import android.os.AsyncTask; import android.os.Handler; @@ -175,7 +176,14 @@ public class ZenModePanel extends LinearLayout { }); mZenConditions = (LinearLayout) findViewById(R.id.zen_conditions); + } + @Override + protected void onConfigurationChanged(Configuration newConfig) { + super.onConfigurationChanged(newConfig); + if (mZenButtons != null) { + mZenButtons.updateLocale(); + } } private void confirmZenIntroduction() { diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/CallbackHandlerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/CallbackHandlerTest.java new file mode 100644 index 0000000..c14d06f --- /dev/null +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/CallbackHandlerTest.java @@ -0,0 +1,187 @@ +/* + * Copyright (C) 2015 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.android.systemui.statusbar.policy; + +import android.os.HandlerThread; +import android.telephony.SubscriptionInfo; +import android.test.AndroidTestCase; + +import com.android.systemui.R; +import com.android.systemui.statusbar.policy.NetworkController.IconState; +import com.android.systemui.statusbar.policy.NetworkController.SignalCallback; +import com.android.systemui.statusbar.policy.NetworkControllerImpl.EmergencyListener; + +import org.mockito.ArgumentCaptor; +import org.mockito.Mock; +import org.mockito.Mockito; +import org.mockito.MockitoAnnotations; + +import java.util.ArrayList; +import java.util.List; + +public class CallbackHandlerTest extends AndroidTestCase { + + private CallbackHandler mHandler; + private HandlerThread mHandlerThread; + + @Mock + private EmergencyListener mEmengencyListener; + @Mock + private SignalCallback mSignalCallback; + + @Override + protected void setUp() throws Exception { + super.setUp(); + + mHandlerThread = new HandlerThread("TestThread"); + mHandlerThread.start(); + mHandler = new CallbackHandler(mHandlerThread.getLooper()); + + MockitoAnnotations.initMocks(this); + mHandler.setListening(mEmengencyListener, true); + mHandler.setListening(mSignalCallback, true); + } + + public void testEmergencyListener() { + mHandler.setEmergencyCallsOnly(true); + waitForCallbacks(); + + ArgumentCaptor<Boolean> captor = ArgumentCaptor.forClass(Boolean.class); + Mockito.verify(mEmengencyListener).setEmergencyCallsOnly(captor.capture()); + assertTrue(captor.getValue()); + } + + public void testSignalCallback_setWifiIndicators() { + boolean enabled = true; + IconState status = new IconState(true, 0, ""); + IconState qs = new IconState(true, 1, ""); + boolean in = true; + boolean out = true; + String description = "Test"; + mHandler.setWifiIndicators(enabled, status, qs, in, out, description); + waitForCallbacks(); + + ArgumentCaptor<Boolean> enableArg = ArgumentCaptor.forClass(Boolean.class); + ArgumentCaptor<IconState> statusArg = ArgumentCaptor.forClass(IconState.class); + ArgumentCaptor<IconState> qsArg = ArgumentCaptor.forClass(IconState.class); + ArgumentCaptor<Boolean> inArg = ArgumentCaptor.forClass(Boolean.class); + ArgumentCaptor<Boolean> outArg = ArgumentCaptor.forClass(Boolean.class); + ArgumentCaptor<String> descArg = ArgumentCaptor.forClass(String.class); + Mockito.verify(mSignalCallback).setWifiIndicators(enableArg.capture(), + statusArg.capture(), qsArg.capture(), inArg.capture(), outArg.capture(), + descArg.capture()); + assertEquals(enabled, (boolean) enableArg.getValue()); + assertEquals(status, statusArg.getValue()); + assertEquals(qs, qsArg.getValue()); + assertEquals(in, (boolean) inArg.getValue()); + assertEquals(out, (boolean) outArg.getValue()); + assertEquals(description, descArg.getValue()); + } + + public void testSignalCallback_setMobileDataIndicators() { + IconState status = new IconState(true, 0, ""); + IconState qs = new IconState(true, 1, ""); + int dark = 2; + boolean in = true; + boolean out = true; + String typeDescription = "Test 1"; + String description = "Test 2"; + int type = R.drawable.stat_sys_data_fully_connected_1x; + int qsType = R.drawable.ic_qs_signal_1x; + boolean wide = true; + int subId = 5; + mHandler.setMobileDataIndicators(status, qs, dark, type, qsType, in, out, typeDescription, + description, wide, subId); + waitForCallbacks(); + + ArgumentCaptor<IconState> statusArg = ArgumentCaptor.forClass(IconState.class); + ArgumentCaptor<IconState> qsArg = ArgumentCaptor.forClass(IconState.class); + ArgumentCaptor<Integer> darkStrengthArg = ArgumentCaptor.forClass(Integer.class); + ArgumentCaptor<Integer> typeIconArg = ArgumentCaptor.forClass(Integer.class); + ArgumentCaptor<Integer> qsTypeIconArg = ArgumentCaptor.forClass(Integer.class); + ArgumentCaptor<Boolean> inArg = ArgumentCaptor.forClass(Boolean.class); + ArgumentCaptor<Boolean> outArg = ArgumentCaptor.forClass(Boolean.class); + ArgumentCaptor<String> typeContentArg = ArgumentCaptor.forClass(String.class); + ArgumentCaptor<String> descArg = ArgumentCaptor.forClass(String.class); + ArgumentCaptor<Boolean> wideArg = ArgumentCaptor.forClass(Boolean.class); + ArgumentCaptor<Integer> subIdArg = ArgumentCaptor.forClass(Integer.class); + Mockito.verify(mSignalCallback).setMobileDataIndicators(statusArg.capture(), qsArg.capture(), + darkStrengthArg.capture(), typeIconArg.capture(), qsTypeIconArg.capture(), + inArg.capture(), outArg.capture(), typeContentArg.capture(), descArg.capture(), + wideArg.capture(), subIdArg.capture()); + assertEquals(status, statusArg.getValue()); + assertEquals(qs, qsArg.getValue()); + assertEquals(dark, (int) darkStrengthArg.getValue()); + assertEquals(type, (int) typeIconArg.getValue()); + assertEquals(qsType, (int) qsTypeIconArg.getValue()); + assertEquals(in, (boolean) inArg.getValue()); + assertEquals(out, (boolean) outArg.getValue()); + assertEquals(typeDescription, typeContentArg.getValue()); + assertEquals(description, descArg.getValue()); + assertEquals(wide, (boolean) wideArg.getValue()); + assertEquals(subId, (int) subIdArg.getValue()); + } + + @SuppressWarnings("unchecked") + public void testSignalCallback_setSubs() { + List<SubscriptionInfo> subs = new ArrayList<>(); + mHandler.setSubs(subs); + waitForCallbacks(); + + ArgumentCaptor<ArrayList> subsArg = ArgumentCaptor.forClass(ArrayList.class); + Mockito.verify(mSignalCallback).setSubs(subsArg.capture()); + assertTrue(subs == subsArg.getValue()); + } + + public void testSignalCallback_setNoSims() { + boolean noSims = true; + mHandler.setNoSims(noSims); + waitForCallbacks(); + + ArgumentCaptor<Boolean> noSimsArg = ArgumentCaptor.forClass(Boolean.class); + Mockito.verify(mSignalCallback).setNoSims(noSimsArg.capture()); + assertEquals(noSims, (boolean) noSimsArg.getValue()); + } + + public void testSignalCallback_setEthernetIndicators() { + IconState state = new IconState(true, R.drawable.stat_sys_ethernet, "Test Description"); + mHandler.setEthernetIndicators(state); + waitForCallbacks(); + + ArgumentCaptor<IconState> iconArg = ArgumentCaptor.forClass(IconState.class); + Mockito.verify(mSignalCallback).setEthernetIndicators(iconArg.capture()); + assertEquals(state, iconArg.getValue()); + } + + public void testSignalCallback_setIsAirplaneMode() { + IconState state = new IconState(true, R.drawable.stat_sys_airplane_mode, "Test Description"); + mHandler.setIsAirplaneMode(state); + waitForCallbacks(); + + ArgumentCaptor<IconState> iconArg = ArgumentCaptor.forClass(IconState.class); + Mockito.verify(mSignalCallback).setIsAirplaneMode(iconArg.capture()); + assertEquals(state, iconArg.getValue()); + } + + private void waitForCallbacks() { + mHandlerThread.quitSafely(); + try { + mHandlerThread.join(); + } catch (InterruptedException e) { + } + } + +} diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerBaseTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerBaseTest.java index 29f461e..2d6bb68 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerBaseTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerBaseTest.java @@ -23,6 +23,7 @@ import android.content.Intent; import android.net.ConnectivityManager; import android.net.NetworkCapabilities; import android.net.wifi.WifiManager; +import android.os.Looper; import android.telephony.PhoneStateListener; import android.telephony.ServiceState; import android.telephony.SignalStrength; @@ -31,12 +32,10 @@ import android.telephony.SubscriptionManager; import android.telephony.TelephonyManager; import android.util.Log; -import com.android.internal.telephony.IccCardConstants; import com.android.internal.telephony.cdma.EriInfo; import com.android.systemui.SysuiTestCase; -import com.android.systemui.statusbar.policy.NetworkController.NetworkSignalChangedCallback; +import com.android.systemui.statusbar.policy.NetworkController.IconState; import com.android.systemui.statusbar.policy.NetworkControllerImpl.Config; -import com.android.systemui.statusbar.policy.NetworkControllerImpl.SignalCluster; import org.mockito.ArgumentCaptor; import org.mockito.Mockito; @@ -59,8 +58,6 @@ public class NetworkControllerBaseTest extends SysuiTestCase { protected NetworkControllerImpl mNetworkController; protected MobileSignalController mMobileSignalController; protected PhoneStateListener mPhoneStateListener; - protected SignalCluster mSignalCluster; - protected NetworkSignalChangedCallback mNetworkSignalChangedCallback; private SignalStrength mSignalStrength; private ServiceState mServiceState; protected ConnectivityManager mMockCm; @@ -68,6 +65,7 @@ public class NetworkControllerBaseTest extends SysuiTestCase { protected SubscriptionManager mMockSm; protected TelephonyManager mMockTm; protected Config mConfig; + protected CallbackHandler mCallbackHandler; protected int mSubId; @@ -91,33 +89,36 @@ public class NetworkControllerBaseTest extends SysuiTestCase { mConfig = new Config(); mConfig.hspaDataDistinguishable = true; + mCallbackHandler = mock(CallbackHandler.class); mNetworkController = new NetworkControllerImpl(mContext, mMockCm, mMockTm, mMockWm, mMockSm, - mConfig, mock(AccessPointControllerImpl.class), - mock(MobileDataControllerImpl.class)); + mConfig, Looper.getMainLooper(), mCallbackHandler, + mock(AccessPointControllerImpl.class), mock(MobileDataControllerImpl.class)); setupNetworkController(); } protected void setupNetworkController() { // For now just pretend to be the data sim, so we can test that too. - mSubId = SubscriptionManager.getDefaultDataSubId(); + mSubId = SubscriptionManager.DEFAULT_SUBSCRIPTION_ID; SubscriptionInfo subscription = mock(SubscriptionInfo.class); List<SubscriptionInfo> subs = new ArrayList<SubscriptionInfo>(); when(subscription.getSubscriptionId()).thenReturn(mSubId); subs.add(subscription); mNetworkController.setCurrentSubscriptions(subs); mMobileSignalController = mNetworkController.mMobileSignalControllers.get(mSubId); + mMobileSignalController.getState().dataSim = true; mPhoneStateListener = mMobileSignalController.mPhoneStateListener; - mSignalCluster = mock(SignalCluster.class); - mNetworkSignalChangedCallback = mock(NetworkSignalChangedCallback.class); - mNetworkController.addSignalCluster(mSignalCluster); - mNetworkController.addNetworkSignalChangedCallback(mNetworkSignalChangedCallback); + + // Trigger blank callbacks to always get the current state (some tests don't trigger + // changes from default state). + mNetworkController.addSignalCallback(null); } protected NetworkControllerImpl setUpNoMobileData() { when(mMockCm.isNetworkSupported(ConnectivityManager.TYPE_MOBILE)).thenReturn(false); NetworkControllerImpl networkControllerNoMobile = new NetworkControllerImpl(mContext, mMockCm, mMockTm, mMockWm, mMockSm, - mConfig, mock(AccessPointControllerImpl.class), + mConfig, Looper.getMainLooper(), mCallbackHandler, + mock(AccessPointControllerImpl.class), mock(MobileDataControllerImpl.class)); setupNetworkController(); @@ -144,10 +145,10 @@ public class NetworkControllerBaseTest extends SysuiTestCase { setLevel(DEFAULT_LEVEL); updateDataConnectionState(TelephonyManager.DATA_CONNECTED, TelephonyManager.NETWORK_TYPE_UMTS); - setConnectivity(100, ConnectivityManager.TYPE_MOBILE, true); + setConnectivity(NetworkCapabilities.TRANSPORT_CELLULAR, true, true); } - public void setConnectivity(int inetCondition, int networkType, boolean isConnected) { + public void setConnectivity(int networkType, boolean inetCondition, boolean isConnected) { Intent i = new Intent(ConnectivityManager.INET_CONDITION_ACTION); // TODO: Separate out into several NetworkCapabilities. if (isConnected) { @@ -155,7 +156,7 @@ public class NetworkControllerBaseTest extends SysuiTestCase { } else { mNetCapabilities.removeTransportType(networkType); } - if (inetCondition != 0) { + if (inetCondition) { mNetCapabilities.addCapability(NetworkCapabilities.NET_CAPABILITY_VALIDATED); } else { mNetCapabilities.removeCapability(NetworkCapabilities.NET_CAPABILITY_VALIDATED); @@ -242,34 +243,30 @@ public class NetworkControllerBaseTest extends SysuiTestCase { protected void verifyHasNoSims(boolean hasNoSimsVisible) { ArgumentCaptor<Boolean> hasNoSimsArg = ArgumentCaptor.forClass(Boolean.class); - Mockito.verify(mSignalCluster, Mockito.atLeastOnce()).setNoSims(hasNoSimsArg.capture()); - assertEquals("No sims in status bar", hasNoSimsVisible, (boolean) hasNoSimsArg.getValue()); - - Mockito.verify(mNetworkSignalChangedCallback, Mockito.atLeastOnce()) - .onNoSimVisibleChanged(hasNoSimsArg.capture()); - assertEquals("No sims in quick settings", hasNoSimsVisible, - (boolean) hasNoSimsArg.getValue()); + Mockito.verify(mCallbackHandler, Mockito.atLeastOnce()).setNoSims(hasNoSimsArg.capture()); + assertEquals("No sims", hasNoSimsVisible, (boolean) hasNoSimsArg.getValue()); } protected void verifyLastQsMobileDataIndicators(boolean visible, int icon, int typeIcon, boolean dataIn, boolean dataOut) { - ArgumentCaptor<Integer> iconArg = ArgumentCaptor.forClass(Integer.class); + ArgumentCaptor<IconState> iconArg = ArgumentCaptor.forClass(IconState.class); ArgumentCaptor<Integer> typeIconArg = ArgumentCaptor.forClass(Integer.class); - ArgumentCaptor<Boolean> visibleArg = ArgumentCaptor.forClass(Boolean.class); ArgumentCaptor<Boolean> dataInArg = ArgumentCaptor.forClass(Boolean.class); ArgumentCaptor<Boolean> dataOutArg = ArgumentCaptor.forClass(Boolean.class); - Mockito.verify(mNetworkSignalChangedCallback, Mockito.atLeastOnce()) - .onMobileDataSignalChanged(visibleArg.capture(), iconArg.capture(), - ArgumentCaptor.forClass(String.class).capture(), - typeIconArg.capture(), - dataInArg.capture(), - dataOutArg.capture(), - ArgumentCaptor.forClass(String.class).capture(), - ArgumentCaptor.forClass(String.class).capture(), - ArgumentCaptor.forClass(Boolean.class).capture()); - assertEquals("Visibility in, quick settings", visible, (boolean) visibleArg.getValue()); - assertEquals("Signal icon in, quick settings", icon, (int) iconArg.getValue()); + Mockito.verify(mCallbackHandler, Mockito.atLeastOnce()).setMobileDataIndicators( + ArgumentCaptor.forClass(IconState.class).capture(), + iconArg.capture(), + ArgumentCaptor.forClass(Integer.class).capture(), + ArgumentCaptor.forClass(Integer.class).capture(), + typeIconArg.capture(), dataInArg.capture(), dataOutArg.capture(), + ArgumentCaptor.forClass(String.class).capture(), + ArgumentCaptor.forClass(String.class).capture(), + ArgumentCaptor.forClass(Boolean.class).capture(), + ArgumentCaptor.forClass(Integer.class).capture()); + IconState iconState = iconArg.getValue(); + assertEquals("Visibility in, quick settings", visible, iconState.visible); + assertEquals("Signal icon in, quick settings", icon, iconState.icon); assertEquals("Data icon in, quick settings", typeIcon, (int) typeIconArg.getValue()); assertEquals("Data direction in, in quick settings", dataIn, (boolean) dataInArg.getValue()); @@ -283,29 +280,32 @@ public class NetworkControllerBaseTest extends SysuiTestCase { protected void verifyLastMobileDataIndicators(boolean visible, int strengthIcon, int darkStrengthIcon, int typeIcon) { - ArgumentCaptor<Integer> strengthIconArg = ArgumentCaptor.forClass(Integer.class); + ArgumentCaptor<IconState> iconArg = ArgumentCaptor.forClass(IconState.class); ArgumentCaptor<Integer> darkStrengthIconArg = ArgumentCaptor.forClass(Integer.class); ArgumentCaptor<Integer> typeIconArg = ArgumentCaptor.forClass(Integer.class); - ArgumentCaptor<Boolean> visibleArg = ArgumentCaptor.forClass(Boolean.class); // TODO: Verify all fields. - Mockito.verify(mSignalCluster, Mockito.atLeastOnce()).setMobileDataIndicators( - visibleArg.capture(), strengthIconArg.capture(), darkStrengthIconArg.capture(), - typeIconArg.capture(), + Mockito.verify(mCallbackHandler, Mockito.atLeastOnce()).setMobileDataIndicators( + iconArg.capture(), + ArgumentCaptor.forClass(IconState.class).capture(), + darkStrengthIconArg.capture(), typeIconArg.capture(), + ArgumentCaptor.forClass(Integer.class).capture(), + ArgumentCaptor.forClass(Boolean.class).capture(), + ArgumentCaptor.forClass(Boolean.class).capture(), ArgumentCaptor.forClass(String.class).capture(), ArgumentCaptor.forClass(String.class).capture(), ArgumentCaptor.forClass(Boolean.class).capture(), ArgumentCaptor.forClass(Integer.class).capture()); + IconState iconState = iconArg.getValue(); - assertEquals("Signal strength icon in status bar", strengthIcon, - (int) strengthIconArg.getValue()); + assertEquals("Signal strength icon in status bar", strengthIcon, iconState.icon); assertEquals("Signal strength icon (dark mode) in status bar", darkStrengthIcon, (int) darkStrengthIconArg.getValue()); assertEquals("Data icon in status bar", typeIcon, (int) typeIconArg.getValue()); - assertEquals("Visibility in status bar", visible, (boolean) visibleArg.getValue()); + assertEquals("Visibility in status bar", visible, iconState.visible); } protected void assertNetworkNameEquals(String expected) { - assertEquals("Network name", expected, mNetworkController.getMobileDataNetworkName()); + assertEquals("Network name", expected, mMobileSignalController.getState().networkName); } } diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerDataTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerDataTest.java index 3f9312d..15752e1 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerDataTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerDataTest.java @@ -1,16 +1,17 @@ package com.android.systemui.statusbar.policy; -import org.mockito.Mockito; - +import android.os.Looper; import android.telephony.TelephonyManager; +import org.mockito.Mockito; + public class NetworkControllerDataTest extends NetworkControllerBaseTest { public void test3gDataIcon() { setupDefaultSignal(); verifyDataIndicators(TelephonyIcons.DATA_3G[1][0 /* No direction */], - TelephonyIcons.QS_DATA_3G[1]); + TelephonyIcons.QS_DATA_3G); } public void testRoamingDataIcon() { @@ -22,7 +23,7 @@ public class NetworkControllerDataTest extends NetworkControllerBaseTest { TelephonyIcons.ROAMING_ICON); verifyLastQsMobileDataIndicators(true, TelephonyIcons.QS_TELEPHONY_SIGNAL_STRENGTH[1][DEFAULT_LEVEL], - TelephonyIcons.QS_DATA_R[1], false, false); + TelephonyIcons.QS_DATA_R, false, false); } public void test2gDataIcon() { @@ -31,7 +32,7 @@ public class NetworkControllerDataTest extends NetworkControllerBaseTest { TelephonyManager.NETWORK_TYPE_GSM); verifyDataIndicators(TelephonyIcons.DATA_G[1][0 /* No direction */], - TelephonyIcons.QS_DATA_G[1]); + TelephonyIcons.QS_DATA_G); } public void testCdmaDataIcon() { @@ -40,7 +41,7 @@ public class NetworkControllerDataTest extends NetworkControllerBaseTest { TelephonyManager.NETWORK_TYPE_CDMA); verifyDataIndicators(TelephonyIcons.DATA_1X[1][0 /* No direction */], - TelephonyIcons.QS_DATA_1X[1]); + TelephonyIcons.QS_DATA_1X); } public void testEdgeDataIcon() { @@ -49,7 +50,7 @@ public class NetworkControllerDataTest extends NetworkControllerBaseTest { TelephonyManager.NETWORK_TYPE_EDGE); verifyDataIndicators(TelephonyIcons.DATA_E[1][0 /* No direction */], - TelephonyIcons.QS_DATA_E[1]); + TelephonyIcons.QS_DATA_E); } public void testLteDataIcon() { @@ -58,7 +59,7 @@ public class NetworkControllerDataTest extends NetworkControllerBaseTest { TelephonyManager.NETWORK_TYPE_LTE); verifyDataIndicators(TelephonyIcons.DATA_LTE[1][0 /* No direction */], - TelephonyIcons.QS_DATA_LTE[1]); + TelephonyIcons.QS_DATA_LTE); } public void testHspaDataIcon() { @@ -67,14 +68,15 @@ public class NetworkControllerDataTest extends NetworkControllerBaseTest { TelephonyManager.NETWORK_TYPE_HSPA); verifyDataIndicators(TelephonyIcons.DATA_H[1][0 /* No direction */], - TelephonyIcons.QS_DATA_H[1]); + TelephonyIcons.QS_DATA_H); } public void test4gDataIcon() { // Switch to showing 4g icon and re-initialize the NetworkController. mConfig.show4gForLte = true; mNetworkController = new NetworkControllerImpl(mContext, mMockCm, mMockTm, mMockWm, mMockSm, - mConfig, Mockito.mock(AccessPointControllerImpl.class), + mConfig, Looper.getMainLooper(), mCallbackHandler, + Mockito.mock(AccessPointControllerImpl.class), Mockito.mock(MobileDataControllerImpl.class)); setupNetworkController(); @@ -83,7 +85,7 @@ public class NetworkControllerDataTest extends NetworkControllerBaseTest { TelephonyManager.NETWORK_TYPE_LTE); verifyDataIndicators(TelephonyIcons.DATA_4G[1][0 /* No direction */], - TelephonyIcons.QS_DATA_4G[1]); + TelephonyIcons.QS_DATA_4G); } public void test4gDataIconConfigChange() { @@ -99,7 +101,7 @@ public class NetworkControllerDataTest extends NetworkControllerBaseTest { mNetworkController.handleConfigurationChanged(); verifyDataIndicators(TelephonyIcons.DATA_4G[1][0 /* No direction */], - TelephonyIcons.QS_DATA_4G[1]); + TelephonyIcons.QS_DATA_4G); } public void testDataActivity() { diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerEthernetTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerEthernetTest.java index 82ced9f..5d63d8d 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerEthernetTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerEthernetTest.java @@ -2,6 +2,8 @@ package com.android.systemui.statusbar.policy; import android.net.NetworkCapabilities; +import com.android.systemui.statusbar.policy.NetworkController.IconState; + import org.mockito.ArgumentCaptor; import org.mockito.Mockito; @@ -24,17 +26,16 @@ public class NetworkControllerEthernetTest extends NetworkControllerBaseTest { } protected void setEthernetState(boolean connected, boolean validated) { - setConnectivity(validated ? 100 : 0, NetworkCapabilities.TRANSPORT_ETHERNET, connected); + setConnectivity(NetworkCapabilities.TRANSPORT_ETHERNET, validated, connected); } protected void verifyLastEthernetIcon(boolean visible, int icon) { - ArgumentCaptor<Boolean> visibleArg = ArgumentCaptor.forClass(Boolean.class); - ArgumentCaptor<Integer> iconArg = ArgumentCaptor.forClass(Integer.class); - - Mockito.verify(mSignalCluster, Mockito.atLeastOnce()).setEthernetIndicators( - visibleArg.capture(), iconArg.capture(), - ArgumentCaptor.forClass(String.class).capture()); - assertEquals("Ethernet visible, in status bar", visible, (boolean) visibleArg.getValue()); - assertEquals("Ethernet icon, in status bar", icon, (int) iconArg.getValue()); + ArgumentCaptor<IconState> iconArg = ArgumentCaptor.forClass(IconState.class); + + Mockito.verify(mCallbackHandler, Mockito.atLeastOnce()).setEthernetIndicators( + iconArg.capture()); + IconState iconState = iconArg.getValue(); + assertEquals("Ethernet visible, in status bar", visible, iconState.visible); + assertEquals("Ethernet icon, in status bar", icon, iconState.icon); } } diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerSignalTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerSignalTest.java index 389ad6f..874fdf9 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerSignalTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerSignalTest.java @@ -19,12 +19,13 @@ import static org.mockito.Mockito.mock; import android.content.Intent; import android.net.ConnectivityManager; +import android.net.NetworkCapabilities; +import android.os.Looper; import android.telephony.ServiceState; import android.telephony.SignalStrength; import android.telephony.SubscriptionInfo; import android.telephony.TelephonyManager; -import com.android.internal.telephony.IccCardConstants; import com.android.internal.telephony.PhoneConstants; import com.android.internal.telephony.TelephonyIntents; import com.android.systemui.R; @@ -41,8 +42,8 @@ public class NetworkControllerSignalTest extends NetworkControllerBaseTest { Mockito.when(mMockCm.isNetworkSupported(ConnectivityManager.TYPE_MOBILE)).thenReturn(false); // Create a new NetworkController as this is currently handled in constructor. mNetworkController = new NetworkControllerImpl(mContext, mMockCm, mMockTm, mMockWm, mMockSm, - mConfig, mock(AccessPointControllerImpl.class), - mock(MobileDataControllerImpl.class)); + mConfig, Looper.getMainLooper(), mCallbackHandler, + mock(AccessPointControllerImpl.class), mock(MobileDataControllerImpl.class)); setupNetworkController(); verifyLastMobileDataIndicators(false, 0, 0); @@ -61,8 +62,8 @@ public class NetworkControllerSignalTest extends NetworkControllerBaseTest { Mockito.when(mMockCm.isNetworkSupported(ConnectivityManager.TYPE_MOBILE)).thenReturn(false); // Create a new NetworkController as this is currently handled in constructor. mNetworkController = new NetworkControllerImpl(mContext, mMockCm, mMockTm, mMockWm, mMockSm, - mConfig, mock(AccessPointControllerImpl.class), - mock(MobileDataControllerImpl.class)); + mConfig, Looper.getMainLooper(), mCallbackHandler, + mock(AccessPointControllerImpl.class), mock(MobileDataControllerImpl.class)); setupNetworkController(); // No Subscriptions. @@ -79,13 +80,12 @@ public class NetworkControllerSignalTest extends NetworkControllerBaseTest { setLevel(testStrength); verifyLastMobileDataIndicators(true, - TelephonyIcons.TELEPHONY_SIGNAL_STRENGTH[1][testStrength], - DEFAULT_ICON); + TelephonyIcons.TELEPHONY_SIGNAL_STRENGTH[1][testStrength], DEFAULT_ICON); // Verify low inet number indexing. - setConnectivity(0, ConnectivityManager.TYPE_MOBILE, true); + setConnectivity(NetworkCapabilities.TRANSPORT_CELLULAR, false, true); verifyLastMobileDataIndicators(true, - TelephonyIcons.TELEPHONY_SIGNAL_STRENGTH[0][testStrength], 0); + TelephonyIcons.TELEPHONY_SIGNAL_STRENGTH[0][testStrength], DEFAULT_ICON); } } @@ -154,18 +154,12 @@ public class NetworkControllerSignalTest extends NetworkControllerBaseTest { } } - public void testNoRoamingWithoutSignal() { + public void testNoBangWithWifi() { setupDefaultSignal(); - setCdma(); - setCdmaRoaming(true); - setVoiceRegState(ServiceState.STATE_OUT_OF_SERVICE); - setDataRegState(ServiceState.STATE_OUT_OF_SERVICE); - - // This exposes the bug in b/18034542, and should be switched to the commented out - // verification below (and pass), once the bug is fixed. - verifyLastMobileDataIndicators(true, R.drawable.stat_sys_signal_null, - TelephonyIcons.ROAMING_ICON); - //verifyLastMobileDataIndicators(true, R.drawable.stat_sys_signal_null, 0 /* No Icon */); + setConnectivity(mMobileSignalController.mTransportType, false, false); + setConnectivity(NetworkCapabilities.TRANSPORT_WIFI, true, true); + + verifyLastMobileDataIndicators(true, TelephonyIcons.TELEPHONY_SIGNAL_STRENGTH[1][2], 0); } // Some tests of actual NetworkController code, just internals not display stuff diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerWifiTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerWifiTest.java index 2e0e9a3..cecf2fd 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerWifiTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerWifiTest.java @@ -1,11 +1,13 @@ package com.android.systemui.statusbar.policy; import android.content.Intent; -import android.net.ConnectivityManager; +import android.net.NetworkCapabilities; import android.net.NetworkInfo; import android.net.wifi.WifiInfo; import android.net.wifi.WifiManager; +import com.android.systemui.statusbar.policy.NetworkController.IconState; + import org.mockito.ArgumentCaptor; import org.mockito.Mockito; @@ -25,9 +27,9 @@ public class NetworkControllerWifiTest extends NetworkControllerBaseTest { for (int testLevel = 0; testLevel < WifiIcons.WIFI_LEVEL_COUNT; testLevel++) { setWifiLevel(testLevel); - setConnectivity(100, ConnectivityManager.TYPE_WIFI, true); + setConnectivity(NetworkCapabilities.TRANSPORT_WIFI, true, true); verifyLastWifiIcon(true, WifiIcons.WIFI_SIGNAL_STRENGTH[1][testLevel]); - setConnectivity(0, ConnectivityManager.TYPE_WIFI, true); + setConnectivity(NetworkCapabilities.TRANSPORT_WIFI, false, true); verifyLastWifiIcon(true, WifiIcons.WIFI_SIGNAL_STRENGTH[0][testLevel]); } } @@ -45,10 +47,10 @@ public class NetworkControllerWifiTest extends NetworkControllerBaseTest { for (int testLevel = 0; testLevel < WifiIcons.WIFI_LEVEL_COUNT; testLevel++) { setWifiLevel(testLevel); - setConnectivity(100, ConnectivityManager.TYPE_WIFI, true); + setConnectivity(NetworkCapabilities.TRANSPORT_WIFI, true, true); verifyLastQsWifiIcon(true, true, WifiIcons.QS_WIFI_SIGNAL_STRENGTH[1][testLevel], testSsid); - setConnectivity(0, ConnectivityManager.TYPE_WIFI, true); + setConnectivity(NetworkCapabilities.TRANSPORT_WIFI, false, true); verifyLastQsWifiIcon(true, true, WifiIcons.QS_WIFI_SIGNAL_STRENGTH[0][testLevel], testSsid); } @@ -61,7 +63,7 @@ public class NetworkControllerWifiTest extends NetworkControllerBaseTest { setWifiEnabled(true); setWifiState(true, testSsid); setWifiLevel(testLevel); - setConnectivity(100, ConnectivityManager.TYPE_WIFI, true); + setConnectivity(NetworkCapabilities.TRANSPORT_WIFI, true, true); verifyLastQsWifiIcon(true, true, WifiIcons.QS_WIFI_SIGNAL_STRENGTH[1][testLevel], testSsid); @@ -82,13 +84,13 @@ public class NetworkControllerWifiTest extends NetworkControllerBaseTest { setWifiEnabled(true); setWifiState(true, testSsid); setWifiLevel(testLevel); - setConnectivity(100, ConnectivityManager.TYPE_WIFI, true); + setConnectivity(NetworkCapabilities.TRANSPORT_WIFI, true, true); verifyLastWifiIcon(true, WifiIcons.WIFI_SIGNAL_STRENGTH[1][testLevel]); setupDefaultSignal(); setGsmRoaming(true); // Still be on wifi though. - setConnectivity(100, ConnectivityManager.TYPE_WIFI, true); + setConnectivity(NetworkCapabilities.TRANSPORT_WIFI, true, true); verifyLastMobileDataIndicators(true, TelephonyIcons.TELEPHONY_SIGNAL_STRENGTH_ROAMING[1][DEFAULT_LEVEL], TelephonyIcons.ROAMING_ICON); @@ -133,46 +135,39 @@ public class NetworkControllerWifiTest extends NetworkControllerBaseTest { ArgumentCaptor<Boolean> inArg = ArgumentCaptor.forClass(Boolean.class); ArgumentCaptor<Boolean> outArg = ArgumentCaptor.forClass(Boolean.class); - Mockito.verify(mNetworkSignalChangedCallback, Mockito.atLeastOnce()).onWifiSignalChanged( - ArgumentCaptor.forClass(Boolean.class).capture(), - ArgumentCaptor.forClass(Boolean.class).capture(), - ArgumentCaptor.forClass(Integer.class).capture(), - inArg.capture(), outArg.capture(), - ArgumentCaptor.forClass(String.class).capture(), - ArgumentCaptor.forClass(String.class).capture()); + Mockito.verify(mCallbackHandler, Mockito.atLeastOnce()).setWifiIndicators( + Mockito.anyBoolean(), Mockito.any(IconState.class), Mockito.any(IconState.class), + inArg.capture(), outArg.capture(), Mockito.anyString()); assertEquals("WiFi data in, in quick settings", in, (boolean) inArg.getValue()); assertEquals("WiFi data out, in quick settings", out, (boolean) outArg.getValue()); } protected void verifyLastQsWifiIcon(boolean enabled, boolean connected, int icon, String description) { + ArgumentCaptor<IconState> iconArg = ArgumentCaptor.forClass(IconState.class); ArgumentCaptor<Boolean> enabledArg = ArgumentCaptor.forClass(Boolean.class); - ArgumentCaptor<Boolean> connectedArg = ArgumentCaptor.forClass(Boolean.class); - ArgumentCaptor<Integer> iconArg = ArgumentCaptor.forClass(Integer.class); ArgumentCaptor<String> descArg = ArgumentCaptor.forClass(String.class); - Mockito.verify(mNetworkSignalChangedCallback, Mockito.atLeastOnce()).onWifiSignalChanged( - enabledArg.capture(), connectedArg.capture(), iconArg.capture(), - ArgumentCaptor.forClass(Boolean.class).capture(), - ArgumentCaptor.forClass(Boolean.class).capture(), - ArgumentCaptor.forClass(String.class).capture(), + Mockito.verify(mCallbackHandler, Mockito.atLeastOnce()).setWifiIndicators( + enabledArg.capture(), Mockito.any(IconState.class), + iconArg.capture(), Mockito.anyBoolean(), + Mockito.anyBoolean(), descArg.capture()); + IconState iconState = iconArg.getValue(); assertEquals("WiFi enabled, in quick settings", enabled, (boolean) enabledArg.getValue()); - assertEquals("WiFi connected, in quick settings", connected, - (boolean) connectedArg.getValue()); - assertEquals("WiFi signal, in quick settings", icon, (int) iconArg.getValue()); - assertEquals("WiFI desc (ssid), in quick settings", description, - (String) descArg.getValue()); + assertEquals("WiFi connected, in quick settings", connected, iconState.visible); + assertEquals("WiFi signal, in quick settings", icon, iconState.icon); + assertEquals("WiFI desc (ssid), in quick settings", description, descArg.getValue()); } protected void verifyLastWifiIcon(boolean visible, int icon) { - ArgumentCaptor<Boolean> visibleArg = ArgumentCaptor.forClass(Boolean.class); - ArgumentCaptor<Integer> iconArg = ArgumentCaptor.forClass(Integer.class); - - Mockito.verify(mSignalCluster, Mockito.atLeastOnce()).setWifiIndicators( - visibleArg.capture(), iconArg.capture(), - ArgumentCaptor.forClass(String.class).capture()); - assertEquals("WiFi visible, in status bar", visible, (boolean) visibleArg.getValue()); - assertEquals("WiFi signal, in status bar", icon, (int) iconArg.getValue()); + ArgumentCaptor<IconState> iconArg = ArgumentCaptor.forClass(IconState.class); + + Mockito.verify(mCallbackHandler, Mockito.atLeastOnce()).setWifiIndicators( + Mockito.anyBoolean(), iconArg.capture(), Mockito.any(IconState.class), + Mockito.anyBoolean(), Mockito.anyBoolean(), Mockito.anyString()); + IconState iconState = iconArg.getValue(); + assertEquals("WiFi visible, in status bar", visible, iconState.visible); + assertEquals("WiFi signal, in status bar", icon, iconState.icon); } } diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java index 6c83192..9f35843 100644 --- a/services/core/java/com/android/server/audio/AudioService.java +++ b/services/core/java/com/android/server/audio/AudioService.java @@ -2862,8 +2862,11 @@ public class AudioService extends IAudioService.Stub { } } if (toRemove != null) { + int delay = checkSendBecomingNoisyIntent( + AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, + 0); for (int i = 0; i < toRemove.size(); i++) { - makeA2dpDeviceUnavailableNow(toRemove.valueAt(i)); + makeA2dpDeviceUnavailableLater(toRemove.valueAt(i), delay); } } } @@ -4426,7 +4429,7 @@ public class AudioService extends IAudioService.Stub { } // must be called synchronized on mConnectedDevices - private void makeA2dpDeviceUnavailableLater(String address) { + private void makeA2dpDeviceUnavailableLater(String address, int delayMs) { // prevent any activity on the A2DP audio output to avoid unwanted // reconnection of the sink. AudioSystem.setParameters("A2dpSuspended=true"); @@ -4435,7 +4438,7 @@ public class AudioService extends IAudioService.Stub { makeDeviceListKey(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, address)); // send the delayed message to make the device unavailable later Message msg = mAudioHandler.obtainMessage(MSG_BTA2DP_DOCK_TIMEOUT, address); - mAudioHandler.sendMessageDelayed(msg, BTA2DP_DOCK_TIMEOUT_MILLIS); + mAudioHandler.sendMessageDelayed(msg, delayMs); } @@ -4492,7 +4495,7 @@ public class AudioService extends IAudioService.Stub { // introduction of a delay for transient disconnections of docks when // power is rapidly turned off/on, this message will be canceled if // we reconnect the dock under a preset delay - makeA2dpDeviceUnavailableLater(address); + makeA2dpDeviceUnavailableLater(address, BTA2DP_DOCK_TIMEOUT_MILLIS); // the next time isConnected is evaluated, it will be false for the dock } } else { |
