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 com.example.android.downloadablefonts.Constants.ITALIC_DEFAULT
     44 import com.example.android.downloadablefonts.Constants.WEIGHT_DEFAULT
     45 import com.example.android.downloadablefonts.Constants.WEIGHT_MAX
     46 import com.example.android.downloadablefonts.Constants.WIDTH_DEFAULT
     47 import com.example.android.downloadablefonts.Constants.WIDTH_MAX
     48 
     49 class MainActivity : AppCompatActivity() {
     50 
     51     lateinit private var mHandler: Handler
     52 
     53     lateinit private var mDownloadableFontTextView: TextView
     54     lateinit private var mWidthSeekBar: SeekBar
     55     lateinit private var mWeightSeekBar: SeekBar
     56     lateinit private var mItalicSeekBar: SeekBar
     57     lateinit private var mBestEffort: CheckBox
     58     lateinit private var mRequestDownloadButton: Button
     59 
     60     lateinit private var mFamilyNameSet: ArraySet<String>
     61 
     62     override fun onCreate(savedInstanceState: Bundle?) {
     63         super.onCreate(savedInstanceState)
     64         setContentView(R.layout.activity_main)
     65 
     66         val handlerThread = HandlerThread("fonts")
     67         handlerThread.start()
     68         mHandler = Handler(handlerThread.looper)
     69         initializeSeekBars()
     70         mFamilyNameSet = ArraySet<String>()
     71         mFamilyNameSet.addAll(Arrays.asList(*resources.getStringArray(R.array.family_names)))
     72 
     73         mDownloadableFontTextView = findViewById<TextView>(R.id.textview)
     74         val adapter = ArrayAdapter(this,
     75                 android.R.layout.simple_dropdown_item_1line,
     76                 resources.getStringArray(R.array.family_names))
     77         val familyNameInput = findViewById<TextInputLayout>(R.id.auto_complete_family_name_input)
     78         val autoCompleteFamilyName = findViewById<AutoCompleteTextView>(R.id.auto_complete_family_name)
     79         autoCompleteFamilyName.setAdapter<ArrayAdapter<String>>(adapter)
     80         autoCompleteFamilyName.addTextChangedListener(object : TextWatcher {
     81             override fun beforeTextChanged(charSequence: CharSequence, start: Int, count: Int,
     82                                            after: Int) {
     83                 // No op
     84             }
     85 
     86             override fun onTextChanged(charSequence: CharSequence, start: Int, count: Int, after: Int) {
     87                 if (isValidFamilyName(charSequence.toString())) {
     88                     familyNameInput.isErrorEnabled = false
     89                     familyNameInput.error = ""
     90                 } else {
     91                     familyNameInput.isErrorEnabled = true
     92                     familyNameInput.error = getString(R.string.invalid_family_name)
     93                 }
     94             }
     95 
     96             override fun afterTextChanged(editable: Editable) {
     97                 // No op
     98             }
     99         })
    100 
    101         mRequestDownloadButton = findViewById<Button>(R.id.button_request)
    102         mRequestDownloadButton.setOnClickListener(View.OnClickListener {
    103             val familyName = autoCompleteFamilyName.getText().toString()
    104             if (!isValidFamilyName(familyName)) {
    105                 familyNameInput.isErrorEnabled = true
    106                 familyNameInput.error = getString(R.string.invalid_family_name)
    107                 Toast.makeText(
    108                         this@MainActivity,
    109                         R.string.invalid_input,
    110                         Toast.LENGTH_SHORT).show()
    111                 return@OnClickListener
    112             }
    113             requestDownload(familyName)
    114             mRequestDownloadButton.isEnabled = false
    115         })
    116         mBestEffort = findViewById<CheckBox>(R.id.checkbox_best_effort)
    117     }
    118 
    119     private fun requestDownload(familyName: String) {
    120         val queryBuilder = QueryBuilder(familyName,
    121                 width = progressToWidth(mWidthSeekBar.progress),
    122                 weight = progressToWeight(mWeightSeekBar.progress),
    123                 italic = progressToItalic(mItalicSeekBar.progress),
    124                 besteffort =  mBestEffort.isChecked)
    125         val query = queryBuilder.build()
    126 
    127         Log.d(TAG, "Requesting a font. Query: " + query)
    128         val request = FontRequest(
    129                 "com.google.android.gms.fonts",
    130                 "com.google.android.gms",
    131                 query,
    132                 R.array.com_google_android_gms_fonts_certs)
    133 
    134         val progressBar = findViewById<ProgressBar>(R.id.progressBar)
    135         progressBar.visibility = View.VISIBLE
    136 
    137         val callback = object : FontsContractCompat.FontRequestCallback() {
    138             override fun onTypefaceRetrieved(typeface: Typeface) {
    139                 mDownloadableFontTextView.typeface = typeface
    140                 progressBar.visibility = View.GONE
    141                 mRequestDownloadButton.isEnabled = true
    142             }
    143 
    144             override fun onTypefaceRequestFailed(reason: Int) {
    145                 Toast.makeText(this@MainActivity,
    146                         getString(R.string.request_failed, reason), Toast.LENGTH_LONG)
    147                         .show()
    148                 progressBar.visibility = View.GONE
    149                 mRequestDownloadButton.isEnabled = true
    150             }
    151         }
    152         FontsContractCompat
    153                 .requestFont(this@MainActivity, request, callback, mHandler)
    154     }
    155 
    156     private fun initializeSeekBars() {
    157         mWidthSeekBar = findViewById<SeekBar>(R.id.seek_bar_width)
    158         val widthValue = (100 * WIDTH_DEFAULT.toFloat() / WIDTH_MAX.toFloat()).toInt()
    159         mWidthSeekBar.progress = widthValue
    160         val widthTextView = findViewById<TextView>(R.id.textview_width)
    161         widthTextView.text = widthValue.toString()
    162         mWidthSeekBar.setOnSeekBarChangeListener(object : SeekBar.OnSeekBarChangeListener {
    163             override fun onProgressChanged(seekBar: SeekBar, progress: Int, fromUser: Boolean) {
    164                 widthTextView.text = progressToWidth(progress).toString()
    165             }
    166 
    167             override fun onStartTrackingTouch(seekBar: SeekBar) {}
    168 
    169             override fun onStopTrackingTouch(seekBar: SeekBar) {}
    170         })
    171 
    172         mWeightSeekBar = findViewById(R.id.seek_bar_weight)
    173         val weightValue = WEIGHT_DEFAULT.toFloat() / WEIGHT_MAX.toFloat() * 100
    174         mWeightSeekBar.progress = weightValue.toInt()
    175         val weightTextView = findViewById<TextView>(R.id.textview_weight)
    176         weightTextView.text = WEIGHT_DEFAULT.toString()
    177         mWeightSeekBar.setOnSeekBarChangeListener(object : SeekBar.OnSeekBarChangeListener {
    178             override fun onProgressChanged(seekBar: SeekBar, progress: Int, fromUser: Boolean) {
    179                 weightTextView
    180                         .setText(progressToWeight(progress).toString())
    181             }
    182 
    183             override fun onStartTrackingTouch(seekBar: SeekBar) {}
    184 
    185             override fun onStopTrackingTouch(seekBar: SeekBar) {}
    186         })
    187 
    188         mItalicSeekBar = findViewById<SeekBar>(R.id.seek_bar_italic)
    189         mItalicSeekBar.progress = ITALIC_DEFAULT.toInt()
    190         val italicTextView = findViewById<TextView>(R.id.textview_italic)
    191         italicTextView.text = ITALIC_DEFAULT.toString()
    192         mItalicSeekBar.setOnSeekBarChangeListener(object : SeekBar.OnSeekBarChangeListener {
    193             override fun onProgressChanged(seekBar: SeekBar, progress: Int, fromUser: Boolean) {
    194                 italicTextView
    195                         .setText(progressToItalic(progress).toString())
    196             }
    197 
    198             override fun onStartTrackingTouch(seekBar: SeekBar) {}
    199 
    200             override fun onStopTrackingTouch(seekBar: SeekBar) {}
    201         })
    202     }
    203 
    204     private fun isValidFamilyName(familyName: String?): Boolean {
    205         return familyName != null && mFamilyNameSet.contains(familyName)
    206     }
    207 
    208     /**
    209      * Converts progress from a SeekBar to the value of width.
    210      * @param progress is passed from 0 to 100 inclusive
    211      * *
    212      * @return the converted width
    213      */
    214     private fun progressToWidth(progress: Int): Float {
    215         return (if (progress == 0) 1 else progress * WIDTH_MAX / 100).toFloat()
    216     }
    217 
    218     /**
    219      * Converts progress from a SeekBar to the value of weight.
    220      * @param progress is passed from 0 to 100 inclusive
    221      * *
    222      * @return the converted weight
    223      */
    224     private fun progressToWeight(progress: Int): Int {
    225         if (progress == 0) {
    226             return 1 // The range of the weight is between (0, 1000) (exclusive)
    227         } else if (progress == 100) {
    228             return WEIGHT_MAX - 1 // The range of the weight is between (0, 1000) (exclusive)
    229         } else {
    230             return WEIGHT_MAX * progress / 100
    231         }
    232     }
    233 
    234     /**
    235      * Converts progress from a SeekBar to the value of italic.
    236      * @param progress is passed from 0 to 100 inclusive.
    237      * *
    238      * @return the converted italic
    239      */
    240     private fun progressToItalic(progress: Int): Float {
    241         return progress.toFloat() / 100f
    242     }
    243 
    244     companion object {
    245 
    246         private val TAG = "MainActivity"
    247     }
    248 }
    249 
    250