1 /* 2 * Copyright (C) 2014 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.picker; 18 19 import static com.android.documentsui.services.FileOperationService.OPERATION_COMPRESS; 20 import static com.android.documentsui.services.FileOperationService.OPERATION_COPY; 21 import static com.android.documentsui.services.FileOperationService.OPERATION_DELETE; 22 import static com.android.documentsui.services.FileOperationService.OPERATION_EXTRACT; 23 import static com.android.documentsui.services.FileOperationService.OPERATION_MOVE; 24 import static com.android.documentsui.services.FileOperationService.OPERATION_UNKNOWN; 25 26 import android.os.Bundle; 27 import android.view.LayoutInflater; 28 import android.view.View; 29 import android.view.ViewGroup; 30 import android.widget.Button; 31 32 import androidx.fragment.app.Fragment; 33 import androidx.fragment.app.FragmentActivity; 34 import androidx.fragment.app.FragmentManager; 35 import androidx.fragment.app.FragmentTransaction; 36 37 import com.android.documentsui.BaseActivity; 38 import com.android.documentsui.Injector; 39 import com.android.documentsui.R; 40 import com.android.documentsui.base.DocumentInfo; 41 import com.android.documentsui.base.State; 42 import com.android.documentsui.services.FileOperationService.OpType; 43 import com.android.documentsui.ui.Snackbars; 44 45 import com.google.android.material.snackbar.Snackbar; 46 47 /** 48 * Display pick confirmation bar, usually for selecting a directory. 49 */ 50 public class PickFragment extends Fragment { 51 public static final String TAG = "PickFragment"; 52 53 private static final String ACTION_KEY = "action"; 54 private static final String COPY_OPERATION_SUBTYPE_KEY = "copyOperationSubType"; 55 private static final String PICK_TARGET_KEY = "pickTarget"; 56 private static final String RESTRICT_SCOPE_STORAGE_KEY = "restrictScopeStorage"; 57 58 private final View.OnClickListener mPickListener = new View.OnClickListener() { 59 @Override 60 public void onClick(View v) { 61 if (mPick.isEnabled()) { 62 mInjector.actions.pickDocument(getChildFragmentManager(), mPickTarget); 63 } else { 64 String msg = getResources().getString(R.string.directory_blocked_header_subtitle); 65 Snackbars.makeSnackbar(getActivity(), msg, Snackbar.LENGTH_LONG).show(); 66 } 67 } 68 }; 69 70 private final View.OnClickListener mCancelListener = new View.OnClickListener() { 71 @Override 72 public void onClick(View v) { 73 mInjector.pickResult.increaseActionCount(); 74 final BaseActivity activity = BaseActivity.get(PickFragment.this); 75 activity.setResult(FragmentActivity.RESULT_CANCELED); 76 activity.finish(); 77 } 78 }; 79 80 private Injector<ActionHandler<PickActivity>> mInjector; 81 private int mAction; 82 private boolean mRestrictScopeStorage; 83 // Only legal values are OPERATION_COPY, OPERATION_COMPRESS, OPERATION_EXTRACT, 84 // OPERATION_MOVE, and unset (OPERATION_UNKNOWN). 85 private @OpType int mCopyOperationSubType = OPERATION_UNKNOWN; 86 private DocumentInfo mPickTarget; 87 private View mContainer; 88 private View mPickOverlay; 89 private Button mPick; 90 private Button mCancel; 91 show(FragmentManager fm)92 public static void show(FragmentManager fm) { 93 // Fragment can be restored by FragmentManager automatically. 94 if (get(fm) != null) { 95 return; 96 } 97 98 final PickFragment fragment = new PickFragment(); 99 final FragmentTransaction ft = fm.beginTransaction(); 100 ft.replace(R.id.container_save, fragment, TAG); 101 ft.commitNowAllowingStateLoss(); 102 } 103 get(FragmentManager fm)104 public static PickFragment get(FragmentManager fm) { 105 return (PickFragment) fm.findFragmentByTag(TAG); 106 } 107 108 @Override onCreateView( LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)109 public View onCreateView( 110 LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { 111 mContainer = inflater.inflate(R.layout.fragment_pick, container, false); 112 113 mPick = (Button) mContainer.findViewById(android.R.id.button1); 114 mPickOverlay = mContainer.findViewById((R.id.pick_button_overlay)); 115 mPickOverlay.setOnClickListener(mPickListener); 116 mPick.setOnClickListener(mPickListener); 117 118 mCancel = (Button) mContainer.findViewById(android.R.id.button2); 119 mCancel.setOnClickListener(mCancelListener); 120 121 updateView(); 122 return mContainer; 123 } 124 125 @Override onActivityCreated(Bundle savedInstanceState)126 public void onActivityCreated(Bundle savedInstanceState) { 127 super.onActivityCreated(savedInstanceState); 128 if (savedInstanceState != null) { 129 // Restore status 130 mAction = savedInstanceState.getInt(ACTION_KEY); 131 mCopyOperationSubType = 132 savedInstanceState.getInt(COPY_OPERATION_SUBTYPE_KEY); 133 mPickTarget = savedInstanceState.getParcelable(PICK_TARGET_KEY); 134 mRestrictScopeStorage = savedInstanceState.getBoolean(RESTRICT_SCOPE_STORAGE_KEY); 135 updateView(); 136 } 137 138 mInjector = ((PickActivity) getActivity()).getInjector(); 139 } 140 141 @Override onSaveInstanceState(final Bundle outState)142 public void onSaveInstanceState(final Bundle outState) { 143 super.onSaveInstanceState(outState); 144 outState.putInt(ACTION_KEY, mAction); 145 outState.putInt(COPY_OPERATION_SUBTYPE_KEY, mCopyOperationSubType); 146 outState.putParcelable(PICK_TARGET_KEY, mPickTarget); 147 outState.putBoolean(RESTRICT_SCOPE_STORAGE_KEY, mRestrictScopeStorage); 148 } 149 150 /** 151 * @param action Which action defined in State is the picker shown for. 152 */ setPickTarget(int action, @OpType int copyOperationSubType, boolean restrictScopeStorage, DocumentInfo pickTarget)153 public void setPickTarget(int action, @OpType int copyOperationSubType, 154 boolean restrictScopeStorage, DocumentInfo pickTarget) { 155 assert(copyOperationSubType != OPERATION_DELETE); 156 157 mAction = action; 158 mCopyOperationSubType = copyOperationSubType; 159 mRestrictScopeStorage = restrictScopeStorage; 160 mPickTarget = pickTarget; 161 if (mContainer != null) { 162 updateView(); 163 } 164 } 165 166 /** 167 * Applies the state of fragment to the view components. 168 */ updateView()169 private void updateView() { 170 if (mPickTarget != null && ( 171 mAction == State.ACTION_OPEN_TREE || 172 mPickTarget.isCreateSupported())) { 173 mContainer.setVisibility(View.VISIBLE); 174 } else { 175 mContainer.setVisibility(View.GONE); 176 return; 177 } 178 179 switch (mAction) { 180 case State.ACTION_OPEN_TREE: 181 mPick.setText(getString(R.string.open_tree_button)); 182 mPick.setWidth(Integer.MAX_VALUE); 183 mCancel.setVisibility(View.GONE); 184 mPick.setEnabled(!(mPickTarget.isBlockedFromTree() && mRestrictScopeStorage)); 185 mPickOverlay.setVisibility( 186 mPickTarget.isBlockedFromTree() && mRestrictScopeStorage 187 ? View.VISIBLE 188 : View.GONE); 189 break; 190 case State.ACTION_PICK_COPY_DESTINATION: 191 int titleId; 192 switch (mCopyOperationSubType) { 193 case OPERATION_COPY: 194 titleId = R.string.button_copy; 195 break; 196 case OPERATION_COMPRESS: 197 titleId = R.string.button_compress; 198 break; 199 case OPERATION_EXTRACT: 200 titleId = R.string.button_extract; 201 break; 202 case OPERATION_MOVE: 203 titleId = R.string.button_move; 204 break; 205 default: 206 throw new UnsupportedOperationException(); 207 } 208 mPick.setText(titleId); 209 mCancel.setVisibility(View.VISIBLE); 210 break; 211 default: 212 mContainer.setVisibility(View.GONE); 213 return; 214 } 215 } 216 } 217