Home | History | Annotate | Download | only in downloadablefonts
      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