1 /* 2 * Copyright (C) 2016 The Android Open Source Project 3 * Copyright (C) 2016 Mopria Alliance, Inc. 4 * 5 * Licensed under the Apache License, Version 2.0 (the "License"); 6 * you may not use this file except in compliance with the License. 7 * You may obtain a copy of the License at 8 * 9 * http://www.apache.org/licenses/LICENSE-2.0 10 * 11 * Unless required by applicable law or agreed to in writing, software 12 * distributed under the License is distributed on an "AS IS" BASIS, 13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 * See the License for the specific language governing permissions and 15 * limitations under the License. 16 */ 17 18 package com.android.bips; 19 20 import android.content.BroadcastReceiver; 21 import android.content.Context; 22 import android.content.pm.PackageInfo; 23 import android.content.pm.PackageManager; 24 import android.net.nsd.NsdManager; 25 import android.net.wifi.WifiManager; 26 import android.os.Handler; 27 import android.printservice.PrintJob; 28 import android.printservice.PrintService; 29 import android.printservice.PrinterDiscoverySession; 30 import android.text.TextUtils; 31 import android.util.Log; 32 33 import com.android.bips.discovery.DelayedDiscovery; 34 import com.android.bips.discovery.DiscoveredPrinter; 35 import com.android.bips.discovery.Discovery; 36 import com.android.bips.discovery.ManualDiscovery; 37 import com.android.bips.discovery.MdnsDiscovery; 38 import com.android.bips.discovery.MultiDiscovery; 39 import com.android.bips.discovery.NsdResolveQueue; 40 import com.android.bips.discovery.P2pDiscovery; 41 import com.android.bips.ipp.Backend; 42 import com.android.bips.ipp.CapabilitiesCache; 43 import com.android.bips.p2p.P2pMonitor; 44 import com.android.bips.p2p.P2pUtils; 45 import com.android.bips.util.BroadcastMonitor; 46 47 import java.lang.ref.WeakReference; 48 49 public class BuiltInPrintService extends PrintService { 50 private static final String TAG = BuiltInPrintService.class.getSimpleName(); 51 private static final boolean DEBUG = false; 52 private static final int IPPS_PRINTER_DELAY = 150; 53 private static final int P2P_DISCOVERY_DELAY = 1000; 54 55 // Present because local activities can bind, but cannot access this object directly 56 private static WeakReference<BuiltInPrintService> sInstance; 57 58 private MultiDiscovery mAllDiscovery; 59 private P2pDiscovery mP2pDiscovery; 60 private Discovery mMdnsDiscovery; 61 private ManualDiscovery mManualDiscovery; 62 private CapabilitiesCache mCapabilitiesCache; 63 private JobQueue mJobQueue; 64 private Handler mMainHandler; 65 private Backend mBackend; 66 private WifiManager.WifiLock mWifiLock; 67 private P2pMonitor mP2pMonitor; 68 private NsdResolveQueue mNsdResolveQueue; 69 70 /** 71 * Return the current print service instance, if running 72 */ 73 public static BuiltInPrintService getInstance() { 74 return sInstance == null ? null : sInstance.get(); 75 } 76 77 @Override 78 public void onCreate() { 79 if (DEBUG) { 80 try { 81 PackageInfo pInfo = getPackageManager().getPackageInfo(getPackageName(), 0); 82 String version = pInfo.versionName; 83 Log.d(TAG, "onCreate() " + version); 84 } catch (PackageManager.NameNotFoundException ignored) { 85 } 86 } 87 super.onCreate(); 88 89 sInstance = new WeakReference<>(this); 90 mBackend = new Backend(this); 91 mCapabilitiesCache = new CapabilitiesCache(this, mBackend, 92 CapabilitiesCache.DEFAULT_MAX_CONCURRENT); 93 mP2pMonitor = new P2pMonitor(this); 94 95 NsdManager nsdManager = (NsdManager) getSystemService(Context.NSD_SERVICE); 96 mNsdResolveQueue = new NsdResolveQueue(this, nsdManager); 97 98 // Delay IPP results so that IPP is preferred 99 Discovery ippDiscovery = new MdnsDiscovery(this, MdnsDiscovery.SCHEME_IPP); 100 Discovery ippsDiscovery = new MdnsDiscovery(this, MdnsDiscovery.SCHEME_IPPS); 101 mMdnsDiscovery = new MultiDiscovery(ippDiscovery, new DelayedDiscovery(ippsDiscovery, 0, 102 IPPS_PRINTER_DELAY)); 103 mP2pDiscovery = new P2pDiscovery(this); 104 mManualDiscovery = new ManualDiscovery(this); 105 106 // Delay P2P discovery so that all others are found first 107 mAllDiscovery = new MultiDiscovery(mMdnsDiscovery, mManualDiscovery, new DelayedDiscovery( 108 mP2pDiscovery, P2P_DISCOVERY_DELAY, 0)); 109 110 mJobQueue = new JobQueue(); 111 mMainHandler = new Handler(getMainLooper()); 112 WifiManager wifiManager = (WifiManager) getSystemService(Context.WIFI_SERVICE); 113 mWifiLock = wifiManager.createWifiLock(WifiManager.WIFI_MODE_FULL, TAG); 114 } 115 116 @Override 117 public void onDestroy() { 118 if (DEBUG) Log.d(TAG, "onDestroy()"); 119 mCapabilitiesCache.close(); 120 mP2pMonitor.stopAll(); 121 mBackend.close(); 122 unlockWifi(); 123 sInstance = null; 124 mMainHandler.removeCallbacksAndMessages(null); 125 super.onDestroy(); 126 } 127 128 @Override 129 protected PrinterDiscoverySession onCreatePrinterDiscoverySession() { 130 if (DEBUG) Log.d(TAG, "onCreatePrinterDiscoverySession"); 131 return new LocalDiscoverySession(this); 132 } 133 134 @Override 135 protected void onPrintJobQueued(PrintJob printJob) { 136 if (DEBUG) Log.d(TAG, "onPrintJobQueued"); 137 mJobQueue.print(new LocalPrintJob(this, mBackend, printJob)); 138 } 139 140 @Override 141 protected void onRequestCancelPrintJob(PrintJob printJob) { 142 if (DEBUG) Log.d(TAG, "onRequestCancelPrintJob"); 143 mJobQueue.cancel(printJob.getId()); 144 } 145 146 /** 147 * Return the global discovery object 148 */ 149 public Discovery getDiscovery() { 150 return mAllDiscovery; 151 } 152 153 /** 154 * Return the global object for MDNS discoveries 155 */ 156 public Discovery getMdnsDiscovery() { 157 return mMdnsDiscovery; 158 } 159 160 /** 161 * Return the global object for manual discoveries 162 */ 163 public ManualDiscovery getManualDiscovery() { 164 return mManualDiscovery; 165 } 166 167 /** 168 * Return the global object for Wi-Fi Direct printer discoveries 169 */ 170 public P2pDiscovery getP2pDiscovery() { 171 return mP2pDiscovery; 172 } 173 174 /** 175 * Return the global object for general Wi-Fi Direct management 176 */ 177 public P2pMonitor getP2pMonitor() { 178 return mP2pMonitor; 179 } 180 181 /** 182 * Return the global {@link NsdResolveQueue} 183 */ 184 public NsdResolveQueue getNsdResolveQueue() { 185 return mNsdResolveQueue; 186 } 187 188 /** 189 * Listen for a set of broadcast messages until stopped 190 */ 191 public BroadcastMonitor receiveBroadcasts(BroadcastReceiver receiver, String... actions) { 192 return new BroadcastMonitor(this, receiver, actions); 193 } 194 195 /** 196 * Return the global Printer Capabilities cache 197 */ 198 public CapabilitiesCache getCapabilitiesCache() { 199 return mCapabilitiesCache; 200 } 201 202 /** 203 * Return the main handler for posting {@link Runnable} objects to the main UI 204 */ 205 public Handler getMainHandler() { 206 return mMainHandler; 207 } 208 209 /** Run something on the main thread, returning an object that can cancel the request */ 210 public DelayedAction delay(int delay, Runnable toRun) { 211 mMainHandler.postDelayed(toRun, delay); 212 return () -> mMainHandler.removeCallbacks(toRun); 213 } 214 215 /** 216 * Return a friendly description string including host and (if present) location 217 */ 218 public String getDescription(DiscoveredPrinter printer) { 219 if (P2pUtils.isP2p(printer) || P2pUtils.isOnConnectedInterface(this, printer)) { 220 return getString(R.string.wifi_direct); 221 } 222 223 String host = printer.getHost(); 224 if (!TextUtils.isEmpty(printer.location)) { 225 return getString(R.string.printer_description, host, printer.location); 226 } else { 227 return host; 228 } 229 } 230 231 /** Prevent Wi-Fi from going to sleep until {@link #unlockWifi} is called */ 232 public void lockWifi() { 233 if (!mWifiLock.isHeld()) { 234 mWifiLock.acquire(); 235 } 236 } 237 238 /** Allow Wi-Fi to be disabled during sleep modes. */ 239 public void unlockWifi() { 240 if (mWifiLock.isHeld()) { 241 mWifiLock.release(); 242 } 243 } 244 } 245