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
17package com.android.accessorydisplay.source;
18
19import com.android.accessorydisplay.common.Logger;
20import com.android.accessorydisplay.source.presentation.DemoPresentation;
21
22import android.app.Activity;
23import android.app.PendingIntent;
24import android.content.BroadcastReceiver;
25import android.content.Context;
26import android.content.Intent;
27import android.content.IntentFilter;
28import android.hardware.usb.UsbAccessory;
29import android.hardware.usb.UsbManager;
30import android.os.Bundle;
31import android.os.ParcelFileDescriptor;
32import android.text.method.ScrollingMovementMethod;
33import android.util.Log;
34import android.view.Display;
35import android.widget.TextView;
36
37public 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
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
98    protected void onDestroy() {
99        super.onDestroy();
100
101        unregisterReceiver(mReceiver);
102    }
103
104    @Override
105    protected void onResume() {
106        super.onResume();
107
108        //new DemoPresentation(this, getWindowManager().getDefaultDisplay()).show();
109    }
110
111    @Override
112    protected void onPause() {
113        super.onPause();
114    }
115
116    private void onAccessoryAttached(UsbAccessory accessory) {
117        mLogger.log("USB accessory attached: " + accessory);
118        if (!mConnected) {
119            connect(accessory);
120        }
121    }
122
123    private void onAccessoryDetached(UsbAccessory accessory) {
124        mLogger.log("USB accessory detached: " + accessory);
125        if (mConnected && accessory.equals(mAccessory)) {
126            disconnect();
127        }
128    }
129
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
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
181    private void startServices() {
182        mDisplaySourceService = new DisplaySourceService(this, mTransport, mPresenter);
183        mDisplaySourceService.start();
184    }
185
186    private void stopServices() {
187        if (mDisplaySourceService != null) {
188            mDisplaySourceService.stop();
189            mDisplaySourceService = null;
190        }
191    }
192
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
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
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
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
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