Loading src/com/android/settings/core/InstrumentedPreferenceFragment.java +24 −0 Original line number Diff line number Diff line Loading @@ -17,13 +17,20 @@ package com.android.settings.core; import android.content.Context; import android.graphics.Color; import android.graphics.drawable.ColorDrawable; import android.graphics.drawable.Drawable; import android.os.Bundle; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import com.android.settings.core.instrumentation.Instrumentable; import com.android.settings.core.instrumentation.MetricsFeatureProvider; import com.android.settings.core.instrumentation.VisibilityLoggerMixin; import com.android.settings.core.lifecycle.ObservablePreferenceFragment; import com.android.settings.overlay.FeatureFactory; import com.android.settings.widget.PreferenceDividerDecoration; /** * Instrumented fragment that logs visibility state. Loading @@ -48,6 +55,9 @@ public abstract class InstrumentedPreferenceFragment extends ObservablePreferenc protected final int GESTURE_DOUBLE_TAP_SCREEN = PLACEHOLDER_METRIC + 11; protected final int GESTURE_DOUBLE_TWIST = PLACEHOLDER_METRIC + 12; private final PreferenceDividerDecoration mDividerDecoration = new PreferenceDividerDecoration(); public InstrumentedPreferenceFragment() { // Mixin that logs visibility change for activity. getLifecycle().addObserver(new VisibilityLoggerMixin(getMetricsCategory())); Loading @@ -59,7 +69,21 @@ public abstract class InstrumentedPreferenceFragment extends ObservablePreferenc mMetricsFeatureProvider = FeatureFactory.getFactory(context).getMetricsFeatureProvider(); } @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { final View view = super.onCreateView(inflater, container, savedInstanceState); getListView().addItemDecoration(mDividerDecoration); return view; } @Override public void onCreatePreferences(Bundle savedInstanceState, String rootKey) { } @Override public void setDivider(Drawable divider) { mDividerDecoration.setDivider(divider); super.setDivider(new ColorDrawable(Color.TRANSPARENT)); } } src/com/android/settings/dashboard/DashboardFragment.java +0 −13 Original line number Diff line number Diff line Loading @@ -17,9 +17,6 @@ package com.android.settings.dashboard; import android.app.Activity; import android.content.Context; import android.graphics.Color; import android.graphics.drawable.ColorDrawable; import android.graphics.drawable.Drawable; import android.os.Bundle; import android.support.annotation.VisibleForTesting; import android.support.v7.preference.Preference; Loading Loading @@ -117,16 +114,6 @@ public abstract class DashboardFragment extends SettingsPreferenceFragment refreshAllPreferences(getLogTag()); } @Override public void setDivider(Drawable divider) { if (mDashboardFeatureProvider.isEnabled()) { // Intercept divider and set it transparent so system divider decoration is disabled. super.setDivider(new ColorDrawable(Color.TRANSPARENT)); } else { super.setDivider(divider); } } @Override public void onStart() { super.onStart(); Loading src/com/android/settings/widget/PreferenceDividerDecoration.java 0 → 100644 +79 −0 Original line number Diff line number Diff line /* * 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.settings.widget; import android.graphics.Canvas; import android.graphics.drawable.Drawable; import android.support.v4.view.ViewCompat; import android.support.v7.preference.Preference; import android.support.v7.preference.PreferenceCategory; import android.support.v7.preference.PreferenceGroupAdapter; import android.support.v7.widget.RecyclerView; import android.view.View; public class PreferenceDividerDecoration extends RecyclerView.ItemDecoration { private Drawable mDivider; private int mDividerHeight; public void setDivider(Drawable divider) { if (divider != null) { mDividerHeight = divider.getIntrinsicHeight(); } else { mDividerHeight = 0; } mDivider = divider; } public void setDividerHeight(int dividerHeight) { mDividerHeight = dividerHeight; } @Override public void onDrawOver(Canvas c, RecyclerView parent, RecyclerView.State state) { if (mDivider == null) { return; } final int childCount = parent.getChildCount(); final int width = parent.getWidth(); for (int childViewIndex = 0; childViewIndex < childCount; childViewIndex++) { final View view = parent.getChildAt(childViewIndex); if (shouldDrawDividerAbove(view, parent)) { int top = (int) ViewCompat.getY(view); mDivider.setBounds(0, top, width, top + mDividerHeight); mDivider.draw(c); } } } private boolean shouldDrawDividerAbove(View view, RecyclerView parent) { final RecyclerView.Adapter adapter = parent.getAdapter(); if (adapter == null || !(adapter instanceof PreferenceGroupAdapter)) { return false; } final PreferenceGroupAdapter prefAdapter = (PreferenceGroupAdapter) adapter; final int adapterPosition = parent.getChildAdapterPosition(view); if (adapterPosition == RecyclerView.NO_POSITION) { return false; } final Preference pref = prefAdapter.getItem(adapterPosition); if (pref instanceof PreferenceCategory) { return adapterPosition != 0; } return pref instanceof FooterPreference; } } tests/robotests/src/com/android/settings/widget/PreferenceDividerDecorationTest.java 0 → 100644 +113 −0 Original line number Diff line number Diff line /* * 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.settings.widget; import android.content.Context; import android.graphics.Canvas; import android.graphics.drawable.Drawable; import android.support.v7.preference.Preference; import android.support.v7.preference.PreferenceCategory; import android.support.v7.preference.PreferenceGroupAdapter; import android.support.v7.widget.RecyclerView; import android.view.View; import com.android.settings.SettingsRobolectricTestRunner; import com.android.settings.TestConfig; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Answers; import org.mockito.Mock; import org.mockito.MockitoAnnotations; import org.robolectric.annotation.Config; import static org.mockito.Matchers.any; import static org.mockito.Matchers.anyInt; import static org.mockito.Mockito.never; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; @RunWith(SettingsRobolectricTestRunner.class) @Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION) public class PreferenceDividerDecorationTest { @Mock(answer = Answers.RETURNS_DEEP_STUBS) private Context mContext; @Mock private Drawable mDrawable; @Mock private Canvas mCanvas; @Mock(answer = Answers.RETURNS_DEEP_STUBS) private RecyclerView mRecyclerView; @Mock private PreferenceGroupAdapter mAdapter; @Mock private PreferenceCategory mPrefCategory; @Mock private Preference mNormalPref; @Mock private FooterPreference mFooterPref; private PreferenceDividerDecoration mDecoration; @Before public void setUp() { MockitoAnnotations.initMocks(this); mDecoration = new PreferenceDividerDecoration(); mDecoration.setDivider(mDrawable); mDecoration.setDividerHeight(3); } @Test public void drawOver_footerPreference_shouldDrawDivider() { when(mRecyclerView.getAdapter()).thenReturn(mAdapter); when(mRecyclerView.getChildCount()).thenReturn(1); when(mAdapter.getItem(anyInt())).thenReturn(mFooterPref); mDecoration.onDrawOver(mCanvas, mRecyclerView, null /* state */); verify(mDrawable).draw(mCanvas); } @Test public void drawOver_preferenceCategory_shouldSkipFirst() { when(mRecyclerView.getAdapter()).thenReturn(mAdapter); when(mRecyclerView.getChildCount()).thenReturn(3); when(mAdapter.getItem(anyInt())).thenReturn(mPrefCategory); when(mRecyclerView.getChildAdapterPosition(any(View.class))) .thenReturn(0) .thenReturn(1) .thenReturn(2); mDecoration.onDrawOver(mCanvas, mRecyclerView, null /* state */); // 3 prefCategory, should skip first draw verify(mDrawable, times(2)).draw(mCanvas); } @Test public void drawOver_preference_doNotDrawDivider() { when(mRecyclerView.getAdapter()).thenReturn(mAdapter); when(mRecyclerView.getChildCount()).thenReturn(1); when(mAdapter.getItem(anyInt())).thenReturn(mNormalPref); mDecoration.onDrawOver(mCanvas, mRecyclerView, null /* state */); verify(mDrawable, never()).draw(mCanvas); } } Loading
src/com/android/settings/core/InstrumentedPreferenceFragment.java +24 −0 Original line number Diff line number Diff line Loading @@ -17,13 +17,20 @@ package com.android.settings.core; import android.content.Context; import android.graphics.Color; import android.graphics.drawable.ColorDrawable; import android.graphics.drawable.Drawable; import android.os.Bundle; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import com.android.settings.core.instrumentation.Instrumentable; import com.android.settings.core.instrumentation.MetricsFeatureProvider; import com.android.settings.core.instrumentation.VisibilityLoggerMixin; import com.android.settings.core.lifecycle.ObservablePreferenceFragment; import com.android.settings.overlay.FeatureFactory; import com.android.settings.widget.PreferenceDividerDecoration; /** * Instrumented fragment that logs visibility state. Loading @@ -48,6 +55,9 @@ public abstract class InstrumentedPreferenceFragment extends ObservablePreferenc protected final int GESTURE_DOUBLE_TAP_SCREEN = PLACEHOLDER_METRIC + 11; protected final int GESTURE_DOUBLE_TWIST = PLACEHOLDER_METRIC + 12; private final PreferenceDividerDecoration mDividerDecoration = new PreferenceDividerDecoration(); public InstrumentedPreferenceFragment() { // Mixin that logs visibility change for activity. getLifecycle().addObserver(new VisibilityLoggerMixin(getMetricsCategory())); Loading @@ -59,7 +69,21 @@ public abstract class InstrumentedPreferenceFragment extends ObservablePreferenc mMetricsFeatureProvider = FeatureFactory.getFactory(context).getMetricsFeatureProvider(); } @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { final View view = super.onCreateView(inflater, container, savedInstanceState); getListView().addItemDecoration(mDividerDecoration); return view; } @Override public void onCreatePreferences(Bundle savedInstanceState, String rootKey) { } @Override public void setDivider(Drawable divider) { mDividerDecoration.setDivider(divider); super.setDivider(new ColorDrawable(Color.TRANSPARENT)); } }
src/com/android/settings/dashboard/DashboardFragment.java +0 −13 Original line number Diff line number Diff line Loading @@ -17,9 +17,6 @@ package com.android.settings.dashboard; import android.app.Activity; import android.content.Context; import android.graphics.Color; import android.graphics.drawable.ColorDrawable; import android.graphics.drawable.Drawable; import android.os.Bundle; import android.support.annotation.VisibleForTesting; import android.support.v7.preference.Preference; Loading Loading @@ -117,16 +114,6 @@ public abstract class DashboardFragment extends SettingsPreferenceFragment refreshAllPreferences(getLogTag()); } @Override public void setDivider(Drawable divider) { if (mDashboardFeatureProvider.isEnabled()) { // Intercept divider and set it transparent so system divider decoration is disabled. super.setDivider(new ColorDrawable(Color.TRANSPARENT)); } else { super.setDivider(divider); } } @Override public void onStart() { super.onStart(); Loading
src/com/android/settings/widget/PreferenceDividerDecoration.java 0 → 100644 +79 −0 Original line number Diff line number Diff line /* * 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.settings.widget; import android.graphics.Canvas; import android.graphics.drawable.Drawable; import android.support.v4.view.ViewCompat; import android.support.v7.preference.Preference; import android.support.v7.preference.PreferenceCategory; import android.support.v7.preference.PreferenceGroupAdapter; import android.support.v7.widget.RecyclerView; import android.view.View; public class PreferenceDividerDecoration extends RecyclerView.ItemDecoration { private Drawable mDivider; private int mDividerHeight; public void setDivider(Drawable divider) { if (divider != null) { mDividerHeight = divider.getIntrinsicHeight(); } else { mDividerHeight = 0; } mDivider = divider; } public void setDividerHeight(int dividerHeight) { mDividerHeight = dividerHeight; } @Override public void onDrawOver(Canvas c, RecyclerView parent, RecyclerView.State state) { if (mDivider == null) { return; } final int childCount = parent.getChildCount(); final int width = parent.getWidth(); for (int childViewIndex = 0; childViewIndex < childCount; childViewIndex++) { final View view = parent.getChildAt(childViewIndex); if (shouldDrawDividerAbove(view, parent)) { int top = (int) ViewCompat.getY(view); mDivider.setBounds(0, top, width, top + mDividerHeight); mDivider.draw(c); } } } private boolean shouldDrawDividerAbove(View view, RecyclerView parent) { final RecyclerView.Adapter adapter = parent.getAdapter(); if (adapter == null || !(adapter instanceof PreferenceGroupAdapter)) { return false; } final PreferenceGroupAdapter prefAdapter = (PreferenceGroupAdapter) adapter; final int adapterPosition = parent.getChildAdapterPosition(view); if (adapterPosition == RecyclerView.NO_POSITION) { return false; } final Preference pref = prefAdapter.getItem(adapterPosition); if (pref instanceof PreferenceCategory) { return adapterPosition != 0; } return pref instanceof FooterPreference; } }
tests/robotests/src/com/android/settings/widget/PreferenceDividerDecorationTest.java 0 → 100644 +113 −0 Original line number Diff line number Diff line /* * 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.settings.widget; import android.content.Context; import android.graphics.Canvas; import android.graphics.drawable.Drawable; import android.support.v7.preference.Preference; import android.support.v7.preference.PreferenceCategory; import android.support.v7.preference.PreferenceGroupAdapter; import android.support.v7.widget.RecyclerView; import android.view.View; import com.android.settings.SettingsRobolectricTestRunner; import com.android.settings.TestConfig; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Answers; import org.mockito.Mock; import org.mockito.MockitoAnnotations; import org.robolectric.annotation.Config; import static org.mockito.Matchers.any; import static org.mockito.Matchers.anyInt; import static org.mockito.Mockito.never; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; @RunWith(SettingsRobolectricTestRunner.class) @Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION) public class PreferenceDividerDecorationTest { @Mock(answer = Answers.RETURNS_DEEP_STUBS) private Context mContext; @Mock private Drawable mDrawable; @Mock private Canvas mCanvas; @Mock(answer = Answers.RETURNS_DEEP_STUBS) private RecyclerView mRecyclerView; @Mock private PreferenceGroupAdapter mAdapter; @Mock private PreferenceCategory mPrefCategory; @Mock private Preference mNormalPref; @Mock private FooterPreference mFooterPref; private PreferenceDividerDecoration mDecoration; @Before public void setUp() { MockitoAnnotations.initMocks(this); mDecoration = new PreferenceDividerDecoration(); mDecoration.setDivider(mDrawable); mDecoration.setDividerHeight(3); } @Test public void drawOver_footerPreference_shouldDrawDivider() { when(mRecyclerView.getAdapter()).thenReturn(mAdapter); when(mRecyclerView.getChildCount()).thenReturn(1); when(mAdapter.getItem(anyInt())).thenReturn(mFooterPref); mDecoration.onDrawOver(mCanvas, mRecyclerView, null /* state */); verify(mDrawable).draw(mCanvas); } @Test public void drawOver_preferenceCategory_shouldSkipFirst() { when(mRecyclerView.getAdapter()).thenReturn(mAdapter); when(mRecyclerView.getChildCount()).thenReturn(3); when(mAdapter.getItem(anyInt())).thenReturn(mPrefCategory); when(mRecyclerView.getChildAdapterPosition(any(View.class))) .thenReturn(0) .thenReturn(1) .thenReturn(2); mDecoration.onDrawOver(mCanvas, mRecyclerView, null /* state */); // 3 prefCategory, should skip first draw verify(mDrawable, times(2)).draw(mCanvas); } @Test public void drawOver_preference_doNotDrawDivider() { when(mRecyclerView.getAdapter()).thenReturn(mAdapter); when(mRecyclerView.getChildCount()).thenReturn(1); when(mAdapter.getItem(anyInt())).thenReturn(mNormalPref); mDecoration.onDrawOver(mCanvas, mRecyclerView, null /* state */); verify(mDrawable, never()).draw(mCanvas); } }