Bug 1366704 - Part 1: Implement ThemedListView for Photon visual refresh. r?sebastian,walkingice draft
authorjwu <topwu.tw@gmail.com>
Fri, 30 Jun 2017 09:32:26 -0700
changeset 602829 65560f1efa79b0beb430f2fb4996e6f68f58d8be
parent 602828 0f294b62d80381d7e5071ed9c3467bc761442d36
child 602830 90f4ab22ec10ef7c7ebce70caf8144546628ba2e
push id66568
push userbmo:topwu.tw@gmail.com
push dateFri, 30 Jun 2017 20:17:31 +0000
reviewerssebastian, walkingice
bugs1366704
milestone56.0a1
Bug 1366704 - Part 1: Implement ThemedListView for Photon visual refresh. r?sebastian,walkingice MozReview-Commit-ID: EdPrQ1oE37l
mobile/android/base/java/org/mozilla/gecko/widget/themed/ThemedEditText.java
mobile/android/base/java/org/mozilla/gecko/widget/themed/ThemedFrameLayout.java
mobile/android/base/java/org/mozilla/gecko/widget/themed/ThemedImageButton.java
mobile/android/base/java/org/mozilla/gecko/widget/themed/ThemedImageView.java
mobile/android/base/java/org/mozilla/gecko/widget/themed/ThemedLinearLayout.java
mobile/android/base/java/org/mozilla/gecko/widget/themed/ThemedListView.java
mobile/android/base/java/org/mozilla/gecko/widget/themed/ThemedRelativeLayout.java
mobile/android/base/java/org/mozilla/gecko/widget/themed/ThemedTextSwitcher.java
mobile/android/base/java/org/mozilla/gecko/widget/themed/ThemedTextView.java
mobile/android/base/java/org/mozilla/gecko/widget/themed/ThemedView.java
mobile/android/base/java/org/mozilla/gecko/widget/themed/ThemedView.java.frag
mobile/android/base/java/org/mozilla/gecko/widget/themed/generate_themed_views.py
mobile/android/base/moz.build
--- a/mobile/android/base/java/org/mozilla/gecko/widget/themed/ThemedEditText.java
+++ b/mobile/android/base/java/org/mozilla/gecko/widget/themed/ThemedEditText.java
@@ -57,25 +57,25 @@ public class ThemedEditText extends andr
         }
 
         final TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.LightweightTheme);
         autoUpdateTheme = theme != null && a.getBoolean(R.styleable.LightweightTheme_autoUpdateTheme, true);
         a.recycle();
     }
 
     @Override
-    public void onAttachedToWindow() {
+    protected void onAttachedToWindow() {
         super.onAttachedToWindow();
 
         if (autoUpdateTheme)
             theme.addListener(this);
     }
 
     @Override
-    public void onDetachedFromWindow() {
+    protected void onDetachedFromWindow() {
         super.onDetachedFromWindow();
 
         if (autoUpdateTheme)
             theme.removeListener(this);
     }
 
     @Override
     public int[] onCreateDrawableState(int extraSpace) {
--- a/mobile/android/base/java/org/mozilla/gecko/widget/themed/ThemedFrameLayout.java
+++ b/mobile/android/base/java/org/mozilla/gecko/widget/themed/ThemedFrameLayout.java
@@ -57,25 +57,25 @@ public class ThemedFrameLayout extends a
         }
 
         final TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.LightweightTheme);
         autoUpdateTheme = theme != null && a.getBoolean(R.styleable.LightweightTheme_autoUpdateTheme, true);
         a.recycle();
     }
 
     @Override
-    public void onAttachedToWindow() {
+    protected void onAttachedToWindow() {
         super.onAttachedToWindow();
 
         if (autoUpdateTheme)
             theme.addListener(this);
     }
 
     @Override
-    public void onDetachedFromWindow() {
+    protected void onDetachedFromWindow() {
         super.onDetachedFromWindow();
 
         if (autoUpdateTheme)
             theme.removeListener(this);
     }
 
     @Override
     public int[] onCreateDrawableState(int extraSpace) {
--- a/mobile/android/base/java/org/mozilla/gecko/widget/themed/ThemedImageButton.java
+++ b/mobile/android/base/java/org/mozilla/gecko/widget/themed/ThemedImageButton.java
@@ -65,25 +65,25 @@ public class ThemedImageButton extends a
         themedA.recycle();
 
         // Apply the tint initially - the Drawable is
         // initially set by XML via super's constructor.
         setTintedImageDrawable(getDrawable());
     }
 
     @Override
-    public void onAttachedToWindow() {
+    protected void onAttachedToWindow() {
         super.onAttachedToWindow();
 
         if (autoUpdateTheme)
             theme.addListener(this);
     }
 
     @Override
-    public void onDetachedFromWindow() {
+    protected void onDetachedFromWindow() {
         super.onDetachedFromWindow();
 
         if (autoUpdateTheme)
             theme.removeListener(this);
     }
 
     @Override
     public int[] onCreateDrawableState(int extraSpace) {
--- a/mobile/android/base/java/org/mozilla/gecko/widget/themed/ThemedImageView.java
+++ b/mobile/android/base/java/org/mozilla/gecko/widget/themed/ThemedImageView.java
@@ -65,25 +65,25 @@ public class ThemedImageView extends and
         themedA.recycle();
 
         // Apply the tint initially - the Drawable is
         // initially set by XML via super's constructor.
         setTintedImageDrawable(getDrawable());
     }
 
     @Override
-    public void onAttachedToWindow() {
+    protected void onAttachedToWindow() {
         super.onAttachedToWindow();
 
         if (autoUpdateTheme)
             theme.addListener(this);
     }
 
     @Override
-    public void onDetachedFromWindow() {
+    protected void onDetachedFromWindow() {
         super.onDetachedFromWindow();
 
         if (autoUpdateTheme)
             theme.removeListener(this);
     }
 
     @Override
     public int[] onCreateDrawableState(int extraSpace) {
--- a/mobile/android/base/java/org/mozilla/gecko/widget/themed/ThemedLinearLayout.java
+++ b/mobile/android/base/java/org/mozilla/gecko/widget/themed/ThemedLinearLayout.java
@@ -52,25 +52,25 @@ public class ThemedLinearLayout extends 
         }
 
         final TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.LightweightTheme);
         autoUpdateTheme = theme != null && a.getBoolean(R.styleable.LightweightTheme_autoUpdateTheme, true);
         a.recycle();
     }
 
     @Override
-    public void onAttachedToWindow() {
+    protected void onAttachedToWindow() {
         super.onAttachedToWindow();
 
         if (autoUpdateTheme)
             theme.addListener(this);
     }
 
     @Override
-    public void onDetachedFromWindow() {
+    protected void onDetachedFromWindow() {
         super.onDetachedFromWindow();
 
         if (autoUpdateTheme)
             theme.removeListener(this);
     }
 
     @Override
     public int[] onCreateDrawableState(int extraSpace) {
new file mode 100644
--- /dev/null
+++ b/mobile/android/base/java/org/mozilla/gecko/widget/themed/ThemedListView.java
@@ -0,0 +1,172 @@
+// This file is generated by generate_themed_views.py; do not edit.
+
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+package org.mozilla.gecko.widget.themed;
+
+import android.support.v4.content.ContextCompat;
+import org.mozilla.gecko.GeckoApplication;
+import org.mozilla.gecko.lwt.LightweightTheme;
+import org.mozilla.gecko.R;
+import org.mozilla.gecko.util.DrawableUtil;
+
+import android.content.Context;
+import android.content.res.ColorStateList;
+import android.content.res.TypedArray;
+import android.graphics.drawable.ColorDrawable;
+import android.graphics.drawable.Drawable;
+import android.util.AttributeSet;
+
+public class ThemedListView extends android.widget.ListView
+                                     implements LightweightTheme.OnChangeListener {
+    private LightweightTheme theme;
+
+    private static final int[] STATE_PRIVATE_MODE = { R.attr.state_private };
+    private static final int[] STATE_LIGHT = { R.attr.state_light };
+    private static final int[] STATE_DARK = { R.attr.state_dark };
+
+    protected static final int[] PRIVATE_PRESSED_STATE_SET = { R.attr.state_private, android.R.attr.state_pressed };
+    protected static final int[] PRIVATE_FOCUSED_STATE_SET = { R.attr.state_private, android.R.attr.state_focused };
+    protected static final int[] PRIVATE_STATE_SET = { R.attr.state_private };
+
+    private boolean isPrivate;
+    private boolean isLight;
+    private boolean isDark;
+    private boolean autoUpdateTheme;        // always false if there's no theme.
+
+    private ColorStateList drawableColors;
+
+    public ThemedListView(Context context, AttributeSet attrs) {
+        super(context, attrs);
+        initialize(context, attrs, 0);
+    }
+
+    public ThemedListView(Context context, AttributeSet attrs, int defStyle) {
+        super(context, attrs, defStyle);
+        initialize(context, attrs, defStyle);
+    }
+
+    private void initialize(final Context context, final AttributeSet attrs, final int defStyle) {
+        // The theme can be null, particularly if we might be instantiating this
+        // View in an IDE, with no ambient GeckoApplication.
+        final Context applicationContext = context.getApplicationContext();
+        if (applicationContext instanceof GeckoApplication) {
+            theme = ((GeckoApplication) applicationContext).getLightweightTheme();
+        }
+
+        final TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.LightweightTheme);
+        autoUpdateTheme = theme != null && a.getBoolean(R.styleable.LightweightTheme_autoUpdateTheme, true);
+        a.recycle();
+    }
+
+    @Override
+    protected void onAttachedToWindow() {
+        super.onAttachedToWindow();
+
+        if (autoUpdateTheme)
+            theme.addListener(this);
+    }
+
+    @Override
+    protected void onDetachedFromWindow() {
+        super.onDetachedFromWindow();
+
+        if (autoUpdateTheme)
+            theme.removeListener(this);
+    }
+
+    @Override
+    public int[] onCreateDrawableState(int extraSpace) {
+        final int[] drawableState = super.onCreateDrawableState(extraSpace + 1);
+
+        if (isPrivate)
+            mergeDrawableStates(drawableState, STATE_PRIVATE_MODE);
+        else if (isLight)
+            mergeDrawableStates(drawableState, STATE_LIGHT);
+        else if (isDark)
+            mergeDrawableStates(drawableState, STATE_DARK);
+
+        return drawableState;
+    }
+
+    @Override
+    public void onLightweightThemeChanged() {
+        if (autoUpdateTheme && theme.isEnabled())
+            setTheme(theme.isLightTheme());
+    }
+
+    @Override
+    public void onLightweightThemeReset() {
+        if (autoUpdateTheme)
+            resetTheme();
+    }
+
+    @Override
+    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
+        super.onLayout(changed, left, top, right, bottom);
+        onLightweightThemeChanged();
+    }
+
+    public boolean isPrivateMode() {
+        return isPrivate;
+    }
+
+    public void setPrivateMode(boolean isPrivate) {
+        if (this.isPrivate != isPrivate) {
+            this.isPrivate = isPrivate;
+            refreshDrawableState();
+            invalidate();
+        }
+    }
+
+    public void setTheme(boolean isLight) {
+        // Set the theme only if it is different from existing theme.
+        if ((isLight && this.isLight != isLight) ||
+            (!isLight && this.isDark == isLight)) {
+            if (isLight) {
+                this.isLight = true;
+                this.isDark = false;
+            } else {
+                this.isLight = false;
+                this.isDark = true;
+            }
+
+            refreshDrawableState();
+            invalidate();
+        }
+    }
+
+    public void resetTheme() {
+        if (isLight || isDark) {
+            isLight = false;
+            isDark = false;
+            refreshDrawableState();
+            invalidate();
+        }
+    }
+
+    public void setAutoUpdateTheme(boolean autoUpdateTheme) {
+        if (theme == null) {
+            return;
+        }
+
+        if (this.autoUpdateTheme != autoUpdateTheme) {
+            this.autoUpdateTheme = autoUpdateTheme;
+
+            if (autoUpdateTheme)
+                theme.addListener(this);
+            else
+                theme.removeListener(this);
+        }
+    }
+
+    public ColorDrawable getColorDrawable(int id) {
+        return new ColorDrawable(ContextCompat.getColor(getContext(), id));
+    }
+
+    protected LightweightTheme getTheme() {
+        return theme;
+    }
+}
--- a/mobile/android/base/java/org/mozilla/gecko/widget/themed/ThemedRelativeLayout.java
+++ b/mobile/android/base/java/org/mozilla/gecko/widget/themed/ThemedRelativeLayout.java
@@ -57,25 +57,25 @@ public class ThemedRelativeLayout extend
         }
 
         final TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.LightweightTheme);
         autoUpdateTheme = theme != null && a.getBoolean(R.styleable.LightweightTheme_autoUpdateTheme, true);
         a.recycle();
     }
 
     @Override
-    public void onAttachedToWindow() {
+    protected void onAttachedToWindow() {
         super.onAttachedToWindow();
 
         if (autoUpdateTheme)
             theme.addListener(this);
     }
 
     @Override
-    public void onDetachedFromWindow() {
+    protected void onDetachedFromWindow() {
         super.onDetachedFromWindow();
 
         if (autoUpdateTheme)
             theme.removeListener(this);
     }
 
     @Override
     public int[] onCreateDrawableState(int extraSpace) {
--- a/mobile/android/base/java/org/mozilla/gecko/widget/themed/ThemedTextSwitcher.java
+++ b/mobile/android/base/java/org/mozilla/gecko/widget/themed/ThemedTextSwitcher.java
@@ -52,25 +52,25 @@ public class ThemedTextSwitcher extends 
         }
 
         final TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.LightweightTheme);
         autoUpdateTheme = theme != null && a.getBoolean(R.styleable.LightweightTheme_autoUpdateTheme, true);
         a.recycle();
     }
 
     @Override
-    public void onAttachedToWindow() {
+    protected void onAttachedToWindow() {
         super.onAttachedToWindow();
 
         if (autoUpdateTheme)
             theme.addListener(this);
     }
 
     @Override
-    public void onDetachedFromWindow() {
+    protected void onDetachedFromWindow() {
         super.onDetachedFromWindow();
 
         if (autoUpdateTheme)
             theme.removeListener(this);
     }
 
     @Override
     public int[] onCreateDrawableState(int extraSpace) {
--- a/mobile/android/base/java/org/mozilla/gecko/widget/themed/ThemedTextView.java
+++ b/mobile/android/base/java/org/mozilla/gecko/widget/themed/ThemedTextView.java
@@ -57,25 +57,25 @@ public class ThemedTextView extends andr
         }
 
         final TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.LightweightTheme);
         autoUpdateTheme = theme != null && a.getBoolean(R.styleable.LightweightTheme_autoUpdateTheme, true);
         a.recycle();
     }
 
     @Override
-    public void onAttachedToWindow() {
+    protected void onAttachedToWindow() {
         super.onAttachedToWindow();
 
         if (autoUpdateTheme)
             theme.addListener(this);
     }
 
     @Override
-    public void onDetachedFromWindow() {
+    protected void onDetachedFromWindow() {
         super.onDetachedFromWindow();
 
         if (autoUpdateTheme)
             theme.removeListener(this);
     }
 
     @Override
     public int[] onCreateDrawableState(int extraSpace) {
--- a/mobile/android/base/java/org/mozilla/gecko/widget/themed/ThemedView.java
+++ b/mobile/android/base/java/org/mozilla/gecko/widget/themed/ThemedView.java
@@ -57,25 +57,25 @@ public class ThemedView extends android.
         }
 
         final TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.LightweightTheme);
         autoUpdateTheme = theme != null && a.getBoolean(R.styleable.LightweightTheme_autoUpdateTheme, true);
         a.recycle();
     }
 
     @Override
-    public void onAttachedToWindow() {
+    protected void onAttachedToWindow() {
         super.onAttachedToWindow();
 
         if (autoUpdateTheme)
             theme.addListener(this);
     }
 
     @Override
-    public void onDetachedFromWindow() {
+    protected void onDetachedFromWindow() {
         super.onDetachedFromWindow();
 
         if (autoUpdateTheme)
             theme.removeListener(this);
     }
 
     @Override
     public int[] onCreateDrawableState(int extraSpace) {
--- a/mobile/android/base/java/org/mozilla/gecko/widget/themed/ThemedView.java.frag
+++ b/mobile/android/base/java/org/mozilla/gecko/widget/themed/ThemedView.java.frag
@@ -70,25 +70,25 @@ public class Themed@VIEW_NAME_SUFFIX@ ex
 
         // Apply the tint initially - the Drawable is
         // initially set by XML via super's constructor.
         setTintedImageDrawable(getDrawable());
 //#endif
     }
 
     @Override
-    public void onAttachedToWindow() {
+    protected void onAttachedToWindow() {
         super.onAttachedToWindow();
 
         if (autoUpdateTheme)
             theme.addListener(this);
     }
 
     @Override
-    public void onDetachedFromWindow() {
+    protected void onDetachedFromWindow() {
         super.onDetachedFromWindow();
 
         if (autoUpdateTheme)
             theme.removeListener(this);
     }
 
     @Override
     public int[] onCreateDrawableState(int extraSpace) {
--- a/mobile/android/base/java/org/mozilla/gecko/widget/themed/generate_themed_views.py
+++ b/mobile/android/base/java/org/mozilla/gecko/widget/themed/generate_themed_views.py
@@ -55,16 +55,19 @@ views = [
     dict(VIEW_NAME_SUFFIX='TextSwitcher',
          BASE_TYPE='android.widget.TextSwitcher'),
     dict(VIEW_NAME_SUFFIX='TextView',
          BASE_TYPE='android.widget.TextView',
          STYLE_CONSTRUCTOR=1),
     dict(VIEW_NAME_SUFFIX='View',
          BASE_TYPE='android.view.View',
          STYLE_CONSTRUCTOR=1),
+    dict(VIEW_NAME_SUFFIX='ListView',
+         BASE_TYPE='android.widget.ListView',
+         STYLE_CONSTRUCTOR=1),
 ]
 
 for view in views:
     pp = Preprocessor(defines=view, marker='//#')
 
     dest = os.path.join(__DIR__, dest_format_string % view)
     with open(template, 'rU') as input:
         with open(dest, 'wt') as output:
--- a/mobile/android/base/moz.build
+++ b/mobile/android/base/moz.build
@@ -1000,16 +1000,17 @@ gbjar.sources += ['java/org/mozilla/geck
 # generated by a script (java/org/mozilla/gecko/widget/themed/generate_themed_views.py).
 # If you're editing this list, make sure to edit that script.
 gbjar.sources += ['java/org/mozilla/gecko/' + x for x in [
     'widget/themed/ThemedEditText.java',
     'widget/themed/ThemedFrameLayout.java',
     'widget/themed/ThemedImageButton.java',
     'widget/themed/ThemedImageView.java',
     'widget/themed/ThemedLinearLayout.java',
+    'widget/themed/ThemedListView.java',
     'widget/themed/ThemedRelativeLayout.java',
     'widget/themed/ThemedTextSwitcher.java',
     'widget/themed/ThemedTextView.java',
     'widget/themed/ThemedView.java',
 ]]
 if CONFIG['MOZ_ANDROID_PHOTON']:
     gbjar.sources += ['../app/src/photon/java/org/mozilla/gecko/' + x for x in [
         'home/SearchEngineRow.java',