| /* |
| * Copyright (C) 2016 The Android Open Source Project |
| * Copyright (C) 2016 Mopria Alliance, Inc. |
| * |
| * 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.ipp; |
| |
| import android.net.Uri; |
| import android.os.AsyncTask; |
| import android.util.Log; |
| |
| import com.android.bips.jni.BackendConstants; |
| import com.android.bips.jni.LocalPrinterCapabilities; |
| import com.android.bips.util.PriorityLock; |
| |
| import java.io.IOException; |
| import java.net.InetAddress; |
| import java.net.InetSocketAddress; |
| import java.net.Socket; |
| import java.net.UnknownHostException; |
| |
| /** A background task that queries a specific URI for its complete capabilities */ |
| public class GetCapabilitiesTask extends AsyncTask<Void, Void, LocalPrinterCapabilities> { |
| private static final String TAG = GetCapabilitiesTask.class.getSimpleName(); |
| private static final boolean DEBUG = false; |
| |
| /** Lock to ensure we don't issue multiple simultaneous capability requests */ |
| private static final PriorityLock sLock = new PriorityLock(); |
| |
| private final Backend mBackend; |
| private final Uri mUri; |
| private final long mTimeout; |
| private final boolean mPriority; |
| private volatile Socket mSocket; |
| |
| GetCapabilitiesTask(Backend backend, Uri uri, long timeout, boolean priority) { |
| mUri = uri; |
| mBackend = backend; |
| mTimeout = timeout; |
| mPriority = priority; |
| } |
| |
| private boolean isDeviceOnline(Uri uri) { |
| try (Socket socket = new Socket()) { |
| mSocket = socket; |
| InetSocketAddress a = new InetSocketAddress(uri.getHost(), uri.getPort()); |
| socket.connect(a, (int) mTimeout); |
| return true; |
| } catch (IOException e) { |
| return false; |
| } finally { |
| mSocket = null; |
| } |
| } |
| |
| /** Forcibly cancel this task, including stopping any socket that was opened */ |
| public void forceCancel() { |
| cancel(true); |
| Socket socket = mSocket; |
| if (socket != null) { |
| try { |
| socket.close(); |
| } catch (IOException e) { |
| // Ignored |
| } |
| } |
| } |
| |
| @Override |
| protected LocalPrinterCapabilities doInBackground(Void... dummy) { |
| long start = System.currentTimeMillis(); |
| |
| LocalPrinterCapabilities printerCaps = new LocalPrinterCapabilities(); |
| try { |
| printerCaps.inetAddress = InetAddress.getByName(mUri.getHost()); |
| } catch (UnknownHostException e) { |
| return null; |
| } |
| |
| boolean online = isDeviceOnline(mUri); |
| if (DEBUG) { |
| Log.d(TAG, "isDeviceOnline uri=" + mUri + " online=" + online |
| + " (" + (System.currentTimeMillis() - start) + "ms)"); |
| } |
| |
| if (!online || isCancelled()) { |
| return null; |
| } |
| |
| // Do not permit more than a single call to this API or crashes may result |
| try { |
| // Always allow priority capability requests to execute first |
| sLock.lock(mPriority ? 1 : 0); |
| } catch (InterruptedException e) { |
| return null; |
| } |
| int status = -1; |
| start = System.currentTimeMillis(); |
| try { |
| if (isCancelled()) { |
| return null; |
| } |
| status = mBackend.nativeGetCapabilities(Backend.getIp(mUri.getHost()), |
| mUri.getPort(), mUri.getPath(), mUri.getScheme(), mTimeout, printerCaps); |
| } finally { |
| sLock.unlock(); |
| } |
| |
| if (DEBUG) { |
| Log.d(TAG, "callNativeGetCapabilities uri=" + mUri + " status=" + status |
| + " (" + (System.currentTimeMillis() - start) + "ms)"); |
| } |
| |
| return status == BackendConstants.STATUS_OK ? printerCaps : null; |
| } |
| } |