• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2023 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.example.android.vdmdemo.host;
18 
19 import android.app.AlertDialog;
20 import android.content.ComponentName;
21 import android.content.Context;
22 import android.content.Intent;
23 import android.content.ServiceConnection;
24 import android.os.Bundle;
25 import android.os.IBinder;
26 import android.util.Log;
27 import android.view.Menu;
28 import android.view.MenuInflater;
29 import android.view.MenuItem;
30 import android.view.View;
31 import android.widget.Button;
32 import android.widget.GridView;
33 
34 import androidx.appcompat.app.AppCompatActivity;
35 import androidx.appcompat.widget.Toolbar;
36 
37 import dagger.hilt.android.AndroidEntryPoint;
38 
39 import javax.inject.Inject;
40 
41 /**
42  * VDM Host activity, streaming apps to a remote device and processing the input coming from there.
43  */
44 @AndroidEntryPoint(AppCompatActivity.class)
45 public class MainActivity extends Hilt_MainActivity {
46     public static final String TAG = "VdmHost";
47 
48     private VdmService mVdmService = null;
49     private GridView mLauncher = null;
50     private Button mHomeDisplayButton = null;
51     private Button mMirrorDisplayButton = null;
52 
53     private final ServiceConnection mServiceConnection =
54             new ServiceConnection() {
55 
56                 @Override
57                 public void onServiceConnected(ComponentName className, IBinder binder) {
58                     Log.i(TAG, "Connected to VDM Service");
59                     mVdmService = ((VdmService.LocalBinder) binder).getService();
60                     mVdmService.setVirtualDeviceListener(
61                             MainActivity.this::updateLauncherVisibility);
62                     updateLauncherVisibility(mVdmService.isVirtualDeviceActive());
63                 }
64 
65                 @Override
66                 public void onServiceDisconnected(ComponentName className) {
67                     Log.i(TAG, "Disconnected from VDM Service");
68                     mVdmService = null;
69                 }
70             };
71 
72     @Inject
73     PreferenceController mPreferenceController;
74 
75     @Override
onCreate(Bundle savedInstanceState)76     public void onCreate(Bundle savedInstanceState) {
77         super.onCreate(savedInstanceState);
78 
79         setContentView(R.layout.activity_main);
80         Toolbar toolbar = requireViewById(R.id.main_tool_bar);
81         setSupportActionBar(toolbar);
82 
83         mHomeDisplayButton = requireViewById(R.id.create_home_display);
84         mHomeDisplayButton.setVisibility(View.GONE);
85         mHomeDisplayButton.setEnabled(
86                 mPreferenceController.getBoolean(R.string.internal_pref_home_displays_supported));
87         mMirrorDisplayButton = requireViewById(R.id.create_mirror_display);
88         mMirrorDisplayButton.setVisibility(View.GONE);
89         mMirrorDisplayButton.setEnabled(
90                 mPreferenceController.getBoolean(R.string.internal_pref_mirror_displays_supported));
91 
92         mLauncher = requireViewById(R.id.app_grid);
93         mLauncher.setVisibility(View.GONE);
94         LauncherAdapter launcherAdapter = new LauncherAdapter(getPackageManager());
95         mLauncher.setAdapter(launcherAdapter);
96         mLauncher.setOnItemClickListener(
97                 (parent, v, position, id) -> {
98                     Intent intent = launcherAdapter.createPendingRemoteIntent(position);
99                     if (intent == null || mVdmService == null) {
100                         return;
101                     }
102                     mVdmService.startStreaming(intent);
103                 });
104         mLauncher.setOnItemLongClickListener(
105                 (parent, v, position, id) -> {
106                     Intent intent = launcherAdapter.createPendingRemoteIntent(position);
107                     if (intent == null || mVdmService == null) {
108                         return true;
109                     }
110                     int[] remoteDisplayIds = mVdmService.getRemoteDisplayIds();
111                     if (remoteDisplayIds.length == 0) {
112                         mVdmService.startStreaming(intent);
113                     } else {
114                         String[] displays = new String[remoteDisplayIds.length + 1];
115                         for (int i = 0; i < remoteDisplayIds.length; ++i) {
116                             displays[i] = "Display " + remoteDisplayIds[i];
117                         }
118                         displays[remoteDisplayIds.length] = "New display";
119                         AlertDialog.Builder alertDialogBuilder =
120                                 new AlertDialog.Builder(MainActivity.this);
121                         alertDialogBuilder.setTitle("Choose display");
122                         alertDialogBuilder.setItems(
123                                 displays,
124                                 (dialog, which) -> {
125                                     if (which == remoteDisplayIds.length) {
126                                         mVdmService.startStreaming(intent);
127                                     } else {
128                                         mVdmService.startIntentOnDisplayIndex(intent, which);
129                                     }
130                                 });
131                         alertDialogBuilder.show();
132                     }
133                     return true;
134                 });
135     }
136 
137     @Override
onStart()138     protected void onStart() {
139         super.onStart();
140         Intent intent = new Intent(this, VdmService.class);
141         Log.i(TAG, "Starting Vdm Host service");
142         startForegroundService(intent);
143         bindService(intent, mServiceConnection, Context.BIND_AUTO_CREATE);
144     }
145 
146     @Override
onStop()147     protected void onStop() {
148         super.onStop();
149         if (mVdmService != null) {
150             mVdmService.setVirtualDeviceListener(null);
151         }
152         unbindService(mServiceConnection);
153     }
154 
updateLauncherVisibility(boolean virtualDeviceActive)155     private void updateLauncherVisibility(boolean virtualDeviceActive) {
156         final int visibility = virtualDeviceActive ? View.VISIBLE : View.GONE;
157         runOnUiThread(
158                 () -> {
159                     if (mLauncher != null) {
160                         mLauncher.setVisibility(visibility);
161                     }
162                     if (mHomeDisplayButton != null) {
163                         mHomeDisplayButton.setVisibility(visibility);
164                     }
165                     if (mMirrorDisplayButton != null) {
166                         mMirrorDisplayButton.setVisibility(visibility);
167                     }
168                 });
169     }
170 
171     /** Process a home display request. */
onCreateHomeDisplay(View view)172     public void onCreateHomeDisplay(View view) {
173         mVdmService.startStreamingHome();
174     }
175 
176     /** Process a mirror display request. */
onCreateMirrorDisplay(View view)177     public void onCreateMirrorDisplay(View view) {
178         mVdmService.startMirroring();
179     }
180 
181     @Override
onCreateOptionsMenu(Menu menu)182     public boolean onCreateOptionsMenu(Menu menu) {
183         MenuInflater inflater = getMenuInflater();
184         inflater.inflate(R.menu.options, menu);
185         return true;
186     }
187 
188     @Override
onOptionsItemSelected(MenuItem item)189     public boolean onOptionsItemSelected(MenuItem item) {
190         switch (item.getItemId()) {
191             case R.id.settings:
192                 startActivity(new Intent(this, SettingsActivity.class));
193                 return true;
194             case R.id.input:
195                 startActivity(new Intent(this, InputActivity.class));
196                 return true;
197             default:
198                 return super.onOptionsItemSelected(item);
199         }
200     }
201 }
202