blob: 81de607f24f868064dc1b83e5e283414a0e4f878 [file] [log] [blame]
/*
* 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.logcat;
import android.annotation.StyleRes;
import android.app.Activity;
import android.app.AlertDialog;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import android.os.RemoteException;
import android.os.UserHandle;
import android.text.SpannableString;
import android.text.Spanned;
import android.text.TextUtils;
import android.text.method.LinkMovementMethod;
import android.text.style.URLSpan;
import android.util.Slog;
import android.view.ContextThemeWrapper;
import android.view.InflateException;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
import com.android.internal.app.ILogAccessDialogCallback;
import com.android.systemui.R;
/**
* Dialog responsible for obtaining user consent per-use log access
*/
public class LogAccessDialogActivity extends Activity implements
View.OnClickListener {
private static final String TAG = LogAccessDialogActivity.class.getSimpleName();
public static final String EXTRA_CALLBACK = "EXTRA_CALLBACK";
private static final int DIALOG_TIME_OUT = Build.IS_DEBUGGABLE ? 60000 : 300000;
private static final int MSG_DISMISS_DIALOG = 0;
private String mPackageName;
private int mUid;
private ILogAccessDialogCallback mCallback;
private String mAlertTitle;
private String mAlertBody;
private boolean mAlertLearnMoreLink;
private SpannableString mAlertLearnMore;
private AlertDialog.Builder mAlertDialog;
private AlertDialog mAlert;
private View mAlertView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// retrieve Intent extra information
if (!readIntentInfo(getIntent())) {
Slog.e(TAG, "Invalid Intent extras, finishing");
finish();
return;
}
// retrieve the title string from passed intent extra
try {
mAlertTitle = getTitleString(this, mPackageName, mUid);
} catch (NameNotFoundException e) {
Slog.e(TAG, "Unable to fetch label of package " + mPackageName, e);
declineLogAccess();
finish();
return;
}
mAlertBody = getString(R.string.log_access_confirmation_body);
mAlertLearnMoreLink = this.getResources()
.getBoolean(R.bool.log_access_confirmation_learn_more_as_link);
if (mAlertLearnMoreLink) {
mAlertLearnMore = new SpannableString(
getString(R.string.log_access_confirmation_learn_more));
mAlertLearnMore.setSpan(new URLSpan(
getString(R.string.log_access_confirmation_learn_more_url)),
0, mAlertLearnMore.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
} else {
mAlertLearnMore = new SpannableString(
getString(R.string.log_access_confirmation_learn_more_at,
getString(R.string.log_access_confirmation_learn_more_url)));
}
// create View
int themeId = R.style.LogAccessDialogTheme;
mAlertView = createView(themeId);
// create AlertDialog
mAlertDialog = new AlertDialog.Builder(this, themeId);
mAlertDialog.setView(mAlertView);
mAlertDialog.setOnCancelListener(dialog -> declineLogAccess());
mAlertDialog.setOnDismissListener(dialog -> finish());
// show Alert
mAlert = mAlertDialog.create();
mAlert.getWindow().setHideOverlayWindows(true);
mAlert.show();
// set Alert Timeout
mHandler.sendEmptyMessageDelayed(MSG_DISMISS_DIALOG, DIALOG_TIME_OUT);
}
@Override
protected void onDestroy() {
super.onDestroy();
if (!isChangingConfigurations() && mAlert != null && mAlert.isShowing()) {
mAlert.dismiss();
}
mAlert = null;
}
private boolean readIntentInfo(Intent intent) {
if (intent == null) {
Slog.e(TAG, "Intent is null");
return false;
}
mCallback = ILogAccessDialogCallback.Stub.asInterface(
intent.getExtras().getBinder(EXTRA_CALLBACK));
if (mCallback == null) {
Slog.e(TAG, "Missing callback");
return false;
}
mPackageName = intent.getStringExtra(Intent.EXTRA_PACKAGE_NAME);
if (mPackageName == null || mPackageName.length() == 0) {
Slog.e(TAG, "Missing package name extra");
return false;
}
if (!intent.hasExtra(Intent.EXTRA_UID)) {
Slog.e(TAG, "Missing EXTRA_UID");
return false;
}
mUid = intent.getIntExtra(Intent.EXTRA_UID, 0);
return true;
}
private Handler mHandler = new Handler() {
public void handleMessage(android.os.Message msg) {
switch (msg.what) {
case MSG_DISMISS_DIALOG:
if (mAlert != null) {
mAlert.dismiss();
mAlert = null;
declineLogAccess();
}
break;
default:
break;
}
}
};
private String getTitleString(Context context, String callingPackage, int uid)
throws NameNotFoundException {
PackageManager pm = context.getPackageManager();
CharSequence appLabel = pm.getApplicationInfoAsUser(callingPackage,
PackageManager.MATCH_DIRECT_BOOT_AUTO,
UserHandle.getUserId(uid)).loadLabel(pm);
String titleString = context.getString(R.string.log_access_confirmation_title, appLabel);
return titleString;
}
/**
* Returns the dialog view.
* If we cannot retrieve the package name, it returns null and we decline the full device log
* access
*/
private View createView(@StyleRes int themeId) {
Context themedContext = new ContextThemeWrapper(this, themeId);
final View view = LayoutInflater.from(themedContext).inflate(
R.layout.log_access_user_consent_dialog_permission, null /*root*/);
if (view == null) {
throw new InflateException();
}
((TextView) view.findViewById(R.id.log_access_dialog_title))
.setText(mAlertTitle);
if (!TextUtils.isEmpty(mAlertLearnMore)) {
((TextView) view.findViewById(R.id.log_access_dialog_body))
.setText(TextUtils.concat(mAlertBody, "\n\n", mAlertLearnMore));
if (mAlertLearnMoreLink) {
((TextView) view.findViewById(R.id.log_access_dialog_body))
.setMovementMethod(LinkMovementMethod.getInstance());
}
} else {
((TextView) view.findViewById(R.id.log_access_dialog_body))
.setText(mAlertBody);
}
Button button_allow = (Button) view.findViewById(R.id.log_access_dialog_allow_button);
button_allow.setOnClickListener(this);
Button button_deny = (Button) view.findViewById(R.id.log_access_dialog_deny_button);
button_deny.setOnClickListener(this);
return view;
}
@Override
public void onClick(View view) {
try {
if (view.getId() == R.id.log_access_dialog_allow_button) {
mCallback.approveAccessForClient(mUid, mPackageName);
finish();
} else if (view.getId() == R.id.log_access_dialog_deny_button) {
declineLogAccess();
finish();
}
} catch (RemoteException e) {
finish();
}
}
private void declineLogAccess() {
try {
mCallback.declineAccessForClient(mUid, mPackageName);
} catch (RemoteException e) {
finish();
}
}
}