diff options
30 files changed, 727 insertions, 863 deletions
diff --git a/Android.mk b/Android.mk index d847d49e89c4..6631adace544 100644 --- a/Android.mk +++ b/Android.mk @@ -385,6 +385,7 @@ LOCAL_SRC_FILES += \ core/java/com/android/internal/appwidget/IAppWidgetHost.aidl \ core/java/com/android/internal/backup/IBackupTransport.aidl \ core/java/com/android/internal/backup/IObbBackupService.aidl \ + core/java/com/android/internal/car/ICarServiceHelper.aidl \ core/java/com/android/internal/inputmethod/IInputContentUriToken.aidl \ core/java/com/android/internal/policy/IKeyguardDrawnCallback.aidl \ core/java/com/android/internal/policy/IKeyguardDismissCallback.aidl \ diff --git a/core/java/com/android/internal/car/ICarServiceHelper.aidl b/core/java/com/android/internal/car/ICarServiceHelper.aidl new file mode 100644 index 000000000000..9ee330be060b --- /dev/null +++ b/core/java/com/android/internal/car/ICarServiceHelper.aidl @@ -0,0 +1,24 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.internal.car; + +/** + * Helper API for car service. Only for itneraction between system server and car service. + * @hide + */ +interface ICarServiceHelper { +} diff --git a/libs/hwui/Android.bp b/libs/hwui/Android.bp index 07ff27de794f..4cfb9d88c716 100644 --- a/libs/hwui/Android.bp +++ b/libs/hwui/Android.bp @@ -5,11 +5,6 @@ cc_defaults { //"hwui_bugreport_font_cache_usage", //"hwui_compile_for_perf", - - // Enables fine-grained GLES error checking - // If enabled, every GLES call is wrapped & error checked - // Has moderate overhead - //"hwui_enable_opengl-validation", ], cflags: [ @@ -108,7 +103,6 @@ cc_defaults { name: "hwui_enable_opengl_validation", defaults: ["hwui_debug"], cflags: ["-DDEBUG_OPENGL=3"], - srcs: ["debug/wrap_gles.cpp"], include_dirs: ["frameworks/native/opengl/libs/GLES2"], } @@ -242,7 +236,14 @@ cc_defaults { cc_library { name: "libhwui", - defaults: ["libhwui_defaults"], + defaults: [ + "libhwui_defaults", + + // Enables fine-grained GLES error checking + // If enabled, every GLES call is wrapped & error checked + // Has moderate overhead + "hwui_enable_opengl_validation", +], } // ------------------------ diff --git a/packages/SettingsLib/res/layout/preference_category_material_settings.xml b/packages/SettingsLib/res/layout/preference_category_material_settings.xml new file mode 100644 index 000000000000..741435ec9b43 --- /dev/null +++ b/packages/SettingsLib/res/layout/preference_category_material_settings.xml @@ -0,0 +1,66 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + Copyright (C) 2017 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. + --> + +<!-- Based off frameworks/base/core/res/res/layout/preference_category_material.xml + except that this supports icon --> +<FrameLayout + xmlns:android="http://schemas.android.com/apk/res/android" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_marginTop="8dp" + android:layout_marginBottom="8dp" + android:paddingStart="?android:attr/listPreferredItemPaddingStart" > + + <LinearLayout + android:id="@+id/icon_container" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:gravity="start|center_vertical" + android:orientation="horizontal"> + <com.android.internal.widget.PreferenceImageView + android:id="@android:id/icon" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:tint="?android:attr/textColorPrimary" + android:maxWidth="18dp" + android:maxHeight="18dp"/> + </LinearLayout> + + <LinearLayout + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:paddingStart="56dp" + android:orientation="vertical"> + <TextView + android:id="@android:id/title" + android:layout_marginTop="16dp" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:textAppearance="@android:style/TextAppearance.Material.Body2" + android:textColor="?android:attr/colorAccent" + android:paddingEnd="?android:attr/listPreferredItemPaddingEnd"/> + <TextView + android:id="@android:id/summary" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:textAppearance="?android:attr/textAppearanceListItemSecondary" + android:textColor="?android:attr/textColorSecondary" + android:ellipsize="end" + android:singleLine="true" /> + </LinearLayout> + +</FrameLayout>
\ No newline at end of file diff --git a/packages/SettingsLib/res/layout/usage_bottom_label.xml b/packages/SettingsLib/res/layout/usage_bottom_label.xml deleted file mode 100644 index 6c168806338e..000000000000 --- a/packages/SettingsLib/res/layout/usage_bottom_label.xml +++ /dev/null @@ -1,20 +0,0 @@ -<!-- - 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. ---> -<TextView - xmlns:android="http://schemas.android.com/apk/res/android" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:textAppearance="?android:attr/textAppearanceSmall" /> diff --git a/packages/SettingsLib/res/layout/usage_side_label.xml b/packages/SettingsLib/res/layout/usage_side_label.xml deleted file mode 100644 index 6c168806338e..000000000000 --- a/packages/SettingsLib/res/layout/usage_side_label.xml +++ /dev/null @@ -1,20 +0,0 @@ -<!-- - 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. ---> -<TextView - xmlns:android="http://schemas.android.com/apk/res/android" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:textAppearance="?android:attr/textAppearanceSmall" /> diff --git a/packages/SettingsLib/res/layout/usage_view.xml b/packages/SettingsLib/res/layout/usage_view.xml deleted file mode 100644 index da66814f49cb..000000000000 --- a/packages/SettingsLib/res/layout/usage_view.xml +++ /dev/null @@ -1,99 +0,0 @@ -<!-- - 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. ---> -<LinearLayout - xmlns:android="http://schemas.android.com/apk/res/android" - android:layout_width="match_parent" - android:layout_height="wrap_content" - android:orientation="vertical"> - - <LinearLayout - android:id="@+id/graph_label_group" - android:layout_width="match_parent" - android:layout_height="0dp" - android:layout_weight="1" - android:orientation="horizontal" - android:clipChildren="false" - android:clipToPadding="false"> - - <LinearLayout - android:id="@+id/label_group" - android:layout_width="@dimen/usage_graph_labels_width" - android:layout_height="match_parent" - android:orientation="vertical"> - - <include android:id="@+id/label_top" - layout="@layout/usage_side_label" /> - - <Space - android:id="@+id/space1" - android:layout_width="wrap_content" - android:layout_height="0dp" - android:layout_weight="1" /> - - <include android:id="@+id/label_middle" - layout="@layout/usage_side_label" /> - - <Space - android:id="@+id/space2" - android:layout_width="wrap_content" - android:layout_height="0dp" - android:layout_weight="1" /> - - <include android:id="@+id/label_bottom" - layout="@layout/usage_side_label" /> - - </LinearLayout> - - <com.android.settingslib.graph.UsageGraph - android:id="@+id/usage_graph" - android:layout_width="match_parent" - android:layout_height="match_parent" - android:layout_weight="1" - android:layout_marginTop="@dimen/usage_graph_margin_top_bottom" - android:layout_marginBottom="@dimen/usage_graph_margin_top_bottom" /> - - </LinearLayout> - - <LinearLayout - android:id="@+id/bottom_label_group" - android:layout_width="match_parent" - android:layout_height="wrap_content" - android:orientation="horizontal"> - <Space - android:id="@+id/bottom_label_space" - android:layout_width="@dimen/usage_graph_labels_width" - android:layout_height="wrap_content"/> - <com.android.settingslib.graph.BottomLabelLayout - android:layout_width="0dp" - android:layout_height="wrap_content" - android:layout_weight="1" - android:orientation="horizontal" - android:layoutDirection="ltr"> - <include android:id="@+id/label_start" - layout="@layout/usage_side_label" /> - - <Space - android:id="@+id/spacer" - android:layout_width="40dp" - android:layout_height="wrap_content" - android:layout_weight="1" /> - - <include android:id="@+id/label_end" - layout="@layout/usage_side_label" /> - </com.android.settingslib.graph.BottomLabelLayout> - </LinearLayout> - -</LinearLayout> diff --git a/packages/SettingsLib/res/values/attrs.xml b/packages/SettingsLib/res/values/attrs.xml index c931722b0963..a8a179358744 100644 --- a/packages/SettingsLib/res/values/attrs.xml +++ b/packages/SettingsLib/res/values/attrs.xml @@ -46,14 +46,6 @@ <attr name="wifi_signal" format="reference" /> <attr name="wifi_friction" format="reference" /> - <declare-styleable name="UsageView"> - <attr name="android:colorAccent" /> - <attr name="sideLabels" format="reference" /> - <attr name="bottomLabels" format="reference" /> - <attr name="textColor" format="color" /> - <attr name="android:gravity" /> - </declare-styleable> - <attr name="footerPreferenceStyle" format="reference" /> </resources> diff --git a/packages/SettingsLib/src/com/android/settingslib/graph/BottomLabelLayout.java b/packages/SettingsLib/src/com/android/settingslib/graph/BottomLabelLayout.java deleted file mode 100644 index 8161dd4bb934..000000000000 --- a/packages/SettingsLib/src/com/android/settingslib/graph/BottomLabelLayout.java +++ /dev/null @@ -1,97 +0,0 @@ -/* - * Copyright (C) 2017 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.settingslib.graph; - -import android.annotation.Nullable; -import android.content.Context; -import android.support.annotation.VisibleForTesting; -import android.util.AttributeSet; -import android.view.Gravity; -import android.view.View; -import android.widget.LinearLayout; - -import com.android.settingslib.R; - -/** - * An extension of LinearLayout that automatically switches to vertical - * orientation when it can't fit its child views horizontally. - * - * Main logic in this class comes from {@link android.support.v7.widget.ButtonBarLayout}. - * Compared with {@link android.support.v7.widget.ButtonBarLayout}, this layout won't reverse - * children's order and won't update the minimum height - */ -public class BottomLabelLayout extends LinearLayout { - private static final String TAG = "BottomLabelLayout"; - - public BottomLabelLayout(Context context, - @Nullable AttributeSet attrs) { - super(context, attrs); - } - - @Override - protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { - final int widthSize = MeasureSpec.getSize(widthMeasureSpec); - final boolean isStacked = isStacked(); - boolean needsRemeasure = false; - - // If we're not stacked, make sure the measure spec is AT_MOST rather - // than EXACTLY. This ensures that we'll still get TOO_SMALL so that we - // know to stack the buttons. - final int initialWidthMeasureSpec; - if (!isStacked && MeasureSpec.getMode(widthMeasureSpec) == MeasureSpec.EXACTLY) { - initialWidthMeasureSpec = MeasureSpec.makeMeasureSpec(widthSize, MeasureSpec.AT_MOST); - - // We'll need to remeasure again to fill excess space. - needsRemeasure = true; - } else { - initialWidthMeasureSpec = widthMeasureSpec; - } - - super.onMeasure(initialWidthMeasureSpec, heightMeasureSpec); - if (!isStacked) { - final int measuredWidth = getMeasuredWidthAndState(); - final int measuredWidthState = measuredWidth & View.MEASURED_STATE_MASK; - - if (measuredWidthState == View.MEASURED_STATE_TOO_SMALL) { - setStacked(true); - // Measure again in the new orientation. - needsRemeasure = true; - } - } - - if (needsRemeasure) { - super.onMeasure(widthMeasureSpec, heightMeasureSpec); - } - - } - - @VisibleForTesting - void setStacked(boolean stacked) { - setOrientation(stacked ? LinearLayout.VERTICAL : LinearLayout.HORIZONTAL); - setGravity(stacked ? Gravity.START : Gravity.BOTTOM); - - final View spacer = findViewById(R.id.spacer); - if (spacer != null) { - spacer.setVisibility(stacked ? View.GONE : View.VISIBLE); - } - } - - private boolean isStacked() { - return getOrientation() == LinearLayout.VERTICAL; - } -} diff --git a/packages/SettingsLib/src/com/android/settingslib/graph/UsageGraph.java b/packages/SettingsLib/src/com/android/settingslib/graph/UsageGraph.java deleted file mode 100644 index 1fff0fbb3f61..000000000000 --- a/packages/SettingsLib/src/com/android/settingslib/graph/UsageGraph.java +++ /dev/null @@ -1,277 +0,0 @@ -/* - * Copyright (C) 2016 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file - * except in compliance with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software distributed under the - * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - -package com.android.settingslib.graph; - -import android.annotation.Nullable; -import android.content.Context; -import android.content.res.Resources; -import android.graphics.Canvas; -import android.graphics.CornerPathEffect; -import android.graphics.DashPathEffect; -import android.graphics.LinearGradient; -import android.graphics.Paint; -import android.graphics.Paint.Cap; -import android.graphics.Paint.Join; -import android.graphics.Paint.Style; -import android.graphics.Path; -import android.graphics.Shader.TileMode; -import android.graphics.drawable.Drawable; -import android.util.AttributeSet; -import android.util.SparseIntArray; -import android.util.TypedValue; -import android.view.View; -import com.android.settingslib.R; - -public class UsageGraph extends View { - - private static final int PATH_DELIM = -1; - - private final Paint mLinePaint; - private final Paint mFillPaint; - private final Paint mDottedPaint; - - private final Drawable mDivider; - private final Drawable mTintedDivider; - private final int mDividerSize; - - private final Path mPath = new Path(); - - // Paths in coordinates they are passed in. - private final SparseIntArray mPaths = new SparseIntArray(); - // Paths in local coordinates for drawing. - private final SparseIntArray mLocalPaths = new SparseIntArray(); - private final int mCornerRadius; - - private int mAccentColor; - private boolean mShowProjection; - private boolean mProjectUp; - - private float mMaxX = 100; - private float mMaxY = 100; - - private float mMiddleDividerLoc = .5f; - private int mMiddleDividerTint = -1; - private int mTopDividerTint = -1; - - public UsageGraph(Context context, @Nullable AttributeSet attrs) { - super(context, attrs); - final Resources resources = context.getResources(); - - mLinePaint = new Paint(); - mLinePaint.setStyle(Style.STROKE); - mLinePaint.setStrokeCap(Cap.ROUND); - mLinePaint.setStrokeJoin(Join.ROUND); - mLinePaint.setAntiAlias(true); - mCornerRadius = resources.getDimensionPixelSize(R.dimen.usage_graph_line_corner_radius); - mLinePaint.setPathEffect(new CornerPathEffect(mCornerRadius)); - mLinePaint.setStrokeWidth(resources.getDimensionPixelSize(R.dimen.usage_graph_line_width)); - - mFillPaint = new Paint(mLinePaint); - mFillPaint.setStyle(Style.FILL); - - mDottedPaint = new Paint(mLinePaint); - mDottedPaint.setStyle(Style.STROKE); - float dots = resources.getDimensionPixelSize(R.dimen.usage_graph_dot_size); - float interval = resources.getDimensionPixelSize(R.dimen.usage_graph_dot_interval); - mDottedPaint.setStrokeWidth(dots * 3); - mDottedPaint.setPathEffect(new DashPathEffect(new float[] {dots, interval}, 0)); - mDottedPaint.setColor(context.getColor(R.color.usage_graph_dots)); - - TypedValue v = new TypedValue(); - context.getTheme().resolveAttribute(com.android.internal.R.attr.listDivider, v, true); - mDivider = context.getDrawable(v.resourceId); - mTintedDivider = context.getDrawable(v.resourceId); - mDividerSize = resources.getDimensionPixelSize(R.dimen.usage_graph_divider_size); - } - - void clearPaths() { - mPaths.clear(); - } - - void setMax(int maxX, int maxY) { - mMaxX = maxX; - mMaxY = maxY; - } - - void setDividerLoc(int height) { - mMiddleDividerLoc = 1 - height / mMaxY; - } - - void setDividerColors(int middleColor, int topColor) { - mMiddleDividerTint = middleColor; - mTopDividerTint = topColor; - } - - public void addPath(SparseIntArray points) { - for (int i = 0; i < points.size(); i++) { - mPaths.put(points.keyAt(i), points.valueAt(i)); - } - mPaths.put(points.keyAt(points.size() - 1) + 1, PATH_DELIM); - calculateLocalPaths(); - postInvalidate(); - } - - void setAccentColor(int color) { - mAccentColor = color; - mLinePaint.setColor(mAccentColor); - updateGradient(); - postInvalidate(); - } - - void setShowProjection(boolean showProjection, boolean projectUp) { - mShowProjection = showProjection; - mProjectUp = projectUp; - postInvalidate(); - } - - @Override - protected void onSizeChanged(int w, int h, int oldw, int oldh) { - super.onSizeChanged(w, h, oldw, oldh); - updateGradient(); - calculateLocalPaths(); - } - - private void calculateLocalPaths() { - if (getWidth() == 0) return; - mLocalPaths.clear(); - int pendingXLoc = 0; - int pendingYLoc = PATH_DELIM; - for (int i = 0; i < mPaths.size(); i++) { - int x = mPaths.keyAt(i); - int y = mPaths.valueAt(i); - if (y == PATH_DELIM) { - if (i == mPaths.size() - 1 && pendingYLoc != PATH_DELIM) { - // Connect to the end of the graph. - mLocalPaths.put(pendingXLoc, pendingYLoc); - } - // Clear out any pending points. - pendingYLoc = PATH_DELIM; - mLocalPaths.put(pendingXLoc + 1, PATH_DELIM); - } else { - final int lx = getX(x); - final int ly = getY(y); - pendingXLoc = lx; - if (mLocalPaths.size() > 0) { - int lastX = mLocalPaths.keyAt(mLocalPaths.size() - 1); - int lastY = mLocalPaths.valueAt(mLocalPaths.size() - 1); - if (lastY != PATH_DELIM && !hasDiff(lastX, lx) && !hasDiff(lastY, ly)) { - pendingYLoc = ly; - continue; - } - } - mLocalPaths.put(lx, ly); - } - } - } - - private boolean hasDiff(int x1, int x2) { - return Math.abs(x2 - x1) >= mCornerRadius; - } - - private int getX(float x) { - return (int) (x / mMaxX * getWidth()); - } - - private int getY(float y) { - return (int) (getHeight() * (1 - (y / mMaxY))); - } - - private void updateGradient() { - mFillPaint.setShader(new LinearGradient(0, 0, 0, getHeight(), - getColor(mAccentColor, .2f), 0, TileMode.CLAMP)); - } - - private int getColor(int color, float alphaScale) { - return (color & (((int) (0xff * alphaScale) << 24) | 0xffffff)); - } - - @Override - protected void onDraw(Canvas canvas) { - // Draw lines across the top, middle, and bottom. - if (mMiddleDividerLoc != 0) { - drawDivider(0, canvas, mTopDividerTint); - } - drawDivider((int) ((canvas.getHeight() - mDividerSize) * mMiddleDividerLoc), canvas, - mMiddleDividerTint); - drawDivider(canvas.getHeight() - mDividerSize, canvas, -1); - - if (mLocalPaths.size() == 0) { - return; - } - if (mShowProjection) { - drawProjection(canvas); - } - drawFilledPath(canvas); - drawLinePath(canvas); - } - - private void drawProjection(Canvas canvas) { - mPath.reset(); - int x = mLocalPaths.keyAt(mLocalPaths.size() - 2); - int y = mLocalPaths.valueAt(mLocalPaths.size() - 2); - mPath.moveTo(x, y); - mPath.lineTo(canvas.getWidth(), mProjectUp ? 0 : canvas.getHeight()); - canvas.drawPath(mPath, mDottedPaint); - } - - private void drawLinePath(Canvas canvas) { - mPath.reset(); - mPath.moveTo(mLocalPaths.keyAt(0), mLocalPaths.valueAt(0)); - for (int i = 1; i < mLocalPaths.size(); i++) { - int x = mLocalPaths.keyAt(i); - int y = mLocalPaths.valueAt(i); - if (y == PATH_DELIM) { - if (++i < mLocalPaths.size()) { - mPath.moveTo(mLocalPaths.keyAt(i), mLocalPaths.valueAt(i)); - } - } else { - mPath.lineTo(x, y); - } - } - canvas.drawPath(mPath, mLinePaint); - } - - private void drawFilledPath(Canvas canvas) { - mPath.reset(); - float lastStartX = mLocalPaths.keyAt(0); - mPath.moveTo(mLocalPaths.keyAt(0), mLocalPaths.valueAt(0)); - for (int i = 1; i < mLocalPaths.size(); i++) { - int x = mLocalPaths.keyAt(i); - int y = mLocalPaths.valueAt(i); - if (y == PATH_DELIM) { - mPath.lineTo(mLocalPaths.keyAt(i - 1), getHeight()); - mPath.lineTo(lastStartX, getHeight()); - mPath.close(); - if (++i < mLocalPaths.size()) { - lastStartX = mLocalPaths.keyAt(i); - mPath.moveTo(mLocalPaths.keyAt(i), mLocalPaths.valueAt(i)); - } - } else { - mPath.lineTo(x, y); - } - } - canvas.drawPath(mPath, mFillPaint); - } - - private void drawDivider(int y, Canvas canvas, int tintColor) { - Drawable d = mDivider; - if (tintColor != -1) { - mTintedDivider.setTint(tintColor); - d = mTintedDivider; - } - d.setBounds(0, y, canvas.getWidth(), y + mDividerSize); - d.draw(canvas); - } -} diff --git a/packages/SettingsLib/src/com/android/settingslib/graph/UsageView.java b/packages/SettingsLib/src/com/android/settingslib/graph/UsageView.java deleted file mode 100644 index e2c05a193882..000000000000 --- a/packages/SettingsLib/src/com/android/settingslib/graph/UsageView.java +++ /dev/null @@ -1,141 +0,0 @@ -/* - * Copyright (C) 2016 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file - * except in compliance with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software distributed under the - * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - -package com.android.settingslib.graph; - -import android.content.Context; -import android.content.res.TypedArray; -import android.util.AttributeSet; -import android.util.SparseIntArray; -import android.view.Gravity; -import android.view.LayoutInflater; -import android.view.View; -import android.widget.FrameLayout; -import android.widget.LinearLayout; -import android.widget.TextView; -import com.android.settingslib.R; - -public class UsageView extends FrameLayout { - - private final UsageGraph mUsageGraph; - private final TextView[] mLabels; - private final TextView[] mBottomLabels; - - public UsageView(Context context, AttributeSet attrs) { - super(context, attrs); - LayoutInflater.from(context).inflate(R.layout.usage_view, this); - mUsageGraph = findViewById(R.id.usage_graph); - mLabels = new TextView[] { - findViewById(R.id.label_bottom), - findViewById(R.id.label_middle), - findViewById(R.id.label_top), - }; - mBottomLabels = new TextView[] { - findViewById(R.id.label_start), - findViewById(R.id.label_end), - }; - TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.UsageView, 0, 0); - if (a.hasValue(R.styleable.UsageView_sideLabels)) { - setSideLabels(a.getTextArray(R.styleable.UsageView_sideLabels)); - } - if (a.hasValue(R.styleable.UsageView_bottomLabels)) { - setBottomLabels(a.getTextArray(R.styleable.UsageView_bottomLabels)); - } - if (a.hasValue(R.styleable.UsageView_textColor)) { - int color = a.getColor(R.styleable.UsageView_textColor, 0); - for (TextView v : mLabels) { - v.setTextColor(color); - } - for (TextView v : mBottomLabels) { - v.setTextColor(color); - } - } - if (a.hasValue(R.styleable.UsageView_android_gravity)) { - int gravity = a.getInt(R.styleable.UsageView_android_gravity, 0); - if (gravity == Gravity.END) { - LinearLayout layout = findViewById(R.id.graph_label_group); - LinearLayout labels = findViewById(R.id.label_group); - // Swap the children order. - layout.removeView(labels); - layout.addView(labels); - // Set gravity. - labels.setGravity(Gravity.END); - // Swap the bottom space order. - LinearLayout bottomLabels = findViewById(R.id.bottom_label_group); - View bottomSpace = bottomLabels.findViewById(R.id.bottom_label_space); - bottomLabels.removeView(bottomSpace); - bottomLabels.addView(bottomSpace); - } else if (gravity != Gravity.START) { - throw new IllegalArgumentException("Unsupported gravity " + gravity); - } - } - mUsageGraph.setAccentColor(a.getColor(R.styleable.UsageView_android_colorAccent, 0)); - } - - public void clearPaths() { - mUsageGraph.clearPaths(); - } - - public void addPath(SparseIntArray points) { - mUsageGraph.addPath(points); - } - - public void configureGraph(int maxX, int maxY, boolean showProjection, boolean projectUp) { - mUsageGraph.setMax(maxX, maxY); - mUsageGraph.setShowProjection(showProjection, projectUp); - } - - public void setAccentColor(int color) { - mUsageGraph.setAccentColor(color); - } - - public void setDividerLoc(int dividerLoc) { - mUsageGraph.setDividerLoc(dividerLoc); - } - - public void setDividerColors(int middleColor, int topColor) { - mUsageGraph.setDividerColors(middleColor, topColor); - } - - public void setSideLabelWeights(float before, float after) { - setWeight(R.id.space1, before); - setWeight(R.id.space2, after); - } - - private void setWeight(int id, float weight) { - View v = findViewById(id); - LinearLayout.LayoutParams params = (LinearLayout.LayoutParams) v.getLayoutParams(); - params.weight = weight; - v.setLayoutParams(params); - } - - public void setSideLabels(CharSequence[] labels) { - if (labels.length != mLabels.length) { - throw new IllegalArgumentException("Invalid number of labels"); - } - for (int i = 0; i < mLabels.length; i++) { - mLabels[i].setText(labels[i]); - } - } - - public void setBottomLabels(CharSequence[] labels) { - if (labels.length != mBottomLabels.length) { - throw new IllegalArgumentException("Invalid number of labels"); - } - for (int i = 0; i < mBottomLabels.length; i++) { - mBottomLabels[i].setText(labels[i]); - } - } - -} diff --git a/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java b/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java index b3565eab79c9..c55280dc1c3e 100644 --- a/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java +++ b/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java @@ -16,6 +16,7 @@ package com.android.settingslib.wifi; +import android.annotation.Nullable; import android.app.AppGlobals; import android.content.Context; import android.content.pm.ApplicationInfo; @@ -639,6 +640,13 @@ public class AccessPoint implements Comparable<AccessPoint> { // Update to new summary StringBuilder summary = new StringBuilder(); + // TODO(b/62354743): Standardize and international delimiter usage + final String concatenator = " / "; + + if (mBadge != NetworkBadging.BADGING_NONE) { + summary.append(getSpeedLabel() + concatenator); + } + if (isActive() && config != null && config.isPasspoint()) { // This is the active connection on passpoint summary.append(getSummary(mContext, getDetailedState(), @@ -718,6 +726,14 @@ public class AccessPoint implements Comparable<AccessPoint> { } } } + + // Strip trailing delimiter if applicable + int concatLength = concatenator.length(); + if (summary.length() >= concatLength && summary.substring( + summary.length() - concatLength, summary.length()).equals(concatenator)) { + summary.delete(summary.length() - concatLength, summary.length()); + } + return summary.toString(); } @@ -745,8 +761,12 @@ public class AccessPoint implements Comparable<AccessPoint> { visibility.append(" rssi=").append(mInfo.getRssi()); visibility.append(" "); visibility.append(" score=").append(mInfo.score); - visibility.append(" rankingScore=").append(getRankingScore()); - visibility.append(" badge=").append(getBadge()); + if (mRankingScore != Integer.MIN_VALUE) { + visibility.append(" rankingScore=").append(getRankingScore()); + } + if (mBadge != NetworkBadging.BADGING_NONE) { + visibility.append(" speed=").append(getSpeedLabel()); + } visibility.append(String.format(" tx=%.1f,", mInfo.txSuccessRate)); visibility.append(String.format("%.1f,", mInfo.txRetriesRate)); visibility.append(String.format("%.1f ", mInfo.txBadRate)); @@ -1042,8 +1062,21 @@ public class AccessPoint implements Comparable<AccessPoint> { return mRankingScore; } - int getBadge() { - return mBadge; + int getBadge() { return mBadge;} + + @Nullable + String getSpeedLabel() { + switch (mBadge) { + case NetworkBadging.BADGING_4K: + return mContext.getString(R.string.speed_label_very_fast); + case NetworkBadging.BADGING_HD: + return mContext.getString(R.string.speed_label_fast); + case NetworkBadging.BADGING_SD: + return mContext.getString(R.string.speed_label_okay); + case NetworkBadging.BADGING_NONE: + default: + return null; + } } /** Return true if the current RSSI is reachable, and false otherwise. */ diff --git a/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPointPreference.java b/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPointPreference.java index 5361b4302b0d..f37590ec8c63 100644 --- a/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPointPreference.java +++ b/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPointPreference.java @@ -162,7 +162,10 @@ public class AccessPointPreference extends Preference { return; } TronUtils.logWifiSettingsBadge(context, mWifiBadge); - Drawable drawable = NetworkBadging.getWifiIcon(level, mWifiBadge, getContext().getTheme()); + + // TODO(b/62355275): Revert this to N code after deleting NetworkBadging API + Drawable drawable = NetworkBadging.getWifiIcon( + level, NetworkBadging.BADGING_NONE, getContext().getTheme()); if (!mForSavedNetworks && drawable != null) { drawable.setTint(Utils.getColorAttr(context, android.R.attr.colorControlNormal)); setIcon(drawable); diff --git a/packages/SettingsLib/tests/integ/src/com/android/settingslib/wifi/AccessPointTest.java b/packages/SettingsLib/tests/integ/src/com/android/settingslib/wifi/AccessPointTest.java index 801844be87cd..9abdf88d42fb 100644 --- a/packages/SettingsLib/tests/integ/src/com/android/settingslib/wifi/AccessPointTest.java +++ b/packages/SettingsLib/tests/integ/src/com/android/settingslib/wifi/AccessPointTest.java @@ -19,12 +19,17 @@ import static com.google.common.truth.Truth.assertThat; import static com.google.common.truth.Truth.assertWithMessage; import static org.mockito.Mockito.any; +import static org.mockito.Mockito.anyInt; import static org.mockito.Mockito.when; import android.content.Context; import android.net.ConnectivityManager; +import android.net.NetworkBadging; import android.net.NetworkInfo; +import android.net.NetworkKey; +import android.net.RssiCurve; import android.net.ScoredNetwork; +import android.net.WifiKey; import android.net.wifi.ScanResult; import android.net.wifi.WifiConfiguration; import android.net.wifi.WifiInfo; @@ -40,6 +45,8 @@ import android.support.test.runner.AndroidJUnit4; import android.text.SpannableString; import android.text.style.TtsSpan; +import com.android.settingslib.R; + import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; @@ -55,7 +62,8 @@ public class AccessPointTest { private static final String TEST_SSID = "test_ssid"; private Context mContext; - @Mock private WifiNetworkScoreCache mWifiNetworkScoreCache; + @Mock private RssiCurve mockBadgeCurve; + @Mock private WifiNetworkScoreCache mockWifiNetworkScoreCache; @Before public void setUp() { @@ -294,13 +302,13 @@ public class AccessPointTest { public void testIsMetered_returnTrueWhenScoredNetworkIsMetered() { AccessPoint ap = createAccessPointWithScanResultCache(); - when(mWifiNetworkScoreCache.getScoredNetwork(any(ScanResult.class))) + when(mockWifiNetworkScoreCache.getScoredNetwork(any(ScanResult.class))) .thenReturn( new ScoredNetwork( null /* NetworkKey */, null /* rssiCurve */, true /* metered */)); - ap.update(mWifiNetworkScoreCache, false /* scoringUiEnabled */); + ap.update(mockWifiNetworkScoreCache, false /* scoringUiEnabled */); assertThat(ap.isMetered()).isTrue(); } @@ -321,6 +329,91 @@ public class AccessPointTest { assertThat(accessPoint.isMetered()).isFalse(); } + @Test + public void testSpeedLabel_returnsVeryFastWhen4kBadgeIsSet() { + AccessPoint ap = createAccessPointWithScanResultCache(); + + when(mockWifiNetworkScoreCache.getScoredNetwork(any(ScanResult.class))) + .thenReturn(buildScoredNetworkWithMockBadgeCurve()); + when(mockBadgeCurve.lookupScore(anyInt())).thenReturn((byte) NetworkBadging.BADGING_4K); + + ap.update(mockWifiNetworkScoreCache, true /* scoringUiEnabled */); + + assertThat(ap.getBadge()).isEqualTo(NetworkBadging.BADGING_4K); + assertThat(ap.getSpeedLabel()) + .isEqualTo(mContext.getString(R.string.speed_label_very_fast)); + } + + @Test + public void testSpeedLabel_returnsFastWhenHdBadgeIsSet() { + AccessPoint ap = createAccessPointWithScanResultCache(); + + when(mockWifiNetworkScoreCache.getScoredNetwork(any(ScanResult.class))) + .thenReturn(buildScoredNetworkWithMockBadgeCurve()); + when(mockBadgeCurve.lookupScore(anyInt())).thenReturn((byte) NetworkBadging.BADGING_HD); + + ap.update(mockWifiNetworkScoreCache, true /* scoringUiEnabled */); + + assertThat(ap.getBadge()).isEqualTo(NetworkBadging.BADGING_HD); + assertThat(ap.getSpeedLabel()) + .isEqualTo(mContext.getString(R.string.speed_label_fast)); + } + + @Test + public void testSpeedLabel_returnsOkayWhenSdBadgeIsSet() { + AccessPoint ap = createAccessPointWithScanResultCache(); + + when(mockWifiNetworkScoreCache.getScoredNetwork(any(ScanResult.class))) + .thenReturn(buildScoredNetworkWithMockBadgeCurve()); + when(mockBadgeCurve.lookupScore(anyInt())).thenReturn((byte) NetworkBadging.BADGING_SD); + + ap.update(mockWifiNetworkScoreCache, true /* scoringUiEnabled */); + + assertThat(ap.getBadge()).isEqualTo(NetworkBadging.BADGING_SD); + assertThat(ap.getSpeedLabel()) + .isEqualTo(mContext.getString(R.string.speed_label_okay)); + } + + @Test + public void testSummaryString_showsSpeedLabel() { + AccessPoint ap = createAccessPointWithScanResultCache(); + + when(mockWifiNetworkScoreCache.getScoredNetwork(any(ScanResult.class))) + .thenReturn(buildScoredNetworkWithMockBadgeCurve()); + when(mockBadgeCurve.lookupScore(anyInt())).thenReturn((byte) NetworkBadging.BADGING_4K); + + ap.update(mockWifiNetworkScoreCache, true /* scoringUiEnabled */); + + assertThat(ap.getSummary()).isEqualTo(mContext.getString(R.string.speed_label_very_fast)); + } + + @Test + public void testSummaryString_concatenatesSpeedLabel() { + AccessPoint ap = createAccessPointWithScanResultCache(); + ap.update(new WifiConfiguration()); + + when(mockWifiNetworkScoreCache.getScoredNetwork(any(ScanResult.class))) + .thenReturn(buildScoredNetworkWithMockBadgeCurve()); + when(mockBadgeCurve.lookupScore(anyInt())).thenReturn((byte) NetworkBadging.BADGING_4K); + + ap.update(mockWifiNetworkScoreCache, true /* scoringUiEnabled */); + + String expectedString = mContext.getString(R.string.speed_label_very_fast) + " / " + + mContext.getString(R.string.wifi_remembered); + assertThat(ap.getSummary()).isEqualTo(expectedString); + } + + private ScoredNetwork buildScoredNetworkWithMockBadgeCurve() { + Bundle attr1 = new Bundle(); + attr1.putParcelable(ScoredNetwork.ATTRIBUTES_KEY_BADGING_CURVE, mockBadgeCurve); + return new ScoredNetwork( + new NetworkKey(new WifiKey("\"ssid\"", "00:00:00:00:00:00")), + mockBadgeCurve, + false /* meteredHint */, + attr1); + + } + private AccessPoint createAccessPointWithScanResultCache() { Bundle bundle = new Bundle(); ArrayList<ScanResult> scanResults = new ArrayList<>(); @@ -333,7 +426,7 @@ public class AccessPointTest { scanResults.add(scanResult); } - bundle.putParcelableArrayList("key_scanresultcache", scanResults); + bundle.putParcelableArrayList(AccessPoint.KEY_SCANRESULTCACHE, scanResults); return new AccessPoint(mContext, bundle); } diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/graph/BottomLabelLayoutTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/graph/BottomLabelLayoutTest.java deleted file mode 100644 index ec217230af95..000000000000 --- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/graph/BottomLabelLayoutTest.java +++ /dev/null @@ -1,70 +0,0 @@ -/* - * Copyright (C) 2017 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.settingslib.graph; - -import static com.google.common.truth.Truth.assertThat; - -import android.content.Context; -import android.view.View; -import android.widget.LinearLayout; -import android.widget.Space; - -import com.android.settingslib.R; -import com.android.settingslib.TestConfig; - -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.robolectric.RobolectricTestRunner; -import org.robolectric.RuntimeEnvironment; -import org.robolectric.annotation.Config; - -@RunWith(RobolectricTestRunner.class) -@Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION) -public class BottomLabelLayoutTest { - private BottomLabelLayout mBottomLabelLayout; - private Context mContext; - private Space mSpace; - - @Before - public void setUp() { - mContext = RuntimeEnvironment.application; - mBottomLabelLayout = new BottomLabelLayout(mContext, null); - mBottomLabelLayout.setOrientation(LinearLayout.HORIZONTAL); - - mSpace = new Space(mContext); - mSpace.setId(R.id.spacer); - mBottomLabelLayout.addView(mSpace); - } - - @Test - public void testSetStacked_stackedTrue_layoutVertical() { - mBottomLabelLayout.setStacked(true); - - assertThat(mBottomLabelLayout.getOrientation()).isEqualTo(LinearLayout.VERTICAL); - assertThat(mSpace.getVisibility()).isEqualTo(View.GONE); - } - - @Test - public void testSetStacked_stackedFalse_layoutHorizontal() { - mBottomLabelLayout.setStacked(false); - - assertThat(mBottomLabelLayout.getOrientation()).isEqualTo(LinearLayout.HORIZONTAL); - assertThat(mSpace.getVisibility()).isEqualTo(View.VISIBLE); - } -} diff --git a/packages/SystemUI/colorextraction/src/com/google/android/colorextraction/ColorExtractor.java b/packages/SystemUI/colorextraction/src/com/google/android/colorextraction/ColorExtractor.java index 1b3519b1d4c2..4a5d8b460517 100644 --- a/packages/SystemUI/colorextraction/src/com/google/android/colorextraction/ColorExtractor.java +++ b/packages/SystemUI/colorextraction/src/com/google/android/colorextraction/ColorExtractor.java @@ -19,9 +19,10 @@ package com.google.android.colorextraction; import android.app.WallpaperColors; import android.app.WallpaperManager; import android.content.Context; -import android.graphics.Color; -import android.support.v4.graphics.ColorUtils; +import android.support.annotation.NonNull; +import android.support.annotation.VisibleForTesting; import android.util.Log; +import android.util.SparseArray; import com.google.android.colorextraction.types.ExtractionType; import com.google.android.colorextraction.types.Tonal; @@ -32,81 +33,143 @@ import java.util.ArrayList; * Class to process wallpaper colors and generate a tonal palette based on them. */ public class ColorExtractor implements WallpaperManager.OnColorsChangedListener { + + public static final int TYPE_NORMAL = 0; + public static final int TYPE_DARK = 1; + public static final int TYPE_EXTRA_DARK = 2; + private static final int[] sGradientTypes = new int[]{TYPE_NORMAL, TYPE_DARK, TYPE_EXTRA_DARK}; + private static final String TAG = "ColorExtractor"; - private static final int FALLBACK_COLOR = Color.BLACK; - private static final float DARK_TEXT_LUMINOSITY = 0.7f; + + @VisibleForTesting + static final int FALLBACK_COLOR = 0xff83888d; private int mMainFallbackColor = FALLBACK_COLOR; private int mSecondaryFallbackColor = FALLBACK_COLOR; - private final GradientColors mSystemColors; - private final GradientColors mLockColors; + private final SparseArray<GradientColors[]> mGradientColors; + private final ArrayList<OnColorsChangedListener> mOnColorsChangedListeners; + // Colors to return when the wallpaper isn't visible + private final GradientColors mWpHiddenColors; private final Context mContext; private final ExtractionType mExtractionType; - private final ArrayList<OnColorsChangedListener> mOnColorsChangedListeners; public ColorExtractor(Context context) { + this(context, new Tonal()); + } + + @VisibleForTesting + public ColorExtractor(Context context, ExtractionType extractionType) { mContext = context; - mSystemColors = new GradientColors(); - mLockColors = new GradientColors(); - mExtractionType = new Tonal(); + mWpHiddenColors = new GradientColors(); + mWpHiddenColors.setMainColor(FALLBACK_COLOR); + mWpHiddenColors.setSecondaryColor(FALLBACK_COLOR); + mExtractionType = extractionType; + + mGradientColors = new SparseArray<>(); + for (int which : new int[] { WallpaperManager.FLAG_LOCK, WallpaperManager.FLAG_SYSTEM}) { + GradientColors[] colors = new GradientColors[sGradientTypes.length]; + mGradientColors.append(which, colors); + for (int type : sGradientTypes) { + colors[type] = new GradientColors(); + } + } + mOnColorsChangedListeners = new ArrayList<>(); WallpaperManager wallpaperManager = mContext.getSystemService(WallpaperManager.class); - if (wallpaperManager == null) { Log.w(TAG, "Can't listen to color changes!"); } else { wallpaperManager.addOnColorsChangedListener(this); + + // Initialize all gradients with the current colors + GradientColors[] systemColors = mGradientColors.get(WallpaperManager.FLAG_SYSTEM); extractInto(wallpaperManager.getWallpaperColors(WallpaperManager.FLAG_SYSTEM), - mSystemColors); + systemColors[TYPE_NORMAL], + systemColors[TYPE_DARK], + systemColors[TYPE_EXTRA_DARK]); + + GradientColors[] lockColors = mGradientColors.get(WallpaperManager.FLAG_LOCK); extractInto(wallpaperManager.getWallpaperColors(WallpaperManager.FLAG_LOCK), - mLockColors); + lockColors[TYPE_NORMAL], + lockColors[TYPE_DARK], + lockColors[TYPE_EXTRA_DARK]); } } + /** + * Retrieve TYPE_NORMAL gradient colors considering wallpaper visibility. + * + * @param which FLAG_LOCK or FLAG_SYSTEM + * @return colors + */ + @NonNull public GradientColors getColors(int which) { - if (which == WallpaperManager.FLAG_LOCK) { - return mLockColors; - } else if (which == WallpaperManager.FLAG_SYSTEM) { - return mSystemColors; - } else { - throw new IllegalArgumentException("which should be either FLAG_SYSTEM or FLAG_LOCK"); + return getColors(which, TYPE_NORMAL); + } + + /** + * Get current gradient colors for one of the possible gradient types + * + * @param which FLAG_LOCK or FLAG_SYSTEM + * @param type TYPE_NORMAL, TYPE_DARK or TYPE_EXTRA_DARK + * @return colors + */ + public GradientColors getColors(int which, int type) { + if (type != TYPE_NORMAL && type != TYPE_DARK && type != TYPE_EXTRA_DARK) { + throw new IllegalArgumentException( + "type should be TYPE_NORMAL, TYPE_DARK or TYPE_EXTRA_DARK"); } + if (which != WallpaperManager.FLAG_LOCK && which != WallpaperManager.FLAG_SYSTEM) { + throw new IllegalArgumentException("which should be FLAG_SYSTEM or FLAG_NORMAL"); + } + + return mGradientColors.get(which)[type]; } @Override public void onColorsChanged(WallpaperColors colors, int which) { + boolean changed = false; if ((which & WallpaperManager.FLAG_LOCK) != 0) { - extractInto(colors, mLockColors); - for (OnColorsChangedListener listener : mOnColorsChangedListeners) { - listener.onColorsChanged(mLockColors, WallpaperManager.FLAG_LOCK); - } + GradientColors[] lockColors = mGradientColors.get(WallpaperManager.FLAG_LOCK); + extractInto(colors, lockColors[TYPE_NORMAL], lockColors[TYPE_DARK], + lockColors[TYPE_EXTRA_DARK]); + + changed = true; } if ((which & WallpaperManager.FLAG_SYSTEM) != 0) { - extractInto(colors, mSystemColors); - for (OnColorsChangedListener listener : mOnColorsChangedListeners) { - listener.onColorsChanged(mSystemColors, WallpaperManager.FLAG_SYSTEM); - } + GradientColors[] systemColors = mGradientColors.get(WallpaperManager.FLAG_SYSTEM); + extractInto(colors, systemColors[TYPE_NORMAL], systemColors[TYPE_DARK], + systemColors[TYPE_EXTRA_DARK]); + changed = true; + } + + if (changed) { + triggerColorsChanged(which); + } + } + + private void triggerColorsChanged(int which) { + for (OnColorsChangedListener listener: mOnColorsChangedListeners) { + listener.onColorsChanged(this, which); } } - private void extractInto(WallpaperColors inWallpaperColors, GradientColors outGradientColors) { - applyFallback(outGradientColors); + private void extractInto(WallpaperColors inWallpaperColors, + GradientColors outGradientColorsNormal, GradientColors outGradientColorsDark, + GradientColors outGradientColorsExtraDark) { if (inWallpaperColors == null) { + applyFallback(outGradientColorsNormal); + applyFallback(outGradientColorsDark); + applyFallback(outGradientColorsExtraDark); return; } - boolean success = mExtractionType.extractInto(inWallpaperColors, outGradientColors); - if (success) { - // Updating dark text support. We're going to verify if the mean luminosity - // is greater then a threshold. - float hsl[] = new float[3]; - float meanLuminosity = 0; - ColorUtils.colorToHSL(outGradientColors.getMainColor(), hsl); - meanLuminosity += hsl[2]; - ColorUtils.colorToHSL(outGradientColors.getSecondaryColor(), hsl); - meanLuminosity += hsl[2]; - meanLuminosity /= 2; - outGradientColors.setSupportsDarkText(meanLuminosity >= DARK_TEXT_LUMINOSITY); + boolean success = mExtractionType.extractInto(inWallpaperColors, outGradientColorsNormal, + outGradientColorsDark, outGradientColorsExtraDark); + if (!success) { + applyFallback(outGradientColorsNormal); + applyFallback(outGradientColorsDark); + applyFallback(outGradientColorsExtraDark); } } @@ -123,11 +186,11 @@ public class ColorExtractor implements WallpaperManager.OnColorsChangedListener } } - public void addOnColorsChangedListener(OnColorsChangedListener listener) { + public void addOnColorsChangedListener(@NonNull OnColorsChangedListener listener) { mOnColorsChangedListeners.add(listener); } - public void removeOnColorsChangedListener(OnColorsChangedListener listener) { + public void removeOnColorsChangedListener(@NonNull OnColorsChangedListener listener) { mOnColorsChangedListeners.remove(listener); } @@ -184,9 +247,15 @@ public class ColorExtractor implements WallpaperManager.OnColorsChangedListener code = 31 * code + (mSupportsDarkText ? 0 : 1); return code; } + + @Override + public String toString() { + return "GradientColors(" + Integer.toHexString(mMainColor) + ", " + + Integer.toHexString(mSecondaryColor) + ")"; + } } public interface OnColorsChangedListener { - void onColorsChanged(GradientColors colors, int which); + void onColorsChanged(ColorExtractor colorExtractor, int which); } } diff --git a/packages/SystemUI/colorextraction/src/com/google/android/colorextraction/types/ExtractionType.java b/packages/SystemUI/colorextraction/src/com/google/android/colorextraction/types/ExtractionType.java index 36cabc999720..4c3ac3e038de 100644 --- a/packages/SystemUI/colorextraction/src/com/google/android/colorextraction/types/ExtractionType.java +++ b/packages/SystemUI/colorextraction/src/com/google/android/colorextraction/types/ExtractionType.java @@ -29,10 +29,19 @@ public interface ExtractionType { * Executes color extraction by reading WallpaperColors and setting * main and secondary colors on GradientColors. * + * Extraction is expected to happen with 3 different gradient types: + * Normal, with the main extracted colors + * Dark, with extra contrast + * ExtraDark, for places where GAR is mandatory, like the emergency dialer + * * @param inWallpaperColors where to read from - * @param outGradientColors object that should receive the colors - * @return true if successful + * @param outGradientColorsNormal object that should receive normal colors + * @param outGradientColorsDark object that should receive dark colors + * @param outGradientColorsExtraDark object that should receive extra dark colors + * @return true if successful. */ boolean extractInto(WallpaperColors inWallpaperColors, - ColorExtractor.GradientColors outGradientColors); + ColorExtractor.GradientColors outGradientColorsNormal, + ColorExtractor.GradientColors outGradientColorsDark, + ColorExtractor.GradientColors outGradientColorsExtraDark); } diff --git a/packages/SystemUI/colorextraction/src/com/google/android/colorextraction/types/Tonal.java b/packages/SystemUI/colorextraction/src/com/google/android/colorextraction/types/Tonal.java index 85ac90a53ea8..5b4b3ed77f3a 100644 --- a/packages/SystemUI/colorextraction/src/com/google/android/colorextraction/types/Tonal.java +++ b/packages/SystemUI/colorextraction/src/com/google/android/colorextraction/types/Tonal.java @@ -27,7 +27,7 @@ import android.util.MathUtils; import android.util.Pair; import android.util.Range; -import com.google.android.colorextraction.ColorExtractor; +import com.google.android.colorextraction.ColorExtractor.GradientColors; /** * Implementation of tonal color extraction @@ -43,25 +43,25 @@ public class Tonal implements ExtractionType { // When extracting the main color, only consider colors // present in at least MIN_COLOR_OCCURRENCE of the image private static final float MIN_COLOR_OCCURRENCE = 0.1f; + private static final boolean DEBUG = true; - // Secondary color will be darker than the main color when - // main color is brighter than this variable. - private static final float MAX_COLOR_LUMINOSITY = 0.8f; - // Luminosity difference between main and secondary colors - // should never be greater then this. - private static final float MAX_LUMINOSITY_DISTANCE = 0.35f; + // Temporary variable to avoid allocations + private float[] mTmpHSL = new float[3]; /** * Grab colors from WallpaperColors as set them into GradientColors * - * @param wallpaperColors input - * @param gradientColors output + * @param inWallpaperColors input + * @param outColorsNormal colors for normal theme + * @param outColorsDark colors for dar theme + * @param outColorsExtraDark colors for extra dark theme * @return true if successful */ - public boolean extractInto(WallpaperColors wallpaperColors, - ColorExtractor.GradientColors gradientColors) { + public boolean extractInto(@NonNull WallpaperColors inWallpaperColors, + @NonNull GradientColors outColorsNormal, @NonNull GradientColors outColorsDark, + @NonNull GradientColors outColorsExtraDark) { - if (wallpaperColors.getColors().size() == 0) { + if (inWallpaperColors.getColors().size() == 0) { return false; } // Tonal is not really a sort, it takes a color from the extracted @@ -70,17 +70,17 @@ public class Tonal implements ExtractionType { // and replaces the original palette // First find the most representative color in the image - populationSort(wallpaperColors); + populationSort(inWallpaperColors); // Calculate total int total = 0; - for (Pair<Color, Integer> weightedColor : wallpaperColors.getColors()) { + for (Pair<Color, Integer> weightedColor : inWallpaperColors.getColors()) { total += weightedColor.second; } // Get bright colors that occur often enough in this image Pair<Color, Integer> bestColor = null; float[] hsl = new float[3]; - for (Pair<Color, Integer> weightedColor : wallpaperColors.getColors()) { + for (Pair<Color, Integer> weightedColor : inWallpaperColors.getColors()) { float colorOccurrence = weightedColor.second / (float) total; if (colorOccurrence < MIN_COLOR_OCCURRENCE) { break; @@ -97,7 +97,7 @@ public class Tonal implements ExtractionType { } } - // Fallback to first color + // Fail if not found if (bestColor == null) { return false; } @@ -107,59 +107,97 @@ public class Tonal implements ExtractionType { hsl); // The Android HSL definition requires the hue to go from 0 to 360 but - // the Material Tonal Palette defines hues from 0 to 1 - hsl[0] /= 360.0f; // normalize + // the Material Tonal Palette defines hues from 0 to 1. + hsl[0] /= 360f; // Find the palette that contains the closest color TonalPalette palette = findTonalPalette(hsl[0]); - if (palette == null) { Log.w(TAG, "Could not find a tonal palette!"); return false; } + // Figure out what's the main color index in the optimal palette int fitIndex = bestFit(palette, hsl[0], hsl[1], hsl[2]); if (fitIndex == -1) { Log.w(TAG, "Could not find best fit!"); return false; } + + // Generate the 10 colors palette by offsetting each one of them float[] h = fit(palette.h, hsl[0], fitIndex, Float.NEGATIVE_INFINITY, Float.POSITIVE_INFINITY); float[] s = fit(palette.s, hsl[1], fitIndex, 0.0f, 1.0f); float[] l = fit(palette.l, hsl[2], fitIndex, 0.0f, 1.0f); - hsl[0] = fract(h[fitIndex]) * 360.0f; - hsl[1] = s[fitIndex]; - hsl[2] = l[fitIndex]; - gradientColors.setMainColor(ColorUtils.HSLToColor(hsl)); - - int secondColorIndex = fitIndex; - if (hsl[2] > MAX_COLOR_LUMINOSITY) { - for (int i = secondColorIndex - 1; i >= 0; i--) { - float distance = Math.abs(hsl[2] - l[i]); - if (distance > MAX_LUMINOSITY_DISTANCE) { - break; - } - secondColorIndex = i; - } - } else { - for (int i = secondColorIndex + 1; i < h.length; i++) { - float distance = Math.abs(hsl[2] - l[i]); - if (distance > MAX_LUMINOSITY_DISTANCE) { - break; + final int textInversionIndex = h.length - 3; + if (DEBUG) { + StringBuilder builder = new StringBuilder("Tonal Palette - index: " + fitIndex + + ". Main color: " + Integer.toHexString(getColorInt(fitIndex, h, s, l)) + + "\nColors: "); + + for (int i=0; i < h.length; i++) { + builder.append(Integer.toHexString(getColorInt(i, h, s, l))); + if (i < h.length - 1) { + builder.append(", "); } - secondColorIndex = i; } + Log.d(TAG, builder.toString()); } - hsl[0] = fract(h[secondColorIndex]) * 360.0f; - hsl[1] = s[secondColorIndex]; - hsl[2] = l[secondColorIndex]; - gradientColors.setSecondaryColor(ColorUtils.HSLToColor(hsl)); + // Normal colors: + // best fit + a 2 colors offset + int primaryIndex = fitIndex; + int secondaryIndex = primaryIndex + (primaryIndex >= 2 ? -2 : 2); + outColorsNormal.setMainColor(getColorInt(primaryIndex, h, s, l)); + outColorsNormal.setSecondaryColor(getColorInt(secondaryIndex, h, s, l)); + + // Dark colors: + // Stops at 4th color, only lighter if dark text is supported + if (fitIndex < 2) { + primaryIndex = 0; + } else if (fitIndex < textInversionIndex) { + primaryIndex = Math.min(fitIndex, 3); + } else { + primaryIndex = h.length - 1; + } + secondaryIndex = primaryIndex + (primaryIndex >= 2 ? -2 : 2); + outColorsDark.setMainColor(getColorInt(primaryIndex, h, s, l)); + outColorsDark.setSecondaryColor(getColorInt(secondaryIndex, h, s, l)); + + // Extra Dark: + // Stay close to dark colors until dark text is supported + if (fitIndex < 2) { + primaryIndex = 0; + } else if (fitIndex < textInversionIndex) { + primaryIndex = 2; + } else { + primaryIndex = h.length - 1; + } + secondaryIndex = primaryIndex + (primaryIndex >= 2 ? -2 : 2); + outColorsExtraDark.setMainColor(getColorInt(primaryIndex, h, s, l)); + outColorsExtraDark.setSecondaryColor(getColorInt(secondaryIndex, h, s, l)); + + final boolean supportsDarkText = fitIndex >= textInversionIndex; + outColorsNormal.setSupportsDarkText(supportsDarkText); + outColorsDark.setSupportsDarkText(supportsDarkText); + outColorsExtraDark.setSupportsDarkText(supportsDarkText); + + if (DEBUG) { + Log.d(TAG, "Gradients: \n\tNormal " + outColorsNormal + "\n\tDark " + outColorsDark + + "\n\tExtra dark: " + outColorsExtraDark); + } return true; } + private int getColorInt(int fitIndex, float[] h, float[] s, float[] l) { + mTmpHSL[0] = fract(h[fitIndex]) * 360.0f; + mTmpHSL[1] = s[fitIndex]; + mTmpHSL[2] = l[fitIndex]; + return ColorUtils.HSLToColor(mTmpHSL); + } + /** * Checks if a given color exists in the blacklist * @param hsl float array with 3 components (H 0..360, S 0..1 and L 0..1) diff --git a/packages/SystemUI/colorextraction/tests/src/com/google/android/colorextraction/ColorExtractorTest.java b/packages/SystemUI/colorextraction/tests/src/com/google/android/colorextraction/ColorExtractorTest.java new file mode 100644 index 000000000000..fd698d050a0c --- /dev/null +++ b/packages/SystemUI/colorextraction/tests/src/com/google/android/colorextraction/ColorExtractorTest.java @@ -0,0 +1,114 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License + */ +package com.google.android.colorextraction; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; + +import android.app.WallpaperColors; +import android.app.WallpaperManager; +import android.content.Context; +import android.graphics.Color; +import android.support.test.InstrumentationRegistry; +import android.support.test.filters.SmallTest; +import android.support.test.runner.AndroidJUnit4; + +import com.google.android.colorextraction.ColorExtractor.GradientColors; +import com.google.android.colorextraction.types.ExtractionType; +import com.google.android.colorextraction.types.Tonal; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; + +/** + * Tests tonal palette generation. + */ +@SmallTest +@RunWith(AndroidJUnit4.class) +public class ColorExtractorTest { + + Context mContext; + + @Before + public void setup() { + mContext = InstrumentationRegistry.getContext(); + } + + @Test + public void ColorExtractor_extractWhenInitialized() { + ExtractionType type = mock(Tonal.class); + new ColorExtractor(mContext, type); + // 1 for lock and 1 for system + verify(type, times(2)) + .extractInto(any(), any(), any(), any()); + } + + @Test + public void getColors_usesFallbackIfFails() { + ExtractionType alwaysFail = + (inWallpaperColors, outGradientColorsNormal, outGradientColorsDark, + outGradientColorsExtraDark) -> false; + ColorExtractor extractor = new ColorExtractor(mContext, alwaysFail); + GradientColors colors = extractor.getColors(WallpaperManager.FLAG_SYSTEM); + + assertEquals("Should be using the fallback color.", + colors.getMainColor(), ColorExtractor.FALLBACK_COLOR); + assertEquals("Should be using the fallback color.", + colors.getSecondaryColor(), ColorExtractor.FALLBACK_COLOR); + assertFalse("Dark text support should be false.", colors.supportsDarkText()); + } + + @Test + public void getColors_usesExtractedColors() { + GradientColors colorsExpectedNormal = new GradientColors(); + colorsExpectedNormal.setMainColor(Color.RED); + colorsExpectedNormal.setSecondaryColor(Color.GRAY); + + GradientColors colorsExpectedDark = new GradientColors(); + colorsExpectedNormal.setMainColor(Color.BLACK); + colorsExpectedNormal.setSecondaryColor(Color.BLUE); + + GradientColors colorsExpectedExtraDark = new GradientColors(); + colorsExpectedNormal.setMainColor(Color.MAGENTA); + colorsExpectedNormal.setSecondaryColor(Color.GREEN); + + ExtractionType type = + (inWallpaperColors, outGradientColorsNormal, outGradientColorsDark, + outGradientColorsExtraDark) -> { + outGradientColorsNormal.set(colorsExpectedNormal); + outGradientColorsDark.set(colorsExpectedDark); + outGradientColorsExtraDark.set(colorsExpectedExtraDark); + // Successful extraction + return true; + }; + ColorExtractor extractor = new ColorExtractor(mContext, type); + + assertEquals("Extracted colors not being used!", + extractor.getColors(WallpaperManager.FLAG_SYSTEM, ColorExtractor.TYPE_NORMAL), + colorsExpectedNormal); + assertEquals("Extracted colors not being used!", + extractor.getColors(WallpaperManager.FLAG_SYSTEM, ColorExtractor.TYPE_DARK), + colorsExpectedDark); + assertEquals("Extracted colors not being used!", + extractor.getColors(WallpaperManager.FLAG_SYSTEM, ColorExtractor.TYPE_EXTRA_DARK), + colorsExpectedExtraDark); + } +} diff --git a/packages/SystemUI/colorextraction/tests/src/com/google/android/colorextraction/types/TonalTest.java b/packages/SystemUI/colorextraction/tests/src/com/google/android/colorextraction/types/TonalTest.java index 537ee1ac2fae..404076cb5301 100644 --- a/packages/SystemUI/colorextraction/tests/src/com/google/android/colorextraction/types/TonalTest.java +++ b/packages/SystemUI/colorextraction/tests/src/com/google/android/colorextraction/types/TonalTest.java @@ -27,6 +27,7 @@ import android.util.Pair; import android.util.Range; import com.google.android.colorextraction.ColorExtractor; +import com.google.android.colorextraction.ColorExtractor.GradientColors; import org.junit.Test; import org.junit.runner.RunWith; @@ -76,7 +77,8 @@ public class TonalTest { // Make sure that palette generation will fail Tonal tonal = new Tonal(); - boolean success = tonal.extractInto(colors, new ColorExtractor.GradientColors()); + boolean success = tonal.extractInto(colors, new GradientColors(), new GradientColors(), + new GradientColors()); assertFalse("Cannot generate a tonal palette from blacklisted colors ", success); } } diff --git a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java index ae6249d57599..e8dcf6c1f0b2 100644 --- a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java +++ b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java @@ -1339,14 +1339,14 @@ class GlobalActionsDialog implements DialogInterface.OnDismissListener, DialogIn } @Override - public void onColorsChanged(GradientColors colors, int which) { + public void onColorsChanged(ColorExtractor extractor, int which) { if (mKeyguardShowing) { if ((WallpaperManager.FLAG_LOCK & which) != 0) { - mGradientDrawable.setColors(colors); + mGradientDrawable.setColors(extractor.getColors(WallpaperManager.FLAG_LOCK)); } } else { if ((WallpaperManager.FLAG_SYSTEM & which) != 0) { - mGradientDrawable.setColors(colors); + mGradientDrawable.setColors(extractor.getColors(WallpaperManager.FLAG_SYSTEM)); } } } diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java b/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java index 978533cfdf56..319b4638713a 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java +++ b/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java @@ -21,6 +21,7 @@ import static android.app.ActivityManager.StackId.INVALID_STACK_ID; import android.animation.Animator; import android.animation.ObjectAnimator; import android.app.ActivityOptions.OnAnimationStartedListener; +import android.app.WallpaperColors; import android.app.WallpaperManager; import android.content.Context; import android.graphics.Canvas; @@ -111,7 +112,7 @@ public class RecentsView extends FrameLayout implements ColorExtractor.OnColorsC private int mDividerSize; private final float mScrimAlpha; - private final GradientDrawable mBackgroundScrim; + private GradientDrawable mBackgroundScrim; private final ColorExtractor mColorExtractor; private Animator mBackgroundScrimAnimator; @@ -828,9 +829,9 @@ public class RecentsView extends FrameLayout implements ColorExtractor.OnColorsC } @Override - public void onColorsChanged(ColorExtractor.GradientColors colors, int which) { + public void onColorsChanged(ColorExtractor extractor, int which) { if ((which & WallpaperManager.FLAG_SYSTEM) != 0) { - mBackgroundScrim.setColors(colors); + mBackgroundScrim.setColors(extractor.getColors(WallpaperManager.FLAG_SYSTEM)); } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/SignalClusterView.java b/packages/SystemUI/src/com/android/systemui/statusbar/SignalClusterView.java index 18cc8721ff95..22192db95c76 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/SignalClusterView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/SignalClusterView.java @@ -28,6 +28,7 @@ import android.graphics.drawable.Animatable; import android.graphics.drawable.AnimatedVectorDrawable; import android.graphics.drawable.Drawable; import android.graphics.drawable.LayerDrawable; +import android.net.NetworkBadging; import android.telephony.SubscriptionInfo; import android.util.ArraySet; import android.util.AttributeSet; @@ -581,10 +582,11 @@ public class SignalClusterView extends LinearLayout implements NetworkController */ private void setBadgedWifiIconForView(ImageView imageView, @DrawableRes int wifiPieId, @DrawableRes int badgeId) { + // TODO(sghuman): Delete this method and revert to N badging logic // Using the imageView's context to retrieve the Drawable so that theme is preserved.; LayerDrawable icon = new LayerDrawable(new Drawable[] { imageView.getContext().getDrawable(wifiPieId), - imageView.getContext().getDrawable(badgeId)}); + imageView.getContext().getDrawable(NetworkBadging.BADGING_NONE)}); // The LayerDrawable shares an underlying state so we must mutate the object to change the // color between the light and dark themes. diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java index 69f5135d406f..f502bb5c5dfc 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java @@ -25,7 +25,6 @@ import android.content.Context; import android.graphics.Color; import android.graphics.Rect; import android.graphics.drawable.Drawable; -import android.util.Log; import android.util.MathUtils; import android.view.View; import android.view.ViewGroup; @@ -44,13 +43,14 @@ import com.android.systemui.statusbar.policy.OnHeadsUpChangedListener; import com.android.systemui.statusbar.stack.ViewState; import com.google.android.colorextraction.ColorExtractor; +import com.google.android.colorextraction.ColorExtractor.OnColorsChangedListener; /** * Controls both the scrim behind the notifications and in front of the notifications (when a * security method gets shown). */ public class ScrimController implements ViewTreeObserver.OnPreDrawListener, - OnHeadsUpChangedListener, ColorExtractor.OnColorsChangedListener { + OnHeadsUpChangedListener, OnColorsChangedListener { public static final long ANIMATION_DURATION = 220; public static final Interpolator KEYGUARD_FADE_OUT_INTERPOLATOR = new PathInterpolator(0f, 0, 0.7f, 1f); @@ -80,7 +80,9 @@ public class ScrimController implements ViewTreeObserver.OnPreDrawListener, private final ColorExtractor mColorExtractor; private ColorExtractor.GradientColors mLockColors; + private ColorExtractor.GradientColors mLockColorsDark; private ColorExtractor.GradientColors mSystemColors; + private ColorExtractor.GradientColors mSystemColorsDark; private boolean mNeedsDrawableColorUpdate; protected float mScrimBehindAlpha; @@ -133,6 +135,11 @@ public class ScrimController implements ViewTreeObserver.OnPreDrawListener, mColorExtractor.addOnColorsChangedListener(this); mLockColors = mColorExtractor.getColors(WallpaperManager.FLAG_LOCK); mSystemColors = mColorExtractor.getColors(WallpaperManager.FLAG_SYSTEM); + // Darker gradient for the top scrim (mScrimInFront) + mLockColorsDark = mColorExtractor.getColors(WallpaperManager.FLAG_LOCK, + ColorExtractor.TYPE_DARK); + mSystemColorsDark = mColorExtractor.getColors(WallpaperManager.FLAG_SYSTEM, + ColorExtractor.TYPE_DARK); mNeedsDrawableColorUpdate = true; updateHeadsUpScrim(false); @@ -142,8 +149,7 @@ public class ScrimController implements ViewTreeObserver.OnPreDrawListener, public void setKeyguardShowing(boolean showing) { mKeyguardShowing = showing; - // Showing/hiding the keyguard means that scrim colors - // will probably have to be switched + // Showing/hiding the keyguard means that scrim colors have to be switched mNeedsDrawableColorUpdate = true; scheduleUpdate(); } @@ -301,11 +307,15 @@ public class ScrimController implements ViewTreeObserver.OnPreDrawListener, if (mNeedsDrawableColorUpdate) { mNeedsDrawableColorUpdate = false; if (mKeyguardShowing) { - mScrimInFront.setColors(mLockColors); + // Always animate color changes if we're seeing the keyguard + mScrimInFront.setColors(mLockColorsDark); mScrimBehind.setColors(mLockColors); } else { - mScrimInFront.setColors(mSystemColors, true); - mScrimBehind.setColors(mSystemColors, true); + // Only animate scrim color if the scrim view is actually visible + boolean animateScrimInFront = mScrimInFront.getViewAlpha() != 0; + boolean animateScrimBehind = mScrimBehind.getViewAlpha() != 0; + mScrimInFront.setColors(mSystemColorsDark, animateScrimInFront); + mScrimBehind.setColors(mSystemColors, animateScrimBehind); } } @@ -647,14 +657,20 @@ public class ScrimController implements ViewTreeObserver.OnPreDrawListener, } @Override - public void onColorsChanged(ColorExtractor.GradientColors colors, int which) { + public void onColorsChanged(ColorExtractor colorExtractor, int which) { if ((which & WallpaperManager.FLAG_LOCK) != 0) { - mLockColors = colors; + mLockColors = colorExtractor.getColors(WallpaperManager.FLAG_LOCK, + ColorExtractor.TYPE_NORMAL); + mLockColorsDark = colorExtractor.getColors(WallpaperManager.FLAG_LOCK, + ColorExtractor.TYPE_DARK); mNeedsDrawableColorUpdate = true; scheduleUpdate(); } if ((which & WallpaperManager.FLAG_SYSTEM) != 0) { - mSystemColors = colors; + mSystemColors = colorExtractor.getColors(WallpaperManager.FLAG_SYSTEM, + ColorExtractor.TYPE_NORMAL); + mSystemColorsDark = colorExtractor.getColors(WallpaperManager.FLAG_SYSTEM, + ColorExtractor.TYPE_DARK); mNeedsDrawableColorUpdate = true; scheduleUpdate(); } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java index 30673cdfc086..3326b3f581d7 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java @@ -2805,7 +2805,7 @@ public class StatusBar extends SystemUI implements DemoMode, } @Override - public void onColorsChanged(ColorExtractor.GradientColors colors, int which) { + public void onColorsChanged(ColorExtractor extractor, int which) { updateTheme(); } @@ -4477,6 +4477,8 @@ public class StatusBar extends SystemUI implements DemoMode, */ private void updateTheme() { boolean useDarkTheme; + // Ignore visibility since we calculate the theme based on the real colors, + // not the current state. if (mState == StatusBarState.KEYGUARD || mState == StatusBarState.SHADE_LOCKED) { useDarkTheme = mColorExtractor.getColors(WallpaperManager.FLAG_LOCK) .supportsDarkText(); diff --git a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java index 1d6bfb627801..1d3b533b6d8f 100644 --- a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java +++ b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java @@ -1092,14 +1092,14 @@ public class VolumeDialogImpl implements VolumeDialog, TunerService.Tunable, }; @Override - public void onColorsChanged(ColorExtractor.GradientColors colors, int which) { + public void onColorsChanged(ColorExtractor extractor, int which) { if (mKeyguard.isKeyguardLocked()) { if ((WallpaperManager.FLAG_LOCK & which) != 0) { - mGradientDrawable.setColors(colors); + mGradientDrawable.setColors(extractor.getColors(WallpaperManager.FLAG_LOCK)); } } else { if ((WallpaperManager.FLAG_SYSTEM & which) != 0) { - mGradientDrawable.setColors(colors); + mGradientDrawable.setColors(extractor.getColors(WallpaperManager.FLAG_SYSTEM)); } } } diff --git a/services/core/java/com/android/server/car/CarServiceHelperService.java b/services/core/java/com/android/server/car/CarServiceHelperService.java new file mode 100644 index 000000000000..9392a6a8fcd9 --- /dev/null +++ b/services/core/java/com/android/server/car/CarServiceHelperService.java @@ -0,0 +1,91 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server.car; + +import android.content.ComponentName; +import android.content.Context; +import android.content.Intent; +import android.content.ServiceConnection; +import android.os.Binder; +import android.os.IBinder; +import android.os.Parcel; +import android.os.RemoteException; +import android.os.UserHandle; +import android.util.Slog; + +import com.android.internal.car.ICarServiceHelper; +import com.android.server.SystemService; + +/** + * System service side companion service for CarService. + * Starts car service and provide necessary API for CarService. Only for car product. + */ +public class CarServiceHelperService extends SystemService { + private static final String TAG = "CarServiceHelper"; + private static final String CAR_SERVICE_INTERFACE = "android.car.ICar"; + private final ICarServiceHelperImpl mHelper = new ICarServiceHelperImpl(); + private IBinder mCarService; + private final ServiceConnection mCarServiceConnection = new ServiceConnection() { + + @Override + public void onServiceConnected(ComponentName componentName, IBinder iBinder) { + Slog.i(TAG, "**CarService connected**"); + mCarService = iBinder; + // Cannot depend on ICar which is defined in CarService, so handle binder call directly + // instead. + // void setCarServiceHelper(in IBinder helper) + Parcel data = Parcel.obtain(); + data.writeInterfaceToken(CAR_SERVICE_INTERFACE); + data.writeStrongBinder(mHelper.asBinder()); + try { + mCarService.transact(IBinder.FIRST_CALL_TRANSACTION, // setCarServiceHelper + data, null, Binder.FLAG_ONEWAY); + } catch (RemoteException e) { + Slog.w(TAG, "RemoteException from car service", e); + handleCarServiceCrash(); + } + } + + @Override + public void onServiceDisconnected(ComponentName componentName) { + handleCarServiceCrash(); + } + }; + + public CarServiceHelperService(Context context) { + super(context); + } + + @Override + public void onStart() { + Intent intent = new Intent(); + intent.setPackage("com.android.car"); + intent.setAction(CAR_SERVICE_INTERFACE); + if (!getContext().bindServiceAsUser(intent, mCarServiceConnection, Context.BIND_AUTO_CREATE, + UserHandle.SYSTEM)) { + Slog.wtf(TAG, "cannot start car service"); + } + } + + private void handleCarServiceCrash() { + //TODO define recovery bahavior + } + + private class ICarServiceHelperImpl extends ICarServiceHelper.Stub { + //TODO + } +} diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java index 66849c3e1348..272c11b985c5 100644 --- a/services/java/com/android/server/SystemServer.java +++ b/services/java/com/android/server/SystemServer.java @@ -63,6 +63,7 @@ import com.android.server.accessibility.AccessibilityManagerService; import com.android.server.am.ActivityManagerService; import com.android.server.audio.AudioService; import com.android.server.camera.CameraServiceProxy; +import com.android.server.car.CarServiceHelperService; import com.android.server.clipboard.ClipboardService; import com.android.server.connectivity.IpConnectivityMetrics; import com.android.server.coverage.CoverageService; @@ -1697,6 +1698,12 @@ public final class SystemServer { }, WEBVIEW_PREPARATION); } + if (mPackageManager.hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE)) { + traceBeginAndSlog("StartCarServiceHelperService"); + mSystemServiceManager.startService(CarServiceHelperService.class); + traceEnd(); + } + traceBeginAndSlog("StartSystemUI"); try { startSystemUi(context, windowManagerF); diff --git a/services/usb/java/com/android/server/usb/UsbDeviceManager.java b/services/usb/java/com/android/server/usb/UsbDeviceManager.java index 415a59be25c7..42272fddb95b 100644 --- a/services/usb/java/com/android/server/usb/UsbDeviceManager.java +++ b/services/usb/java/com/android/server/usb/UsbDeviceManager.java @@ -1232,10 +1232,13 @@ public class UsbDeviceManager { private String getDefaultFunctions() { String func = SystemProperties.get(getPersistProp(true), UsbManager.USB_FUNCTION_NONE); - if (UsbManager.USB_FUNCTION_NONE.equals(func)) { - func = UsbManager.USB_FUNCTION_MTP; + // if ADB is enabled, reset functions to ADB + // else enable MTP as usual. + if (UsbManager.containsFunction(func, UsbManager.USB_FUNCTION_ADB)) { + return UsbManager.USB_FUNCTION_ADB; + } else { + return UsbManager.USB_FUNCTION_MTP; } - return func; } public void dump(IndentingPrintWriter pw) { diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java index 414780869a4d..9781fb16c2bb 100644 --- a/telephony/java/android/telephony/CarrierConfigManager.java +++ b/telephony/java/android/telephony/CarrierConfigManager.java @@ -1129,6 +1129,8 @@ public class CarrierConfigManager { /** @hide */ public static final int CDMA_ROAMING_MODE_AFFILIATED = 1; /** @hide */ + public static final int IMSI_ENCRYPTION_DAYS_TIME_DISABLED = -1; + /** @hide */ public static final int CDMA_ROAMING_MODE_ANY = 2; /** * Boolean indicating if support is provided for directly dialing FDN number from FDN list. @@ -1446,6 +1448,23 @@ public class CarrierConfigManager { public static final String KEY_DISABLE_VOICE_BARRING_NOTIFICATION_BOOL = "disable_voice_barring_notification_bool"; + /** + * URL from which the proto containing the public key of the Carrier used for + * IMSI encryption will be downloaded. + * @hide + */ + public static final String IMSI_KEY_DOWNLOAD_URL_STRING = "imsi_key_download_url_string"; + + /** + * Time in days, after which the key will expire, and a new key will need to be downloaded. + * default value is {@link IMSI_ENCRYPTION_DAYS_TIME_DISABLED}, and indicates that IMSI + * encryption is not enabled by default for a carrier. Value of 0 indicates that the key + * does not expire. + * @hide + */ + public static final String IMSI_KEY_EXPIRATION_DAYS_TIME_INT = + "imsi_key_expiration_days_time_int"; + /** The default value for every variable. */ private final static PersistableBundle sDefaults; @@ -1693,6 +1712,8 @@ public class CarrierConfigManager { sDefaults.putInt(KEY_LTE_EARFCNS_RSRP_BOOST_INT, 0); sDefaults.putStringArray(KEY_BOOSTED_LTE_EARFCNS_STRING_ARRAY, null); sDefaults.putBoolean(KEY_DISABLE_VOICE_BARRING_NOTIFICATION_BOOL, false); + sDefaults.putInt(IMSI_KEY_EXPIRATION_DAYS_TIME_INT, IMSI_ENCRYPTION_DAYS_TIME_DISABLED); + sDefaults.putString(IMSI_KEY_DOWNLOAD_URL_STRING, null); } /** |