1 /* 2 * Copyright 2019 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 androidx.navigation.dynamicfeatures.fragment.ui 18 19 import android.content.ComponentName 20 import android.content.pm.PackageManager 21 import android.os.Bundle 22 import android.util.Log 23 import android.view.View 24 import android.widget.Button 25 import android.widget.ImageView 26 import android.widget.ProgressBar 27 import android.widget.TextView 28 import androidx.annotation.StringRes 29 import androidx.navigation.dynamicfeatures.fragment.R 30 import androidx.navigation.fragment.findNavController 31 import com.google.android.play.core.splitinstall.model.SplitInstallErrorCode 32 33 /** 34 * The default [androidx.fragment.app.Fragment] to display during installation progress. 35 * 36 * This `Fragment` provides a default UI and handles split install state changes so you don't have 37 * to deal with this. 38 * 39 * To create a custom progress fragment, extend [AbstractProgressFragment]. 40 */ 41 public class DefaultProgressFragment : 42 AbstractProgressFragment(R.layout.dynamic_feature_install_fragment) { 43 44 internal companion object { 45 private const val PROGRESS_MAX = 100 46 private const val TAG = "DefaultProgressFragment" 47 } 48 49 private var title: TextView? = null 50 private var progressBar: ProgressBar? = null 51 private var action: Button? = null 52 onViewCreatednull53 override fun onViewCreated(view: View, savedInstanceState: Bundle?) { 54 super.onViewCreated(view, savedInstanceState) 55 with(view) { 56 title = findViewById(R.id.progress_title) 57 progressBar = findViewById(R.id.installation_progress) 58 setActivityIcon(findViewById(R.id.progress_icon)) 59 action = findViewById(R.id.progress_action) 60 } 61 } 62 onDestroyViewnull63 override fun onDestroyView() { 64 super.onDestroyView() 65 title = null 66 progressBar = null 67 action = null 68 } 69 setActivityIconnull70 private fun setActivityIcon(activityIcon: ImageView) { 71 with(requireContext().packageManager) { 72 val icon = 73 try { 74 getActivityIcon(ComponentName(requireContext(), requireActivity().javaClass)) 75 } catch (e: PackageManager.NameNotFoundException) { 76 defaultActivityIcon 77 } 78 activityIcon.setImageDrawable(icon) 79 } 80 } 81 onProgressnull82 override fun onProgress(status: Int, bytesDownloaded: Long, bytesTotal: Long) { 83 progressBar?.run { 84 visibility = View.VISIBLE 85 if (bytesTotal == 0L) { 86 isIndeterminate = true 87 } else { 88 progress = (PROGRESS_MAX * bytesDownloaded / bytesTotal).toInt() 89 isIndeterminate = false 90 } 91 } 92 } 93 onCancellednull94 override fun onCancelled() { 95 displayErrorState(R.string.installation_cancelled) 96 displayAction(R.string.retry) { navigate() } 97 } 98 onFailednull99 override fun onFailed(@SplitInstallErrorCode errorCode: Int) { 100 Log.w(TAG, "Installation failed with error $errorCode") 101 displayErrorState(R.string.installation_failed) 102 displayAction(R.string.ok) { findNavController().popBackStack() } 103 } 104 105 /** Display an error state message. */ displayErrorStatenull106 private fun displayErrorState(@StringRes text: Int) { 107 title?.setText(text) 108 progressBar?.visibility = View.INVISIBLE 109 } 110 111 /** Display the action button and assign `onClick` behavior. */ displayActionnull112 private fun displayAction(@StringRes text: Int, onClick: () -> Unit) { 113 action?.run { 114 setText(text) 115 setOnClickListener { onClick() } 116 visibility = View.VISIBLE 117 } 118 } 119 } 120