1 /* 2 * Copyright (C) 2013 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.documentsui.dirlist; 18 19 import static com.android.documentsui.util.FlagUtils.isUseMaterial3FlagEnabled; 20 21 import android.content.Context; 22 import android.os.Bundle; 23 import android.util.AttributeSet; 24 import android.widget.LinearLayout; 25 26 import androidx.annotation.IntDef; 27 import androidx.fragment.app.FragmentTransaction; 28 29 import com.android.documentsui.R; 30 import com.android.documentsui.base.Shared; 31 32 import java.lang.annotation.Retention; 33 import java.lang.annotation.RetentionPolicy; 34 import java.util.ArrayList; 35 36 /** 37 * This class exists solely to support animated transition of our directory fragment. 38 * The structure of this class is tightly coupled with the static animations defined in 39 * res/animator, specifically the "position" property referenced by 40 * res/animator/dir_{enter,leave}.xml. 41 */ 42 public class AnimationView extends LinearLayout { 43 44 @IntDef(flag = true, value = { 45 ANIM_NONE, 46 ANIM_SIDE, 47 ANIM_LEAVE, 48 ANIM_ENTER 49 }) 50 @Retention(RetentionPolicy.SOURCE) 51 public @interface AnimationType {} 52 public static final int ANIM_NONE = 1; 53 public static final int ANIM_SIDE = 2; 54 public static final int ANIM_LEAVE = 3; 55 public static final int ANIM_ENTER = 4; 56 57 private final ArrayList<OnSizeChangedListener> mOnSizeChangedListeners = new ArrayList<>(); 58 59 private float mPosition = 0f; 60 61 // The distance the animation will cover...currently matches the height of the 62 // content area. 63 private int mSpan; 64 AnimationView(Context context)65 public AnimationView(Context context) { 66 super(context); 67 } 68 AnimationView(Context context, AttributeSet attrs)69 public AnimationView(Context context, AttributeSet attrs) { 70 super(context, attrs); 71 } 72 73 /** 74 * A listener of the onSizeChanged method. 75 */ 76 public interface OnSizeChangedListener { 77 /** 78 * Called on the View's onSizeChanged. 79 */ onSizeChanged()80 void onSizeChanged(); 81 } 82 83 /** 84 * Adds a listener of the onSizeChanged method. 85 */ addOnSizeChangedListener(OnSizeChangedListener listener)86 public void addOnSizeChangedListener(OnSizeChangedListener listener) { 87 if (isUseMaterial3FlagEnabled()) { 88 mOnSizeChangedListeners.add(listener); 89 } 90 } 91 92 /** 93 * Removes a listener of the onSizeChanged method. 94 */ removeOnSizeChangedListener(OnSizeChangedListener listener)95 public void removeOnSizeChangedListener(OnSizeChangedListener listener) { 96 if (isUseMaterial3FlagEnabled()) { 97 mOnSizeChangedListeners.remove(listener); 98 } 99 } 100 101 102 @Override onSizeChanged(int w, int h, int oldw, int oldh)103 protected void onSizeChanged(int w, int h, int oldw, int oldh) { 104 super.onSizeChanged(w, h, oldw, oldh); 105 mSpan = h; 106 setPosition(mPosition); 107 if (isUseMaterial3FlagEnabled()) { 108 for (int i = mOnSizeChangedListeners.size() - 1; i >= 0; --i) { 109 mOnSizeChangedListeners.get(i).onSizeChanged(); 110 } 111 } 112 } 113 getPosition()114 public float getPosition() { 115 return mPosition; 116 } 117 setPosition(float position)118 public void setPosition(float position) { 119 mPosition = position; 120 // Warning! If we ever decide to switch this to setX (slide left/right) 121 // please remember to add RLT variations of the animations under res/animator-ldrtl. 122 setY((mSpan > 0) ? (mPosition * mSpan) : 0); 123 124 if (mPosition != 0) { 125 setTranslationZ(getResources().getDimensionPixelSize(R.dimen.dir_elevation)); 126 } else { 127 setTranslationZ(0); 128 } 129 } 130 131 /** 132 * Configures custom animations on the transaction according to the specified 133 * @AnimationType. 134 */ setupAnimations( FragmentTransaction ft, @AnimationType int anim, Bundle args)135 static void setupAnimations( 136 FragmentTransaction ft, @AnimationType int anim, Bundle args) { 137 switch (anim) { 138 case AnimationView.ANIM_SIDE: 139 args.putBoolean(Shared.EXTRA_IGNORE_STATE, true); 140 break; 141 case AnimationView.ANIM_ENTER: 142 // TODO: Document which behavior is being tailored 143 // by passing this bit. Remove if possible. 144 args.putBoolean(Shared.EXTRA_IGNORE_STATE, true); 145 ft.setCustomAnimations(R.animator.dir_enter, R.animator.fade_out); 146 break; 147 case AnimationView.ANIM_LEAVE: 148 ft.setCustomAnimations(R.animator.fade_in, R.animator.dir_leave); 149 break; 150 } 151 } 152 } 153