Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 3e137eb2 authored by Jason Monk's avatar Jason Monk Committed by Android (Google) Code Review
Browse files

Merge "QS: Add security footer." into lmp-dev

parents bcb0c5d2 3d5f551c
Loading
Loading
Loading
Loading
+25 −0
Original line number Diff line number Diff line
<!--
Copyright (C) 2014 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.
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
        android:width="12.0dp"
        android:height="12.0dp"
        android:viewportWidth="24.0"
        android:viewportHeight="24.0">

    <path
        android:fillColor="#4DFFFFFF"
        android:pathData="M22.000000,4.000000L22.000000,3.500000C22.000000,2.100000 20.900000,1.000000 19.500000,1.000000C18.100000,1.000000 17.000000,2.100000 17.000000,3.500000L17.000000,4.000000c-0.600000,0.000000 -1.000000,0.400000 -1.000000,1.000000l0.000000,4.000000c0.000000,0.600000 0.400000,1.000000 1.000000,1.000000l5.000000,0.000000c0.600000,0.000000 1.000000,-0.400000 1.000000,-1.000000L23.000000,5.000000C23.000000,4.400000 22.600000,4.000000 22.000000,4.000000zM21.200001,4.000000l-3.400000,0.000000L17.800001,3.500000c0.000000,-0.900000 0.800000,-1.700000 1.700000,-1.700000c0.900000,0.000000 1.700000,0.800000 1.700000,1.700000L21.200003,4.000000zM18.900000,12.000000c0.000000,0.300000 0.100000,0.700000 0.100000,1.000000c0.000000,2.100000 -0.800000,4.000000 -2.100000,5.400000c-0.300000,-0.800000 -1.000000,-1.400000 -1.900000,-1.400000l-1.000000,0.000000l0.000000,-3.000000c0.000000,-0.600000 -0.400000,-1.000000 -1.000000,-1.000000L7.000000,13.000000l0.000000,-2.000000l2.000000,0.000000c0.600000,0.000000 1.000000,-0.400000 1.000000,-1.000000L10.000000,8.000000l2.000000,0.000000c1.100000,0.000000 2.000000,-0.900000 2.000000,-2.000000L14.000000,3.500000C13.100000,3.200000 12.000000,3.000000 11.000000,3.000000C5.500000,3.000000 1.000000,7.500000 1.000000,13.000000c0.000000,5.500000 4.500000,10.000000 10.000000,10.000000c5.500000,0.000000 10.000000,-4.500000 10.000000,-10.000000c0.000000,-0.300000 0.000000,-0.700000 -0.100000,-1.000000L18.900000,12.000000zM10.000000,20.900000c-3.900000,-0.500000 -7.000000,-3.900000 -7.000000,-7.900000c0.000000,-0.600000 0.100000,-1.200000 0.200000,-1.800000L8.000000,16.000000l0.000000,1.000000c0.000000,1.100000 0.900000,2.000000 2.000000,2.000000L10.000000,20.900000z"/>
</vector>
+42 −0
Original line number Diff line number Diff line
<?xml version="1.0" encoding="utf-8"?>
<!--
     Copyright (C) 2014 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.
-->
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:clickable="true"
    android:paddingBottom="@dimen/qs_tile_padding_top"
    android:paddingTop="@dimen/qs_tile_padding_top" >

    <TextView
        android:id="@+id/footer_text"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerHorizontal="true"
        android:textSize="@dimen/qs_tile_text_size" />

    <ImageView
        android:id="@+id/footer_icon"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerVertical="true"
        android:layout_marginEnd="8dp"
        android:layout_toStartOf="@id/footer_text"
        android:contentDescription="@null"
        android:src="@drawable/ic_qs_vpn"
        android:visibility="invisible" />

</RelativeLayout>
 No newline at end of file
+34 −0
Original line number Diff line number Diff line
@@ -741,4 +741,38 @@

    <!-- Text which is shown in the notification shade when there are no notifications. [CHAR LIMIT=30] -->
    <string name="empty_shade_text">No notifications</string>

    <!-- Footer device owned text [CHAR LIMIT=50] -->
    <string name="device_owned_footer">Device may be monitored</string>

    <!-- Footer vpn present text [CHAR LIMIT=50] -->
    <string name="vpn_footer">Network may be monitored</string>

    <!-- Monitoring dialog title for device owned devices [CHAR LIMIT=35] -->
    <string name="monitoring_title_device_owned">Device monitoring</string>

    <!-- Monitoring dialog title for normal devices  [CHAR LIMIT=35]-->
    <string name="monitoring_title">Network monitoring</string>

    <!-- Monitoring dialog open app button [CHAR LIMIT=30] -->
    <string name="open_app">Open app</string>

    <!-- Monitoring dialog disconnect vpn button [CHAR LIMIT=30] -->
    <string name="disconnect_vpn">Disconnect VPN</string>

    <!-- Monitoring dialog device owner body text [CHAR LIMIT=300] -->
    <string name="monitoring_description_device_owned">This device is managed by:\n<xliff:g id="organization">%1$s</xliff:g>\n\nYour administrator can monitor your network activity, including emails, apps and secure websites.\n\nFor more information, contact your administrator.</string>

    <!-- Monitoring dialog non-legacy VPN text [CHAR LIMIT=300] -->
    <string name="monitoring_description_vpn">You gave \"<xliff:g id="application">%1$s</xliff:g>\" permission to set up a VPN connection.\n\nThis app can monitor your network activity, including emails, apps and secure websites.</string>

    <!-- Monitoring dialog legacy VPN text [CHAR LIMIT=300] -->
    <string name="monitoring_description_legacy_vpn">You\'re connected to a VPN (\"<xliff:g id="application">%1$s</xliff:g>\").\n\nYour VPN service provider can monitor your network activity including emails, apps, and secure websites.</string>

    <!-- Monitoring dialog non-legacy VPN with device owner text [CHAR LIMIT=300] -->
    <string name="monitoring_description_vpn_device_owned">This device is managed by:\n<xliff:g id="organization">%1$s</xliff:g>\n\nYour administrator is capable of monitoring your network activity including emails, apps, and secure websites. For more information, contact your administrator.\n\nAlso, you gave \"<xliff:g id="application">%2$s</xliff:g>\" permission to set up a VPN connection. This app can monitor network activity too.</string>

    <!-- Monitoring dialog legacy VPN with device owner text [CHAR LIMIT=300] -->
    <string name="monitoring_description_legacy_vpn_device_owned">This device is managed by:\n<xliff:g id="organization">%1$s</xliff:g>\n\nYour administrator is capable of monitoring your network activity including emails, apps, and secure websites. For more information, contact your administrator.\n\nAlso, you\'re connected to a VPN (\"<xliff:g id="application">%2$s</xliff:g>\"). Your VPN service provider can monitor network activity too.</string>

</resources>
+218 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2014 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.qs;

import android.app.AlertDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.util.Log;
import android.view.ContextThemeWrapper;
import android.view.LayoutInflater;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.WindowManager;
import android.widget.ImageView;
import android.widget.TextView;

import com.android.systemui.R;
import com.android.systemui.statusbar.phone.QSTileHost;
import com.android.systemui.statusbar.phone.SystemUIDialog;
import com.android.systemui.statusbar.policy.SecurityController;
import com.android.systemui.statusbar.policy.SecurityController.VpnCallback;

public class QSFooter implements OnClickListener, DialogInterface.OnClickListener {
    protected static final String TAG = "QSFooter";
    protected static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);

    private final View mRootView;
    private final TextView mFooterText;
    private final ImageView mFooterIcon;
    private final Context mContext;
    private final Callback mCallback = new Callback();

    private SecurityController mSecurityController;
    private AlertDialog mDialog;
    private QSTileHost mHost;
    private Handler mHandler;

    public QSFooter(QSPanel qsPanel, Context context) {
        mRootView = LayoutInflater.from(context)
                .inflate(R.layout.quick_settings_footer, qsPanel, false);
        mRootView.setOnClickListener(this);
        mFooterText = (TextView) mRootView.findViewById(R.id.footer_text);
        mFooterIcon = (ImageView) mRootView.findViewById(R.id.footer_icon);
        mContext = context;
    }

    public void setHost(QSTileHost host) {
        mHost = host;
        mSecurityController = host.getSecurityController();
        mHandler = new H(host.getLooper());
    }

    public void setListening(boolean listening) {
        if (listening) {
            mSecurityController.addCallback(mCallback);
        } else {
            mSecurityController.removeCallback(mCallback);
        }
    }

    public View getView() {
        return mRootView;
    }

    public boolean hasFooter() {
        return mRootView.getVisibility() != View.GONE;
    }

    @Override
    public void onClick(View v) {
        mHandler.sendEmptyMessage(H.CLICK);
    }

    private void handleClick() {
        mHost.collapsePanels();
        // TODO: Delay dialog creation until after panels are collapsed.
        createDialog();
    }

    public void refreshState() {
        mHandler.sendEmptyMessage(H.REFRESH_STATE);
    }

    private void handleRefreshState() {
        if (mSecurityController.hasDeviceOwner()) {
            mFooterText.setText(R.string.device_owned_footer);
            mRootView.setVisibility(View.VISIBLE);
            mFooterIcon.setVisibility(View.INVISIBLE);
        } else if (mSecurityController.isVpnEnabled()) {
            mFooterText.setText(R.string.vpn_footer);
            mRootView.setVisibility(View.VISIBLE);
            mFooterIcon.setVisibility(View.VISIBLE);
        } else {
            mRootView.setVisibility(View.GONE);
        }
    }

    @Override
    public void onClick(DialogInterface dialog, int which) {
        if (which == DialogInterface.BUTTON_NEGATIVE) {
            if (mSecurityController.isLegacyVpn()) {
                mSecurityController.disconnectFromLegacyVpn();
            } else {
                mSecurityController.openVpnApp();
            }
        }
    }

    private void createDialog() {
        mDialog = new SystemUIDialog(mContext);
        mDialog.setTitle(getTitle());
        mDialog.setMessage(getMessage());
        mDialog.setButton(DialogInterface.BUTTON_POSITIVE, getPositiveButton(), this);
        if (mSecurityController.isVpnEnabled()) {
            mDialog.setButton(DialogInterface.BUTTON_NEGATIVE, getNegativeButton(), this);
        }
        mDialog.show();
    }

    private String getNegativeButton() {
        if (mSecurityController.isLegacyVpn()) {
            return mContext.getString(R.string.disconnect_vpn);
        } else {
            return mContext.getString(R.string.open_app);
        }
    }

    private String getPositiveButton() {
        return mContext.getString(R.string.quick_settings_done);
    }

    private String getMessage() {
        if (mSecurityController.hasDeviceOwner()) {
            if (mSecurityController.isVpnEnabled()) {
                if (mSecurityController.isLegacyVpn()) {
                    return mContext.getString(
                            R.string.monitoring_description_legacy_vpn_device_owned,
                            mSecurityController.getDeviceOwnerName(),
                            mSecurityController.getLegacyVpnName());
                } else {
                    return mContext.getString(R.string.monitoring_description_vpn_device_owned,
                            mSecurityController.getDeviceOwnerName(),
                            mSecurityController.getVpnApp());
                }
            } else {
                return mContext.getString(R.string.monitoring_description_device_owned,
                        mSecurityController.getDeviceOwnerName());
            }
        } else {
            if (mSecurityController.isLegacyVpn()) {
                return mContext.getString(R.string.monitoring_description_legacy_vpn,
                        mSecurityController.getLegacyVpnName());

            } else {
                return mContext.getString(R.string.monitoring_description_vpn,
                        mSecurityController.getVpnApp());
            }
        }
    }

    private int getTitle() {
        if (mSecurityController.hasDeviceOwner()) {
            return R.string.monitoring_title_device_owned;
        }
        return R.string.monitoring_title;
    }

    private class Callback implements VpnCallback {
        @Override
        public void onVpnStateChanged() {
            refreshState();
        }
    }

    private class H extends Handler {
        private static final int CLICK = 0;
        private static final int REFRESH_STATE = 1;

        private H(Looper looper) {
            super(looper);
        }

        @Override
        public void handleMessage(Message msg) {
            String name = null;
            try {
                if (msg.what == REFRESH_STATE) {
                    name = "handleRefreshState";
                    handleRefreshState();
                } else if (msg.what == CLICK) {
                    name = "handleClick";
                    handleClick();
                }
            } catch (Throwable t) {
                final String error = "Error in " + name;
                Log.w(TAG, error, t);
                mHost.warn(error, t);
            }
        }
    }

}
+16 −0
Original line number Diff line number Diff line
@@ -67,6 +67,8 @@ public class QSPanel extends ViewGroup {
    private BrightnessController mBrightnessController;
    private QSTileHost mHost;

    private QSFooter mFooter;

    public QSPanel(Context context) {
        this(context, null);
    }
@@ -83,8 +85,10 @@ public class QSPanel extends ViewGroup {
        mDetail.setClickable(true);
        mBrightnessView = LayoutInflater.from(context).inflate(
                R.layout.quick_settings_brightness_dialog, this, false);
        mFooter = new QSFooter(this, context);
        addView(mDetail);
        addView(mBrightnessView);
        addView(mFooter.getView());
        mClipper = new QSDetailClipper(mDetail);
        updateResources();

@@ -106,6 +110,7 @@ public class QSPanel extends ViewGroup {

    public void setHost(QSTileHost host) {
        mHost = host;
        mFooter.setHost(host);
    }

    public QSTileHost getHost() {
@@ -144,6 +149,7 @@ public class QSPanel extends ViewGroup {
        for (TileRecord r : mRecords) {
            r.tile.setListening(mListening);
        }
        mFooter.setListening(mListening);
        if (mListening) {
            refreshAllTiles();
        }
@@ -158,6 +164,7 @@ public class QSPanel extends ViewGroup {
        for (TileRecord r : mRecords) {
            r.tile.refreshState();
        }
        mFooter.refreshState();
    }

    public void showDetailAdapter(boolean show, DetailAdapter adapter) {
@@ -287,6 +294,7 @@ public class QSPanel extends ViewGroup {
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        final int width = MeasureSpec.getSize(widthMeasureSpec);
        mBrightnessView.measure(exactly(width), MeasureSpec.UNSPECIFIED);
        mFooter.getView().measure(exactly(width), MeasureSpec.UNSPECIFIED);
        int r = -1;
        int c = -1;
        int rows = 0;
@@ -315,6 +323,9 @@ public class QSPanel extends ViewGroup {
            record.tileView.measure(exactly(cw), exactly(ch));
        }
        int h = rows == 0 ? mBrightnessView.getHeight() : (getRowTop(rows) + mPanelPaddingBottom);
        if (mFooter.hasFooter()) {
            h += mFooter.getView().getHeight();
        }
        mDetail.measure(exactly(width), exactly(h));
        setMeasuredDimension(width, h);
    }
@@ -341,6 +352,11 @@ public class QSPanel extends ViewGroup {
        }
        final int dh = Math.max(mDetail.getMeasuredHeight(), getMeasuredHeight());
        mDetail.layout(0, 0, mDetail.getMeasuredWidth(), dh);
        if (mFooter.hasFooter()) {
            View footer = mFooter.getView();
            footer.layout(0, getMeasuredHeight() - footer.getMeasuredHeight(),
                    footer.getMeasuredWidth(), getMeasuredHeight());
        }
    }

    private int getRowTop(int row) {
Loading