Request ACCESS_FINE_LOCATION when necessary
P2P printing will stop working for users who configure a P2P printer
then update to Q. This pull detects this condition and posts a notification
allowing the user to fix or intentionally disable P2P. Also allows the
user to enable/disable P2P from the "Add printer" activity.
Test: Add P2P printer, deny location permissions, then start print.
Change-Id: I844b38705097cf760766fcf64d19ec6a5270e637
Merged-In: I90323c180b7de9f1d3b9fdeee3afb803f0a77a2d
Signed-off-by: Glade Diviney <mopriadevteam@gmail.com>
diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index e87f721..05028e8 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -18,7 +18,7 @@
<uses-feature android:name="android.hardware.wifi" android:required="false"/>
- <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
+ <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.CHANGE_WIFI_MULTICAST_STATE" />
@@ -59,5 +59,6 @@
android:exported="true"
android:configChanges="orientation|keyboardHidden|screenSize"
android:permission="android.permission.START_PRINT_SERVICE_CONFIG_ACTIVITY" />
+
</application>
</manifest>
diff --git a/res/values/strings.xml b/res/values/strings.xml
index 2ff94c6..04fb35f 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -65,6 +65,8 @@
<string name="printer_not_supported">Printer not supported</string>
<string name="wifi_direct">Wi-Fi Direct</string>
<string name="find_wifi_direct">Find Wi-Fi Direct printers</string>
+ <!-- Preference name for enable/disable of Wi-Fi Direct printing [CHAR LIMIT=UNLIMITED] -->
+ <string name="wifi_direct_printing">Wi-Fi Direct printing</string>
<string name="wifi_direct_printers">Wi-Fi Direct printers</string>
<string name="searching">Searching\u2026</string>
<string name="connect_hint_text">You may need to approve this connection on your printer\'s
@@ -95,4 +97,11 @@
<!-- Button label in a notification. This button rejects a printer security change [CHAR LIMIT=20] -->
<string name="reject">Reject</string>
+ <!-- Channel name for connection-related notifications [CHAR LIMIT=40] -->
+ <string name="connections">Connections</string>
+ <!-- Message shown in dialog, toast, or notification if the service cannot get Wi-Fi Direct permissions [CHAR LIMIT=UNLIMITED] -->
+ <string name="wifi_direct_permission_rationale">Default Print Service needs location permissions
+ to access Wi-Fi Direct printers because your location can be inferred from nearby devices.</string>
+ <!-- Button label in a notification or dialog. This button leads to a request to grant permissions [CHAR LIMIT=20] -->
+ <string name="fix">Fix</string>
</resources>
diff --git a/res/xml/add_printers_prefs.xml b/res/xml/add_printers_prefs.xml
index ce44052..2f6d981 100644
--- a/res/xml/add_printers_prefs.xml
+++ b/res/xml/add_printers_prefs.xml
@@ -25,17 +25,24 @@
android:persistent="false"
android:order="1" />
+ <SwitchPreference
+ android:key="wifi_direct_printing"
+ android:title="@string/wifi_direct_printing"
+ android:iconSpaceReserved="true"
+ android:persistent="false"
+ android:order="2" />
+
<Preference
android:key="find_wifi_direct"
android:title="@string/find_wifi_direct"
android:icon="@drawable/ic_menu_search"
android:persistent="false"
- android:order="2" />
+ android:order="3" />
<PreferenceCategory
android:key="saved_printers"
android:title="@string/saved_printers"
android:persistent="false"
- android:order="3" />
+ android:order="4" />
</PreferenceScreen>
diff --git a/src/com/android/bips/BuiltInPrintService.java b/src/com/android/bips/BuiltInPrintService.java
index 9519962..f9931a5 100644
--- a/src/com/android/bips/BuiltInPrintService.java
+++ b/src/com/android/bips/BuiltInPrintService.java
@@ -66,10 +66,13 @@
BuiltInPrintService.class.getCanonicalName() + ".CERTIFICATE_ACCEPT";
private static final String ACTION_CERTIFICATE_REJECT =
BuiltInPrintService.class.getCanonicalName() + ".CERTIFICATE_REJECT";
+ public static final String ACTION_P2P_PERMISSION_CANCEL =
+ BuiltInPrintService.class.getCanonicalName() + ".P2P_PERMISSION_CANCEL";
private static final String EXTRA_CERTIFICATE = "certificate";
private static final String EXTRA_PRINTER_ID = "printer-id";
private static final String EXTRA_PRINTER_UUID = "printer-uuid";
private static final int CERTIFICATE_REQUEST_ID = 1000;
+ public static final int P2P_PERMISSION_REQUEST_ID = 1001;
// Present because local activities can bind, but cannot access this object directly
private static WeakReference<BuiltInPrintService> sInstance;
@@ -86,6 +89,7 @@
private WifiManager.WifiLock mWifiLock;
private P2pMonitor mP2pMonitor;
private NsdResolveQueue mNsdResolveQueue;
+ private P2pPermissionManager mP2pPermissionManager;
/**
* Return the current print service instance, if running
@@ -106,6 +110,8 @@
}
super.onCreate();
createNotificationChannel();
+ mP2pPermissionManager = new P2pPermissionManager(this);
+ mP2pPermissionManager.reset();
sInstance = new WeakReference<>(this);
mBackend = new Backend(this);
@@ -138,6 +144,7 @@
@Override
public void onDestroy() {
if (DEBUG) Log.d(TAG, "onDestroy()");
+ mP2pPermissionManager.closeNotification();
mCapabilitiesCache.close();
mP2pMonitor.stopAll();
mBackend.close();
@@ -208,6 +215,13 @@
}
/**
+ * Return a general {@link P2pPermissionManager}
+ */
+ public P2pPermissionManager getP2pPermissionManager() {
+ return mP2pPermissionManager;
+ }
+
+ /**
* Listen for a set of broadcast messages until stopped
*/
public BroadcastMonitor receiveBroadcasts(BroadcastReceiver receiver, String... actions) {
@@ -341,6 +355,8 @@
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
if (DEBUG) Log.d(TAG, "Received action=" + intent.getAction());
+ NotificationManager manager = (NotificationManager) getSystemService(
+ Context.NOTIFICATION_SERVICE);
if (ACTION_CERTIFICATE_ACCEPT.equals(intent.getAction())) {
byte[] certificate = intent.getByteArrayExtra(EXTRA_CERTIFICATE);
PrinterId printerId = intent.getParcelableExtra(EXTRA_PRINTER_ID);
@@ -352,14 +368,16 @@
}
// Restart the job with the updated certificate in place
mJobQueue.restart(printerId);
+ manager.cancel(TAG_CERTIFICATE_REQUEST, CERTIFICATE_REQUEST_ID);
} else if (ACTION_CERTIFICATE_REJECT.equals(intent.getAction())) {
// Cancel any job in certificate state for this uuid
PrinterId printerId = intent.getParcelableExtra(EXTRA_PRINTER_ID);
mJobQueue.cancel(printerId);
+ manager.cancel(TAG_CERTIFICATE_REQUEST, CERTIFICATE_REQUEST_ID);
+ } else if (ACTION_P2P_PERMISSION_CANCEL.equals(intent.getAction())) {
+ // Inform p2pPermissionManager the user canceled the notification (non-permanent)
+ mP2pPermissionManager.applyPermissionChange(false);
}
- NotificationManager manager = (NotificationManager) getSystemService(
- Context.NOTIFICATION_SERVICE);
- manager.cancel(TAG_CERTIFICATE_REQUEST, CERTIFICATE_REQUEST_ID);
return START_NOT_STICKY;
}
}
diff --git a/src/com/android/bips/P2pPermissionManager.java b/src/com/android/bips/P2pPermissionManager.java
new file mode 100644
index 0000000..4773818
--- /dev/null
+++ b/src/com/android/bips/P2pPermissionManager.java
@@ -0,0 +1,303 @@
+/*
+ * Copyright (C) 2019 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.bips;
+
+import static android.Manifest.permission.ACCESS_FINE_LOCATION;
+
+import android.app.Activity;
+import android.app.AlertDialog;
+import android.app.Notification;
+import android.app.NotificationChannel;
+import android.app.NotificationManager;
+import android.app.PendingIntent;
+import android.content.Context;
+import android.content.DialogInterface;
+import android.content.Intent;
+import android.content.SharedPreferences;
+import android.content.pm.PackageManager;
+import android.graphics.drawable.Icon;
+import android.util.Log;
+import android.view.ContextThemeWrapper;
+import android.widget.Toast;
+
+import com.android.bips.ui.AddPrintersActivity;
+import com.android.bips.ui.AddPrintersFragment;
+
+/**
+ * Manage Wi-Fi Direct permission requirements and state.
+ */
+public class P2pPermissionManager {
+ private static final String TAG = P2pPermissionManager.class.getCanonicalName();
+ private static final boolean DEBUG = false;
+
+ private static final String CHANNEL_ID_CONNECTIONS = "connections";
+ public static final int REQUEST_P2P_PERMISSION_CODE = 1000;
+
+ private static final String STATE_KEY = "state";
+
+ private static final P2pPermissionRequest sFinishedRequest = () -> { };
+
+ private final Context mContext;
+ private final SharedPreferences mPrefs;
+ private final NotificationManager mNotificationManager;
+
+ public P2pPermissionManager(Context context) {
+ mContext = context;
+ mPrefs = mContext.getSharedPreferences(TAG, 0);
+ mNotificationManager = mContext.getSystemService(NotificationManager.class);
+ }
+
+ /**
+ * Reset any temporary modes.
+ */
+ public void reset() {
+ if (getState() == State.TEMPORARILY_DISABLED) {
+ setState(State.DENIED);
+ }
+ }
+
+ /**
+ * Update the current P2P permissions request state.
+ */
+ public void setState(State state) {
+ if (DEBUG) Log.d(TAG, "Setting state=" + state);
+ mPrefs.edit().putString(STATE_KEY, state.name()).apply();
+ }
+
+ /**
+ * Return true if P2P features are enabled.
+ */
+ public boolean isP2pEnabled() {
+ return getState() == State.ALLOWED;
+ }
+
+ /**
+ * The user has made a permissions-related choice.
+ */
+ public void applyPermissionChange(boolean permanent) {
+ closeNotification();
+ if (hasP2pPermission()) {
+ setState(State.ALLOWED);
+ } else {
+ // Inform the user and don't try again for the rest of this session.
+ setState(permanent ? State.DISABLED : State.TEMPORARILY_DISABLED);
+ Toast.makeText(mContext, R.string.wifi_direct_permission_rationale, Toast.LENGTH_LONG)
+ .show();
+ }
+ }
+
+ /**
+ * Return true if the user has granted P2P-related permission.
+ */
+ private boolean hasP2pPermission() {
+ return mContext.checkSelfPermission(ACCESS_FINE_LOCATION)
+ == PackageManager.PERMISSION_GRANTED;
+ }
+
+ /**
+ * Request P2P permission from the user, until the user makes a selection or the returned
+ * {@link P2pPermissionRequest} is closed.
+ *
+ * Note: if requested on behalf of an Activity, the Activity MUST call
+ * {@link P2pPermissionManager#applyPermissionChange(boolean)} whenever
+ * {@link Activity#onRequestPermissionsResult(int, String[], int[])} is called with code
+ * {@link P2pPermissionManager#REQUEST_P2P_PERMISSION_CODE}.
+ */
+ public P2pPermissionRequest request(boolean explain, P2pPermissionListener listener) {
+ // Check current permission level
+ State state = getState();
+
+ if (DEBUG) Log.d(TAG, "request() state=" + state);
+
+ if (state.isTerminal()) {
+ listener.onP2pPermissionComplete(state == State.ALLOWED);
+ // Nothing to close because no listener registered.
+ return sFinishedRequest;
+ }
+
+ SharedPreferences.OnSharedPreferenceChangeListener preferenceListener =
+ listenForPreferenceChanges(listener);
+
+ if (mContext instanceof Activity) {
+ Activity activity = (Activity) mContext;
+ if (explain && activity.shouldShowRequestPermissionRationale(ACCESS_FINE_LOCATION)) {
+ explain(activity);
+ } else {
+ request(activity);
+ }
+ } else {
+ showNotification();
+ }
+
+ return () -> {
+ // Allow the caller to close this request if it no longer cares about the result
+ closeNotification();
+ mPrefs.unregisterOnSharedPreferenceChangeListener(preferenceListener);
+ };
+ }
+
+ /**
+ * Use the activity to request permissions if possible.
+ */
+ private void request(Activity activity) {
+ activity.requestPermissions(new String[]{ACCESS_FINE_LOCATION},
+ REQUEST_P2P_PERMISSION_CODE);
+ }
+
+ private void explain(Activity activity) {
+ // User denied, but asked us to use P2P, so explain and redirect to settings
+ DialogInterface.OnClickListener clickListener = (dialog, which) -> {
+ if (which == DialogInterface.BUTTON_POSITIVE) {
+ request(activity);
+ }
+ };
+
+ new AlertDialog.Builder(new ContextThemeWrapper(activity,
+ android.R.style.Theme_Material_Settings))
+ .setMessage(mContext.getString(R.string.wifi_direct_permission_rationale))
+ .setPositiveButton(R.string.fix, clickListener)
+ .show();
+ }
+
+ private SharedPreferences.OnSharedPreferenceChangeListener listenForPreferenceChanges(
+ P2pPermissionListener listener) {
+ SharedPreferences.OnSharedPreferenceChangeListener preferenceListener =
+ new SharedPreferences.OnSharedPreferenceChangeListener() {
+ @Override
+ public void onSharedPreferenceChanged(SharedPreferences sharedPreferences,
+ String key) {
+ State state = getState();
+ if (state.isTerminal() || state == State.DENIED) {
+ listener.onP2pPermissionComplete(state == State.ALLOWED);
+ mPrefs.unregisterOnSharedPreferenceChangeListener(this);
+ }
+ }
+ };
+ mPrefs.registerOnSharedPreferenceChangeListener(preferenceListener);
+ return preferenceListener;
+ }
+
+ /**
+ * Deliver a notification to the user.
+ */
+ private void showNotification() {
+ // Because we are not in an activity create a notification to do the work
+ mNotificationManager.createNotificationChannel(new NotificationChannel(
+ CHANNEL_ID_CONNECTIONS, mContext.getString(R.string.connections),
+ NotificationManager.IMPORTANCE_HIGH));
+
+ Intent proceedIntent = new Intent(mContext, AddPrintersActivity.class);
+ proceedIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
+ proceedIntent.putExtra(AddPrintersFragment.EXTRA_FIX_P2P_PERMISSION, true);
+ PendingIntent proceedPendingIntent = PendingIntent.getActivity(mContext, 0,
+ proceedIntent, PendingIntent.FLAG_UPDATE_CURRENT);
+ Notification.Action fixAction = new Notification.Action.Builder(
+ Icon.createWithResource(mContext, R.drawable.ic_printservice),
+ mContext.getString(R.string.fix), proceedPendingIntent).build();
+
+ Intent cancelIntent = new Intent(mContext, BuiltInPrintService.class)
+ .setAction(BuiltInPrintService.ACTION_P2P_PERMISSION_CANCEL);
+ PendingIntent cancelPendingIndent = PendingIntent.getService(mContext,
+ BuiltInPrintService.P2P_PERMISSION_REQUEST_ID, cancelIntent,
+ PendingIntent.FLAG_UPDATE_CURRENT);
+ Notification.Action cancelAction = new Notification.Action.Builder(
+ Icon.createWithResource(mContext, R.drawable.ic_printservice),
+ mContext.getString(android.R.string.cancel), cancelPendingIndent).build();
+
+ Notification notification = new Notification.Builder(mContext, CHANNEL_ID_CONNECTIONS)
+ .setSmallIcon(R.drawable.ic_printservice)
+ .setStyle(new Notification.BigTextStyle().bigText(
+ mContext.getString(R.string.wifi_direct_permission_rationale)))
+ .setAutoCancel(true)
+ .setContentIntent(proceedPendingIntent)
+ .setDeleteIntent(cancelPendingIndent)
+ .addAction(fixAction)
+ .addAction(cancelAction)
+ .build();
+
+ mNotificationManager.notify(BuiltInPrintService.P2P_PERMISSION_REQUEST_ID, notification);
+ }
+
+ /**
+ * Return the current {@link State}.
+ */
+ public State getState() {
+ // Look up stored state
+ String stateString = mPrefs.getString(STATE_KEY, State.DENIED.name());
+ State state = State.valueOf(stateString);
+
+ if (state == State.DISABLED) {
+ // If disabled do no further checking
+ return state;
+ }
+
+ boolean hasPermission = hasP2pPermission();
+ if (hasPermission && state != State.ALLOWED) {
+ // Upgrade state if now allowed
+ state = State.ALLOWED;
+ setState(state);
+ } else if (!hasPermission && state == State.ALLOWED) {
+ state = State.DENIED;
+ setState(state);
+ }
+ return state;
+ }
+
+ /**
+ * Close any outstanding notification.
+ */
+ void closeNotification() {
+ mNotificationManager.cancel(BuiltInPrintService.P2P_PERMISSION_REQUEST_ID);
+ }
+
+ /**
+ * The current P2P permission request state.
+ */
+ public enum State {
+ // The user has not granted permissions.
+ DENIED,
+ // The user did not grant permissions this time but try again next time.
+ TEMPORARILY_DISABLED,
+ // The user explicitly disabled or chose not to enable P2P.
+ DISABLED,
+ // Permissions are granted.
+ ALLOWED;
+
+ /** Return true if the user {@link State} is at a final permissions state. */
+ public boolean isTerminal() {
+ return this != DENIED;
+ }
+ }
+
+ /**
+ * Listener for determining when a P2P permission request is complete.
+ */
+ public interface P2pPermissionListener {
+ /**
+ * Invoked when it is known that the user has allowed or denied the permission request.
+ */
+ void onP2pPermissionComplete(boolean allowed);
+ }
+
+ /**
+ * A closeable request for grant of P2P permissions.
+ */
+ public interface P2pPermissionRequest extends AutoCloseable {
+ @Override
+ void close();
+ }
+}
diff --git a/src/com/android/bips/discovery/P2pDiscovery.java b/src/com/android/bips/discovery/P2pDiscovery.java
index 4b6776a..083e88d 100644
--- a/src/com/android/bips/discovery/P2pDiscovery.java
+++ b/src/com/android/bips/discovery/P2pDiscovery.java
@@ -21,6 +21,7 @@
import android.util.Log;
import com.android.bips.BuiltInPrintService;
+import com.android.bips.P2pPermissionManager;
import com.android.bips.p2p.P2pPeerListener;
/**
@@ -32,6 +33,7 @@
private static final boolean DEBUG = false;
private boolean mDiscoveringPeers = false;
+ private P2pPermissionManager.P2pPermissionRequest mP2pPermissionRequest;
public P2pDiscovery(BuiltInPrintService printService) {
super(printService);
@@ -61,6 +63,10 @@
@Override
void onStop() {
if (DEBUG) Log.d(TAG, "onStop()");
+ if (mP2pPermissionRequest != null) {
+ mP2pPermissionRequest.close();
+ mP2pPermissionRequest = null;
+ }
if (mDiscoveringPeers) {
mDiscoveringPeers = false;
getPrintService().getP2pMonitor().stopDiscover(this);
@@ -73,8 +79,16 @@
if (mDiscoveringPeers || getSavedPrinters().isEmpty()) {
return;
}
- mDiscoveringPeers = true;
- getPrintService().getP2pMonitor().discover(this);
+
+ // Only begin discovery if the user has granted permissions
+ P2pPermissionManager permissionManager = getPrintService().getP2pPermissionManager();
+ mP2pPermissionRequest = permissionManager.request(true, approved -> {
+ if (approved) {
+ mDiscoveringPeers = true;
+ getPrintService().getP2pMonitor().discover(this);
+ }
+ mP2pPermissionRequest = null;
+ });
}
@Override
diff --git a/src/com/android/bips/ui/AddPrintersActivity.java b/src/com/android/bips/ui/AddPrintersActivity.java
index 78de1dc..182b108 100644
--- a/src/com/android/bips/ui/AddPrintersActivity.java
+++ b/src/com/android/bips/ui/AddPrintersActivity.java
@@ -19,10 +19,11 @@
import android.app.ActionBar;
import android.app.Activity;
-import android.app.Fragment;
import android.os.Bundle;
import android.view.MenuItem;
+import com.android.bips.P2pPermissionManager;
+
/**
* Launched by system in response to an Add Printer request
*/
@@ -53,14 +54,11 @@
@Override
public void onRequestPermissionsResult(int requestCode, String[] permissions,
- int[] grantResults) {
- Fragment fragment = getFragmentManager().findFragmentById(android.R.id.content);
- if (fragment != null && fragment instanceof OnPermissionChangeListener) {
- ((OnPermissionChangeListener) fragment).onPermissionChange();
+ int[] grantResults) {
+ // Update permission status on any change requested by a fragment.
+ if (requestCode == P2pPermissionManager.REQUEST_P2P_PERMISSION_CODE) {
+ new P2pPermissionManager(this).applyPermissionChange(true);
}
- }
-
- interface OnPermissionChangeListener {
- void onPermissionChange();
+ super.onRequestPermissionsResult(requestCode, permissions, grantResults);
}
}
diff --git a/src/com/android/bips/ui/AddPrintersFragment.java b/src/com/android/bips/ui/AddPrintersFragment.java
index 7b51447..e122cad 100644
--- a/src/com/android/bips/ui/AddPrintersFragment.java
+++ b/src/com/android/bips/ui/AddPrintersFragment.java
@@ -26,9 +26,11 @@
import android.preference.Preference;
import android.preference.PreferenceCategory;
import android.preference.PreferenceFragment;
+import android.preference.SwitchPreference;
import android.util.Log;
import com.android.bips.BuiltInPrintService;
+import com.android.bips.P2pPermissionManager;
import com.android.bips.R;
import com.android.bips.discovery.DiscoveredPrinter;
import com.android.bips.p2p.P2pUtils;
@@ -42,12 +44,18 @@
private static final String KEY_ADD_BY_IP = "add_by_ip";
private static final String KEY_FIND_WIFI_DIRECT = "find_wifi_direct";
+ private static final String KEY_WIFI_DIRECT_PRINTING = "wifi_direct_printing";
private static final String KEY_SAVED_PRINTERS = "saved_printers";
+ public static final String EXTRA_FIX_P2P_PERMISSION = "fix_p2p_permission";
+
private static final int ORDER_SAVED = 2;
private PreferenceCategory mSavedPrintersCategory;
private Preference mAddPrinterByIpPreference;
+ private Preference mFindP2pPrintersPreference;
+ private SwitchPreference mP2pEnablePreference;
private BuiltInPrintService mPrintService;
+ private P2pPermissionManager mP2pPermissionManager;
@Override
public void onCreate(Bundle in) {
@@ -56,16 +64,17 @@
addPreferencesFromResource(R.xml.add_printers_prefs);
mAddPrinterByIpPreference = getPreferenceScreen().findPreference(KEY_ADD_BY_IP);
- Preference findP2pPrintersPreference = getPreferenceScreen().findPreference(
+ mFindP2pPrintersPreference = getPreferenceScreen().findPreference(
KEY_FIND_WIFI_DIRECT);
- findP2pPrintersPreference.setOnPreferenceClickListener(preference -> {
+ mFindP2pPrintersPreference.setOnPreferenceClickListener(preference -> {
getFragmentManager().beginTransaction()
.replace(android.R.id.content, new FindP2pPrintersFragment())
.addToBackStack(null)
.commit();
return true;
});
-
+ mP2pEnablePreference = (SwitchPreference) getPreferenceScreen()
+ .findPreference(KEY_WIFI_DIRECT_PRINTING);
mSavedPrintersCategory = (PreferenceCategory) getPreferenceScreen()
.findPreference(KEY_SAVED_PRINTERS);
}
@@ -78,6 +87,37 @@
getActivity().setTitle(R.string.title_activity_add_printer);
getContext().bindService(new Intent(getContext(), BuiltInPrintService.class), this,
Context.BIND_AUTO_CREATE);
+
+ mP2pPermissionManager = new P2pPermissionManager(getActivity());
+ updateP2pPreferences();
+
+ if (getActivity().getIntent().getBooleanExtra(EXTRA_FIX_P2P_PERMISSION, false)) {
+ // Additional explanation is redundant, since the user saw it in notification.
+ mP2pPermissionManager.request(false, approve -> {
+ updateP2pPreferences();
+ if (!approve) {
+ // The user is choosing to disable by denying Location.
+ mP2pPermissionManager.setState(P2pPermissionManager.State.DISABLED);
+ }
+ });
+ }
+
+ mP2pEnablePreference.setOnPreferenceClickListener(preference -> {
+ if (mP2pEnablePreference.isChecked()) {
+ mP2pEnablePreference.setChecked(false);
+ if (mP2pPermissionManager.getState() == P2pPermissionManager.State.DISABLED) {
+ // We're no longer disabled, just denied
+ mP2pPermissionManager.setState(P2pPermissionManager.State.DENIED);
+ }
+ mP2pPermissionManager.reset();
+ mP2pPermissionManager.request(true, approve -> updateP2pPreferences());
+ } else {
+ // User disabled P2P
+ mP2pPermissionManager.setState(P2pPermissionManager.State.DISABLED);
+ updateP2pPreferences();
+ }
+ return true;
+ });
}
@Override
@@ -104,13 +144,31 @@
updateSavedPrinters();
}
+ private void updateP2pPreferences() {
+ // Only allow the user to find new P2P printers when enabled
+ if (mP2pPermissionManager.isP2pEnabled()) {
+ mP2pEnablePreference.setChecked(true);
+ getPreferenceScreen().addPreference(mFindP2pPrintersPreference);
+ if (getActivity().getIntent().getBooleanExtra(EXTRA_FIX_P2P_PERMISSION, false)) {
+ // If we were only here to enable P2P permissions, go back to the print now.
+ getActivity().finish();
+ }
+ } else {
+ mP2pEnablePreference.setChecked(false);
+ getPreferenceScreen().removePreference(mFindP2pPrintersPreference);
+ }
+
+ updateSavedPrinters();
+ }
+
@Override
public void onServiceDisconnected(ComponentName componentName) {
mPrintService = null;
}
private void updateSavedPrinters() {
- int savedCount = mPrintService.getDiscovery().getSavedPrinters().size();
+ int savedCount = mPrintService == null ? 0 : mPrintService.getDiscovery()
+ .getSavedPrinters().size();
if (savedCount == 0) {
if (getPreferenceScreen().findPreference(mSavedPrintersCategory.getKey()) != null) {
@@ -124,7 +182,12 @@
mSavedPrintersCategory.removeAll();
// With the service enumerate all saved printers
+ boolean p2pEnabled = mP2pPermissionManager.isP2pEnabled();
for (DiscoveredPrinter printer : mPrintService.getDiscovery().getSavedPrinters()) {
+ // Don't show P2P printers while P2P is disabled.
+ if (P2pUtils.isP2p(printer) && !p2pEnabled) {
+ continue;
+ }
if (DEBUG) Log.d(TAG, "Adding saved printer " + printer);
PrinterPreference pref = new PrinterPreference(getContext(), mPrintService,
printer, false);
diff --git a/src/com/android/bips/ui/FindP2pPrintersFragment.java b/src/com/android/bips/ui/FindP2pPrintersFragment.java
index 6d8bb83..39b9495 100644
--- a/src/com/android/bips/ui/FindP2pPrintersFragment.java
+++ b/src/com/android/bips/ui/FindP2pPrintersFragment.java
@@ -16,12 +16,10 @@
package com.android.bips.ui;
-import android.Manifest;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
-import android.content.pm.PackageManager;
import android.net.Uri;
import android.net.wifi.p2p.WifiP2pDevice;
import android.os.Bundle;
@@ -41,13 +39,11 @@
/**
* Present a list of previously-saved printers, and allow them to be removed
*/
-public class FindP2pPrintersFragment extends PreferenceFragment implements ServiceConnection,
- AddPrintersActivity.OnPermissionChangeListener {
+public class FindP2pPrintersFragment extends PreferenceFragment implements ServiceConnection {
private static final String TAG = FindP2pPrintersFragment.class.getSimpleName();
private static final boolean DEBUG = false;
private static final String KEY_AVAILABLE = "available";
- private static final int REQUEST_PERMISSION = 1;
private BuiltInPrintService mPrintService;
private P2pListener mPeerDiscoveryListener;
@@ -90,37 +86,13 @@
return;
}
- // If we do not yet have permissions, ask.
- if (getContext().checkSelfPermission(Manifest.permission.ACCESS_COARSE_LOCATION)
- != PackageManager.PERMISSION_GRANTED) {
- getActivity().requestPermissions(
- new String[]{Manifest.permission.ACCESS_COARSE_LOCATION},
- REQUEST_PERMISSION);
- } else {
- startP2pDiscovery();
- }
- }
-
- private void startP2pDiscovery() {
- if (mPrintService != null && mPeerDiscoveryListener == null) {
+ if (mPeerDiscoveryListener == null) {
mPeerDiscoveryListener = new P2pListener();
mPrintService.getP2pMonitor().discover(mPeerDiscoveryListener);
}
}
@Override
- public void onPermissionChange() {
- // P2P discovery requires dangerous ACCESS_COARSE_LOCATION
- if (getContext().checkSelfPermission(Manifest.permission.ACCESS_COARSE_LOCATION)
- == PackageManager.PERMISSION_GRANTED) {
- startP2pDiscovery();
- } else {
- // Wind back out of this fragment
- getActivity().onBackPressed();
- }
- }
-
- @Override
public void onServiceDisconnected(ComponentName componentName) {
mPrintService = null;
}