1 /*
2  * Copyright (C) 2013 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.accessorydisplay.source;
18 
19 import com.android.accessorydisplay.common.Logger;
20 import com.android.accessorydisplay.source.presentation.DemoPresentation;
21 
22 import android.app.Activity;
23 import android.app.PendingIntent;
24 import android.content.BroadcastReceiver;
25 import android.content.Context;
26 import android.content.Intent;
27 import android.content.IntentFilter;
28 import android.hardware.usb.UsbAccessory;
29 import android.hardware.usb.UsbManager;
30 import android.os.Bundle;
31 import android.os.ParcelFileDescriptor;
32 import android.text.method.ScrollingMovementMethod;
33 import android.util.Log;
34 import android.view.Display;
35 import android.widget.TextView;
36 
37 public class SourceActivity extends Activity {
38     private static final String TAG = "SourceActivity";
39 
40     private static final String ACTION_USB_ACCESSORY_PERMISSION =
41             "com.android.accessorydisplay.source.ACTION_USB_ACCESSORY_PERMISSION";
42 
43     private static final String MANUFACTURER = "Android";
44     private static final String MODEL = "Accessory Display";
45 
46     private UsbManager mUsbManager;
47     private AccessoryReceiver mReceiver;
48     private TextView mLogTextView;
49     private Logger mLogger;
50     private Presenter mPresenter;
51 
52     private boolean mConnected;
53     private UsbAccessory mAccessory;
54     private UsbAccessoryStreamTransport mTransport;
55 
56     private DisplaySourceService mDisplaySourceService;
57 
58     @Override
onCreate(Bundle savedInstanceState)59     protected void onCreate(Bundle savedInstanceState) {
60         super.onCreate(savedInstanceState);
61 
62         mUsbManager = (UsbManager)getSystemService(Context.USB_SERVICE);
63 
64         setContentView(R.layout.source_activity);
65 
66         mLogTextView = findViewById(R.id.logTextView);
67         mLogTextView.setMovementMethod(ScrollingMovementMethod.getInstance());
68         mLogger = new TextLogger();
69         mPresenter = new Presenter();
70 
71         mLogger.log("Waiting for accessory display sink to be attached to USB...");
72 
73         IntentFilter filter = new IntentFilter();
74         filter.addAction(UsbManager.ACTION_USB_ACCESSORY_ATTACHED);
75         filter.addAction(UsbManager.ACTION_USB_ACCESSORY_DETACHED);
76         filter.addAction(ACTION_USB_ACCESSORY_PERMISSION);
77         mReceiver = new AccessoryReceiver();
78         registerReceiver(mReceiver, filter);
79 
80         Intent intent = getIntent();
81         if (intent.getAction().equals(UsbManager.ACTION_USB_ACCESSORY_ATTACHED)) {
82             UsbAccessory accessory =
83                     (UsbAccessory) intent.getParcelableExtra(UsbManager.EXTRA_ACCESSORY);
84             if (accessory != null) {
85                 onAccessoryAttached(accessory);
86             }
87         } else {
88             UsbAccessory[] accessories = mUsbManager.getAccessoryList();
89             if (accessories != null) {
90                 for (UsbAccessory accessory : accessories) {
91                     onAccessoryAttached(accessory);
92                 }
93             }
94         }
95     }
96 
97     @Override
onDestroy()98     protected void onDestroy() {
99         super.onDestroy();
100 
101         unregisterReceiver(mReceiver);
102     }
103 
104     @Override
onResume()105     protected void onResume() {
106         super.onResume();
107 
108         //new DemoPresentation(this, getWindowManager().getDefaultDisplay()).show();
109     }
110 
111     @Override
onPause()112     protected void onPause() {
113         super.onPause();
114     }
115 
onAccessoryAttached(UsbAccessory accessory)116     private void onAccessoryAttached(UsbAccessory accessory) {
117         mLogger.log("USB accessory attached: " + accessory);
118         if (!mConnected) {
119             connect(accessory);
120         }
121     }
122 
onAccessoryDetached(UsbAccessory accessory)123     private void onAccessoryDetached(UsbAccessory accessory) {
124         mLogger.log("USB accessory detached: " + accessory);
125         if (mConnected && accessory.equals(mAccessory)) {
126             disconnect();
127         }
128     }
129 
connect(UsbAccessory accessory)130     private void connect(UsbAccessory accessory) {
131         if (!isSink(accessory)) {
132             mLogger.log("Not connecting to USB accessory because it is not an accessory display sink: "
133                     + accessory);
134             return;
135         }
136 
137         if (mConnected) {
138             disconnect();
139         }
140 
141         // Check whether we have permission to access the accessory.
142         if (!mUsbManager.hasPermission(accessory)) {
143             mLogger.log("Prompting the user for access to the accessory.");
144             Intent intent = new Intent(ACTION_USB_ACCESSORY_PERMISSION);
145             intent.setPackage(getPackageName());
146             PendingIntent pendingIntent = PendingIntent.getBroadcast(
147                     this, 0, intent, PendingIntent.FLAG_ONE_SHOT);
148             mUsbManager.requestPermission(accessory, pendingIntent);
149             return;
150         }
151 
152         // Open the accessory.
153         ParcelFileDescriptor fd = mUsbManager.openAccessory(accessory);
154         if (fd == null) {
155             mLogger.logError("Could not obtain accessory connection.");
156             return;
157         }
158 
159         // All set.
160         mLogger.log("Connected.");
161         mConnected = true;
162         mAccessory = accessory;
163         mTransport = new UsbAccessoryStreamTransport(mLogger, fd);
164         startServices();
165         mTransport.startReading();
166     }
167 
disconnect()168     private void disconnect() {
169         mLogger.log("Disconnecting from accessory: " + mAccessory);
170         stopServices();
171 
172         mLogger.log("Disconnected.");
173         mConnected = false;
174         mAccessory = null;
175         if (mTransport != null) {
176             mTransport.close();
177             mTransport = null;
178         }
179     }
180 
startServices()181     private void startServices() {
182         mDisplaySourceService = new DisplaySourceService(this, mTransport, mPresenter);
183         mDisplaySourceService.start();
184     }
185 
stopServices()186     private void stopServices() {
187         if (mDisplaySourceService != null) {
188             mDisplaySourceService.stop();
189             mDisplaySourceService = null;
190         }
191     }
192 
isSink(UsbAccessory accessory)193     private static boolean isSink(UsbAccessory accessory) {
194         return MANUFACTURER.equals(accessory.getManufacturer())
195                 && MODEL.equals(accessory.getModel());
196     }
197 
198     class TextLogger extends Logger {
199         @Override
log(final String message)200         public void log(final String message) {
201             Log.d(TAG, message);
202 
203             mLogTextView.post(new Runnable() {
204                 @Override
205                 public void run() {
206                     mLogTextView.append(message);
207                     mLogTextView.append("\n");
208                 }
209             });
210         }
211     }
212 
213     class AccessoryReceiver extends BroadcastReceiver {
214         @Override
onReceive(Context context, Intent intent)215         public void onReceive(Context context, Intent intent) {
216             UsbAccessory accessory = intent.<UsbAccessory>getParcelableExtra(
217                     UsbManager.EXTRA_ACCESSORY);
218             if (accessory != null) {
219                 String action = intent.getAction();
220                 if (action.equals(UsbManager.ACTION_USB_ACCESSORY_ATTACHED)) {
221                     onAccessoryAttached(accessory);
222                 } else if (action.equals(UsbManager.ACTION_USB_ACCESSORY_DETACHED)) {
223                     onAccessoryDetached(accessory);
224                 } else if (action.equals(ACTION_USB_ACCESSORY_PERMISSION)) {
225                     if (intent.getBooleanExtra(UsbManager.EXTRA_PERMISSION_GRANTED, false)) {
226                         mLogger.log("Accessory permission granted: " + accessory);
227                         onAccessoryAttached(accessory);
228                     } else {
229                         mLogger.logError("Accessory permission denied: " + accessory);
230                     }
231                 }
232             }
233         }
234     }
235 
236     class Presenter implements DisplaySourceService.Callbacks {
237         private DemoPresentation mPresentation;
238 
239         @Override
onDisplayAdded(Display display)240         public void onDisplayAdded(Display display) {
241             mLogger.log("Accessory display added: " + display);
242 
243             mPresentation = new DemoPresentation(SourceActivity.this, display, mLogger);
244             mPresentation.show();
245         }
246 
247         @Override
onDisplayRemoved(Display display)248         public void onDisplayRemoved(Display display) {
249             mLogger.log("Accessory display removed: " + display);
250 
251             if (mPresentation != null) {
252                 mPresentation.dismiss();
253                 mPresentation = null;
254             }
255         }
256     }
257 }
258