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