1 /* 2 * Copyright (C) 2017 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.example.android.downloadablefonts; 18 19 import android.graphics.Typeface; 20 import android.os.Bundle; 21 import android.os.Handler; 22 import android.os.HandlerThread; 23 import android.support.design.widget.TextInputLayout; 24 import android.support.v4.provider.FontRequest; 25 import android.support.v4.provider.FontsContractCompat; 26 import android.support.v4.util.ArraySet; 27 import android.support.v7.app.AppCompatActivity; 28 import android.text.Editable; 29 import android.text.TextWatcher; 30 import android.util.Log; 31 import android.view.View; 32 import android.widget.ArrayAdapter; 33 import android.widget.AutoCompleteTextView; 34 import android.widget.Button; 35 import android.widget.CheckBox; 36 import android.widget.ProgressBar; 37 import android.widget.SeekBar; 38 import android.widget.TextView; 39 import android.widget.Toast; 40 41 import java.util.Arrays; 42 43 import static com.example.android.downloadablefonts.Constants.ITALIC_DEFAULT; 44 import static com.example.android.downloadablefonts.Constants.WEIGHT_DEFAULT; 45 import static com.example.android.downloadablefonts.Constants.WEIGHT_MAX; 46 import static com.example.android.downloadablefonts.Constants.WIDTH_DEFAULT; 47 import static com.example.android.downloadablefonts.Constants.WIDTH_MAX; 48 49 public class MainActivity extends AppCompatActivity { 50 51 private static final String TAG = "MainActivity"; 52 53 private Handler mHandler = null; 54 55 private TextView mDownloadableFontTextView; 56 private SeekBar mWidthSeekBar; 57 private SeekBar mWeightSeekBar; 58 private SeekBar mItalicSeekBar; 59 private CheckBox mBestEffort; 60 private Button mRequestDownloadButton; 61 62 private ArraySet<String> mFamilyNameSet; 63 64 @Override 65 protected void onCreate(Bundle savedInstanceState) { 66 super.onCreate(savedInstanceState); 67 setContentView(R.layout.activity_main); 68 69 initializeSeekBars(); 70 mFamilyNameSet = new ArraySet<>(); 71 mFamilyNameSet.addAll(Arrays.asList(getResources().getStringArray(R.array.family_names))); 72 73 mDownloadableFontTextView = findViewById(R.id.textview); 74 ArrayAdapter<String> adapter = new ArrayAdapter<>(this, 75 android.R.layout.simple_dropdown_item_1line, 76 getResources().getStringArray(R.array.family_names)); 77 final TextInputLayout familyNameInput = findViewById(R.id.auto_complete_family_name_input); 78 final AutoCompleteTextView autoCompleteFamilyName = findViewById( 79 R.id.auto_complete_family_name); 80 autoCompleteFamilyName.setAdapter(adapter); 81 autoCompleteFamilyName.addTextChangedListener(new TextWatcher() { 82 @Override 83 public void beforeTextChanged(CharSequence charSequence, int start, int count, 84 int after) { 85 // No op 86 } 87 88 @Override 89 public void onTextChanged(CharSequence charSequence, int start, int count, int after) { 90 if (isValidFamilyName(charSequence.toString())) { 91 familyNameInput.setErrorEnabled(false); 92 familyNameInput.setError(""); 93 } else { 94 familyNameInput.setErrorEnabled(true); 95 familyNameInput.setError(getString(R.string.invalid_family_name)); 96 } 97 } 98 99 @Override 100 public void afterTextChanged(Editable editable) { 101 // No op 102 } 103 }); 104 105 mRequestDownloadButton = findViewById(R.id.button_request); 106 mRequestDownloadButton.setOnClickListener(new View.OnClickListener() { 107 @Override 108 public void onClick(View view) { 109 String familyName = autoCompleteFamilyName.getText().toString(); 110 if (!isValidFamilyName(familyName)) { 111 familyNameInput.setErrorEnabled(true); 112 familyNameInput.setError(getString(R.string.invalid_family_name)); 113 Toast.makeText( 114 MainActivity.this, 115 R.string.invalid_input, 116 Toast.LENGTH_SHORT).show(); 117 return; 118 } 119 requestDownload(familyName); 120 mRequestDownloadButton.setEnabled(false); 121 } 122 }); 123 mBestEffort = findViewById(R.id.checkbox_best_effort); 124 } 125 126 private void requestDownload(String familyName) { 127 QueryBuilder queryBuilder = new QueryBuilder(familyName) 128 .withWidth(progressToWidth(mWidthSeekBar.getProgress())) 129 .withWeight(progressToWeight(mWeightSeekBar.getProgress())) 130 .withItalic(progressToItalic(mItalicSeekBar.getProgress())) 131 .withBestEffort(mBestEffort.isChecked()); 132 String query = queryBuilder.build(); 133 134 Log.d(TAG, "Requesting a font. Query: " + query); 135 FontRequest request = new FontRequest( 136 "com.google.android.gms.fonts", 137 "com.google.android.gms", 138 query, 139 R.array.com_google_android_gms_fonts_certs); 140 141 final ProgressBar progressBar = findViewById(R.id.progressBar); 142 progressBar.setVisibility(View.VISIBLE); 143 144 FontsContractCompat.FontRequestCallback callback = new FontsContractCompat 145 .FontRequestCallback() { 146 @Override 147 public void onTypefaceRetrieved(Typeface typeface) { 148 mDownloadableFontTextView.setTypeface(typeface); 149 progressBar.setVisibility(View.GONE); 150 mRequestDownloadButton.setEnabled(true); 151 } 152 153 @Override 154 public void onTypefaceRequestFailed(int reason) { 155 Toast.makeText(MainActivity.this, 156 getString(R.string.request_failed, reason), Toast.LENGTH_LONG) 157 .show(); 158 progressBar.setVisibility(View.GONE); 159 mRequestDownloadButton.setEnabled(true); 160 } 161 }; 162 FontsContractCompat 163 .requestFont(MainActivity.this, request, callback, 164 getHandlerThreadHandler()); 165 } 166 167 private void initializeSeekBars() { 168 mWidthSeekBar = findViewById(R.id.seek_bar_width); 169 int widthValue = (int) (100 * (float) WIDTH_DEFAULT / (float) WIDTH_MAX); 170 mWidthSeekBar.setProgress(widthValue); 171 final TextView widthTextView = findViewById(R.id.textview_width); 172 widthTextView.setText(String.valueOf(widthValue)); 173 mWidthSeekBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() { 174 @Override 175 public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) { 176 widthTextView 177 .setText(String.valueOf(progressToWidth(progress))); 178 } 179 180 @Override 181 public void onStartTrackingTouch(SeekBar seekBar) { 182 } 183 184 @Override 185 public void onStopTrackingTouch(SeekBar seekBar) { 186 } 187 }); 188 189 mWeightSeekBar = findViewById(R.id.seek_bar_weight); 190 float weightValue = (float) WEIGHT_DEFAULT / (float) WEIGHT_MAX * 100; 191 mWeightSeekBar.setProgress((int) weightValue); 192 final TextView weightTextView = findViewById(R.id.textview_weight); 193 weightTextView.setText(String.valueOf(WEIGHT_DEFAULT)); 194 mWeightSeekBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() { 195 @Override 196 public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) { 197 weightTextView 198 .setText(String.valueOf(progressToWeight(progress))); 199 } 200 201 @Override 202 public void onStartTrackingTouch(SeekBar seekBar) { 203 } 204 205 @Override 206 public void onStopTrackingTouch(SeekBar seekBar) { 207 } 208 }); 209 210 mItalicSeekBar = findViewById(R.id.seek_bar_italic); 211 mItalicSeekBar.setProgress((int) ITALIC_DEFAULT); 212 final TextView italicTextView = findViewById(R.id.textview_italic); 213 italicTextView.setText(String.valueOf(ITALIC_DEFAULT)); 214 mItalicSeekBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() { 215 @Override 216 public void onProgressChanged(SeekBar seekBar, int progress, boolean fromuser) { 217 italicTextView 218 .setText(String.valueOf(progressToItalic(progress))); 219 } 220 221 @Override 222 public void onStartTrackingTouch(SeekBar seekBar) { 223 } 224 225 @Override 226 public void onStopTrackingTouch(SeekBar seekBar) { 227 } 228 }); 229 } 230 231 private boolean isValidFamilyName(String familyName) { 232 return familyName != null && mFamilyNameSet.contains(familyName); 233 } 234 235 private Handler getHandlerThreadHandler() { 236 if (mHandler == null) { 237 HandlerThread handlerThread = new HandlerThread("fonts"); 238 handlerThread.start(); 239 mHandler = new Handler(handlerThread.getLooper()); 240 } 241 return mHandler; 242 } 243 244 /** 245 * Converts progress from a SeekBar to the value of width. 246 * @param progress is passed from 0 to 100 inclusive 247 * @return the converted width 248 */ 249 private float progressToWidth(int progress) { 250 return progress == 0 ? 1 : progress * WIDTH_MAX / 100; 251 } 252 253 /** 254 * Converts progress from a SeekBar to the value of weight. 255 * @param progress is passed from 0 to 100 inclusive 256 * @return the converted weight 257 */ 258 private int progressToWeight(int progress) { 259 if (progress == 0) { 260 return 1; // The range of the weight is between (0, 1000) (exclusive) 261 } else if (progress == 100) { 262 return WEIGHT_MAX - 1; // The range of the weight is between (0, 1000) (exclusive) 263 } else { 264 return WEIGHT_MAX * progress / 100; 265 } 266 } 267 268 /** 269 * Converts progress from a SeekBar to the value of italic. 270 * @param progress is passed from 0 to 100 inclusive. 271 * @return the converted italic 272 */ 273 private float progressToItalic(int progress) { 274 return (float) progress / 100f; 275 } 276 } 277