1 /*
2  * Copyright (C) 2018 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.android.packageinstaller.role.utils;
18 
19 import android.animation.Animator;
20 import android.animation.AnimatorListenerAdapter;
21 import android.content.Context;
22 import android.util.DisplayMetrics;
23 import android.util.TypedValue;
24 import android.view.View;
25 import android.view.animation.AnimationUtils;
26 import android.view.animation.Interpolator;
27 
28 import androidx.annotation.Dimension;
29 import androidx.annotation.NonNull;
30 import androidx.annotation.Px;
31 
32 /**
33  * Utility methods about UI.
34  */
35 public class UiUtils {
36 
UiUtils()37     private UiUtils() {}
38 
39     /**
40      * Convert a dimension value in density independent pixels to pixels.
41      *
42      * @param dp the dimension value in density independent pixels
43      * @param context the context to get the {@link DisplayMetrics}
44      * @return the pixels
45      *
46      * @see TypedValue#complexToDimension(int, DisplayMetrics)
47      */
48     @Dimension
dpToPx(@imensionunit = Dimension.DP) float dp, @NonNull Context context)49     public static float dpToPx(@Dimension(unit = Dimension.DP) float dp, @NonNull Context context) {
50         DisplayMetrics metrics = context.getResources().getDisplayMetrics();
51         return TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dp, metrics);
52     }
53 
54     /**
55      * Convert a dimension value in density independent pixels to an integer pixel offset.
56      *
57      * @param dp the dimension value in density independent pixels
58      * @param context the context to get the {@link DisplayMetrics}
59      * @return the integer pixel offset
60      *
61      * @see TypedValue#complexToDimensionPixelOffset(int, DisplayMetrics)
62      */
63     @Px
dpToPxOffset(@imensionunit = Dimension.DP) float dp, @NonNull Context context)64     public static int dpToPxOffset(@Dimension(unit = Dimension.DP) float dp,
65             @NonNull Context context) {
66         return (int) dpToPx(dp, context);
67     }
68 
69     /**
70      * Convert a dimension value in density independent pixels to an integer pixel size.
71      *
72      * @param dp the dimension value in density independent pixels
73      * @param context the context to get the {@link DisplayMetrics}
74      * @return the integer pixel size
75      *
76      * @see TypedValue#complexToDimensionPixelSize(int, DisplayMetrics)
77      */
78     @Px
dpToPxSize(@imensionunit = Dimension.DP) float dp, @NonNull Context context)79     public static int dpToPxSize(@Dimension(unit = Dimension.DP) float dp,
80             @NonNull Context context) {
81         float value = dpToPx(dp, context);
82         int size = (int) (value >= 0 ? value + 0.5f : value - 0.5f);
83         if (size != 0) {
84             return size;
85         } else if (value == 0) {
86             return 0;
87         } else if (value > 0) {
88             return 1;
89         } else {
90             return -1;
91         }
92     }
93 
94     /**
95      * Set whether a view is shown.
96      *
97      * @param view the view to be set to shown or not
98      * @param shown whether the view should be shown
99      */
setViewShown(@onNull View view, boolean shown)100     public static void setViewShown(@NonNull View view, boolean shown) {
101         if (shown && view.getVisibility() == View.VISIBLE && view.getAlpha() == 1) {
102             // This cancels any on-going animation.
103             view.animate()
104                     .alpha(1)
105                     .setDuration(0);
106             return;
107         } else if (!shown && (view.getVisibility() != View.VISIBLE || view.getAlpha() == 0)) {
108             // This cancels any on-going animation.
109             view.animate()
110                     .alpha(0)
111                     .setDuration(0);
112             view.setVisibility(View.INVISIBLE);
113             return;
114         }
115         if (shown && view.getVisibility() != View.VISIBLE) {
116             view.setAlpha(0);
117             view.setVisibility(View.VISIBLE);
118         }
119         int duration = view.getResources().getInteger(android.R.integer.config_mediumAnimTime);
120         Interpolator interpolator = AnimationUtils.loadInterpolator(view.getContext(), shown
121                 ? android.R.interpolator.fast_out_slow_in
122                 : android.R.interpolator.fast_out_linear_in);
123         view.animate()
124                 .alpha(shown ? 1 : 0)
125                 .setDuration(duration)
126                 .setInterpolator(interpolator)
127                 // Always update the listener or the view will try to reuse the previous one.
128                 .setListener(shown ? null : new AnimatorListenerAdapter() {
129                     private boolean mCanceled = false;
130                     @Override
131                     public void onAnimationCancel(@NonNull Animator animator) {
132                         mCanceled = true;
133                     }
134                     @Override
135                     public void onAnimationEnd(@NonNull Animator animator) {
136                         if (!mCanceled) {
137                             view.setVisibility(View.INVISIBLE);
138                         }
139                     }
140                 });
141     }
142 }
143