blob: 7394c12558f8f97d01630c65428e9c3770b3e5af [file] [log] [blame]
Aga Wronska3b327ef2016-01-20 16:32:33 -08001/*
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
17package com.android.documentsui.dirlist;
18
19import static com.android.documentsui.Shared.TAG;
20import static com.android.internal.util.Preconditions.checkArgument;
21
22import android.app.AlertDialog;
23import android.app.Dialog;
24import android.app.DialogFragment;
25import android.app.FragmentManager;
26import android.content.ContentProviderClient;
27import android.content.ContentResolver;
28import android.content.Context;
29import android.content.DialogInterface;
30import android.content.DialogInterface.OnClickListener;
31import android.net.Uri;
32import android.os.AsyncTask;
33import android.os.Bundle;
34import android.provider.DocumentsContract;
35import android.support.annotation.Nullable;
36import android.support.design.widget.Snackbar;
37import android.util.Log;
38import android.view.KeyEvent;
Aga Wronska40416802016-02-08 09:14:25 -080039import android.view.inputmethod.EditorInfo;
Aga Wronska3b327ef2016-01-20 16:32:33 -080040import android.view.LayoutInflater;
41import android.view.View;
42import android.widget.EditText;
43import android.widget.TextView;
44import android.widget.TextView.OnEditorActionListener;
45
46import com.android.documentsui.BaseActivity;
47import com.android.documentsui.DocumentsApplication;
Aga Wronska3b327ef2016-01-20 16:32:33 -080048import com.android.documentsui.R;
49import com.android.documentsui.Snackbars;
Ben Kwae3aee182016-02-02 12:11:10 -080050import com.android.documentsui.model.DocumentInfo;
Aga Wronska40416802016-02-08 09:14:25 -080051
Aga Wronska3b327ef2016-01-20 16:32:33 -080052/**
53 * Dialog to rename file or directory.
54 */
Ben Kwae3aee182016-02-02 12:11:10 -080055public class RenameDocumentFragment extends DialogFragment {
Aga Wronska3b327ef2016-01-20 16:32:33 -080056 private static final String TAG_RENAME_DOCUMENT = "rename_document";
57 private DocumentInfo mDocument;
58
59 public static void show(FragmentManager fm, DocumentInfo document) {
60 final RenameDocumentFragment dialog = new RenameDocumentFragment();
61 dialog.mDocument = document;
62 dialog.show(fm, TAG_RENAME_DOCUMENT);
63 }
64
65 @Override
66 public Dialog onCreateDialog(Bundle savedInstanceState) {
67 Context context = getActivity();
68 AlertDialog.Builder builder = new AlertDialog.Builder(context);
69 LayoutInflater dialogInflater = LayoutInflater.from(builder.getContext());
70 View view = dialogInflater.inflate(R.layout.dialog_file_name, null, false);
71
72 final EditText editText = (EditText) view.findViewById(android.R.id.text1);
Aga Wronska40416802016-02-08 09:14:25 -080073 fillWithFileName(editText, mDocument.displayName);
Aga Wronska3b327ef2016-01-20 16:32:33 -080074 builder.setTitle(R.string.menu_rename);
75 builder.setView(view);
76
77 builder.setPositiveButton(
78 android.R.string.ok,
79 new OnClickListener() {
80 @Override
81 public void onClick(DialogInterface dialog, int which) {
82 renameDocuments(editText.getText().toString());
83 }
84 });
85
86 builder.setNegativeButton(android.R.string.cancel, null);
87
88 final AlertDialog dialog = builder.create();
89
90 editText.setOnEditorActionListener(
91 new OnEditorActionListener() {
92 @Override
93 public boolean onEditorAction(
94 TextView view, int actionId, @Nullable KeyEvent event) {
Aga Wronska40416802016-02-08 09:14:25 -080095 if ((actionId == EditorInfo.IME_ACTION_DONE) || (event != null
Aga Wronska3b327ef2016-01-20 16:32:33 -080096 && event.getKeyCode() == KeyEvent.KEYCODE_ENTER
Aga Wronska40416802016-02-08 09:14:25 -080097 && event.hasNoModifiers())) {
Aga Wronska3b327ef2016-01-20 16:32:33 -080098 renameDocuments(editText.getText().toString());
99 dialog.dismiss();
100 return true;
101 }
102 return false;
103 }
104 });
105
106 return dialog;
107 }
108
Aga Wronska40416802016-02-08 09:14:25 -0800109 /**
110 * Validates if string is a proper document name.
111 * Checks if string is not empty. More rules might be added later.
112 * @param docName string representing document name
113 * @returns true if string is a valid name.
114 **/
115 private boolean isValidDocumentName(String docName) {
116 return !docName.isEmpty();
117 }
118
119 /**
120 * Fills text field with the file name and selects the name without extension.
121 *
122 * @param editText text field to be filled
123 * @param name full name of the file
124 */
125 private void fillWithFileName(EditText editText, String name) {
126 editText.setText(name);
127 int separatorIndex = name.indexOf(".");
128 editText.setSelection(0, separatorIndex == -1 ? name.length() : separatorIndex);
129 }
130
Aga Wronska3b327ef2016-01-20 16:32:33 -0800131 private void renameDocuments(String newDisplayName) {
132 BaseActivity activity = (BaseActivity) getActivity();
133
Aga Wronska40416802016-02-08 09:14:25 -0800134 if (isValidDocumentName(newDisplayName)) {
135 new RenameDocumentsTask(activity, newDisplayName).execute(mDocument);
136 } else {
137 Log.w(TAG, "Failed to rename file - invalid name:" + newDisplayName);
138 Snackbars.makeSnackbar(getActivity(), R.string.rename_error,
139 Snackbar.LENGTH_SHORT).show();
140 }
141
Aga Wronska3b327ef2016-01-20 16:32:33 -0800142 }
143
144 private class RenameDocumentsTask extends AsyncTask<DocumentInfo, Void, DocumentInfo> {
145 private final BaseActivity mActivity;
146 private final String mNewDisplayName;
147
148 public RenameDocumentsTask(BaseActivity activity, String newDisplayName) {
149 mActivity = activity;
150 mNewDisplayName = newDisplayName;
151 }
152
153 @Override
154 protected void onPreExecute() {
155 mActivity.setPending(true);
156 }
157
158 @Override
159 protected DocumentInfo doInBackground(DocumentInfo... document) {
160 checkArgument(document.length == 1);
161 final ContentResolver resolver = mActivity.getContentResolver();
162 ContentProviderClient client = null;
163
164 try {
165 client = DocumentsApplication.acquireUnstableProviderOrThrow(
166 resolver, document[0].derivedUri.getAuthority());
167 Uri newUri = DocumentsContract.renameDocument(
168 client, document[0].derivedUri, mNewDisplayName);
169 return DocumentInfo.fromUri(resolver, newUri);
170 } catch (Exception e) {
171 Log.w(TAG, "Failed to rename file", e);
172 return null;
173 } finally {
174 ContentProviderClient.releaseQuietly(client);
175 }
176 }
177
178 @Override
179 protected void onPostExecute(DocumentInfo result) {
180 if (result == null) {
181 Snackbars.makeSnackbar(mActivity, R.string.rename_error, Snackbar.LENGTH_SHORT)
182 .show();
183 }
184
185 mActivity.setPending(false);
186 }
187 }
188}