Home | History | Annotate | Download | only in support
      1 /*
      2  * Copyright (C) 2016 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.android.settings.support;
     18 
     19 import android.accounts.Account;
     20 import android.app.Activity;
     21 import android.app.AlertDialog;
     22 import android.app.Dialog;
     23 import android.app.DialogFragment;
     24 import android.content.DialogInterface;
     25 import android.os.Bundle;
     26 import android.text.Annotation;
     27 import android.text.Spannable;
     28 import android.text.Spanned;
     29 import android.text.TextPaint;
     30 import android.text.TextUtils;
     31 import android.text.style.URLSpan;
     32 import android.view.LayoutInflater;
     33 import android.view.View;
     34 import android.widget.CheckBox;
     35 import android.widget.TextView;
     36 
     37 import com.android.internal.annotations.VisibleForTesting;
     38 import com.android.internal.logging.nano.MetricsProto;
     39 import com.android.settings.R;
     40 import com.android.settings.core.instrumentation.InstrumentedDialogFragment;
     41 import com.android.settings.overlay.FeatureFactory;
     42 import com.android.settings.overlay.SupportFeatureProvider;
     43 
     44 /**
     45  * {@link DialogFragment} for support disclaimer.
     46  */
     47 public final class SupportDisclaimerDialogFragment extends InstrumentedDialogFragment
     48         implements DialogInterface.OnClickListener {
     49 
     50     public static final String TAG = "SupportDisclaimerDialog";
     51     public static final String EXTRA_TYPE = "extra_type";
     52     public static final String EXTRA_ACCOUNT = "extra_account";
     53 
     54     public static SupportDisclaimerDialogFragment newInstance(Account account,
     55             @SupportFeatureProvider.SupportType int type) {
     56         final SupportDisclaimerDialogFragment fragment = new SupportDisclaimerDialogFragment();
     57         final Bundle bundle = new Bundle(2);
     58         bundle.putParcelable(SupportDisclaimerDialogFragment.EXTRA_ACCOUNT, account);
     59         bundle.putInt(SupportDisclaimerDialogFragment.EXTRA_TYPE, type);
     60         fragment.setArguments(bundle);
     61         return fragment;
     62     }
     63 
     64     @Override
     65     public Dialog onCreateDialog(Bundle savedInstanceState) {
     66         final AlertDialog.Builder builder = new AlertDialog.Builder(getActivity())
     67                 .setTitle(R.string.support_disclaimer_title)
     68                 .setPositiveButton(android.R.string.ok, this)
     69                 .setNegativeButton(android.R.string.cancel, this);
     70         final View content = LayoutInflater.from(builder.getContext())
     71                 .inflate(R.layout.support_disclaimer_content, null);
     72         final TextView disclaimer = (TextView) content.findViewById(R.id.support_disclaimer_text);
     73         final Activity activity = getActivity();
     74         final SupportFeatureProvider supportFeatureProvider =
     75                 FeatureFactory.getFactory(activity).getSupportFeatureProvider(activity);
     76 
     77         // sets the two links that go to privacy policy and terms of service
     78         disclaimer.setText(supportFeatureProvider.getDisclaimerStringResId());
     79         Spannable viewText = (Spannable) disclaimer.getText();
     80         stripUnderlines(viewText);
     81         SystemInformationSpan.linkify(viewText, this);
     82         // sets the link that launches a dialog to expose the signals we are sending
     83         return builder
     84                 .setView(content)
     85                 .create();
     86     }
     87 
     88     @Override
     89     public void onClick(DialogInterface dialog, int which) {
     90         if (which == Dialog.BUTTON_NEGATIVE) {
     91             mMetricsFeatureProvider.action(getContext(),
     92                     MetricsProto.MetricsEvent.ACTION_SUPPORT_DISCLAIMER_CANCEL);
     93             return;
     94         }
     95         final Activity activity = getActivity();
     96         final CheckBox doNotShow =
     97                 (CheckBox) getDialog().findViewById(R.id.support_disclaimer_do_not_show_again);
     98         final boolean isChecked = doNotShow.isChecked();
     99         final SupportFeatureProvider supportFeatureProvider =
    100                 FeatureFactory.getFactory(activity).getSupportFeatureProvider(activity);
    101         supportFeatureProvider.setShouldShowDisclaimerDialog(getContext(), !isChecked);
    102         final Bundle bundle = getArguments();
    103         if (isChecked) {
    104             mMetricsFeatureProvider.action(activity,
    105                     MetricsProto.MetricsEvent.ACTION_SKIP_DISCLAIMER_SELECTED);
    106         }
    107         mMetricsFeatureProvider.action(activity,
    108                 MetricsProto.MetricsEvent.ACTION_SUPPORT_DISCLAIMER_OK);
    109         supportFeatureProvider.startSupport(getActivity(),
    110                 bundle.getParcelable(EXTRA_ACCOUNT), bundle.getInt(EXTRA_TYPE));
    111     }
    112 
    113     @Override
    114     public void onCancel(DialogInterface dialog) {
    115         super.onCancel(dialog);
    116         mMetricsFeatureProvider.action(getContext(),
    117                 MetricsProto.MetricsEvent.ACTION_SUPPORT_DISCLAIMER_CANCEL);
    118     }
    119 
    120     /**
    121      * Removes the underlines of {@link android.text.style.URLSpan}s.
    122      */
    123     private static void stripUnderlines(Spannable input) {
    124         final URLSpan[] urls = input.getSpans(0, input.length(), URLSpan.class);
    125 
    126         for (URLSpan span : urls) {
    127             final int start = input.getSpanStart(span);
    128             final int end = input.getSpanEnd(span);
    129             if (!TextUtils.isEmpty(span.getURL())) {
    130                 input.removeSpan(span);
    131                 input.setSpan(new NoUnderlineUrlSpan(span.getURL()), start, end,
    132                         Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
    133             }
    134         }
    135     }
    136 
    137     @Override
    138     public int getMetricsCategory() {
    139         return MetricsProto.MetricsEvent.DIALOG_SUPPORT_DISCLAIMER;
    140     }
    141 
    142     /**
    143      * A {@link URLSpan} that doesn't decorate the link with underline.
    144      */
    145     public static class NoUnderlineUrlSpan extends URLSpan {
    146 
    147         public NoUnderlineUrlSpan(String url) {
    148             super(url);
    149         }
    150 
    151         @Override
    152         public void updateDrawState(TextPaint ds) {
    153             super.updateDrawState(ds);
    154             ds.setUnderlineText(false);
    155         }
    156     }
    157 
    158     /**
    159      * A {@link URLSpan} that opens a dialog when clicked
    160      */
    161     public static class SystemInformationSpan extends URLSpan {
    162 
    163         private static final String ANNOTATION_URL = "url";
    164         private final DialogFragment mDialog;
    165         private SupportFeatureProvider mSupport;
    166 
    167         public SystemInformationSpan(DialogFragment parent) {
    168             // sets the url to empty string so we can prevent the NoUnderlineUrlSpan from stripping
    169             // this one
    170             super("");
    171             mSupport  = FeatureFactory.getFactory(parent.getContext())
    172                     .getSupportFeatureProvider(parent.getContext());
    173             mDialog = parent;
    174         }
    175 
    176         @Override
    177         public void onClick(View widget) {
    178             Activity activity =  mDialog.getActivity();
    179             if (mSupport != null && activity != null) {
    180                 // launch the system info fragment
    181                 mSupport.launchSystemInfoFragment(mDialog.getArguments(),
    182                         activity.getFragmentManager());
    183 
    184                 // dismiss this fragment
    185                 mDialog.dismiss();
    186             }
    187         }
    188 
    189         @Override
    190         public void updateDrawState(TextPaint ds) {
    191             super.updateDrawState(ds);
    192             // remove underline
    193             ds.setUnderlineText(false);
    194         }
    195 
    196         /**
    197          * This method takes a string and turns it into a url span that will launch a
    198          * SupportSystemInformationDialogFragment
    199          * @param msg The text to turn into a link
    200          * @param parent The dialog the text is in
    201          * @return A CharSequence containing the original text content as a url
    202          */
    203         public static CharSequence linkify(Spannable msg, DialogFragment parent) {
    204             Annotation[] spans = msg.getSpans(0, msg.length(), Annotation.class);
    205             for (Annotation annotation : spans) {
    206                 int start = msg.getSpanStart(annotation);
    207                 int end = msg.getSpanEnd(annotation);
    208                 if (ANNOTATION_URL.equals(annotation.getValue())) {
    209                     SystemInformationSpan link = new SystemInformationSpan(parent);
    210                     msg.removeSpan(annotation);
    211                     msg.setSpan(link, start, end, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
    212                 }
    213             }
    214             return msg;
    215         }
    216 
    217         @VisibleForTesting
    218         public void setSupportProvider(SupportFeatureProvider prov) {
    219             mSupport = prov;
    220         }
    221     }
    222 }
    223