1 /* -*- Mode: Java; c-basic-offset: 4; tab-width: 4; indent-tabs-mode: nil; -*-
2  * This Source Code Form is subject to the terms of the Mozilla Public
3  * License, v. 2.0. If a copy of the MPL was not distributed with this
4  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
5 
6 package org.mozilla.gecko.preferences;
7 
8 import org.mozilla.gecko.R;
9 
10 import android.app.AlertDialog;
11 import android.content.Context;
12 import android.content.res.Resources;
13 import android.graphics.Color;
14 import android.preference.DialogPreference;
15 import android.util.AttributeSet;
16 import android.util.Log;
17 import android.util.TypedValue;
18 import android.view.LayoutInflater;
19 import android.view.View;
20 import android.view.ViewGroup;
21 import android.widget.Button;
22 import android.widget.ScrollView;
23 import android.widget.TextView;
24 
25 import java.util.HashMap;
26 
27 class FontSizePreference extends DialogPreference {
28     private static final String LOGTAG = "FontSizePreference";
29     private static final int TWIP_TO_PT_RATIO = 20; // 20 twip = 1 point.
30     private static final int PREVIEW_FONT_SIZE_UNIT = TypedValue.COMPLEX_UNIT_PT;
31     private static final int DEFAULT_FONT_INDEX = 2;
32 
33     private final Context mContext;
34     /** Container for mPreviewFontView to allow for scrollable padding at the top of the view. */
35     private ScrollView mScrollingContainer;
36     private TextView mPreviewFontView;
37     private Button mIncreaseFontButton;
38     private Button mDecreaseFontButton;
39 
40     private final String[] mFontTwipValues;
41     private final String[] mFontSizeNames; // Ex: "Small".
42     /** Index into the above arrays for the saved preference value (from Gecko). */
43     private int mSavedFontIndex = DEFAULT_FONT_INDEX;
44     /** Index into the above arrays for the currently displayed font size (the preview). */
45     private int mPreviewFontIndex = mSavedFontIndex;
46     private final HashMap<String, Integer> mFontTwipToIndexMap;
47 
FontSizePreference(Context context, AttributeSet attrs)48     public FontSizePreference(Context context, AttributeSet attrs) {
49         super(context, attrs);
50         mContext = context;
51 
52         final Resources res = mContext.getResources();
53         mFontTwipValues = res.getStringArray(R.array.pref_font_size_values);
54         mFontSizeNames = res.getStringArray(R.array.pref_font_size_entries);
55         mFontTwipToIndexMap = new HashMap<String, Integer>();
56         for (int i = 0; i < mFontTwipValues.length; ++i) {
57             mFontTwipToIndexMap.put(mFontTwipValues[i], i);
58         }
59     }
60 
61     @Override
onPrepareDialogBuilder(AlertDialog.Builder builder)62     protected void onPrepareDialogBuilder(AlertDialog.Builder builder) {
63         final LayoutInflater inflater =
64             (LayoutInflater) mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
65         View dialogView = inflater.inflate(R.layout.font_size_preference, null);
66         initInternalViews(dialogView);
67         updatePreviewFontSize(mFontTwipValues[mPreviewFontIndex]);
68 
69         builder.setTitle(null);
70         builder.setView(dialogView);
71     }
72 
73     /** Saves relevant views to instance variables and initializes their settings. */
initInternalViews(View dialogView)74     private void initInternalViews(View dialogView) {
75         mScrollingContainer = (ScrollView) dialogView.findViewById(R.id.scrolling_container);
76         // Background cannot be set in XML (see bug 783597 - TODO: Change this to XML when bug is fixed).
77         mScrollingContainer.setBackgroundColor(Color.WHITE);
78         mPreviewFontView = (TextView) dialogView.findViewById(R.id.preview);
79 
80         mDecreaseFontButton = (Button) dialogView.findViewById(R.id.decrease_preview_font_button);
81         mIncreaseFontButton = (Button) dialogView.findViewById(R.id.increase_preview_font_button);
82         setButtonState(mPreviewFontIndex);
83         mDecreaseFontButton.setOnClickListener(new View.OnClickListener() {
84             @Override
85             public void onClick(View v) {
86                 mPreviewFontIndex = Math.max(mPreviewFontIndex - 1, 0);
87                 updatePreviewFontSize(mFontTwipValues[mPreviewFontIndex]);
88                 mIncreaseFontButton.setEnabled(true);
89                 // If we reached the minimum index, disable the button.
90                 if (mPreviewFontIndex == 0) {
91                     mDecreaseFontButton.setEnabled(false);
92                 }
93             }
94         });
95         mIncreaseFontButton.setOnClickListener(new View.OnClickListener() {
96             @Override
97             public void onClick(View v) {
98                 mPreviewFontIndex = Math.min(mPreviewFontIndex + 1, mFontTwipValues.length - 1);
99                 updatePreviewFontSize(mFontTwipValues[mPreviewFontIndex]);
100 
101                 mDecreaseFontButton.setEnabled(true);
102                 // If we reached the maximum index, disable the button.
103                 if (mPreviewFontIndex == mFontTwipValues.length - 1) {
104                     mIncreaseFontButton.setEnabled(false);
105                 }
106             }
107         });
108     }
109 
110     @Override
onDialogClosed(boolean positiveResult)111     protected void onDialogClosed(boolean positiveResult) {
112         super.onDialogClosed(positiveResult);
113         if (!positiveResult) {
114             mPreviewFontIndex = mSavedFontIndex;
115             return;
116         }
117         mSavedFontIndex = mPreviewFontIndex;
118         final String twipVal = mFontTwipValues[mSavedFontIndex];
119         final OnPreferenceChangeListener prefChangeListener = getOnPreferenceChangeListener();
120         if (prefChangeListener == null) {
121             Log.e(LOGTAG, "PreferenceChangeListener is null. FontSizePreference will not be saved to Gecko.");
122             return;
123         }
124         prefChangeListener.onPreferenceChange(this, twipVal);
125     }
126 
127     /**
128      * Finds the index of the given twip value and sets it as the saved preference value. Also the
129      * current preview text size to the given value. Does not update the mPreviewFontView text size.
130      */
setSavedFontSize(String twip)131     protected void setSavedFontSize(String twip) {
132         final Integer index = mFontTwipToIndexMap.get(twip);
133         if (index != null) {
134             mSavedFontIndex = index;
135             mPreviewFontIndex = mSavedFontIndex;
136             return;
137         }
138         resetSavedFontSizeToDefault();
139         Log.e(LOGTAG, "setSavedFontSize: Given font size does not exist in twip values map. Reverted to default font size.");
140     }
141 
142     /**
143      * Updates the mPreviewFontView to the given text size, resets the container's scroll to the top
144      * left, and invalidates the view. Does not update the font indices.
145      */
updatePreviewFontSize(String twip)146     private void updatePreviewFontSize(String twip) {
147         float pt = convertTwipStrToPT(twip);
148         // Android will not render a font size of 0 pt but for Gecko, 0 twip turns off font
149         // inflation. Thus we special case 0 twip to display a renderable font size.
150         if (pt == 0) {
151             // Android adds an inexplicable extra margin on the smallest font size so to get around
152             // this, we reinflate the view.
153             ViewGroup parentView = (ViewGroup) mScrollingContainer.getParent();
154             parentView.removeAllViews();
155             final LayoutInflater inflater =
156                 (LayoutInflater) mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
157             View dialogView = inflater.inflate(R.layout.font_size_preference, parentView);
158             initInternalViews(dialogView);
159             mPreviewFontView.setTextSize(PREVIEW_FONT_SIZE_UNIT, 1);
160         } else {
161             mPreviewFontView.setTextSize(PREVIEW_FONT_SIZE_UNIT, pt);
162         }
163         mScrollingContainer.scrollTo(0, 0);
164     }
165 
166     /**
167      * Resets the font indices to the default value. Does not update the mPreviewFontView text size.
168      */
resetSavedFontSizeToDefault()169     private void resetSavedFontSizeToDefault() {
170         mSavedFontIndex = DEFAULT_FONT_INDEX;
171         mPreviewFontIndex = mSavedFontIndex;
172     }
173 
setButtonState(int index)174     private void setButtonState(int index) {
175         if (index == 0) {
176             mDecreaseFontButton.setEnabled(false);
177         } else if (index == mFontTwipValues.length - 1) {
178             mIncreaseFontButton.setEnabled(false);
179         }
180     }
181 
182     /**
183      * Returns the name of the font size (ex: "Small") at the currently saved preference value.
184      */
getSavedFontSizeName()185     protected String getSavedFontSizeName() {
186         return mFontSizeNames[mSavedFontIndex];
187     }
188 
convertTwipStrToPT(String twip)189     private float convertTwipStrToPT(String twip) {
190         return Float.parseFloat(twip) / TWIP_TO_PT_RATIO;
191     }
192 }
193