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 
17 package android.server.wm.dndsourceapp;
18 
19 import static android.app.PendingIntent.FLAG_IMMUTABLE;
20 
21 import android.app.Activity;
22 import android.app.PendingIntent;
23 import android.content.ClipData;
24 import android.content.ClipDescription;
25 import android.content.Intent;
26 import android.net.Uri;
27 import android.os.Bundle;
28 import android.os.Handler;
29 import android.os.FileUriExposedException;
30 import android.os.PersistableBundle;
31 import android.server.wm.TestLogClient;
32 import android.view.MotionEvent;
33 import android.view.View;
34 import android.widget.TextView;
35 
36 import java.io.File;
37 
38 public class DragSource extends Activity {
39     private static final String RESULT_KEY_START_DRAG = "START_DRAG";
40     private static final String RESULT_KEY_DETAILS = "DETAILS";
41     private static final String RESULT_OK = "OK";
42     private static final String RESULT_EXCEPTION = "Exception";
43 
44     private static final String URI_PREFIX =
45             "content://" + DragSourceContentProvider.AUTHORITY + "/data";
46 
47     private static final String MAGIC_VALUE = "42";
48     private static final long TIMEOUT_CANCEL = 150;
49 
50     private TextView mTextView;
51     private TestLogClient mLogClient;
52 
53     @Override
onCreate(Bundle savedInstanceState)54     public void onCreate(Bundle savedInstanceState) {
55         super.onCreate(savedInstanceState);
56 
57         mLogClient = new TestLogClient(this, getIntent().getStringExtra("logtag"));
58 
59         View view = getLayoutInflater().inflate(R.layout.source_activity, null);
60         setContentView(view);
61 
62         final Uri plainUri = Uri.parse(URI_PREFIX + "/" + MAGIC_VALUE);
63 
64         setUpDragSource("disallow_global", plainUri, 0);
65         setUpDragSource("global_same_app", plainUri, View.DRAG_FLAG_GLOBAL_SAME_APPLICATION);
66         setUpDragSource("cancel_soon", plainUri, View.DRAG_FLAG_GLOBAL);
67 
68         setUpDragSource("grant_none", plainUri, View.DRAG_FLAG_GLOBAL);
69         setUpDragSource("grant_read", plainUri,
70                 View.DRAG_FLAG_GLOBAL | View.DRAG_FLAG_GLOBAL_URI_READ);
71         setUpDragSource("grant_write", plainUri,
72                 View.DRAG_FLAG_GLOBAL | View.DRAG_FLAG_GLOBAL_URI_WRITE);
73         setUpDragSource("grant_read_persistable", plainUri,
74                 View.DRAG_FLAG_GLOBAL | View.DRAG_FLAG_GLOBAL_URI_READ |
75                         View.DRAG_FLAG_GLOBAL_PERSISTABLE_URI_PERMISSION);
76 
77         final Uri prefixUri = Uri.parse(URI_PREFIX);
78 
79         setUpDragSource("grant_read_prefix", prefixUri,
80                 View.DRAG_FLAG_GLOBAL | View.DRAG_FLAG_GLOBAL_URI_READ |
81                         View.DRAG_FLAG_GLOBAL_PREFIX_URI_PERMISSION);
82         setUpDragSource("grant_read_noprefix", prefixUri,
83                 View.DRAG_FLAG_GLOBAL | View.DRAG_FLAG_GLOBAL_URI_READ);
84 
85         final Uri fileUri = Uri.fromFile(new File("/sdcard/sample.jpg"));
86 
87         setUpDragSource("file_local", fileUri, 0);
88         setUpDragSource("file_global", fileUri, View.DRAG_FLAG_GLOBAL);
89 
90         final ClipData.Item intentSenderItem = new ClipData.Item.Builder()
91                 .setIntentSender(PendingIntent.getActivity(this, 0, new Intent(),
92                         FLAG_IMMUTABLE).getIntentSender())
93                 .build();
94         final ClipDescription clipDescription = new ClipDescription("", new String[] {
95                 ClipDescription.MIMETYPE_TEXT_INTENT });
96         setUpDragSource("intent_sender", clipDescription,
97                 intentSenderItem, View.DRAG_FLAG_GLOBAL_SAME_APPLICATION);
98     }
99 
setUpDragSource(String mode, final Uri uri, final int flags)100     private void setUpDragSource(String mode, final Uri uri, final int flags) {
101         final ClipDescription clipDescription = new ClipDescription("", new String[] {
102                 ClipDescription.MIMETYPE_TEXT_URILIST });
103         PersistableBundle extras = new PersistableBundle(1);
104         extras.putString("extraKey", "extraValue");
105         clipDescription.setExtras(extras);
106         setUpDragSource(mode, clipDescription, new ClipData.Item(uri), flags);
107     }
108 
setUpDragSource(String mode, final ClipDescription clipDescription, final ClipData.Item item, final int flags)109     private void setUpDragSource(String mode, final ClipDescription clipDescription,
110             final ClipData.Item item, final int flags) {
111         if (!mode.equals(getIntent().getStringExtra("mode"))) {
112             return;
113         }
114         mTextView = (TextView) findViewById(R.id.drag_source);
115         mTextView.setText(mode);
116         mTextView.setOnTouchListener(new View.OnTouchListener() {
117             @Override
118             public boolean onTouch(View v, MotionEvent event) {
119                 if (event.getAction() != MotionEvent.ACTION_DOWN) {
120                     return false;
121                 }
122 
123                 try {
124                     final ClipData clipData = new ClipData(clipDescription, item);
125                     v.startDragAndDrop(
126                             clipData,
127                             new View.DragShadowBuilder(v),
128                             null,
129                             flags);
130                     logResult(RESULT_KEY_START_DRAG, RESULT_OK);
131                 } catch (FileUriExposedException e) {
132                     logResult(RESULT_KEY_DETAILS, e.getMessage());
133                     logResult(RESULT_KEY_START_DRAG, RESULT_EXCEPTION);
134                 }
135                 if (mode.equals("cancel_soon")) {
136                     new Handler().postDelayed(new Runnable() {
137                         @Override
138                         public void run() {
139                             v.cancelDragAndDrop();
140                         }
141                     }, TIMEOUT_CANCEL);
142                 }
143                 return true;
144             }
145         });
146     }
147 
logResult(String key, String value)148     private void logResult(String key, String value) {
149         mLogClient.record(key, value);
150         mTextView.setText(mTextView.getText() + "\n" + key + "=" + value);
151     }
152 }
153