| /* |
| * Copyright (C) 2020 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.controls.ui |
| |
| import android.app.ActivityView |
| import android.app.Dialog |
| import android.content.Intent |
| import android.provider.Settings |
| import android.view.View |
| import android.view.ViewGroup |
| import android.view.WindowInsets |
| import android.view.WindowInsets.Type |
| import android.view.WindowManager |
| import android.widget.ImageView |
| |
| import com.android.internal.policy.ScreenDecorationsUtils |
| import com.android.systemui.R |
| |
| /** |
| * A dialog that provides an {@link ActivityView}, allowing the application to provide |
| * additional information and actions pertaining to a {@link android.service.controls.Control}. |
| * The activity being launched is specified by {@link android.service.controls.Control#getAppIntent}. |
| */ |
| class DetailDialog( |
| val cvh: ControlViewHolder, |
| val intent: Intent |
| ) : Dialog(cvh.context, R.style.Theme_SystemUI_Dialog_Control_DetailPanel) { |
| |
| companion object { |
| private const val PANEL_TOP_OFFSET = "systemui.controls_panel_top_offset" |
| /* |
| * Indicate to the activity that it is being rendered in a bottomsheet, and they |
| * should optimize the layout for a smaller space. |
| */ |
| private const val EXTRA_USE_PANEL = "controls.DISPLAY_IN_PANEL" |
| } |
| |
| var activityView = ActivityView(context, null, 0, false) |
| |
| val stateCallback: ActivityView.StateCallback = object : ActivityView.StateCallback() { |
| override fun onActivityViewReady(view: ActivityView) { |
| val launchIntent = Intent(intent) |
| launchIntent.putExtra(EXTRA_USE_PANEL, true) |
| |
| // Apply flags to make behaviour match documentLaunchMode=always. |
| launchIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_DOCUMENT) |
| launchIntent.addFlags(Intent.FLAG_ACTIVITY_MULTIPLE_TASK) |
| |
| view.startActivity(launchIntent) |
| } |
| |
| override fun onActivityViewDestroyed(view: ActivityView) {} |
| |
| override fun onTaskRemovalStarted(taskId: Int) { |
| dismiss() |
| } |
| } |
| |
| init { |
| window.setType(WindowManager.LayoutParams.TYPE_VOLUME_OVERLAY) |
| setContentView(R.layout.controls_detail_dialog) |
| |
| requireViewById<ViewGroup>(R.id.controls_activity_view).apply { |
| addView(activityView) |
| } |
| |
| requireViewById<ImageView>(R.id.control_detail_close).apply { |
| setOnClickListener { _: View -> dismiss() } |
| } |
| |
| requireViewById<ImageView>(R.id.control_detail_open_in_app).apply { |
| setOnClickListener { v: View -> |
| dismiss() |
| context.sendBroadcast(Intent(Intent.ACTION_CLOSE_SYSTEM_DIALOGS)) |
| v.context.startActivity(intent) |
| } |
| } |
| |
| // consume all insets to achieve slide under effect |
| window.getDecorView().setOnApplyWindowInsetsListener { |
| _: View, insets: WindowInsets -> |
| activityView.apply { |
| val l = getPaddingLeft() |
| val t = getPaddingTop() |
| val r = getPaddingRight() |
| setPadding(l, t, r, insets.getInsets(Type.systemBars()).bottom) |
| } |
| |
| WindowInsets.CONSUMED |
| } |
| |
| requireViewById<ViewGroup>(R.id.control_detail_root).apply { |
| // use flag only temporarily for testing |
| val resolver = cvh.context.contentResolver |
| val defaultOffsetInPx = cvh.context.resources |
| .getDimensionPixelSize(R.dimen.controls_activity_view_top_offset) |
| val offsetInPx = Settings.Secure.getInt(resolver, PANEL_TOP_OFFSET, defaultOffsetInPx) |
| |
| val lp = getLayoutParams() as ViewGroup.MarginLayoutParams |
| lp.topMargin = offsetInPx |
| setLayoutParams(lp) |
| |
| setOnClickListener { dismiss() } |
| (getParent() as View).setOnClickListener { dismiss() } |
| } |
| |
| if (ScreenDecorationsUtils.supportsRoundedCornersOnWindows(context.getResources())) { |
| val cornerRadius = context.resources |
| .getDimensionPixelSize(R.dimen.controls_activity_view_corner_radius) |
| activityView.setCornerRadius(cornerRadius.toFloat()) |
| } |
| } |
| |
| override fun show() { |
| activityView.setCallback(stateCallback) |
| |
| super.show() |
| } |
| |
| override fun dismiss() { |
| if (!isShowing()) return |
| activityView.release() |
| |
| super.dismiss() |
| } |
| } |