• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2018 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.wifi.dpp;
18 
19 import android.annotation.Nullable;
20 import android.app.settings.SettingsEnums;
21 import android.content.ComponentName;
22 import android.content.Intent;
23 import android.content.pm.PackageManager;
24 import android.content.pm.ResolveInfo;
25 import android.content.res.Resources;
26 import android.graphics.Bitmap;
27 import android.graphics.drawable.Drawable;
28 import android.os.Bundle;
29 import android.provider.Settings;
30 import android.text.TextUtils;
31 import android.util.Log;
32 import android.view.LayoutInflater;
33 import android.view.Menu;
34 import android.view.MenuInflater;
35 import android.view.MenuItem;
36 import android.view.View;
37 import android.view.ViewGroup;
38 import android.widget.Button;
39 import android.widget.ImageView;
40 import android.widget.TextView;
41 
42 import com.android.internal.annotations.VisibleForTesting;
43 import com.android.internal.app.chooser.DisplayResolveInfo;
44 import com.android.internal.app.chooser.TargetInfo;
45 import com.android.settings.R;
46 import com.android.settings.wifi.qrcode.QrCodeGenerator;
47 
48 import com.google.zxing.WriterException;
49 
50 /**
51  * After sharing a saved Wi-Fi network, {@code WifiDppConfiguratorActivity} start with this fragment
52  * to generate a Wi-Fi DPP QR code for other device to initiate as an enrollee.
53  */
54 public class WifiDppQrCodeGeneratorFragment extends WifiDppQrCodeBaseFragment {
55     private static final String TAG = "WifiDppQrCodeGeneratorFragment";
56 
57     private ImageView mQrCodeView;
58     private String mQrCode;
59 
60     private static final String CHIP_LABEL_METADATA_KEY = "android.service.chooser.chip_label";
61     private static final String CHIP_ICON_METADATA_KEY = "android.service.chooser.chip_icon";
62     private static final String EXTRA_WIFI_CREDENTIALS_BUNDLE =
63             "android.intent.extra.WIFI_CREDENTIALS_BUNDLE";
64     private static final String EXTRA_SSID = "android.intent.extra.SSID";
65     private static final String EXTRA_PASSWORD = "android.intent.extra.PASSWORD";
66     private static final String EXTRA_SECURITY_TYPE = "android.intent.extra.SECURITY_TYPE";
67     private static final String EXTRA_HIDDEN_SSID = "android.intent.extra.HIDDEN_SSID";
68 
69     @Override
getMetricsCategory()70     public int getMetricsCategory() {
71         return SettingsEnums.SETTINGS_WIFI_DPP_CONFIGURATOR;
72     }
73 
74     @Override
onActivityCreated(Bundle savedInstanceState)75     public void onActivityCreated(Bundle savedInstanceState) {
76         super.onActivityCreated(savedInstanceState);
77 
78         // setTitle for TalkBack
79         final WifiNetworkConfig wifiNetworkConfig = getWifiNetworkConfigFromHostActivity();
80         if (getActivity() != null) {
81             if (wifiNetworkConfig.isHotspot()) {
82                 getActivity().setTitle(R.string.wifi_dpp_share_hotspot);
83             } else {
84                 getActivity().setTitle(R.string.wifi_dpp_share_wifi);
85             }
86         }
87     }
88 
89     @Override
onCreateOptionsMenu(Menu menu, MenuInflater inflater)90     public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
91         final MenuItem menuItem = menu.findItem(Menu.FIRST);
92         if (menuItem != null) {
93             menuItem.setShowAsAction(MenuItem.SHOW_AS_ACTION_NEVER);
94         }
95 
96         super.onCreateOptionsMenu(menu, inflater);
97     }
98 
99     @Override
onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)100     public final View onCreateView(LayoutInflater inflater, ViewGroup container,
101             Bundle savedInstanceState) {
102         return inflater.inflate(R.layout.wifi_dpp_qrcode_generator_fragment, container,
103                 /* attachToRoot */ false);
104     }
105 
106     @Override
onViewCreated(View view, Bundle savedInstanceState)107     public void onViewCreated(View view, Bundle savedInstanceState) {
108         super.onViewCreated(view, savedInstanceState);
109 
110         mQrCodeView = view.findViewById(R.id.qrcode_view);
111 
112         final WifiNetworkConfig wifiNetworkConfig = getWifiNetworkConfigFromHostActivity();
113         if (wifiNetworkConfig.isHotspot()) {
114             setHeaderTitle(R.string.wifi_dpp_share_hotspot);
115         } else {
116             setHeaderTitle(R.string.wifi_dpp_share_wifi);
117         }
118 
119         final String password = wifiNetworkConfig.getPreSharedKey();
120         TextView passwordView = view.findViewById(R.id.password);
121         if (TextUtils.isEmpty(password)) {
122             mSummary.setText(getString(
123                     R.string.wifi_dpp_scan_open_network_qr_code_with_another_device,
124                     wifiNetworkConfig.getSsid()));
125 
126             passwordView.setVisibility(View.GONE);
127         } else {
128             mSummary.setText(getString(R.string.wifi_dpp_scan_qr_code_with_another_device,
129                     wifiNetworkConfig.getSsid()));
130 
131             if (wifiNetworkConfig.isHotspot()) {
132                 passwordView.setText(getString(R.string.wifi_dpp_hotspot_password, password));
133             } else {
134                 passwordView.setText(getString(R.string.wifi_dpp_wifi_password, password));
135             }
136         }
137 
138         final Intent intent = new Intent().setComponent(getNearbySharingComponent());
139         addActionButton(view.findViewById(R.id.wifi_dpp_layout), createNearbyButton(intent, v -> {
140             intent.setAction(Intent.ACTION_SEND);
141             intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
142             intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK);
143 
144             Bundle wifiCredentialBundle = new Bundle();
145 
146             String ssid = WifiDppUtils.removeFirstAndLastDoubleQuotes(wifiNetworkConfig.getSsid());
147 
148             String passwordExtra = wifiNetworkConfig.getPreSharedKey();
149             String securityType = wifiNetworkConfig.getSecurity();
150             boolean hiddenSsid = wifiNetworkConfig.getHiddenSsid();
151 
152             wifiCredentialBundle.putString(EXTRA_SSID, ssid);
153             wifiCredentialBundle.putString(EXTRA_PASSWORD, passwordExtra);
154             wifiCredentialBundle.putString(EXTRA_SECURITY_TYPE, securityType);
155             wifiCredentialBundle.putBoolean(EXTRA_HIDDEN_SSID, hiddenSsid);
156 
157             intent.putExtra(EXTRA_WIFI_CREDENTIALS_BUNDLE, wifiCredentialBundle);
158             startActivity(intent);
159         }));
160 
161         mQrCode = wifiNetworkConfig.getQrCode();
162         setQrCode();
163     }
164 
165     @VisibleForTesting
getNearbySharingComponent()166     ComponentName getNearbySharingComponent() {
167         String nearbyComponent = Settings.Secure.getString(
168                 getContext().getContentResolver(),
169                 Settings.Secure.NEARBY_SHARING_COMPONENT);
170         if (TextUtils.isEmpty(nearbyComponent)) {
171             nearbyComponent = getString(
172                     com.android.internal.R.string.config_defaultNearbySharingComponent);
173         }
174         if (TextUtils.isEmpty(nearbyComponent)) {
175             return null;
176         }
177         return ComponentName.unflattenFromString(nearbyComponent);
178     }
179 
getNearbySharingTarget(Intent originalIntent)180     private TargetInfo getNearbySharingTarget(Intent originalIntent) {
181         final ComponentName cn = getNearbySharingComponent();
182         if (cn == null) return null;
183 
184         final Intent resolveIntent = new Intent(originalIntent);
185         resolveIntent.setComponent(cn);
186         PackageManager pm = getContext().getPackageManager();
187         final ResolveInfo resolveInfo = pm.resolveActivity(
188                 resolveIntent, PackageManager.GET_META_DATA);
189         if (resolveInfo == null || resolveInfo.activityInfo == null) {
190             Log.e(TAG, "Device-specified nearby sharing component (" + cn
191                     + ") not available");
192             return null;
193         }
194 
195         // Allow the nearby sharing component to provide a more appropriate icon and label
196         // for the chip.
197         CharSequence name = null;
198         Drawable icon = null;
199         final Bundle metaData = resolveInfo.activityInfo.metaData;
200         if (metaData != null) {
201             try {
202                 final Resources pkgRes = pm.getResourcesForActivity(cn);
203                 final int nameResId = metaData.getInt(CHIP_LABEL_METADATA_KEY);
204                 name = pkgRes.getString(nameResId);
205                 final int resId = metaData.getInt(CHIP_ICON_METADATA_KEY);
206                 icon = pkgRes.getDrawable(resId);
207             } catch (Resources.NotFoundException ex) {
208             } catch (PackageManager.NameNotFoundException ex) {
209             }
210         }
211         if (TextUtils.isEmpty(name)) {
212             name = resolveInfo.loadLabel(pm);
213         }
214         if (icon == null) {
215             icon = resolveInfo.loadIcon(pm);
216         }
217 
218         final DisplayResolveInfo dri = new DisplayResolveInfo(
219                 originalIntent, resolveInfo, name, "", resolveIntent, null);
220         dri.setDisplayIcon(icon);
221         return dri;
222     }
223 
createActionButton(Drawable icon, CharSequence title, View.OnClickListener r)224     private Button createActionButton(Drawable icon, CharSequence title, View.OnClickListener r) {
225         final Button b = (Button) LayoutInflater.from(getContext()).inflate(
226                 com.android.internal.R.layout.chooser_action_button, null);
227         if (icon != null) {
228             final int size = getResources()
229                     .getDimensionPixelSize(
230                             com.android.internal.R.dimen.chooser_action_button_icon_size);
231             icon.setBounds(0, 0, size, size);
232             b.setCompoundDrawablesRelative(icon, null, null, null);
233         }
234         b.setText(title);
235         b.setOnClickListener(r);
236         return b;
237     }
238 
addActionButton(ViewGroup parent, Button b)239     private void addActionButton(ViewGroup parent, Button b) {
240         if (b == null) return;
241         final ViewGroup.MarginLayoutParams lp = new ViewGroup.MarginLayoutParams(
242                 ViewGroup.LayoutParams.WRAP_CONTENT,
243                 ViewGroup.LayoutParams.WRAP_CONTENT
244         );
245         final int gap = getResources().getDimensionPixelSize(
246                 com.android.internal.R.dimen.resolver_icon_margin) / 2;
247         lp.setMarginsRelative(gap, 0, gap, 0);
248         parent.addView(b, lp);
249     }
250 
251     @VisibleForTesting
252     @Nullable
createNearbyButton(Intent originalIntent, View.OnClickListener r)253     Button createNearbyButton(Intent originalIntent, View.OnClickListener r) {
254         final TargetInfo ti = getNearbySharingTarget(originalIntent);
255         if (ti == null) return null;
256         final Button button = createActionButton(ti.getDisplayIcon(getContext()),
257                 ti.getDisplayLabel(), r);
258         button.setAllCaps(false);
259         return button;
260     }
261 
setQrCode()262     private void setQrCode() {
263         try {
264             final int qrcodeSize = getContext().getResources().getDimensionPixelSize(
265                     R.dimen.qrcode_size);
266             final Bitmap bmp = QrCodeGenerator.encodeQrCode(mQrCode, qrcodeSize);
267             mQrCodeView.setImageBitmap(bmp);
268         } catch (WriterException e) {
269             Log.e(TAG, "Error generating QR code bitmap " + e);
270         }
271     }
272 
getWifiNetworkConfigFromHostActivity()273     private WifiNetworkConfig getWifiNetworkConfigFromHostActivity() {
274         final WifiNetworkConfig wifiNetworkConfig = ((WifiNetworkConfig.Retriever) getActivity())
275                 .getWifiNetworkConfig();
276         if (!WifiNetworkConfig.isValidConfig(wifiNetworkConfig)) {
277             throw new IllegalStateException("Invalid Wi-Fi network for configuring");
278         }
279 
280         return wifiNetworkConfig;
281     }
282 
283     @Override
isFooterAvailable()284     protected boolean isFooterAvailable() {
285         return false;
286     }
287 }
288