1 /* 2 * Copyright (C) 2016 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 package com.android.documentsui.ui; 17 18 import android.app.Activity; 19 import android.app.AlertDialog; 20 import android.app.FragmentManager; 21 import android.content.DialogInterface; 22 import android.support.design.widget.Snackbar; 23 import android.widget.Button; 24 import android.widget.TextView; 25 26 import com.android.documentsui.R; 27 import com.android.documentsui.base.ConfirmationCallback; 28 import com.android.documentsui.base.DocumentInfo; 29 import com.android.documentsui.picker.OverwriteConfirmFragment; 30 import com.android.documentsui.services.FileOperationService; 31 import com.android.documentsui.services.FileOperationService.OpType; 32 import com.android.documentsui.services.FileOperations; 33 import com.android.documentsui.services.FileOperations.Callback.Status; 34 35 import java.util.List; 36 37 public interface DialogController { 38 39 // Dialogs used in FilesActivity 40 void confirmDelete(List<DocumentInfo> docs, ConfirmationCallback callback); 41 void showFileOperationStatus(int status, int opType, int docCount); 42 void showNoApplicationFound(); 43 void showViewInArchivesUnsupported(); 44 void showDocumentsClipped(int size); 45 46 // Dialogs used in PickActivity 47 void confirmOverwrite(FragmentManager fm, DocumentInfo overwriteTarget); 48 49 // Should be private, but Java doesn't like me treating an interface like a mini-package. 50 public static final class RuntimeDialogController implements DialogController { 51 52 private final Activity mActivity; 53 private final MessageBuilder mMessages; 54 55 public RuntimeDialogController(Activity activity, MessageBuilder messages) { 56 mActivity = activity; 57 mMessages = messages; 58 } 59 60 @Override 61 public void confirmDelete(List<DocumentInfo> docs, ConfirmationCallback callback) { 62 assert(!docs.isEmpty()); 63 64 TextView message = 65 (TextView) mActivity.getLayoutInflater().inflate( 66 R.layout.dialog_delete_confirmation, null); 67 message.setText(mMessages.generateDeleteMessage(docs)); 68 69 // For now, we implement this dialog NOT 70 // as a fragment (which can survive rotation and have its own state), 71 // but as a simple runtime dialog. So rotating a device with an 72 // active delete dialog...results in that dialog disappearing. 73 // We can do better, but don't have cycles for it now. 74 final AlertDialog alertDialog = new AlertDialog.Builder(mActivity) 75 .setView(message) 76 .setPositiveButton( 77 android.R.string.ok, 78 new DialogInterface.OnClickListener() { 79 @Override 80 public void onClick(DialogInterface dialog, int id) { 81 callback.accept(ConfirmationCallback.CONFIRM); 82 } 83 }) 84 .setNegativeButton(android.R.string.cancel, null) 85 .create(); 86 87 alertDialog.setOnShowListener( 88 (DialogInterface) -> { 89 Button positive = alertDialog.getButton(AlertDialog.BUTTON_POSITIVE); 90 positive.setFocusable(true); 91 positive.requestFocus(); 92 }); 93 alertDialog.show(); 94 } 95 96 @Override 97 public void showFileOperationStatus( 98 @Status int status, @OpType int opType, int docCount) { 99 if (status == FileOperations.Callback.STATUS_REJECTED) { 100 Snackbars.showOperationRejected(mActivity); 101 return; 102 } 103 if (status == FileOperations.Callback.STATUS_FAILED) { 104 Snackbars.showOperationFailed(mActivity); 105 return; 106 } 107 108 if (docCount == 0) { 109 // Nothing has been pasted, so there is no need to show a snackbar. 110 return; 111 } 112 113 switch (opType) { 114 case FileOperationService.OPERATION_MOVE: 115 Snackbars.showMove(mActivity, docCount); 116 break; 117 case FileOperationService.OPERATION_COPY: 118 Snackbars.showCopy(mActivity, docCount); 119 break; 120 case FileOperationService.OPERATION_COMPRESS: 121 Snackbars.showCompress(mActivity, docCount); 122 break; 123 case FileOperationService.OPERATION_EXTRACT: 124 Snackbars.showExtract(mActivity, docCount); 125 break; 126 case FileOperationService.OPERATION_DELETE: 127 Snackbars.showDelete(mActivity, docCount); 128 break; 129 default: 130 throw new UnsupportedOperationException("Unsupported Operation: " + opType); 131 } 132 } 133 134 @Override 135 public void showNoApplicationFound() { 136 Snackbars.makeSnackbar( 137 mActivity, R.string.toast_no_application, Snackbar.LENGTH_SHORT).show(); 138 } 139 140 @Override 141 public void showViewInArchivesUnsupported() { 142 Snackbars.makeSnackbar(mActivity, R.string.toast_view_in_archives_unsupported, 143 Snackbar.LENGTH_SHORT).show(); 144 } 145 146 @Override 147 public void showDocumentsClipped(int size) { 148 Snackbars.showDocumentsClipped(mActivity, size); 149 } 150 151 @Override 152 public void confirmOverwrite(FragmentManager fm, DocumentInfo overwriteTarget) { 153 OverwriteConfirmFragment.show(fm, overwriteTarget); 154 } 155 } 156 157 static DialogController create(Activity activity, MessageBuilder messages) { 158 return new RuntimeDialogController(activity, messages); 159 } 160 } 161