diff --git a/res/layout/layout_color_selector.xml b/res/layout/layout_color_selector.xml index c366add00ec..a6b9cc89688 100644 --- a/res/layout/layout_color_selector.xml +++ b/res/layout/layout_color_selector.xml @@ -14,161 +14,167 @@ See the License for the specific language governing permissions and limitations under the License. --> - - + android:padding="20dp" + android:clipToPadding="false" + android:scrollbarStyle="outsideOverlay"> - - - - + + android:layout_marginBottom="10dp" + android:orientation="horizontal"> - + - + + + + + + + + + + + + + + android:layout_marginBottom="10dp" + android:orientation="horizontal"> - + - + + + + + + + + + + + + + + android:layout_marginBottom="10dp" + android:orientation="horizontal"> - + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file + diff --git a/res/layout/layout_color_selector_dialog.xml b/res/layout/layout_color_selector_dialog.xml index 70d4509f07e..e107689ae6a 100644 --- a/res/layout/layout_color_selector_dialog.xml +++ b/res/layout/layout_color_selector_dialog.xml @@ -17,16 +17,12 @@ + android:gravity="center_horizontal" + android:orientation="vertical"> + android:layout_height="wrap_content"/> \ No newline at end of file diff --git a/src/com/android/settings/connecteddevice/stylus/StylusDevicesController.java b/src/com/android/settings/connecteddevice/stylus/StylusDevicesController.java index ec9f4c6eb51..0a0e2081a8f 100644 --- a/src/com/android/settings/connecteddevice/stylus/StylusDevicesController.java +++ b/src/com/android/settings/connecteddevice/stylus/StylusDevicesController.java @@ -124,7 +124,7 @@ public class StylusDevicesController extends AbstractPreferenceController implem try { ApplicationInfo ai = pm.getApplicationInfo(packageName, PackageManager.ApplicationInfoFlags.of(0)); - appName = ai == null ? packageName : pm.getApplicationLabel(ai).toString(); + appName = ai == null ? "" : pm.getApplicationLabel(ai).toString(); } catch (PackageManager.NameNotFoundException e) { Log.e(TAG, "Notes role package not found."); } diff --git a/src/com/android/settings/display/ScreenResolutionFragment.java b/src/com/android/settings/display/ScreenResolutionFragment.java index de7d25fefb9..daf1793f11f 100644 --- a/src/com/android/settings/display/ScreenResolutionFragment.java +++ b/src/com/android/settings/display/ScreenResolutionFragment.java @@ -369,6 +369,12 @@ public class ScreenResolutionFragment extends RadioButtonPickerFragment { private void restoreDensity() { final DisplayDensityUtils density = new DisplayDensityUtils(mContext); + /* If current density is the same as a default density of other resolutions, + * then mCurrentIndex may be out of boundary. + */ + if (density.getDefaultDisplayDensityValues().length <= mCurrentIndex) { + mCurrentIndex = density.getCurrentIndexForDefaultDisplay(); + } if (density.getDefaultDisplayDensityValues()[mCurrentIndex] != density.getDefaultDensityForDefaultDisplay()) { density.setForcedDisplayDensity(mCurrentIndex); diff --git a/src/com/android/settings/fuelgauge/PowerUsageFeatureProvider.java b/src/com/android/settings/fuelgauge/PowerUsageFeatureProvider.java index 0b0e2430c90..c06e7f023d9 100644 --- a/src/com/android/settings/fuelgauge/PowerUsageFeatureProvider.java +++ b/src/com/android/settings/fuelgauge/PowerUsageFeatureProvider.java @@ -128,6 +128,11 @@ public interface PowerUsageFeatureProvider { */ boolean delayHourlyJobWhenBooting(); + /** + * Insert device usage data for anomaly detection + */ + void insertSettingsData(Context context); + /** * Gets an intent for one time bypass charge limited to resume charging. */ diff --git a/src/com/android/settings/fuelgauge/PowerUsageFeatureProviderImpl.java b/src/com/android/settings/fuelgauge/PowerUsageFeatureProviderImpl.java index 1d0ba18b40f..89d793a9e92 100644 --- a/src/com/android/settings/fuelgauge/PowerUsageFeatureProviderImpl.java +++ b/src/com/android/settings/fuelgauge/PowerUsageFeatureProviderImpl.java @@ -160,6 +160,9 @@ public class PowerUsageFeatureProviderImpl implements PowerUsageFeatureProvider return true; } + @Override + public void insertSettingsData(Context context) {} + @Override public Set getOthersSystemComponentSet() { return new ArraySet<>(); diff --git a/src/com/android/settings/fuelgauge/batteryusage/BatteryChartView.java b/src/com/android/settings/fuelgauge/batteryusage/BatteryChartView.java index 0fae92d575c..891e5e0b0ec 100644 --- a/src/com/android/settings/fuelgauge/batteryusage/BatteryChartView.java +++ b/src/com/android/settings/fuelgauge/batteryusage/BatteryChartView.java @@ -18,6 +18,7 @@ package com.android.settings.fuelgauge.batteryusage; import static com.android.settings.Utils.formatPercentage; import static com.android.settings.fuelgauge.batteryusage.BatteryChartViewModel.AxisLabelPosition.BETWEEN_TRAPEZOIDS; +import static java.lang.Math.abs; import static java.lang.Math.round; import static java.util.Objects.requireNonNull; @@ -74,6 +75,8 @@ public class BatteryChartView extends AppCompatImageView implements View.OnClick private final Rect[] mPercentageBounds = new Rect[]{new Rect(), new Rect(), new Rect()}; private final List mAxisLabelsBounds = new ArrayList<>(); private final Set mLabelDrawnIndexes = new ArraySet<>(); + private final int mLayoutDirection = + getContext().getResources().getConfiguration().getLayoutDirection(); private BatteryChartViewModel mViewModel; private int mHoveredIndex = BatteryChartViewModel.SELECTED_INDEX_INVALID; @@ -159,7 +162,12 @@ public class BatteryChartView extends AppCompatImageView implements View.OnClick } // Updates the indent configurations. mIndent.top = mPercentageBounds[0].height(); - mIndent.right = mPercentageBounds[0].width() + mTextPadding; + final int textWidth = mPercentageBounds[0].width() + mTextPadding; + if (isRTL()) { + mIndent.left = textWidth; + } else { + mIndent.right = textWidth; + } if (mViewModel != null) { int maxTop = 0; @@ -334,7 +342,7 @@ public class BatteryChartView extends AppCompatImageView implements View.OnClick } private void drawHorizontalDividers(Canvas canvas) { - final int width = getWidth() - mIndent.right; + final int width = getWidth() - abs(mIndent.width()); final int height = getHeight() - mIndent.top - mIndent.bottom; final float topOffsetY = mIndent.top + mDividerWidth * .5f; final float bottomOffsetY = mIndent.top + (height - mDividerHeight - mDividerWidth * .5f); @@ -347,7 +355,8 @@ public class BatteryChartView extends AppCompatImageView implements View.OnClick // Draws 5 divider lines. for (int index = 0; index < HORIZONTAL_DIVIDER_COUNT; index++) { float offsetY = topOffsetY + dividerOffsetUnit * index; - canvas.drawLine(0, offsetY, width, offsetY, mDividerPaint); + canvas.drawLine(mIndent.left, offsetY, + mIndent.left + width, offsetY, mDividerPaint); // Draws percentage text only for 100% / 50% / 0% if (index % 2 == 0) { @@ -362,14 +371,14 @@ public class BatteryChartView extends AppCompatImageView implements View.OnClick mTextPaint.setColor(mDefaultTextColor); canvas.drawText( mPercentages[index], - getWidth(), + isRTL() ? mIndent.left - mTextPadding : getWidth(), offsetY + mPercentageBounds[index].height() * .5f, mTextPaint); } } private void drawVerticalDividers(Canvas canvas) { - final int width = getWidth() - mIndent.right; + final int width = getWidth() - abs(mIndent.width()); final int dividerCount = mTrapezoidSlots.length + 1; final float dividerSpace = dividerCount * mDividerWidth; final float unitWidth = (width - dividerSpace) / (float) mTrapezoidSlots.length; @@ -384,7 +393,7 @@ public class BatteryChartView extends AppCompatImageView implements View.OnClick case CENTER_OF_TRAPEZOIDS: axisLabelDisplayAreas = getAxisLabelDisplayAreas( /* size= */ mViewModel.size() - 1, - /* baselineX= */ mDividerWidth + unitWidth * .5f, + /* baselineX= */ mIndent.left + mDividerWidth + unitWidth * .5f, /* offsetX= */ mDividerWidth + unitWidth, baselineY, /* shiftFirstAndLast= */ false); @@ -393,7 +402,7 @@ public class BatteryChartView extends AppCompatImageView implements View.OnClick default: axisLabelDisplayAreas = getAxisLabelDisplayAreas( /* size= */ mViewModel.size(), - /* baselineX= */ mDividerWidth * .5f, + /* baselineX= */ mIndent.left + mDividerWidth * .5f, /* offsetX= */ mDividerWidth + unitWidth, baselineY, /* shiftFirstAndLast= */ true); @@ -402,7 +411,7 @@ public class BatteryChartView extends AppCompatImageView implements View.OnClick drawAxisLabels(canvas, axisLabelDisplayAreas, baselineY); } // Draws each vertical dividers. - float startX = mDividerWidth * .5f; + float startX = mDividerWidth * .5f + mIndent.left; for (int index = 0; index < dividerCount; index++) { float dividerY = bottomY; if (mViewModel.axisLabelPosition() == BETWEEN_TRAPEZOIDS @@ -416,8 +425,9 @@ public class BatteryChartView extends AppCompatImageView implements View.OnClick final float nextX = startX + mDividerWidth + unitWidth; // Updates the trapezoid slots for drawing. if (index < mTrapezoidSlots.length) { - mTrapezoidSlots[index].mLeft = round(startX + trapezoidSlotOffset); - mTrapezoidSlots[index].mRight = round(nextX - trapezoidSlotOffset); + final int trapezoidIndex = isRTL() ? mTrapezoidSlots.length - index - 1 : index; + mTrapezoidSlots[trapezoidIndex].mLeft = round(startX + trapezoidSlotOffset); + mTrapezoidSlots[trapezoidIndex].mRight = round(nextX - trapezoidSlotOffset); } startX = nextX; } @@ -509,10 +519,20 @@ public class BatteryChartView extends AppCompatImageView implements View.OnClick return displayAreas[leftIndex].right + mTextPadding * 2.3f > displayAreas[rightIndex].left; } + private boolean isRTL() { + return mLayoutDirection == View.LAYOUT_DIRECTION_RTL; + } + private void drawAxisLabelText( - Canvas canvas, final int index, final Rect displayArea, final float baselineY) { + Canvas canvas, int index, final Rect displayArea, final float baselineY) { mTextPaint.setColor(mTrapezoidSolidColor); mTextPaint.setTextAlign(Paint.Align.CENTER); + // Reverse the sort of axis labels for RTL + if (isRTL()) { + index = mViewModel.axisLabelPosition() == BETWEEN_TRAPEZOIDS + ? mViewModel.size() - index - 1 // for hourly + : mViewModel.size() - index - 2; // for daily + } canvas.drawText( mViewModel.getText(index), displayArea.centerX(), @@ -548,10 +568,16 @@ public class BatteryChartView extends AppCompatImageView implements View.OnClick mHoveredIndex); mTrapezoidPaint.setColor(isHoverState ? mTrapezoidHoverColor : trapezoidColor); - final float leftTop = round( + float leftTop = round( trapezoidBottom - requireNonNull(mViewModel.getLevel(index)) * unitHeight); - final float rightTop = round(trapezoidBottom + float rightTop = round(trapezoidBottom - requireNonNull(mViewModel.getLevel(index + 1)) * unitHeight); + // Mirror the shape of the trapezoid for RTL + if (isRTL()) { + float temp = leftTop; + leftTop = rightTop; + rightTop = temp; + } trapezoidPath.reset(); trapezoidPath.moveTo(mTrapezoidSlots[index].mLeft, trapezoidBottom); trapezoidPath.lineTo(mTrapezoidSlots[index].mLeft, leftTop); diff --git a/src/com/android/settings/wifi/WifiEntryPreference.java b/src/com/android/settings/wifi/WifiEntryPreference.java index 5b448870016..7206666b576 100644 --- a/src/com/android/settings/wifi/WifiEntryPreference.java +++ b/src/com/android/settings/wifi/WifiEntryPreference.java @@ -15,6 +15,8 @@ */ package com.android.settings.wifi; +import static com.android.settingslib.wifi.WifiUtils.getHotspotIconResource; + import android.annotation.Nullable; import android.content.Context; import android.content.res.Resources; @@ -37,6 +39,7 @@ import com.android.settingslib.RestrictedPreference; import com.android.settingslib.Utils; import com.android.settingslib.wifi.WifiUtils; import com.android.wifitrackerlib.BaseWifiTracker; +import com.android.wifitrackerlib.HotspotNetworkEntry; import com.android.wifitrackerlib.WifiEntry; /** @@ -145,13 +148,17 @@ public class WifiEntryPreference extends RestrictedPreference implements */ public void refresh() { setTitle(mWifiEntry.getTitle()); - final int level = mWifiEntry.getLevel(); - final boolean showX = mWifiEntry.shouldShowXLevelIcon(); - if (level != mLevel || showX != mShowX) { - mLevel = level; - mShowX = showX; - updateIcon(mShowX, mLevel); - notifyChanged(); + if (mWifiEntry instanceof HotspotNetworkEntry) { + updateHotspotIcon(((HotspotNetworkEntry) mWifiEntry).getDeviceType()); + } else { + int level = mWifiEntry.getLevel(); + boolean showX = mWifiEntry.shouldShowXLevelIcon(); + + if (level != mLevel || showX != mShowX) { + mLevel = level; + mShowX = showX; + updateIcon(mShowX, mLevel); + } } setSummary(mWifiEntry.getSummary(false /* concise */)); @@ -201,14 +208,7 @@ public class WifiEntryPreference extends RestrictedPreference implements return accent ? android.R.attr.colorAccent : android.R.attr.colorControlNormal; } - @VisibleForTesting - void updateIcon(boolean showX, int level) { - if (level == -1) { - setIcon(null); - return; - } - - final Drawable drawable = mIconInjector.getIcon(showX, level); + private void setIconWithTint(Drawable drawable) { if (drawable != null) { // Must use Drawable#setTintList() instead of Drawable#setTint() to show the grey // icon when the preference is disabled. @@ -219,6 +219,20 @@ public class WifiEntryPreference extends RestrictedPreference implements } } + @VisibleForTesting + void updateIcon(boolean showX, int level) { + if (level == -1) { + setIcon(null); + return; + } + setIconWithTint(mIconInjector.getIcon(showX, level)); + } + + @VisibleForTesting + void updateHotspotIcon(int deviceType) { + setIconWithTint(getContext().getDrawable(getHotspotIconResource(deviceType))); + } + @Nullable private StateListDrawable getFrictionStateListDrawable() { TypedArray frictionSld; diff --git a/tests/robotests/src/com/android/settings/connecteddevice/stylus/StylusDevicesControllerTest.java b/tests/robotests/src/com/android/settings/connecteddevice/stylus/StylusDevicesControllerTest.java index 1fcf396f31c..3c459de3792 100644 --- a/tests/robotests/src/com/android/settings/connecteddevice/stylus/StylusDevicesControllerTest.java +++ b/tests/robotests/src/com/android/settings/connecteddevice/stylus/StylusDevicesControllerTest.java @@ -272,6 +272,20 @@ public class StylusDevicesControllerTest { NOTES_APP_LABEL.toString())); } + @Test + public void defaultNotesPreference_noApplicationInfo_showsBlankSummary() + throws PackageManager.NameNotFoundException { + when(mPm.getApplicationInfo(eq(NOTES_PACKAGE_NAME), + any(PackageManager.ApplicationInfoFlags.class))).thenReturn(null); + + showScreen(mController); + + Preference defaultNotesPref = mPreferenceContainer.getPreference(0); + assertThat(defaultNotesPref.getTitle().toString()).isEqualTo( + mContext.getString(R.string.stylus_default_notes_app)); + assertThat(defaultNotesPref.getSummary().toString()).isEqualTo(""); + } + @Test public void defaultNotesPreference_roleHolderChanges_updatesPreference() { showScreen(mController); diff --git a/tests/robotests/src/com/android/settings/wifi/WifiEntryPreferenceTest.java b/tests/robotests/src/com/android/settings/wifi/WifiEntryPreferenceTest.java index a60b5313730..316beb37f70 100644 --- a/tests/robotests/src/com/android/settings/wifi/WifiEntryPreferenceTest.java +++ b/tests/robotests/src/com/android/settings/wifi/WifiEntryPreferenceTest.java @@ -18,11 +18,15 @@ package com.android.settings.wifi; import static com.google.common.truth.Truth.assertThat; import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyInt; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.spy; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import android.content.Context; import android.graphics.drawable.Drawable; +import android.net.wifi.sharedconnectivity.app.NetworkProviderInfo; import android.view.LayoutInflater; import android.view.View; import android.widget.LinearLayout; @@ -31,6 +35,7 @@ import androidx.preference.PreferenceViewHolder; import com.android.settingslib.R; import com.android.settingslib.wifi.WifiUtils; +import com.android.wifitrackerlib.HotspotNetworkEntry; import com.android.wifitrackerlib.WifiEntry; import org.junit.Before; @@ -52,6 +57,8 @@ public class WifiEntryPreferenceTest { @Mock private WifiEntry mMockWifiEntry; @Mock + private HotspotNetworkEntry mHotspotNetworkEntry; + @Mock private WifiUtils.InternetIconInjector mMockIconInjector; @Mock @@ -256,4 +263,26 @@ public class WifiEntryPreferenceTest { public void getSecondTargetResId_shouldNotReturnZero() { assertThat(mPref.getSecondTargetResId()).isNotEqualTo(0); } + + @Test + public void refresh_itsHotspotNetworkEntry_shouldUpdateHotspotIcon() { + int deviceType = NetworkProviderInfo.DEVICE_TYPE_PHONE; + when(mHotspotNetworkEntry.getDeviceType()).thenReturn(deviceType); + WifiEntryPreference pref = spy( + new WifiEntryPreference(mContext, mHotspotNetworkEntry, mMockIconInjector)); + + pref.refresh(); + + verify(pref).updateHotspotIcon(deviceType); + } + + @Test + public void refresh_notHotspotNetworkEntry_shouldNotUpdateHotspotIcon() { + WifiEntryPreference pref = spy( + new WifiEntryPreference(mContext, mMockWifiEntry, mMockIconInjector)); + + pref.refresh(); + + verify(pref, never()).updateHotspotIcon(anyInt()); + } }