diff options
-rw-r--r-- | core/java/android/view/RoundScrollbarRenderer.java | 121 | ||||
-rw-r--r-- | core/java/android/view/View.java | 62 | ||||
-rw-r--r-- | docs/html/guide/topics/manifest/activity-element.jd | 2 | ||||
-rw-r--r-- | services/core/java/com/android/server/am/PendingIntentRecord.java | 25 |
4 files changed, 185 insertions, 25 deletions
diff --git a/core/java/android/view/RoundScrollbarRenderer.java b/core/java/android/view/RoundScrollbarRenderer.java new file mode 100644 index 000000000000..f258458a9b15 --- /dev/null +++ b/core/java/android/view/RoundScrollbarRenderer.java @@ -0,0 +1,121 @@ +/* + * Copyright (C) 2016 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.view; + +import android.graphics.Canvas; +import android.graphics.Color; +import android.graphics.Paint; +import android.graphics.RectF; + +/** + * Helper class for drawing round scroll bars on round Wear devices. + */ +class RoundScrollbarRenderer { + // The range of the scrollbar position represented as an angle in degrees. + private static final int SCROLLBAR_ANGLE_RANGE = 90; + private static final int MAX_SCROLLBAR_ANGLE_SWIPE = 16; + private static final int MIN_SCROLLBAR_ANGLE_SWIPE = 6; + private static final float WIDTH_PERCENTAGE = 0.02f; + private static final int DEFAULT_THUMB_COLOR = 0xFF757575; + private static final int DEFAULT_TRACK_COLOR = 0x21FFFFFF; + + private final Paint mThumbPaint = new Paint(); + private final Paint mTrackPaint = new Paint(); + private final RectF mRect = new RectF(); + private final View mParent; + + public RoundScrollbarRenderer(View parent) { + // Paints for the round scrollbar. + // Set up the thumb paint + mThumbPaint.setAntiAlias(true); + mThumbPaint.setStrokeCap(Paint.Cap.ROUND); + mThumbPaint.setStyle(Paint.Style.STROKE); + + // Set up the track paint + mTrackPaint.setAntiAlias(true); + mTrackPaint.setStrokeCap(Paint.Cap.ROUND); + mTrackPaint.setStyle(Paint.Style.STROKE); + + mParent = parent; + } + + public void drawRoundScrollbars(Canvas canvas, float alpha) { + if (alpha == 0) { + return; + } + // Get information about the current scroll state of the parent view. + float maxScroll = mParent.computeVerticalScrollRange(); + float scrollExtent = mParent.computeVerticalScrollExtent(); + if (scrollExtent <= 0 || maxScroll <= scrollExtent) { + return; + } + float currentScroll = Math.max(0, mParent.computeVerticalScrollOffset()); + float linearThumbLength = mParent.computeVerticalScrollExtent(); + float thumbWidth = mParent.getWidth() * WIDTH_PERCENTAGE; + mThumbPaint.setStrokeWidth(thumbWidth); + mTrackPaint.setStrokeWidth(thumbWidth); + + setThumbColor(applyAlpha(DEFAULT_THUMB_COLOR, alpha)); + setTrackColor(applyAlpha(DEFAULT_TRACK_COLOR, alpha)); + + // Normalize the sweep angle for the scroll bar. + float sweepAngle = (linearThumbLength / maxScroll) * SCROLLBAR_ANGLE_RANGE; + sweepAngle = clamp(sweepAngle, MIN_SCROLLBAR_ANGLE_SWIPE, MAX_SCROLLBAR_ANGLE_SWIPE); + // Normalize the start angle so that it falls on the track. + float startAngle = (currentScroll * (SCROLLBAR_ANGLE_RANGE - sweepAngle)) + / (maxScroll - linearThumbLength) - SCROLLBAR_ANGLE_RANGE / 2; + startAngle = clamp(startAngle, -SCROLLBAR_ANGLE_RANGE / 2, + SCROLLBAR_ANGLE_RANGE / 2 - sweepAngle); + + // Draw the track and the scroll bar. + mRect.set( + 0 + thumbWidth / 2, + 0 + thumbWidth / 2, + mParent.getWidth() - thumbWidth / 2, + mParent.getHeight() - thumbWidth / 2); + canvas.drawArc(mRect, -SCROLLBAR_ANGLE_RANGE / 2, SCROLLBAR_ANGLE_RANGE, false, + mTrackPaint); + canvas.drawArc(mRect, startAngle, sweepAngle, false, mThumbPaint); + } + + private static float clamp(float val, float min, float max) { + if (val < min) { + return min; + } else if (val > max) { + return max; + } else { + return val; + } + } + + private static int applyAlpha(int color, float alpha) { + int alphaByte = (int) (Color.alpha(color) * alpha); + return Color.argb(alphaByte, Color.red(color), Color.green(color), Color.blue(color)); + } + + private void setThumbColor(int thumbColor) { + if (mThumbPaint.getColor() != thumbColor) { + mThumbPaint.setColor(thumbColor); + } + } + + private void setTrackColor(int trackColor) { + if (mTrackPaint.getColor() != trackColor) { + mTrackPaint.setColor(trackColor); + } + } +} diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java index 2026f4e429dd..6ccc0ee523c7 100644 --- a/core/java/android/view/View.java +++ b/core/java/android/view/View.java @@ -40,6 +40,7 @@ import android.content.res.Resources; import android.content.res.TypedArray; import android.graphics.Bitmap; import android.graphics.Canvas; +import android.graphics.Color; import android.graphics.Insets; import android.graphics.Interpolator; import android.graphics.LinearGradient; @@ -3993,6 +3994,9 @@ public class View implements Drawable.Callback, KeyEvent.Callback, */ String mStartActivityRequestWho; + @Nullable + private RoundScrollbarRenderer mRoundScrollbarRenderer; + /** * Simple constructor to use when creating a view from code. * @@ -14804,6 +14808,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback, protected final void onDrawScrollBars(Canvas canvas) { // scrollbars are drawn only when the animation is running final ScrollabilityCache cache = mScrollCache; + if (cache != null) { int state = cache.state; @@ -14844,13 +14849,23 @@ public class View implements Drawable.Callback, KeyEvent.Callback, final boolean drawVerticalScrollBar = isVerticalScrollBarEnabled() && !isVerticalScrollBarHidden(); - if (drawVerticalScrollBar || drawHorizontalScrollBar) { + // Fork out the scroll bar drawing for round wearable devices. + if (mRoundScrollbarRenderer != null) { + if (drawVerticalScrollBar) { + mRoundScrollbarRenderer.drawRoundScrollbars( + canvas, (float) cache.scrollBar.getAlpha() / 255f); + if (invalidate) { + invalidate(); + } + } + // Do not draw horizontal scroll bars for round wearable devices. + } else if (drawVerticalScrollBar || drawHorizontalScrollBar) { final ScrollBarDrawable scrollBar = cache.scrollBar; if (drawHorizontalScrollBar) { scrollBar.setParameters(computeHorizontalScrollRange(), - computeHorizontalScrollOffset(), - computeHorizontalScrollExtent(), false); + computeHorizontalScrollOffset(), + computeHorizontalScrollExtent(), false); final Rect bounds = cache.mScrollBarBounds; getHorizontalScrollBarBounds(bounds); onDrawHorizontalScrollBar(canvas, scrollBar, bounds.left, bounds.top, @@ -14862,8 +14877,8 @@ public class View implements Drawable.Callback, KeyEvent.Callback, if (drawVerticalScrollBar) { scrollBar.setParameters(computeVerticalScrollRange(), - computeVerticalScrollOffset(), - computeVerticalScrollExtent(), true); + computeVerticalScrollOffset(), + computeVerticalScrollExtent(), true); final Rect bounds = cache.mScrollBarBounds; getVerticalScrollBarBounds(bounds); onDrawVerticalScrollBar(canvas, scrollBar, bounds.left, bounds.top, @@ -17574,6 +17589,15 @@ public class View implements Drawable.Callback, KeyEvent.Callback, if (changed || (mPrivateFlags & PFLAG_LAYOUT_REQUIRED) == PFLAG_LAYOUT_REQUIRED) { onLayout(changed, l, t, r, b); + + if (shouldDrawRoundScrollbar()) { + if(mRoundScrollbarRenderer == null) { + mRoundScrollbarRenderer = new RoundScrollbarRenderer(this); + } + } else { + mRoundScrollbarRenderer = null; + } + mPrivateFlags &= ~PFLAG_LAYOUT_REQUIRED; ListenerInfo li = mListenerInfo; @@ -22955,7 +22979,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback, final int[] mInvalidateChildLocation = new int[2]; /** - * Global to the view hierarchy used as a temporary for dealng with + * Global to the view hierarchy used as a temporary for dealing with * computing absolute on-screen location. */ final int[] mTmpLocation = new int[2]; @@ -23793,4 +23817,30 @@ public class View implements Drawable.Callback, KeyEvent.Callback, stream.addProperty("accessibility:labelFor", getLabelFor()); stream.addProperty("accessibility:importantForAccessibility", getImportantForAccessibility()); } + + /** + * Determine if this view is rendered on a round wearable device and is the main view + * on the screen. + */ + private boolean shouldDrawRoundScrollbar() { + if (!mResources.getConfiguration().isScreenRound()) { + return false; + } + + final View rootView = getRootView(); + final WindowInsets insets = getRootWindowInsets(); + + int height = getHeight(); + int width = getWidth(); + int displayHeight = rootView.getHeight(); + int displayWidth = rootView.getWidth(); + + if (height != displayHeight || width != displayWidth) { + return false; + } + + getLocationOnScreen(mAttachInfo.mTmpLocation); + return mAttachInfo.mTmpLocation[0] == insets.getStableInsetLeft() + && mAttachInfo.mTmpLocation[1] == insets.getStableInsetTop(); + } } diff --git a/docs/html/guide/topics/manifest/activity-element.jd b/docs/html/guide/topics/manifest/activity-element.jd index f30263e8983c..5ced295daa8a 100644 --- a/docs/html/guide/topics/manifest/activity-element.jd +++ b/docs/html/guide/topics/manifest/activity-element.jd @@ -25,7 +25,7 @@ parent.link=manifest-intro.html android:<a href="#hwaccel">hardwareAccelerated</a>=["true" | "false"] android:<a href="#icon">icon</a>="<i>drawable resource</i>" android:<a href="#label">label</a>="<i>string resource</i>" - android:<a href="#lmode">launchMode</a>=["multiple" | "singleTop" | + android:<a href="#lmode">launchMode</a>=["standard" | "singleTop" | "singleTask" | "singleInstance"] android:<a href="#maxRecents">maxRecents</a>="<i>integer</i>" android:<a href="#multi">multiprocess</a>=["true" | "false"] diff --git a/services/core/java/com/android/server/am/PendingIntentRecord.java b/services/core/java/com/android/server/am/PendingIntentRecord.java index 2467a9094072..9c0845363860 100644 --- a/services/core/java/com/android/server/am/PendingIntentRecord.java +++ b/services/core/java/com/android/server/am/PendingIntentRecord.java @@ -38,6 +38,7 @@ import com.android.server.am.ActivityStackSupervisor.ActivityContainer; import java.io.PrintWriter; import java.lang.ref.WeakReference; +import java.util.Objects; final class PendingIntentRecord extends IIntentSender.Stub { private static final String TAG = TAG_WITH_CLASS_NAME ? "PendingIntentRecord" : TAG_AM; @@ -102,7 +103,7 @@ final class PendingIntentRecord extends IIntentSender.Stub { if (requestResolvedType != null) { hash = (ODD_PRIME_NUMBER*hash) + requestResolvedType.hashCode(); } - hash = (ODD_PRIME_NUMBER*hash) + _p.hashCode(); + hash = (ODD_PRIME_NUMBER*hash) + (_p != null ? _p.hashCode() : 0); hash = (ODD_PRIME_NUMBER*hash) + _t; hashCode = hash; //Slog.i(ActivityManagerService.TAG, this + " hashCode=0x" @@ -121,20 +122,14 @@ final class PendingIntentRecord extends IIntentSender.Stub { if (userId != other.userId){ return false; } - if (!packageName.equals(other.packageName)) { + if (!Objects.equals(packageName, other.packageName)) { return false; } if (activity != other.activity) { return false; } - if (who != other.who) { - if (who != null) { - if (!who.equals(other.who)) { - return false; - } - } else if (other.who != null) { - return false; - } + if (!Objects.equals(who, other.who)) { + return false; } if (requestCode != other.requestCode) { return false; @@ -148,14 +143,8 @@ final class PendingIntentRecord extends IIntentSender.Stub { return false; } } - if (requestResolvedType != other.requestResolvedType) { - if (requestResolvedType != null) { - if (!requestResolvedType.equals(other.requestResolvedType)) { - return false; - } - } else if (other.requestResolvedType != null) { - return false; - } + if (!Objects.equals(requestResolvedType, other.requestResolvedType)) { + return false; } if (flags != other.flags) { return false; |