| /* |
| * Copyright (C) 2022 The Android Open Source Project |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| package com.android.systemui.media |
| |
| import android.app.ActivityOptions |
| import android.content.Intent |
| import android.media.projection.IMediaProjection |
| import android.media.projection.MediaProjectionManager.EXTRA_MEDIA_PROJECTION |
| import android.os.Binder |
| import android.os.Bundle |
| import android.os.IBinder |
| import android.view.View |
| import com.android.internal.app.ChooserActivity |
| import com.android.internal.app.chooser.NotSelectableTargetInfo |
| import com.android.internal.app.chooser.TargetInfo |
| import com.android.systemui.util.AsyncActivityLauncher |
| import com.android.systemui.R; |
| import javax.inject.Inject |
| |
| class MediaProjectionAppSelectorActivity @Inject constructor( |
| private val activityLauncher: AsyncActivityLauncher |
| ) : ChooserActivity() { |
| |
| public override fun onCreate(bundle: Bundle?) { |
| val queryIntent = Intent(Intent.ACTION_MAIN) |
| .addCategory(Intent.CATEGORY_LAUNCHER) |
| intent.putExtra(Intent.EXTRA_INTENT, queryIntent) |
| |
| // TODO(b/235465652) Use resource lexeme |
| intent.putExtra(Intent.EXTRA_TITLE, "Record or cast an app") |
| |
| super.onCreate(bundle) |
| |
| // TODO(b/235465652) we should update VisD of the title and add an icon |
| findViewById<View>(R.id.title)?.visibility = View.VISIBLE |
| } |
| |
| override fun appliedThemeResId(): Int = |
| R.style.Theme_SystemUI_MediaProjectionAppSelector |
| |
| override fun startSelected(which: Int, always: Boolean, filtered: Boolean) { |
| val currentListAdapter = mChooserMultiProfilePagerAdapter.activeListAdapter |
| val targetInfo = currentListAdapter.targetInfoForPosition(which, filtered) ?: return |
| if (targetInfo is NotSelectableTargetInfo) return |
| |
| val intent = createIntent(targetInfo) |
| |
| val launchToken: IBinder = Binder("media_projection_launch_token") |
| val activityOptions = ActivityOptions.makeBasic() |
| activityOptions.launchCookie = launchToken |
| |
| val userHandle = mMultiProfilePagerAdapter.activeListAdapter.userHandle |
| |
| // Launch activity asynchronously and wait for the result, launching of an activity |
| // is typically very fast, so we don't show any loaders. |
| // We wait for the activity to be launched to make sure that the window of the activity |
| // is created and ready to be captured. |
| val activityStarted = activityLauncher |
| .startActivityAsUser(intent, userHandle, activityOptions.toBundle()) { |
| onTargetActivityLaunched(launchToken) |
| } |
| |
| // Rely on the ActivityManager to pop up a dialog regarding app suspension |
| // and return false if suspended |
| if (!targetInfo.isSuspended && activityStarted) { |
| // TODO(b/222078415) track activity launch |
| } |
| } |
| |
| private fun createIntent(target: TargetInfo): Intent { |
| val intent = Intent(target.resolvedIntent) |
| |
| // Launch the app in a new task, so it won't be in the host's app task |
| intent.flags = intent.flags or Intent.FLAG_ACTIVITY_NEW_TASK |
| |
| // Remove activity forward result flag as this activity will |
| // return the media projection session |
| intent.flags = intent.flags and Intent.FLAG_ACTIVITY_FORWARD_RESULT.inv() |
| |
| return intent |
| } |
| |
| override fun onDestroy() { |
| activityLauncher.destroy() |
| super.onDestroy() |
| } |
| |
| override fun onActivityStarted(cti: TargetInfo) { |
| // do nothing |
| } |
| |
| private fun onTargetActivityLaunched(launchToken: IBinder) { |
| val mediaProjectionBinder = intent.getIBinderExtra(EXTRA_MEDIA_PROJECTION) |
| val projection = IMediaProjection.Stub.asInterface(mediaProjectionBinder) |
| |
| projection.launchCookie = launchToken |
| |
| val intent = Intent() |
| intent.putExtra(EXTRA_MEDIA_PROJECTION, projection.asBinder()) |
| setResult(RESULT_OK, intent) |
| setForceSendResultForMediaProjection() |
| finish() |
| } |
| |
| override fun shouldGetOnlyDefaultActivities() = false |
| } |