11package com .dropbox .core .examples .android ;
22
3+ import android .Manifest ;
34import android .app .ProgressDialog ;
45import android .content .Context ;
6+ import android .content .DialogInterface ;
57import android .content .Intent ;
68import android .content .pm .PackageManager ;
79import android .content .pm .ResolveInfo ;
810import android .net .Uri ;
911import android .os .Bundle ;
12+ import android .support .annotation .NonNull ;
1013import android .support .design .widget .FloatingActionButton ;
14+ import android .support .v4 .app .ActivityCompat ;
15+ import android .support .v4 .content .ContextCompat ;
16+ import android .support .v7 .app .AlertDialog ;
1117import android .support .v7 .widget .LinearLayoutManager ;
1218import android .support .v7 .widget .RecyclerView ;
19+ import android .support .v7 .widget .Toolbar ;
1320import android .util .Log ;
1421import android .view .View ;
1522import android .webkit .MimeTypeMap ;
2734 * and upload/download files
2835 */
2936public class FilesActivity extends DropboxActivity {
37+ private static final String TAG = FilesActivity .class .getName ();
3038
3139 public final static String EXTRA_PATH = "FilesActivity_Path" ;
3240 private static final int PICKFILE_REQUEST_CODE = 1 ;
3341
3442 private String mPath ;
3543 private FilesAdapter mFilesAdapter ;
44+ private DbxFiles .FileMetadata mSelectedFile ;
3645
3746 public static Intent getIntent (Context context , String path ) {
3847 Intent filesIntent = new Intent (context , FilesActivity .class );
@@ -49,11 +58,14 @@ protected void onCreate(Bundle savedInstanceState) {
4958
5059 setContentView (R .layout .activity_files );
5160
61+ Toolbar toolbar = (Toolbar ) findViewById (R .id .app_bar );
62+ setSupportActionBar (toolbar );
63+
5264 FloatingActionButton fab = (FloatingActionButton )findViewById (R .id .fab );
5365 fab .setOnClickListener (new View .OnClickListener () {
5466 @ Override
5567 public void onClick (View v ) {
56- launchFilePicker ( );
68+ performWithPermissions ( FileAction . UPLOAD );
5769 }
5870 });
5971
@@ -65,13 +77,15 @@ public void onFolderClicked(DbxFiles.FolderMetadata folder) {
6577 }
6678
6779 @ Override
68- public void onFileClicked (DbxFiles .FileMetadata file ) {
69- downloadFile ( file ) ;
70-
80+ public void onFileClicked (final DbxFiles .FileMetadata file ) {
81+ mSelectedFile = file ;
82+ performWithPermissions ( FileAction . DOWNLOAD );
7183 }
7284 });
7385 recyclerView .setLayoutManager (new LinearLayoutManager (this ));
7486 recyclerView .setAdapter (mFilesAdapter );
87+
88+ mSelectedFile = null ;
7589 }
7690
7791 private void launchFilePicker () {
@@ -83,7 +97,7 @@ private void launchFilePicker() {
8397 }
8498
8599 @ Override
86- protected void onActivityResult (int requestCode , int resultCode , Intent data ) {
100+ protected void onActivityResult (int requestCode , int resultCode , final Intent data ) {
87101 super .onActivityResult (requestCode , resultCode , data );
88102
89103 if (requestCode == PICKFILE_REQUEST_CODE ) {
@@ -95,6 +109,59 @@ protected void onActivityResult(int requestCode, int resultCode, Intent data) {
95109 }
96110 }
97111
112+ @ Override
113+ public void onRequestPermissionsResult (int actionCode , @ NonNull String [] permissions , @ NonNull int [] grantResults ) {
114+ FileAction action = FileAction .fromCode (actionCode );
115+
116+ boolean granted = true ;
117+ for (int i = 0 ; i < grantResults .length ; ++i ) {
118+ if (grantResults [i ] == PackageManager .PERMISSION_DENIED ) {
119+ Log .w (TAG , "User denied " + permissions [i ] +
120+ " permission to perform file action: " + action );
121+ granted = false ;
122+ break ;
123+ }
124+ }
125+
126+ if (granted ) {
127+ performAction (action );
128+ } else {
129+ switch (action ) {
130+ case UPLOAD :
131+ Toast .makeText (this ,
132+ "Can't upload file: read access denied. " +
133+ "Please grant storage permissions to use this functionality." ,
134+ Toast .LENGTH_LONG )
135+ .show ();
136+ break ;
137+ case DOWNLOAD :
138+ Toast .makeText (this ,
139+ "Can't download file: write access denied. " +
140+ "Please grant storage permissions to use this functionality." ,
141+ Toast .LENGTH_LONG )
142+ .show ();
143+ break ;
144+ }
145+ }
146+ }
147+
148+ private void performAction (FileAction action ) {
149+ switch (action ) {
150+ case UPLOAD :
151+ launchFilePicker ();
152+ break ;
153+ case DOWNLOAD :
154+ if (mSelectedFile != null ) {
155+ downloadFile (mSelectedFile );
156+ } else {
157+ Log .e (TAG , "No file selected to download." );
158+ }
159+ break ;
160+ default :
161+ Log .e (TAG , "Can't perform unhandled file action: " + action );
162+ }
163+ }
164+
98165 @ Override
99166 protected void loadData () {
100167
@@ -116,7 +183,7 @@ public void onDataLoaded(DbxFiles.ListFolderResult result) {
116183 public void onError (Exception e ) {
117184 dialog .dismiss ();
118185
119- Log .e (getClass (). getName () , "Failed to list folder." , e );
186+ Log .e (TAG , "Failed to list folder." , e );
120187 Toast .makeText (FilesActivity .this ,
121188 "An error has occurred" ,
122189 Toast .LENGTH_SHORT )
@@ -126,7 +193,6 @@ public void onError(Exception e) {
126193 }
127194
128195 private void downloadFile (DbxFiles .FileMetadata file ) {
129-
130196 final ProgressDialog dialog = new ProgressDialog (this );
131197 dialog .setProgressStyle (ProgressDialog .STYLE_SPINNER );
132198 dialog .setCancelable (false );
@@ -147,7 +213,7 @@ public void onDownloadComplete(File result) {
147213 public void onError (Exception e ) {
148214 dialog .dismiss ();
149215
150- Log .e (getClass (). getName () , "Failed to download file." , e );
216+ Log .e (TAG , "Failed to download file." , e );
151217 Toast .makeText (FilesActivity .this ,
152218 "An error has occurred" ,
153219 Toast .LENGTH_SHORT )
@@ -198,12 +264,90 @@ public void onUploadComplete(DbxFiles.FileMetadata result) {
198264 public void onError (Exception e ) {
199265 dialog .dismiss ();
200266
201- Log .e (getClass (). getName () , "Failed to upload file." , e );
267+ Log .e (TAG , "Failed to upload file." , e );
202268 Toast .makeText (FilesActivity .this ,
203269 "An error has occurred" ,
204270 Toast .LENGTH_SHORT )
205271 .show ();
206272 }
207273 }).execute (fileUri , mPath );
208274 }
275+
276+ private void performWithPermissions (final FileAction action ) {
277+ if (hasPermissionsForAction (action )) {
278+ performAction (action );
279+ return ;
280+ }
281+
282+ if (shouldDisplayRationaleForAction (action )) {
283+ new AlertDialog .Builder (this )
284+ .setMessage ("This app requires storage access to download and upload files." )
285+ .setPositiveButton ("OK" , new DialogInterface .OnClickListener () {
286+ @ Override
287+ public void onClick (DialogInterface dialog , int which ) {
288+ requestPermissionsForAction (action );
289+ }
290+ })
291+ .setNegativeButton ("Cancel" , null )
292+ .create ()
293+ .show ();
294+ } else {
295+ requestPermissionsForAction (action );
296+ }
297+ }
298+
299+ private boolean hasPermissionsForAction (FileAction action ) {
300+ for (String permission : action .getPermissions ()) {
301+ int result = ContextCompat .checkSelfPermission (this , permission );
302+ if (result == PackageManager .PERMISSION_DENIED ) {
303+ return false ;
304+ }
305+ }
306+ return true ;
307+ }
308+
309+ private boolean shouldDisplayRationaleForAction (FileAction action ) {
310+ for (String permission : action .getPermissions ()) {
311+ if (!ActivityCompat .shouldShowRequestPermissionRationale (this , permission )) {
312+ return true ;
313+ }
314+ }
315+ return false ;
316+ }
317+
318+ private void requestPermissionsForAction (FileAction action ) {
319+ ActivityCompat .requestPermissions (
320+ this ,
321+ action .getPermissions (),
322+ action .getCode ()
323+ );
324+ }
325+
326+ private enum FileAction {
327+ DOWNLOAD (Manifest .permission .WRITE_EXTERNAL_STORAGE ),
328+ UPLOAD (Manifest .permission .READ_EXTERNAL_STORAGE );
329+
330+ private static final FileAction [] values = values ();
331+
332+ private final String [] permissions ;
333+
334+ FileAction (String ... permissions ) {
335+ this .permissions = permissions ;
336+ }
337+
338+ public int getCode () {
339+ return ordinal ();
340+ }
341+
342+ public String [] getPermissions () {
343+ return permissions ;
344+ }
345+
346+ public static FileAction fromCode (int code ) {
347+ if (code < 0 || code >= values .length ) {
348+ throw new IllegalArgumentException ("Invalid FileAction code: " + code );
349+ }
350+ return values [code ];
351+ }
352+ }
209353}
0 commit comments