Merge "Defer rotation update during recent transition" into tm-dev
diff --git a/core/java/android/view/IWindowManager.aidl b/core/java/android/view/IWindowManager.aidl
index 53b842a..f8a1b45 100644
--- a/core/java/android/view/IWindowManager.aidl
+++ b/core/java/android/view/IWindowManager.aidl
@@ -955,4 +955,10 @@
* @hide
*/
Bitmap snapshotTaskForRecents(int taskId);
+
+ /**
+ * Informs the system whether the recents app is currently behind the system bars. If so,
+ * means the recents app can control the SystemUI flags, and vice-versa.
+ */
+ void setRecentsAppBehindSystemBars(boolean behindSystemBars);
}
diff --git a/core/java/android/view/WindowManagerGlobal.java b/core/java/android/view/WindowManagerGlobal.java
index 93cb0dd7..2dc5fbd 100644
--- a/core/java/android/view/WindowManagerGlobal.java
+++ b/core/java/android/view/WindowManagerGlobal.java
@@ -752,6 +752,14 @@
public void removeWindowlessRoot(ViewRootImpl impl) {
synchronized (mLock) {
mWindowlessRoots.remove(impl);
+ }
+ }
+
+ public void setRecentsAppBehindSystemBars(boolean behindSystemBars) {
+ try {
+ getWindowManagerService().setRecentsAppBehindSystemBars(behindSystemBars);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
}
}
}
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 58a3bb4..73cdaba 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -1903,14 +1903,16 @@
to improve wifi performance.
<p>Not for use by third-party applications. -->
<permission android:name="android.permission.MANAGE_WIFI_AUTO_JOIN"
- android:protectionLevel="signature|privileged" />
+ android:protectionLevel="signature|privileged|knownSigner"
+ android:knownCerts="@array/wifi_known_signers" />
<!-- Allows applications to get notified when a Wi-Fi interface request cannot
be satisfied without tearing down one or more other interfaces, and provide a decision
whether to approve the request or reject it.
<p>Not for use by third-party applications. -->
<permission android:name="android.permission.MANAGE_WIFI_INTERFACES"
- android:protectionLevel="signature|privileged" />
+ android:protectionLevel="signature|privileged|knownSigner"
+ android:knownCerts="@array/wifi_known_signers" />
<!-- @SystemApi @hide Allows apps to create and manage IPsec tunnels.
<p>Only granted to applications that are currently bound by the
@@ -1948,7 +1950,8 @@
modifications.
<p>Not for use by third-party applications. -->
<permission android:name="android.permission.OVERRIDE_WIFI_CONFIG"
- android:protectionLevel="signature|privileged" />
+ android:protectionLevel="signature|privileged|knownSigner"
+ android:knownCerts="@array/wifi_known_signers" />
<!-- @deprecated Allows applications to act as network scorers. @hide @SystemApi-->
<permission android:name="android.permission.SCORE_NETWORKS"
diff --git a/core/res/res/values/arrays.xml b/core/res/res/values/arrays.xml
index 8f2d6c3..dff7751 100644
--- a/core/res/res/values/arrays.xml
+++ b/core/res/res/values/arrays.xml
@@ -185,6 +185,12 @@
<item>@string/app_info</item>
</string-array>
+ <!-- Certificate digests for trusted apps that will be allowed to obtain the knownSigner Wi-Fi
+ permissions. The digest should be computed over the DER encoding of the trusted certificate
+ using the SHA-256 digest algorithm. -->
+ <string-array name="wifi_known_signers">
+ </string-array>
+
<!-- Device-specific array of SIM slot indexes which are are embedded eUICCs.
e.g. If a device has two physical slots with indexes 0, 1, and slot 1 is an
eUICC, then the value of this array should be:
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index c2cb57d..4648f8a 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -4130,9 +4130,9 @@
This service must be trusted, as it can be activated without explicit consent of the user.
If no service with the specified name exists on the device, cloudsearch will be disabled.
Example: "com.android.intelligence/.CloudSearchService"
- config_defaultCloudSearchService is for the single provider case.
+ config_defaultCloudSearchServices is for the multiple provider case.
-->
- <string name="config_defaultCloudSearchService" translatable="false"></string>
+ <string-array name="config_defaultCloudSearchServices"></string-array>
<!-- The package name for the system's translation service.
This service must be trusted, as it can be activated without explicit consent of the user.
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index e543034..ffd1f125 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -3675,7 +3675,7 @@
<java-symbol type="string" name="notification_channel_network_status" />
<java-symbol type="string" name="notification_channel_network_alerts" />
<java-symbol type="string" name="notification_channel_network_available" />
- <java-symbol type="string" name="config_defaultCloudSearchService" />
+ <java-symbol type="array" name="config_defaultCloudSearchServices" />
<java-symbol type="string" name="notification_channel_vpn" />
<java-symbol type="string" name="notification_channel_device_admin" />
<java-symbol type="string" name="notification_channel_alerts" />
diff --git a/obex/Android.bp b/obex/Android.bp
index 37e7f76..d89d41d 100644
--- a/obex/Android.bp
+++ b/obex/Android.bp
@@ -44,6 +44,8 @@
],
}
+// No longer used. Only kept because the ObexPacket class is a public API.
+// The library has been migrated to platform/external/obex.
java_sdk_library {
name: "javax.obex",
srcs: ["javax/**/*.java"],
diff --git a/obex/javax/obex/ApplicationParameter.java b/obex/javax/obex/ApplicationParameter.java
deleted file mode 100644
index 16770a1a..0000000
--- a/obex/javax/obex/ApplicationParameter.java
+++ /dev/null
@@ -1,162 +0,0 @@
-/*
- * Copyright (c) 2008-2009, Motorola, Inc.
- *
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * - Redistributions of source code must retain the above copyright notice,
- * this list of conditions and the following disclaimer.
- *
- * - Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- *
- * - Neither the name of the Motorola, Inc. nor the names of its contributors
- * may be used to endorse or promote products derived from this software
- * without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
- * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
- * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
- * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
- * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGE.
- */
-
-package javax.obex;
-
-/**
- * @hide
- */
-public final class ApplicationParameter {
-
- private byte[] mArray;
-
- private int mLength;
-
- private int mMaxLength = 1000;
-
- public static class TRIPLET_TAGID {
- public static final byte ORDER_TAGID = 0x01;
-
- public static final byte SEARCH_VALUE_TAGID = 0x02;
-
- public static final byte SEARCH_ATTRIBUTE_TAGID = 0x03;
-
- // if equals to "0", PSE only reply number of contacts
- public static final byte MAXLISTCOUNT_TAGID = 0x04;
-
- public static final byte LISTSTARTOFFSET_TAGID = 0x05;
-
- public static final byte PROPERTY_SELECTOR_TAGID = 0x06;
-
- public static final byte FORMAT_TAGID = 0x07;
-
- // only used if max list count = 0
- public static final byte PHONEBOOKSIZE_TAGID = 0x08;
-
- // only used in "mch" in response
- public static final byte NEWMISSEDCALLS_TAGID = 0x09;
-
- public static final byte SUPPORTEDFEATURE_TAGID = 0x10;
-
- public static final byte PRIMARYVERSIONCOUNTER_TAGID = 0x0A;
-
- public static final byte SECONDARYVERSIONCOUNTER_TAGID = 0x0B;
-
- public static final byte VCARDSELECTOR_TAGID = 0x0C;
-
- public static final byte DATABASEIDENTIFIER_TAGID = 0x0D;
-
- public static final byte VCARDSELECTOROPERATOR_TAGID = 0x0E;
-
- public static final byte RESET_NEW_MISSED_CALLS_TAGID = 0x0F;
- }
-
- public static class TRIPLET_VALUE {
- public static class ORDER {
- public static final byte ORDER_BY_INDEX = 0x00;
-
- public static final byte ORDER_BY_ALPHANUMERIC = 0x01;
-
- public static final byte ORDER_BY_PHONETIC = 0x02;
- }
-
- public static class SEARCHATTRIBUTE {
- public static final byte SEARCH_BY_NAME = 0x00;
-
- public static final byte SEARCH_BY_NUMBER = 0x01;
-
- public static final byte SEARCH_BY_SOUND = 0x02;
- }
-
- public static class FORMAT {
- public static final byte VCARD_VERSION_21 = 0x00;
-
- public static final byte VCARD_VERSION_30 = 0x01;
- }
- }
-
- public static class TRIPLET_LENGTH {
- public static final byte ORDER_LENGTH = 1;
-
- public static final byte SEARCH_ATTRIBUTE_LENGTH = 1;
-
- public static final byte MAXLISTCOUNT_LENGTH = 2;
-
- public static final byte LISTSTARTOFFSET_LENGTH = 2;
-
- public static final byte PROPERTY_SELECTOR_LENGTH = 8;
-
- public static final byte FORMAT_LENGTH = 1;
-
- public static final byte PHONEBOOKSIZE_LENGTH = 2;
-
- public static final byte NEWMISSEDCALLS_LENGTH = 1;
-
- public static final byte SUPPORTEDFEATURE_LENGTH = 4;
-
- public static final byte PRIMARYVERSIONCOUNTER_LENGTH = 16;
-
- public static final byte SECONDARYVERSIONCOUNTER_LENGTH = 16;
-
- public static final byte VCARDSELECTOR_LENGTH = 8;
-
- public static final byte DATABASEIDENTIFIER_LENGTH = 16;
-
- public static final byte VCARDSELECTOROPERATOR_LENGTH = 1;
-
- public static final byte RESETNEWMISSEDCALLS_LENGTH = 1;
- }
-
- public ApplicationParameter() {
- mArray = new byte[mMaxLength];
- mLength = 0;
- }
-
- public void addAPPHeader(byte tag, byte len, byte[] value) {
- if ((mLength + len + 2) > mMaxLength) {
- byte[] array_tmp = new byte[mLength + 4 * len];
- System.arraycopy(mArray, 0, array_tmp, 0, mLength);
- mArray = array_tmp;
- mMaxLength = mLength + 4 * len;
- }
- mArray[mLength++] = tag;
- mArray[mLength++] = len;
- System.arraycopy(value, 0, mArray, mLength, len);
- mLength += len;
- }
-
- public byte[] getAPPparam() {
- byte[] para = new byte[mLength];
- System.arraycopy(mArray, 0, para, 0, mLength);
- return para;
- }
-}
diff --git a/obex/javax/obex/Authenticator.java b/obex/javax/obex/Authenticator.java
deleted file mode 100644
index ec226fb..0000000
--- a/obex/javax/obex/Authenticator.java
+++ /dev/null
@@ -1,115 +0,0 @@
-/*
- * Copyright (c) 2008-2009, Motorola, Inc.
- *
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * - Redistributions of source code must retain the above copyright notice,
- * this list of conditions and the following disclaimer.
- *
- * - Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- *
- * - Neither the name of the Motorola, Inc. nor the names of its contributors
- * may be used to endorse or promote products derived from this software
- * without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
- * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
- * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
- * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
- * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGE.
- */
-
-package javax.obex;
-
-/**
- * This interface provides a way to respond to authentication challenge and
- * authentication response headers. When a client or server receives an
- * authentication challenge or authentication response header, the
- * <code>onAuthenticationChallenge()</code> or
- * <code>onAuthenticationResponse()</code> will be called, respectively, by the
- * implementation.
- * <P>
- * For more information on how the authentication procedure works in OBEX,
- * please review the IrOBEX specification at <A
- * HREF="http://www.irda.org">http://www.irda.org</A>.
- * <P>
- * <STRONG>Authentication Challenges</STRONG>
- * <P>
- * When a client or server receives an authentication challenge header, the
- * <code>onAuthenticationChallenge()</code> method will be invoked by the OBEX
- * API implementation. The application will then return the user name (if
- * needed) and password via a <code>PasswordAuthentication</code> object. The
- * password in this object is not sent in the authentication response. Instead,
- * the 16-byte challenge received in the authentication challenge is combined
- * with the password returned from the <code>onAuthenticationChallenge()</code>
- * method and passed through the MD5 hash algorithm. The resulting value is sent
- * in the authentication response along with the user name if it was provided.
- * <P>
- * <STRONG>Authentication Responses</STRONG>
- * <P>
- * When a client or server receives an authentication response header, the
- * <code>onAuthenticationResponse()</code> method is invoked by the API
- * implementation with the user name received in the authentication response
- * header. (The user name will be <code>null</code> if no user name was provided
- * in the authentication response header.) The application must determine the
- * correct password. This value should be returned from the
- * <code>onAuthenticationResponse()</code> method. If the authentication request
- * should fail without the implementation checking the password,
- * <code>null</code> should be returned by the application. (This is needed for
- * reasons like not recognizing the user name, etc.) If the returned value is
- * not <code>null</code>, the OBEX API implementation will combine the password
- * returned from the <code>onAuthenticationResponse()</code> method and
- * challenge sent via the authentication challenge, apply the MD5 hash
- * algorithm, and compare the result to the response hash received in the
- * authentication response header. If the values are not equal, an
- * <code>IOException</code> will be thrown if the client requested
- * authentication. If the server requested authentication, the
- * <code>onAuthenticationFailure()</code> method will be called on the
- * <code>ServerRequestHandler</code> that failed authentication. The connection
- * is <B>not</B> closed if authentication failed.
- * @hide
- */
-public interface Authenticator {
-
- /**
- * Called when a client or a server receives an authentication challenge
- * header. It should respond to the challenge with a
- * <code>PasswordAuthentication</code> that contains the correct user name
- * and password for the challenge.
- * @param description the description of which user name and password should
- * be used; if no description is provided in the authentication
- * challenge or the description is encoded in an encoding scheme that
- * is not supported, an empty string will be provided
- * @param isUserIdRequired <code>true</code> if the user ID is required;
- * <code>false</code> if the user ID is not required
- * @param isFullAccess <code>true</code> if full access to the server will
- * be granted; <code>false</code> if read only access will be granted
- * @return a <code>PasswordAuthentication</code> object containing the user
- * name and password used for authentication
- */
- PasswordAuthentication onAuthenticationChallenge(String description, boolean isUserIdRequired,
- boolean isFullAccess);
-
- /**
- * Called when a client or server receives an authentication response
- * header. This method will provide the user name and expect the correct
- * password to be returned.
- * @param userName the user name provided in the authentication response; may
- * be <code>null</code>
- * @return the correct password for the user name provided; if
- * <code>null</code> is returned then the authentication request
- * failed
- */
- byte[] onAuthenticationResponse(byte[] userName);
-}
diff --git a/obex/javax/obex/BaseStream.java b/obex/javax/obex/BaseStream.java
deleted file mode 100644
index 022ad4f..0000000
--- a/obex/javax/obex/BaseStream.java
+++ /dev/null
@@ -1,76 +0,0 @@
-/*
- * Copyright (c) 2008-2009, Motorola, Inc.
- *
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * - Redistributions of source code must retain the above copyright notice,
- * this list of conditions and the following disclaimer.
- *
- * - Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- *
- * - Neither the name of the Motorola, Inc. nor the names of its contributors
- * may be used to endorse or promote products derived from this software
- * without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
- * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
- * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
- * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
- * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGE.
- */
-
-package javax.obex;
-
-import java.io.IOException;
-
-/**
- * This interface defines the methods needed by a parent that uses the
- * PrivateInputStream and PrivateOutputStream objects defined in this package.
- * @hide
- */
-public interface BaseStream {
-
- /**
- * Verifies that this object is still open.
- * @throws IOException if the object is closed
- */
- void ensureOpen() throws IOException;
-
- /**
- * Verifies that additional information may be sent. In other words, the
- * operation is not done.
- * @throws IOException if the operation is completed
- */
- void ensureNotDone() throws IOException;
-
- /**
- * Continues the operation since there is no data to read.
- * @param sendEmpty <code>true</code> if the operation should send an empty
- * packet or not send anything if there is no data to send
- * @param inStream <code>true</code> if the stream is input stream or is
- * output stream
- * @return <code>true</code> if the operation was completed;
- * <code>false</code> if no operation took place
- * @throws IOException if an IO error occurs
- */
- boolean continueOperation(boolean sendEmpty, boolean inStream) throws IOException;
-
- /**
- * Called when the output or input stream is closed.
- * @param inStream <code>true</code> if the input stream is closed;
- * <code>false</code> if the output stream is closed
- * @throws IOException if an IO error occurs
- */
- void streamClosed(boolean inStream) throws IOException;
-}
diff --git a/obex/javax/obex/ClientOperation.java b/obex/javax/obex/ClientOperation.java
deleted file mode 100644
index c627dfb..0000000
--- a/obex/javax/obex/ClientOperation.java
+++ /dev/null
@@ -1,851 +0,0 @@
-/*
- * Copyright (c) 2015 The Android Open Source Project
- * Copyright (C) 2015 Samsung LSI
- * Copyright (c) 2008-2009, Motorola, Inc.
- *
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * - Redistributions of source code must retain the above copyright notice,
- * this list of conditions and the following disclaimer.
- *
- * - Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- *
- * - Neither the name of the Motorola, Inc. nor the names of its contributors
- * may be used to endorse or promote products derived from this software
- * without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
- * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
- * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
- * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
- * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGE.
- */
-
-package javax.obex;
-
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
-import java.io.DataInputStream;
-import java.io.DataOutputStream;
-import java.io.ByteArrayOutputStream;
-
-import android.util.Log;
-
-/**
- * This class implements the <code>Operation</code> interface. It will read and
- * write data via puts and gets.
- * @hide
- */
-public final class ClientOperation implements Operation, BaseStream {
-
- private static final String TAG = "ClientOperation";
-
- private static final boolean V = ObexHelper.VDBG;
-
- private ClientSession mParent;
-
- private boolean mInputOpen;
-
- private PrivateInputStream mPrivateInput;
-
- private boolean mPrivateInputOpen;
-
- private PrivateOutputStream mPrivateOutput;
-
- private boolean mPrivateOutputOpen;
-
- private String mExceptionMessage;
-
- private int mMaxPacketSize;
-
- private boolean mOperationDone;
-
- private boolean mGetOperation;
-
- private boolean mGetFinalFlag;
-
- private HeaderSet mRequestHeader;
-
- private HeaderSet mReplyHeader;
-
- private boolean mEndOfBodySent;
-
- private boolean mSendBodyHeader = true;
- // A latch - when triggered, there is not way back ;-)
- private boolean mSrmActive = false;
-
- // Assume SRM disabled - until support is confirmed
- // by the server
- private boolean mSrmEnabled = false;
- // keep waiting until final-bit is received in request
- // to handle the case where the SRM enable header is in
- // a different OBEX packet than the SRMP header.
- private boolean mSrmWaitingForRemote = true;
-
-
- /**
- * Creates new OperationImpl to read and write data to a server
- * @param maxSize the maximum packet size
- * @param p the parent to this object
- * @param type <code>true</code> if this is a get request;
- * <code>false</code. if this is a put request
- * @param header the header to set in the initial request
- * @throws IOException if the an IO error occurred
- */
- public ClientOperation(int maxSize, ClientSession p, HeaderSet header, boolean type)
- throws IOException {
-
- mParent = p;
- mEndOfBodySent = false;
- mInputOpen = true;
- mOperationDone = false;
- mMaxPacketSize = maxSize;
- mGetOperation = type;
- mGetFinalFlag = false;
-
- mPrivateInputOpen = false;
- mPrivateOutputOpen = false;
- mPrivateInput = null;
- mPrivateOutput = null;
-
- mReplyHeader = new HeaderSet();
-
- mRequestHeader = new HeaderSet();
-
- int[] headerList = header.getHeaderList();
-
- if (headerList != null) {
-
- for (int i = 0; i < headerList.length; i++) {
- mRequestHeader.setHeader(headerList[i], header.getHeader(headerList[i]));
- }
- }
-
- if ((header).mAuthChall != null) {
- mRequestHeader.mAuthChall = new byte[(header).mAuthChall.length];
- System.arraycopy((header).mAuthChall, 0, mRequestHeader.mAuthChall, 0,
- (header).mAuthChall.length);
- }
-
- if ((header).mAuthResp != null) {
- mRequestHeader.mAuthResp = new byte[(header).mAuthResp.length];
- System.arraycopy((header).mAuthResp, 0, mRequestHeader.mAuthResp, 0,
- (header).mAuthResp.length);
-
- }
-
- if ((header).mConnectionID != null) {
- mRequestHeader.mConnectionID = new byte[4];
- System.arraycopy((header).mConnectionID, 0, mRequestHeader.mConnectionID, 0,
- 4);
-
- }
- }
-
- /**
- * Allows to set flag which will force GET to be always sent as single packet request with
- * final flag set. This is to improve compatibility with some profiles, i.e. PBAP which
- * require requests to be sent this way.
- */
- public void setGetFinalFlag(boolean flag) {
- mGetFinalFlag = flag;
- }
-
- /**
- * Sends an ABORT message to the server. By calling this method, the
- * corresponding input and output streams will be closed along with this
- * object.
- * @throws IOException if the transaction has already ended or if an OBEX
- * server called this method
- */
- public synchronized void abort() throws IOException {
- ensureOpen();
- //no compatible with sun-ri
- if ((mOperationDone) && (mReplyHeader.responseCode != ResponseCodes.OBEX_HTTP_CONTINUE)) {
- throw new IOException("Operation has already ended");
- }
-
- mExceptionMessage = "Operation aborted";
- if ((!mOperationDone) && (mReplyHeader.responseCode == ResponseCodes.OBEX_HTTP_CONTINUE)) {
- mOperationDone = true;
- /*
- * Since we are not sending any headers or returning any headers then
- * we just need to write and read the same bytes
- */
- mParent.sendRequest(ObexHelper.OBEX_OPCODE_ABORT, null, mReplyHeader, null, false);
-
- if (mReplyHeader.responseCode != ResponseCodes.OBEX_HTTP_OK) {
- throw new IOException("Invalid response code from server");
- }
-
- mExceptionMessage = null;
- }
-
- close();
- }
-
- /**
- * Retrieves the response code retrieved from the server. Response codes are
- * defined in the <code>ResponseCodes</code> interface.
- * @return the response code retrieved from the server
- * @throws IOException if an error occurred in the transport layer during
- * the transaction; if this method is called on a
- * <code>HeaderSet</code> object created by calling
- * <code>createHeaderSet</code> in a <code>ClientSession</code>
- * object
- */
- public synchronized int getResponseCode() throws IOException {
- if ((mReplyHeader.responseCode == -1)
- || (mReplyHeader.responseCode == ResponseCodes.OBEX_HTTP_CONTINUE)) {
- validateConnection();
- }
-
- return mReplyHeader.responseCode;
- }
-
- /**
- * This method will always return <code>null</code>
- * @return <code>null</code>
- */
- public String getEncoding() {
- return null;
- }
-
- /**
- * Returns the type of content that the resource connected to is providing.
- * E.g. if the connection is via HTTP, then the value of the content-type
- * header field is returned.
- * @return the content type of the resource that the URL references, or
- * <code>null</code> if not known
- */
- public String getType() {
- try {
- return (String)mReplyHeader.getHeader(HeaderSet.TYPE);
- } catch (IOException e) {
- if(V) Log.d(TAG, "Exception occured - returning null",e);
- return null;
- }
- }
-
- /**
- * Returns the length of the content which is being provided. E.g. if the
- * connection is via HTTP, then the value of the content-length header field
- * is returned.
- * @return the content length of the resource that this connection's URL
- * references, or -1 if the content length is not known
- */
- public long getLength() {
- try {
- Long temp = (Long)mReplyHeader.getHeader(HeaderSet.LENGTH);
-
- if (temp == null) {
- return -1;
- } else {
- return temp.longValue();
- }
- } catch (IOException e) {
- if(V) Log.d(TAG,"Exception occured - returning -1",e);
- return -1;
- }
- }
-
- /**
- * Open and return an input stream for a connection.
- * @return an input stream
- * @throws IOException if an I/O error occurs
- */
- public InputStream openInputStream() throws IOException {
-
- ensureOpen();
-
- if (mPrivateInputOpen)
- throw new IOException("no more input streams available");
- if (mGetOperation) {
- // send the GET request here
- validateConnection();
- } else {
- if (mPrivateInput == null) {
- mPrivateInput = new PrivateInputStream(this);
- }
- }
-
- mPrivateInputOpen = true;
-
- return mPrivateInput;
- }
-
- /**
- * Open and return a data input stream for a connection.
- * @return an input stream
- * @throws IOException if an I/O error occurs
- */
- public DataInputStream openDataInputStream() throws IOException {
- return new DataInputStream(openInputStream());
- }
-
- /**
- * Open and return an output stream for a connection.
- * @return an output stream
- * @throws IOException if an I/O error occurs
- */
- public OutputStream openOutputStream() throws IOException {
-
- ensureOpen();
- ensureNotDone();
-
- if (mPrivateOutputOpen)
- throw new IOException("no more output streams available");
-
- if (mPrivateOutput == null) {
- // there are 3 bytes operation headers and 3 bytes body headers //
- mPrivateOutput = new PrivateOutputStream(this, getMaxPacketSize());
- }
-
- mPrivateOutputOpen = true;
-
- return mPrivateOutput;
- }
-
- public int getMaxPacketSize() {
- return mMaxPacketSize - 6 - getHeaderLength();
- }
-
- public int getHeaderLength() {
- // OPP may need it
- byte[] headerArray = ObexHelper.createHeader(mRequestHeader, false);
- return headerArray.length;
- }
-
- /**
- * Open and return a data output stream for a connection.
- * @return an output stream
- * @throws IOException if an I/O error occurs
- */
- public DataOutputStream openDataOutputStream() throws IOException {
- return new DataOutputStream(openOutputStream());
- }
-
- /**
- * Closes the connection and ends the transaction
- * @throws IOException if the operation has already ended or is closed
- */
- public void close() throws IOException {
- mInputOpen = false;
- mPrivateInputOpen = false;
- mPrivateOutputOpen = false;
- mParent.setRequestInactive();
- }
-
- /**
- * Returns the headers that have been received during the operation.
- * Modifying the object returned has no effect on the headers that are sent
- * or retrieved.
- * @return the headers received during this <code>Operation</code>
- * @throws IOException if this <code>Operation</code> has been closed
- */
- public HeaderSet getReceivedHeader() throws IOException {
- ensureOpen();
-
- return mReplyHeader;
- }
-
- /**
- * Specifies the headers that should be sent in the next OBEX message that
- * is sent.
- * @param headers the headers to send in the next message
- * @throws IOException if this <code>Operation</code> has been closed or the
- * transaction has ended and no further messages will be exchanged
- * @throws IllegalArgumentException if <code>headers</code> was not created
- * by a call to <code>ServerRequestHandler.createHeaderSet()</code>
- * @throws NullPointerException if <code>headers</code> is <code>null</code>
- */
- public void sendHeaders(HeaderSet headers) throws IOException {
- ensureOpen();
- if (mOperationDone) {
- throw new IOException("Operation has already exchanged all data");
- }
-
- if (headers == null) {
- throw new IOException("Headers may not be null");
- }
-
- int[] headerList = headers.getHeaderList();
- if (headerList != null) {
- for (int i = 0; i < headerList.length; i++) {
- mRequestHeader.setHeader(headerList[i], headers.getHeader(headerList[i]));
- }
- }
- }
-
- /**
- * Verifies that additional information may be sent. In other words, the
- * operation is not done.
- * @throws IOException if the operation is completed
- */
- public void ensureNotDone() throws IOException {
- if (mOperationDone) {
- throw new IOException("Operation has completed");
- }
- }
-
- /**
- * Verifies that the connection is open and no exceptions should be thrown.
- * @throws IOException if an exception needs to be thrown
- */
- public void ensureOpen() throws IOException {
- mParent.ensureOpen();
-
- if (mExceptionMessage != null) {
- throw new IOException(mExceptionMessage);
- }
- if (!mInputOpen) {
- throw new IOException("Operation has already ended");
- }
- }
-
- /**
- * Verifies that the connection is open and the proper data has been read.
- * @throws IOException if an IO error occurs
- */
- private void validateConnection() throws IOException {
- ensureOpen();
-
- // Make sure that a response has been recieved from remote
- // before continuing
- if (mPrivateInput == null || mReplyHeader.responseCode == -1) {
- startProcessing();
- }
- }
-
- /**
- * Sends a request to the client of the specified type.
- * This function will enable SRM and set SRM active if the server
- * response allows this.
- * @param opCode the request code to send to the client
- * @return <code>true</code> if there is more data to send;
- * <code>false</code> if there is no more data to send
- * @throws IOException if an IO error occurs
- */
- private boolean sendRequest(int opCode) throws IOException {
- boolean returnValue = false;
- ByteArrayOutputStream out = new ByteArrayOutputStream();
- int bodyLength = -1;
- byte[] headerArray = ObexHelper.createHeader(mRequestHeader, true);
- if (mPrivateOutput != null) {
- bodyLength = mPrivateOutput.size();
- }
-
- /*
- * Determine if there is space to add a body request. At present
- * this method checks to see if there is room for at least a 17
- * byte body header. This number needs to be at least 6 so that
- * there is room for the header ID and length and the reply ID and
- * length, but it is a waste of resources if we can't send much of
- * the body.
- */
- final int MINIMUM_BODY_LENGTH = 3;
- if ((ObexHelper.BASE_PACKET_LENGTH + headerArray.length + MINIMUM_BODY_LENGTH)
- > mMaxPacketSize) {
- int end = 0;
- int start = 0;
- // split & send the headerArray in multiple packets.
-
- while (end != headerArray.length) {
- //split the headerArray
-
- end = ObexHelper.findHeaderEnd(headerArray, start, mMaxPacketSize
- - ObexHelper.BASE_PACKET_LENGTH);
- // can not split
- if (end == -1) {
- mOperationDone = true;
- abort();
- mExceptionMessage = "Header larger then can be sent in a packet";
- mInputOpen = false;
-
- if (mPrivateInput != null) {
- mPrivateInput.close();
- }
-
- if (mPrivateOutput != null) {
- mPrivateOutput.close();
- }
- throw new IOException("OBEX Packet exceeds max packet size");
- }
-
- byte[] sendHeader = new byte[end - start];
- System.arraycopy(headerArray, start, sendHeader, 0, sendHeader.length);
- if (!mParent.sendRequest(opCode, sendHeader, mReplyHeader, mPrivateInput, false)) {
- return false;
- }
-
- if (mReplyHeader.responseCode != ResponseCodes.OBEX_HTTP_CONTINUE) {
- return false;
- }
-
- start = end;
- }
-
- // Enable SRM if it should be enabled
- checkForSrm();
-
- if (bodyLength > 0) {
- return true;
- } else {
- return false;
- }
- } else {
- /* All headers will fit into a single package */
- if(mSendBodyHeader == false) {
- /* As we are not to send any body data, set the FINAL_BIT */
- opCode |= ObexHelper.OBEX_OPCODE_FINAL_BIT_MASK;
- }
- out.write(headerArray);
- }
-
- if (bodyLength > 0) {
- /*
- * Determine if we can send the whole body or just part of
- * the body. Remember that there is the 3 bytes for the
- * response message and 3 bytes for the header ID and length
- */
- if (bodyLength > (mMaxPacketSize - headerArray.length - 6)) {
- returnValue = true;
-
- bodyLength = mMaxPacketSize - headerArray.length - 6;
- }
-
- byte[] body = mPrivateOutput.readBytes(bodyLength);
-
- /*
- * Since this is a put request if the final bit is set or
- * the output stream is closed we need to send the 0x49
- * (End of Body) otherwise, we need to send 0x48 (Body)
- */
- if ((mPrivateOutput.isClosed()) && (!returnValue) && (!mEndOfBodySent)
- && ((opCode & ObexHelper.OBEX_OPCODE_FINAL_BIT_MASK) != 0)) {
- out.write(HeaderSet.END_OF_BODY);
- mEndOfBodySent = true;
- } else {
- out.write(HeaderSet.BODY);
- }
-
- bodyLength += 3;
- out.write((byte)(bodyLength >> 8));
- out.write((byte)bodyLength);
-
- if (body != null) {
- out.write(body);
- }
- }
-
- if (mPrivateOutputOpen && bodyLength <= 0 && !mEndOfBodySent) {
- // only 0x82 or 0x83 can send 0x49
- if ((opCode & ObexHelper.OBEX_OPCODE_FINAL_BIT_MASK) == 0) {
- out.write(HeaderSet.BODY);
- } else {
- out.write(HeaderSet.END_OF_BODY);
- mEndOfBodySent = true;
- }
-
- bodyLength = 3;
- out.write((byte)(bodyLength >> 8));
- out.write((byte)bodyLength);
- }
-
- if (out.size() == 0) {
- if (!mParent.sendRequest(opCode, null, mReplyHeader, mPrivateInput, mSrmActive)) {
- return false;
- }
- // Enable SRM if it should be enabled
- checkForSrm();
- return returnValue;
- }
- if ((out.size() > 0)
- && (!mParent.sendRequest(opCode, out.toByteArray(),
- mReplyHeader, mPrivateInput, mSrmActive))) {
- return false;
- }
- // Enable SRM if it should be enabled
- checkForSrm();
-
- // send all of the output data in 0x48,
- // send 0x49 with empty body
- if ((mPrivateOutput != null) && (mPrivateOutput.size() > 0))
- returnValue = true;
-
- return returnValue;
- }
-
- private void checkForSrm() throws IOException {
- Byte srmMode = (Byte)mReplyHeader.getHeader(HeaderSet.SINGLE_RESPONSE_MODE);
- if(mParent.isSrmSupported() == true && srmMode != null
- && srmMode == ObexHelper.OBEX_SRM_ENABLE) {
- mSrmEnabled = true;
- }
- /**
- * Call this only when a complete obex packet have been received.
- * (This is not optimal, but the current design is not really suited to
- * the way SRM is specified.)
- * The BT usage of SRM is not really safe - it assumes that the SRMP will fit
- * into every OBEX packet, hence if another header occupies the entire packet,
- * the scheme will not work - unlikely though.
- */
- if(mSrmEnabled) {
- mSrmWaitingForRemote = false;
- Byte srmp = (Byte)mReplyHeader.getHeader(HeaderSet.SINGLE_RESPONSE_MODE_PARAMETER);
- if(srmp != null && srmp == ObexHelper.OBEX_SRMP_WAIT) {
- mSrmWaitingForRemote = true;
- // Clear the wait header, as the absence of the header in the next packet
- // indicates don't wait anymore.
- mReplyHeader.setHeader(HeaderSet.SINGLE_RESPONSE_MODE_PARAMETER, null);
- }
- }
- if((mSrmWaitingForRemote == false) && (mSrmEnabled == true)) {
- mSrmActive = true;
- }
- }
-
- /**
- * This method starts the processing thread results. It will send the
- * initial request. If the response takes more then one packet, a thread
- * will be started to handle additional requests
- * @throws IOException if an IO error occurs
- */
- private synchronized void startProcessing() throws IOException {
-
- if (mPrivateInput == null) {
- mPrivateInput = new PrivateInputStream(this);
- }
- boolean more = true;
-
- if (mGetOperation) {
- if (!mOperationDone) {
- if (!mGetFinalFlag) {
- mReplyHeader.responseCode = ResponseCodes.OBEX_HTTP_CONTINUE;
- while ((more) && (mReplyHeader.responseCode ==
- ResponseCodes.OBEX_HTTP_CONTINUE)) {
- more = sendRequest(ObexHelper.OBEX_OPCODE_GET);
- }
- // For GET we need to loop until all headers have been sent,
- // And then we wait for the first continue package with the
- // reply.
- if (mReplyHeader.responseCode == ResponseCodes.OBEX_HTTP_CONTINUE) {
- mParent.sendRequest(ObexHelper.OBEX_OPCODE_GET_FINAL,
- null, mReplyHeader, mPrivateInput, mSrmActive);
- }
- if (mReplyHeader.responseCode != ResponseCodes.OBEX_HTTP_CONTINUE) {
- mOperationDone = true;
- } else {
- checkForSrm();
- }
- } else {
- more = sendRequest(ObexHelper.OBEX_OPCODE_GET_FINAL);
-
- if (more) {
- throw new IOException("FINAL_GET forced, data didn't fit into one packet");
- }
-
- mOperationDone = true;
- }
- }
- } else {
- // PUT operation
- if (!mOperationDone) {
- mReplyHeader.responseCode = ResponseCodes.OBEX_HTTP_CONTINUE;
- while ((more) && (mReplyHeader.responseCode == ResponseCodes.OBEX_HTTP_CONTINUE)) {
- more = sendRequest(ObexHelper.OBEX_OPCODE_PUT);
- }
- }
-
- if (mReplyHeader.responseCode == ResponseCodes.OBEX_HTTP_CONTINUE) {
- mParent.sendRequest(ObexHelper.OBEX_OPCODE_PUT_FINAL,
- null, mReplyHeader, mPrivateInput, mSrmActive);
- }
-
- if (mReplyHeader.responseCode != ResponseCodes.OBEX_HTTP_CONTINUE) {
- mOperationDone = true;
- }
- }
- }
-
- /**
- * Continues the operation since there is no data to read.
- * @param sendEmpty <code>true</code> if the operation should send an empty
- * packet or not send anything if there is no data to send
- * @param inStream <code>true</code> if the stream is input stream or is
- * output stream
- * @throws IOException if an IO error occurs
- */
- public synchronized boolean continueOperation(boolean sendEmpty, boolean inStream)
- throws IOException {
-
- // One path to the first put operation - the other one does not need to
- // handle SRM, as all will fit into one packet.
-
- if (mGetOperation) {
- if ((inStream) && (!mOperationDone)) {
- // to deal with inputstream in get operation
- mParent.sendRequest(ObexHelper.OBEX_OPCODE_GET_FINAL,
- null, mReplyHeader, mPrivateInput, mSrmActive);
- /*
- * Determine if that was not the last packet in the operation
- */
- if (mReplyHeader.responseCode != ResponseCodes.OBEX_HTTP_CONTINUE) {
- mOperationDone = true;
- } else {
- checkForSrm();
- }
-
- return true;
-
- } else if ((!inStream) && (!mOperationDone)) {
- // to deal with outputstream in get operation
-
- if (mPrivateInput == null) {
- mPrivateInput = new PrivateInputStream(this);
- }
-
- if (!mGetFinalFlag) {
- sendRequest(ObexHelper.OBEX_OPCODE_GET);
- } else {
- sendRequest(ObexHelper.OBEX_OPCODE_GET_FINAL);
- }
- if (mReplyHeader.responseCode != ResponseCodes.OBEX_HTTP_CONTINUE) {
- mOperationDone = true;
- }
- return true;
-
- } else if (mOperationDone) {
- return false;
- }
-
- } else {
- // PUT operation
- if ((!inStream) && (!mOperationDone)) {
- // to deal with outputstream in put operation
- if (mReplyHeader.responseCode == -1) {
- mReplyHeader.responseCode = ResponseCodes.OBEX_HTTP_CONTINUE;
- }
- sendRequest(ObexHelper.OBEX_OPCODE_PUT);
- return true;
- } else if ((inStream) && (!mOperationDone)) {
- // How to deal with inputstream in put operation ?
- return false;
-
- } else if (mOperationDone) {
- return false;
- }
-
- }
- return false;
- }
-
- /**
- * Called when the output or input stream is closed.
- * @param inStream <code>true</code> if the input stream is closed;
- * <code>false</code> if the output stream is closed
- * @throws IOException if an IO error occurs
- */
- public void streamClosed(boolean inStream) throws IOException {
- if (!mGetOperation) {
- if ((!inStream) && (!mOperationDone)) {
- // to deal with outputstream in put operation
-
- boolean more = true;
-
- if ((mPrivateOutput != null) && (mPrivateOutput.size() <= 0)) {
- byte[] headerArray = ObexHelper.createHeader(mRequestHeader, false);
- if (headerArray.length <= 0)
- more = false;
- }
- // If have not sent any data so send all now
- if (mReplyHeader.responseCode == -1) {
- mReplyHeader.responseCode = ResponseCodes.OBEX_HTTP_CONTINUE;
- }
-
- while ((more) && (mReplyHeader.responseCode == ResponseCodes.OBEX_HTTP_CONTINUE)) {
- more = sendRequest(ObexHelper.OBEX_OPCODE_PUT);
- }
-
- /*
- * According to the IrOBEX specification, after the final put, you
- * only have a single reply to send. so we don't need the while
- * loop.
- */
- while (mReplyHeader.responseCode == ResponseCodes.OBEX_HTTP_CONTINUE) {
-
- sendRequest(ObexHelper.OBEX_OPCODE_PUT_FINAL);
- }
- mOperationDone = true;
- } else if ((inStream) && (mOperationDone)) {
- // how to deal with input stream in put stream ?
- mOperationDone = true;
- }
- } else {
- if ((inStream) && (!mOperationDone)) {
-
- // to deal with inputstream in get operation
- // Have not sent any data so send it all now
-
- if (mReplyHeader.responseCode == -1) {
- mReplyHeader.responseCode = ResponseCodes.OBEX_HTTP_CONTINUE;
- }
-
- while (mReplyHeader.responseCode == ResponseCodes.OBEX_HTTP_CONTINUE && !mOperationDone) {
- if (!sendRequest(ObexHelper.OBEX_OPCODE_GET_FINAL)) {
- break;
- }
- }
- while (mReplyHeader.responseCode == ResponseCodes.OBEX_HTTP_CONTINUE && !mOperationDone) {
- mParent.sendRequest(ObexHelper.OBEX_OPCODE_GET_FINAL, null,
- mReplyHeader, mPrivateInput, false);
- // Regardless of the SRM state, wait for the response.
- }
- mOperationDone = true;
- } else if ((!inStream) && (!mOperationDone)) {
- // to deal with outputstream in get operation
- // part of the data may have been sent in continueOperation.
-
- boolean more = true;
-
- if ((mPrivateOutput != null) && (mPrivateOutput.size() <= 0)) {
- byte[] headerArray = ObexHelper.createHeader(mRequestHeader, false);
- if (headerArray.length <= 0)
- more = false;
- }
-
- if (mPrivateInput == null) {
- mPrivateInput = new PrivateInputStream(this);
- }
- if ((mPrivateOutput != null) && (mPrivateOutput.size() <= 0))
- more = false;
-
- mReplyHeader.responseCode = ResponseCodes.OBEX_HTTP_CONTINUE;
- while ((more) && (mReplyHeader.responseCode == ResponseCodes.OBEX_HTTP_CONTINUE)) {
- more = sendRequest(ObexHelper.OBEX_OPCODE_GET);
- }
- sendRequest(ObexHelper.OBEX_OPCODE_GET_FINAL);
- // parent.sendRequest(0x83, null, replyHeaders, privateInput);
- if (mReplyHeader.responseCode != ResponseCodes.OBEX_HTTP_CONTINUE) {
- mOperationDone = true;
- }
- }
- }
- }
-
- public void noBodyHeader(){
- mSendBodyHeader = false;
- }
-}
diff --git a/obex/javax/obex/ClientSession.java b/obex/javax/obex/ClientSession.java
deleted file mode 100644
index 272a920..0000000
--- a/obex/javax/obex/ClientSession.java
+++ /dev/null
@@ -1,616 +0,0 @@
-/*
- * Copyright (c) 2015 The Android Open Source Project
- * Copyright (C) 2015 Samsung LSI
- * Copyright (c) 2008-2009, Motorola, Inc.
- *
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * - Redistributions of source code must retain the above copyright notice,
- * this list of conditions and the following disclaimer.
- *
- * - Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- *
- * - Neither the name of the Motorola, Inc. nor the names of its contributors
- * may be used to endorse or promote products derived from this software
- * without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
- * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
- * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
- * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
- * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGE.
- */
-
-package javax.obex;
-
-import java.io.ByteArrayOutputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
-
-import android.util.Log;
-
-/**
- * This class in an implementation of the OBEX ClientSession.
- * @hide
- */
-public final class ClientSession extends ObexSession {
-
- private static final String TAG = "ClientSession";
-
- private boolean mOpen;
-
- // Determines if an OBEX layer connection has been established
- private boolean mObexConnected;
-
- private byte[] mConnectionId = null;
-
- /*
- * The max Packet size must be at least 255 according to the OBEX
- * specification.
- */
- private int mMaxTxPacketSize = ObexHelper.LOWER_LIMIT_MAX_PACKET_SIZE;
-
- private boolean mRequestActive;
-
- private final InputStream mInput;
-
- private final OutputStream mOutput;
-
- private final boolean mLocalSrmSupported;
-
- private final ObexTransport mTransport;
-
- public ClientSession(final ObexTransport trans) throws IOException {
- mInput = trans.openInputStream();
- mOutput = trans.openOutputStream();
- mOpen = true;
- mRequestActive = false;
- mLocalSrmSupported = trans.isSrmSupported();
- mTransport = trans;
- }
-
- /**
- * Create a ClientSession
- * @param trans The transport to use for OBEX transactions
- * @param supportsSrm True if Single Response Mode should be used e.g. if the
- * supplied transport is a TCP or l2cap channel.
- * @throws IOException if it occurs while opening the transport streams.
- */
- public ClientSession(final ObexTransport trans, final boolean supportsSrm) throws IOException {
- mInput = trans.openInputStream();
- mOutput = trans.openOutputStream();
- mOpen = true;
- mRequestActive = false;
- mLocalSrmSupported = supportsSrm;
- mTransport = trans;
- }
-
- public HeaderSet connect(final HeaderSet header) throws IOException {
- ensureOpen();
- if (mObexConnected) {
- throw new IOException("Already connected to server");
- }
- setRequestActive();
-
- int totalLength = 4;
- byte[] head = null;
-
- // Determine the header byte array
- if (header != null) {
- if (header.nonce != null) {
- mChallengeDigest = new byte[16];
- System.arraycopy(header.nonce, 0, mChallengeDigest, 0, 16);
- }
- head = ObexHelper.createHeader(header, false);
- totalLength += head.length;
- }
- /*
- * Write the OBEX CONNECT packet to the server.
- * Byte 0: 0x80
- * Byte 1&2: Connect Packet Length
- * Byte 3: OBEX Version Number (Presently, 0x10)
- * Byte 4: Flags (For TCP 0x00)
- * Byte 5&6: Max OBEX Packet Length (Defined in MAX_PACKET_SIZE)
- * Byte 7 to n: headers
- */
- byte[] requestPacket = new byte[totalLength];
- int maxRxPacketSize = ObexHelper.getMaxRxPacketSize(mTransport);
- // We just need to start at byte 3 since the sendRequest() method will
- // handle the length and 0x80.
- requestPacket[0] = (byte)0x10;
- requestPacket[1] = (byte)0x00;
- requestPacket[2] = (byte)(maxRxPacketSize >> 8);
- requestPacket[3] = (byte)(maxRxPacketSize & 0xFF);
- if (head != null) {
- System.arraycopy(head, 0, requestPacket, 4, head.length);
- }
-
- // Since we are not yet connected, the peer max packet size is unknown,
- // hence we are only guaranteed the server will use the first 7 bytes.
- if ((requestPacket.length + 3) > ObexHelper.MAX_PACKET_SIZE_INT) {
- throw new IOException("Packet size exceeds max packet size for connect");
- }
-
- HeaderSet returnHeaderSet = new HeaderSet();
- sendRequest(ObexHelper.OBEX_OPCODE_CONNECT, requestPacket, returnHeaderSet, null, false);
-
- /*
- * Read the response from the OBEX server.
- * Byte 0: Response Code (If successful then OBEX_HTTP_OK)
- * Byte 1&2: Packet Length
- * Byte 3: OBEX Version Number
- * Byte 4: Flags3
- * Byte 5&6: Max OBEX packet Length
- * Byte 7 to n: Optional HeaderSet
- */
- if (returnHeaderSet.responseCode == ResponseCodes.OBEX_HTTP_OK) {
- mObexConnected = true;
- }
- setRequestInactive();
-
- return returnHeaderSet;
- }
-
- public Operation get(HeaderSet header) throws IOException {
-
- if (!mObexConnected) {
- throw new IOException("Not connected to the server");
- }
- setRequestActive();
-
- ensureOpen();
-
- HeaderSet head;
- if (header == null) {
- head = new HeaderSet();
- } else {
- head = header;
- if (head.nonce != null) {
- mChallengeDigest = new byte[16];
- System.arraycopy(head.nonce, 0, mChallengeDigest, 0, 16);
- }
- }
- // Add the connection ID if one exists
- if (mConnectionId != null) {
- head.mConnectionID = new byte[4];
- System.arraycopy(mConnectionId, 0, head.mConnectionID, 0, 4);
- }
-
- if(mLocalSrmSupported) {
- head.setHeader(HeaderSet.SINGLE_RESPONSE_MODE, ObexHelper.OBEX_SRM_ENABLE);
- /* TODO: Consider creating an interface to get the wait state.
- * On an android system, I cannot see when this is to be used.
- * except perhaps if we are to wait for user accept on a push message.
- if(getLocalWaitState()) {
- head.setHeader(HeaderSet.SINGLE_RESPONSE_MODE_PARAMETER, ObexHelper.OBEX_SRMP_WAIT);
- }
- */
- }
-
- return new ClientOperation(mMaxTxPacketSize, this, head, true);
- }
-
- /**
- * 0xCB Connection Id an identifier used for OBEX connection multiplexing
- */
- public void setConnectionID(long id) {
- if ((id < 0) || (id > 0xFFFFFFFFL)) {
- throw new IllegalArgumentException("Connection ID is not in a valid range");
- }
- mConnectionId = ObexHelper.convertToByteArray(id);
- }
-
- public HeaderSet delete(HeaderSet header) throws IOException {
-
- Operation op = put(header);
- op.getResponseCode();
- HeaderSet returnValue = op.getReceivedHeader();
- op.close();
-
- return returnValue;
- }
-
- public HeaderSet disconnect(HeaderSet header) throws IOException {
- if (!mObexConnected) {
- throw new IOException("Not connected to the server");
- }
- setRequestActive();
-
- ensureOpen();
- // Determine the header byte array
- byte[] head = null;
- if (header != null) {
- if (header.nonce != null) {
- mChallengeDigest = new byte[16];
- System.arraycopy(header.nonce, 0, mChallengeDigest, 0, 16);
- }
- // Add the connection ID if one exists
- if (mConnectionId != null) {
- header.mConnectionID = new byte[4];
- System.arraycopy(mConnectionId, 0, header.mConnectionID, 0, 4);
- }
- head = ObexHelper.createHeader(header, false);
-
- if ((head.length + 3) > mMaxTxPacketSize) {
- throw new IOException("Packet size exceeds max packet size");
- }
- } else {
- // Add the connection ID if one exists
- if (mConnectionId != null) {
- head = new byte[5];
- head[0] = (byte)HeaderSet.CONNECTION_ID;
- System.arraycopy(mConnectionId, 0, head, 1, 4);
- }
- }
-
- HeaderSet returnHeaderSet = new HeaderSet();
- sendRequest(ObexHelper.OBEX_OPCODE_DISCONNECT, head, returnHeaderSet, null, false);
-
- /*
- * An OBEX DISCONNECT reply from the server:
- * Byte 1: Response code
- * Bytes 2 & 3: packet size
- * Bytes 4 & up: headers
- */
-
- /* response code , and header are ignored
- * */
-
- synchronized (this) {
- mObexConnected = false;
- setRequestInactive();
- }
-
- return returnHeaderSet;
- }
-
- public long getConnectionID() {
-
- if (mConnectionId == null) {
- return -1;
- }
- return ObexHelper.convertToLong(mConnectionId);
- }
-
- public Operation put(HeaderSet header) throws IOException {
- if (!mObexConnected) {
- throw new IOException("Not connected to the server");
- }
- setRequestActive();
-
- ensureOpen();
- HeaderSet head;
- if (header == null) {
- head = new HeaderSet();
- } else {
- head = header;
- // when auth is initiated by client ,save the digest
- if (head.nonce != null) {
- mChallengeDigest = new byte[16];
- System.arraycopy(head.nonce, 0, mChallengeDigest, 0, 16);
- }
- }
-
- // Add the connection ID if one exists
- if (mConnectionId != null) {
-
- head.mConnectionID = new byte[4];
- System.arraycopy(mConnectionId, 0, head.mConnectionID, 0, 4);
- }
-
- if(mLocalSrmSupported) {
- head.setHeader(HeaderSet.SINGLE_RESPONSE_MODE, ObexHelper.OBEX_SRM_ENABLE);
- /* TODO: Consider creating an interface to get the wait state.
- * On an android system, I cannot see when this is to be used.
- if(getLocalWaitState()) {
- head.setHeader(HeaderSet.SINGLE_RESPONSE_MODE_PARAMETER, ObexHelper.OBEX_SRMP_WAIT);
- }
- */
- }
- return new ClientOperation(mMaxTxPacketSize, this, head, false);
- }
-
- public void setAuthenticator(Authenticator auth) throws IOException {
- if (auth == null) {
- throw new IOException("Authenticator may not be null");
- }
- mAuthenticator = auth;
- }
-
- public HeaderSet setPath(HeaderSet header, boolean backup, boolean create) throws IOException {
- if (!mObexConnected) {
- throw new IOException("Not connected to the server");
- }
- setRequestActive();
- ensureOpen();
-
- int totalLength = 2;
- byte[] head = null;
- HeaderSet headset;
- if (header == null) {
- headset = new HeaderSet();
- } else {
- headset = header;
- if (headset.nonce != null) {
- mChallengeDigest = new byte[16];
- System.arraycopy(headset.nonce, 0, mChallengeDigest, 0, 16);
- }
- }
-
- // when auth is initiated by client ,save the digest
- if (headset.nonce != null) {
- mChallengeDigest = new byte[16];
- System.arraycopy(headset.nonce, 0, mChallengeDigest, 0, 16);
- }
-
- // Add the connection ID if one exists
- if (mConnectionId != null) {
- headset.mConnectionID = new byte[4];
- System.arraycopy(mConnectionId, 0, headset.mConnectionID, 0, 4);
- }
-
- head = ObexHelper.createHeader(headset, false);
- totalLength += head.length;
-
- if (totalLength > mMaxTxPacketSize) {
- throw new IOException("Packet size exceeds max packet size");
- }
-
- int flags = 0;
- /*
- * The backup flag bit is bit 0 so if we add 1, this will set that bit
- */
- if (backup) {
- flags++;
- }
- /*
- * The create bit is bit 1 so if we or with 2 the bit will be set.
- */
- if (!create) {
- flags |= 2;
- }
-
- /*
- * An OBEX SETPATH packet to the server:
- * Byte 1: 0x85
- * Byte 2 & 3: packet size
- * Byte 4: flags
- * Byte 5: constants
- * Byte 6 & up: headers
- */
- byte[] packet = new byte[totalLength];
- packet[0] = (byte)flags;
- packet[1] = (byte)0x00;
- if (headset != null) {
- System.arraycopy(head, 0, packet, 2, head.length);
- }
-
- HeaderSet returnHeaderSet = new HeaderSet();
- sendRequest(ObexHelper.OBEX_OPCODE_SETPATH, packet, returnHeaderSet, null, false);
-
- /*
- * An OBEX SETPATH reply from the server:
- * Byte 1: Response code
- * Bytes 2 & 3: packet size
- * Bytes 4 & up: headers
- */
-
- setRequestInactive();
-
- return returnHeaderSet;
- }
-
- /**
- * Verifies that the connection is open.
- * @throws IOException if the connection is closed
- */
- public synchronized void ensureOpen() throws IOException {
- if (!mOpen) {
- throw new IOException("Connection closed");
- }
- }
-
- /**
- * Set request inactive. Allows Put and get operation objects to tell this
- * object when they are done.
- */
- /*package*/synchronized void setRequestInactive() {
- mRequestActive = false;
- }
-
- /**
- * Set request to active.
- * @throws IOException if already active
- */
- private synchronized void setRequestActive() throws IOException {
- if (mRequestActive) {
- throw new IOException("OBEX request is already being performed");
- }
- mRequestActive = true;
- }
-
- /**
- * Sends a standard request to the client. It will then wait for the reply
- * and update the header set object provided. If any authentication headers
- * (i.e. authentication challenge or authentication response) are received,
- * they will be processed.
- * @param opCode the type of request to send to the client
- * @param head the headers to send to the client
- * @param header the header object to update with the response
- * @param privateInput the input stream used by the Operation object; null
- * if this is called on a CONNECT, SETPATH or DISCONNECT
- * @return
- * <code>true</code> if the operation completed successfully;
- * <code>false</code> if an authentication response failed to pass
- * @throws IOException if an IO error occurs
- */
- public boolean sendRequest(int opCode, byte[] head, HeaderSet header,
- PrivateInputStream privateInput, boolean srmActive) throws IOException {
- //check header length with local max size
- if (head != null) {
- if ((head.length + 3) > ObexHelper.MAX_PACKET_SIZE_INT) {
- // TODO: This is an implementation limit - not a specification requirement.
- throw new IOException("header too large ");
- }
- }
-
- boolean skipSend = false;
- boolean skipReceive = false;
- if (srmActive == true) {
- if (opCode == ObexHelper.OBEX_OPCODE_PUT) {
- // we are in the middle of a SRM PUT operation, don't expect a continue.
- skipReceive = true;
- } else if (opCode == ObexHelper.OBEX_OPCODE_GET) {
- // We are still sending the get request, send, but don't expect continue
- // until the request is transfered (the final bit is set)
- skipReceive = true;
- } else if (opCode == ObexHelper.OBEX_OPCODE_GET_FINAL) {
- // All done sending the request, expect data from the server, without
- // sending continue.
- skipSend = true;
- }
-
- }
-
- int bytesReceived;
- ByteArrayOutputStream out = new ByteArrayOutputStream();
- out.write((byte)opCode);
-
- // Determine if there are any headers to send
- if (head == null) {
- out.write(0x00);
- out.write(0x03);
- } else {
- out.write((byte)((head.length + 3) >> 8));
- out.write((byte)(head.length + 3));
- out.write(head);
- }
-
- if (!skipSend) {
- // Write the request to the output stream and flush the stream
- mOutput.write(out.toByteArray());
- // TODO: is this really needed? if this flush is implemented
- // correctly, we will get a gap between each obex packet.
- // which is kind of the idea behind SRM to avoid.
- // Consider offloading to another thread (async action)
- mOutput.flush();
- }
-
- if (!skipReceive) {
- header.responseCode = mInput.read();
-
- int length = ((mInput.read() << 8) | (mInput.read()));
-
- if (length > ObexHelper.getMaxRxPacketSize(mTransport)) {
- throw new IOException("Packet received exceeds packet size limit");
- }
- if (length > ObexHelper.BASE_PACKET_LENGTH) {
- byte[] data = null;
- if (opCode == ObexHelper.OBEX_OPCODE_CONNECT) {
- @SuppressWarnings("unused")
- int version = mInput.read();
- @SuppressWarnings("unused")
- int flags = mInput.read();
- mMaxTxPacketSize = (mInput.read() << 8) + mInput.read();
-
- //check with local max size
- if (mMaxTxPacketSize > ObexHelper.MAX_CLIENT_PACKET_SIZE) {
- mMaxTxPacketSize = ObexHelper.MAX_CLIENT_PACKET_SIZE;
- }
-
- // check with transport maximum size
- if(mMaxTxPacketSize > ObexHelper.getMaxTxPacketSize(mTransport)) {
- // To increase this size, increase the buffer size in L2CAP layer
- // in Bluedroid.
- Log.w(TAG, "An OBEX packet size of " + mMaxTxPacketSize + "was"
- + " requested. Transport only allows: "
- + ObexHelper.getMaxTxPacketSize(mTransport)
- + " Lowering limit to this value.");
- mMaxTxPacketSize = ObexHelper.getMaxTxPacketSize(mTransport);
- }
-
- if (length > 7) {
- data = new byte[length - 7];
-
- bytesReceived = mInput.read(data);
- while (bytesReceived != (length - 7)) {
- bytesReceived += mInput.read(data, bytesReceived, data.length
- - bytesReceived);
- }
- } else {
- return true;
- }
- } else {
- data = new byte[length - 3];
- bytesReceived = mInput.read(data);
-
- while (bytesReceived != (length - 3)) {
- bytesReceived += mInput.read(data, bytesReceived, data.length - bytesReceived);
- }
- if (opCode == ObexHelper.OBEX_OPCODE_ABORT) {
- return true;
- }
- }
-
- byte[] body = ObexHelper.updateHeaderSet(header, data);
- if ((privateInput != null) && (body != null)) {
- privateInput.writeBytes(body, 1);
- }
-
- if (header.mConnectionID != null) {
- mConnectionId = new byte[4];
- System.arraycopy(header.mConnectionID, 0, mConnectionId, 0, 4);
- }
-
- if (header.mAuthResp != null) {
- if (!handleAuthResp(header.mAuthResp)) {
- setRequestInactive();
- throw new IOException("Authentication Failed");
- }
- }
-
- if ((header.responseCode == ResponseCodes.OBEX_HTTP_UNAUTHORIZED)
- && (header.mAuthChall != null)) {
-
- if (handleAuthChall(header)) {
- out.write((byte)HeaderSet.AUTH_RESPONSE);
- out.write((byte)((header.mAuthResp.length + 3) >> 8));
- out.write((byte)(header.mAuthResp.length + 3));
- out.write(header.mAuthResp);
- header.mAuthChall = null;
- header.mAuthResp = null;
-
- byte[] sendHeaders = new byte[out.size() - 3];
- System.arraycopy(out.toByteArray(), 3, sendHeaders, 0, sendHeaders.length);
-
- return sendRequest(opCode, sendHeaders, header, privateInput, false);
- }
- }
- }
- }
-
- return true;
- }
-
- public void close() throws IOException {
- mOpen = false;
- mInput.close();
- mOutput.close();
- }
-
- public boolean isSrmSupported() {
- return mLocalSrmSupported;
- }
-}
diff --git a/obex/javax/obex/HeaderSet.java b/obex/javax/obex/HeaderSet.java
deleted file mode 100644
index 35fe186..0000000
--- a/obex/javax/obex/HeaderSet.java
+++ /dev/null
@@ -1,710 +0,0 @@
-/*
- * Copyright (c) 2014 The Android Open Source Project
- * Copyright (c) 2008-2009, Motorola, Inc.
- *
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * - Redistributions of source code must retain the above copyright notice,
- * this list of conditions and the following disclaimer.
- *
- * - Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- *
- * - Neither the name of the Motorola, Inc. nor the names of its contributors
- * may be used to endorse or promote products derived from this software
- * without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
- * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
- * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
- * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
- * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGE.
- */
-
-package javax.obex;
-
-import java.io.ByteArrayOutputStream;
-import java.io.IOException;
-import java.util.Calendar;
-import java.security.SecureRandom;
-
-/**
- * This class implements the javax.obex.HeaderSet interface for OBEX over
- * RFCOMM or OBEX over l2cap.
- * @hide
- */
-public final class HeaderSet {
-
- /**
- * Represents the OBEX Count header. This allows the connection statement to
- * tell the server how many objects it plans to send or retrieve.
- * <P>
- * The value of <code>COUNT</code> is 0xC0 (192).
- */
- public static final int COUNT = 0xC0;
-
- /**
- * Represents the OBEX Name header. This specifies the name of the object.
- * <P>
- * The value of <code>NAME</code> is 0x01 (1).
- */
- public static final int NAME = 0x01;
-
- /**
- * Represents the OBEX Type header. This allows a request to specify the
- * type of the object (e.g. text, html, binary, etc.).
- * <P>
- * The value of <code>TYPE</code> is 0x42 (66).
- */
- public static final int TYPE = 0x42;
-
- /**
- * Represents the OBEX Length header. This is the length of the object in
- * bytes.
- * <P>
- * The value of <code>LENGTH</code> is 0xC3 (195).
- */
- public static final int LENGTH = 0xC3;
-
- /**
- * Represents the OBEX Time header using the ISO 8601 standards. This is the
- * preferred time header.
- * <P>
- * The value of <code>TIME_ISO_8601</code> is 0x44 (68).
- */
- public static final int TIME_ISO_8601 = 0x44;
-
- /**
- * Represents the OBEX Time header using the 4 byte representation. This is
- * only included for backwards compatibility. It represents the number of
- * seconds since January 1, 1970.
- * <P>
- * The value of <code>TIME_4_BYTE</code> is 0xC4 (196).
- */
- public static final int TIME_4_BYTE = 0xC4;
-
- /**
- * Represents the OBEX Description header. This is a text description of the
- * object.
- * <P>
- * The value of <code>DESCRIPTION</code> is 0x05 (5).
- */
- public static final int DESCRIPTION = 0x05;
-
- /**
- * Represents the OBEX Target header. This is the name of the service an
- * operation is targeted to.
- * <P>
- * The value of <code>TARGET</code> is 0x46 (70).
- */
- public static final int TARGET = 0x46;
-
- /**
- * Represents the OBEX HTTP header. This allows an HTTP 1.X header to be
- * included in a request or reply.
- * <P>
- * The value of <code>HTTP</code> is 0x47 (71).
- */
- public static final int HTTP = 0x47;
-
- /**
- * Represents the OBEX BODY header.
- * <P>
- * The value of <code>BODY</code> is 0x48 (72).
- */
- public static final int BODY = 0x48;
-
- /**
- * Represents the OBEX End of BODY header.
- * <P>
- * The value of <code>BODY</code> is 0x49 (73).
- */
- public static final int END_OF_BODY = 0x49;
-
- /**
- * Represents the OBEX Who header. Identifies the OBEX application to
- * determine if the two peers are talking to each other.
- * <P>
- * The value of <code>WHO</code> is 0x4A (74).
- */
- public static final int WHO = 0x4A;
-
- /**
- * Represents the OBEX Connection ID header. Identifies used for OBEX
- * connection multiplexing.
- * <P>
- * The value of <code>CONNECTION_ID</code> is 0xCB (203).
- */
-
- public static final int CONNECTION_ID = 0xCB;
-
- /**
- * Represents the OBEX Application Parameter header. This header specifies
- * additional application request and response information.
- * <P>
- * The value of <code>APPLICATION_PARAMETER</code> is 0x4C (76).
- */
- public static final int APPLICATION_PARAMETER = 0x4C;
-
- /**
- * Represents the OBEX authentication digest-challenge.
- * <P>
- * The value of <code>AUTH_CHALLENGE</code> is 0x4D (77).
- */
- public static final int AUTH_CHALLENGE = 0x4D;
-
- /**
- * Represents the OBEX authentication digest-response.
- * <P>
- * The value of <code>AUTH_RESPONSE</code> is 0x4E (78).
- */
- public static final int AUTH_RESPONSE = 0x4E;
-
- /**
- * Represents the OBEX Object Class header. This header specifies the OBEX
- * object class of the object.
- * <P>
- * The value of <code>OBJECT_CLASS</code> is 0x4F (79).
- */
- public static final int OBJECT_CLASS = 0x4F;
-
- /**
- * Represents the OBEX Single Response Mode (SRM). This header is used
- * for Single response mode, introduced in OBEX 1.5.
- * <P>
- * The value of <code>SINGLE_RESPONSE_MODE</code> is 0x97 (151).
- */
- public static final int SINGLE_RESPONSE_MODE = 0x97;
-
- /**
- * Represents the OBEX Single Response Mode Parameters. This header is used
- * for Single response mode, introduced in OBEX 1.5.
- * <P>
- * The value of <code>SINGLE_RESPONSE_MODE_PARAMETER</code> is 0x98 (152).
- */
- public static final int SINGLE_RESPONSE_MODE_PARAMETER = 0x98;
-
- private Long mCount; // 4 byte unsigned integer
-
- private String mName; // null terminated Unicode text string
-
- private boolean mEmptyName;
-
- private String mType; // null terminated ASCII text string
-
- private Long mLength; // 4 byte unsigend integer
-
- private Calendar mIsoTime; // String of the form YYYYMMDDTHHMMSSZ
-
- private Calendar mByteTime; // 4 byte unsigned integer
-
- private String mDescription; // null terminated Unicode text String
-
- private byte[] mTarget; // byte sequence
-
- private byte[] mHttpHeader; // byte sequence
-
- private byte[] mWho; // length prefixed byte sequence
-
- private byte[] mAppParam; // byte sequence of the form tag length value
-
- private byte[] mObjectClass; // byte sequence
-
- private String[] mUnicodeUserDefined; // null terminated unicode string
-
- private byte[][] mSequenceUserDefined; // byte sequence user defined
-
- private Byte[] mByteUserDefined; // 1 byte
-
- private Long[] mIntegerUserDefined; // 4 byte unsigned integer
-
- private SecureRandom mRandom = null;
-
- private Byte mSingleResponseMode; // byte to indicate enable/disable/support for SRM
-
- private Byte mSrmParam; // byte representing the SRM parameters - only "wait"
- // is supported by Bluetooth
-
- /*package*/ byte[] nonce;
-
- public byte[] mAuthChall; // The authentication challenge header
-
- public byte[] mAuthResp; // The authentication response header
-
- public byte[] mConnectionID; // THe connection ID
-
- public int responseCode;
-
- /**
- * Creates new <code>HeaderSet</code> object.
- * @param size the max packet size for this connection
- */
- public HeaderSet() {
- mUnicodeUserDefined = new String[16];
- mSequenceUserDefined = new byte[16][];
- mByteUserDefined = new Byte[16];
- mIntegerUserDefined = new Long[16];
- responseCode = -1;
- }
-
- /**
- * Sets flag for special "value" of NAME header which should be empty. This
- * is not the same as NAME header with empty string in which case it will
- * have length of 5 bytes. It should be 3 bytes with only header id and
- * length field.
- */
- public void setEmptyNameHeader() {
- mName = null;
- mEmptyName = true;
- }
-
- /**
- * Gets flag for special "value" of NAME header which should be empty. See
- * above.
- */
- public boolean getEmptyNameHeader() {
- return mEmptyName;
- }
-
- /**
- * Sets the value of the header identifier to the value provided. The type
- * of object must correspond to the Java type defined in the description of
- * this interface. If <code>null</code> is passed as the
- * <code>headerValue</code> then the header will be removed from the set of
- * headers to include in the next request.
- * @param headerID the identifier to include in the message
- * @param headerValue the value of the header identifier
- * @throws IllegalArgumentException if the header identifier provided is not
- * one defined in this interface or a user-defined header; if the
- * type of <code>headerValue</code> is not the correct Java type as
- * defined in the description of this interface\
- */
- public void setHeader(int headerID, Object headerValue) {
- long temp = -1;
-
- switch (headerID) {
- case COUNT:
- if (!(headerValue instanceof Long)) {
- if (headerValue == null) {
- mCount = null;
- break;
- }
- throw new IllegalArgumentException("Count must be a Long");
- }
- temp = ((Long)headerValue).longValue();
- if ((temp < 0L) || (temp > 0xFFFFFFFFL)) {
- throw new IllegalArgumentException("Count must be between 0 and 0xFFFFFFFF");
- }
- mCount = (Long)headerValue;
- break;
- case NAME:
- if ((headerValue != null) && (!(headerValue instanceof String))) {
- throw new IllegalArgumentException("Name must be a String");
- }
- mEmptyName = false;
- mName = (String)headerValue;
- break;
- case TYPE:
- if ((headerValue != null) && (!(headerValue instanceof String))) {
- throw new IllegalArgumentException("Type must be a String");
- }
- mType = (String)headerValue;
- break;
- case LENGTH:
- if (!(headerValue instanceof Long)) {
- if (headerValue == null) {
- mLength = null;
- break;
- }
- throw new IllegalArgumentException("Length must be a Long");
- }
- temp = ((Long)headerValue).longValue();
- if ((temp < 0L) || (temp > 0xFFFFFFFFL)) {
- throw new IllegalArgumentException("Length must be between 0 and 0xFFFFFFFF");
- }
- mLength = (Long)headerValue;
- break;
- case TIME_ISO_8601:
- if ((headerValue != null) && (!(headerValue instanceof Calendar))) {
- throw new IllegalArgumentException("Time ISO 8601 must be a Calendar");
- }
- mIsoTime = (Calendar)headerValue;
- break;
- case TIME_4_BYTE:
- if ((headerValue != null) && (!(headerValue instanceof Calendar))) {
- throw new IllegalArgumentException("Time 4 Byte must be a Calendar");
- }
- mByteTime = (Calendar)headerValue;
- break;
- case DESCRIPTION:
- if ((headerValue != null) && (!(headerValue instanceof String))) {
- throw new IllegalArgumentException("Description must be a String");
- }
- mDescription = (String)headerValue;
- break;
- case TARGET:
- if (headerValue == null) {
- mTarget = null;
- } else {
- if (!(headerValue instanceof byte[])) {
- throw new IllegalArgumentException("Target must be a byte array");
- } else {
- mTarget = new byte[((byte[])headerValue).length];
- System.arraycopy(headerValue, 0, mTarget, 0, mTarget.length);
- }
- }
- break;
- case HTTP:
- if (headerValue == null) {
- mHttpHeader = null;
- } else {
- if (!(headerValue instanceof byte[])) {
- throw new IllegalArgumentException("HTTP must be a byte array");
- } else {
- mHttpHeader = new byte[((byte[])headerValue).length];
- System.arraycopy(headerValue, 0, mHttpHeader, 0, mHttpHeader.length);
- }
- }
- break;
- case WHO:
- if (headerValue == null) {
- mWho = null;
- } else {
- if (!(headerValue instanceof byte[])) {
- throw new IllegalArgumentException("WHO must be a byte array");
- } else {
- mWho = new byte[((byte[])headerValue).length];
- System.arraycopy(headerValue, 0, mWho, 0, mWho.length);
- }
- }
- break;
- case OBJECT_CLASS:
- if (headerValue == null) {
- mObjectClass = null;
- } else {
- if (!(headerValue instanceof byte[])) {
- throw new IllegalArgumentException("Object Class must be a byte array");
- } else {
- mObjectClass = new byte[((byte[])headerValue).length];
- System.arraycopy(headerValue, 0, mObjectClass, 0, mObjectClass.length);
- }
- }
- break;
- case APPLICATION_PARAMETER:
- if (headerValue == null) {
- mAppParam = null;
- } else {
- if (!(headerValue instanceof byte[])) {
- throw new IllegalArgumentException(
- "Application Parameter must be a byte array");
- } else {
- mAppParam = new byte[((byte[])headerValue).length];
- System.arraycopy(headerValue, 0, mAppParam, 0, mAppParam.length);
- }
- }
- break;
- case SINGLE_RESPONSE_MODE:
- if (headerValue == null) {
- mSingleResponseMode = null;
- } else {
- if (!(headerValue instanceof Byte)) {
- throw new IllegalArgumentException(
- "Single Response Mode must be a Byte");
- } else {
- mSingleResponseMode = (Byte)headerValue;
- }
- }
- break;
- case SINGLE_RESPONSE_MODE_PARAMETER:
- if (headerValue == null) {
- mSrmParam = null;
- } else {
- if (!(headerValue instanceof Byte)) {
- throw new IllegalArgumentException(
- "Single Response Mode Parameter must be a Byte");
- } else {
- mSrmParam = (Byte)headerValue;
- }
- }
- break;
- default:
- // Verify that it was not a Unicode String user Defined
- if ((headerID >= 0x30) && (headerID <= 0x3F)) {
- if ((headerValue != null) && (!(headerValue instanceof String))) {
- throw new IllegalArgumentException(
- "Unicode String User Defined must be a String");
- }
- mUnicodeUserDefined[headerID - 0x30] = (String)headerValue;
-
- break;
- }
- // Verify that it was not a byte sequence user defined value
- if ((headerID >= 0x70) && (headerID <= 0x7F)) {
-
- if (headerValue == null) {
- mSequenceUserDefined[headerID - 0x70] = null;
- } else {
- if (!(headerValue instanceof byte[])) {
- throw new IllegalArgumentException(
- "Byte Sequence User Defined must be a byte array");
- } else {
- mSequenceUserDefined[headerID - 0x70] = new byte[((byte[])headerValue).length];
- System.arraycopy(headerValue, 0, mSequenceUserDefined[headerID - 0x70],
- 0, mSequenceUserDefined[headerID - 0x70].length);
- }
- }
- break;
- }
- // Verify that it was not a Byte user Defined
- if ((headerID >= 0xB0) && (headerID <= 0xBF)) {
- if ((headerValue != null) && (!(headerValue instanceof Byte))) {
- throw new IllegalArgumentException("ByteUser Defined must be a Byte");
- }
- mByteUserDefined[headerID - 0xB0] = (Byte)headerValue;
-
- break;
- }
- // Verify that is was not the 4 byte unsigned integer user
- // defined header
- if ((headerID >= 0xF0) && (headerID <= 0xFF)) {
- if (!(headerValue instanceof Long)) {
- if (headerValue == null) {
- mIntegerUserDefined[headerID - 0xF0] = null;
- break;
- }
- throw new IllegalArgumentException("Integer User Defined must be a Long");
- }
- temp = ((Long)headerValue).longValue();
- if ((temp < 0L) || (temp > 0xFFFFFFFFL)) {
- throw new IllegalArgumentException(
- "Integer User Defined must be between 0 and 0xFFFFFFFF");
- }
- mIntegerUserDefined[headerID - 0xF0] = (Long)headerValue;
- break;
- }
- throw new IllegalArgumentException("Invalid Header Identifier");
- }
- }
-
- /**
- * Retrieves the value of the header identifier provided. The type of the
- * Object returned is defined in the description of this interface.
- * @param headerID the header identifier whose value is to be returned
- * @return the value of the header provided or <code>null</code> if the
- * header identifier specified is not part of this
- * <code>HeaderSet</code> object
- * @throws IllegalArgumentException if the <code>headerID</code> is not one
- * defined in this interface or any of the user-defined headers
- * @throws IOException if an error occurred in the transport layer during
- * the operation or if the connection has been closed
- */
- public Object getHeader(int headerID) throws IOException {
-
- switch (headerID) {
- case COUNT:
- return mCount;
- case NAME:
- return mName;
- case TYPE:
- return mType;
- case LENGTH:
- return mLength;
- case TIME_ISO_8601:
- return mIsoTime;
- case TIME_4_BYTE:
- return mByteTime;
- case DESCRIPTION:
- return mDescription;
- case TARGET:
- return mTarget;
- case HTTP:
- return mHttpHeader;
- case WHO:
- return mWho;
- case CONNECTION_ID:
- return mConnectionID;
- case OBJECT_CLASS:
- return mObjectClass;
- case APPLICATION_PARAMETER:
- return mAppParam;
- case SINGLE_RESPONSE_MODE:
- return mSingleResponseMode;
- case SINGLE_RESPONSE_MODE_PARAMETER:
- return mSrmParam;
- default:
- // Verify that it was not a Unicode String user Defined
- if ((headerID >= 0x30) && (headerID <= 0x3F)) {
- return mUnicodeUserDefined[headerID - 0x30];
- }
- // Verify that it was not a byte sequence user defined header
- if ((headerID >= 0x70) && (headerID <= 0x7F)) {
- return mSequenceUserDefined[headerID - 0x70];
- }
- // Verify that it was not a byte user defined header
- if ((headerID >= 0xB0) && (headerID <= 0xBF)) {
- return mByteUserDefined[headerID - 0xB0];
- }
- // Verify that it was not a integer user defined header
- if ((headerID >= 0xF0) && (headerID <= 0xFF)) {
- return mIntegerUserDefined[headerID - 0xF0];
- }
- throw new IllegalArgumentException("Invalid Header Identifier");
- }
- }
-
- /**
- * Retrieves the list of headers that may be retrieved via the
- * <code>getHeader</code> method that will not return <code>null</code>. In
- * other words, this method returns all the headers that are available in
- * this object.
- * @see #getHeader
- * @return the array of headers that are set in this object or
- * <code>null</code> if no headers are available
- * @throws IOException if an error occurred in the transport layer during
- * the operation or the connection has been closed
- */
- public int[] getHeaderList() throws IOException {
- ByteArrayOutputStream out = new ByteArrayOutputStream();
-
- if (mCount != null) {
- out.write(COUNT);
- }
- if (mName != null) {
- out.write(NAME);
- }
- if (mType != null) {
- out.write(TYPE);
- }
- if (mLength != null) {
- out.write(LENGTH);
- }
- if (mIsoTime != null) {
- out.write(TIME_ISO_8601);
- }
- if (mByteTime != null) {
- out.write(TIME_4_BYTE);
- }
- if (mDescription != null) {
- out.write(DESCRIPTION);
- }
- if (mTarget != null) {
- out.write(TARGET);
- }
- if (mHttpHeader != null) {
- out.write(HTTP);
- }
- if (mWho != null) {
- out.write(WHO);
- }
- if (mAppParam != null) {
- out.write(APPLICATION_PARAMETER);
- }
- if (mObjectClass != null) {
- out.write(OBJECT_CLASS);
- }
- if(mSingleResponseMode != null) {
- out.write(SINGLE_RESPONSE_MODE);
- }
- if(mSrmParam != null) {
- out.write(SINGLE_RESPONSE_MODE_PARAMETER);
- }
-
- for (int i = 0x30; i < 0x40; i++) {
- if (mUnicodeUserDefined[i - 0x30] != null) {
- out.write(i);
- }
- }
-
- for (int i = 0x70; i < 0x80; i++) {
- if (mSequenceUserDefined[i - 0x70] != null) {
- out.write(i);
- }
- }
-
- for (int i = 0xB0; i < 0xC0; i++) {
- if (mByteUserDefined[i - 0xB0] != null) {
- out.write(i);
- }
- }
-
- for (int i = 0xF0; i < 0x100; i++) {
- if (mIntegerUserDefined[i - 0xF0] != null) {
- out.write(i);
- }
- }
-
- byte[] headers = out.toByteArray();
- out.close();
-
- if ((headers == null) || (headers.length == 0)) {
- return null;
- }
-
- int[] result = new int[headers.length];
- for (int i = 0; i < headers.length; i++) {
- // Convert the byte to a positive integer. That is, an integer
- // between 0 and 256.
- result[i] = headers[i] & 0xFF;
- }
-
- return result;
- }
-
- /**
- * Sets the authentication challenge header. The <code>realm</code> will be
- * encoded based upon the default encoding scheme used by the implementation
- * to encode strings. Therefore, the encoding scheme used to encode the
- * <code>realm</code> is application dependent.
- * @param realm a short description that describes what password to use; if
- * <code>null</code> no realm will be sent in the authentication
- * challenge header
- * @param userID if <code>true</code>, a user ID is required in the reply;
- * if <code>false</code>, no user ID is required
- * @param access if <code>true</code> then full access will be granted if
- * successful; if <code>false</code> then read-only access will be
- * granted if successful
- * @throws IOException
- */
- public void createAuthenticationChallenge(String realm, boolean userID, boolean access)
- throws IOException {
-
- nonce = new byte[16];
- if(mRandom == null) {
- mRandom = new SecureRandom();
- }
- for (int i = 0; i < 16; i++) {
- nonce[i] = (byte)mRandom.nextInt();
- }
-
- mAuthChall = ObexHelper.computeAuthenticationChallenge(nonce, realm, access, userID);
- }
-
- /**
- * Returns the response code received from the server. Response codes are
- * defined in the <code>ResponseCodes</code> class.
- * @see ResponseCodes
- * @return the response code retrieved from the server
- * @throws IOException if an error occurred in the transport layer during
- * the transaction; if this method is called on a
- * <code>HeaderSet</code> object created by calling
- * <code>createHeaderSet()</code> in a <code>ClientSession</code>
- * object; if this object was created by an OBEX server
- */
- public int getResponseCode() throws IOException {
- if (responseCode == -1) {
- throw new IOException("May not be called on a server");
- } else {
- return responseCode;
- }
- }
-}
diff --git a/obex/javax/obex/ObexHelper.java b/obex/javax/obex/ObexHelper.java
deleted file mode 100644
index 843793a..0000000
--- a/obex/javax/obex/ObexHelper.java
+++ /dev/null
@@ -1,1100 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- * Copyright (C) 2015 Samsung LSI
- * Copyright (c) 2008-2009, Motorola, Inc.
- *
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * - Redistributions of source code must retain the above copyright notice,
- * this list of conditions and the following disclaimer.
- *
- * - Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- *
- * - Neither the name of the Motorola, Inc. nor the names of its contributors
- * may be used to endorse or promote products derived from this software
- * without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
- * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
- * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
- * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
- * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGE.
- */
-
-package javax.obex;
-
-import android.util.Log;
-
-import java.io.ByteArrayOutputStream;
-import java.io.IOException;
-import java.io.UnsupportedEncodingException;
-import java.security.MessageDigest;
-import java.security.NoSuchAlgorithmException;
-import java.util.Calendar;
-import java.util.Date;
-import java.util.TimeZone;
-
-
-/**
- * This class defines a set of helper methods for the implementation of Obex.
- * @hide
- */
-public final class ObexHelper {
-
- private static final String TAG = "ObexHelper";
- public static final boolean VDBG = false;
- /**
- * Defines the basic packet length used by OBEX. Every OBEX packet has the
- * same basic format:<BR>
- * Byte 0: Request or Response Code Byte 1&2: Length of the packet.
- */
- public static final int BASE_PACKET_LENGTH = 3;
-
- /** Prevent object construction of helper class */
- private ObexHelper() {
- }
-
- /**
- * The maximum packet size for OBEX packets that this client can handle. At
- * present, this must be changed for each port. TODO: The max packet size
- * should be the Max incoming MTU minus TODO: L2CAP package headers and
- * RFCOMM package headers. TODO: Retrieve the max incoming MTU from TODO:
- * LocalDevice.getProperty().
- * NOTE: This value must be larger than or equal to the L2CAP SDU
- */
- /*
- * android note set as 0xFFFE to match remote MPS
- */
- public static final int MAX_PACKET_SIZE_INT = 0xFFFE;
-
- // The minimum allowed max packet size is 255 according to the OBEX specification
- public static final int LOWER_LIMIT_MAX_PACKET_SIZE = 255;
-
- // The length of OBEX Byte Sequency Header Id according to the OBEX specification
- public static final int OBEX_BYTE_SEQ_HEADER_LEN = 0x03;
-
- /**
- * Temporary workaround to be able to push files to Windows 7.
- * TODO: Should be removed as soon as Microsoft updates their driver.
- */
- public static final int MAX_CLIENT_PACKET_SIZE = 0xFC00;
-
- public static final int OBEX_OPCODE_FINAL_BIT_MASK = 0x80;
-
- public static final int OBEX_OPCODE_CONNECT = 0x80;
-
- public static final int OBEX_OPCODE_DISCONNECT = 0x81;
-
- public static final int OBEX_OPCODE_PUT = 0x02;
-
- public static final int OBEX_OPCODE_PUT_FINAL = 0x82;
-
- public static final int OBEX_OPCODE_GET = 0x03;
-
- public static final int OBEX_OPCODE_GET_FINAL = 0x83;
-
- public static final int OBEX_OPCODE_RESERVED = 0x04;
-
- public static final int OBEX_OPCODE_RESERVED_FINAL = 0x84;
-
- public static final int OBEX_OPCODE_SETPATH = 0x85;
-
- public static final int OBEX_OPCODE_ABORT = 0xFF;
-
- public static final int OBEX_AUTH_REALM_CHARSET_ASCII = 0x00;
-
- public static final int OBEX_AUTH_REALM_CHARSET_ISO_8859_1 = 0x01;
-
- public static final int OBEX_AUTH_REALM_CHARSET_ISO_8859_2 = 0x02;
-
- public static final int OBEX_AUTH_REALM_CHARSET_ISO_8859_3 = 0x03;
-
- public static final int OBEX_AUTH_REALM_CHARSET_ISO_8859_4 = 0x04;
-
- public static final int OBEX_AUTH_REALM_CHARSET_ISO_8859_5 = 0x05;
-
- public static final int OBEX_AUTH_REALM_CHARSET_ISO_8859_6 = 0x06;
-
- public static final int OBEX_AUTH_REALM_CHARSET_ISO_8859_7 = 0x07;
-
- public static final int OBEX_AUTH_REALM_CHARSET_ISO_8859_8 = 0x08;
-
- public static final int OBEX_AUTH_REALM_CHARSET_ISO_8859_9 = 0x09;
-
- public static final int OBEX_AUTH_REALM_CHARSET_UNICODE = 0xFF;
-
- public static final byte OBEX_SRM_ENABLE = 0x01; // For BT we only need enable/disable
- public static final byte OBEX_SRM_DISABLE = 0x00;
- public static final byte OBEX_SRM_SUPPORT = 0x02; // Unused for now
-
- public static final byte OBEX_SRMP_WAIT = 0x01; // Only SRMP value used by BT
-
- /**
- * Updates the HeaderSet with the headers received in the byte array
- * provided. Invalid headers are ignored.
- * <P>
- * The first two bits of an OBEX Header specifies the type of object that is
- * being sent. The table below specifies the meaning of the high bits.
- * <TABLE>
- * <TR>
- * <TH>Bits 8 and 7</TH>
- * <TH>Value</TH>
- * <TH>Description</TH>
- * </TR>
- * <TR>
- * <TD>00</TD>
- * <TD>0x00</TD>
- * <TD>Null Terminated Unicode text, prefixed with 2 byte unsigned integer</TD>
- * </TR>
- * <TR>
- * <TD>01</TD>
- * <TD>0x40</TD>
- * <TD>Byte Sequence, length prefixed with 2 byte unsigned integer</TD>
- * </TR>
- * <TR>
- * <TD>10</TD>
- * <TD>0x80</TD>
- * <TD>1 byte quantity</TD>
- * </TR>
- * <TR>
- * <TD>11</TD>
- * <TD>0xC0</TD>
- * <TD>4 byte quantity - transmitted in network byte order (high byte first</TD>
- * </TR>
- * </TABLE>
- * This method uses the information in this table to determine the type of
- * Java object to create and passes that object with the full header to
- * setHeader() to update the HeaderSet object. Invalid headers will cause an
- * exception to be thrown. When it is thrown, it is ignored.
- * @param header the HeaderSet to update
- * @param headerArray the byte array containing headers
- * @return the result of the last start body or end body header provided;
- * the first byte in the result will specify if a body or end of
- * body is received
- * @throws IOException if an invalid header was found
- */
- public static byte[] updateHeaderSet(HeaderSet header, byte[] headerArray) throws IOException {
- int index = 0;
- int length = 0;
- int headerID;
- byte[] value = null;
- byte[] body = null;
- HeaderSet headerImpl = header;
- try {
- while (index < headerArray.length) {
- headerID = 0xFF & headerArray[index];
- switch (headerID & (0xC0)) {
-
- /*
- * 0x00 is a unicode null terminate string with the first
- * two bytes after the header identifier being the length
- */
- case 0x00:
- // Fall through
- /*
- * 0x40 is a byte sequence with the first
- * two bytes after the header identifier being the length
- */
- case 0x40:
- boolean trimTail = true;
- index++;
- length = ((0xFF & headerArray[index]) << 8) +
- (0xFF & headerArray[index + 1]);
- index += 2;
- if (length <= OBEX_BYTE_SEQ_HEADER_LEN) {
- Log.e(TAG, "Remote sent an OBEX packet with " +
- "incorrect header length = " + length);
- break;
- }
- length -= OBEX_BYTE_SEQ_HEADER_LEN;
- value = new byte[length];
- System.arraycopy(headerArray, index, value, 0, length);
- if (length == 0 || (length > 0 && (value[length - 1] != 0))) {
- trimTail = false;
- }
- switch (headerID) {
- case HeaderSet.TYPE:
- try {
- // Remove trailing null
- if (trimTail == false) {
- headerImpl.setHeader(headerID, new String(value, 0,
- value.length, "ISO8859_1"));
- } else {
- headerImpl.setHeader(headerID, new String(value, 0,
- value.length - 1, "ISO8859_1"));
- }
- } catch (UnsupportedEncodingException e) {
- throw e;
- }
- break;
-
- case HeaderSet.AUTH_CHALLENGE:
- headerImpl.mAuthChall = new byte[length];
- System.arraycopy(headerArray, index, headerImpl.mAuthChall, 0,
- length);
- break;
-
- case HeaderSet.AUTH_RESPONSE:
- headerImpl.mAuthResp = new byte[length];
- System.arraycopy(headerArray, index, headerImpl.mAuthResp, 0,
- length);
- break;
-
- case HeaderSet.BODY:
- /* Fall Through */
- case HeaderSet.END_OF_BODY:
- body = new byte[length + 1];
- body[0] = (byte)headerID;
- System.arraycopy(headerArray, index, body, 1, length);
- break;
-
- case HeaderSet.TIME_ISO_8601:
- try {
- String dateString = new String(value, "ISO8859_1");
- Calendar temp = Calendar.getInstance();
- if ((dateString.length() == 16)
- && (dateString.charAt(15) == 'Z')) {
- temp.setTimeZone(TimeZone.getTimeZone("UTC"));
- }
- temp.set(Calendar.YEAR, Integer.parseInt(dateString.substring(
- 0, 4)));
- temp.set(Calendar.MONTH, Integer.parseInt(dateString.substring(
- 4, 6)));
- temp.set(Calendar.DAY_OF_MONTH, Integer.parseInt(dateString
- .substring(6, 8)));
- temp.set(Calendar.HOUR_OF_DAY, Integer.parseInt(dateString
- .substring(9, 11)));
- temp.set(Calendar.MINUTE, Integer.parseInt(dateString
- .substring(11, 13)));
- temp.set(Calendar.SECOND, Integer.parseInt(dateString
- .substring(13, 15)));
- headerImpl.setHeader(HeaderSet.TIME_ISO_8601, temp);
- } catch (UnsupportedEncodingException e) {
- throw e;
- }
- break;
-
- default:
- if ((headerID & 0xC0) == 0x00) {
- headerImpl.setHeader(headerID, ObexHelper.convertToUnicode(
- value, true));
- } else {
- headerImpl.setHeader(headerID, value);
- }
- }
-
- index += length;
- break;
-
- /*
- * 0x80 is a byte header. The only valid byte headers are
- * the 16 user defined byte headers.
- */
- case 0x80:
- index++;
- try {
- headerImpl.setHeader(headerID, Byte.valueOf(headerArray[index]));
- } catch (Exception e) {
- // Not a valid header so ignore
- }
- index++;
- break;
-
- /*
- * 0xC0 is a 4 byte unsigned integer header and with the
- * exception of TIME_4_BYTE will be converted to a Long
- * and added.
- */
- case 0xC0:
- index++;
- value = new byte[4];
- System.arraycopy(headerArray, index, value, 0, 4);
- try {
- if (headerID != HeaderSet.TIME_4_BYTE) {
- // Determine if it is a connection ID. These
- // need to be handled differently
- if (headerID == HeaderSet.CONNECTION_ID) {
- headerImpl.mConnectionID = new byte[4];
- System.arraycopy(value, 0, headerImpl.mConnectionID, 0, 4);
- } else {
- headerImpl.setHeader(headerID, Long
- .valueOf(convertToLong(value)));
- }
- } else {
- Calendar temp = Calendar.getInstance();
- temp.setTime(new Date(convertToLong(value) * 1000L));
- headerImpl.setHeader(HeaderSet.TIME_4_BYTE, temp);
- }
- } catch (Exception e) {
- // Not a valid header so ignore
- throw new IOException("Header was not formatted properly", e);
- }
- index += 4;
- break;
- }
-
- }
- } catch (IOException e) {
- throw new IOException("Header was not formatted properly", e);
- }
-
- return body;
- }
-
- /**
- * Creates the header part of OBEX packet based on the header provided.
- * TODO: Could use getHeaderList() to get the array of headers to include
- * and then use the high two bits to determine the the type of the object
- * and construct the byte array from that. This will make the size smaller.
- * @param head the header used to construct the byte array
- * @param nullOut <code>true</code> if the header should be set to
- * <code>null</code> once it is added to the array or
- * <code>false</code> if it should not be nulled out
- * @return the header of an OBEX packet
- */
- public static byte[] createHeader(HeaderSet head, boolean nullOut) {
- Long intHeader = null;
- String stringHeader = null;
- Calendar dateHeader = null;
- Byte byteHeader = null;
- StringBuffer buffer = null;
- byte[] value = null;
- byte[] result = null;
- byte[] lengthArray = new byte[2];
- int length;
- HeaderSet headImpl = null;
- ByteArrayOutputStream out = new ByteArrayOutputStream();
- headImpl = head;
-
- try {
- /*
- * Determine if there is a connection ID to send. If there is,
- * then it should be the first header in the packet.
- */
- if ((headImpl.mConnectionID != null) && (headImpl.getHeader(HeaderSet.TARGET) == null)) {
-
- out.write((byte)HeaderSet.CONNECTION_ID);
- out.write(headImpl.mConnectionID);
- }
-
- // Count Header
- intHeader = (Long)headImpl.getHeader(HeaderSet.COUNT);
- if (intHeader != null) {
- out.write((byte)HeaderSet.COUNT);
- value = ObexHelper.convertToByteArray(intHeader.longValue());
- out.write(value);
- if (nullOut) {
- headImpl.setHeader(HeaderSet.COUNT, null);
- }
- }
-
- // Name Header
- stringHeader = (String)headImpl.getHeader(HeaderSet.NAME);
- if (stringHeader != null) {
- out.write((byte)HeaderSet.NAME);
- value = ObexHelper.convertToUnicodeByteArray(stringHeader);
- length = value.length + 3;
- lengthArray[0] = (byte)(0xFF & (length >> 8));
- lengthArray[1] = (byte)(0xFF & length);
- out.write(lengthArray);
- out.write(value);
- if (nullOut) {
- headImpl.setHeader(HeaderSet.NAME, null);
- }
- } else if (headImpl.getEmptyNameHeader()) {
- out.write((byte) HeaderSet.NAME);
- lengthArray[0] = (byte) 0x00;
- lengthArray[1] = (byte) 0x03;
- out.write(lengthArray);
- }
-
- // Type Header
- stringHeader = (String)headImpl.getHeader(HeaderSet.TYPE);
- if (stringHeader != null) {
- out.write((byte)HeaderSet.TYPE);
- try {
- value = stringHeader.getBytes("ISO8859_1");
- } catch (UnsupportedEncodingException e) {
- throw e;
- }
-
- length = value.length + 4;
- lengthArray[0] = (byte)(255 & (length >> 8));
- lengthArray[1] = (byte)(255 & length);
- out.write(lengthArray);
- out.write(value);
- out.write(0x00);
- if (nullOut) {
- headImpl.setHeader(HeaderSet.TYPE, null);
- }
- }
-
- // Length Header
- intHeader = (Long)headImpl.getHeader(HeaderSet.LENGTH);
- if (intHeader != null) {
- out.write((byte)HeaderSet.LENGTH);
- value = ObexHelper.convertToByteArray(intHeader.longValue());
- out.write(value);
- if (nullOut) {
- headImpl.setHeader(HeaderSet.LENGTH, null);
- }
- }
-
- // Time ISO Header
- dateHeader = (Calendar)headImpl.getHeader(HeaderSet.TIME_ISO_8601);
- if (dateHeader != null) {
-
- /*
- * The ISO Header should take the form YYYYMMDDTHHMMSSZ. The
- * 'Z' will only be included if it is a UTC time.
- */
- buffer = new StringBuffer();
- int temp = dateHeader.get(Calendar.YEAR);
- for (int i = temp; i < 1000; i = i * 10) {
- buffer.append("0");
- }
- buffer.append(temp);
- temp = dateHeader.get(Calendar.MONTH);
- if (temp < 10) {
- buffer.append("0");
- }
- buffer.append(temp);
- temp = dateHeader.get(Calendar.DAY_OF_MONTH);
- if (temp < 10) {
- buffer.append("0");
- }
- buffer.append(temp);
- buffer.append("T");
- temp = dateHeader.get(Calendar.HOUR_OF_DAY);
- if (temp < 10) {
- buffer.append("0");
- }
- buffer.append(temp);
- temp = dateHeader.get(Calendar.MINUTE);
- if (temp < 10) {
- buffer.append("0");
- }
- buffer.append(temp);
- temp = dateHeader.get(Calendar.SECOND);
- if (temp < 10) {
- buffer.append("0");
- }
- buffer.append(temp);
-
- if (dateHeader.getTimeZone().getID().equals("UTC")) {
- buffer.append("Z");
- }
-
- try {
- value = buffer.toString().getBytes("ISO8859_1");
- } catch (UnsupportedEncodingException e) {
- throw e;
- }
-
- length = value.length + 3;
- lengthArray[0] = (byte)(255 & (length >> 8));
- lengthArray[1] = (byte)(255 & length);
- out.write(HeaderSet.TIME_ISO_8601);
- out.write(lengthArray);
- out.write(value);
- if (nullOut) {
- headImpl.setHeader(HeaderSet.TIME_ISO_8601, null);
- }
- }
-
- // Time 4 Byte Header
- dateHeader = (Calendar)headImpl.getHeader(HeaderSet.TIME_4_BYTE);
- if (dateHeader != null) {
- out.write(HeaderSet.TIME_4_BYTE);
-
- /*
- * Need to call getTime() twice. The first call will return
- * a java.util.Date object. The second call returns the number
- * of milliseconds since January 1, 1970. We need to convert
- * it to seconds since the TIME_4_BYTE expects the number of
- * seconds since January 1, 1970.
- */
- value = ObexHelper.convertToByteArray(dateHeader.getTime().getTime() / 1000L);
- out.write(value);
- if (nullOut) {
- headImpl.setHeader(HeaderSet.TIME_4_BYTE, null);
- }
- }
-
- // Description Header
- stringHeader = (String)headImpl.getHeader(HeaderSet.DESCRIPTION);
- if (stringHeader != null) {
- out.write((byte)HeaderSet.DESCRIPTION);
- value = ObexHelper.convertToUnicodeByteArray(stringHeader);
- length = value.length + 3;
- lengthArray[0] = (byte)(255 & (length >> 8));
- lengthArray[1] = (byte)(255 & length);
- out.write(lengthArray);
- out.write(value);
- if (nullOut) {
- headImpl.setHeader(HeaderSet.DESCRIPTION, null);
- }
- }
-
- // Target Header
- value = (byte[])headImpl.getHeader(HeaderSet.TARGET);
- if (value != null) {
- out.write((byte)HeaderSet.TARGET);
- length = value.length + 3;
- lengthArray[0] = (byte)(255 & (length >> 8));
- lengthArray[1] = (byte)(255 & length);
- out.write(lengthArray);
- out.write(value);
- if (nullOut) {
- headImpl.setHeader(HeaderSet.TARGET, null);
- }
- }
-
- // HTTP Header
- value = (byte[])headImpl.getHeader(HeaderSet.HTTP);
- if (value != null) {
- out.write((byte)HeaderSet.HTTP);
- length = value.length + 3;
- lengthArray[0] = (byte)(255 & (length >> 8));
- lengthArray[1] = (byte)(255 & length);
- out.write(lengthArray);
- out.write(value);
- if (nullOut) {
- headImpl.setHeader(HeaderSet.HTTP, null);
- }
- }
-
- // Who Header
- value = (byte[])headImpl.getHeader(HeaderSet.WHO);
- if (value != null) {
- out.write((byte)HeaderSet.WHO);
- length = value.length + 3;
- lengthArray[0] = (byte)(255 & (length >> 8));
- lengthArray[1] = (byte)(255 & length);
- out.write(lengthArray);
- out.write(value);
- if (nullOut) {
- headImpl.setHeader(HeaderSet.WHO, null);
- }
- }
-
- // Connection ID Header
- value = (byte[])headImpl.getHeader(HeaderSet.APPLICATION_PARAMETER);
- if (value != null) {
- out.write((byte)HeaderSet.APPLICATION_PARAMETER);
- length = value.length + 3;
- lengthArray[0] = (byte)(255 & (length >> 8));
- lengthArray[1] = (byte)(255 & length);
- out.write(lengthArray);
- out.write(value);
- if (nullOut) {
- headImpl.setHeader(HeaderSet.APPLICATION_PARAMETER, null);
- }
- }
-
- // Object Class Header
- value = (byte[])headImpl.getHeader(HeaderSet.OBJECT_CLASS);
- if (value != null) {
- out.write((byte)HeaderSet.OBJECT_CLASS);
- length = value.length + 3;
- lengthArray[0] = (byte)(255 & (length >> 8));
- lengthArray[1] = (byte)(255 & length);
- out.write(lengthArray);
- out.write(value);
- if (nullOut) {
- headImpl.setHeader(HeaderSet.OBJECT_CLASS, null);
- }
- }
-
- // Check User Defined Headers
- for (int i = 0; i < 16; i++) {
-
- //Unicode String Header
- stringHeader = (String)headImpl.getHeader(i + 0x30);
- if (stringHeader != null) {
- out.write((byte)i + 0x30);
- value = ObexHelper.convertToUnicodeByteArray(stringHeader);
- length = value.length + 3;
- lengthArray[0] = (byte)(255 & (length >> 8));
- lengthArray[1] = (byte)(255 & length);
- out.write(lengthArray);
- out.write(value);
- if (nullOut) {
- headImpl.setHeader(i + 0x30, null);
- }
- }
-
- // Byte Sequence Header
- value = (byte[])headImpl.getHeader(i + 0x70);
- if (value != null) {
- out.write((byte)i + 0x70);
- length = value.length + 3;
- lengthArray[0] = (byte)(255 & (length >> 8));
- lengthArray[1] = (byte)(255 & length);
- out.write(lengthArray);
- out.write(value);
- if (nullOut) {
- headImpl.setHeader(i + 0x70, null);
- }
- }
-
- // Byte Header
- byteHeader = (Byte)headImpl.getHeader(i + 0xB0);
- if (byteHeader != null) {
- out.write((byte)i + 0xB0);
- out.write(byteHeader.byteValue());
- if (nullOut) {
- headImpl.setHeader(i + 0xB0, null);
- }
- }
-
- // Integer header
- intHeader = (Long)headImpl.getHeader(i + 0xF0);
- if (intHeader != null) {
- out.write((byte)i + 0xF0);
- out.write(ObexHelper.convertToByteArray(intHeader.longValue()));
- if (nullOut) {
- headImpl.setHeader(i + 0xF0, null);
- }
- }
- }
-
- // Add the authentication challenge header
- if (headImpl.mAuthChall != null) {
- out.write((byte)HeaderSet.AUTH_CHALLENGE);
- length = headImpl.mAuthChall.length + 3;
- lengthArray[0] = (byte)(255 & (length >> 8));
- lengthArray[1] = (byte)(255 & length);
- out.write(lengthArray);
- out.write(headImpl.mAuthChall);
- if (nullOut) {
- headImpl.mAuthChall = null;
- }
- }
-
- // Add the authentication response header
- if (headImpl.mAuthResp != null) {
- out.write((byte)HeaderSet.AUTH_RESPONSE);
- length = headImpl.mAuthResp.length + 3;
- lengthArray[0] = (byte)(255 & (length >> 8));
- lengthArray[1] = (byte)(255 & length);
- out.write(lengthArray);
- out.write(headImpl.mAuthResp);
- if (nullOut) {
- headImpl.mAuthResp = null;
- }
- }
-
- // TODO:
- // If the SRM and SRMP header is in use, they must be send in the same OBEX packet
- // But the current structure of the obex code cannot handle this, and therefore
- // it makes sense to put them in the tail of the headers, since we then reduce the
- // chance of enabling SRM to soon. The down side is that SRM cannot be used while
- // transferring non-body headers
-
- // Add the SRM header
- byteHeader = (Byte)headImpl.getHeader(HeaderSet.SINGLE_RESPONSE_MODE);
- if (byteHeader != null) {
- out.write((byte)HeaderSet.SINGLE_RESPONSE_MODE);
- out.write(byteHeader.byteValue());
- if (nullOut) {
- headImpl.setHeader(HeaderSet.SINGLE_RESPONSE_MODE, null);
- }
- }
-
- // Add the SRM parameter header
- byteHeader = (Byte)headImpl.getHeader(HeaderSet.SINGLE_RESPONSE_MODE_PARAMETER);
- if (byteHeader != null) {
- out.write((byte)HeaderSet.SINGLE_RESPONSE_MODE_PARAMETER);
- out.write(byteHeader.byteValue());
- if (nullOut) {
- headImpl.setHeader(HeaderSet.SINGLE_RESPONSE_MODE_PARAMETER, null);
- }
- }
-
- } catch (IOException e) {
- } finally {
- result = out.toByteArray();
- try {
- out.close();
- } catch (Exception ex) {
- }
- }
-
- return result;
-
- }
-
- /**
- * Determines where the maximum divide is between headers. This method is
- * used by put and get operations to separate headers to a size that meets
- * the max packet size allowed.
- * @param headerArray the headers to separate
- * @param start the starting index to search
- * @param maxSize the maximum size of a packet
- * @return the index of the end of the header block to send or -1 if the
- * header could not be divided because the header is too large
- */
- public static int findHeaderEnd(byte[] headerArray, int start, int maxSize) {
-
- int fullLength = 0;
- int lastLength = -1;
- int index = start;
- int length = 0;
-
- // TODO: Ensure SRM and SRMP headers are not split into two OBEX packets
-
- while ((fullLength < maxSize) && (index < headerArray.length)) {
- int headerID = (headerArray[index] < 0 ? headerArray[index] + 256 : headerArray[index]);
- lastLength = fullLength;
-
- switch (headerID & (0xC0)) {
-
- case 0x00:
- // Fall through
- case 0x40:
-
- index++;
- length = (headerArray[index] < 0 ? headerArray[index] + 256
- : headerArray[index]);
- length = length << 8;
- index++;
- length += (headerArray[index] < 0 ? headerArray[index] + 256
- : headerArray[index]);
- length -= 3;
- index++;
- index += length;
- fullLength += length + 3;
- break;
-
- case 0x80:
-
- index++;
- index++;
- fullLength += 2;
- break;
-
- case 0xC0:
-
- index += 5;
- fullLength += 5;
- break;
-
- }
-
- }
-
- /*
- * Determine if this is the last header or not
- */
- if (lastLength == 0) {
- /*
- * Since this is the last header, check to see if the size of this
- * header is less then maxSize. If it is, return the length of the
- * header, otherwise return -1. The length of the header is
- * returned since it would be the start of the next header
- */
- if (fullLength < maxSize) {
- return headerArray.length;
- } else {
- return -1;
- }
- } else {
- return lastLength + start;
- }
- }
-
- /**
- * Converts the byte array to a long.
- * @param b the byte array to convert to a long
- * @return the byte array as a long
- */
- public static long convertToLong(byte[] b) {
- long result = 0;
- long value = 0;
- long power = 0;
-
- for (int i = (b.length - 1); i >= 0; i--) {
- value = b[i];
- if (value < 0) {
- value += 256;
- }
-
- result = result | (value << power);
- power += 8;
- }
-
- return result;
- }
-
- /**
- * Converts the long to a 4 byte array. The long must be non negative.
- * @param l the long to convert
- * @return a byte array that is the same as the long
- */
- public static byte[] convertToByteArray(long l) {
- byte[] b = new byte[4];
-
- b[0] = (byte)(255 & (l >> 24));
- b[1] = (byte)(255 & (l >> 16));
- b[2] = (byte)(255 & (l >> 8));
- b[3] = (byte)(255 & l);
-
- return b;
- }
-
- /**
- * Converts the String to a UNICODE byte array. It will also add the ending
- * null characters to the end of the string.
- * @param s the string to convert
- * @return the unicode byte array of the string
- */
- public static byte[] convertToUnicodeByteArray(String s) {
- if (s == null) {
- return null;
- }
-
- char c[] = s.toCharArray();
- byte[] result = new byte[(c.length * 2) + 2];
- for (int i = 0; i < c.length; i++) {
- result[(i * 2)] = (byte)(c[i] >> 8);
- result[((i * 2) + 1)] = (byte)c[i];
- }
-
- // Add the UNICODE null character
- result[result.length - 2] = 0;
- result[result.length - 1] = 0;
-
- return result;
- }
-
- /**
- * Retrieves the value from the byte array for the tag value specified. The
- * array should be of the form Tag - Length - Value triplet.
- * @param tag the tag to retrieve from the byte array
- * @param triplet the byte sequence containing the tag length value form
- * @return the value of the specified tag
- */
- public static byte[] getTagValue(byte tag, byte[] triplet) {
-
- int index = findTag(tag, triplet);
- if (index == -1) {
- return null;
- }
-
- index++;
- int length = triplet[index] & 0xFF;
-
- byte[] result = new byte[length];
- index++;
- System.arraycopy(triplet, index, result, 0, length);
-
- return result;
- }
-
- /**
- * Finds the index that starts the tag value pair in the byte array provide.
- * @param tag the tag to look for
- * @param value the byte array to search
- * @return the starting index of the tag or -1 if the tag could not be found
- */
- public static int findTag(byte tag, byte[] value) {
- int length = 0;
-
- if (value == null) {
- return -1;
- }
-
- int index = 0;
-
- while ((index < value.length) && (value[index] != tag)) {
- length = value[index + 1] & 0xFF;
- index += length + 2;
- }
-
- if (index >= value.length) {
- return -1;
- }
-
- return index;
- }
-
- /**
- * Converts the byte array provided to a unicode string.
- * @param b the byte array to convert to a string
- * @param includesNull determine if the byte string provided contains the
- * UNICODE null character at the end or not; if it does, it will be
- * removed
- * @return a Unicode string
- * @throws IllegalArgumentException if the byte array has an odd length
- */
- public static String convertToUnicode(byte[] b, boolean includesNull) {
- if (b == null || b.length == 0) {
- return null;
- }
- int arrayLength = b.length;
- if (!((arrayLength % 2) == 0)) {
- throw new IllegalArgumentException("Byte array not of a valid form");
- }
- arrayLength = (arrayLength >> 1);
- if (includesNull) {
- arrayLength -= 1;
- }
-
- char[] c = new char[arrayLength];
- for (int i = 0; i < arrayLength; i++) {
- int upper = b[2 * i];
- int lower = b[(2 * i) + 1];
- if (upper < 0) {
- upper += 256;
- }
- if (lower < 0) {
- lower += 256;
- }
- // If upper and lower both equal 0, it should be the end of string.
- // Ignore left bytes from array to avoid potential issues
- if (upper == 0 && lower == 0) {
- return new String(c, 0, i);
- }
-
- c[i] = (char)((upper << 8) | lower);
- }
-
- return new String(c);
- }
-
- /**
- * Compute the MD5 hash of the byte array provided. Does not accumulate
- * input.
- * @param in the byte array to hash
- * @return the MD5 hash of the byte array
- */
- public static byte[] computeMd5Hash(byte[] in) {
- try {
- MessageDigest md5 = MessageDigest.getInstance("MD5");
- return md5.digest(in);
- } catch (NoSuchAlgorithmException e) {
- throw new RuntimeException(e);
- }
- }
-
- /**
- * Computes an authentication challenge header.
- * @param nonce the challenge that will be provided to the peer; the
- * challenge must be 16 bytes long
- * @param realm a short description that describes what password to use
- * @param access if <code>true</code> then full access will be granted if
- * successful; if <code>false</code> then read only access will be
- * granted if successful
- * @param userID if <code>true</code>, a user ID is required in the reply;
- * if <code>false</code>, no user ID is required
- * @throws IllegalArgumentException if the challenge is not 16 bytes long;
- * if the realm can not be encoded in less then 255 bytes
- * @throws IOException if the encoding scheme ISO 8859-1 is not supported
- */
- public static byte[] computeAuthenticationChallenge(byte[] nonce, String realm, boolean access,
- boolean userID) throws IOException {
- byte[] authChall = null;
-
- if (nonce.length != 16) {
- throw new IllegalArgumentException("Nonce must be 16 bytes long");
- }
-
- /*
- * The authentication challenge is a byte sequence of the following form
- * byte 0: 0x00 - the tag for the challenge
- * byte 1: 0x10 - the length of the challenge; must be 16
- * byte 2-17: the authentication challenge
- * byte 18: 0x01 - the options tag; this is optional in the spec, but
- * we are going to include it in every message
- * byte 19: 0x01 - length of the options; must be 1
- * byte 20: the value of the options; bit 0 is set if user ID is
- * required; bit 1 is set if access mode is read only
- * byte 21: 0x02 - the tag for authentication realm; only included if
- * an authentication realm is specified
- * byte 22: the length of the authentication realm; only included if
- * the authentication realm is specified
- * byte 23: the encoding scheme of the authentication realm; we will use
- * the ISO 8859-1 encoding scheme since it is part of the KVM
- * byte 24 & up: the realm if one is specified.
- */
- if (realm == null) {
- authChall = new byte[21];
- } else {
- if (realm.length() >= 255) {
- throw new IllegalArgumentException("Realm must be less then 255 bytes");
- }
- authChall = new byte[24 + realm.length()];
- authChall[21] = 0x02;
- authChall[22] = (byte)(realm.length() + 1);
- authChall[23] = 0x01; // ISO 8859-1 Encoding
- System.arraycopy(realm.getBytes("ISO8859_1"), 0, authChall, 24, realm.length());
- }
-
- // Include the nonce field in the header
- authChall[0] = 0x00;
- authChall[1] = 0x10;
- System.arraycopy(nonce, 0, authChall, 2, 16);
-
- // Include the options header
- authChall[18] = 0x01;
- authChall[19] = 0x01;
- authChall[20] = 0x00;
-
- if (!access) {
- authChall[20] = (byte)(authChall[20] | 0x02);
- }
- if (userID) {
- authChall[20] = (byte)(authChall[20] | 0x01);
- }
-
- return authChall;
- }
-
- /**
- * Return the maximum allowed OBEX packet to transmit.
- * OBEX packets transmitted must be smaller than this value.
- * @param transport Reference to the ObexTransport in use.
- * @return the maximum allowed OBEX packet to transmit
- */
- public static int getMaxTxPacketSize(ObexTransport transport) {
- int size = transport.getMaxTransmitPacketSize();
- return validateMaxPacketSize(size);
- }
-
- /**
- * Return the maximum allowed OBEX packet to receive - used in OBEX connect.
- * @param transport
- * @return he maximum allowed OBEX packet to receive
- */
- public static int getMaxRxPacketSize(ObexTransport transport) {
- int size = transport.getMaxReceivePacketSize();
- return validateMaxPacketSize(size);
- }
-
- private static int validateMaxPacketSize(int size) {
- if (VDBG && (size > MAX_PACKET_SIZE_INT)) {
- Log.w(TAG, "The packet size supported for the connection (" + size + ") is larger"
- + " than the configured OBEX packet size: " + MAX_PACKET_SIZE_INT);
- }
- if (size != -1 && size < MAX_PACKET_SIZE_INT) {
- if (size < LOWER_LIMIT_MAX_PACKET_SIZE) {
- throw new IllegalArgumentException(size + " is less that the lower limit: "
- + LOWER_LIMIT_MAX_PACKET_SIZE);
- }
- return size;
- }
- return MAX_PACKET_SIZE_INT;
- }
-}
diff --git a/obex/javax/obex/ObexSession.java b/obex/javax/obex/ObexSession.java
deleted file mode 100644
index 542b9c8..0000000
--- a/obex/javax/obex/ObexSession.java
+++ /dev/null
@@ -1,224 +0,0 @@
-/*
- * Copyright (c) 2008-2009, Motorola, Inc.
- *
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * - Redistributions of source code must retain the above copyright notice,
- * this list of conditions and the following disclaimer.
- *
- * - Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- *
- * - Neither the name of the Motorola, Inc. nor the names of its contributors
- * may be used to endorse or promote products derived from this software
- * without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
- * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
- * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
- * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
- * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGE.
- */
-
-package javax.obex;
-
-import java.io.IOException;
-
-import android.util.Log;
-
-/**
- * The <code>ObexSession</code> interface characterizes the term
- * "OBEX Connection" as defined in the IrDA Object Exchange Protocol v1.2, which
- * could be the server-side view of an OBEX connection, or the client-side view
- * of the same connection, which is established by server's accepting of a
- * client issued "CONNECT".
- * <P>
- * This interface serves as the common super class for
- * <CODE>ClientSession</CODE> and <CODE>ServerSession</CODE>.
- * @hide
- */
-public class ObexSession {
-
- private static final String TAG = "ObexSession";
- private static final boolean V = ObexHelper.VDBG;
-
- protected Authenticator mAuthenticator;
-
- protected byte[] mChallengeDigest;
-
- /**
- * Called when the server received an authentication challenge header. This
- * will cause the authenticator to handle the authentication challenge.
- * @param header the header with the authentication challenge
- * @return <code>true</code> if the last request should be resent;
- * <code>false</code> if the last request should not be resent
- * @throws IOException
- */
- public boolean handleAuthChall(HeaderSet header) throws IOException {
- if (mAuthenticator == null) {
- return false;
- }
-
- /*
- * An authentication challenge is made up of one required and two
- * optional tag length value triplets. The tag 0x00 is required to be in
- * the authentication challenge and it represents the challenge digest
- * that was received. The tag 0x01 is the options tag. This tag tracks
- * if user ID is required and if full access will be granted. The tag
- * 0x02 is the realm, which provides a description of which user name
- * and password to use.
- */
- byte[] challenge = ObexHelper.getTagValue((byte)0x00, header.mAuthChall);
- byte[] option = ObexHelper.getTagValue((byte)0x01, header.mAuthChall);
- byte[] description = ObexHelper.getTagValue((byte)0x02, header.mAuthChall);
-
- String realm = null;
- if (description != null) {
- byte[] realmString = new byte[description.length - 1];
- System.arraycopy(description, 1, realmString, 0, realmString.length);
-
- switch (description[0] & 0xFF) {
-
- case ObexHelper.OBEX_AUTH_REALM_CHARSET_ASCII:
- // ASCII encoding
- // Fall through
- case ObexHelper.OBEX_AUTH_REALM_CHARSET_ISO_8859_1:
- // ISO-8859-1 encoding
- try {
- realm = new String(realmString, "ISO8859_1");
- } catch (Exception e) {
- throw new IOException("Unsupported Encoding Scheme");
- }
- break;
-
- case ObexHelper.OBEX_AUTH_REALM_CHARSET_UNICODE:
- // UNICODE Encoding
- realm = ObexHelper.convertToUnicode(realmString, false);
- break;
-
- default:
- throw new IOException("Unsupported Encoding Scheme");
- }
- }
-
- boolean isUserIDRequired = false;
- boolean isFullAccess = true;
- if (option != null) {
- if ((option[0] & 0x01) != 0) {
- isUserIDRequired = true;
- }
-
- if ((option[0] & 0x02) != 0) {
- isFullAccess = false;
- }
- }
-
- PasswordAuthentication result = null;
- header.mAuthChall = null;
-
- try {
- result = mAuthenticator
- .onAuthenticationChallenge(realm, isUserIDRequired, isFullAccess);
- } catch (Exception e) {
- if (V) Log.d(TAG, "Exception occured - returning false", e);
- return false;
- }
-
- /*
- * If no password is provided then we not resent the request
- */
- if (result == null) {
- return false;
- }
-
- byte[] password = result.getPassword();
- if (password == null) {
- return false;
- }
-
- byte[] userName = result.getUserName();
-
- /*
- * Create the authentication response header. It includes 1 required and
- * 2 option tag length value triples. The required triple has a tag of
- * 0x00 and is the response digest. The first optional tag is 0x01 and
- * represents the user ID. If no user ID is provided, then no user ID
- * will be sent. The second optional tag is 0x02 and is the challenge
- * that was received. This will always be sent
- */
- if (userName != null) {
- header.mAuthResp = new byte[38 + userName.length];
- header.mAuthResp[36] = (byte)0x01;
- header.mAuthResp[37] = (byte)userName.length;
- System.arraycopy(userName, 0, header.mAuthResp, 38, userName.length);
- } else {
- header.mAuthResp = new byte[36];
- }
-
- // Create the secret String
- byte[] digest = new byte[challenge.length + password.length + 1];
- System.arraycopy(challenge, 0, digest, 0, challenge.length);
- // Insert colon between challenge and password
- digest[challenge.length] = (byte)0x3A;
- System.arraycopy(password, 0, digest, challenge.length + 1, password.length);
-
- // Add the Response Digest
- header.mAuthResp[0] = (byte)0x00;
- header.mAuthResp[1] = (byte)0x10;
-
- System.arraycopy(ObexHelper.computeMd5Hash(digest), 0, header.mAuthResp, 2, 16);
-
- // Add the challenge
- header.mAuthResp[18] = (byte)0x02;
- header.mAuthResp[19] = (byte)0x10;
- System.arraycopy(challenge, 0, header.mAuthResp, 20, 16);
-
- return true;
- }
-
- /**
- * Called when the server received an authentication response header. This
- * will cause the authenticator to handle the authentication response.
- * @param authResp the authentication response
- * @return <code>true</code> if the response passed; <code>false</code> if
- * the response failed
- */
- public boolean handleAuthResp(byte[] authResp) {
- if (mAuthenticator == null) {
- return false;
- }
- // get the correct password from the application
- byte[] correctPassword = mAuthenticator.onAuthenticationResponse(ObexHelper.getTagValue(
- (byte)0x01, authResp));
- if (correctPassword == null) {
- return false;
- }
-
- byte[] temp = new byte[correctPassword.length + 16];
-
- System.arraycopy(mChallengeDigest, 0, temp, 0, 16);
- System.arraycopy(correctPassword, 0, temp, 16, correctPassword.length);
-
- byte[] correctResponse = ObexHelper.computeMd5Hash(temp);
- byte[] actualResponse = ObexHelper.getTagValue((byte)0x00, authResp);
-
- // compare the MD5 hash array .
- for (int i = 0; i < 16; i++) {
- if (correctResponse[i] != actualResponse[i]) {
- return false;
- }
- }
-
- return true;
- }
-}
diff --git a/obex/javax/obex/ObexTransport.java b/obex/javax/obex/ObexTransport.java
deleted file mode 100644
index 4cef0b3..0000000
--- a/obex/javax/obex/ObexTransport.java
+++ /dev/null
@@ -1,113 +0,0 @@
-/*
- * Copyright (c) 2008-2009, Motorola, Inc.
- *
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * - Redistributions of source code must retain the above copyright notice,
- * this list of conditions and the following disclaimer.
- *
- * - Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- *
- * - Neither the name of the Motorola, Inc. nor the names of its contributors
- * may be used to endorse or promote products derived from this software
- * without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
- * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
- * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
- * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
- * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGE.
- */
-
-package javax.obex;
-
-import java.io.DataInputStream;
-import java.io.DataOutputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
-
-/**
- * The <code>ObexTransport</code> interface defines the underlying transport
- * connection which carries the OBEX protocol( such as TCP, RFCOMM device file
- * exposed by Bluetooth or USB in kernel, RFCOMM socket emulated in Android
- * platform, Irda). This interface provides an abstract layer to be used by the
- * <code>ObexConnection</code>. Each kind of medium shall have its own
- * implementation to wrap and follow the same interface.
- * <P>
- * See section 1.2.2 of IrDA Object Exchange Protocol specification.
- * <P>
- * Different kind of medium may have different construction - for example, the
- * RFCOMM device file medium may be constructed from a file descriptor or simply
- * a string while the TCP medium usually from a socket.
- * @hide
- */
-public interface ObexTransport {
-
- void create() throws IOException;
-
- void listen() throws IOException;
-
- void close() throws IOException;
-
- void connect() throws IOException;
-
- void disconnect() throws IOException;
-
- InputStream openInputStream() throws IOException;
-
- OutputStream openOutputStream() throws IOException;
-
- DataInputStream openDataInputStream() throws IOException;
-
- DataOutputStream openDataOutputStream() throws IOException;
-
- /**
- * Must return the maximum allowed OBEX packet that can be sent over
- * the transport. For L2CAP this will be the Max SDU reported by the
- * peer device.
- * The returned value will be used to set the outgoing OBEX packet
- * size. Therefore this value shall not change.
- * For RFCOMM or other transport types where the OBEX packets size
- * is unrelated to the transport packet size, return -1;
- * Exception can be made (like PBAP transport) with a smaller value
- * to avoid bad effect on other profiles using the RFCOMM;
- * @return the maximum allowed OBEX packet that can be send over
- * the transport. Or -1 in case of don't care.
- */
- int getMaxTransmitPacketSize();
-
- /**
- * Must return the maximum allowed OBEX packet that can be received over
- * the transport. For L2CAP this will be the Max SDU configured for the
- * L2CAP channel.
- * The returned value will be used to validate the incoming packet size
- * values.
- * For RFCOMM or other transport types where the OBEX packets size
- * is unrelated to the transport packet size, return -1;
- * @return the maximum allowed OBEX packet that can be send over
- * the transport. Or -1 in case of don't care.
- */
- int getMaxReceivePacketSize();
-
- /**
- * Shall return true if the transport in use supports SRM.
- * @return
- * <code>true</code> if SRM operation is supported, and is to be enabled.
- * <code>false</code> if SRM operations are not supported, or should not be used.
- */
- boolean isSrmSupported();
-
-
-}
diff --git a/obex/javax/obex/Operation.java b/obex/javax/obex/Operation.java
deleted file mode 100644
index 5b4d5ac..0000000
--- a/obex/javax/obex/Operation.java
+++ /dev/null
@@ -1,183 +0,0 @@
-/*
- * Copyright (c) 2008-2009, Motorola, Inc.
- *
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * - Redistributions of source code must retain the above copyright notice,
- * this list of conditions and the following disclaimer.
- *
- * - Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- *
- * - Neither the name of the Motorola, Inc. nor the names of its contributors
- * may be used to endorse or promote products derived from this software
- * without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
- * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
- * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
- * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
- * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGE.
- */
-
-package javax.obex;
-
-import java.io.DataInputStream;
-import java.io.DataOutputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
-
-/**
- * The <code>Operation</code> interface provides ways to manipulate a single
- * OBEX PUT or GET operation. The implementation of this interface sends OBEX
- * packets as they are built. If during the operation the peer in the operation
- * ends the operation, an <code>IOException</code> is thrown on the next read
- * from the input stream, write to the output stream, or call to
- * <code>sendHeaders()</code>.
- * <P>
- * <STRONG>Definition of methods inherited from <code>ContentConnection</code>
- * </STRONG>
- * <P>
- * <code>getEncoding()</code> will always return <code>null</code>. <BR>
- * <code>getLength()</code> will return the length specified by the OBEX Length
- * header or -1 if the OBEX Length header was not included. <BR>
- * <code>getType()</code> will return the value specified in the OBEX Type
- * header or <code>null</code> if the OBEX Type header was not included.<BR>
- * <P>
- * <STRONG>How Headers are Handled</STRONG>
- * <P>
- * As headers are received, they may be retrieved through the
- * <code>getReceivedHeaders()</code> method. If new headers are set during the
- * operation, the new headers will be sent during the next packet exchange.
- * <P>
- * <STRONG>PUT example</STRONG>
- * <P>
- * <PRE>
- * void putObjectViaOBEX(ClientSession conn, HeaderSet head, byte[] obj) throws IOException {
- * // Include the length header
- * head.setHeader(head.LENGTH, new Long(obj.length));
- * // Initiate the PUT request
- * Operation op = conn.put(head);
- * // Open the output stream to put the object to it
- * DataOutputStream out = op.openDataOutputStream();
- * // Send the object to the server
- * out.write(obj);
- * // End the transaction
- * out.close();
- * op.close();
- * }
- * </PRE>
- * <P>
- * <STRONG>GET example</STRONG>
- * <P>
- * <PRE>
- * byte[] getObjectViaOBEX(ClientSession conn, HeaderSet head) throws IOException {
- * // Send the initial GET request to the server
- * Operation op = conn.get(head);
- * // Retrieve the length of the object being sent back
- * int length = op.getLength();
- * // Create space for the object
- * byte[] obj = new byte[length];
- * // Get the object from the input stream
- * DataInputStream in = trans.openDataInputStream();
- * in.read(obj);
- * // End the transaction
- * in.close();
- * op.close();
- * return obj;
- * }
- * </PRE>
- *
- * <H3>Client PUT Operation Flow</H3> For PUT operations, a call to
- * <code>close()</code> the <code>OutputStream</code> returned from
- * <code>openOutputStream()</code> or <code>openDataOutputStream()</code> will
- * signal that the request is done. (In OBEX terms, the End-Of-Body header
- * should be sent and the final bit in the request will be set.) At this point,
- * the reply from the server may begin to be processed. A call to
- * <code>getResponseCode()</code> will do an implicit close on the
- * <code>OutputStream</code> and therefore signal that the request is done.
- * <H3>Client GET Operation Flow</H3> For GET operation, a call to
- * <code>openInputStream()</code> or <code>openDataInputStream()</code> will
- * signal that the request is done. (In OBEX terms, the final bit in the request
- * will be set.) A call to <code>getResponseCode()</code> will cause an implicit
- * close on the <code>InputStream</code>. No further data may be read at this
- * point.
- * @hide
- */
-public interface Operation {
-
- /**
- * Sends an ABORT message to the server. By calling this method, the
- * corresponding input and output streams will be closed along with this
- * object. No headers are sent in the abort request. This will end the
- * operation since <code>close()</code> will be called by this method.
- * @throws IOException if the transaction has already ended or if an OBEX
- * server calls this method
- */
- void abort() throws IOException;
-
- /**
- * Returns the headers that have been received during the operation.
- * Modifying the object returned has no effect on the headers that are sent
- * or retrieved.
- * @return the headers received during this <code>Operation</code>
- * @throws IOException if this <code>Operation</code> has been closed
- */
- HeaderSet getReceivedHeader() throws IOException;
-
- /**
- * Specifies the headers that should be sent in the next OBEX message that
- * is sent.
- * @param headers the headers to send in the next message
- * @throws IOException if this <code>Operation</code> has been closed or the
- * transaction has ended and no further messages will be exchanged
- * @throws IllegalArgumentException if <code>headers</code> was not created
- * by a call to <code>ServerRequestHandler.createHeaderSet()</code>
- * or <code>ClientSession.createHeaderSet()</code>
- * @throws NullPointerException if <code>headers</code> if <code>null</code>
- */
- void sendHeaders(HeaderSet headers) throws IOException;
-
- /**
- * Returns the response code received from the server. Response codes are
- * defined in the <code>ResponseCodes</code> class.
- * @see ResponseCodes
- * @return the response code retrieved from the server
- * @throws IOException if an error occurred in the transport layer during
- * the transaction; if this object was created by an OBEX server
- */
- int getResponseCode() throws IOException;
-
- String getEncoding();
-
- long getLength();
-
- int getHeaderLength();
-
- String getType();
-
- InputStream openInputStream() throws IOException;
-
- DataInputStream openDataInputStream() throws IOException;
-
- OutputStream openOutputStream() throws IOException;
-
- DataOutputStream openDataOutputStream() throws IOException;
-
- void close() throws IOException;
-
- int getMaxPacketSize();
-
- public void noBodyHeader();
-}
diff --git a/obex/javax/obex/PasswordAuthentication.java b/obex/javax/obex/PasswordAuthentication.java
deleted file mode 100644
index 326b1ff..0000000
--- a/obex/javax/obex/PasswordAuthentication.java
+++ /dev/null
@@ -1,79 +0,0 @@
-/*
- * Copyright (c) 2008-2009, Motorola, Inc.
- *
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * - Redistributions of source code must retain the above copyright notice,
- * this list of conditions and the following disclaimer.
- *
- * - Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- *
- * - Neither the name of the Motorola, Inc. nor the names of its contributors
- * may be used to endorse or promote products derived from this software
- * without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
- * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
- * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
- * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
- * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGE.
- */
-
-package javax.obex;
-
-/**
- * This class holds user name and password combinations.
- * @hide
- */
-public final class PasswordAuthentication {
-
- private byte[] mUserName;
-
- private final byte[] mPassword;
-
- /**
- * Creates a new <code>PasswordAuthentication</code> with the user name and
- * password provided.
- * @param userName the user name to include; this may be <code>null</code>
- * @param password the password to include in the response
- * @throws NullPointerException if <code>password</code> is
- * <code>null</code>
- */
- public PasswordAuthentication(final byte[] userName, final byte[] password) {
- if (userName != null) {
- mUserName = new byte[userName.length];
- System.arraycopy(userName, 0, mUserName, 0, userName.length);
- }
-
- mPassword = new byte[password.length];
- System.arraycopy(password, 0, mPassword, 0, password.length);
- }
-
- /**
- * Retrieves the user name that was specified in the constructor. The user
- * name may be <code>null</code>.
- * @return the user name
- */
- public byte[] getUserName() {
- return mUserName;
- }
-
- /**
- * Retrieves the password.
- * @return the password
- */
- public byte[] getPassword() {
- return mPassword;
- }
-}
diff --git a/obex/javax/obex/PrivateInputStream.java b/obex/javax/obex/PrivateInputStream.java
deleted file mode 100644
index 5daee72..0000000
--- a/obex/javax/obex/PrivateInputStream.java
+++ /dev/null
@@ -1,181 +0,0 @@
-/*
- * Copyright (c) 2008-2009, Motorola, Inc.
- *
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * - Redistributions of source code must retain the above copyright notice,
- * this list of conditions and the following disclaimer.
- *
- * - Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- *
- * - Neither the name of the Motorola, Inc. nor the names of its contributors
- * may be used to endorse or promote products derived from this software
- * without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
- * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
- * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
- * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
- * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGE.
- */
-
-package javax.obex;
-
-import java.io.InputStream;
-import java.io.IOException;
-
-/**
- * This object provides an input stream to the Operation objects used in this
- * package.
- * @hide
- */
-public final class PrivateInputStream extends InputStream {
-
- private BaseStream mParent;
-
- private byte[] mData;
-
- private int mIndex;
-
- private boolean mOpen;
-
- /**
- * Creates an input stream for the <code>Operation</code> to read from
- * @param p the connection this input stream is for
- */
- public PrivateInputStream(BaseStream p) {
- mParent = p;
- mData = new byte[0];
- mIndex = 0;
- mOpen = true;
- }
-
- /**
- * Returns the number of bytes that can be read (or skipped over) from this
- * input stream without blocking by the next caller of a method for this
- * input stream. The next caller might be the same thread or or another
- * thread.
- * @return the number of bytes that can be read from this input stream
- * without blocking
- * @throws IOException if an I/O error occurs
- */
- @Override
- public synchronized int available() throws IOException {
- ensureOpen();
- return mData.length - mIndex;
- }
-
- /**
- * Reads the next byte of data from the input stream. The value byte is
- * returned as an int in the range 0 to 255. If no byte is available because
- * the end of the stream has been reached, the value -1 is returned. This
- * method blocks until input data is available, the end of the stream is
- * detected, or an exception is thrown.
- * @return the byte read from the input stream or -1 if it reaches the end of
- * stream
- * @throws IOException if an I/O error occurs
- */
- @Override
- public synchronized int read() throws IOException {
- ensureOpen();
- while (mData.length == mIndex) {
- if (!mParent.continueOperation(true, true)) {
- return -1;
- }
- }
- return (mData[mIndex++] & 0xFF);
- }
-
- @Override
- public int read(byte[] b) throws IOException {
- return read(b, 0, b.length);
- }
-
- @Override
- public synchronized int read(byte[] b, int offset, int length) throws IOException {
-
- if (b == null) {
- throw new IOException("buffer is null");
- }
- if ((offset | length) < 0 || length > b.length - offset) {
- throw new ArrayIndexOutOfBoundsException("index outof bound");
- }
- ensureOpen();
-
- int currentDataLength = mData.length - mIndex;
- int remainReadLength = length;
- int offset1 = offset;
- int result = 0;
-
- while (currentDataLength <= remainReadLength) {
- System.arraycopy(mData, mIndex, b, offset1, currentDataLength);
- mIndex += currentDataLength;
- offset1 += currentDataLength;
- result += currentDataLength;
- remainReadLength -= currentDataLength;
-
- if (!mParent.continueOperation(true, true)) {
- return result == 0 ? -1 : result;
- }
- currentDataLength = mData.length - mIndex;
- }
- if (remainReadLength > 0) {
- System.arraycopy(mData, mIndex, b, offset1, remainReadLength);
- mIndex += remainReadLength;
- result += remainReadLength;
- }
- return result;
- }
-
- /**
- * Allows the <code>OperationImpl</code> thread to add body data to the
- * input stream.
- * @param body the data to add to the stream
- * @param start the start of the body to array to copy
- */
- public synchronized void writeBytes(byte[] body, int start) {
-
- int length = (body.length - start) + (mData.length - mIndex);
- byte[] temp = new byte[length];
-
- System.arraycopy(mData, mIndex, temp, 0, mData.length - mIndex);
- System.arraycopy(body, start, temp, mData.length - mIndex, body.length - start);
-
- mData = temp;
- mIndex = 0;
- notifyAll();
- }
-
- /**
- * Verifies that this stream is open
- * @throws IOException if the stream is not open
- */
- private void ensureOpen() throws IOException {
- mParent.ensureOpen();
- if (!mOpen) {
- throw new IOException("Input stream is closed");
- }
- }
-
- /**
- * Closes the input stream. If the input stream is already closed, do
- * nothing.
- * @throws IOException this will never happen
- */
- @Override
- public void close() throws IOException {
- mOpen = false;
- mParent.streamClosed(true);
- }
-}
diff --git a/obex/javax/obex/PrivateOutputStream.java b/obex/javax/obex/PrivateOutputStream.java
deleted file mode 100644
index 713f4ae..0000000
--- a/obex/javax/obex/PrivateOutputStream.java
+++ /dev/null
@@ -1,172 +0,0 @@
-/*
- * Copyright (c) 2008-2009, Motorola, Inc.
- *
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * - Redistributions of source code must retain the above copyright notice,
- * this list of conditions and the following disclaimer.
- *
- * - Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- *
- * - Neither the name of the Motorola, Inc. nor the names of its contributors
- * may be used to endorse or promote products derived from this software
- * without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
- * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
- * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
- * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
- * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGE.
- */
-
-package javax.obex;
-
-import java.io.IOException;
-import java.io.OutputStream;
-import java.io.ByteArrayOutputStream;
-
-/**
- * This object provides an output stream to the Operation objects used in this
- * package.
- * @hide
- */
-public final class PrivateOutputStream extends OutputStream {
-
- private BaseStream mParent;
-
- private ByteArrayOutputStream mArray;
-
- private boolean mOpen;
-
- private int mMaxPacketSize;
-
- /**
- * Creates an empty <code>PrivateOutputStream</code> to write to.
- * @param p the connection that this stream runs over
- */
- public PrivateOutputStream(BaseStream p, int maxSize) {
- mParent = p;
- mArray = new ByteArrayOutputStream();
- mMaxPacketSize = maxSize;
- mOpen = true;
- }
-
- /**
- * Determines how many bytes have been written to the output stream.
- * @return the number of bytes written to the output stream
- */
- public int size() {
- return mArray.size();
- }
-
- /**
- * Writes the specified byte to this output stream. The general contract for
- * write is that one byte is written to the output stream. The byte to be
- * written is the eight low-order bits of the argument b. The 24 high-order
- * bits of b are ignored.
- * @param b the byte to write
- * @throws IOException if an I/O error occurs
- */
- @Override
- public synchronized void write(int b) throws IOException {
- ensureOpen();
- mParent.ensureNotDone();
- mArray.write(b);
- if (mArray.size() == mMaxPacketSize) {
- mParent.continueOperation(true, false);
- }
- }
-
- @Override
- public void write(byte[] buffer) throws IOException {
- write(buffer, 0, buffer.length);
- }
-
- @Override
- public synchronized void write(byte[] buffer, int offset, int count) throws IOException {
- int offset1 = offset;
- int remainLength = count;
-
- if (buffer == null) {
- throw new IOException("buffer is null");
- }
- if ((offset | count) < 0 || count > buffer.length - offset) {
- throw new IndexOutOfBoundsException("index outof bound");
- }
-
- ensureOpen();
- mParent.ensureNotDone();
- while ((mArray.size() + remainLength) >= mMaxPacketSize) {
- int bufferLeft = mMaxPacketSize - mArray.size();
- mArray.write(buffer, offset1, bufferLeft);
- offset1 += bufferLeft;
- remainLength -= bufferLeft;
- mParent.continueOperation(true, false);
- }
- if (remainLength > 0) {
- mArray.write(buffer, offset1, remainLength);
- }
- }
-
- /**
- * Reads the bytes that have been written to this stream.
- * @param size the size of the array to return
- * @return the byte array that is written
- */
- public synchronized byte[] readBytes(int size) {
- if (mArray.size() > 0) {
- byte[] temp = mArray.toByteArray();
- mArray.reset();
- byte[] result = new byte[size];
- System.arraycopy(temp, 0, result, 0, size);
- if (temp.length != size) {
- mArray.write(temp, size, temp.length - size);
- }
- return result;
- } else {
- return null;
- }
- }
-
- /**
- * Verifies that this stream is open
- * @throws IOException if the stream is not open
- */
- private void ensureOpen() throws IOException {
- mParent.ensureOpen();
- if (!mOpen) {
- throw new IOException("Output stream is closed");
- }
- }
-
- /**
- * Closes the output stream. If the input stream is already closed, do
- * nothing.
- * @throws IOException this will never happen
- */
- @Override
- public void close() throws IOException {
- mOpen = false;
- mParent.streamClosed(false);
- }
-
- /**
- * Determines if the connection is closed
- * @return <code>true</code> if the connection is closed; <code>false</code>
- * if the connection is open
- */
- public boolean isClosed() {
- return !mOpen;
- }
-}
diff --git a/obex/javax/obex/ResponseCodes.java b/obex/javax/obex/ResponseCodes.java
deleted file mode 100644
index a2b9a37..0000000
--- a/obex/javax/obex/ResponseCodes.java
+++ /dev/null
@@ -1,326 +0,0 @@
-/*
- * Copyright (c) 2008-2009, Motorola, Inc.
- *
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * - Redistributions of source code must retain the above copyright notice,
- * this list of conditions and the following disclaimer.
- *
- * - Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- *
- * - Neither the name of the Motorola, Inc. nor the names of its contributors
- * may be used to endorse or promote products derived from this software
- * without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
- * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
- * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
- * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
- * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGE.
- */
-
-package javax.obex;
-
-/**
- * The <code>ResponseCodes</code> class contains the list of valid response
- * codes a server may send to a client.
- * <P>
- * <STRONG>IMPORTANT NOTE</STRONG>
- * <P>
- * The values in this interface represent the values defined in the IrOBEX
- * specification, which is different with the HTTP specification.
- * <P>
- * <code>OBEX_DATABASE_FULL</code> and <code>OBEX_DATABASE_LOCKED</code> require
- * further description since they are not defined in HTTP. The server will send
- * an <code>OBEX_DATABASE_FULL</code> message when the client requests that
- * something be placed into a database but the database is full (cannot take
- * more data). <code>OBEX_DATABASE_LOCKED</code> will be returned when the
- * client wishes to access a database, database table, or database record that
- * has been locked.
- * @hide
- */
-public final class ResponseCodes {
-
- /**
- * Defines the OBEX CONTINUE response code.
- * <P>
- * The value of <code>OBEX_HTTP_CONTINUE</code> is 0x90 (144).
- */
- public static final int OBEX_HTTP_CONTINUE = 0x90;
-
- /**
- * Defines the OBEX SUCCESS response code.
- * <P>
- * The value of <code>OBEX_HTTP_OK</code> is 0xA0 (160).
- */
- public static final int OBEX_HTTP_OK = 0xA0;
-
- /**
- * Defines the OBEX CREATED response code.
- * <P>
- * The value of <code>OBEX_HTTP_CREATED</code> is 0xA1 (161).
- */
- public static final int OBEX_HTTP_CREATED = 0xA1;
-
- /**
- * Defines the OBEX ACCEPTED response code.
- * <P>
- * The value of <code>OBEX_HTTP_ACCEPTED</code> is 0xA2 (162).
- */
- public static final int OBEX_HTTP_ACCEPTED = 0xA2;
-
- /**
- * Defines the OBEX NON-AUTHORITATIVE INFORMATION response code.
- * <P>
- * The value of <code>OBEX_HTTP_NOT_AUTHORITATIVE</code> is 0xA3 (163).
- */
- public static final int OBEX_HTTP_NOT_AUTHORITATIVE = 0xA3;
-
- /**
- * Defines the OBEX NO CONTENT response code.
- * <P>
- * The value of <code>OBEX_HTTP_NO_CONTENT</code> is 0xA4 (164).
- */
- public static final int OBEX_HTTP_NO_CONTENT = 0xA4;
-
- /**
- * Defines the OBEX RESET CONTENT response code.
- * <P>
- * The value of <code>OBEX_HTTP_RESET</code> is 0xA5 (165).
- */
- public static final int OBEX_HTTP_RESET = 0xA5;
-
- /**
- * Defines the OBEX PARTIAL CONTENT response code.
- * <P>
- * The value of <code>OBEX_HTTP_PARTIAL</code> is 0xA6 (166).
- */
- public static final int OBEX_HTTP_PARTIAL = 0xA6;
-
- /**
- * Defines the OBEX MULTIPLE_CHOICES response code.
- * <P>
- * The value of <code>OBEX_HTTP_MULT_CHOICE</code> is 0xB0 (176).
- */
- public static final int OBEX_HTTP_MULT_CHOICE = 0xB0;
-
- /**
- * Defines the OBEX MOVED PERMANENTLY response code.
- * <P>
- * The value of <code>OBEX_HTTP_MOVED_PERM</code> is 0xB1 (177).
- */
- public static final int OBEX_HTTP_MOVED_PERM = 0xB1;
-
- /**
- * Defines the OBEX MOVED TEMPORARILY response code.
- * <P>
- * The value of <code>OBEX_HTTP_MOVED_TEMP</code> is 0xB2 (178).
- */
- public static final int OBEX_HTTP_MOVED_TEMP = 0xB2;
-
- /**
- * Defines the OBEX SEE OTHER response code.
- * <P>
- * The value of <code>OBEX_HTTP_SEE_OTHER</code> is 0xB3 (179).
- */
- public static final int OBEX_HTTP_SEE_OTHER = 0xB3;
-
- /**
- * Defines the OBEX NOT MODIFIED response code.
- * <P>
- * The value of <code>OBEX_HTTP_NOT_MODIFIED</code> is 0xB4 (180).
- */
- public static final int OBEX_HTTP_NOT_MODIFIED = 0xB4;
-
- /**
- * Defines the OBEX USE PROXY response code.
- * <P>
- * The value of <code>OBEX_HTTP_USE_PROXY</code> is 0xB5 (181).
- */
- public static final int OBEX_HTTP_USE_PROXY = 0xB5;
-
- /**
- * Defines the OBEX BAD REQUEST response code.
- * <P>
- * The value of <code>OBEX_HTTP_BAD_REQUEST</code> is 0xC0 (192).
- */
- public static final int OBEX_HTTP_BAD_REQUEST = 0xC0;
-
- /**
- * Defines the OBEX UNAUTHORIZED response code.
- * <P>
- * The value of <code>OBEX_HTTP_UNAUTHORIZED</code> is 0xC1 (193).
- */
- public static final int OBEX_HTTP_UNAUTHORIZED = 0xC1;
-
- /**
- * Defines the OBEX PAYMENT REQUIRED response code.
- * <P>
- * The value of <code>OBEX_HTTP_PAYMENT_REQUIRED</code> is 0xC2 (194).
- */
- public static final int OBEX_HTTP_PAYMENT_REQUIRED = 0xC2;
-
- /**
- * Defines the OBEX FORBIDDEN response code.
- * <P>
- * The value of <code>OBEX_HTTP_FORBIDDEN</code> is 0xC3 (195).
- */
- public static final int OBEX_HTTP_FORBIDDEN = 0xC3;
-
- /**
- * Defines the OBEX NOT FOUND response code.
- * <P>
- * The value of <code>OBEX_HTTP_NOT_FOUND</code> is 0xC4 (196).
- */
- public static final int OBEX_HTTP_NOT_FOUND = 0xC4;
-
- /**
- * Defines the OBEX METHOD NOT ALLOWED response code.
- * <P>
- * The value of <code>OBEX_HTTP_BAD_METHOD</code> is 0xC5 (197).
- */
- public static final int OBEX_HTTP_BAD_METHOD = 0xC5;
-
- /**
- * Defines the OBEX NOT ACCEPTABLE response code.
- * <P>
- * The value of <code>OBEX_HTTP_NOT_ACCEPTABLE</code> is 0xC6 (198).
- */
- public static final int OBEX_HTTP_NOT_ACCEPTABLE = 0xC6;
-
- /**
- * Defines the OBEX PROXY AUTHENTICATION REQUIRED response code.
- * <P>
- * The value of <code>OBEX_HTTP_PROXY_AUTH</code> is 0xC7 (199).
- */
- public static final int OBEX_HTTP_PROXY_AUTH = 0xC7;
-
- /**
- * Defines the OBEX REQUEST TIME OUT response code.
- * <P>
- * The value of <code>OBEX_HTTP_TIMEOUT</code> is 0xC8 (200).
- */
- public static final int OBEX_HTTP_TIMEOUT = 0xC8;
-
- /**
- * Defines the OBEX METHOD CONFLICT response code.
- * <P>
- * The value of <code>OBEX_HTTP_CONFLICT</code> is 0xC9 (201).
- */
- public static final int OBEX_HTTP_CONFLICT = 0xC9;
-
- /**
- * Defines the OBEX METHOD GONE response code.
- * <P>
- * The value of <code>OBEX_HTTP_GONE</code> is 0xCA (202).
- */
- public static final int OBEX_HTTP_GONE = 0xCA;
-
- /**
- * Defines the OBEX METHOD LENGTH REQUIRED response code.
- * <P>
- * The value of <code>OBEX_HTTP_LENGTH_REQUIRED</code> is 0xCB (203).
- */
- public static final int OBEX_HTTP_LENGTH_REQUIRED = 0xCB;
-
- /**
- * Defines the OBEX PRECONDITION FAILED response code.
- * <P>
- * The value of <code>OBEX_HTTP_PRECON_FAILED</code> is 0xCC (204).
- */
- public static final int OBEX_HTTP_PRECON_FAILED = 0xCC;
-
- /**
- * Defines the OBEX REQUESTED ENTITY TOO LARGE response code.
- * <P>
- * The value of <code>OBEX_HTTP_ENTITY_TOO_LARGE</code> is 0xCD (205).
- */
- public static final int OBEX_HTTP_ENTITY_TOO_LARGE = 0xCD;
-
- /**
- * Defines the OBEX REQUESTED URL TOO LARGE response code.
- * <P>
- * The value of <code>OBEX_HTTP_REQ_TOO_LARGE</code> is 0xCE (206).
- */
- public static final int OBEX_HTTP_REQ_TOO_LARGE = 0xCE;
-
- /**
- * Defines the OBEX UNSUPPORTED MEDIA TYPE response code.
- * <P>
- * The value of <code>OBEX_HTTP_UNSUPPORTED_TYPE</code> is 0xCF (207).
- */
- public static final int OBEX_HTTP_UNSUPPORTED_TYPE = 0xCF;
-
- /**
- * Defines the OBEX INTERNAL SERVER ERROR response code.
- * <P>
- * The value of <code>OBEX_HTTP_INTERNAL_ERROR</code> is 0xD0 (208).
- */
- public static final int OBEX_HTTP_INTERNAL_ERROR = 0xD0;
-
- /**
- * Defines the OBEX NOT IMPLEMENTED response code.
- * <P>
- * The value of <code>OBEX_HTTP_NOT_IMPLEMENTED</code> is 0xD1 (209).
- */
- public static final int OBEX_HTTP_NOT_IMPLEMENTED = 0xD1;
-
- /**
- * Defines the OBEX BAD GATEWAY response code.
- * <P>
- * The value of <code>OBEX_HTTP_BAD_GATEWAY</code> is 0xD2 (210).
- */
- public static final int OBEX_HTTP_BAD_GATEWAY = 0xD2;
-
- /**
- * Defines the OBEX SERVICE UNAVAILABLE response code.
- * <P>
- * The value of <code>OBEX_HTTP_UNAVAILABLE</code> is 0xD3 (211).
- */
- public static final int OBEX_HTTP_UNAVAILABLE = 0xD3;
-
- /**
- * Defines the OBEX GATEWAY TIMEOUT response code.
- * <P>
- * The value of <code>OBEX_HTTP_GATEWAY_TIMEOUT</code> is 0xD4 (212).
- */
- public static final int OBEX_HTTP_GATEWAY_TIMEOUT = 0xD4;
-
- /**
- * Defines the OBEX HTTP VERSION NOT SUPPORTED response code.
- * <P>
- * The value of <code>OBEX_HTTP_VERSION</code> is 0xD5 (213).
- */
- public static final int OBEX_HTTP_VERSION = 0xD5;
-
- /**
- * Defines the OBEX DATABASE FULL response code.
- * <P>
- * The value of <code>OBEX_DATABASE_FULL</code> is 0xE0 (224).
- */
- public static final int OBEX_DATABASE_FULL = 0xE0;
-
- /**
- * Defines the OBEX DATABASE LOCKED response code.
- * <P>
- * The value of <code>OBEX_DATABASE_LOCKED</code> is 0xE1 (225).
- */
- public static final int OBEX_DATABASE_LOCKED = 0xE1;
-
- /**
- * Constructor does nothing.
- */
- private ResponseCodes() {
- }
-}
diff --git a/obex/javax/obex/ServerOperation.java b/obex/javax/obex/ServerOperation.java
deleted file mode 100644
index 15ea367..0000000
--- a/obex/javax/obex/ServerOperation.java
+++ /dev/null
@@ -1,861 +0,0 @@
-/* Copyright (c) 2015 The Android Open Source Project
- * Copyright (C) 2015 Samsung LSI
- * Copyright (c) 2008-2009, Motorola, Inc.
- *
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * - Redistributions of source code must retain the above copyright notice,
- * this list of conditions and the following disclaimer.
- *
- * - Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- *
- * - Neither the name of the Motorola, Inc. nor the names of its contributors
- * may be used to endorse or promote products derived from this software
- * without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
- * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
- * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
- * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
- * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGE.
- */
-
-package javax.obex;
-
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.DataInputStream;
-import java.io.OutputStream;
-import java.io.DataOutputStream;
-import java.io.ByteArrayOutputStream;
-
-import android.util.Log;
-
-/**
- * This class implements the Operation interface for server side connections.
- * <P>
- * <STRONG>Request Codes</STRONG> There are four different request codes that
- * are in this class. 0x02 is a PUT request that signals that the request is not
- * complete and requires an additional OBEX packet. 0x82 is a PUT request that
- * says that request is complete. In this case, the server can begin sending the
- * response. The 0x03 is a GET request that signals that the request is not
- * finished. When the server receives a 0x83, the client is signaling the server
- * that it is done with its request. TODO: Extend the ClientOperation and reuse
- * the methods defined TODO: in that class.
- * @hide
- */
-public final class ServerOperation implements Operation, BaseStream {
-
- private static final String TAG = "ServerOperation";
-
- private static final boolean V = ObexHelper.VDBG; // Verbose debugging
-
- public boolean isAborted;
-
- public HeaderSet requestHeader;
-
- public HeaderSet replyHeader;
-
- public boolean finalBitSet;
-
- private InputStream mInput;
-
- private ServerSession mParent;
-
- private int mMaxPacketLength;
-
- private int mResponseSize;
-
- private boolean mClosed;
-
- private boolean mGetOperation;
-
- private PrivateInputStream mPrivateInput;
-
- private PrivateOutputStream mPrivateOutput;
-
- private ObexTransport mTransport;
-
- private boolean mPrivateOutputOpen;
-
- private String mExceptionString;
-
- private ServerRequestHandler mListener;
-
- private boolean mRequestFinished;
-
- private boolean mHasBody;
-
- private boolean mSendBodyHeader = true;
- // Assume SRM disabled - needs to be explicit
- // enabled by client
- private boolean mSrmEnabled = false;
- // A latch - when triggered, there is not way back ;-)
- private boolean mSrmActive = false;
- // Set to true when a SRM enable response have been send
- private boolean mSrmResponseSent = false;
- // keep waiting until final-bit is received in request
- // to handle the case where the SRM enable header is in
- // a different OBEX packet than the SRMP header.
- private boolean mSrmWaitingForRemote = true;
- // Why should we wait? - currently not exposed to apps.
- private boolean mSrmLocalWait = false;
-
- /**
- * Creates new ServerOperation
- * @param p the parent that created this object
- * @param in the input stream to read from
- * @param out the output stream to write to
- * @param request the initial request that was received from the client
- * @param maxSize the max packet size that the client will accept
- * @param listen the listener that is responding to the request
- * @throws IOException if an IO error occurs
- */
- public ServerOperation(ServerSession p, InputStream in, int request, int maxSize,
- ServerRequestHandler listen) throws IOException {
-
- isAborted = false;
- mParent = p;
- mInput = in;
- mMaxPacketLength = maxSize;
- mClosed = false;
- requestHeader = new HeaderSet();
- replyHeader = new HeaderSet();
- mPrivateInput = new PrivateInputStream(this);
- mResponseSize = 3;
- mListener = listen;
- mRequestFinished = false;
- mPrivateOutputOpen = false;
- mHasBody = false;
- ObexPacket packet;
- mTransport = p.getTransport();
-
- /*
- * Determine if this is a PUT request
- */
- if ((request == ObexHelper.OBEX_OPCODE_PUT) ||
- (request == ObexHelper.OBEX_OPCODE_PUT_FINAL)) {
- /*
- * It is a PUT request.
- */
- mGetOperation = false;
-
- /*
- * Determine if the final bit is set
- */
- if ((request & ObexHelper.OBEX_OPCODE_FINAL_BIT_MASK) == 0) {
- finalBitSet = false;
- } else {
- finalBitSet = true;
- mRequestFinished = true;
- }
- } else if ((request == ObexHelper.OBEX_OPCODE_GET) ||
- (request == ObexHelper.OBEX_OPCODE_GET_FINAL)) {
- /*
- * It is a GET request.
- */
- mGetOperation = true;
-
- // For Get request, final bit set is decided by server side logic
- finalBitSet = false;
-
- if (request == ObexHelper.OBEX_OPCODE_GET_FINAL) {
- mRequestFinished = true;
- }
- } else {
- throw new IOException("ServerOperation can not handle such request");
- }
-
- packet = ObexPacket.read(request, mInput);
-
- /*
- * Determine if the packet length is larger than this device can receive
- */
- if (packet.mLength > ObexHelper.getMaxRxPacketSize(mTransport)) {
- mParent.sendResponse(ResponseCodes.OBEX_HTTP_REQ_TOO_LARGE, null);
- throw new IOException("Packet received was too large. Length: "
- + packet.mLength + " maxLength: " + ObexHelper.getMaxRxPacketSize(mTransport));
- }
-
- /*
- * Determine if any headers were sent in the initial request
- */
- if (packet.mLength > 3) {
- if(!handleObexPacket(packet)) {
- return;
- }
- /* Don't Pre-Send continue when Remote requested for SRM
- * Let the Application confirm.
- */
- if (V) Log.v(TAG, "Get App confirmation if SRM ENABLED case: " + mSrmEnabled
- + " not hasBody case: " + mHasBody);
- if (!mHasBody && !mSrmEnabled) {
- while ((!mGetOperation) && (!finalBitSet)) {
- sendReply(ResponseCodes.OBEX_HTTP_CONTINUE);
- if (mPrivateInput.available() > 0) {
- break;
- }
- }
- }
- }
- /* Don't Pre-Send continue when Remote requested for SRM
- * Let the Application confirm.
- */
- if (V) Log.v(TAG, "Get App confirmation if SRM ENABLED case: " + mSrmEnabled
- + " not finalPacket: " + finalBitSet + " not GETOp Case: " + mGetOperation);
- while ((!mSrmEnabled) && (!mGetOperation) && (!finalBitSet)
- && (mPrivateInput.available() == 0)) {
- sendReply(ResponseCodes.OBEX_HTTP_CONTINUE);
- if (mPrivateInput.available() > 0) {
- break;
- }
- }
-
- // wait for get request finished !!!!
- while (mGetOperation && !mRequestFinished) {
- sendReply(ResponseCodes.OBEX_HTTP_CONTINUE);
- }
- }
-
- /**
- * Parse headers and update member variables
- * @param packet the received obex packet
- * @return false for failing authentication - and a OBEX_HTTP_UNAUTHORIZED
- * response have been send. Else true.
- * @throws IOException
- */
- private boolean handleObexPacket(ObexPacket packet) throws IOException {
- byte[] body = updateRequestHeaders(packet);
-
- if (body != null) {
- mHasBody = true;
- }
- if (mListener.getConnectionId() != -1 && requestHeader.mConnectionID != null) {
- mListener.setConnectionId(ObexHelper
- .convertToLong(requestHeader.mConnectionID));
- } else {
- mListener.setConnectionId(1);
- }
-
- if (requestHeader.mAuthResp != null) {
- if (!mParent.handleAuthResp(requestHeader.mAuthResp)) {
- mExceptionString = "Authentication Failed";
- mParent.sendResponse(ResponseCodes.OBEX_HTTP_UNAUTHORIZED, null);
- mClosed = true;
- requestHeader.mAuthResp = null;
- return false;
- }
- requestHeader.mAuthResp = null;
- }
-
- if (requestHeader.mAuthChall != null) {
- mParent.handleAuthChall(requestHeader);
- // send the auhtResp to the client
- replyHeader.mAuthResp = new byte[requestHeader.mAuthResp.length];
- System.arraycopy(requestHeader.mAuthResp, 0, replyHeader.mAuthResp, 0,
- replyHeader.mAuthResp.length);
- requestHeader.mAuthResp = null;
- requestHeader.mAuthChall = null;
- }
-
- if (body != null) {
- mPrivateInput.writeBytes(body, 1);
- }
- return true;
- }
-
- /**
- * Update the request header set, and sniff on SRM headers to update local state.
- * @param data the OBEX packet data
- * @return any bytes in a body/end-of-body header returned by {@link ObexHelper.updateHeaderSet}
- * @throws IOException
- */
- private byte[] updateRequestHeaders(ObexPacket packet) throws IOException {
- byte[] body = null;
- if (packet.mPayload != null) {
- body = ObexHelper.updateHeaderSet(requestHeader, packet.mPayload);
- }
- Byte srmMode = (Byte)requestHeader.getHeader(HeaderSet.SINGLE_RESPONSE_MODE);
- if(mTransport.isSrmSupported() && srmMode != null
- && srmMode == ObexHelper.OBEX_SRM_ENABLE) {
- mSrmEnabled = true;
- if(V) Log.d(TAG,"SRM is now ENABLED (but not active) for this operation");
- }
- checkForSrmWait(packet.mHeaderId);
- if((!mSrmWaitingForRemote) && (mSrmEnabled)) {
- if(V) Log.d(TAG,"SRM is now ACTIVE for this operation");
- mSrmActive = true;
- }
- return body;
- }
-
- /**
- * Call this only when a complete request have been received.
- * (This is not optimal, but the current design is not really suited to
- * the way SRM is specified.)
- */
- private void checkForSrmWait(int headerId){
- if (mSrmEnabled && (headerId == ObexHelper.OBEX_OPCODE_GET
- || headerId == ObexHelper.OBEX_OPCODE_GET_FINAL
- || headerId == ObexHelper.OBEX_OPCODE_PUT)) {
- try {
- mSrmWaitingForRemote = false;
- Byte srmp = (Byte)requestHeader.getHeader(HeaderSet.SINGLE_RESPONSE_MODE_PARAMETER);
- if(srmp != null && srmp == ObexHelper.OBEX_SRMP_WAIT) {
- mSrmWaitingForRemote = true;
- // Clear the wait header, as the absents of the header when the final bit is set
- // indicates don't wait.
- requestHeader.setHeader(HeaderSet.SINGLE_RESPONSE_MODE_PARAMETER, null);
- }
- } catch (IOException e) {if(V){Log.w(TAG,"Exception while extracting header",e);}}
- }
- }
-
- public boolean isValidBody() {
- return mHasBody;
- }
-
- /**
- * Determines if the operation should continue or should wait. If it should
- * continue, this method will continue the operation.
- * @param sendEmpty if <code>true</code> then this will continue the
- * operation even if no headers will be sent; if <code>false</code>
- * then this method will only continue the operation if there are
- * headers to send
- * @param inStream if<code>true</code> the stream is input stream, otherwise
- * output stream
- * @return <code>true</code> if the operation was completed;
- * <code>false</code> if no operation took place
- */
- public synchronized boolean continueOperation(boolean sendEmpty, boolean inStream)
- throws IOException {
- if (!mGetOperation) {
- if (!finalBitSet) {
- if (sendEmpty) {
- sendReply(ResponseCodes.OBEX_HTTP_CONTINUE);
- return true;
- } else {
- if ((mResponseSize > 3) || (mPrivateOutput.size() > 0)) {
- sendReply(ResponseCodes.OBEX_HTTP_CONTINUE);
- return true;
- } else {
- return false;
- }
- }
- } else {
- return false;
- }
- } else {
- sendReply(ResponseCodes.OBEX_HTTP_CONTINUE);
- return true;
- }
- }
-
- /**
- * Sends a reply to the client. If the reply is a OBEX_HTTP_CONTINUE, it
- * will wait for a response from the client before ending unless SRM is active.
- * @param type the response code to send back to the client
- * @return <code>true</code> if the final bit was not set on the reply;
- * <code>false</code> if no reply was received because the operation
- * ended, an abort was received, the final bit was set in the
- * reply or SRM is active.
- * @throws IOException if an IO error occurs
- */
- public synchronized boolean sendReply(int type) throws IOException {
- ByteArrayOutputStream out = new ByteArrayOutputStream();
- boolean skipSend = false;
- boolean skipReceive = false;
- boolean srmRespSendPending = false;
-
- long id = mListener.getConnectionId();
- if (id == -1) {
- replyHeader.mConnectionID = null;
- } else {
- replyHeader.mConnectionID = ObexHelper.convertToByteArray(id);
- }
-
- if(mSrmEnabled && !mSrmResponseSent) {
- // As we are not ensured that the SRM enable is in the first OBEX packet
- // We must check for each reply.
- if(V)Log.v(TAG, "mSrmEnabled==true, sending SRM enable response.");
- replyHeader.setHeader(HeaderSet.SINGLE_RESPONSE_MODE, (byte)ObexHelper.OBEX_SRM_ENABLE);
- srmRespSendPending = true;
- }
-
- if(mSrmEnabled && !mGetOperation && mSrmLocalWait) {
- replyHeader.setHeader(HeaderSet.SINGLE_RESPONSE_MODE, (byte)ObexHelper.OBEX_SRMP_WAIT);
- }
-
- byte[] headerArray = ObexHelper.createHeader(replyHeader, true); // This clears the headers
- int bodyLength = -1;
- int orginalBodyLength = -1;
-
- if (mPrivateOutput != null) {
- bodyLength = mPrivateOutput.size();
- orginalBodyLength = bodyLength;
- }
-
- if ((ObexHelper.BASE_PACKET_LENGTH + headerArray.length) > mMaxPacketLength) {
-
- int end = 0;
- int start = 0;
-
- while (end != headerArray.length) {
- end = ObexHelper.findHeaderEnd(headerArray, start, mMaxPacketLength
- - ObexHelper.BASE_PACKET_LENGTH);
- if (end == -1) {
-
- mClosed = true;
-
- if (mPrivateInput != null) {
- mPrivateInput.close();
- }
-
- if (mPrivateOutput != null) {
- mPrivateOutput.close();
- }
- mParent.sendResponse(ResponseCodes.OBEX_HTTP_INTERNAL_ERROR, null);
- throw new IOException("OBEX Packet exceeds max packet size");
- }
- byte[] sendHeader = new byte[end - start];
- System.arraycopy(headerArray, start, sendHeader, 0, sendHeader.length);
-
- mParent.sendResponse(type, sendHeader);
- start = end;
- }
-
- if (bodyLength > 0) {
- return true;
- } else {
- return false;
- }
-
- } else {
- out.write(headerArray);
- }
-
- // For Get operation: if response code is OBEX_HTTP_OK, then this is the
- // last packet; so set finalBitSet to true.
- if (mGetOperation && type == ResponseCodes.OBEX_HTTP_OK) {
- finalBitSet = true;
- }
-
- if(mSrmActive) {
- if(!mGetOperation && type == ResponseCodes.OBEX_HTTP_CONTINUE &&
- mSrmResponseSent == true) {
- // we are in the middle of a SRM PUT operation, don't send a continue.
- skipSend = true;
- } else if(mGetOperation && mRequestFinished == false && mSrmResponseSent == true) {
- // We are still receiving the get request, receive, but don't send continue.
- skipSend = true;
- } else if(mGetOperation && mRequestFinished == true) {
- // All done receiving the GET request, send data to the client, without
- // expecting a continue.
- skipReceive = true;
- }
- if(V)Log.v(TAG, "type==" + type + " skipSend==" + skipSend
- + " skipReceive==" + skipReceive);
- }
- if(srmRespSendPending) {
- if(V)Log.v(TAG,
- "SRM Enabled (srmRespSendPending == true)- sending SRM Enable response");
- mSrmResponseSent = true;
- }
-
- if ((finalBitSet) || (headerArray.length < (mMaxPacketLength - 20))) {
- if (bodyLength > 0) {
- /*
- * Determine if I can send the whole body or just part of
- * the body. Remember that there is the 3 bytes for the
- * response message and 3 bytes for the header ID and length
- */
- if (bodyLength > (mMaxPacketLength - headerArray.length - 6)) {
- bodyLength = mMaxPacketLength - headerArray.length - 6;
- }
-
- byte[] body = mPrivateOutput.readBytes(bodyLength);
-
- /*
- * Since this is a put request if the final bit is set or
- * the output stream is closed we need to send the 0x49
- * (End of Body) otherwise, we need to send 0x48 (Body)
- */
- if ((finalBitSet) || (mPrivateOutput.isClosed())) {
- if(mSendBodyHeader == true) {
- out.write(0x49);
- bodyLength += 3;
- out.write((byte)(bodyLength >> 8));
- out.write((byte)bodyLength);
- out.write(body);
- }
- } else {
- if(mSendBodyHeader == true) {
- out.write(0x48);
- bodyLength += 3;
- out.write((byte)(bodyLength >> 8));
- out.write((byte)bodyLength);
- out.write(body);
- }
- }
-
- }
- }
-
- if ((finalBitSet) && (type == ResponseCodes.OBEX_HTTP_OK) && (orginalBodyLength <= 0)) {
- if(mSendBodyHeader) {
- out.write(0x49);
- orginalBodyLength = 3;
- out.write((byte)(orginalBodyLength >> 8));
- out.write((byte)orginalBodyLength);
- }
- }
-
- if(skipSend == false) {
- mResponseSize = 3;
- mParent.sendResponse(type, out.toByteArray());
- }
-
- if (type == ResponseCodes.OBEX_HTTP_CONTINUE) {
-
- if(mGetOperation && skipReceive) {
- // Here we need to check for and handle abort (throw an exception).
- // Any other signal received should be discarded silently (only on server side)
- checkSrmRemoteAbort();
- } else {
- // Receive and handle data (only send reply if !skipSend)
- // Read a complete OBEX Packet
- ObexPacket packet = ObexPacket.read(mInput);
-
- int headerId = packet.mHeaderId;
- if ((headerId != ObexHelper.OBEX_OPCODE_PUT)
- && (headerId != ObexHelper.OBEX_OPCODE_PUT_FINAL)
- && (headerId != ObexHelper.OBEX_OPCODE_GET)
- && (headerId != ObexHelper.OBEX_OPCODE_GET_FINAL)) {
-
- /*
- * Determine if an ABORT was sent as the reply
- */
- if (headerId == ObexHelper.OBEX_OPCODE_ABORT) {
- handleRemoteAbort();
- } else {
- // TODO:shall we send this if it occurs during SRM? Errata on the subject
- mParent.sendResponse(ResponseCodes.OBEX_HTTP_BAD_REQUEST, null);
- mClosed = true;
- mExceptionString = "Bad Request Received";
- throw new IOException("Bad Request Received");
- }
- } else {
-
- if ((headerId == ObexHelper.OBEX_OPCODE_PUT_FINAL)) {
- finalBitSet = true;
- } else if (headerId == ObexHelper.OBEX_OPCODE_GET_FINAL) {
- mRequestFinished = true;
- }
-
- /*
- * Determine if the packet length is larger than the negotiated packet size
- */
- if (packet.mLength > ObexHelper.getMaxRxPacketSize(mTransport)) {
- mParent.sendResponse(ResponseCodes.OBEX_HTTP_REQ_TOO_LARGE, null);
- throw new IOException("Packet received was too large");
- }
-
- /*
- * Determine if any headers were sent in the initial request
- */
- if (packet.mLength > 3 || (mSrmEnabled && packet.mLength == 3)) {
- if(handleObexPacket(packet) == false) {
- return false;
- }
- }
- }
-
- }
- return true;
- } else {
- return false;
- }
- }
-
- /**
- * This method will look for an abort from the peer during a SRM transfer.
- * The function will not block if no data has been received from the remote device.
- * If data have been received, the function will block while reading the incoming
- * OBEX package.
- * An Abort request will be handled, and cause an IOException("Abort Received").
- * Other messages will be discarded silently as per GOEP specification.
- * @throws IOException if an abort request have been received.
- * TODO: I think this is an error in the specification. If we discard other messages,
- * the peer device will most likely stall, as it will not receive the expected
- * response for the message...
- * I'm not sure how to understand "Receipt of invalid or unexpected SRM or SRMP
- * header values shall be ignored by the receiving device."
- * If any signal is received during an active SRM transfer it is unexpected regardless
- * whether or not it contains SRM/SRMP headers...
- */
- private void checkSrmRemoteAbort() throws IOException {
- if(mInput.available() > 0) {
- ObexPacket packet = ObexPacket.read(mInput);
- /*
- * Determine if an ABORT was sent as the reply
- */
- if (packet.mHeaderId == ObexHelper.OBEX_OPCODE_ABORT) {
- handleRemoteAbort();
- } else {
- // TODO: should we throw an exception here anyway? - don't see how to
- // ignore SRM/SRMP headers without ignoring the complete signal
- // (in this particular case).
- Log.w(TAG, "Received unexpected request from client - discarding...\n"
- + " headerId: " + packet.mHeaderId + " length: " + packet.mLength);
- }
- }
- }
-
- private void handleRemoteAbort() throws IOException {
- /* TODO: To increase the speed of the abort operation in SRM, we need
- * to be able to flush the L2CAP queue for the PSM in use.
- * This could be implemented by introducing a control
- * message to be send over the socket, that in the abort case
- * could carry a flush command. */
- mParent.sendResponse(ResponseCodes.OBEX_HTTP_OK, null);
- mClosed = true;
- isAborted = true;
- mExceptionString = "Abort Received";
- throw new IOException("Abort Received");
- }
-
- /**
- * Sends an ABORT message to the server. By calling this method, the
- * corresponding input and output streams will be closed along with this
- * object.
- * @throws IOException if the transaction has already ended or if an OBEX
- * server called this method
- */
- public void abort() throws IOException {
- throw new IOException("Called from a server");
- }
-
- /**
- * Returns the headers that have been received during the operation.
- * Modifying the object returned has no effect on the headers that are sent
- * or retrieved.
- * @return the headers received during this <code>Operation</code>
- * @throws IOException if this <code>Operation</code> has been closed
- */
- public HeaderSet getReceivedHeader() throws IOException {
- ensureOpen();
- return requestHeader;
- }
-
- /**
- * Specifies the headers that should be sent in the next OBEX message that
- * is sent.
- * @param headers the headers to send in the next message
- * @throws IOException if this <code>Operation</code> has been closed or the
- * transaction has ended and no further messages will be exchanged
- * @throws IllegalArgumentException if <code>headers</code> was not created
- * by a call to <code>ServerRequestHandler.createHeaderSet()</code>
- */
- public void sendHeaders(HeaderSet headers) throws IOException {
- ensureOpen();
-
- if (headers == null) {
- throw new IOException("Headers may not be null");
- }
-
- int[] headerList = headers.getHeaderList();
- if (headerList != null) {
- for (int i = 0; i < headerList.length; i++) {
- replyHeader.setHeader(headerList[i], headers.getHeader(headerList[i]));
- }
-
- }
- }
-
- /**
- * Retrieves the response code retrieved from the server. Response codes are
- * defined in the <code>ResponseCodes</code> interface.
- * @return the response code retrieved from the server
- * @throws IOException if an error occurred in the transport layer during
- * the transaction; if this method is called on a
- * <code>HeaderSet</code> object created by calling
- * <code>createHeaderSet</code> in a <code>ClientSession</code>
- * object; if this is called from a server
- */
- public int getResponseCode() throws IOException {
- throw new IOException("Called from a server");
- }
-
- /**
- * Always returns <code>null</code>
- * @return <code>null</code>
- */
- public String getEncoding() {
- return null;
- }
-
- /**
- * Returns the type of content that the resource connected to is providing.
- * E.g. if the connection is via HTTP, then the value of the content-type
- * header field is returned.
- * @return the content type of the resource that the URL references, or
- * <code>null</code> if not known
- */
- public String getType() {
- try {
- return (String)requestHeader.getHeader(HeaderSet.TYPE);
- } catch (IOException e) {
- return null;
- }
- }
-
- /**
- * Returns the length of the content which is being provided. E.g. if the
- * connection is via HTTP, then the value of the content-length header field
- * is returned.
- * @return the content length of the resource that this connection's URL
- * references, or -1 if the content length is not known
- */
- public long getLength() {
- try {
- Long temp = (Long)requestHeader.getHeader(HeaderSet.LENGTH);
-
- if (temp == null) {
- return -1;
- } else {
- return temp.longValue();
- }
- } catch (IOException e) {
- return -1;
- }
- }
-
- public int getMaxPacketSize() {
- return mMaxPacketLength - 6 - getHeaderLength();
- }
-
- public int getHeaderLength() {
- long id = mListener.getConnectionId();
- if (id == -1) {
- replyHeader.mConnectionID = null;
- } else {
- replyHeader.mConnectionID = ObexHelper.convertToByteArray(id);
- }
-
- byte[] headerArray = ObexHelper.createHeader(replyHeader, false);
-
- return headerArray.length;
- }
-
- /**
- * Open and return an input stream for a connection.
- * @return an input stream
- * @throws IOException if an I/O error occurs
- */
- public InputStream openInputStream() throws IOException {
- ensureOpen();
- return mPrivateInput;
- }
-
- /**
- * Open and return a data input stream for a connection.
- * @return an input stream
- * @throws IOException if an I/O error occurs
- */
- public DataInputStream openDataInputStream() throws IOException {
- return new DataInputStream(openInputStream());
- }
-
- /**
- * Open and return an output stream for a connection.
- * @return an output stream
- * @throws IOException if an I/O error occurs
- */
- public OutputStream openOutputStream() throws IOException {
- ensureOpen();
-
- if (mPrivateOutputOpen) {
- throw new IOException("no more input streams available, stream already opened");
- }
-
- if (!mRequestFinished) {
- throw new IOException("no output streams available ,request not finished");
- }
-
- if (mPrivateOutput == null) {
- mPrivateOutput = new PrivateOutputStream(this, getMaxPacketSize());
- }
- mPrivateOutputOpen = true;
- return mPrivateOutput;
- }
-
- /**
- * Open and return a data output stream for a connection.
- * @return an output stream
- * @throws IOException if an I/O error occurs
- */
- public DataOutputStream openDataOutputStream() throws IOException {
- return new DataOutputStream(openOutputStream());
- }
-
- /**
- * Closes the connection and ends the transaction
- * @throws IOException if the operation has already ended or is closed
- */
- public void close() throws IOException {
- ensureOpen();
- mClosed = true;
- }
-
- /**
- * Verifies that the connection is open and no exceptions should be thrown.
- * @throws IOException if an exception needs to be thrown
- */
- public void ensureOpen() throws IOException {
- if (mExceptionString != null) {
- throw new IOException(mExceptionString);
- }
- if (mClosed) {
- throw new IOException("Operation has already ended");
- }
- }
-
- /**
- * Verifies that additional information may be sent. In other words, the
- * operation is not done.
- * <P>
- * Included to implement the BaseStream interface only. It does not do
- * anything on the server side since the operation of the Operation object
- * is not done until after the handler returns from its method.
- * @throws IOException if the operation is completed
- */
- public void ensureNotDone() throws IOException {
- }
-
- /**
- * Called when the output or input stream is closed. It does not do anything
- * on the server side since the operation of the Operation object is not
- * done until after the handler returns from its method.
- * @param inStream <code>true</code> if the input stream is closed;
- * <code>false</code> if the output stream is closed
- * @throws IOException if an IO error occurs
- */
- public void streamClosed(boolean inStream) throws IOException {
-
- }
-
- public void noBodyHeader(){
- mSendBodyHeader = false;
- }
-}
diff --git a/obex/javax/obex/ServerRequestHandler.java b/obex/javax/obex/ServerRequestHandler.java
deleted file mode 100644
index 09cbc2c..0000000
--- a/obex/javax/obex/ServerRequestHandler.java
+++ /dev/null
@@ -1,287 +0,0 @@
-/*
- * Copyright (c) 2008-2009, Motorola, Inc.
- *
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * - Redistributions of source code must retain the above copyright notice,
- * this list of conditions and the following disclaimer.
- *
- * - Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- *
- * - Neither the name of the Motorola, Inc. nor the names of its contributors
- * may be used to endorse or promote products derived from this software
- * without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
- * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
- * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
- * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
- * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGE.
- */
-
-package javax.obex;
-
-/**
- * The <code>ServerRequestHandler</code> class defines an event listener that
- * will respond to OBEX requests made to the server.
- * <P>
- * The <code>onConnect()</code>, <code>onSetPath()</code>,
- * <code>onDelete()</code>, <code>onGet()</code>, and <code>onPut()</code>
- * methods may return any response code defined in the
- * <code>ResponseCodes</code> class except for <code>OBEX_HTTP_CONTINUE</code>.
- * If <code>OBEX_HTTP_CONTINUE</code> or a value not defined in the
- * <code>ResponseCodes</code> class is returned, the server implementation will
- * send an <code>OBEX_HTTP_INTERNAL_ERROR</code> response to the client.
- * <P>
- * <STRONG>Connection ID and Target Headers</STRONG>
- * <P>
- * According to the IrOBEX specification, a packet may not contain a Connection
- * ID and Target header. Since the Connection ID header is managed by the
- * implementation, it will not send a Connection ID header, if a Connection ID
- * was specified, in a packet that has a Target header. In other words, if an
- * application adds a Target header to a <code>HeaderSet</code> object used in
- * an OBEX operation and a Connection ID was specified, no Connection ID will be
- * sent in the packet containing the Target header.
- * <P>
- * <STRONG>CREATE-EMPTY Requests</STRONG>
- * <P>
- * A CREATE-EMPTY request allows clients to create empty objects on the server.
- * When a CREATE-EMPTY request is received, the <code>onPut()</code> method will
- * be called by the implementation. To differentiate between a normal PUT
- * request and a CREATE-EMPTY request, an application must open the
- * <code>InputStream</code> from the <code>Operation</code> object passed to the
- * <code>onPut()</code> method. For a PUT request, the application will be able
- * to read Body data from this <code>InputStream</code>. For a CREATE-EMPTY
- * request, there will be no Body data to read. Therefore, a call to
- * <code>InputStream.read()</code> will return -1.
- * @hide
- */
-public class ServerRequestHandler {
-
- private long mConnectionId;
-
- /**
- * Creates a <code>ServerRequestHandler</code>.
- */
- protected ServerRequestHandler() {
- /*
- * A connection ID of -1 implies there is no conenction ID
- */
- mConnectionId = -1;
- }
-
- /**
- * Sets the connection ID header to include in the reply packets.
- * @param connectionId the connection ID to use; -1 if no connection ID
- * should be sent
- * @throws IllegalArgumentException if <code>id</code> is not in the range
- * -1 to 2<sup>32</sup>-1
- */
- public void setConnectionId(final long connectionId) {
- if ((connectionId < -1) || (connectionId > 0xFFFFFFFFL)) {
- throw new IllegalArgumentException("Illegal Connection ID");
- }
- mConnectionId = connectionId;
- }
-
- /**
- * Retrieves the connection ID that is being used in the present connection.
- * This method will return -1 if no connection ID is being used.
- * @return the connection id being used or -1 if no connection ID is being
- * used
- */
- public long getConnectionId() {
- return mConnectionId;
- }
-
- /**
- * Called when a CONNECT request is received.
- * <P>
- * If this method is not implemented by the class that extends this class,
- * <code>onConnect()</code> will always return an <code>OBEX_HTTP_OK</code>
- * response code.
- * <P>
- * The headers received in the request can be retrieved from the
- * <code>request</code> argument. The headers that should be sent in the
- * reply must be specified in the <code>reply</code> argument.
- * @param request contains the headers sent by the client;
- * <code>request</code> will never be <code>null</code>
- * @param reply the headers that should be sent in the reply;
- * <code>reply</code> will never be <code>null</code>
- * @return a response code defined in <code>ResponseCodes</code> that will
- * be returned to the client; if an invalid response code is
- * provided, the <code>OBEX_HTTP_INTERNAL_ERROR</code> response code
- * will be used
- */
- public int onConnect(HeaderSet request, HeaderSet reply) {
- return ResponseCodes.OBEX_HTTP_OK;
- }
-
- /**
- * Called when a DISCONNECT request is received.
- * <P>
- * The headers received in the request can be retrieved from the
- * <code>request</code> argument. The headers that should be sent in the
- * reply must be specified in the <code>reply</code> argument.
- * @param request contains the headers sent by the client;
- * <code>request</code> will never be <code>null</code>
- * @param reply the headers that should be sent in the reply;
- * <code>reply</code> will never be <code>null</code>
- */
- public void onDisconnect(HeaderSet request, HeaderSet reply) {
- }
-
- /**
- * Called when a SETPATH request is received.
- * <P>
- * If this method is not implemented by the class that extends this class,
- * <code>onSetPath()</code> will always return an
- * <code>OBEX_HTTP_NOT_IMPLEMENTED</code> response code.
- * <P>
- * The headers received in the request can be retrieved from the
- * <code>request</code> argument. The headers that should be sent in the
- * reply must be specified in the <code>reply</code> argument.
- * @param request contains the headers sent by the client;
- * <code>request</code> will never be <code>null</code>
- * @param reply the headers that should be sent in the reply;
- * <code>reply</code> will never be <code>null</code>
- * @param backup <code>true</code> if the client requests that the server
- * back up one directory before changing to the path described by
- * <code>name</code>; <code>false</code> to apply the request to the
- * present path
- * @param create <code>true</code> if the path should be created if it does
- * not already exist; <code>false</code> if the path should not be
- * created if it does not exist and an error code should be returned
- * @return a response code defined in <code>ResponseCodes</code> that will
- * be returned to the client; if an invalid response code is
- * provided, the <code>OBEX_HTTP_INTERNAL_ERROR</code> response code
- * will be used
- */
- public int onSetPath(HeaderSet request, HeaderSet reply, boolean backup, boolean create) {
-
- return ResponseCodes.OBEX_HTTP_NOT_IMPLEMENTED;
- }
-
- /**
- * Called when a DELETE request is received.
- * <P>
- * If this method is not implemented by the class that extends this class,
- * <code>onDelete()</code> will always return an
- * <code>OBEX_HTTP_NOT_IMPLEMENTED</code> response code.
- * <P>
- * The headers received in the request can be retrieved from the
- * <code>request</code> argument. The headers that should be sent in the
- * reply must be specified in the <code>reply</code> argument.
- * @param request contains the headers sent by the client;
- * <code>request</code> will never be <code>null</code>
- * @param reply the headers that should be sent in the reply;
- * <code>reply</code> will never be <code>null</code>
- * @return a response code defined in <code>ResponseCodes</code> that will
- * be returned to the client; if an invalid response code is
- * provided, the <code>OBEX_HTTP_INTERNAL_ERROR</code> response code
- * will be used
- */
- public int onDelete(HeaderSet request, HeaderSet reply) {
- return ResponseCodes.OBEX_HTTP_NOT_IMPLEMENTED;
- }
-
- /**
- * Called when a ABORT request is received.
- */
- public int onAbort(HeaderSet request, HeaderSet reply) {
- return ResponseCodes.OBEX_HTTP_NOT_IMPLEMENTED;
- }
-
- /**
- * Called when a PUT request is received.
- * <P>
- * If this method is not implemented by the class that extends this class,
- * <code>onPut()</code> will always return an
- * <code>OBEX_HTTP_NOT_IMPLEMENTED</code> response code.
- * <P>
- * If an ABORT request is received during the processing of a PUT request,
- * <code>op</code> will be closed by the implementation.
- * @param operation contains the headers sent by the client and allows new
- * headers to be sent in the reply; <code>op</code> will never be
- * <code>null</code>
- * @return a response code defined in <code>ResponseCodes</code> that will
- * be returned to the client; if an invalid response code is
- * provided, the <code>OBEX_HTTP_INTERNAL_ERROR</code> response code
- * will be used
- */
- public int onPut(Operation operation) {
- return ResponseCodes.OBEX_HTTP_NOT_IMPLEMENTED;
- }
-
- /**
- * Called when a GET request is received.
- * <P>
- * If this method is not implemented by the class that extends this class,
- * <code>onGet()</code> will always return an
- * <code>OBEX_HTTP_NOT_IMPLEMENTED</code> response code.
- * <P>
- * If an ABORT request is received during the processing of a GET request,
- * <code>op</code> will be closed by the implementation.
- * @param operation contains the headers sent by the client and allows new
- * headers to be sent in the reply; <code>op</code> will never be
- * <code>null</code>
- * @return a response code defined in <code>ResponseCodes</code> that will
- * be returned to the client; if an invalid response code is
- * provided, the <code>OBEX_HTTP_INTERNAL_ERROR</code> response code
- * will be used
- */
- public int onGet(Operation operation) {
- return ResponseCodes.OBEX_HTTP_NOT_IMPLEMENTED;
- }
-
- /**
- * Called when this object attempts to authenticate a client and the
- * authentication request fails because the response digest in the
- * authentication response header was wrong.
- * <P>
- * If this method is not implemented by the class that extends this class,
- * this method will do nothing.
- * @param userName the user name returned in the authentication response;
- * <code>null</code> if no user name was provided in the response
- */
- public void onAuthenticationFailure(byte[] userName) {
- }
-
- /**
- * Called by ServerSession to update the status of current transaction
- * <P>
- * If this method is not implemented by the class that extends this class,
- * this method will do nothing.
- */
- public void updateStatus(String message) {
- }
-
- /**
- * Called when session is closed.
- * <P>
- * If this method is not implemented by the class that extends this class,
- * this method will do nothing.
- */
- public void onClose() {
- }
-
- /**
- * Override to add Single Response Mode support - e.g. if the supplied
- * transport is l2cap.
- * @return True if SRM is supported, else False
- */
- public boolean isSrmSupported() {
- return false;
- }
-}
diff --git a/obex/javax/obex/ServerSession.java b/obex/javax/obex/ServerSession.java
deleted file mode 100644
index dbfeefd..0000000
--- a/obex/javax/obex/ServerSession.java
+++ /dev/null
@@ -1,742 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- * Copyright (c) 2015 Samsung LSI
- * Copyright (c) 2008-2009, Motorola, Inc.
- *
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * - Redistributions of source code must retain the above copyright notice,
- * this list of conditions and the following disclaimer.
- *
- * - Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- *
- * - Neither the name of the Motorola, Inc. nor the names of its contributors
- * may be used to endorse or promote products derived from this software
- * without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
- * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
- * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
- * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
- * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGE.
- */
-
-package javax.obex;
-
-import android.util.Log;
-
-import java.io.InputStream;
-import java.io.IOException;
-import java.io.OutputStream;
-
-/**
- * This class in an implementation of the OBEX ServerSession.
- * @hide
- */
-public final class ServerSession extends ObexSession implements Runnable {
-
- private static final String TAG = "Obex ServerSession";
- private static final boolean V = ObexHelper.VDBG;
-
- private ObexTransport mTransport;
-
- private InputStream mInput;
-
- private OutputStream mOutput;
-
- private ServerRequestHandler mListener;
-
- private Thread mProcessThread;
-
- private int mMaxPacketLength;
-
- private boolean mClosed;
-
- /**
- * Creates new ServerSession.
- * @param trans the connection to the client
- * @param handler the event listener that will process requests
- * @param auth the authenticator to use with this connection
- * @throws IOException if an error occurred while opening the input and
- * output streams
- */
- public ServerSession(ObexTransport trans, ServerRequestHandler handler, Authenticator auth)
- throws IOException {
- mAuthenticator = auth;
- mTransport = trans;
- mInput = mTransport.openInputStream();
- mOutput = mTransport.openOutputStream();
- mListener = handler;
- mMaxPacketLength = 256;
-
- mClosed = false;
- mProcessThread = new Thread(this);
- mProcessThread.start();
- }
-
- /**
- * Processes requests made to the server and forwards them to the
- * appropriate event listener.
- */
- public void run() {
- try {
-
- boolean done = false;
- while (!done && !mClosed) {
- if(V) Log.v(TAG, "Waiting for incoming request...");
- int requestType = mInput.read();
- if(V) Log.v(TAG, "Read request: " + requestType);
- switch (requestType) {
- case ObexHelper.OBEX_OPCODE_CONNECT:
- handleConnectRequest();
- break;
-
- case ObexHelper.OBEX_OPCODE_DISCONNECT:
- handleDisconnectRequest();
- break;
-
- case ObexHelper.OBEX_OPCODE_GET:
- case ObexHelper.OBEX_OPCODE_GET_FINAL:
- handleGetRequest(requestType);
- break;
-
- case ObexHelper.OBEX_OPCODE_PUT:
- case ObexHelper.OBEX_OPCODE_PUT_FINAL:
- handlePutRequest(requestType);
- break;
-
- case ObexHelper.OBEX_OPCODE_SETPATH:
- handleSetPathRequest();
- break;
- case ObexHelper.OBEX_OPCODE_ABORT:
- handleAbortRequest();
- break;
-
- case -1:
- done = true;
- break;
-
- default:
-
- /*
- * Received a request type that is not recognized so I am
- * just going to read the packet and send a not implemented
- * to the client
- */
- int length = mInput.read();
- length = (length << 8) + mInput.read();
- for (int i = 3; i < length; i++) {
- mInput.read();
- }
- sendResponse(ResponseCodes.OBEX_HTTP_NOT_IMPLEMENTED, null);
- }
- }
-
- } catch (NullPointerException e) {
- Log.d(TAG, "Exception occured - ignoring", e);
- } catch (Exception e) {
- Log.d(TAG, "Exception occured - ignoring", e);
- }
- close();
- }
-
- /**
- * Handles a ABORT request from a client. This method will read the rest of
- * the request from the client. Assuming the request is valid, it will
- * create a <code>HeaderSet</code> object to pass to the
- * <code>ServerRequestHandler</code> object. After the handler processes the
- * request, this method will create a reply message to send to the server.
- *
- * @throws IOException if an error occurred at the transport layer
- */
- private void handleAbortRequest() throws IOException {
- int code = ResponseCodes.OBEX_HTTP_OK;
- HeaderSet request = new HeaderSet();
- HeaderSet reply = new HeaderSet();
-
- int length = mInput.read();
- length = (length << 8) + mInput.read();
- if (length > ObexHelper.getMaxRxPacketSize(mTransport)) {
- code = ResponseCodes.OBEX_HTTP_REQ_TOO_LARGE;
- } else {
- for (int i = 3; i < length; i++) {
- mInput.read();
- }
- code = mListener.onAbort(request, reply);
- Log.v(TAG, "onAbort request handler return value- " + code);
- code = validateResponseCode(code);
- }
- sendResponse(code, null);
- }
-
- /**
- * Handles a PUT request from a client. This method will provide a
- * <code>ServerOperation</code> object to the request handler. The
- * <code>ServerOperation</code> object will handle the rest of the request.
- * It will also send replies and receive requests until the final reply
- * should be sent. When the final reply should be sent, this method will get
- * the response code to use and send the reply. The
- * <code>ServerOperation</code> object will always reply with a
- * OBEX_HTTP_CONTINUE reply. It will only reply if further information is
- * needed.
- * @param type the type of request received; either 0x02 or 0x82
- * @throws IOException if an error occurred at the transport layer
- */
- private void handlePutRequest(int type) throws IOException {
- ServerOperation op = new ServerOperation(this, mInput, type, mMaxPacketLength, mListener);
- try {
- int response = -1;
-
- if ((op.finalBitSet) && !op.isValidBody()) {
- response = validateResponseCode(mListener
- .onDelete(op.requestHeader, op.replyHeader));
- } else {
- response = validateResponseCode(mListener.onPut(op));
- }
- if (response != ResponseCodes.OBEX_HTTP_OK && !op.isAborted) {
- op.sendReply(response);
- } else if (!op.isAborted) {
- // wait for the final bit
- while (!op.finalBitSet) {
- op.sendReply(ResponseCodes.OBEX_HTTP_CONTINUE);
- }
- op.sendReply(response);
- }
- } catch (Exception e) {
- /*To fix bugs in aborted cases,
- *(client abort file transfer prior to the last packet which has the end of body header,
- *internal error should not be sent because server has already replied with
- *OK response in "sendReply")
- */
- if(V) Log.d(TAG,"Exception occured - sending OBEX_HTTP_INTERNAL_ERROR reply",e);
- if (!op.isAborted) {
- sendResponse(ResponseCodes.OBEX_HTTP_INTERNAL_ERROR, null);
- }
- }
- }
-
- /**
- * Handles a GET request from a client. This method will provide a
- * <code>ServerOperation</code> object to the request handler. The
- * <code>ServerOperation</code> object will handle the rest of the request.
- * It will also send replies and receive requests until the final reply
- * should be sent. When the final reply should be sent, this method will get
- * the response code to use and send the reply. The
- * <code>ServerOperation</code> object will always reply with a
- * OBEX_HTTP_CONTINUE reply. It will only reply if further information is
- * needed.
- * @param type the type of request received; either 0x03 or 0x83
- * @throws IOException if an error occurred at the transport layer
- */
- private void handleGetRequest(int type) throws IOException {
- ServerOperation op = new ServerOperation(this, mInput, type, mMaxPacketLength, mListener);
- try {
- int response = validateResponseCode(mListener.onGet(op));
-
- if (!op.isAborted) {
- op.sendReply(response);
- }
- } catch (Exception e) {
- if(V) Log.d(TAG,"Exception occured - sending OBEX_HTTP_INTERNAL_ERROR reply",e);
- sendResponse(ResponseCodes.OBEX_HTTP_INTERNAL_ERROR, null);
- }
- }
-
- /**
- * Send standard response.
- * @param code the response code to send
- * @param header the headers to include in the response
- * @throws IOException if an IO error occurs
- */
- public void sendResponse(int code, byte[] header) throws IOException {
- int totalLength = 3;
- byte[] data = null;
- OutputStream op = mOutput;
- if (op == null) {
- return;
- }
-
- if (header != null) {
- totalLength += header.length;
- data = new byte[totalLength];
- data[0] = (byte)code;
- data[1] = (byte)(totalLength >> 8);
- data[2] = (byte)totalLength;
- System.arraycopy(header, 0, data, 3, header.length);
- } else {
- data = new byte[totalLength];
- data[0] = (byte)code;
- data[1] = (byte)0x00;
- data[2] = (byte)totalLength;
- }
- op.write(data);
- op.flush(); // TODO: Do we need to flush?
- }
-
- /**
- * Handles a SETPATH request from a client. This method will read the rest
- * of the request from the client. Assuming the request is valid, it will
- * create a <code>HeaderSet</code> object to pass to the
- * <code>ServerRequestHandler</code> object. After the handler processes the
- * request, this method will create a reply message to send to the server
- * with the response code provided.
- * @throws IOException if an error occurred at the transport layer
- */
- private void handleSetPathRequest() throws IOException {
- int length;
- int flags;
- @SuppressWarnings("unused")
- int constants;
- int totalLength = 3;
- byte[] head = null;
- int code = -1;
- int bytesReceived;
- HeaderSet request = new HeaderSet();
- HeaderSet reply = new HeaderSet();
-
- length = mInput.read();
- length = (length << 8) + mInput.read();
- flags = mInput.read();
- constants = mInput.read();
-
- if (length > ObexHelper.getMaxRxPacketSize(mTransport)) {
- code = ResponseCodes.OBEX_HTTP_REQ_TOO_LARGE;
- totalLength = 3;
- } else {
- if (length > 5) {
- byte[] headers = new byte[length - 5];
- bytesReceived = mInput.read(headers);
-
- while (bytesReceived != headers.length) {
- bytesReceived += mInput.read(headers, bytesReceived, headers.length
- - bytesReceived);
- }
-
- ObexHelper.updateHeaderSet(request, headers);
-
- if (mListener.getConnectionId() != -1 && request.mConnectionID != null) {
- mListener.setConnectionId(ObexHelper.convertToLong(request.mConnectionID));
- } else {
- mListener.setConnectionId(1);
- }
- // the Auth chan is initiated by the server, client sent back the authResp .
- if (request.mAuthResp != null) {
- if (!handleAuthResp(request.mAuthResp)) {
- code = ResponseCodes.OBEX_HTTP_UNAUTHORIZED;
- mListener.onAuthenticationFailure(ObexHelper.getTagValue((byte)0x01,
- request.mAuthResp));
- }
- request.mAuthResp = null;
- }
- }
-
- if (code != ResponseCodes.OBEX_HTTP_UNAUTHORIZED) {
- // the Auth challenge is initiated by the client
- // the server will send back the authResp to the client
- if (request.mAuthChall != null) {
- handleAuthChall(request);
- reply.mAuthResp = new byte[request.mAuthResp.length];
- System.arraycopy(request.mAuthResp, 0, reply.mAuthResp, 0,
- reply.mAuthResp.length);
- request.mAuthChall = null;
- request.mAuthResp = null;
- }
- boolean backup = false;
- boolean create = true;
- if (!((flags & 1) == 0)) {
- backup = true;
- }
- if (!((flags & 2) == 0)) {
- create = false;
- }
-
- try {
- code = mListener.onSetPath(request, reply, backup, create);
- } catch (Exception e) {
- if(V) Log.d(TAG,"Exception occured - sending OBEX_HTTP_INTERNAL_ERROR reply",e);
- sendResponse(ResponseCodes.OBEX_HTTP_INTERNAL_ERROR, null);
- return;
- }
-
- code = validateResponseCode(code);
-
- if (reply.nonce != null) {
- mChallengeDigest = new byte[16];
- System.arraycopy(reply.nonce, 0, mChallengeDigest, 0, 16);
- } else {
- mChallengeDigest = null;
- }
-
- long id = mListener.getConnectionId();
- if (id == -1) {
- reply.mConnectionID = null;
- } else {
- reply.mConnectionID = ObexHelper.convertToByteArray(id);
- }
-
- head = ObexHelper.createHeader(reply, false);
- totalLength += head.length;
-
- if (totalLength > mMaxPacketLength) {
- totalLength = 3;
- head = null;
- code = ResponseCodes.OBEX_HTTP_INTERNAL_ERROR;
- }
- }
- }
-
- // Compute Length of OBEX SETPATH packet
- byte[] replyData = new byte[totalLength];
- replyData[0] = (byte)code;
- replyData[1] = (byte)(totalLength >> 8);
- replyData[2] = (byte)totalLength;
- if (head != null) {
- System.arraycopy(head, 0, replyData, 3, head.length);
- }
- /*
- * Write the OBEX SETPATH packet to the server. Byte 0: response code
- * Byte 1&2: Connect Packet Length Byte 3 to n: headers
- */
- mOutput.write(replyData);
- mOutput.flush();
- }
-
- /**
- * Handles a disconnect request from a client. This method will read the
- * rest of the request from the client. Assuming the request is valid, it
- * will create a <code>HeaderSet</code> object to pass to the
- * <code>ServerRequestHandler</code> object. After the handler processes the
- * request, this method will create a reply message to send to the server.
- * @throws IOException if an error occurred at the transport layer
- */
- private void handleDisconnectRequest() throws IOException {
- int length;
- int code = ResponseCodes.OBEX_HTTP_OK;
- int totalLength = 3;
- byte[] head = null;
- int bytesReceived;
- HeaderSet request = new HeaderSet();
- HeaderSet reply = new HeaderSet();
-
- length = mInput.read();
- length = (length << 8) + mInput.read();
-
- if (length > ObexHelper.getMaxRxPacketSize(mTransport)) {
- code = ResponseCodes.OBEX_HTTP_REQ_TOO_LARGE;
- totalLength = 3;
- } else {
- if (length > 3) {
- byte[] headers = new byte[length - 3];
- bytesReceived = mInput.read(headers);
-
- while (bytesReceived != headers.length) {
- bytesReceived += mInput.read(headers, bytesReceived, headers.length
- - bytesReceived);
- }
-
- ObexHelper.updateHeaderSet(request, headers);
- }
-
- if (mListener.getConnectionId() != -1 && request.mConnectionID != null) {
- mListener.setConnectionId(ObexHelper.convertToLong(request.mConnectionID));
- } else {
- mListener.setConnectionId(1);
- }
-
- if (request.mAuthResp != null) {
- if (!handleAuthResp(request.mAuthResp)) {
- code = ResponseCodes.OBEX_HTTP_UNAUTHORIZED;
- mListener.onAuthenticationFailure(ObexHelper.getTagValue((byte)0x01,
- request.mAuthResp));
- }
- request.mAuthResp = null;
- }
-
- if (code != ResponseCodes.OBEX_HTTP_UNAUTHORIZED) {
-
- if (request.mAuthChall != null) {
- handleAuthChall(request);
- request.mAuthChall = null;
- }
-
- try {
- mListener.onDisconnect(request, reply);
- } catch (Exception e) {
- if(V) Log.d(TAG,"Exception occured - sending OBEX_HTTP_INTERNAL_ERROR reply",e);
- sendResponse(ResponseCodes.OBEX_HTTP_INTERNAL_ERROR, null);
- return;
- }
-
- long id = mListener.getConnectionId();
- if (id == -1) {
- reply.mConnectionID = null;
- } else {
- reply.mConnectionID = ObexHelper.convertToByteArray(id);
- }
-
- head = ObexHelper.createHeader(reply, false);
- totalLength += head.length;
-
- if (totalLength > mMaxPacketLength) {
- totalLength = 3;
- head = null;
- code = ResponseCodes.OBEX_HTTP_INTERNAL_ERROR;
- }
- }
- }
-
- // Compute Length of OBEX CONNECT packet
- byte[] replyData;
- if (head != null) {
- replyData = new byte[3 + head.length];
- } else {
- replyData = new byte[3];
- }
- replyData[0] = (byte)code;
- replyData[1] = (byte)(totalLength >> 8);
- replyData[2] = (byte)totalLength;
- if (head != null) {
- System.arraycopy(head, 0, replyData, 3, head.length);
- }
- /*
- * Write the OBEX DISCONNECT packet to the server. Byte 0: response code
- * Byte 1&2: Connect Packet Length Byte 3 to n: headers
- */
- mOutput.write(replyData);
- mOutput.flush();
- }
-
- /**
- * Handles a connect request from a client. This method will read the rest
- * of the request from the client. Assuming the request is valid, it will
- * create a <code>HeaderSet</code> object to pass to the
- * <code>ServerRequestHandler</code> object. After the handler processes the
- * request, this method will create a reply message to send to the server
- * with the response code provided.
- * @throws IOException if an error occurred at the transport layer
- */
- private void handleConnectRequest() throws IOException {
- int packetLength;
- @SuppressWarnings("unused")
- int version;
- @SuppressWarnings("unused")
- int flags;
- int totalLength = 7;
- byte[] head = null;
- int code = -1;
- HeaderSet request = new HeaderSet();
- HeaderSet reply = new HeaderSet();
- int bytesReceived;
-
- if(V) Log.v(TAG,"handleConnectRequest()");
-
- /*
- * Read in the length of the OBEX packet, OBEX version, flags, and max
- * packet length
- */
- packetLength = mInput.read();
- packetLength = (packetLength << 8) + mInput.read();
- if(V) Log.v(TAG,"handleConnectRequest() - packetLength: " + packetLength);
-
- version = mInput.read();
- flags = mInput.read();
- mMaxPacketLength = mInput.read();
- mMaxPacketLength = (mMaxPacketLength << 8) + mInput.read();
-
- if(V) Log.v(TAG,"handleConnectRequest() - version: " + version
- + " MaxLength: " + mMaxPacketLength + " flags: " + flags);
-
- // should we check it?
- if (mMaxPacketLength > ObexHelper.MAX_PACKET_SIZE_INT) {
- mMaxPacketLength = ObexHelper.MAX_PACKET_SIZE_INT;
- }
-
- if(mMaxPacketLength > ObexHelper.getMaxTxPacketSize(mTransport)) {
- Log.w(TAG, "Requested MaxObexPacketSize " + mMaxPacketLength
- + " is larger than the max size supported by the transport: "
- + ObexHelper.getMaxTxPacketSize(mTransport)
- + " Reducing to this size.");
- mMaxPacketLength = ObexHelper.getMaxTxPacketSize(mTransport);
- }
-
- if (packetLength > ObexHelper.getMaxRxPacketSize(mTransport)) {
- code = ResponseCodes.OBEX_HTTP_REQ_TOO_LARGE;
- totalLength = 7;
- } else {
- if (packetLength > 7) {
- byte[] headers = new byte[packetLength - 7];
- bytesReceived = mInput.read(headers);
-
- while (bytesReceived != headers.length) {
- bytesReceived += mInput.read(headers, bytesReceived, headers.length
- - bytesReceived);
- }
-
- ObexHelper.updateHeaderSet(request, headers);
- }
-
- if (mListener.getConnectionId() != -1 && request.mConnectionID != null) {
- mListener.setConnectionId(ObexHelper.convertToLong(request.mConnectionID));
- } else {
- mListener.setConnectionId(1);
- }
-
- if (request.mAuthResp != null) {
- if (!handleAuthResp(request.mAuthResp)) {
- code = ResponseCodes.OBEX_HTTP_UNAUTHORIZED;
- mListener.onAuthenticationFailure(ObexHelper.getTagValue((byte)0x01,
- request.mAuthResp));
- }
- request.mAuthResp = null;
- }
-
- if (code != ResponseCodes.OBEX_HTTP_UNAUTHORIZED) {
- if (request.mAuthChall != null) {
- handleAuthChall(request);
- reply.mAuthResp = new byte[request.mAuthResp.length];
- System.arraycopy(request.mAuthResp, 0, reply.mAuthResp, 0,
- reply.mAuthResp.length);
- request.mAuthChall = null;
- request.mAuthResp = null;
- }
-
- try {
- code = mListener.onConnect(request, reply);
- code = validateResponseCode(code);
-
- if (reply.nonce != null) {
- mChallengeDigest = new byte[16];
- System.arraycopy(reply.nonce, 0, mChallengeDigest, 0, 16);
- } else {
- mChallengeDigest = null;
- }
- long id = mListener.getConnectionId();
- if (id == -1) {
- reply.mConnectionID = null;
- } else {
- reply.mConnectionID = ObexHelper.convertToByteArray(id);
- }
-
- head = ObexHelper.createHeader(reply, false);
- totalLength += head.length;
-
- if (totalLength > mMaxPacketLength) {
- totalLength = 7;
- head = null;
- code = ResponseCodes.OBEX_HTTP_INTERNAL_ERROR;
- }
- } catch (Exception e) {
- if(V) Log.d(TAG,"Exception occured - sending OBEX_HTTP_INTERNAL_ERROR reply",e);
- totalLength = 7;
- head = null;
- code = ResponseCodes.OBEX_HTTP_INTERNAL_ERROR;
- }
-
- }
- }
-
- // Compute Length of OBEX CONNECT packet
- byte[] length = ObexHelper.convertToByteArray(totalLength);
-
- /*
- * Write the OBEX CONNECT packet to the server. Byte 0: response code
- * Byte 1&2: Connect Packet Length Byte 3: OBEX Version Number
- * (Presently, 0x10) Byte 4: Flags (For TCP 0x00) Byte 5&6: Max OBEX
- * Packet Length (Defined in MAX_PACKET_SIZE) Byte 7 to n: headers
- */
- byte[] sendData = new byte[totalLength];
- int maxRxLength = ObexHelper.getMaxRxPacketSize(mTransport);
- if (maxRxLength > mMaxPacketLength) {
- if(V) Log.v(TAG,"Set maxRxLength to min of maxRxServrLen:" + maxRxLength +
- " and MaxNegotiated from Client: " + mMaxPacketLength);
- maxRxLength = mMaxPacketLength;
- }
- sendData[0] = (byte)code;
- sendData[1] = length[2];
- sendData[2] = length[3];
- sendData[3] = (byte)0x10;
- sendData[4] = (byte)0x00;
- sendData[5] = (byte)(maxRxLength >> 8);
- sendData[6] = (byte)(maxRxLength & 0xFF);
-
- if (head != null) {
- System.arraycopy(head, 0, sendData, 7, head.length);
- }
-
- mOutput.write(sendData);
- mOutput.flush();
- }
-
- /**
- * Closes the server session - in detail close I/O streams and the
- * underlying transport layer. Internal flag is also set so that later
- * attempt to read/write will throw an exception.
- */
- public synchronized void close() {
- if (mListener != null) {
- mListener.onClose();
- }
- try {
- /* Set state to closed before interrupting the thread by closing the streams */
- mClosed = true;
- if(mInput != null)
- mInput.close();
- if(mOutput != null)
- mOutput.close();
- if(mTransport != null)
- mTransport.close();
- } catch (Exception e) {
- if(V) Log.d(TAG,"Exception occured during close() - ignore",e);
- }
- mTransport = null;
- mInput = null;
- mOutput = null;
- mListener = null;
- }
-
- /**
- * Verifies that the response code is valid. If it is not valid, it will
- * return the <code>OBEX_HTTP_INTERNAL_ERROR</code> response code.
- * @param code the response code to check
- * @return the valid response code or <code>OBEX_HTTP_INTERNAL_ERROR</code>
- * if <code>code</code> is not valid
- */
- private int validateResponseCode(int code) {
-
- if ((code >= ResponseCodes.OBEX_HTTP_OK) && (code <= ResponseCodes.OBEX_HTTP_PARTIAL)) {
- return code;
- }
- if ((code >= ResponseCodes.OBEX_HTTP_MULT_CHOICE)
- && (code <= ResponseCodes.OBEX_HTTP_USE_PROXY)) {
- return code;
- }
- if ((code >= ResponseCodes.OBEX_HTTP_BAD_REQUEST)
- && (code <= ResponseCodes.OBEX_HTTP_UNSUPPORTED_TYPE)) {
- return code;
- }
- if ((code >= ResponseCodes.OBEX_HTTP_INTERNAL_ERROR)
- && (code <= ResponseCodes.OBEX_HTTP_VERSION)) {
- return code;
- }
- if ((code >= ResponseCodes.OBEX_DATABASE_FULL)
- && (code <= ResponseCodes.OBEX_DATABASE_LOCKED)) {
- return code;
- }
- return ResponseCodes.OBEX_HTTP_INTERNAL_ERROR;
- }
-
- public ObexTransport getTransport() {
- return mTransport;
- }
-}
diff --git a/obex/javax/obex/SessionNotifier.java b/obex/javax/obex/SessionNotifier.java
deleted file mode 100644
index 9836dd6..0000000
--- a/obex/javax/obex/SessionNotifier.java
+++ /dev/null
@@ -1,128 +0,0 @@
-/*
- * Copyright (c) 2008-2009, Motorola, Inc.
- *
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * - Redistributions of source code must retain the above copyright notice,
- * this list of conditions and the following disclaimer.
- *
- * - Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- *
- * - Neither the name of the Motorola, Inc. nor the names of its contributors
- * may be used to endorse or promote products derived from this software
- * without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
- * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
- * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
- * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
- * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGE.
- */
-
-package javax.obex;
-
-import java.io.IOException;
-
-/**
- * The <code>SessionNotifier</code> interface defines a connection notifier for
- * server-side OBEX connections. When a <code>SessionNotifier</code> is created
- * and calls <code>acceptAndOpen()</code>, it will begin listening for clients
- * to create a connection at the transport layer. When the transport layer
- * connection is received, the <code>acceptAndOpen()</code> method will return a
- * <code>javax.microedition.io.Connection</code> that is the connection to the
- * client. The <code>acceptAndOpen()</code> method also takes a
- * <code>ServerRequestHandler</code> argument that will process the requests
- * from the client that connects to the server.
- * @hide
- */
-public interface SessionNotifier {
-
- /**
- * Waits for a transport layer connection to be established and specifies
- * the handler to handle the requests from the client. No authenticator is
- * associated with this connection, therefore, it is implementation
- * dependent as to how an authentication challenge and authentication
- * response header will be received and processed.
- * <P>
- * <H4>Additional Note for OBEX over Bluetooth</H4> If this method is called
- * on a <code>SessionNotifier</code> object that does not have a
- * <code>ServiceRecord</code> in the SDDB, the <code>ServiceRecord</code>
- * for this object will be added to the SDDB. This method requests the BCC
- * to put the local device in connectable mode so that it will respond to
- * connection attempts by clients.
- * <P>
- * The following checks are done to verify that the service record provided
- * is valid. If any of these checks fail, then a
- * <code>ServiceRegistrationException</code> is thrown.
- * <UL>
- * <LI>ServiceClassIDList and ProtocolDescriptorList, the mandatory service
- * attributes for a <code>btgoep</code> service record, must be present in
- * the <code>ServiceRecord</code> associated with this notifier.
- * <LI>L2CAP, RFCOMM and OBEX must all be in the ProtocolDescriptorList
- * <LI>The <code>ServiceRecord</code> associated with this notifier must not
- * have changed the RFCOMM server channel number
- * </UL>
- * <P>
- * This method will not ensure that <code>ServiceRecord</code> associated
- * with this notifier is a completely valid service record. It is the
- * responsibility of the application to ensure that the service record
- * follows all of the applicable syntactic and semantic rules for service
- * record correctness.
- * @param handler the request handler that will respond to OBEX requests
- * @return the connection to the client
- * @throws IOException if an error occurs in the transport layer
- * @throws NullPointerException if <code>handler</code> is <code>null</code>
- */
- ObexSession acceptAndOpen(ServerRequestHandler handler) throws IOException;
-
- /**
- * Waits for a transport layer connection to be established and specifies
- * the handler to handle the requests from the client and the
- * <code>Authenticator</code> to use to respond to authentication challenge
- * and authentication response headers.
- * <P>
- * <H4>Additional Note for OBEX over Bluetooth</H4> If this method is called
- * on a <code>SessionNotifier</code> object that does not have a
- * <code>ServiceRecord</code> in the SDDB, the <code>ServiceRecord</code>
- * for this object will be added to the SDDB. This method requests the BCC
- * to put the local device in connectable mode so that it will respond to
- * connection attempts by clients.
- * <P>
- * The following checks are done to verify that the service record provided
- * is valid. If any of these checks fail, then a
- * <code>ServiceRegistrationException</code> is thrown.
- * <UL>
- * <LI>ServiceClassIDList and ProtocolDescriptorList, the mandatory service
- * attributes for a <code>btgoep</code> service record, must be present in
- * the <code>ServiceRecord</code> associated with this notifier.
- * <LI>L2CAP, RFCOMM and OBEX must all be in the ProtocolDescriptorList
- * <LI>The <code>ServiceRecord</code> associated with this notifier must not
- * have changed the RFCOMM server channel number
- * </UL>
- * <P>
- * This method will not ensure that <code>ServiceRecord</code> associated
- * with this notifier is a completely valid service record. It is the
- * responsibility of the application to ensure that the service record
- * follows all of the applicable syntactic and semantic rules for service
- * record correctness.
- * @param handler the request handler that will respond to OBEX requests
- * @param auth the <code>Authenticator</code> to use with this connection;
- * if <code>null</code> then no <code>Authenticator</code> will be
- * used
- * @return the connection to the client
- * @throws IOException if an error occurs in the transport layer
- * @throws NullPointerException if <code>handler</code> is <code>null</code>
- */
- ObexSession acceptAndOpen(ServerRequestHandler handler, Authenticator auth) throws IOException;
-}
diff --git a/services/cloudsearch/java/com/android/server/cloudsearch/CloudSearchManagerService.java b/services/cloudsearch/java/com/android/server/cloudsearch/CloudSearchManagerService.java
index daead0a..b1f572d 100644
--- a/services/cloudsearch/java/com/android/server/cloudsearch/CloudSearchManagerService.java
+++ b/services/cloudsearch/java/com/android/server/cloudsearch/CloudSearchManagerService.java
@@ -43,6 +43,8 @@
import com.android.server.wm.ActivityTaskManagerInternal;
import java.io.FileDescriptor;
+import java.util.ArrayList;
+import java.util.List;
import java.util.function.Consumer;
/**
@@ -62,7 +64,7 @@
public CloudSearchManagerService(Context context) {
super(context, new FrameworkResourcesServiceNameResolver(context,
- R.string.config_defaultCloudSearchService), null,
+ R.array.config_defaultCloudSearchServices, true), null,
PACKAGE_UPDATE_POLICY_NO_REFRESH | PACKAGE_RESTART_POLICY_NO_REFRESH);
mActivityTaskManagerInternal = LocalServices.getService(ActivityTaskManagerInternal.class);
mContext = context;
@@ -70,7 +72,25 @@
@Override
protected CloudSearchPerUserService newServiceLocked(int resolvedUserId, boolean disabled) {
- return new CloudSearchPerUserService(this, mLock, resolvedUserId);
+ return new CloudSearchPerUserService(this, mLock, resolvedUserId, "");
+ }
+
+ @Override
+ protected List<CloudSearchPerUserService> newServiceListLocked(int resolvedUserId,
+ boolean disabled, String[] serviceNames) {
+ if (serviceNames == null) {
+ return new ArrayList<>();
+ }
+ List<CloudSearchPerUserService> serviceList =
+ new ArrayList<>(serviceNames.length);
+ for (int i = 0; i < serviceNames.length; i++) {
+ if (serviceNames[i] == null) {
+ continue;
+ }
+ serviceList.add(new CloudSearchPerUserService(this, mLock, resolvedUserId,
+ serviceNames[i]));
+ }
+ return serviceList;
}
@Override
@@ -111,19 +131,28 @@
@NonNull ICloudSearchManagerCallback callBack) {
searchRequest.setSource(
mContext.getPackageManager().getNameForUid(Binder.getCallingUid()));
- runForUserLocked("search", searchRequest.getRequestId(), (service) ->
- service.onSearchLocked(searchRequest, callBack));
+ runForUser("search", (service) -> {
+ synchronized (service.mLock) {
+ service.onSearchLocked(searchRequest, callBack);
+ }
+ });
}
@Override
public void returnResults(IBinder token, String requestId, SearchResponse response) {
- runForUserLocked("returnResults", requestId, (service) ->
- service.onReturnResultsLocked(token, requestId, response));
+ runForUser("returnResults", (service) -> {
+ synchronized (service.mLock) {
+ service.onReturnResultsLocked(token, requestId, response);
+ }
+ });
}
public void destroy(@NonNull SearchRequest searchRequest) {
- runForUserLocked("destroyCloudSearchSession", searchRequest.getRequestId(),
- (service) -> service.onDestroyLocked(searchRequest.getRequestId()));
+ runForUser("destroyCloudSearchSession", (service) -> {
+ synchronized (service.mLock) {
+ service.onDestroyLocked(searchRequest.getRequestId());
+ }
+ });
}
public void onShellCommand(@Nullable FileDescriptor in, @Nullable FileDescriptor out,
@@ -134,8 +163,7 @@
.exec(this, in, out, err, args, callback, resultReceiver);
}
- private void runForUserLocked(@NonNull final String func,
- @NonNull final String requestId,
+ private void runForUser(@NonNull final String func,
@NonNull final Consumer<CloudSearchPerUserService> c) {
ActivityManagerInternal am = LocalServices.getService(ActivityManagerInternal.class);
final int userId = am.handleIncomingUser(Binder.getCallingPid(), Binder.getCallingUid(),
@@ -143,7 +171,7 @@
null, null);
if (DEBUG) {
- Slog.d(TAG, "runForUserLocked:" + func + " from pid=" + Binder.getCallingPid()
+ Slog.d(TAG, "runForUser:" + func + " from pid=" + Binder.getCallingPid()
+ ", uid=" + Binder.getCallingUid());
}
Context ctx = getContext();
@@ -160,8 +188,11 @@
final long origId = Binder.clearCallingIdentity();
try {
synchronized (mLock) {
- final CloudSearchPerUserService service = getServiceForUserLocked(userId);
- c.accept(service);
+ final List<CloudSearchPerUserService> services =
+ getServiceListForUserLocked(userId);
+ for (int i = 0; i < services.size(); i++) {
+ c.accept(services.get(i));
+ }
}
} finally {
Binder.restoreCallingIdentity(origId);
diff --git a/services/cloudsearch/java/com/android/server/cloudsearch/CloudSearchManagerServiceShellCommand.java b/services/cloudsearch/java/com/android/server/cloudsearch/CloudSearchManagerServiceShellCommand.java
index 51f5fd9..c64982d 100644
--- a/services/cloudsearch/java/com/android/server/cloudsearch/CloudSearchManagerServiceShellCommand.java
+++ b/services/cloudsearch/java/com/android/server/cloudsearch/CloudSearchManagerServiceShellCommand.java
@@ -54,7 +54,12 @@
return 0;
}
final int duration = Integer.parseInt(getNextArgRequired());
- mService.setTemporaryService(userId, serviceName, duration);
+ String[] services = serviceName.split(";");
+ if (services.length == 0) {
+ return 0;
+ } else {
+ mService.setTemporaryServices(userId, services, duration);
+ }
pw.println("CloudSearchService temporarily set to " + serviceName
+ " for " + duration + "ms");
break;
diff --git a/services/cloudsearch/java/com/android/server/cloudsearch/CloudSearchPerUserService.java b/services/cloudsearch/java/com/android/server/cloudsearch/CloudSearchPerUserService.java
index 32d66af..116c739 100644
--- a/services/cloudsearch/java/com/android/server/cloudsearch/CloudSearchPerUserService.java
+++ b/services/cloudsearch/java/com/android/server/cloudsearch/CloudSearchPerUserService.java
@@ -49,6 +49,8 @@
@GuardedBy("mLock")
private final CircularQueue<String, CloudSearchCallbackInfo> mCallbackQueue =
new CircularQueue<>(QUEUE_SIZE);
+ private final String mServiceName;
+ private final ComponentName mRemoteComponentName;
@Nullable
@GuardedBy("mLock")
private RemoteCloudSearchService mRemoteService;
@@ -60,8 +62,10 @@
private boolean mZombie;
protected CloudSearchPerUserService(CloudSearchManagerService master,
- Object lock, int userId) {
+ Object lock, int userId, String serviceName) {
super(master, lock, userId);
+ mServiceName = serviceName;
+ mRemoteComponentName = ComponentName.unflattenFromString(mServiceName);
}
@Override // from PerUserSystemService
@@ -108,7 +112,7 @@
? searchRequest.getSearchConstraints().getString(
SearchRequest.CONSTRAINT_SEARCH_PROVIDER_FILTER) : "";
- String remoteServicePackageName = getServiceComponentName().getPackageName();
+ String remoteServicePackageName = mRemoteComponentName.getPackageName();
// By default, all providers are marked as wanted.
boolean wantedProvider = true;
if (filterList.length() > 0) {
@@ -150,11 +154,19 @@
/**
* Used to return results back to the clients.
*/
+ @GuardedBy("mLock")
public void onReturnResultsLocked(@NonNull IBinder token,
@NonNull String requestId,
@NonNull SearchResponse response) {
+ if (mRemoteService == null) {
+ return;
+ }
+ ICloudSearchService serviceInterface = mRemoteService.getServiceInterface();
+ if (serviceInterface == null || token != serviceInterface.asBinder()) {
+ return;
+ }
if (mCallbackQueue.containsKey(requestId)) {
- response.setSource(mRemoteService.getComponentName().getPackageName());
+ response.setSource(mServiceName);
final CloudSearchCallbackInfo sessionInfo = mCallbackQueue.getElement(requestId);
try {
if (response.getStatusCode() == SearchResponse.SEARCH_STATUS_OK) {
@@ -163,6 +175,10 @@
sessionInfo.mCallback.onSearchFailed(response);
}
} catch (RemoteException e) {
+ if (mMaster.debug) {
+ Slog.e(TAG, "Exception in posting results");
+ e.printStackTrace();
+ }
onDestroyLocked(requestId);
}
}
@@ -297,7 +313,7 @@
@Nullable
private RemoteCloudSearchService getRemoteServiceLocked() {
if (mRemoteService == null) {
- final String serviceName = getComponentNameLocked();
+ final String serviceName = getComponentNameForMultipleLocked(mServiceName);
if (serviceName == null) {
if (mMaster.verbose) {
Slog.v(TAG, "getRemoteServiceLocked(): not set");
diff --git a/services/core/java/com/android/server/infra/AbstractMasterSystemService.java b/services/core/java/com/android/server/infra/AbstractMasterSystemService.java
index 9e00f95..29e5f92 100644
--- a/services/core/java/com/android/server/infra/AbstractMasterSystemService.java
+++ b/services/core/java/com/android/server/infra/AbstractMasterSystemService.java
@@ -48,6 +48,7 @@
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.List;
import java.util.Objects;
@@ -168,10 +169,10 @@
private final SparseBooleanArray mDisabledByUserRestriction;
/**
- * Cache of services per user id.
+ * Cache of service list per user id.
*/
@GuardedBy("mLock")
- private final SparseArray<S> mServicesCache = new SparseArray<>();
+ private final SparseArray<List<S>> mServicesCacheList = new SparseArray<>();
/**
* Value that determines whether the per-user service should be removed from the cache when its
@@ -252,8 +253,7 @@
mServiceNameResolver = serviceNameResolver;
if (mServiceNameResolver != null) {
mServiceNameResolver.setOnTemporaryServiceNameChangedCallback(
- (u, s, t) -> onServiceNameChanged(u, s, t));
-
+ this::onServiceNameChanged);
}
if (disallowProperty == null) {
mDisabledByUserRestriction = null;
@@ -308,7 +308,7 @@
@Override // from SystemService
public void onUserStopped(@NonNull TargetUser user) {
synchronized (mLock) {
- removeCachedServiceLocked(user.getUserIdentifier());
+ removeCachedServiceListLocked(user.getUserIdentifier());
}
}
@@ -386,21 +386,58 @@
synchronized (mLock) {
final S oldService = peekServiceForUserLocked(userId);
if (oldService != null) {
- oldService.removeSelfFromCacheLocked();
+ oldService.removeSelfFromCache();
}
mServiceNameResolver.setTemporaryService(userId, componentName, durationMs);
}
}
/**
+ * Temporarily sets the service implementation.
+ *
+ * <p>Typically used by Shell command and/or CTS tests.
+ *
+ * @param componentNames list of the names of the new component
+ * @param durationMs how long the change will be valid (the service will be automatically
+ * reset
+ * to the default component after this timeout expires).
+ * @throws SecurityException if caller is not allowed to manage this service's settings.
+ * @throws IllegalArgumentException if value of {@code durationMs} is higher than
+ * {@link #getMaximumTemporaryServiceDurationMs()}.
+ */
+ public final void setTemporaryServices(@UserIdInt int userId, @NonNull String[] componentNames,
+ int durationMs) {
+ Slog.i(mTag, "setTemporaryService(" + userId + ") to " + Arrays.toString(componentNames)
+ + " for " + durationMs + "ms");
+ if (mServiceNameResolver == null) {
+ return;
+ }
+ enforceCallingPermissionForManagement();
+
+ Objects.requireNonNull(componentNames);
+ final int maxDurationMs = getMaximumTemporaryServiceDurationMs();
+ if (durationMs > maxDurationMs) {
+ throw new IllegalArgumentException(
+ "Max duration is " + maxDurationMs + " (called with " + durationMs + ")");
+ }
+
+ synchronized (mLock) {
+ final S oldService = peekServiceForUserLocked(userId);
+ if (oldService != null) {
+ oldService.removeSelfFromCache();
+ }
+ mServiceNameResolver.setTemporaryServices(userId, componentNames, durationMs);
+ }
+ }
+
+ /**
* Sets whether the default service should be used.
*
* <p>Typically used during CTS tests to make sure only the default service doesn't interfere
* with the test results.
*
- * @throws SecurityException if caller is not allowed to manage this service's settings.
- *
* @return whether the enabled state changed.
+ * @throws SecurityException if caller is not allowed to manage this service's settings.
*/
public final boolean setDefaultServiceEnabled(@UserIdInt int userId, boolean enabled) {
Slog.i(mTag, "setDefaultServiceEnabled() for userId " + userId + ": " + enabled);
@@ -420,7 +457,7 @@
final S oldService = peekServiceForUserLocked(userId);
if (oldService != null) {
- oldService.removeSelfFromCacheLocked();
+ oldService.removeSelfFromCache();
}
// Must update the service on cache so its initialization code is triggered
@@ -501,6 +538,21 @@
protected abstract S newServiceLocked(@UserIdInt int resolvedUserId, boolean disabled);
/**
+ * Creates a new service list that will be added to the cache.
+ *
+ * @param resolvedUserId the resolved user id for the service.
+ * @param disabled whether the service is currently disabled (due to {@link UserManager}
+ * restrictions).
+ * @return a new instance.
+ */
+ @Nullable
+ @GuardedBy("mLock")
+ protected List<S> newServiceListLocked(@UserIdInt int resolvedUserId, boolean disabled,
+ String[] serviceNames) {
+ throw new UnsupportedOperationException("newServiceListLocked not implemented. ");
+ }
+
+ /**
* Register the service for extra Settings changes (i.e., other than
* {@link android.provider.Settings.Secure#USER_SETUP_COMPLETE} or
* {@link #getServiceSettingsProperty()}, which are automatically handled).
@@ -516,7 +568,6 @@
* <p><b>NOTE: </p>it doesn't need to register for
* {@link android.provider.Settings.Secure#USER_SETUP_COMPLETE} or
* {@link #getServiceSettingsProperty()}.
- *
*/
@SuppressWarnings("unused")
protected void registerForExtraSettingsChanges(@NonNull ContentResolver resolver,
@@ -527,7 +578,7 @@
* Callback for Settings changes that were registered though
* {@link #registerForExtraSettingsChanges(ContentResolver, ContentObserver)}.
*
- * @param userId user associated with the change
+ * @param userId user associated with the change
* @param property Settings property changed.
*/
protected void onSettingsChanged(@UserIdInt int userId, @NonNull String property) {
@@ -539,18 +590,38 @@
@GuardedBy("mLock")
@NonNull
protected S getServiceForUserLocked(@UserIdInt int userId) {
+ List<S> services = getServiceListForUserLocked(userId);
+ return services == null || services.size() == 0 ? null : services.get(0);
+ }
+
+ /**
+ * Gets the service instance list for a user, creating instances if not present in the cache.
+ */
+ @GuardedBy("mLock")
+ protected List<S> getServiceListForUserLocked(@UserIdInt int userId) {
final int resolvedUserId = ActivityManager.handleIncomingUser(Binder.getCallingPid(),
Binder.getCallingUid(), userId, false, false, null, null);
- S service = mServicesCache.get(resolvedUserId);
- if (service == null) {
+ List<S> services = mServicesCacheList.get(resolvedUserId);
+ if (services == null || services.size() == 0) {
final boolean disabled = isDisabledLocked(userId);
- service = newServiceLocked(resolvedUserId, disabled);
- if (!disabled) {
- onServiceEnabledLocked(service, resolvedUserId);
+ if (mServiceNameResolver == null) {
+ return null;
}
- mServicesCache.put(userId, service);
+ if (mServiceNameResolver.isConfiguredInMultipleMode()) {
+ services = newServiceListLocked(resolvedUserId, disabled,
+ mServiceNameResolver.getServiceNameList(userId));
+ } else {
+ services = new ArrayList<>();
+ services.add(newServiceLocked(resolvedUserId, disabled));
+ }
+ if (!disabled) {
+ for (int i = 0; i < services.size(); i++) {
+ onServiceEnabledLocked(services.get(i), resolvedUserId);
+ }
+ }
+ mServicesCacheList.put(userId, services);
}
- return service;
+ return services;
}
/**
@@ -560,9 +631,20 @@
@GuardedBy("mLock")
@Nullable
protected S peekServiceForUserLocked(@UserIdInt int userId) {
+ List<S> serviceList = peekServiceListForUserLocked(userId);
+ return serviceList == null || serviceList.size() == 0 ? null : serviceList.get(0);
+ }
+
+ /**
+ * Gets the <b>existing</b> service instance for a user, returning {@code null} if not already
+ * present in the cache.
+ */
+ @GuardedBy("mLock")
+ @Nullable
+ protected List<S> peekServiceListForUserLocked(@UserIdInt int userId) {
final int resolvedUserId = ActivityManager.handleIncomingUser(Binder.getCallingPid(),
Binder.getCallingUid(), userId, false, false, null, null);
- return mServicesCache.get(resolvedUserId);
+ return mServicesCacheList.get(resolvedUserId);
}
/**
@@ -570,36 +652,59 @@
*/
@GuardedBy("mLock")
protected void updateCachedServiceLocked(@UserIdInt int userId) {
- updateCachedServiceLocked(userId, isDisabledLocked(userId));
+ updateCachedServiceListLocked(userId, isDisabledLocked(userId));
}
/**
* Checks whether the service is disabled (through {@link UserManager} restrictions) for the
* given user.
*/
+ @GuardedBy("mLock")
protected boolean isDisabledLocked(@UserIdInt int userId) {
- return mDisabledByUserRestriction == null ? false : mDisabledByUserRestriction.get(userId);
+ return mDisabledByUserRestriction != null && mDisabledByUserRestriction.get(userId);
}
/**
* Updates a cached service for a given user.
*
- * @param userId user handle.
+ * @param userId user handle.
* @param disabled whether the user is disabled.
* @return service for the user.
*/
@GuardedBy("mLock")
protected S updateCachedServiceLocked(@UserIdInt int userId, boolean disabled) {
final S service = getServiceForUserLocked(userId);
- if (service != null) {
- service.updateLocked(disabled);
- if (!service.isEnabledLocked()) {
- removeCachedServiceLocked(userId);
- } else {
- onServiceEnabledLocked(service, userId);
+ updateCachedServiceListLocked(userId, disabled);
+ return service;
+ }
+
+ /**
+ * Updates a cached service for a given user.
+ *
+ * @param userId user handle.
+ * @param disabled whether the user is disabled.
+ * @return service for the user.
+ */
+ @GuardedBy("mLock")
+ protected List<S> updateCachedServiceListLocked(@UserIdInt int userId, boolean disabled) {
+ final List<S> services = getServiceListForUserLocked(userId);
+ if (services == null) {
+ return null;
+ }
+ for (int i = 0; i < services.size(); i++) {
+ S service = services.get(i);
+ if (service != null) {
+ synchronized (service.mLock) {
+ service.updateLocked(disabled);
+ if (!service.isEnabledLocked()) {
+ removeCachedServiceListLocked(userId);
+ } else {
+ onServiceEnabledLocked(services.get(i), userId);
+ }
+ }
}
}
- return service;
+ return services;
}
/**
@@ -619,28 +724,32 @@
* <p>By default doesn't do anything, but can be overridden by subclasses.
*/
@SuppressWarnings("unused")
+ @GuardedBy("mLock")
protected void onServiceEnabledLocked(@NonNull S service, @UserIdInt int userId) {
}
/**
- * Removes a cached service for a given user.
+ * Removes a cached service list for a given user.
*
* @return the removed service.
*/
@GuardedBy("mLock")
@NonNull
- protected final S removeCachedServiceLocked(@UserIdInt int userId) {
- final S service = peekServiceForUserLocked(userId);
- if (service != null) {
- mServicesCache.delete(userId);
- onServiceRemoved(service, userId);
+ protected final List<S> removeCachedServiceListLocked(@UserIdInt int userId) {
+ final List<S> services = peekServiceListForUserLocked(userId);
+ if (services != null) {
+ mServicesCacheList.delete(userId);
+ for (int i = 0; i < services.size(); i++) {
+ onServiceRemoved(services.get(i), userId);
+ }
}
- return service;
+ return services;
}
/**
* Called before the package that provides the service for the given user is being updated.
*/
+ @GuardedBy("mLock")
protected void onServicePackageUpdatingLocked(@UserIdInt int userId) {
if (verbose) Slog.v(mTag, "onServicePackageUpdatingLocked(" + userId + ")");
}
@@ -648,6 +757,7 @@
/**
* Called after the package that provides the service for the given user is being updated.
*/
+ @GuardedBy("mLock")
protected void onServicePackageUpdatedLocked(@UserIdInt int userId) {
if (verbose) Slog.v(mTag, "onServicePackageUpdated(" + userId + ")");
}
@@ -655,6 +765,7 @@
/**
* Called after the package data that provides the service for the given user is cleared.
*/
+ @GuardedBy("mLock")
protected void onServicePackageDataClearedLocked(@UserIdInt int userId) {
if (verbose) Slog.v(mTag, "onServicePackageDataCleared(" + userId + ")");
}
@@ -662,6 +773,7 @@
/**
* Called after the package that provides the service for the given user is restarted.
*/
+ @GuardedBy("mLock")
protected void onServicePackageRestartedLocked(@UserIdInt int userId) {
if (verbose) Slog.v(mTag, "onServicePackageRestarted(" + userId + ")");
}
@@ -679,14 +791,31 @@
* <p>By default, it calls {@link #updateCachedServiceLocked(int)}; subclasses must either call
* that same method, or {@code super.onServiceNameChanged()}.
*
- * @param userId user handle.
+ * @param userId user handle.
* @param serviceName the new service name.
* @param isTemporary whether the new service is temporary.
*/
protected void onServiceNameChanged(@UserIdInt int userId, @Nullable String serviceName,
boolean isTemporary) {
synchronized (mLock) {
- updateCachedServiceLocked(userId);
+ updateCachedServiceListLocked(userId, isDisabledLocked(userId));
+ }
+ }
+
+ /**
+ * Called when the service name list has changed (typically when using temporary services).
+ *
+ * <p>By default, it calls {@link #updateCachedServiceLocked(int)}; subclasses must either call
+ * that same method, or {@code super.onServiceNameChanged()}.
+ *
+ * @param userId user handle.
+ * @param serviceNames the new service name list.
+ * @param isTemporary whether the new service is temporary.
+ */
+ protected void onServiceNameListChanged(@UserIdInt int userId, @Nullable String[] serviceNames,
+ boolean isTemporary) {
+ synchronized (mLock) {
+ updateCachedServiceListLocked(userId, isDisabledLocked(userId));
}
}
@@ -695,9 +824,12 @@
*/
@GuardedBy("mLock")
protected void visitServicesLocked(@NonNull Visitor<S> visitor) {
- final int size = mServicesCache.size();
+ final int size = mServicesCacheList.size();
for (int i = 0; i < size; i++) {
- visitor.visit(mServicesCache.valueAt(i));
+ List<S> services = mServicesCacheList.valueAt(i);
+ for (int j = 0; j < services.size(); j++) {
+ visitor.visit(services.get(j));
+ }
}
}
@@ -706,7 +838,7 @@
*/
@GuardedBy("mLock")
protected void clearCacheLocked() {
- mServicesCache.clear();
+ mServicesCacheList.clear();
}
/**
@@ -757,6 +889,7 @@
}
// TODO(b/117779333): support proto
+ @GuardedBy("mLock")
protected void dumpLocked(@NonNull String prefix, @NonNull PrintWriter pw) {
boolean realDebug = debug;
boolean realVerbose = verbose;
@@ -765,40 +898,64 @@
try {
// Temporarily turn on full logging;
debug = verbose = true;
- final int size = mServicesCache.size();
- pw.print(prefix); pw.print("Debug: "); pw.print(realDebug);
- pw.print(" Verbose: "); pw.println(realVerbose);
- pw.print("Package policy flags: "); pw.println(mServicePackagePolicyFlags);
+ final int size = mServicesCacheList.size();
+ pw.print(prefix);
+ pw.print("Debug: ");
+ pw.print(realDebug);
+ pw.print(" Verbose: ");
+ pw.println(realVerbose);
+ pw.print("Package policy flags: ");
+ pw.println(mServicePackagePolicyFlags);
if (mUpdatingPackageNames != null) {
- pw.print("Packages being updated: "); pw.println(mUpdatingPackageNames);
+ pw.print("Packages being updated: ");
+ pw.println(mUpdatingPackageNames);
}
dumpSupportedUsers(pw, prefix);
if (mServiceNameResolver != null) {
- pw.print(prefix); pw.print("Name resolver: ");
- mServiceNameResolver.dumpShort(pw); pw.println();
+ pw.print(prefix);
+ pw.print("Name resolver: ");
+ mServiceNameResolver.dumpShort(pw);
+ pw.println();
final List<UserInfo> users = getSupportedUsers();
for (int i = 0; i < users.size(); i++) {
final int userId = users.get(i).id;
- pw.print(prefix2); pw.print(userId); pw.print(": ");
- mServiceNameResolver.dumpShort(pw, userId); pw.println();
+ pw.print(prefix2);
+ pw.print(userId);
+ pw.print(": ");
+ mServiceNameResolver.dumpShort(pw, userId);
+ pw.println();
}
}
- pw.print(prefix); pw.print("Users disabled by restriction: ");
+ pw.print(prefix);
+ pw.print("Users disabled by restriction: ");
pw.println(mDisabledByUserRestriction);
- pw.print(prefix); pw.print("Allow instant service: "); pw.println(mAllowInstantService);
+ pw.print(prefix);
+ pw.print("Allow instant service: ");
+ pw.println(mAllowInstantService);
final String settingsProperty = getServiceSettingsProperty();
if (settingsProperty != null) {
- pw.print(prefix); pw.print("Settings property: "); pw.println(settingsProperty);
+ pw.print(prefix);
+ pw.print("Settings property: ");
+ pw.println(settingsProperty);
}
- pw.print(prefix); pw.print("Cached services: ");
+ pw.print(prefix);
+ pw.print("Cached services: ");
if (size == 0) {
pw.println("none");
} else {
pw.println(size);
for (int i = 0; i < size; i++) {
- pw.print(prefix); pw.print("Service at "); pw.print(i); pw.println(": ");
- final S service = mServicesCache.valueAt(i);
- service.dumpLocked(prefix2, pw);
+ pw.print(prefix);
+ pw.print("Service at ");
+ pw.print(i);
+ pw.println(": ");
+ final List<S> services = mServicesCacheList.valueAt(i);
+ for (int j = 0; j < services.size(); j++) {
+ S service = services.get(i);
+ synchronized (service.mLock) {
+ service.dumpLocked(prefix2, pw);
+ }
+ }
pw.println();
}
}
@@ -820,7 +977,7 @@
final int userId = getChangingUserId();
synchronized (mLock) {
if (mUpdatingPackageNames == null) {
- mUpdatingPackageNames = new SparseArray<String>(mServicesCache.size());
+ mUpdatingPackageNames = new SparseArray<String>(mServicesCacheList.size());
}
mUpdatingPackageNames.put(userId, packageName);
onServicePackageUpdatingLocked(userId);
@@ -835,7 +992,7 @@
+ " because package " + activePackageName
+ " is being updated");
}
- removeCachedServiceLocked(userId);
+ removeCachedServiceListLocked(userId);
if ((mServicePackagePolicyFlags & PACKAGE_UPDATE_POLICY_REFRESH_EAGER)
!= 0) {
@@ -901,7 +1058,7 @@
if (Intent.ACTION_PACKAGE_RESTARTED.equals(action)) {
handleActiveServiceRestartedLocked(activePackageName, userId);
} else {
- removeCachedServiceLocked(userId);
+ removeCachedServiceListLocked(userId);
}
} else {
handlePackageUpdateLocked(pkg);
@@ -930,7 +1087,7 @@
private void handleActiveServiceRemoved(@UserIdInt int userId) {
synchronized (mLock) {
- removeCachedServiceLocked(userId);
+ removeCachedServiceListLocked(userId);
}
final String serviceSettingsProperty = getServiceSettingsProperty();
if (serviceSettingsProperty != null) {
@@ -939,6 +1096,7 @@
}
}
+ @GuardedBy("mLock")
private void handleActiveServiceRestartedLocked(String activePackageName,
@UserIdInt int userId) {
if ((mServicePackagePolicyFlags & PACKAGE_RESTART_POLICY_NO_REFRESH) != 0) {
@@ -952,7 +1110,7 @@
+ " because package " + activePackageName
+ " is being restarted");
}
- removeCachedServiceLocked(userId);
+ removeCachedServiceListLocked(userId);
if ((mServicePackagePolicyFlags & PACKAGE_RESTART_POLICY_REFRESH_EAGER) != 0) {
if (debug) {
@@ -966,14 +1124,27 @@
@Override
public void onPackageModified(String packageName) {
- if (verbose) Slog.v(mTag, "onPackageModified(): " + packageName);
+ synchronized (mLock) {
+ if (verbose) Slog.v(mTag, "onPackageModified(): " + packageName);
- if (mServiceNameResolver == null) {
- return;
+ if (mServiceNameResolver == null) {
+ return;
+ }
+
+ final int userId = getChangingUserId();
+ final String[] serviceNames = mServiceNameResolver.getDefaultServiceNameList(
+ userId);
+ if (serviceNames != null) {
+ for (int i = 0; i < serviceNames.length; i++) {
+ peekAndUpdateCachedServiceLocked(packageName, userId, serviceNames[i]);
+ }
+ }
}
+ }
- final int userId = getChangingUserId();
- final String serviceName = mServiceNameResolver.getDefaultServiceName(userId);
+ @GuardedBy("mLock")
+ private void peekAndUpdateCachedServiceLocked(String packageName, int userId,
+ String serviceName) {
if (serviceName == null) {
return;
}
@@ -997,6 +1168,7 @@
}
}
+ @GuardedBy("mLock")
private String getActiveServicePackageNameLocked() {
final int userId = getChangingUserId();
final S service = peekServiceForUserLocked(userId);
@@ -1017,7 +1189,7 @@
};
// package changes
- monitor.register(getContext(), null, UserHandle.ALL, true);
+ monitor.register(getContext(), null, UserHandle.ALL, true);
}
/**
diff --git a/services/core/java/com/android/server/infra/AbstractPerUserSystemService.java b/services/core/java/com/android/server/infra/AbstractPerUserSystemService.java
index 757a5cc..58413c9 100644
--- a/services/core/java/com/android/server/infra/AbstractPerUserSystemService.java
+++ b/services/core/java/com/android/server/infra/AbstractPerUserSystemService.java
@@ -43,14 +43,13 @@
*
* @param <M> "main" service class.
* @param <S> "real" service class.
- *
* @hide
*/
public abstract class AbstractPerUserSystemService<S extends AbstractPerUserSystemService<S, M>,
M extends AbstractMasterSystemService<M, S>> {
- protected final @UserIdInt int mUserId;
- protected final Object mLock;
+ @UserIdInt protected final int mUserId;
+ public final Object mLock;
protected final String mTag = getClass().getSimpleName();
protected final M mMaster;
@@ -91,14 +90,14 @@
* <p><b>MUST</b> be overridden by subclasses that bind to an
* {@link com.android.internal.infra.AbstractRemoteService}.
*
- * @throws NameNotFoundException if the service does not exist.
- * @throws SecurityException if the service does not have the proper permissions to be bound to.
- * @throws UnsupportedOperationException if subclass binds to a remote service but does not
- * overrides it.
- *
* @return new {@link ServiceInfo},
+ * @throws NameNotFoundException if the service does not exist.
+ * @throws SecurityException if the service does not have the proper permissions to
+ * be bound to.
+ * @throws UnsupportedOperationException if subclass binds to a remote service but does not
+ * overrides it.
*/
- protected @NonNull ServiceInfo newServiceInfoLocked(
+ @NonNull protected ServiceInfo newServiceInfoLocked(
@SuppressWarnings("unused") @NonNull ComponentName serviceComponent)
throws NameNotFoundException {
throw new UnsupportedOperationException("not overridden");
@@ -137,7 +136,6 @@
* previous state.
*
* @param disabled whether the service is disabled (due to {@link UserManager} restrictions).
- *
* @return whether the disabled state changed.
*/
@GuardedBy("mLock")
@@ -154,18 +152,48 @@
updateIsSetupComplete(mUserId);
mDisabled = disabled;
- updateServiceInfoLocked();
+ if (mMaster.mServiceNameResolver.isConfiguredInMultipleMode()) {
+ updateServiceInfoListLocked();
+ } else {
+ updateServiceInfoLocked();
+ }
return wasEnabled != isEnabledLocked();
}
/**
* Updates the internal reference to the service info, and returns the service's component.
*/
+ @GuardedBy("mLock")
protected final ComponentName updateServiceInfoLocked() {
- ComponentName serviceComponent = null;
- if (mMaster.mServiceNameResolver != null) {
- ServiceInfo serviceInfo = null;
+ ComponentName[] componentNames = updateServiceInfoListLocked();
+ return componentNames == null || componentNames.length == 0 ? null : componentNames[0];
+ }
+
+ /**
+ * Updates the internal reference to the service info, and returns the service's component.
+ */
+ @GuardedBy("mLock")
+ protected final ComponentName[] updateServiceInfoListLocked() {
+ if (mMaster.mServiceNameResolver == null) {
+ return null;
+ }
+ if (!mMaster.mServiceNameResolver.isConfiguredInMultipleMode()) {
final String componentName = getComponentNameLocked();
+ return new ComponentName[] { getServiceComponent(componentName) };
+ }
+ final String[] componentNames = mMaster.mServiceNameResolver.getServiceNameList(
+ mUserId);
+ ComponentName[] serviceComponents = new ComponentName[componentNames.length];
+ for (int i = 0; i < componentNames.length; i++) {
+ serviceComponents[i] = getServiceComponent(componentNames[i]);
+ }
+ return serviceComponents;
+ }
+
+ private ComponentName getServiceComponent(String componentName) {
+ synchronized (mLock) {
+ ServiceInfo serviceInfo = null;
+ ComponentName serviceComponent = null;
if (!TextUtils.isEmpty(componentName)) {
try {
serviceComponent = ComponentName.unflattenFromString(componentName);
@@ -196,14 +224,14 @@
Slog.e(mTag, "Bad ServiceInfo for '" + componentName + "': " + e);
mServiceInfo = null;
}
+ return serviceComponent;
}
- return serviceComponent;
}
/**
* Gets the user associated with this service.
*/
- public final @UserIdInt int getUserId() {
+ @UserIdInt public final int getUserId() {
return mUserId;
}
@@ -229,15 +257,34 @@
/**
* Gets the current name of the service, which is either the default service or the
- * {@link AbstractMasterSystemService#setTemporaryService(int, String, int) temporary one}.
+ * {@link AbstractMasterSystemService#setTemporaryService(int, String, int) temporary one}.
*/
- protected final @Nullable String getComponentNameLocked() {
+ @Nullable
+ @GuardedBy("mLock")
+ protected final String getComponentNameLocked() {
return mMaster.mServiceNameResolver.getServiceName(mUserId);
}
/**
+ * Gets the current name of the service, which is either the default service or the
+ * {@link AbstractMasterSystemService#setTemporaryService(int, String, int) temporary one}.
+ */
+ @Nullable
+ @GuardedBy("mLock")
+ protected final String getComponentNameForMultipleLocked(String serviceName) {
+ String[] services = mMaster.mServiceNameResolver.getServiceNameList(mUserId);
+ for (int i = 0; i < services.length; i++) {
+ if (serviceName.equals(services[i])) {
+ return services[i];
+ }
+ }
+ return null;
+ }
+
+ /**
* Checks whether the current service for the user was temporarily set.
*/
+ @GuardedBy("mLock")
public final boolean isTemporaryServiceSetLocked() {
return mMaster.mServiceNameResolver.isTemporary(mUserId);
}
@@ -245,6 +292,7 @@
/**
* Resets the temporary service implementation to the default component.
*/
+ @GuardedBy("mLock")
protected final void resetTemporaryServiceLocked() {
mMaster.mServiceNameResolver.resetTemporaryService(mUserId);
}
@@ -268,6 +316,7 @@
return mServiceInfo == null ? null : mServiceInfo.getComponentName();
}
}
+
/**
* Gets the name of the of the app this service binds to, or {@code null} if the service is
* disabled.
@@ -303,8 +352,10 @@
/**
* Removes the service from the main service's cache.
*/
- protected final void removeSelfFromCacheLocked() {
- mMaster.removeCachedServiceLocked(mUserId);
+ protected final void removeSelfFromCache() {
+ synchronized (mMaster.mLock) {
+ mMaster.removeCachedServiceListLocked(mUserId);
+ }
}
/**
@@ -327,6 +378,7 @@
* Gets the target SDK level of the service this service binds to,
* or {@code 0} if the service is disabled.
*/
+ @GuardedBy("mLock")
public final int getTargedSdkLocked() {
return mServiceInfo == null ? 0 : mServiceInfo.applicationInfo.targetSdkVersion;
}
@@ -334,6 +386,7 @@
/**
* Gets whether the device already finished setup.
*/
+ @GuardedBy("mLock")
protected final boolean isSetupCompletedLocked() {
return mSetupComplete;
}
@@ -348,19 +401,32 @@
// TODO(b/117779333): support proto
@GuardedBy("mLock")
protected void dumpLocked(@NonNull String prefix, @NonNull PrintWriter pw) {
- pw.print(prefix); pw.print("User: "); pw.println(mUserId);
+ pw.print(prefix);
+ pw.print("User: ");
+ pw.println(mUserId);
if (mServiceInfo != null) {
- pw.print(prefix); pw.print("Service Label: "); pw.println(getServiceLabelLocked());
- pw.print(prefix); pw.print("Target SDK: "); pw.println(getTargedSdkLocked());
+ pw.print(prefix);
+ pw.print("Service Label: ");
+ pw.println(getServiceLabelLocked());
+ pw.print(prefix);
+ pw.print("Target SDK: ");
+ pw.println(getTargedSdkLocked());
}
if (mMaster.mServiceNameResolver != null) {
- pw.print(prefix); pw.print("Name resolver: ");
- mMaster.mServiceNameResolver.dumpShort(pw, mUserId); pw.println();
+ pw.print(prefix);
+ pw.print("Name resolver: ");
+ mMaster.mServiceNameResolver.dumpShort(pw, mUserId);
+ pw.println();
}
- pw.print(prefix); pw.print("Disabled by UserManager: "); pw.println(mDisabled);
- pw.print(prefix); pw.print("Setup complete: "); pw.println(mSetupComplete);
+ pw.print(prefix);
+ pw.print("Disabled by UserManager: ");
+ pw.println(mDisabled);
+ pw.print(prefix);
+ pw.print("Setup complete: ");
+ pw.println(mSetupComplete);
if (mServiceInfo != null) {
- pw.print(prefix); pw.print("Service UID: ");
+ pw.print(prefix);
+ pw.print("Service UID: ");
pw.println(mServiceInfo.applicationInfo.uid);
}
pw.println();
diff --git a/services/core/java/com/android/server/infra/FrameworkResourcesServiceNameResolver.java b/services/core/java/com/android/server/infra/FrameworkResourcesServiceNameResolver.java
index 35d5956..db2cb52 100644
--- a/services/core/java/com/android/server/infra/FrameworkResourcesServiceNameResolver.java
+++ b/services/core/java/com/android/server/infra/FrameworkResourcesServiceNameResolver.java
@@ -15,6 +15,7 @@
*/
package com.android.server.infra;
+import android.annotation.ArrayRes;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.StringRes;
@@ -33,6 +34,7 @@
import com.android.internal.annotations.GuardedBy;
import java.io.PrintWriter;
+import java.util.Arrays;
/**
* Gets the service name using a framework resources, temporarily changing the service if necessary
@@ -47,20 +49,20 @@
/** Handler message to {@link #resetTemporaryService(int)} */
private static final int MSG_RESET_TEMPORARY_SERVICE = 0;
- private final @NonNull Context mContext;
- private final @NonNull Object mLock = new Object();
- private final @StringRes int mResourceId;
- private @Nullable NameResolverListener mOnSetCallback;
-
+ @NonNull private final Context mContext;
+ @NonNull private final Object mLock = new Object();
+ @StringRes private final int mStringResourceId;
+ @ArrayRes private final int mArrayResourceId;
+ private final boolean mIsMultiple;
/**
- * Map of temporary service name set by {@link #setTemporaryService(int, String, int)},
+ * Map of temporary service name list set by {@link #setTemporaryServices(int, String[], int)},
* keyed by {@code userId}.
*
- * <p>Typically used by Shell command and/or CTS tests.
+ * <p>Typically used by Shell command and/or CTS tests to configure temporary services if
+ * mIsMultiple is true.
*/
@GuardedBy("mLock")
- private final SparseArray<String> mTemporaryServiceNames = new SparseArray<>();
-
+ private final SparseArray<String[]> mTemporaryServiceNamesList = new SparseArray<>();
/**
* Map of default services that have been disabled by
* {@link #setDefaultServiceEnabled(int, boolean)},keyed by {@code userId}.
@@ -69,7 +71,7 @@
*/
@GuardedBy("mLock")
private final SparseBooleanArray mDefaultServicesDisabled = new SparseBooleanArray();
-
+ @Nullable private NameResolverListener mOnSetCallback;
/**
* When the temporary service will expire (and reset back to the default).
*/
@@ -85,7 +87,22 @@
public FrameworkResourcesServiceNameResolver(@NonNull Context context,
@StringRes int resourceId) {
mContext = context;
- mResourceId = resourceId;
+ mStringResourceId = resourceId;
+ mArrayResourceId = -1;
+ mIsMultiple = false;
+ }
+
+ public FrameworkResourcesServiceNameResolver(@NonNull Context context,
+ @ArrayRes int resourceId, boolean isMultiple) {
+ if (!isMultiple) {
+ throw new UnsupportedOperationException("Please use "
+ + "FrameworkResourcesServiceNameResolver(context, @StringRes int) constructor "
+ + "if single service mode is requested.");
+ }
+ mContext = context;
+ mStringResourceId = -1;
+ mArrayResourceId = resourceId;
+ mIsMultiple = true;
}
@Override
@@ -96,22 +113,31 @@
}
@Override
- public String getDefaultServiceName(@UserIdInt int userId) {
- synchronized (mLock) {
- final String name = mContext.getString(mResourceId);
- return TextUtils.isEmpty(name) ? null : name;
- }
+ public String getServiceName(@UserIdInt int userId) {
+ String[] serviceNames = getServiceNameList(userId);
+ return (serviceNames == null || serviceNames.length == 0) ? null : serviceNames[0];
}
@Override
- public String getServiceName(@UserIdInt int userId) {
+ public String getDefaultServiceName(@UserIdInt int userId) {
+ String[] serviceNames = getDefaultServiceNameList(userId);
+ return (serviceNames == null || serviceNames.length == 0) ? null : serviceNames[0];
+ }
+
+ /**
+ * Gets the default list of the service names for the given user.
+ *
+ * <p>Typically implemented by services which want to provide multiple backends.
+ */
+ @Override
+ public String[] getServiceNameList(int userId) {
synchronized (mLock) {
- final String temporaryName = mTemporaryServiceNames.get(userId);
- if (temporaryName != null) {
+ String[] temporaryNames = mTemporaryServiceNamesList.get(userId);
+ if (temporaryNames != null) {
// Always log it, as it should only be used on CTS or during development
- Slog.w(TAG, "getServiceName(): using temporary name " + temporaryName
- + " for user " + userId);
- return temporaryName;
+ Slog.w(TAG, "getServiceName(): using temporary name "
+ + Arrays.toString(temporaryNames) + " for user " + userId);
+ return temporaryNames;
}
final boolean disabled = mDefaultServicesDisabled.get(userId);
if (disabled) {
@@ -120,22 +146,50 @@
+ "user " + userId);
return null;
}
- return getDefaultServiceName(userId);
+ return getDefaultServiceNameList(userId);
+
}
}
+ /**
+ * Gets the default list of the service names for the given user.
+ *
+ * <p>Typically implemented by services which want to provide multiple backends.
+ */
+ @Override
+ public String[] getDefaultServiceNameList(int userId) {
+ synchronized (mLock) {
+ if (mIsMultiple) {
+ return mContext.getResources().getStringArray(mArrayResourceId);
+ } else {
+ final String name = mContext.getString(mStringResourceId);
+ return TextUtils.isEmpty(name) ? new String[0] : new String[] { name };
+ }
+ }
+ }
+
+ @Override
+ public boolean isConfiguredInMultipleMode() {
+ return mIsMultiple;
+ }
+
@Override
public boolean isTemporary(@UserIdInt int userId) {
synchronized (mLock) {
- return mTemporaryServiceNames.get(userId) != null;
+ return mTemporaryServiceNamesList.get(userId) != null;
}
}
@Override
public void setTemporaryService(@UserIdInt int userId, @NonNull String componentName,
int durationMs) {
+ setTemporaryServices(userId, new String[]{componentName}, durationMs);
+ }
+
+ @Override
+ public void setTemporaryServices(int userId, @NonNull String[] componentNames, int durationMs) {
synchronized (mLock) {
- mTemporaryServiceNames.put(userId, componentName);
+ mTemporaryServiceNamesList.put(userId, componentNames);
if (mTemporaryHandler == null) {
mTemporaryHandler = new Handler(Looper.getMainLooper(), null, true) {
@@ -155,8 +209,10 @@
}
mTemporaryServiceExpiration = SystemClock.elapsedRealtime() + durationMs;
mTemporaryHandler.sendEmptyMessageDelayed(MSG_RESET_TEMPORARY_SERVICE, durationMs);
- notifyTemporaryServiceNameChangedLocked(userId, componentName,
- /* isTemporary= */ true);
+ for (int i = 0; i < componentNames.length; i++) {
+ notifyTemporaryServiceNameChangedLocked(userId, componentNames[i],
+ /* isTemporary= */ true);
+ }
}
}
@@ -164,8 +220,8 @@
public void resetTemporaryService(@UserIdInt int userId) {
synchronized (mLock) {
Slog.i(TAG, "resetting temporary service for user " + userId + " from "
- + mTemporaryServiceNames.get(userId));
- mTemporaryServiceNames.remove(userId);
+ + Arrays.toString(mTemporaryServiceNamesList.get(userId)));
+ mTemporaryServiceNamesList.remove(userId);
if (mTemporaryHandler != null) {
mTemporaryHandler.removeMessages(MSG_RESET_TEMPORARY_SERVICE);
mTemporaryHandler = null;
@@ -207,16 +263,21 @@
@Override
public String toString() {
- return "FrameworkResourcesServiceNamer[temps=" + mTemporaryServiceNames + "]";
+ synchronized (mLock) {
+ return "FrameworkResourcesServiceNamer[temps=" + mTemporaryServiceNamesList + "]";
+ }
}
// TODO(b/117779333): support proto
@Override
public void dumpShort(@NonNull PrintWriter pw) {
synchronized (mLock) {
- pw.print("FrameworkResourcesServiceNamer: resId="); pw.print(mResourceId);
- pw.print(", numberTemps="); pw.print(mTemporaryServiceNames.size());
- pw.print(", enabledDefaults="); pw.print(mDefaultServicesDisabled.size());
+ pw.print("FrameworkResourcesServiceNamer: resId=");
+ pw.print(mStringResourceId);
+ pw.print(", numberTemps=");
+ pw.print(mTemporaryServiceNamesList.size());
+ pw.print(", enabledDefaults=");
+ pw.print(mDefaultServicesDisabled.size());
}
}
@@ -224,13 +285,17 @@
@Override
public void dumpShort(@NonNull PrintWriter pw, @UserIdInt int userId) {
synchronized (mLock) {
- final String temporaryName = mTemporaryServiceNames.get(userId);
- if (temporaryName != null) {
- pw.print("tmpName="); pw.print(temporaryName);
+ final String[] temporaryNames = mTemporaryServiceNamesList.get(userId);
+ if (temporaryNames != null) {
+ pw.print("tmpName=");
+ pw.print(Arrays.toString(temporaryNames));
final long ttl = mTemporaryServiceExpiration - SystemClock.elapsedRealtime();
- pw.print(" (expires in "); TimeUtils.formatDuration(ttl, pw); pw.print("), ");
+ pw.print(" (expires in ");
+ TimeUtils.formatDuration(ttl, pw);
+ pw.print("), ");
}
- pw.print("defaultName="); pw.print(getDefaultServiceName(userId));
+ pw.print("defaultName=");
+ pw.print(getDefaultServiceName(userId));
final boolean disabled = mDefaultServicesDisabled.get(userId);
pw.println(disabled ? " (disabled)" : " (enabled)");
}
diff --git a/services/core/java/com/android/server/infra/ServiceNameResolver.java b/services/core/java/com/android/server/infra/ServiceNameResolver.java
index e20c459..7d85fdb4 100644
--- a/services/core/java/com/android/server/infra/ServiceNameResolver.java
+++ b/services/core/java/com/android/server/infra/ServiceNameResolver.java
@@ -34,7 +34,7 @@
/**
* Listener for name changes.
*/
- public interface NameResolverListener {
+ interface NameResolverListener {
/**
* The name change callback.
@@ -64,6 +64,30 @@
String getDefaultServiceName(@UserIdInt int userId);
/**
+ * Gets the default list of names of the services for the given user.
+ *
+ * <p>Typically implemented by reading a Settings property or framework resource.
+ */
+ @Nullable
+ default String[] getDefaultServiceNameList(@UserIdInt int userId) {
+ if (isConfiguredInMultipleMode()) {
+ throw new UnsupportedOperationException("getting default service list not supported");
+ } else {
+ return new String[] { getDefaultServiceName(userId) };
+ }
+ }
+
+ /**
+ * Returns whether the resolver is configured to connect to multiple backend services.
+ * The default return type is false.
+ *
+ * <p>Typically implemented by reading a Settings property or framework resource.
+ */
+ default boolean isConfiguredInMultipleMode() {
+ return false;
+ }
+
+ /**
* Gets the current name of the service for the given user
*
* @return either the temporary name (set by
@@ -76,6 +100,18 @@
}
/**
+ * Gets the current name of the service for the given user
+ *
+ * @return either the temporary name (set by
+ * {@link #setTemporaryService(int, String, int)}, or the
+ * {@link #getDefaultServiceName(int) default name}.
+ */
+ @Nullable
+ default String[] getServiceNameList(@UserIdInt int userId) {
+ return getDefaultServiceNameList(userId);
+ }
+
+ /**
* Checks whether the current service is temporary for the given user.
*/
default boolean isTemporary(@SuppressWarnings("unused") @UserIdInt int userId) {
@@ -85,11 +121,11 @@
/**
* Temporarily sets the service implementation for the given user.
*
- * @param userId user handle
+ * @param userId user handle
* @param componentName name of the new component
- * @param durationMs how long the change will be valid (the service will be automatically reset
- * to the default component after this timeout expires).
- *
+ * @param durationMs how long the change will be valid (the service will be automatically
+ * reset
+ * to the default component after this timeout expires).
* @throws UnsupportedOperationException if not implemented.
*/
default void setTemporaryService(@UserIdInt int userId, @NonNull String componentName,
@@ -98,10 +134,24 @@
}
/**
+ * Temporarily sets the service implementation for the given user.
+ *
+ * @param userId user handle
+ * @param componentNames list of the names of the new component
+ * @param durationMs how long the change will be valid (the service will be automatically
+ * reset
+ * to the default component after this timeout expires).
+ * @throws UnsupportedOperationException if not implemented.
+ */
+ default void setTemporaryServices(@UserIdInt int userId, @NonNull String[] componentNames,
+ int durationMs) {
+ throw new UnsupportedOperationException("temporary user not supported");
+ }
+
+ /**
* Resets the temporary service implementation to the default component for the given user.
*
* @param userId user handle
- *
* @throws UnsupportedOperationException if not implemented.
*/
default void resetTemporaryService(@UserIdInt int userId) {
@@ -114,11 +164,11 @@
* <p>Typically used during CTS tests to make sure only the default service doesn't interfere
* with the test results.
*
- * @param userId user handle
+ * @param userId user handle
* @param enabled whether the default service should be used when the temporary service is not
- * set. If the service enabled state is already that value, the command is ignored and this
- * method return {@code false}.
- *
+ * set. If the service enabled state is already that value, the command is
+ * ignored and this
+ * method return {@code false}.
* @return whether the enabled state changed.
* @throws UnsupportedOperationException if not implemented.
*/
@@ -133,7 +183,6 @@
* with the test results.
*
* @param userId user handle
- *
* @throws UnsupportedOperationException if not implemented.
*/
default boolean isDefaultServiceEnabled(@UserIdInt int userId) {
diff --git a/services/core/java/com/android/server/wm/AccessibilityController.java b/services/core/java/com/android/server/wm/AccessibilityController.java
index 57f77d5..8f703c5 100644
--- a/services/core/java/com/android/server/wm/AccessibilityController.java
+++ b/services/core/java/com/android/server/wm/AccessibilityController.java
@@ -263,8 +263,6 @@
FLAGS_MAGNIFICATION_CALLBACK | FLAGS_WINDOWS_FOR_ACCESSIBILITY_CALLBACK,
"displayId=" + displayId + "; spec={" + spec + "}");
}
- mAccessibilityWindowsPopulator.setMagnificationSpec(displayId, spec);
-
final DisplayMagnifier displayMagnifier = mDisplayMagnifiers.get(displayId);
if (displayMagnifier != null) {
displayMagnifier.setMagnificationSpec(spec);
@@ -456,6 +454,19 @@
return null;
}
+ boolean getMagnificationSpecForDisplay(int displayId, MagnificationSpec outSpec) {
+ if (mAccessibilityTracing.isTracingEnabled(FLAGS_MAGNIFICATION_CALLBACK)) {
+ mAccessibilityTracing.logTrace(TAG + ".getMagnificationSpecForDisplay",
+ FLAGS_MAGNIFICATION_CALLBACK, "displayId=" + displayId);
+ }
+ final DisplayMagnifier displayMagnifier = mDisplayMagnifiers.get(displayId);
+ if (displayMagnifier == null) {
+ return false;
+ }
+
+ return displayMagnifier.getMagnificationSpec(outSpec);
+ }
+
boolean hasCallbacks() {
if (mAccessibilityTracing.isTracingEnabled(FLAGS_MAGNIFICATION_CALLBACK
| FLAGS_WINDOWS_FOR_ACCESSIBILITY_CALLBACK)) {
@@ -757,6 +768,25 @@
return spec;
}
+ boolean getMagnificationSpec(MagnificationSpec outSpec) {
+ if (mAccessibilityTracing.isTracingEnabled(FLAGS_MAGNIFICATION_CALLBACK)) {
+ mAccessibilityTracing.logTrace(LOG_TAG + ".getMagnificationSpec",
+ FLAGS_MAGNIFICATION_CALLBACK);
+ }
+ MagnificationSpec spec = mMagnifedViewport.getMagnificationSpec();
+ if (spec == null) {
+ return false;
+ }
+
+ outSpec.setTo(spec);
+ if (mAccessibilityTracing.isTracingEnabled(FLAGS_MAGNIFICATION_CALLBACK)) {
+ mAccessibilityTracing.logTrace(LOG_TAG + ".getMagnificationSpec",
+ FLAGS_MAGNIFICATION_CALLBACK, "outSpec={" + outSpec + "}");
+ }
+
+ return true;
+ }
+
void getMagnificationRegion(Region outMagnificationRegion) {
if (mAccessibilityTracing.isTracingEnabled(FLAGS_MAGNIFICATION_CALLBACK)) {
mAccessibilityTracing.logTrace(LOG_TAG + ".getMagnificationRegion",
diff --git a/services/core/java/com/android/server/wm/AccessibilityWindowsPopulator.java b/services/core/java/com/android/server/wm/AccessibilityWindowsPopulator.java
index 43317ad..c0fb83b 100644
--- a/services/core/java/com/android/server/wm/AccessibilityWindowsPopulator.java
+++ b/services/core/java/com/android/server/wm/AccessibilityWindowsPopulator.java
@@ -41,9 +41,7 @@
import com.android.internal.annotations.GuardedBy;
import java.util.ArrayList;
-import java.util.HashMap;
import java.util.List;
-import java.util.Map;
/**
* This class is the accessibility windows population adapter.
@@ -70,24 +68,13 @@
private final SparseArray<Matrix> mMagnificationSpecInverseMatrix = new SparseArray<>();
@GuardedBy("mLock")
private final SparseArray<DisplayInfo> mDisplayInfos = new SparseArray<>();
- private final SparseArray<MagnificationSpec> mCurrentMagnificationSpec = new SparseArray<>();
- @GuardedBy("mLock")
- private final SparseArray<MagnificationSpec> mPreviousMagnificationSpec = new SparseArray<>();
@GuardedBy("mLock")
private final List<InputWindowHandle> mVisibleWindows = new ArrayList<>();
@GuardedBy("mLock")
private boolean mWindowsNotificationEnabled = false;
- @GuardedBy("mLock")
- private final Map<IBinder, Matrix> mWindowsTransformMatrixMap = new HashMap<>();
private final Object mLock = new Object();
private final Handler mHandler;
- private final Matrix mTempMatrix1 = new Matrix();
- private final Matrix mTempMatrix2 = new Matrix();
- private final float[] mTempFloat1 = new float[9];
- private final float[] mTempFloat2 = new float[9];
- private final float[] mTempFloat3 = new float[9];
-
AccessibilityWindowsPopulator(WindowManagerService service,
AccessibilityController accessibilityController) {
mService = service;
@@ -145,55 +132,28 @@
@Override
public void onWindowInfosChanged(InputWindowHandle[] windowHandles,
DisplayInfo[] displayInfos) {
- final List<InputWindowHandle> tempVisibleWindows = new ArrayList<>();
-
- for (InputWindowHandle window : windowHandles) {
- if (window.visible && window.getWindow() != null) {
- tempVisibleWindows.add(window);
- }
- }
- final HashMap<IBinder, Matrix> windowsTransformMatrixMap =
- getWindowsTransformMatrix(tempVisibleWindows);
-
synchronized (mLock) {
- mWindowsTransformMatrixMap.clear();
- mWindowsTransformMatrixMap.putAll(windowsTransformMatrixMap);
-
mVisibleWindows.clear();
- mVisibleWindows.addAll(tempVisibleWindows);
+ for (InputWindowHandle window : windowHandles) {
+ if (window.visible && window.getWindow() != null) {
+ mVisibleWindows.add(window);
+ }
+ }
mDisplayInfos.clear();
for (final DisplayInfo displayInfo : displayInfos) {
mDisplayInfos.put(displayInfo.mDisplayId, displayInfo);
}
- if (!mHandler.hasMessages(
- MyHandler.MESSAGE_NOTIFY_WINDOWS_CHANGED_BY_TIMEOUT)) {
- mHandler.sendEmptyMessageDelayed(
- MyHandler.MESSAGE_NOTIFY_WINDOWS_CHANGED_BY_TIMEOUT,
- WINDOWS_CHANGED_NOTIFICATION_MAX_DURATION_TIMES_MS);
- }
- populateVisibleWindowHandlesAndNotifyWindowsChangeIfNeeded();
- }
- }
-
- private HashMap<IBinder, Matrix> getWindowsTransformMatrix(List<InputWindowHandle> windows) {
- synchronized (mService.mGlobalLock) {
- final HashMap<IBinder, Matrix> windowsTransformMatrixMap = new HashMap<>();
-
- for (InputWindowHandle inputWindowHandle : windows) {
- final IWindow iWindow = inputWindowHandle.getWindow();
- final WindowState windowState = iWindow != null ? mService.mWindowMap.get(
- iWindow.asBinder()) : null;
-
- if (windowState != null && windowState.shouldMagnify()) {
- final Matrix transformMatrix = new Matrix();
- windowState.getTransformationMatrix(sTempFloats, transformMatrix);
- windowsTransformMatrixMap.put(iWindow.asBinder(), transformMatrix);
+ if (mWindowsNotificationEnabled) {
+ if (!mHandler.hasMessages(
+ MyHandler.MESSAGE_NOTIFY_WINDOWS_CHANGED_BY_TIMEOUT)) {
+ mHandler.sendEmptyMessageDelayed(
+ MyHandler.MESSAGE_NOTIFY_WINDOWS_CHANGED_BY_TIMEOUT,
+ WINDOWS_CHANGED_NOTIFICATION_MAX_DURATION_TIMES_MS);
}
+ populateVisibleWindowHandlesAndNotifyWindowsChangeIfNeededLocked();
}
-
- return windowsTransformMatrixMap;
}
}
@@ -211,43 +171,14 @@
}
mWindowsNotificationEnabled = register;
if (mWindowsNotificationEnabled) {
- populateVisibleWindowHandlesAndNotifyWindowsChangeIfNeeded();
+ populateVisibleWindowHandlesAndNotifyWindowsChangeIfNeededLocked();
} else {
releaseResources();
}
}
}
- /**
- * Sets the magnification spec for calculating the window bounds of all windows
- * reported from the surface flinger in the magnifying.
- *
- * @param displayId The display Id.
- * @param spec THe magnification spec.
- */
- public void setMagnificationSpec(int displayId, MagnificationSpec spec) {
- synchronized (mLock) {
- MagnificationSpec currentMagnificationSpec = mCurrentMagnificationSpec.get(displayId);
- if (currentMagnificationSpec == null) {
- currentMagnificationSpec = new MagnificationSpec();
- currentMagnificationSpec.setTo(spec);
- mCurrentMagnificationSpec.put(displayId, currentMagnificationSpec);
-
- return;
- }
-
- MagnificationSpec previousMagnificationSpec = mPreviousMagnificationSpec.get(displayId);
- if (previousMagnificationSpec == null) {
- previousMagnificationSpec = new MagnificationSpec();
- mPreviousMagnificationSpec.put(displayId, previousMagnificationSpec);
- }
- previousMagnificationSpec.setTo(currentMagnificationSpec);
- currentMagnificationSpec.setTo(spec);
- }
- }
-
- @GuardedBy("mLock")
- private void populateVisibleWindowHandlesAndNotifyWindowsChangeIfNeeded() {
+ private void populateVisibleWindowHandlesAndNotifyWindowsChangeIfNeededLocked() {
final SparseArray<List<InputWindowHandle>> tempWindowHandleList = new SparseArray<>();
for (final InputWindowHandle windowHandle : mVisibleWindows) {
@@ -257,15 +188,15 @@
if (inputWindowHandles == null) {
inputWindowHandles = new ArrayList<>();
tempWindowHandleList.put(windowHandle.displayId, inputWindowHandles);
+ generateMagnificationSpecInverseMatrixLocked(windowHandle.displayId);
}
inputWindowHandles.add(windowHandle);
}
- findMagnificationSpecInverseMatrixIfNeeded(tempWindowHandleList);
final List<Integer> displayIdsForWindowsChanged = new ArrayList<>();
- getDisplaysForWindowsChanged(displayIdsForWindowsChanged, tempWindowHandleList,
- mInputWindowHandlesOnDisplays);
+ getDisplaysForWindowsChangedLocked(displayIdsForWindowsChanged, tempWindowHandleList,
+ mInputWindowHandlesOnDisplays);
// Clones all windows from the callback of the surface flinger.
mInputWindowHandlesOnDisplays.clear();
for (int i = 0; i < tempWindowHandleList.size(); i++) {
@@ -273,7 +204,7 @@
mInputWindowHandlesOnDisplays.put(displayId, tempWindowHandleList.get(displayId));
}
- if (!displayIdsForWindowsChanged.isEmpty()) {
+ if (displayIdsForWindowsChanged.size() > 0) {
if (!mHandler.hasMessages(MyHandler.MESSAGE_NOTIFY_WINDOWS_CHANGED)) {
mHandler.obtainMessage(MyHandler.MESSAGE_NOTIFY_WINDOWS_CHANGED,
displayIdsForWindowsChanged).sendToTarget();
@@ -286,8 +217,7 @@
SURFACE_FLINGER_CALLBACK_WINDOWS_STABLE_TIMES_MS);
}
- @GuardedBy("mLock")
- private static void getDisplaysForWindowsChanged(List<Integer> outDisplayIdsForWindowsChanged,
+ private void getDisplaysForWindowsChangedLocked(List<Integer> outDisplayIdsForWindowsChanged,
SparseArray<List<InputWindowHandle>> newWindowsList,
SparseArray<List<InputWindowHandle>> oldWindowsList) {
for (int i = 0; i < newWindowsList.size(); i++) {
@@ -295,14 +225,13 @@
final List<InputWindowHandle> newWindows = newWindowsList.get(displayId);
final List<InputWindowHandle> oldWindows = oldWindowsList.get(displayId);
- if (hasWindowsChanged(newWindows, oldWindows)) {
+ if (hasWindowsChangedLocked(newWindows, oldWindows)) {
outDisplayIdsForWindowsChanged.add(displayId);
}
}
}
- @GuardedBy("mLock")
- private static boolean hasWindowsChanged(List<InputWindowHandle> newWindows,
+ private boolean hasWindowsChangedLocked(List<InputWindowHandle> newWindows,
List<InputWindowHandle> oldWindows) {
if (oldWindows == null || oldWindows.size() != newWindows.size()) {
return true;
@@ -324,195 +253,34 @@
return false;
}
- @GuardedBy("mLock")
- private void findMagnificationSpecInverseMatrixIfNeeded(SparseArray<List<InputWindowHandle>>
- windowHandleList) {
- MagnificationSpec currentMagnificationSpec;
- MagnificationSpec previousMagnificationSpec;
- for (int i = 0; i < windowHandleList.size(); i++) {
- final int displayId = windowHandleList.keyAt(i);
- List<InputWindowHandle> inputWindowHandles = windowHandleList.get(displayId);
-
- final MagnificationSpec currentSpec = mCurrentMagnificationSpec.get(displayId);
- if (currentSpec == null) {
- continue;
- }
- currentMagnificationSpec = new MagnificationSpec();
- currentMagnificationSpec.setTo(currentSpec);
-
- final MagnificationSpec previousSpec = mPreviousMagnificationSpec.get(displayId);
-
- if (previousSpec == null) {
- final Matrix inverseMatrixForCurrentSpec = new Matrix();
- generateInverseMatrix(currentMagnificationSpec, inverseMatrixForCurrentSpec);
- mMagnificationSpecInverseMatrix.put(displayId, inverseMatrixForCurrentSpec);
- continue;
- }
- previousMagnificationSpec = new MagnificationSpec();
- previousMagnificationSpec.setTo(previousSpec);
-
- generateInverseMatrixBasedOnProperMagnificationSpecForDisplay(inputWindowHandles,
- currentMagnificationSpec, previousMagnificationSpec);
+ private void generateMagnificationSpecInverseMatrixLocked(int displayId) {
+ MagnificationSpec spec = new MagnificationSpec();
+ if (!mAccessibilityController.getMagnificationSpecForDisplay(displayId, spec)) {
+ mMagnificationSpecInverseMatrix.remove(displayId);
+ return;
}
- }
-
- @GuardedBy("mLock")
- private void generateInverseMatrixBasedOnProperMagnificationSpecForDisplay(
- List<InputWindowHandle> inputWindowHandles, MagnificationSpec currentMagnificationSpec,
- MagnificationSpec previousMagnificationSpec) {
- // To decrease the counts of holding the WindowManagerService#mGlogalLock in
- // the method, getWindowTransformMatrix(), this for loop begins from the bottom
- // to top of the z-order windows.
- for (int index = inputWindowHandles.size() - 1; index >= 0; index--) {
- final Matrix windowTransformMatrix = mTempMatrix2;
- final InputWindowHandle windowHandle = inputWindowHandles.get(index);
- final IBinder iBinder = windowHandle.getWindow().asBinder();
-
- if (getWindowTransformMatrix(iBinder, windowTransformMatrix)) {
- generateMagnificationSpecInverseMatrix(windowHandle, currentMagnificationSpec,
- previousMagnificationSpec, windowTransformMatrix);
-
- break;
- }
- }
- }
-
- @GuardedBy("mLock")
- private boolean getWindowTransformMatrix(IBinder iBinder, Matrix outTransform) {
- final Matrix windowMatrix = iBinder != null
- ? mWindowsTransformMatrixMap.get(iBinder) : null;
-
- if (windowMatrix == null) {
- return false;
- }
- outTransform.set(windowMatrix);
-
- return true;
- }
-
- /**
- * Generates the inverse matrix based on the proper magnification spec.
- * The magnification spec associated with the InputWindowHandle might not the current
- * spec set by WM, which might be the previous one. To find the appropriate spec,
- * we store two consecutive magnification specs, and found out which one is the proper
- * one closing the identity matrix for generating the inverse matrix.
- *
- * @param inputWindowHandle The window from the surface flinger.
- * @param currentMagnificationSpec The current magnification spec.
- * @param previousMagnificationSpec The previous magnification spec.
- * @param transformMatrix The transform matrix of the window doesn't consider the
- * magnifying effect.
- */
- @GuardedBy("mLock")
- private void generateMagnificationSpecInverseMatrix(InputWindowHandle inputWindowHandle,
- @NonNull MagnificationSpec currentMagnificationSpec,
- @NonNull MagnificationSpec previousMagnificationSpec, Matrix transformMatrix) {
-
- final float[] identityMatrixFloatsForCurrentSpec = mTempFloat1;
- computeIdentityMatrix(inputWindowHandle, currentMagnificationSpec,
- transformMatrix, identityMatrixFloatsForCurrentSpec);
- final float[] identityMatrixFloatsForPreviousSpec = mTempFloat2;
- computeIdentityMatrix(inputWindowHandle, previousMagnificationSpec,
- transformMatrix, identityMatrixFloatsForPreviousSpec);
-
- Matrix inverseMatrixForMagnificationSpec = new Matrix();
- if (selectProperMagnificationSpecByComparingIdentityDegree(
- identityMatrixFloatsForCurrentSpec, identityMatrixFloatsForPreviousSpec)) {
- generateInverseMatrix(currentMagnificationSpec,
- inverseMatrixForMagnificationSpec);
-
- // Choosing the current spec means the previous spec is out of date,
- // so removing it. And if the current spec is no magnifying, meaning
- // the magnifying is done so removing the inverse matrix of this display.
- mPreviousMagnificationSpec.remove(inputWindowHandle.displayId);
- if (currentMagnificationSpec.isNop()) {
- mCurrentMagnificationSpec.remove(inputWindowHandle.displayId);
- mMagnificationSpecInverseMatrix.remove(inputWindowHandle.displayId);
- return;
- }
- } else {
- generateInverseMatrix(previousMagnificationSpec,
- inverseMatrixForMagnificationSpec);
- }
-
- mMagnificationSpecInverseMatrix.put(inputWindowHandle.displayId,
- inverseMatrixForMagnificationSpec);
- }
-
- /**
- * Computes the identity matrix for generating the
- * inverse matrix based on below formula under window is at the stable state:
- * inputWindowHandle#transform * MagnificationSpecMatrix * WindowState#transform
- * = IdentityMatrix
- */
- @GuardedBy("mLock")
- private void computeIdentityMatrix(InputWindowHandle inputWindowHandle,
- @NonNull MagnificationSpec magnificationSpec,
- Matrix transformMatrix, float[] magnifyMatrixFloats) {
- final Matrix specMatrix = mTempMatrix1;
- transformMagnificationSpecToMatrix(magnificationSpec, specMatrix);
-
- final Matrix resultMatrix = new Matrix(inputWindowHandle.transform);
- resultMatrix.preConcat(specMatrix);
- resultMatrix.preConcat(transformMatrix);
-
- resultMatrix.getValues(magnifyMatrixFloats);
- }
-
- /**
- * @return true if selecting the magnification spec one, otherwise selecting the
- * magnification spec two.
- */
- @GuardedBy("mLock")
- private boolean selectProperMagnificationSpecByComparingIdentityDegree(
- float[] magnifyMatrixFloatsForSpecOne,
- float[] magnifyMatrixFloatsForSpecTwo) {
- final float[] IdentityMatrixValues = mTempFloat3;
- Matrix.IDENTITY_MATRIX.getValues(IdentityMatrixValues);
-
- final float scaleDiffForSpecOne = Math.abs(IdentityMatrixValues[Matrix.MSCALE_X]
- - magnifyMatrixFloatsForSpecOne[Matrix.MSCALE_X]);
- final float scaleDiffForSpecTwo = Math.abs(IdentityMatrixValues[Matrix.MSCALE_X]
- - magnifyMatrixFloatsForSpecTwo[Matrix.MSCALE_X]);
- final float offsetXDiffForSpecOne = Math.abs(IdentityMatrixValues[Matrix.MTRANS_X]
- - magnifyMatrixFloatsForSpecOne[Matrix.MTRANS_X]);
- final float offsetXDiffForSpecTwo = Math.abs(IdentityMatrixValues[Matrix.MTRANS_X]
- - magnifyMatrixFloatsForSpecTwo[Matrix.MTRANS_X]);
- final float offsetYDiffForSpecOne = Math.abs(IdentityMatrixValues[Matrix.MTRANS_Y]
- - magnifyMatrixFloatsForSpecOne[Matrix.MTRANS_Y]);
- final float offsetYDiffForSpecTwo = Math.abs(IdentityMatrixValues[Matrix.MTRANS_Y]
- - magnifyMatrixFloatsForSpecTwo[Matrix.MTRANS_Y]);
- final float offsetDiffForSpecOne = offsetXDiffForSpecOne
- + offsetYDiffForSpecOne;
- final float offsetDiffForSpecTwo = offsetXDiffForSpecTwo
- + offsetYDiffForSpecTwo;
-
- return Float.compare(scaleDiffForSpecTwo, scaleDiffForSpecOne) > 0
- || (Float.compare(scaleDiffForSpecTwo, scaleDiffForSpecOne) == 0
- && Float.compare(offsetDiffForSpecTwo, offsetDiffForSpecOne) > 0);
- }
-
- @GuardedBy("mLock")
- private static void generateInverseMatrix(MagnificationSpec spec, Matrix outMatrix) {
- outMatrix.reset();
+ sTempFloats[Matrix.MSCALE_X] = spec.scale;
+ sTempFloats[Matrix.MSKEW_Y] = 0;
+ sTempFloats[Matrix.MSKEW_X] = 0;
+ sTempFloats[Matrix.MSCALE_Y] = spec.scale;
+ sTempFloats[Matrix.MTRANS_X] = spec.offsetX;
+ sTempFloats[Matrix.MTRANS_Y] = spec.offsetY;
+ sTempFloats[Matrix.MPERSP_0] = 0;
+ sTempFloats[Matrix.MPERSP_1] = 0;
+ sTempFloats[Matrix.MPERSP_2] = 1;
final Matrix tempMatrix = new Matrix();
- transformMagnificationSpecToMatrix(spec, tempMatrix);
+ tempMatrix.setValues(sTempFloats);
- final boolean result = tempMatrix.invert(outMatrix);
+ final Matrix inverseMatrix = new Matrix();
+ final boolean result = tempMatrix.invert(inverseMatrix);
+
if (!result) {
Slog.e(TAG, "Can't inverse the magnification spec matrix with the "
- + "magnification spec = " + spec);
- outMatrix.reset();
+ + "magnification spec = " + spec + " on the displayId = " + displayId);
+ return;
}
- }
-
- @GuardedBy("mLock")
- private static void transformMagnificationSpecToMatrix(MagnificationSpec spec,
- Matrix outMatrix) {
- outMatrix.reset();
- outMatrix.postScale(spec.scale, spec.scale);
- outMatrix.postTranslate(spec.offsetX, spec.offsetY);
+ mMagnificationSpecInverseMatrix.set(displayId, inverseMatrix);
}
private void notifyWindowsChanged(@NonNull List<Integer> displayIdsForWindowsChanged) {
@@ -542,9 +310,6 @@
mMagnificationSpecInverseMatrix.clear();
mVisibleWindows.clear();
mDisplayInfos.clear();
- mCurrentMagnificationSpec.clear();
- mPreviousMagnificationSpec.clear();
- mWindowsTransformMatrixMap.clear();
mWindowsNotificationEnabled = false;
mHandler.removeCallbacksAndMessages(null);
}
diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java
index 26815b4..764d148 100644
--- a/services/core/java/com/android/server/wm/ActivityRecord.java
+++ b/services/core/java/com/android/server/wm/ActivityRecord.java
@@ -44,6 +44,7 @@
import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
import static android.app.WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW;
import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
+import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
import static android.app.WindowConfiguration.activityTypeToString;
import static android.app.WindowConfiguration.isSplitScreenWindowingMode;
import static android.app.admin.DevicePolicyResources.Drawables.Source.PROFILE_SWITCH_ANIMATION;
@@ -8211,6 +8212,20 @@
@Override
public void onConfigurationChanged(Configuration newParentConfig) {
+ // We want to collect the ActivityRecord if the windowing mode is changed, so that it will
+ // dispatch app transition finished event correctly at the end.
+ // Check #isVisible() because we don't want to animate for activity that stays invisible.
+ // Activity with #isVisibleRequested() changed should be collected when that is requested.
+ if (mTransitionController.isShellTransitionsEnabled() && isVisible()
+ && isVisibleRequested()) {
+ final int projectedWindowingMode =
+ getRequestedOverrideWindowingMode() == WINDOWING_MODE_UNDEFINED
+ ? newParentConfig.windowConfiguration.getWindowingMode()
+ : getRequestedOverrideWindowingMode();
+ if (getWindowingMode() != projectedWindowingMode) {
+ mTransitionController.collect(this);
+ }
+ }
if (mCompatDisplayInsets != null) {
Configuration overrideConfig = getRequestedOverrideConfiguration();
// Adapt to changes in orientation locking. The app is still non-resizable, but
diff --git a/services/core/java/com/android/server/wm/Transition.java b/services/core/java/com/android/server/wm/Transition.java
index 785867b..29d1742 100644
--- a/services/core/java/com/android/server/wm/Transition.java
+++ b/services/core/java/com/android/server/wm/Transition.java
@@ -80,9 +80,12 @@
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.graphics.ColorUtils;
+import com.android.internal.inputmethod.SoftInputShowHideReason;
import com.android.internal.protolog.ProtoLogGroup;
import com.android.internal.protolog.common.ProtoLog;
import com.android.internal.util.function.pooled.PooledLambda;
+import com.android.server.LocalServices;
+import com.android.server.inputmethod.InputMethodManagerInternal;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@@ -552,14 +555,24 @@
asyncRotationController.onTransitionFinished();
}
if (mTransientLaunches != null) {
+ InsetsControlTarget prevImeTarget = dc.getImeTarget(
+ DisplayContent.IME_TARGET_CONTROL);
+ InsetsControlTarget newImeTarget = null;
// Transient-launch activities cannot be IME target (WindowState#canBeImeTarget),
// so re-compute in case the IME target is changed after transition.
for (int t = 0; t < mTransientLaunches.size(); ++t) {
if (mTransientLaunches.keyAt(t).getDisplayContent() == dc) {
- dc.computeImeTarget(true /* updateImeTarget */);
+ newImeTarget = dc.computeImeTarget(true /* updateImeTarget */);
break;
}
}
+ if (mRecentsDisplayId != INVALID_DISPLAY && prevImeTarget == newImeTarget) {
+ // Restore IME icon only when moving the original app task to front from
+ // recents, in case IME icon may missing if the moving task has already been
+ // the current focused task.
+ InputMethodManagerInternal.get().updateImeWindowStatus(
+ false /* disableImeIcon */);
+ }
}
dc.handleCompleteDeferredRemoval();
}
@@ -781,6 +794,26 @@
}
}
+ // Hiding IME/IME icon when starting quick-step with resents animation.
+ if (!mTargetDisplays.get(mRecentsDisplayId).isImeAttachedToApp()) {
+ // Hiding IME if IME window is not attached to app.
+ // Since some windowing mode is not proper to snapshot Task with IME window
+ // while the app transitioning to the next task (e.g. split-screen mode)
+ final InputMethodManagerInternal inputMethodManagerInternal =
+ LocalServices.getService(InputMethodManagerInternal.class);
+ if (inputMethodManagerInternal != null) {
+ inputMethodManagerInternal.hideCurrentInputMethod(
+ SoftInputShowHideReason.HIDE_RECENTS_ANIMATION);
+ }
+ } else {
+ // Disable IME icon explicitly when IME attached to the app in case
+ // IME icon might flickering while swiping to the next app task still
+ // in animating before the next app window focused, or IME icon
+ // persists on the bottom when swiping the task to recents.
+ InputMethodManagerInternal.get().updateImeWindowStatus(
+ true /* disableImeIcon */);
+ }
+
// The rest of this function handles nav-bar reparenting
if (!dc.getDisplayPolicy().shouldAttachNavBarToAppDuringTransition()
diff --git a/services/core/java/com/android/server/wm/TransitionController.java b/services/core/java/com/android/server/wm/TransitionController.java
index 0cfc702..a6ff15b 100644
--- a/services/core/java/com/android/server/wm/TransitionController.java
+++ b/services/core/java/com/android/server/wm/TransitionController.java
@@ -16,7 +16,6 @@
package com.android.server.wm;
-import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME;
import static android.view.WindowManager.TRANSIT_CHANGE;
import static android.view.WindowManager.TRANSIT_CLOSE;
import static android.view.WindowManager.TRANSIT_FLAG_IS_RECENTS;
@@ -514,8 +513,13 @@
// TODO(b/188669821): Remove once legacy recents behavior is moved to shell.
// Also interpret HOME transient launch as recents
- if (activity.getActivityType() == ACTIVITY_TYPE_HOME) {
+ if (activity.isActivityTypeHomeOrRecents()) {
mCollectingTransition.addFlag(TRANSIT_FLAG_IS_RECENTS);
+ // When starting recents animation, we assume the recents activity is behind the app
+ // task and should not affect system bar appearance,
+ // until WMS#setRecentsAppBehindSystemBars be called from launcher when passing
+ // the gesture threshold.
+ activity.getTask().setCanAffectSystemUiFlags(false);
}
}
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 6445d1e..04f135e 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -25,6 +25,7 @@
import static android.Manifest.permission.READ_FRAME_BUFFER;
import static android.Manifest.permission.REGISTER_WINDOW_MANAGER_LISTENERS;
import static android.Manifest.permission.RESTRICTED_VR_ACCESS;
+import static android.Manifest.permission.START_TASKS_FROM_RECENTS;
import static android.Manifest.permission.WRITE_SECURE_SETTINGS;
import static android.app.ActivityManagerInternal.ALLOW_FULL_ONLY;
import static android.app.ActivityManagerInternal.ALLOW_NON_FULL;
@@ -8983,4 +8984,24 @@
return Bitmap.wrapHardwareBuffer(taskSnapshot.getHardwareBuffer(),
taskSnapshot.getColorSpace());
}
+
+ @Override
+ public void setRecentsAppBehindSystemBars(boolean behindSystemBars) {
+ if (!checkCallingPermission(START_TASKS_FROM_RECENTS, "setRecentsAppBehindSystemBars()")) {
+ throw new SecurityException("Requires START_TASKS_FROM_RECENTS permission");
+ }
+ final long token = Binder.clearCallingIdentity();
+ try {
+ synchronized (mGlobalLock) {
+ final Task recentsApp = mRoot.getTask(task -> task.isActivityTypeHomeOrRecents()
+ && task.getTopVisibleActivity() != null);
+ if (recentsApp != null) {
+ recentsApp.getTask().setCanAffectSystemUiFlags(behindSystemBars);
+ mWindowPlacerLocked.requestTraversal();
+ }
+ }
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
+ }
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
index b3d6b3e..2ea0bdc 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
@@ -24,6 +24,7 @@
import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
import static android.app.WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW;
+import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
import static android.content.pm.ActivityInfo.CONFIG_ORIENTATION;
import static android.content.pm.ActivityInfo.CONFIG_SCREEN_LAYOUT;
import static android.content.pm.ActivityInfo.FLAG_SUPPORTS_PICTURE_IN_PICTURE;
@@ -54,6 +55,7 @@
import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
import static android.view.WindowManager.TRANSIT_CLOSE;
import static android.view.WindowManager.TRANSIT_OLD_ACTIVITY_OPEN;
+import static android.view.WindowManager.TRANSIT_PIP;
import static android.window.StartingWindowInfo.TYPE_PARAMETER_LEGACY_SPLASH_SCREEN;
import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;
@@ -3397,6 +3399,24 @@
assertFalse(activity.mVisibleRequested);
}
+ @Test
+ public void testShellTransitionTaskWindowingModeChange() {
+ final ActivityRecord activity = createActivityWithTask();
+ final Task task = activity.getTask();
+ task.setWindowingMode(WINDOWING_MODE_FULLSCREEN);
+
+ assertTrue(activity.isVisible());
+ assertTrue(activity.isVisibleRequested());
+ assertEquals(WINDOWING_MODE_FULLSCREEN, activity.getWindowingMode());
+
+ registerTestTransitionPlayer();
+ task.mTransitionController.requestTransitionIfNeeded(TRANSIT_PIP, task);
+ task.setWindowingMode(WINDOWING_MODE_PINNED);
+
+ // Collect activity in the transition if the Task windowing mode is going to change.
+ assertTrue(activity.inTransition());
+ }
+
private ICompatCameraControlCallback getCompatCameraControlCallback() {
return new ICompatCameraControlCallback.Stub() {
@Override
diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java
index adb51c4..837cf8b 100644
--- a/telephony/java/android/telephony/CarrierConfigManager.java
+++ b/telephony/java/android/telephony/CarrierConfigManager.java
@@ -3850,30 +3850,42 @@
public static final String KEY_OPPORTUNISTIC_ESIM_DOWNLOAD_VIA_WIFI_ONLY_BOOL =
"opportunistic_esim_download_via_wifi_only_bool";
- /**
- * Controls RSRP threshold at which OpportunisticNetworkService will decide whether
+/**
+ * Controls RSRP threshold, in dBm, at which OpportunisticNetworkService will decide whether
* the opportunistic network is good enough for internet data.
+ *
+ * <p>The value of {@link CellSignalStrengthLte#getRsrp()} will be compared with this
+ * threshold.
*/
public static final String KEY_OPPORTUNISTIC_NETWORK_ENTRY_THRESHOLD_RSRP_INT =
"opportunistic_network_entry_threshold_rsrp_int";
/**
- * Controls RSSNR threshold at which OpportunisticNetworkService will decide whether
- * the opportunistic network is good enough for internet data.
+ * Controls RSSNR threshold, in dB, at which OpportunisticNetworkService will
+ * decide whether the opportunistic network is good enough for internet data.
+ *
+ * <p>The value of {@link CellSignalStrengthLte#getRssnr()} will be compared with this
+ * threshold.
*/
public static final String KEY_OPPORTUNISTIC_NETWORK_ENTRY_THRESHOLD_RSSNR_INT =
"opportunistic_network_entry_threshold_rssnr_int";
/**
- * Controls RSRP threshold below which OpportunisticNetworkService will decide whether
+ * Controls RSRP threshold, in dBm, below which OpportunisticNetworkService will decide whether
* the opportunistic network available is not good enough for internet data.
+ *
+ * <p>The value of {@link CellSignalStrengthLte#getRsrp()} will be compared with this
+ * threshold.
*/
public static final String KEY_OPPORTUNISTIC_NETWORK_EXIT_THRESHOLD_RSRP_INT =
"opportunistic_network_exit_threshold_rsrp_int";
/**
- * Controls RSSNR threshold below which OpportunisticNetworkService will decide whether
- * the opportunistic network available is not good enough for internet data.
+ * Controls RSSNR threshold, in dB, below which OpportunisticNetworkService will
+ * decide whether the opportunistic network available is not good enough for internet data.
+ *
+ * <p>The value of {@link CellSignalStrengthLte#getRssnr()} will be compared with this
+ * threshold.
*/
public static final String KEY_OPPORTUNISTIC_NETWORK_EXIT_THRESHOLD_RSSNR_INT =
"opportunistic_network_exit_threshold_rssnr_int";
@@ -3971,7 +3983,7 @@
* good enough for internet data. Note other factors may be considered for the final
* decision.
*
- * <p>The value of {@link CellSignalStrengthNr#getSsRsrp} will be compared with this
+ * <p>The value of {@link CellSignalStrengthNr#getSsRsrp()} will be compared with this
* threshold.
*
* @hide
@@ -3998,7 +4010,7 @@
* good enough for internet data. Note other factors may be considered for the final
* decision.
*
- * <p>The value of {@link CellSignalStrengthNr#getSsRsrq} will be compared with this
+ * <p>The value of {@link CellSignalStrengthNr#getSsRsrq()} will be compared with this
* threshold.
*
* @hide
@@ -4025,6 +4037,9 @@
* be considered good enough for internet data. Note other factors may be considered
* for the final decision.
*
+ * <p>The value of {@link CellSignalStrengthNr#getSsRsrp()} will be compared with this
+ * threshold.
+ *
* @hide
*/
public static final String KEY_EXIT_THRESHOLD_SS_RSRP_INT =
@@ -4048,6 +4063,9 @@
* be considered good enough for internet data. Note other factors may be considered
* for the final decision.
*
+ * <p>The value of {@link CellSignalStrengthNr#getSsRsrq()} will be compared with this
+ * threshold.
+ *
* @hide
*/
public static final String KEY_EXIT_THRESHOLD_SS_RSRQ_DOUBLE =
@@ -8995,9 +9013,9 @@
/* Default value is minimum RSRP level needed for SIGNAL_STRENGTH_MODERATE */
sDefaults.putInt(KEY_OPPORTUNISTIC_NETWORK_EXIT_THRESHOLD_RSRP_INT, -118);
/* Default value is minimum RSSNR level needed for SIGNAL_STRENGTH_GOOD */
- sDefaults.putInt(KEY_OPPORTUNISTIC_NETWORK_ENTRY_THRESHOLD_RSSNR_INT, 45);
+ sDefaults.putInt(KEY_OPPORTUNISTIC_NETWORK_ENTRY_THRESHOLD_RSSNR_INT, 5);
/* Default value is minimum RSSNR level needed for SIGNAL_STRENGTH_MODERATE */
- sDefaults.putInt(KEY_OPPORTUNISTIC_NETWORK_EXIT_THRESHOLD_RSSNR_INT, 10);
+ sDefaults.putInt(KEY_OPPORTUNISTIC_NETWORK_EXIT_THRESHOLD_RSSNR_INT, 1);
/* Default value is 1024 kbps */
sDefaults.putInt(KEY_OPPORTUNISTIC_NETWORK_ENTRY_THRESHOLD_BANDWIDTH_INT, 1024);
/* Default value is 10 seconds */
diff --git a/telephony/java/android/telephony/CellSignalStrengthLte.java b/telephony/java/android/telephony/CellSignalStrengthLte.java
index 947dc01..5e90261 100644
--- a/telephony/java/android/telephony/CellSignalStrengthLte.java
+++ b/telephony/java/android/telephony/CellSignalStrengthLte.java
@@ -125,13 +125,13 @@
/**
* Construct a cell signal strength
*
- * @param rssi in dBm [-113,-51], UNKNOWN
- * @param rsrp in dBm [-140,-43], UNKNOWN
- * @param rsrq in dB [-34, 3], UNKNOWN
- * @param rssnr in dB [-20, +30], UNKNOWN
- * @param cqiTableIndex [1, 6], UNKNOWN
- * @param cqi [0, 15], UNKNOWN
- * @param timingAdvance [0, 1282], UNKNOWN
+ * @param rssi in dBm [-113,-51], {@link CellInfo#UNAVAILABLE}
+ * @param rsrp in dBm [-140,-43], {@link CellInfo#UNAVAILABLE}
+ * @param rsrq in dB [-34, 3], {@link CellInfo#UNAVAILABLE}
+ * @param rssnr in dB [-20, +30], {@link CellInfo#UNAVAILABLE}
+ * @param cqiTableIndex [1, 6], {@link CellInfo#UNAVAILABLE}
+ * @param cqi [0, 15], {@link CellInfo#UNAVAILABLE}
+ * @param timingAdvance [0, 1282], {@link CellInfo#UNAVAILABLE}
*
*/
/** @hide */
@@ -151,12 +151,12 @@
/**
* Construct a cell signal strength
*
- * @param rssi in dBm [-113,-51], UNKNOWN
- * @param rsrp in dBm [-140,-43], UNKNOWN
- * @param rsrq in dB [-34, 3], UNKNOWN
- * @param rssnr in dB [-20, +30], UNKNOWN
- * @param cqi [0, 15], UNKNOWN
- * @param timingAdvance [0, 1282], UNKNOWN
+ * @param rssi in dBm [-113,-51], {@link CellInfo#UNAVAILABLE}
+ * @param rsrp in dBm [-140,-43], {@link CellInfo#UNAVAILABLE}
+ * @param rsrq in dB [-34, 3], {@link CellInfo#UNAVAILABLE}
+ * @param rssnr in dB [-20, +30], {@link CellInfo#UNAVAILABLE}
+ * @param cqi [0, 15], {@link CellInfo#UNAVAILABLE}
+ * @param timingAdvance [0, 1282], {@link CellInfo#UNAVAILABLE}
*
*/
/** @hide */
@@ -403,10 +403,11 @@
}
/**
- * Get reference signal signal-to-noise ratio
+ * Get reference signal signal-to-noise ratio in dB
+ * Range: -20 dB to +30 dB.
*
* @return the RSSNR if available or
- * {@link android.telephony.CellInfo#UNAVAILABLE UNAVAILABLE} if unavailable.
+ * {@link android.telephony.CellInfo#UNAVAILABLE} if unavailable.
*/
public int getRssnr() {
return mRssnr;
@@ -414,8 +415,10 @@
/**
* Get reference signal received power in dBm
+ * Range: -140 dBm to -43 dBm.
*
- * @return the RSRP of the measured cell.
+ * @return the RSRP of the measured cell or {@link CellInfo#UNAVAILABLE} if
+ * unavailable.
*/
public int getRsrp() {
return mRsrp;