summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Android.mk1
-rw-r--r--api/current.xml15
-rw-r--r--core/java/android/app/NativeActivity.java41
-rwxr-xr-xcore/java/android/content/res/Resources.java2
-rw-r--r--core/java/android/net/MobileDataStateTracker.java6
-rw-r--r--core/java/android/net/NetworkStateTracker.java19
-rw-r--r--core/java/android/os/storage/IMountService.aidl11
-rw-r--r--core/java/android/os/storage/IObbActionListener.aidl34
-rw-r--r--core/java/android/os/storage/StorageManager.java84
-rw-r--r--core/java/android/webkit/WebViewDatabase.java3
-rwxr-xr-xcore/java/com/android/internal/app/IMediaContainerService.aidl2
-rw-r--r--core/java/com/android/internal/app/PlatLogoActivity.java34
-rw-r--r--core/jni/Android.mk3
-rw-r--r--core/jni/AndroidRuntime.cpp2
-rw-r--r--core/jni/android_app_NativeActivity.cpp50
-rw-r--r--core/jni/android_content_res_Configuration.cpp118
-rw-r--r--core/res/AndroidManifest.xml3
-rw-r--r--core/res/res/drawable-hdpi/btn_check_label_background_light.9.pngbin0 -> 224 bytes
-rw-r--r--core/res/res/drawable-hdpi/btn_check_off.pngbin1693 -> 1238 bytes
-rw-r--r--core/res/res/drawable-hdpi/btn_check_off_disable.pngbin1170 -> 672 bytes
-rw-r--r--core/res/res/drawable-hdpi/btn_check_off_disable_focused.pngbin1568 -> 672 bytes
-rw-r--r--core/res/res/drawable-hdpi/btn_check_off_disable_focused_light.pngbin0 -> 689 bytes
-rw-r--r--core/res/res/drawable-hdpi/btn_check_off_disable_light.pngbin0 -> 689 bytes
-rw-r--r--core/res/res/drawable-hdpi/btn_check_off_light.pngbin0 -> 1945 bytes
-rw-r--r--core/res/res/drawable-hdpi/btn_check_off_pressed.pngbin2413 -> 4311 bytes
-rw-r--r--core/res/res/drawable-hdpi/btn_check_off_pressed_light.pngbin0 -> 2367 bytes
-rw-r--r--core/res/res/drawable-hdpi/btn_check_off_selected.pngbin2378 -> 1924 bytes
-rw-r--r--core/res/res/drawable-hdpi/btn_check_off_selected_light.pngbin0 -> 2260 bytes
-rw-r--r--core/res/res/drawable-hdpi/btn_check_on.pngbin2115 -> 5628 bytes
-rw-r--r--core/res/res/drawable-hdpi/btn_check_on_disable.pngbin1417 -> 4963 bytes
-rw-r--r--core/res/res/drawable-hdpi/btn_check_on_disable_focused.pngbin1788 -> 4963 bytes
-rw-r--r--core/res/res/drawable-hdpi/btn_check_on_disable_focused_light.pngbin0 -> 3715 bytes
-rw-r--r--core/res/res/drawable-hdpi/btn_check_on_disable_light.pngbin0 -> 3715 bytes
-rw-r--r--core/res/res/drawable-hdpi/btn_check_on_light.pngbin0 -> 5059 bytes
-rw-r--r--core/res/res/drawable-hdpi/btn_check_on_pressed.pngbin2586 -> 7963 bytes
-rw-r--r--core/res/res/drawable-hdpi/btn_check_on_pressed_light.pngbin0 -> 5489 bytes
-rw-r--r--core/res/res/drawable-hdpi/btn_check_on_selected.pngbin2546 -> 5603 bytes
-rw-r--r--core/res/res/drawable-hdpi/btn_check_on_selected_light.pngbin0 -> 5162 bytes
-rw-r--r--core/res/res/drawable-hdpi/btn_radio_label_background_light.9.pngbin0 -> 216 bytes
-rw-r--r--core/res/res/drawable-hdpi/btn_radio_off.pngbin2491 -> 3171 bytes
-rw-r--r--core/res/res/drawable-hdpi/btn_radio_off_light.pngbin0 -> 5508 bytes
-rw-r--r--core/res/res/drawable-hdpi/btn_radio_off_pressed.pngbin3304 -> 5501 bytes
-rw-r--r--core/res/res/drawable-hdpi/btn_radio_off_pressed_light.pngbin0 -> 6469 bytes
-rw-r--r--core/res/res/drawable-hdpi/btn_radio_off_selected.pngbin3267 -> 5104 bytes
-rw-r--r--core/res/res/drawable-hdpi/btn_radio_off_selected_light.pngbin0 -> 7433 bytes
-rw-r--r--core/res/res/drawable-hdpi/btn_radio_on.pngbin2777 -> 6956 bytes
-rw-r--r--core/res/res/drawable-hdpi/btn_radio_on_light.pngbin0 -> 7667 bytes
-rw-r--r--core/res/res/drawable-hdpi/btn_radio_on_pressed.pngbin3454 -> 9234 bytes
-rw-r--r--core/res/res/drawable-hdpi/btn_radio_on_pressed_light.pngbin0 -> 8606 bytes
-rw-r--r--core/res/res/drawable-hdpi/btn_radio_on_selected.pngbin3441 -> 7780 bytes
-rw-r--r--core/res/res/drawable-hdpi/btn_radio_on_selected_light.pngbin0 -> 9475 bytes
-rw-r--r--core/res/res/drawable-mdpi/btn_check_label_background_light.9.pngbin0 -> 178 bytes
-rw-r--r--core/res/res/drawable-mdpi/btn_check_off.pngbin1172 -> 968 bytes
-rw-r--r--core/res/res/drawable-mdpi/btn_check_off_disable.pngbin903 -> 613 bytes
-rw-r--r--core/res/res/drawable-mdpi/btn_check_off_disable_focused.pngbin1073 -> 613 bytes
-rw-r--r--core/res/res/drawable-mdpi/btn_check_off_disable_focused_light.pngbin0 -> 606 bytes
-rw-r--r--core/res/res/drawable-mdpi/btn_check_off_disable_light.pngbin0 -> 606 bytes
-rw-r--r--core/res/res/drawable-mdpi/btn_check_off_light.pngbin0 -> 1581 bytes
-rw-r--r--core/res/res/drawable-mdpi/btn_check_off_pressed.pngbin1630 -> 2269 bytes
-rw-r--r--core/res/res/drawable-mdpi/btn_check_off_pressed_light.pngbin0 -> 1748 bytes
-rw-r--r--core/res/res/drawable-mdpi/btn_check_off_selected.pngbin1598 -> 1661 bytes
-rw-r--r--core/res/res/drawable-mdpi/btn_check_off_selected_light.pngbin0 -> 1837 bytes
-rw-r--r--core/res/res/drawable-mdpi/btn_check_on.pngbin1390 -> 3109 bytes
-rw-r--r--core/res/res/drawable-mdpi/btn_check_on_disable.pngbin973 -> 2923 bytes
-rw-r--r--core/res/res/drawable-mdpi/btn_check_on_disable_focused.pngbin1138 -> 2923 bytes
-rw-r--r--core/res/res/drawable-mdpi/btn_check_on_disable_focused_light.pngbin0 -> 2100 bytes
-rw-r--r--core/res/res/drawable-mdpi/btn_check_on_disable_light.pngbin0 -> 2100 bytes
-rw-r--r--core/res/res/drawable-mdpi/btn_check_on_light.pngbin0 -> 2874 bytes
-rw-r--r--core/res/res/drawable-mdpi/btn_check_on_pressed.pngbin1680 -> 4053 bytes
-rw-r--r--core/res/res/drawable-mdpi/btn_check_on_pressed_light.pngbin0 -> 3109 bytes
-rw-r--r--core/res/res/drawable-mdpi/btn_check_on_selected.pngbin1661 -> 3340 bytes
-rw-r--r--core/res/res/drawable-mdpi/btn_check_on_selected_light.pngbin0 -> 2877 bytes
-rw-r--r--core/res/res/drawable-mdpi/btn_radio_label_background_light.9.pngbin0 -> 178 bytes
-rw-r--r--core/res/res/drawable-mdpi/btn_radio_off.pngbin1542 -> 1850 bytes
-rw-r--r--core/res/res/drawable-mdpi/btn_radio_off_light.pngbin0 -> 3414 bytes
-rw-r--r--core/res/res/drawable-mdpi/btn_radio_off_pressed.pngbin1928 -> 2748 bytes
-rw-r--r--core/res/res/drawable-mdpi/btn_radio_off_pressed_light.pngbin0 -> 3749 bytes
-rw-r--r--core/res/res/drawable-mdpi/btn_radio_off_selected.pngbin1954 -> 3390 bytes
-rw-r--r--core/res/res/drawable-mdpi/btn_radio_off_selected_light.pngbin0 -> 4546 bytes
-rw-r--r--core/res/res/drawable-mdpi/btn_radio_on.pngbin1692 -> 3714 bytes
-rw-r--r--core/res/res/drawable-mdpi/btn_radio_on_light.pngbin0 -> 4169 bytes
-rw-r--r--core/res/res/drawable-mdpi/btn_radio_on_pressed.pngbin1997 -> 4592 bytes
-rw-r--r--core/res/res/drawable-mdpi/btn_radio_on_pressed_light.pngbin0 -> 4521 bytes
-rw-r--r--core/res/res/drawable-mdpi/btn_radio_on_selected.pngbin2009 -> 4323 bytes
-rw-r--r--core/res/res/drawable-mdpi/btn_radio_on_selected_light.pngbin0 -> 5127 bytes
-rw-r--r--core/res/res/drawable-nodpi/platlogo.jpgbin0 -> 102076 bytes
-rw-r--r--core/res/res/drawable/btn_check_light.xml65
-rw-r--r--core/res/res/drawable/btn_radio_light.xml35
-rw-r--r--core/res/res/values-xlarge/styles.xml1
-rw-r--r--core/res/res/values/styles.xml10
-rw-r--r--core/res/res/values/themes.xml28
-rw-r--r--graphics/java/android/renderscript/Matrix4f.java70
-rw-r--r--include/android_runtime/android_content_res_Configuration.h36
-rw-r--r--include/utils/AssetManager.h2
-rw-r--r--include/utils/ObbFile.h4
-rw-r--r--include/utils/ResourceTypes.h119
-rw-r--r--libs/rs/rsAllocation.cpp3
-rw-r--r--libs/rs/rsElement.cpp5
-rw-r--r--libs/rs/scriptc/rs_core.rsh165
-rw-r--r--libs/rs/scriptc/rs_types.rsh4
-rw-r--r--libs/utils/AssetManager.cpp6
-rw-r--r--libs/utils/ObbFile.cpp42
-rw-r--r--media/libstagefright/CameraSource.cpp2
-rw-r--r--media/libstagefright/CameraSourceTimeLapse.cpp1
-rw-r--r--native/android/Android.mk1
-rw-r--r--native/android/asset_manager.cpp2
-rw-r--r--native/android/configuration.cpp202
-rw-r--r--native/copy-to-ndk.sh55
-rw-r--r--native/include/android/asset_manager.h10
-rw-r--r--native/include/android/asset_manager_jni.h40
-rw-r--r--native/include/android/configuration.h319
-rw-r--r--native/include/android/native_activity.h10
-rw-r--r--native/include/android/native_window.h11
-rw-r--r--packages/DefaultContainerService/src/com/android/defcontainer/DefaultContainerService.java6
-rw-r--r--packages/SystemUI/res/layout-xlarge/status_bar_center.xml3
-rw-r--r--services/java/com/android/server/ConnectivityService.java21
-rw-r--r--services/java/com/android/server/InputMethodManagerService.java7
-rw-r--r--services/java/com/android/server/MountService.java522
-rw-r--r--services/java/com/android/server/WifiService.java402
-rw-r--r--services/java/com/android/server/WifiWatchdogService.java13
-rw-r--r--services/surfaceflinger/LayerBuffer.cpp2
-rw-r--r--telephony/java/com/android/internal/telephony/CallManager.java2
-rw-r--r--telephony/java/com/android/internal/telephony/cat/AppInterface.java3
-rw-r--r--telephony/java/com/android/internal/telephony/cat/CatService.java144
-rw-r--r--telephony/java/com/android/internal/telephony/cat/CommandParamsFactory.java35
-rw-r--r--telephony/java/com/android/internal/telephony/cat/Input.java4
-rw-r--r--telephony/java/com/android/internal/telephony/cat/ResponseData.java12
-rw-r--r--telephony/java/com/android/internal/telephony/gsm/GSMPhone.java4
-rw-r--r--tests/DumpRenderTree2/Android.mk2
-rw-r--r--tests/DumpRenderTree2/AndroidManifest.xml6
-rw-r--r--tests/DumpRenderTree2/assets/run_layout_tests.py65
-rw-r--r--tests/DumpRenderTree2/src/com/android/dumprendertree2/ManagerService.java1
-rw-r--r--tests/DumpRenderTree2/src/com/android/dumprendertree2/Summarizer.java16
-rw-r--r--tests/DumpRenderTree2/src/com/android/dumprendertree2/TestsListActivity.java16
-rw-r--r--tests/DumpRenderTree2/src/com/android/dumprendertree2/TestsListPreloaderThread.java14
-rw-r--r--tests/DumpRenderTree2/src/com/android/dumprendertree2/scriptsupport/OnEverythingFinishedCallback.java25
-rw-r--r--tests/DumpRenderTree2/src/com/android/dumprendertree2/scriptsupport/ScriptTestRunner.java37
-rw-r--r--tests/DumpRenderTree2/src/com/android/dumprendertree2/scriptsupport/Starter.java74
-rw-r--r--tests/DumpRenderTree2/src/com/android/dumprendertree2/ui/DirListActivity.java4
-rw-r--r--tools/aapt/Android.mk2
-rw-r--r--tools/localize/Android.mk2
-rw-r--r--tools/obbtool/Android.mk30
-rw-r--r--tools/obbtool/Main.cpp225
-rw-r--r--wifi/java/android/net/wifi/IWifiManager.aidl8
-rw-r--r--wifi/java/android/net/wifi/WifiManager.java91
-rw-r--r--wifi/java/android/net/wifi/WifiMonitor.java33
-rw-r--r--wifi/java/android/net/wifi/WifiStateMachine.java3571
-rw-r--r--wifi/java/android/net/wifi/WifiStateTracker.java3812
148 files changed, 6740 insertions, 4150 deletions
diff --git a/Android.mk b/Android.mk
index 524ec51..65f7a35 100644
--- a/Android.mk
+++ b/Android.mk
@@ -123,6 +123,7 @@ LOCAL_SRC_FILES += \
core/java/android/os/storage/IMountService.aidl \
core/java/android/os/storage/IMountServiceListener.aidl \
core/java/android/os/storage/IMountShutdownObserver.aidl \
+ core/java/android/os/storage/IObbActionListener.aidl \
core/java/android/os/INetworkManagementService.aidl \
core/java/android/os/INetStatService.aidl \
core/java/android/os/IPermissionController.aidl \
diff --git a/api/current.xml b/api/current.xml
index 53d2fdd..64ac66f 100644
--- a/api/current.xml
+++ b/api/current.xml
@@ -30669,6 +30669,17 @@
<parameter name="holder" type="android.view.SurfaceHolder">
</parameter>
</method>
+<field name="KEY_NATIVE_SAVED_STATE"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value="&quot;android:native_state&quot;"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
<field name="META_DATA_LIB_NAME"
type="java.lang.String"
transient="false"
@@ -136174,6 +136185,8 @@
>
<parameter name="filename" type="java.lang.String">
</parameter>
+<exception name="IllegalArgumentException" type="java.lang.IllegalArgumentException">
+</exception>
</method>
<method name="isUsbMassStorageConnected"
return="boolean"
@@ -136239,6 +136252,8 @@
</parameter>
<parameter name="force" type="boolean">
</parameter>
+<exception name="IllegalArgumentException" type="java.lang.IllegalArgumentException">
+</exception>
</method>
<method name="unregisterListener"
return="void"
diff --git a/core/java/android/app/NativeActivity.java b/core/java/android/app/NativeActivity.java
index eaf0675..4dc88b3 100644
--- a/core/java/android/app/NativeActivity.java
+++ b/core/java/android/app/NativeActivity.java
@@ -10,6 +10,7 @@ import android.content.pm.ActivityInfo;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.content.res.AssetManager;
+import android.content.res.Configuration;
import android.graphics.PixelFormat;
import android.os.Build;
import android.os.Bundle;
@@ -32,12 +33,27 @@ import java.lang.ref.WeakReference;
/**
* Convenience for implementing an activity that will be implemented
- * purely in native code. That is, a game (or game-like thing).
+ * purely in native code. That is, a game (or game-like thing). There
+ * is no need to derive from this class; you can simply declare it in your
+ * manifest, and use the NDK APIs from there.
+ *
+ * <p>A typical manifest would look like:
+ *
+ * {@sample development/ndk/platforms/android-9/samples/native-activity/AndroidManifest.xml
+ * manifest}
+ *
+ * <p>A very simple example of native code that is run by NativeActivity
+ * follows. This reads input events from the user and uses OpenGLES to
+ * draw into the native activity's window.
+ *
+ * {@sample development/ndk/platforms/android-9/samples/native-activity/jni/main.c all}
*/
public class NativeActivity extends Activity implements SurfaceHolder.Callback2,
InputQueue.Callback, OnGlobalLayoutListener {
public static final String META_DATA_LIB_NAME = "android.app.lib_name";
+ public static final String KEY_NATIVE_SAVED_STATE = "android:native_state";
+
private NativeContentView mNativeContentView;
private InputMethodManager mIMM;
private InputMethodCallback mInputMethodCallback;
@@ -59,14 +75,15 @@ public class NativeActivity extends Activity implements SurfaceHolder.Callback2,
private native int loadNativeCode(String path, MessageQueue queue,
String internalDataPath, String externalDataPath, int sdkVersion,
- AssetManager assetMgr);
+ AssetManager assetMgr, byte[] savedState);
private native void unloadNativeCode(int handle);
private native void onStartNative(int handle);
private native void onResumeNative(int handle);
- private native void onSaveInstanceStateNative(int handle);
+ private native byte[] onSaveInstanceStateNative(int handle);
private native void onPauseNative(int handle);
private native void onStopNative(int handle);
+ private native void onConfigurationChangedNative(int handle);
private native void onLowMemoryNative(int handle);
private native void onWindowFocusChangedNative(int handle, boolean focused);
private native void onSurfaceCreatedNative(int handle, Surface surface);
@@ -165,10 +182,13 @@ public class NativeActivity extends Activity implements SurfaceHolder.Callback2,
throw new IllegalArgumentException("Unable to find native library: " + libname);
}
+ byte[] nativeSavedState = savedInstanceState != null
+ ? savedInstanceState.getByteArray(KEY_NATIVE_SAVED_STATE) : null;
+
mNativeHandle = loadNativeCode(path, Looper.myQueue(),
getFilesDir().toString(),
Environment.getExternalStorageAppFilesDirectory(ai.packageName).toString(),
- Build.VERSION.SDK_INT, getAssets());
+ Build.VERSION.SDK_INT, getAssets(), nativeSavedState);
if (mNativeHandle == 0) {
throw new IllegalArgumentException("Unable to load native library: " + path);
@@ -206,7 +226,10 @@ public class NativeActivity extends Activity implements SurfaceHolder.Callback2,
@Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
- onSaveInstanceStateNative(mNativeHandle);
+ byte[] state = onSaveInstanceStateNative(mNativeHandle);
+ if (state != null) {
+ outState.putByteArray(KEY_NATIVE_SAVED_STATE, state);
+ }
}
@Override
@@ -222,6 +245,14 @@ public class NativeActivity extends Activity implements SurfaceHolder.Callback2,
}
@Override
+ public void onConfigurationChanged(Configuration newConfig) {
+ super.onConfigurationChanged(newConfig);
+ if (!mDestroyed) {
+ onConfigurationChangedNative(mNativeHandle);
+ }
+ }
+
+ @Override
public void onLowMemory() {
super.onLowMemory();
if (!mDestroyed) {
diff --git a/core/java/android/content/res/Resources.java b/core/java/android/content/res/Resources.java
index ba1b3a9..812af5a 100755
--- a/core/java/android/content/res/Resources.java
+++ b/core/java/android/content/res/Resources.java
@@ -1333,7 +1333,7 @@ public class Resources {
height = mMetrics.widthPixels;
}
int keyboardHidden = mConfiguration.keyboardHidden;
- if (keyboardHidden == Configuration.HARDKEYBOARDHIDDEN_NO
+ if (keyboardHidden == Configuration.KEYBOARDHIDDEN_NO
&& mConfiguration.hardKeyboardHidden
== Configuration.HARDKEYBOARDHIDDEN_YES) {
keyboardHidden = Configuration.KEYBOARDHIDDEN_SOFT;
diff --git a/core/java/android/net/MobileDataStateTracker.java b/core/java/android/net/MobileDataStateTracker.java
index 11cd526..efbccd2 100644
--- a/core/java/android/net/MobileDataStateTracker.java
+++ b/core/java/android/net/MobileDataStateTracker.java
@@ -526,12 +526,6 @@ public class MobileDataStateTracker implements NetworkStateTracker {
return -1;
}
- /**
- * This is not supported.
- */
- public void interpretScanResultsAvailable() {
- }
-
@Override
public String toString() {
StringBuffer sb = new StringBuffer("Mobile data state: ");
diff --git a/core/java/android/net/NetworkStateTracker.java b/core/java/android/net/NetworkStateTracker.java
index 44215e7..82735e5 100644
--- a/core/java/android/net/NetworkStateTracker.java
+++ b/core/java/android/net/NetworkStateTracker.java
@@ -27,18 +27,17 @@ package android.net;
public interface NetworkStateTracker {
public static final int EVENT_STATE_CHANGED = 1;
- public static final int EVENT_SCAN_RESULTS_AVAILABLE = 2;
/**
* arg1: 1 to show, 0 to hide
* arg2: ID of the notification
* obj: Notification (if showing)
*/
- public static final int EVENT_NOTIFICATION_CHANGED = 3;
- public static final int EVENT_CONFIGURATION_CHANGED = 4;
- public static final int EVENT_ROAMING_CHANGED = 5;
- public static final int EVENT_NETWORK_SUBTYPE_CHANGED = 6;
- public static final int EVENT_RESTORE_DEFAULT_NETWORK = 7;
- public static final int EVENT_CLEAR_NET_TRANSITION_WAKELOCK = 8;
+ public static final int EVENT_NOTIFICATION_CHANGED = 2;
+ public static final int EVENT_CONFIGURATION_CHANGED = 3;
+ public static final int EVENT_ROAMING_CHANGED = 4;
+ public static final int EVENT_NETWORK_SUBTYPE_CHANGED = 5;
+ public static final int EVENT_RESTORE_DEFAULT_NETWORK = 6;
+ public static final int EVENT_CLEAR_NET_TRANSITION_WAKELOCK = 7;
/**
* Fetch NetworkInfo for the network
@@ -147,10 +146,4 @@ public interface NetworkStateTracker {
*/
public int stopUsingNetworkFeature(String feature, int callingPid, int callingUid);
- /**
- * Interprets scan results. This will be called at a safe time for
- * processing, and from a safe thread.
- */
- public void interpretScanResultsAvailable();
-
}
diff --git a/core/java/android/os/storage/IMountService.aidl b/core/java/android/os/storage/IMountService.aidl
index ca7efe7..5c69214 100644
--- a/core/java/android/os/storage/IMountService.aidl
+++ b/core/java/android/os/storage/IMountService.aidl
@@ -19,6 +19,7 @@ package android.os.storage;
import android.os.storage.IMountServiceListener;
import android.os.storage.IMountShutdownObserver;
+import android.os.storage.IObbActionListener;
/** WARNING! Update IMountService.h and IMountService.cpp if you change this file.
* In particular, the ordering of the methods below must match the
@@ -156,14 +157,20 @@ interface IMountService
/**
* Mounts an Opaque Binary Blob (OBB) with the specified decryption key and only
* allows the calling process's UID access to the contents.
+ *
+ * MountService will call back to the supplied IObbActionListener to inform
+ * it of the terminal state of the call.
*/
- int mountObb(String filename, String key);
+ void mountObb(String filename, String key, IObbActionListener token);
/**
* Unmounts an Opaque Binary Blob (OBB). When the force flag is specified, any
* program using it will be forcibly killed to unmount the image.
+ *
+ * MountService will call back to the supplied IObbActionListener to inform
+ * it of the terminal state of the call.
*/
- int unmountObb(String filename, boolean force);
+ void unmountObb(String filename, boolean force, IObbActionListener token);
/**
* Checks whether the specified Opaque Binary Blob (OBB) is mounted somewhere.
diff --git a/core/java/android/os/storage/IObbActionListener.aidl b/core/java/android/os/storage/IObbActionListener.aidl
new file mode 100644
index 0000000..78d7a9e
--- /dev/null
+++ b/core/java/android/os/storage/IObbActionListener.aidl
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.os.storage;
+
+/**
+ * Callback class for receiving events from MountService about
+ * Opaque Binary Blobs (OBBs).
+ *
+ * @hide - Applications should use android.os.storage.StorageManager
+ * to interact with OBBs.
+ */
+interface IObbActionListener {
+ /**
+ * Return from an OBB action result.
+ *
+ * @param filename the path to the OBB the operation was performed on
+ * @param returnCode status of the operation
+ */
+ void onObbResult(String filename, String status);
+}
diff --git a/core/java/android/os/storage/StorageManager.java b/core/java/android/os/storage/StorageManager.java
index 61cdace..7c9effa 100644
--- a/core/java/android/os/storage/StorageManager.java
+++ b/core/java/android/os/storage/StorageManager.java
@@ -16,28 +16,14 @@
package android.os.storage;
-import android.content.Context;
-import android.os.Binder;
-import android.os.Bundle;
-import android.os.Looper;
-import android.os.Parcelable;
-import android.os.ParcelFileDescriptor;
-import android.os.Process;
-import android.os.RemoteException;
import android.os.Handler;
+import android.os.Looper;
import android.os.Message;
+import android.os.RemoteException;
import android.os.ServiceManager;
-import android.os.storage.IMountService;
-import android.os.storage.IMountServiceListener;
import android.util.Log;
-import android.util.SparseArray;
-import java.io.FileDescriptor;
-import java.io.IOException;
import java.util.ArrayList;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.List;
/**
* StorageManager is the interface to the systems storage service.
@@ -88,6 +74,17 @@ public class StorageManager
}
/**
+ * Binder listener for OBB action results.
+ */
+ private final ObbActionBinderListener mObbActionListener = new ObbActionBinderListener();
+ private class ObbActionBinderListener extends IObbActionListener.Stub {
+ @Override
+ public void onObbResult(String filename, String status) throws RemoteException {
+ Log.i(TAG, "filename = " + filename + ", result = " + status);
+ }
+ }
+
+ /**
* Private base class for messages sent between the callback thread
* and the target looper handler.
*/
@@ -290,12 +287,23 @@ public class StorageManager
}
/**
- * Mount an OBB file.
+ * Mount an Opaque Binary Blob (OBB) file. If a <code>key</code> is
+ * specified, it is supplied to the mounting process to be used in any
+ * encryption used in the OBB.
+ * <p>
+ * <em>Note:</em> you can only mount OBB files for which the OBB tag on the
+ * file matches a package ID that is owned by the calling program's UID.
+ * That is, shared UID applications can obtain access to any other
+ * application's OBB that shares its UID.
+ *
+ * @param filename the path to the OBB file
+ * @param key decryption key
+ * @return whether the mount call was successfully queued or not
*/
public boolean mountObb(String filename, String key) {
try {
- return mMountService.mountObb(filename, key)
- == StorageResultCode.OperationSucceeded;
+ mMountService.mountObb(filename, key, mObbActionListener);
+ return true;
} catch (RemoteException e) {
Log.e(TAG, "Failed to mount OBB", e);
}
@@ -304,12 +312,24 @@ public class StorageManager
}
/**
- * Mount an OBB file.
+ * Unmount an Opaque Binary Blob (OBB) file. If the <code>force</code> flag
+ * is true, it will kill any application needed to unmount the given OBB.
+ * <p>
+ * <em>Note:</em> you can only mount OBB files for which the OBB tag on the
+ * file matches a package ID that is owned by the calling program's UID.
+ * That is, shared UID applications can obtain access to any other
+ * application's OBB that shares its UID.
+ *
+ * @param filename path to the OBB file
+ * @param force whether to kill any programs using this in order to unmount
+ * it
+ * @return whether the unmount call was successfully queued or not
+ * @throws IllegalArgumentException when OBB is not already mounted
*/
- public boolean unmountObb(String filename, boolean force) {
+ public boolean unmountObb(String filename, boolean force) throws IllegalArgumentException {
try {
- return mMountService.unmountObb(filename, force)
- == StorageResultCode.OperationSucceeded;
+ mMountService.unmountObb(filename, force, mObbActionListener);
+ return true;
} catch (RemoteException e) {
Log.e(TAG, "Failed to mount OBB", e);
}
@@ -317,7 +337,13 @@ public class StorageManager
return false;
}
- public boolean isObbMounted(String filename) {
+ /**
+ * Check whether an Opaque Binary Blob (OBB) is mounted or not.
+ *
+ * @param filename path to OBB image
+ * @return true if OBB is mounted; false if not mounted or on error
+ */
+ public boolean isObbMounted(String filename) throws IllegalArgumentException {
try {
return mMountService.isObbMounted(filename);
} catch (RemoteException e) {
@@ -328,13 +354,21 @@ public class StorageManager
}
/**
- * Check the mounted path of an OBB file.
+ * Check the mounted path of an Opaque Binary Blob (OBB) file. This will
+ * give you the path to where you can obtain access to the internals of the
+ * OBB.
+ *
+ * @param filename path to OBB image
+ * @return absolute path to mounted OBB image data or <code>null</code> if
+ * not mounted or exception encountered trying to read status
*/
public String getMountedObbPath(String filename) {
try {
return mMountService.getMountedObbPath(filename);
} catch (RemoteException e) {
Log.e(TAG, "Failed to find mounted path for OBB", e);
+ } catch (IllegalArgumentException e) {
+ Log.d(TAG, "Couldn't read OBB file", e);
}
return null;
diff --git a/core/java/android/webkit/WebViewDatabase.java b/core/java/android/webkit/WebViewDatabase.java
index d75d421..d7b4452 100644
--- a/core/java/android/webkit/WebViewDatabase.java
+++ b/core/java/android/webkit/WebViewDatabase.java
@@ -772,6 +772,9 @@ public class WebViewDatabase {
}
long getCacheTotalSize() {
+ if (mCacheDatabase == null) {
+ return 0;
+ }
long size = 0;
Cursor cursor = null;
final String query = "SELECT SUM(contentlength) as sum FROM cache";
diff --git a/core/java/com/android/internal/app/IMediaContainerService.aidl b/core/java/com/android/internal/app/IMediaContainerService.aidl
index 89649a9..5d1f632 100755
--- a/core/java/com/android/internal/app/IMediaContainerService.aidl
+++ b/core/java/com/android/internal/app/IMediaContainerService.aidl
@@ -19,6 +19,7 @@ package com.android.internal.app;
import android.net.Uri;
import android.os.ParcelFileDescriptor;
import android.content.pm.PackageInfoLite;
+import android.content.res.ObbInfo;
interface IMediaContainerService {
String copyResourceToContainer(in Uri packageURI,
@@ -28,4 +29,5 @@ interface IMediaContainerService {
in ParcelFileDescriptor outStream);
PackageInfoLite getMinimalPackageInfo(in Uri fileUri, int flags);
boolean checkFreeStorage(boolean external, in Uri fileUri);
+ ObbInfo getObbInfo(String filename);
}
diff --git a/core/java/com/android/internal/app/PlatLogoActivity.java b/core/java/com/android/internal/app/PlatLogoActivity.java
new file mode 100644
index 0000000..ce5959d
--- /dev/null
+++ b/core/java/com/android/internal/app/PlatLogoActivity.java
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.app;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.widget.ImageView;
+
+public class PlatLogoActivity extends Activity {
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ ImageView content = new ImageView(this);
+ content.setImageResource(com.android.internal.R.drawable.platlogo);
+ content.setScaleType(ImageView.ScaleType.FIT_CENTER);
+
+ setContentView(content);
+ }
+}
diff --git a/core/jni/Android.mk b/core/jni/Android.mk
index d1a5ae1..860b5b7 100644
--- a/core/jni/Android.mk
+++ b/core/jni/Android.mk
@@ -139,7 +139,8 @@ LOCAL_SRC_FILES:= \
android_backup_BackupDataOutput.cpp \
android_backup_FileBackupHelperBase.cpp \
android_backup_BackupHelperDispatcher.cpp \
- android_content_res_ObbScanner.cpp
+ android_content_res_ObbScanner.cpp \
+ android_content_res_Configuration.cpp
LOCAL_C_INCLUDES += \
$(JNI_H_INCLUDE) \
diff --git a/core/jni/AndroidRuntime.cpp b/core/jni/AndroidRuntime.cpp
index 8b09e5f..2dd17bb 100644
--- a/core/jni/AndroidRuntime.cpp
+++ b/core/jni/AndroidRuntime.cpp
@@ -167,6 +167,7 @@ extern int register_android_view_InputQueue(JNIEnv* env);
extern int register_android_view_KeyEvent(JNIEnv* env);
extern int register_android_view_MotionEvent(JNIEnv* env);
extern int register_android_content_res_ObbScanner(JNIEnv* env);
+extern int register_android_content_res_Configuration(JNIEnv* env);
static AndroidRuntime* gCurRuntime = NULL;
@@ -1331,6 +1332,7 @@ static const RegJNIRec gRegJNI[] = {
REG_JNI(register_android_view_MotionEvent),
REG_JNI(register_android_content_res_ObbScanner),
+ REG_JNI(register_android_content_res_Configuration),
};
/*
diff --git a/core/jni/android_app_NativeActivity.cpp b/core/jni/android_app_NativeActivity.cpp
index 1feb3b3..0932473 100644
--- a/core/jni/android_app_NativeActivity.cpp
+++ b/core/jni/android_app_NativeActivity.cpp
@@ -600,7 +600,7 @@ static bool mainWorkCallback(int fd, int events, void* data) {
static jint
loadNativeCode_native(JNIEnv* env, jobject clazz, jstring path, jobject messageQueue,
jstring internalDataDir, jstring externalDataDir, int sdkVersion,
- jobject jAssetMgr)
+ jobject jAssetMgr, jbyteArray savedState)
{
LOG_TRACE("loadNativeCode_native");
@@ -666,7 +666,18 @@ loadNativeCode_native(JNIEnv* env, jobject clazz, jstring path, jobject messageQ
code->assetManager = assetManagerForJavaObject(env, jAssetMgr);
- code->createActivityFunc(code, NULL, 0);
+ jbyte* rawSavedState = NULL;
+ jsize rawSavedSize = 0;
+ if (savedState != NULL) {
+ rawSavedState = env->GetByteArrayElements(savedState, NULL);
+ rawSavedSize = env->GetArrayLength(savedState);
+ }
+
+ code->createActivityFunc(code, rawSavedState, rawSavedSize);
+
+ if (rawSavedState != NULL) {
+ env->ReleaseByteArrayElements(savedState, rawSavedState, 0);
+ }
}
return (jint)code;
@@ -706,17 +717,31 @@ onResume_native(JNIEnv* env, jobject clazz, jint handle)
}
}
-static void
+static jbyteArray
onSaveInstanceState_native(JNIEnv* env, jobject clazz, jint handle)
{
LOG_TRACE("onSaveInstanceState_native");
+
+ jbyteArray array = NULL;
+
if (handle != 0) {
NativeCode* code = (NativeCode*)handle;
if (code->callbacks.onSaveInstanceState != NULL) {
size_t len = 0;
- code->callbacks.onSaveInstanceState(code, &len);
+ jbyte* state = (jbyte*)code->callbacks.onSaveInstanceState(code, &len);
+ if (len > 0) {
+ array = env->NewByteArray(len);
+ if (array != NULL) {
+ env->SetByteArrayRegion(array, 0, len, state);
+ }
+ }
+ if (state != NULL) {
+ free(state);
+ }
}
}
+
+ return array;
}
static void
@@ -744,6 +769,18 @@ onStop_native(JNIEnv* env, jobject clazz, jint handle)
}
static void
+onConfigurationChanged_native(JNIEnv* env, jobject clazz, jint handle)
+{
+ LOG_TRACE("onConfigurationChanged_native");
+ if (handle != 0) {
+ NativeCode* code = (NativeCode*)handle;
+ if (code->callbacks.onConfigurationChanged != NULL) {
+ code->callbacks.onConfigurationChanged(code);
+ }
+ }
+}
+
+static void
onLowMemory_native(JNIEnv* env, jobject clazz, jint handle)
{
LOG_TRACE("onLowMemory_native");
@@ -934,14 +971,15 @@ finishPreDispatchKeyEvent_native(JNIEnv* env, jobject clazz, jint handle,
}
static const JNINativeMethod g_methods[] = {
- { "loadNativeCode", "(Ljava/lang/String;Landroid/os/MessageQueue;Ljava/lang/String;Ljava/lang/String;ILandroid/content/res/AssetManager;)I",
+ { "loadNativeCode", "(Ljava/lang/String;Landroid/os/MessageQueue;Ljava/lang/String;Ljava/lang/String;ILandroid/content/res/AssetManager;[B)I",
(void*)loadNativeCode_native },
{ "unloadNativeCode", "(I)V", (void*)unloadNativeCode_native },
{ "onStartNative", "(I)V", (void*)onStart_native },
{ "onResumeNative", "(I)V", (void*)onResume_native },
- { "onSaveInstanceStateNative", "(I)V", (void*)onSaveInstanceState_native },
+ { "onSaveInstanceStateNative", "(I)[B", (void*)onSaveInstanceState_native },
{ "onPauseNative", "(I)V", (void*)onPause_native },
{ "onStopNative", "(I)V", (void*)onStop_native },
+ { "onConfigurationChangedNative", "(I)V", (void*)onConfigurationChanged_native },
{ "onLowMemoryNative", "(I)V", (void*)onLowMemory_native },
{ "onWindowFocusChangedNative", "(IZ)V", (void*)onWindowFocusChanged_native },
{ "onSurfaceCreatedNative", "(ILandroid/view/Surface;)V", (void*)onSurfaceCreated_native },
diff --git a/core/jni/android_content_res_Configuration.cpp b/core/jni/android_content_res_Configuration.cpp
new file mode 100644
index 0000000..28a43ab
--- /dev/null
+++ b/core/jni/android_content_res_Configuration.cpp
@@ -0,0 +1,118 @@
+/*
+ * Copyright 2010, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "Configuration"
+
+#include <utils/Log.h>
+#include "utils/misc.h"
+
+#include "jni.h"
+#include <android_runtime/android_content_res_Configuration.h>
+#include "android_runtime/AndroidRuntime.h"
+
+namespace android {
+
+static struct {
+ jclass clazz;
+
+ jfieldID mcc;
+ jfieldID mnc;
+ jfieldID locale;
+ jfieldID screenLayout;
+ jfieldID touchscreen;
+ jfieldID keyboard;
+ jfieldID keyboardHidden;
+ jfieldID hardKeyboardHidden;
+ jfieldID navigation;
+ jfieldID navigationHidden;
+ jfieldID orientation;
+ jfieldID uiMode;
+} gConfigurationClassInfo;
+
+void android_Configuration_getFromJava(
+ JNIEnv* env, jobject clazz, struct AConfiguration* out) {
+ out->mcc = env->GetIntField(clazz, gConfigurationClassInfo.mcc);
+ out->mnc = env->GetIntField(clazz, gConfigurationClassInfo.mnc);
+ out->screenLayout = env->GetIntField(clazz, gConfigurationClassInfo.screenLayout);
+ out->touchscreen = env->GetIntField(clazz, gConfigurationClassInfo.touchscreen);
+ out->keyboard = env->GetIntField(clazz, gConfigurationClassInfo.keyboard);
+ out->navigation = env->GetIntField(clazz, gConfigurationClassInfo.navigation);
+
+ out->inputFlags = env->GetIntField(clazz, gConfigurationClassInfo.keyboardHidden);
+ int hardKeyboardHidden = env->GetIntField(clazz, gConfigurationClassInfo.hardKeyboardHidden);
+ if (out->inputFlags == ACONFIGURATION_KEYSHIDDEN_NO
+ && hardKeyboardHidden == 2) {
+ out->inputFlags = ACONFIGURATION_KEYSHIDDEN_SOFT;
+ }
+ out->inputFlags |= env->GetIntField(clazz, gConfigurationClassInfo.navigationHidden)
+ << ResTable_config::SHIFT_NAVHIDDEN;
+
+ out->orientation = env->GetIntField(clazz, gConfigurationClassInfo.orientation);
+ out->uiMode = env->GetIntField(clazz, gConfigurationClassInfo.uiMode);
+}
+
+/*
+ * JNI registration.
+ */
+static JNINativeMethod gMethods[] = {
+ /* name, signature, funcPtr */
+ //{ "getObbInfo_native", "(Ljava/lang/String;Landroid/content/res/ObbInfo;)Z",
+ // (void*) android_content_res_ObbScanner_getObbInfo },
+};
+
+#define FIND_CLASS(var, className) \
+ var = env->FindClass(className); \
+ LOG_FATAL_IF(! var, "Unable to find class " className); \
+ var = jclass(env->NewGlobalRef(var));
+
+#define GET_FIELD_ID(var, clazz, fieldName, fieldDescriptor) \
+ var = env->GetFieldID(clazz, fieldName, fieldDescriptor); \
+ LOG_FATAL_IF(! var, "Unable to find field " fieldName);
+
+int register_android_content_res_Configuration(JNIEnv* env)
+{
+ FIND_CLASS(gConfigurationClassInfo.clazz, "android/content/res/Configuration");
+
+ GET_FIELD_ID(gConfigurationClassInfo.mcc, gConfigurationClassInfo.clazz,
+ "mcc", "I");
+ GET_FIELD_ID(gConfigurationClassInfo.mnc, gConfigurationClassInfo.clazz,
+ "mnc", "I");
+ GET_FIELD_ID(gConfigurationClassInfo.locale, gConfigurationClassInfo.clazz,
+ "locale", "Ljava/util/Locale;");
+ GET_FIELD_ID(gConfigurationClassInfo.screenLayout, gConfigurationClassInfo.clazz,
+ "screenLayout", "I");
+ GET_FIELD_ID(gConfigurationClassInfo.touchscreen, gConfigurationClassInfo.clazz,
+ "touchscreen", "I");
+ GET_FIELD_ID(gConfigurationClassInfo.keyboard, gConfigurationClassInfo.clazz,
+ "keyboard", "I");
+ GET_FIELD_ID(gConfigurationClassInfo.keyboardHidden, gConfigurationClassInfo.clazz,
+ "keyboardHidden", "I");
+ GET_FIELD_ID(gConfigurationClassInfo.hardKeyboardHidden, gConfigurationClassInfo.clazz,
+ "hardKeyboardHidden", "I");
+ GET_FIELD_ID(gConfigurationClassInfo.navigation, gConfigurationClassInfo.clazz,
+ "navigation", "I");
+ GET_FIELD_ID(gConfigurationClassInfo.navigationHidden, gConfigurationClassInfo.clazz,
+ "navigationHidden", "I");
+ GET_FIELD_ID(gConfigurationClassInfo.orientation, gConfigurationClassInfo.clazz,
+ "orientation", "I");
+ GET_FIELD_ID(gConfigurationClassInfo.uiMode, gConfigurationClassInfo.clazz,
+ "uiMode", "I");
+
+ return AndroidRuntime::registerNativeMethods(env, "android/content/res/Configuration", gMethods,
+ NELEM(gMethods));
+}
+
+}; // namespace android
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 01ded68..1f66d05 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -1284,6 +1284,9 @@
android:finishOnCloseSystemDialogs="true"
android:excludeFromRecents="true">
</activity>
+ <activity android:name="com.android.internal.app.PlatLogoActivity"
+ android:theme="@style/Theme.NoTitleBar.Fullscreen">
+ </activity>
<activity android:name="com.android.internal.app.DisableCarModeActivity"
android:theme="@style/Theme.NoDisplay"
android:excludeFromRecents="true">
diff --git a/core/res/res/drawable-hdpi/btn_check_label_background_light.9.png b/core/res/res/drawable-hdpi/btn_check_label_background_light.9.png
new file mode 100644
index 0000000..97e6806
--- /dev/null
+++ b/core/res/res/drawable-hdpi/btn_check_label_background_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_check_off.png b/core/res/res/drawable-hdpi/btn_check_off.png
index aad9ef7..911e1aa 100644
--- a/core/res/res/drawable-hdpi/btn_check_off.png
+++ b/core/res/res/drawable-hdpi/btn_check_off.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_check_off_disable.png b/core/res/res/drawable-hdpi/btn_check_off_disable.png
index eaee9e0..d72e2b9 100644
--- a/core/res/res/drawable-hdpi/btn_check_off_disable.png
+++ b/core/res/res/drawable-hdpi/btn_check_off_disable.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_check_off_disable_focused.png b/core/res/res/drawable-hdpi/btn_check_off_disable_focused.png
index 6d2c293..d72e2b9 100644
--- a/core/res/res/drawable-hdpi/btn_check_off_disable_focused.png
+++ b/core/res/res/drawable-hdpi/btn_check_off_disable_focused.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_check_off_disable_focused_light.png b/core/res/res/drawable-hdpi/btn_check_off_disable_focused_light.png
new file mode 100644
index 0000000..240a044
--- /dev/null
+++ b/core/res/res/drawable-hdpi/btn_check_off_disable_focused_light.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_check_off_disable_light.png b/core/res/res/drawable-hdpi/btn_check_off_disable_light.png
new file mode 100644
index 0000000..240a044
--- /dev/null
+++ b/core/res/res/drawable-hdpi/btn_check_off_disable_light.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_check_off_light.png b/core/res/res/drawable-hdpi/btn_check_off_light.png
new file mode 100644
index 0000000..4ca3c56
--- /dev/null
+++ b/core/res/res/drawable-hdpi/btn_check_off_light.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_check_off_pressed.png b/core/res/res/drawable-hdpi/btn_check_off_pressed.png
index 1c442e9..08f4181 100644
--- a/core/res/res/drawable-hdpi/btn_check_off_pressed.png
+++ b/core/res/res/drawable-hdpi/btn_check_off_pressed.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_check_off_pressed_light.png b/core/res/res/drawable-hdpi/btn_check_off_pressed_light.png
new file mode 100644
index 0000000..d3754dd
--- /dev/null
+++ b/core/res/res/drawable-hdpi/btn_check_off_pressed_light.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_check_off_selected.png b/core/res/res/drawable-hdpi/btn_check_off_selected.png
index b852b2c..264f102 100644
--- a/core/res/res/drawable-hdpi/btn_check_off_selected.png
+++ b/core/res/res/drawable-hdpi/btn_check_off_selected.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_check_off_selected_light.png b/core/res/res/drawable-hdpi/btn_check_off_selected_light.png
new file mode 100644
index 0000000..48506bf
--- /dev/null
+++ b/core/res/res/drawable-hdpi/btn_check_off_selected_light.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_check_on.png b/core/res/res/drawable-hdpi/btn_check_on.png
index cd5c181..5541c67 100644
--- a/core/res/res/drawable-hdpi/btn_check_on.png
+++ b/core/res/res/drawable-hdpi/btn_check_on.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_check_on_disable.png b/core/res/res/drawable-hdpi/btn_check_on_disable.png
index b4fc51a..7805458 100644
--- a/core/res/res/drawable-hdpi/btn_check_on_disable.png
+++ b/core/res/res/drawable-hdpi/btn_check_on_disable.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_check_on_disable_focused.png b/core/res/res/drawable-hdpi/btn_check_on_disable_focused.png
index bf34647..7805458 100644
--- a/core/res/res/drawable-hdpi/btn_check_on_disable_focused.png
+++ b/core/res/res/drawable-hdpi/btn_check_on_disable_focused.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_check_on_disable_focused_light.png b/core/res/res/drawable-hdpi/btn_check_on_disable_focused_light.png
new file mode 100644
index 0000000..4e268d5
--- /dev/null
+++ b/core/res/res/drawable-hdpi/btn_check_on_disable_focused_light.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_check_on_disable_light.png b/core/res/res/drawable-hdpi/btn_check_on_disable_light.png
new file mode 100644
index 0000000..4e268d5
--- /dev/null
+++ b/core/res/res/drawable-hdpi/btn_check_on_disable_light.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_check_on_light.png b/core/res/res/drawable-hdpi/btn_check_on_light.png
new file mode 100644
index 0000000..768c4af
--- /dev/null
+++ b/core/res/res/drawable-hdpi/btn_check_on_light.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_check_on_pressed.png b/core/res/res/drawable-hdpi/btn_check_on_pressed.png
index fa5c7a2..37e3953 100644
--- a/core/res/res/drawable-hdpi/btn_check_on_pressed.png
+++ b/core/res/res/drawable-hdpi/btn_check_on_pressed.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_check_on_pressed_light.png b/core/res/res/drawable-hdpi/btn_check_on_pressed_light.png
new file mode 100644
index 0000000..fc29e46
--- /dev/null
+++ b/core/res/res/drawable-hdpi/btn_check_on_pressed_light.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_check_on_selected.png b/core/res/res/drawable-hdpi/btn_check_on_selected.png
index a6a21ad..a0beac4 100644
--- a/core/res/res/drawable-hdpi/btn_check_on_selected.png
+++ b/core/res/res/drawable-hdpi/btn_check_on_selected.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_check_on_selected_light.png b/core/res/res/drawable-hdpi/btn_check_on_selected_light.png
new file mode 100644
index 0000000..5df45c7
--- /dev/null
+++ b/core/res/res/drawable-hdpi/btn_check_on_selected_light.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_radio_label_background_light.9.png b/core/res/res/drawable-hdpi/btn_radio_label_background_light.9.png
new file mode 100644
index 0000000..45c5c6a
--- /dev/null
+++ b/core/res/res/drawable-hdpi/btn_radio_label_background_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_radio_off.png b/core/res/res/drawable-hdpi/btn_radio_off.png
index c0b14aa..301c97d 100644
--- a/core/res/res/drawable-hdpi/btn_radio_off.png
+++ b/core/res/res/drawable-hdpi/btn_radio_off.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_radio_off_light.png b/core/res/res/drawable-hdpi/btn_radio_off_light.png
new file mode 100644
index 0000000..657c8e5
--- /dev/null
+++ b/core/res/res/drawable-hdpi/btn_radio_off_light.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_radio_off_pressed.png b/core/res/res/drawable-hdpi/btn_radio_off_pressed.png
index 3189581..5e6ef2b 100644
--- a/core/res/res/drawable-hdpi/btn_radio_off_pressed.png
+++ b/core/res/res/drawable-hdpi/btn_radio_off_pressed.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_radio_off_pressed_light.png b/core/res/res/drawable-hdpi/btn_radio_off_pressed_light.png
new file mode 100644
index 0000000..342bf11
--- /dev/null
+++ b/core/res/res/drawable-hdpi/btn_radio_off_pressed_light.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_radio_off_selected.png b/core/res/res/drawable-hdpi/btn_radio_off_selected.png
index f337703..d11ae85 100644
--- a/core/res/res/drawable-hdpi/btn_radio_off_selected.png
+++ b/core/res/res/drawable-hdpi/btn_radio_off_selected.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_radio_off_selected_light.png b/core/res/res/drawable-hdpi/btn_radio_off_selected_light.png
new file mode 100644
index 0000000..68bd1df
--- /dev/null
+++ b/core/res/res/drawable-hdpi/btn_radio_off_selected_light.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_radio_on.png b/core/res/res/drawable-hdpi/btn_radio_on.png
index c90d2eb..5b0dbe8 100644
--- a/core/res/res/drawable-hdpi/btn_radio_on.png
+++ b/core/res/res/drawable-hdpi/btn_radio_on.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_radio_on_light.png b/core/res/res/drawable-hdpi/btn_radio_on_light.png
new file mode 100644
index 0000000..45ae36b
--- /dev/null
+++ b/core/res/res/drawable-hdpi/btn_radio_on_light.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_radio_on_pressed.png b/core/res/res/drawable-hdpi/btn_radio_on_pressed.png
index d79450b..c3a0d48 100644
--- a/core/res/res/drawable-hdpi/btn_radio_on_pressed.png
+++ b/core/res/res/drawable-hdpi/btn_radio_on_pressed.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_radio_on_pressed_light.png b/core/res/res/drawable-hdpi/btn_radio_on_pressed_light.png
new file mode 100644
index 0000000..ca22358
--- /dev/null
+++ b/core/res/res/drawable-hdpi/btn_radio_on_pressed_light.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_radio_on_selected.png b/core/res/res/drawable-hdpi/btn_radio_on_selected.png
index db50c43..6c05f47 100644
--- a/core/res/res/drawable-hdpi/btn_radio_on_selected.png
+++ b/core/res/res/drawable-hdpi/btn_radio_on_selected.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_radio_on_selected_light.png b/core/res/res/drawable-hdpi/btn_radio_on_selected_light.png
new file mode 100644
index 0000000..a17fa1e
--- /dev/null
+++ b/core/res/res/drawable-hdpi/btn_radio_on_selected_light.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_check_label_background_light.9.png b/core/res/res/drawable-mdpi/btn_check_label_background_light.9.png
new file mode 100644
index 0000000..79367b8
--- /dev/null
+++ b/core/res/res/drawable-mdpi/btn_check_label_background_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_check_off.png b/core/res/res/drawable-mdpi/btn_check_off.png
index 56d3861..5e44c29 100644
--- a/core/res/res/drawable-mdpi/btn_check_off.png
+++ b/core/res/res/drawable-mdpi/btn_check_off.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_check_off_disable.png b/core/res/res/drawable-mdpi/btn_check_off_disable.png
index e012afd..a603fb1 100644
--- a/core/res/res/drawable-mdpi/btn_check_off_disable.png
+++ b/core/res/res/drawable-mdpi/btn_check_off_disable.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_check_off_disable_focused.png b/core/res/res/drawable-mdpi/btn_check_off_disable_focused.png
index 0837bbd..a603fb1 100644
--- a/core/res/res/drawable-mdpi/btn_check_off_disable_focused.png
+++ b/core/res/res/drawable-mdpi/btn_check_off_disable_focused.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_check_off_disable_focused_light.png b/core/res/res/drawable-mdpi/btn_check_off_disable_focused_light.png
new file mode 100644
index 0000000..69e9ff9
--- /dev/null
+++ b/core/res/res/drawable-mdpi/btn_check_off_disable_focused_light.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_check_off_disable_light.png b/core/res/res/drawable-mdpi/btn_check_off_disable_light.png
new file mode 100644
index 0000000..69e9ff9
--- /dev/null
+++ b/core/res/res/drawable-mdpi/btn_check_off_disable_light.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_check_off_light.png b/core/res/res/drawable-mdpi/btn_check_off_light.png
new file mode 100644
index 0000000..5b2ec92
--- /dev/null
+++ b/core/res/res/drawable-mdpi/btn_check_off_light.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_check_off_pressed.png b/core/res/res/drawable-mdpi/btn_check_off_pressed.png
index 984dfd7..611bb1d 100644
--- a/core/res/res/drawable-mdpi/btn_check_off_pressed.png
+++ b/core/res/res/drawable-mdpi/btn_check_off_pressed.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_check_off_pressed_light.png b/core/res/res/drawable-mdpi/btn_check_off_pressed_light.png
new file mode 100644
index 0000000..5a0ea44
--- /dev/null
+++ b/core/res/res/drawable-mdpi/btn_check_off_pressed_light.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_check_off_selected.png b/core/res/res/drawable-mdpi/btn_check_off_selected.png
index 20842d4..aa28df2 100644
--- a/core/res/res/drawable-mdpi/btn_check_off_selected.png
+++ b/core/res/res/drawable-mdpi/btn_check_off_selected.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_check_off_selected_light.png b/core/res/res/drawable-mdpi/btn_check_off_selected_light.png
new file mode 100644
index 0000000..ade1136
--- /dev/null
+++ b/core/res/res/drawable-mdpi/btn_check_off_selected_light.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_check_on.png b/core/res/res/drawable-mdpi/btn_check_on.png
index 791ac1d..130d562 100644
--- a/core/res/res/drawable-mdpi/btn_check_on.png
+++ b/core/res/res/drawable-mdpi/btn_check_on.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_check_on_disable.png b/core/res/res/drawable-mdpi/btn_check_on_disable.png
index 6cb02f3..f19972a 100644
--- a/core/res/res/drawable-mdpi/btn_check_on_disable.png
+++ b/core/res/res/drawable-mdpi/btn_check_on_disable.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_check_on_disable_focused.png b/core/res/res/drawable-mdpi/btn_check_on_disable_focused.png
index 8a73b33..f19972a 100644
--- a/core/res/res/drawable-mdpi/btn_check_on_disable_focused.png
+++ b/core/res/res/drawable-mdpi/btn_check_on_disable_focused.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_check_on_disable_focused_light.png b/core/res/res/drawable-mdpi/btn_check_on_disable_focused_light.png
new file mode 100644
index 0000000..13ef46e
--- /dev/null
+++ b/core/res/res/drawable-mdpi/btn_check_on_disable_focused_light.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_check_on_disable_light.png b/core/res/res/drawable-mdpi/btn_check_on_disable_light.png
new file mode 100644
index 0000000..13ef46e
--- /dev/null
+++ b/core/res/res/drawable-mdpi/btn_check_on_disable_light.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_check_on_light.png b/core/res/res/drawable-mdpi/btn_check_on_light.png
new file mode 100644
index 0000000..6b7808b
--- /dev/null
+++ b/core/res/res/drawable-mdpi/btn_check_on_light.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_check_on_pressed.png b/core/res/res/drawable-mdpi/btn_check_on_pressed.png
index 300d64a..df753f5 100644
--- a/core/res/res/drawable-mdpi/btn_check_on_pressed.png
+++ b/core/res/res/drawable-mdpi/btn_check_on_pressed.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_check_on_pressed_light.png b/core/res/res/drawable-mdpi/btn_check_on_pressed_light.png
new file mode 100644
index 0000000..6a4dd2c
--- /dev/null
+++ b/core/res/res/drawable-mdpi/btn_check_on_pressed_light.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_check_on_selected.png b/core/res/res/drawable-mdpi/btn_check_on_selected.png
index 0b36adb..7586881 100644
--- a/core/res/res/drawable-mdpi/btn_check_on_selected.png
+++ b/core/res/res/drawable-mdpi/btn_check_on_selected.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_check_on_selected_light.png b/core/res/res/drawable-mdpi/btn_check_on_selected_light.png
new file mode 100644
index 0000000..24701ce
--- /dev/null
+++ b/core/res/res/drawable-mdpi/btn_check_on_selected_light.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_radio_label_background_light.9.png b/core/res/res/drawable-mdpi/btn_radio_label_background_light.9.png
new file mode 100644
index 0000000..16e8939
--- /dev/null
+++ b/core/res/res/drawable-mdpi/btn_radio_label_background_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_radio_off.png b/core/res/res/drawable-mdpi/btn_radio_off.png
index 407632b..16c1c6b 100644
--- a/core/res/res/drawable-mdpi/btn_radio_off.png
+++ b/core/res/res/drawable-mdpi/btn_radio_off.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_radio_off_light.png b/core/res/res/drawable-mdpi/btn_radio_off_light.png
new file mode 100644
index 0000000..e8287f3
--- /dev/null
+++ b/core/res/res/drawable-mdpi/btn_radio_off_light.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_radio_off_pressed.png b/core/res/res/drawable-mdpi/btn_radio_off_pressed.png
index d6d8a9d..b25217b 100644
--- a/core/res/res/drawable-mdpi/btn_radio_off_pressed.png
+++ b/core/res/res/drawable-mdpi/btn_radio_off_pressed.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_radio_off_pressed_light.png b/core/res/res/drawable-mdpi/btn_radio_off_pressed_light.png
new file mode 100644
index 0000000..b63b9b0
--- /dev/null
+++ b/core/res/res/drawable-mdpi/btn_radio_off_pressed_light.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_radio_off_selected.png b/core/res/res/drawable-mdpi/btn_radio_off_selected.png
index 53f3e87..bef7572 100644
--- a/core/res/res/drawable-mdpi/btn_radio_off_selected.png
+++ b/core/res/res/drawable-mdpi/btn_radio_off_selected.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_radio_off_selected_light.png b/core/res/res/drawable-mdpi/btn_radio_off_selected_light.png
new file mode 100644
index 0000000..af754e1
--- /dev/null
+++ b/core/res/res/drawable-mdpi/btn_radio_off_selected_light.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_radio_on.png b/core/res/res/drawable-mdpi/btn_radio_on.png
index 25a3ccc..4ed7471 100644
--- a/core/res/res/drawable-mdpi/btn_radio_on.png
+++ b/core/res/res/drawable-mdpi/btn_radio_on.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_radio_on_light.png b/core/res/res/drawable-mdpi/btn_radio_on_light.png
new file mode 100644
index 0000000..62aaa41
--- /dev/null
+++ b/core/res/res/drawable-mdpi/btn_radio_on_light.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_radio_on_pressed.png b/core/res/res/drawable-mdpi/btn_radio_on_pressed.png
index c904a35..7cf91c6 100644
--- a/core/res/res/drawable-mdpi/btn_radio_on_pressed.png
+++ b/core/res/res/drawable-mdpi/btn_radio_on_pressed.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_radio_on_pressed_light.png b/core/res/res/drawable-mdpi/btn_radio_on_pressed_light.png
new file mode 100644
index 0000000..0d93507
--- /dev/null
+++ b/core/res/res/drawable-mdpi/btn_radio_on_pressed_light.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_radio_on_selected.png b/core/res/res/drawable-mdpi/btn_radio_on_selected.png
index 78e1fc0..56f6f5b 100644
--- a/core/res/res/drawable-mdpi/btn_radio_on_selected.png
+++ b/core/res/res/drawable-mdpi/btn_radio_on_selected.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_radio_on_selected_light.png b/core/res/res/drawable-mdpi/btn_radio_on_selected_light.png
new file mode 100644
index 0000000..48dd8e9
--- /dev/null
+++ b/core/res/res/drawable-mdpi/btn_radio_on_selected_light.png
Binary files differ
diff --git a/core/res/res/drawable-nodpi/platlogo.jpg b/core/res/res/drawable-nodpi/platlogo.jpg
new file mode 100644
index 0000000..0e7780c
--- /dev/null
+++ b/core/res/res/drawable-nodpi/platlogo.jpg
Binary files differ
diff --git a/core/res/res/drawable/btn_check_light.xml b/core/res/res/drawable/btn_check_light.xml
new file mode 100644
index 0000000..85f119a
--- /dev/null
+++ b/core/res/res/drawable/btn_check_light.xml
@@ -0,0 +1,65 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2008 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+
+ <!-- Enabled states -->
+
+ <item android:state_checked="true" android:state_window_focused="false"
+ android:state_enabled="true"
+ android:drawable="@drawable/btn_check_on_light" />
+ <item android:state_checked="false" android:state_window_focused="false"
+ android:state_enabled="true"
+ android:drawable="@drawable/btn_check_off_light" />
+
+ <item android:state_checked="true" android:state_pressed="true"
+ android:state_enabled="true"
+ android:drawable="@drawable/btn_check_on_pressed_light" />
+ <item android:state_checked="false" android:state_pressed="true"
+ android:state_enabled="true"
+ android:drawable="@drawable/btn_check_off_pressed_light" />
+
+ <item android:state_checked="true" android:state_focused="true"
+ android:state_enabled="true"
+ android:drawable="@drawable/btn_check_on_selected_light" />
+ <item android:state_checked="false" android:state_focused="true"
+ android:state_enabled="true"
+ android:drawable="@drawable/btn_check_off_selected_light" />
+
+ <item android:state_checked="false"
+ android:state_enabled="true"
+ android:drawable="@drawable/btn_check_off_light" />
+ <item android:state_checked="true"
+ android:state_enabled="true"
+ android:drawable="@drawable/btn_check_on_light" />
+
+
+ <!-- Disabled states -->
+
+ <item android:state_checked="true" android:state_window_focused="false"
+ android:drawable="@drawable/btn_check_on_disable_light" />
+ <item android:state_checked="false" android:state_window_focused="false"
+ android:drawable="@drawable/btn_check_off_disable_light" />
+
+ <item android:state_checked="true" android:state_focused="true"
+ android:drawable="@drawable/btn_check_on_disable_focused_light" />
+ <item android:state_checked="false" android:state_focused="true"
+ android:drawable="@drawable/btn_check_off_disable_focused_light" />
+
+ <item android:state_checked="false" android:drawable="@drawable/btn_check_off_disable_light" />
+ <item android:state_checked="true" android:drawable="@drawable/btn_check_on_disable_light" />
+
+</selector>
diff --git a/core/res/res/drawable/btn_radio_light.xml b/core/res/res/drawable/btn_radio_light.xml
new file mode 100644
index 0000000..51c930b
--- /dev/null
+++ b/core/res/res/drawable/btn_radio_light.xml
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2008 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+ <item android:state_checked="true" android:state_window_focused="false"
+ android:drawable="@drawable/btn_radio_on_light" />
+ <item android:state_checked="false" android:state_window_focused="false"
+ android:drawable="@drawable/btn_radio_off_light" />
+
+ <item android:state_checked="true" android:state_pressed="true"
+ android:drawable="@drawable/btn_radio_on_pressed_light" />
+ <item android:state_checked="false" android:state_pressed="true"
+ android:drawable="@drawable/btn_radio_off_pressed_light" />
+
+ <item android:state_checked="true" android:state_focused="true"
+ android:drawable="@drawable/btn_radio_on_selected_light" />
+ <item android:state_checked="false" android:state_focused="true"
+ android:drawable="@drawable/btn_radio_off_selected_light" />
+
+ <item android:state_checked="false" android:drawable="@drawable/btn_radio_off_light" />
+ <item android:state_checked="true" android:drawable="@drawable/btn_radio_on_light" />
+</selector>
diff --git a/core/res/res/values-xlarge/styles.xml b/core/res/res/values-xlarge/styles.xml
index 40e423e..ff7df7c 100644
--- a/core/res/res/values-xlarge/styles.xml
+++ b/core/res/res/values-xlarge/styles.xml
@@ -19,7 +19,6 @@
<style name="TextAppearance.StatusBar">
<item name="android:textAppearance">?android:attr/textAppearanceSmall</item>
- <item name="android:textColor">?android:attr/textColorPrimaryInverse</item>
</style>
<style name="TextAppearance.StatusBar.Ticker">
</style>
diff --git a/core/res/res/values/styles.xml b/core/res/res/values/styles.xml
index 993048d..e0dc3a9 100644
--- a/core/res/res/values/styles.xml
+++ b/core/res/res/values/styles.xml
@@ -279,11 +279,21 @@
<item name="android:button">@android:drawable/btn_check</item>
</style>
+ <style name="Widget.CompoundButton.CheckBox.Inverse">
+ <item name="android:background">@android:drawable/btn_check_label_background_light</item>
+ <item name="android:button">@android:drawable/btn_check_light</item>
+ </style>
+
<style name="Widget.CompoundButton.RadioButton">
<item name="android:background">@android:drawable/btn_radio_label_background</item>
<item name="android:button">@android:drawable/btn_radio</item>
</style>
+ <style name="Widget.CompoundButton.RadioButton.Inverse">
+ <item name="android:background">@android:drawable/btn_radio_label_background_light</item>
+ <item name="android:button">@android:drawable/btn_radio_light</item>
+ </style>
+
<style name="Widget.CompoundButton.Star">
<item name="android:background">@android:drawable/btn_star_label_background</item>
<item name="android:button">@android:drawable/btn_star</item>
diff --git a/core/res/res/values/themes.xml b/core/res/res/values/themes.xml
index 739912a..3348b4e 100644
--- a/core/res/res/values/themes.xml
+++ b/core/res/res/values/themes.xml
@@ -84,9 +84,9 @@
<item name="searchResultListItemHeight">58dip</item>
<item name="listDivider">@drawable/divider_horizontal_dark</item>
<item name="listSeparatorTextViewStyle">@android:style/Widget.TextView.ListSeparator</item>
-
- <item name="listChoiceIndicatorSingle">@android:drawable/btn_radio</item>
- <item name="listChoiceIndicatorMultiple">@android:drawable/btn_check</item>
+
+ <item name="listChoiceIndicatorSingle">@android:drawable/btn_radio</item>
+ <item name="listChoiceIndicatorMultiple">@android:drawable/btn_check</item>
<item name="expandableListPreferredItemPaddingLeft">40dip</item>
<item name="expandableListPreferredChildPaddingLeft">
@@ -160,8 +160,8 @@
<item name="progressBarStyleSmallTitle">@android:style/Widget.ProgressBar.Small.Title</item>
<item name="progressBarStyleLarge">@android:style/Widget.ProgressBar.Large</item>
<item name="progressBarStyleInverse">@android:style/Widget.ProgressBar.Inverse</item>
- <item name="progressBarStyleSmallInverse">@android:style/Widget.ProgressBar.Small.Inverse</item>
- <item name="progressBarStyleLargeInverse">@android:style/Widget.ProgressBar.Large.Inverse</item>
+ <item name="progressBarStyleSmallInverse">@android:style/Widget.ProgressBar.Small.Inverse</item>
+ <item name="progressBarStyleLargeInverse">@android:style/Widget.ProgressBar.Large.Inverse</item>
<item name="seekBarStyle">@android:style/Widget.SeekBar</item>
<item name="ratingBarStyle">@android:style/Widget.RatingBar</item>
<item name="ratingBarStyleIndicator">@android:style/Widget.RatingBar.Indicator</item>
@@ -253,18 +253,24 @@
<item name="textCheckMark">@android:drawable/indicator_check_mark_light</item>
<item name="textCheckMarkInverse">@android:drawable/indicator_check_mark_dark</item>
+ <!-- List attributes -->
+ <item name="listChoiceIndicatorSingle">@android:drawable/btn_radio_light</item>
+ <item name="listChoiceIndicatorMultiple">@android:drawable/btn_check_light</item>
+
+ <!-- Widget styles -->
+ <item name="checkboxStyle">@android:style/Widget.CompoundButton.CheckBox.Inverse</item>
<item name="gestureOverlayViewStyle">@android:style/Widget.GestureOverlayView.White</item>
<item name="expandableListViewStyle">@android:style/Widget.ExpandableListView.White</item>
<item name="listViewStyle">@android:style/Widget.ListView.White</item>
<item name="listDivider">@drawable/divider_horizontal_bright</item>
<item name="listSeparatorTextViewStyle">@android:style/Widget.TextView.ListSeparator.White</item>
-
<item name="progressBarStyle">@android:style/Widget.ProgressBar.Inverse</item>
- <item name="progressBarStyleSmall">@android:style/Widget.ProgressBar.Small.Inverse</item>
- <item name="progressBarStyleLarge">@android:style/Widget.ProgressBar.Large.Inverse</item>
- <item name="progressBarStyleInverse">@android:style/Widget.ProgressBar</item>
- <item name="progressBarStyleSmallInverse">@android:style/Widget.ProgressBar.Small</item>
- <item name="progressBarStyleLargeInverse">@android:style/Widget.ProgressBar.Large</item>
+ <item name="progressBarStyleSmall">@android:style/Widget.ProgressBar.Small.Inverse</item>
+ <item name="progressBarStyleLarge">@android:style/Widget.ProgressBar.Large.Inverse</item>
+ <item name="progressBarStyleInverse">@android:style/Widget.ProgressBar</item>
+ <item name="progressBarStyleSmallInverse">@android:style/Widget.ProgressBar.Small</item>
+ <item name="progressBarStyleLargeInverse">@android:style/Widget.ProgressBar.Large</item>
+ <item name="radioButtonStyle">@android:style/Widget.CompoundButton.RadioButton.Inverse</item>
</style>
<!-- Variant of the light theme with no title bar -->
diff --git a/graphics/java/android/renderscript/Matrix4f.java b/graphics/java/android/renderscript/Matrix4f.java
index e854cd9..5ffc21a 100644
--- a/graphics/java/android/renderscript/Matrix4f.java
+++ b/graphics/java/android/renderscript/Matrix4f.java
@@ -179,6 +179,76 @@ public class Matrix4f {
tmp.loadTranslate(x, y, z);
multiply(tmp);
}
+ private float computeCofactor(int i, int j) {
+ int c0 = (i+1) % 4;
+ int c1 = (i+2) % 4;
+ int c2 = (i+3) % 4;
+ int r0 = (j+1) % 4;
+ int r1 = (j+2) % 4;
+ int r2 = (j+3) % 4;
+
+ float minor = (mMat[c0 + 4*r0] * (mMat[c1 + 4*r1] * mMat[c2 + 4*r2] -
+ mMat[c1 + 4*r2] * mMat[c2 + 4*r1]))
+ - (mMat[c0 + 4*r1] * (mMat[c1 + 4*r0] * mMat[c2 + 4*r2] -
+ mMat[c1 + 4*r2] * mMat[c2 + 4*r0]))
+ + (mMat[c0 + 4*r2] * (mMat[c1 + 4*r0] * mMat[c2 + 4*r1] -
+ mMat[c1 + 4*r1] * mMat[c2 + 4*r0]));
+
+ float cofactor = ((i+j) & 1) != 0 ? -minor : minor;
+ return cofactor;
+ }
+
+ public boolean inverse() {
+
+ Matrix4f result = new Matrix4f();
+
+ for (int i = 0; i < 4; ++i) {
+ for (int j = 0; j < 4; ++j) {
+ result.mMat[4*i + j] = computeCofactor(i, j);
+ }
+ }
+
+ // Dot product of 0th column of source and 0th row of result
+ float det = mMat[0]*result.mMat[0] + mMat[4]*result.mMat[1] +
+ mMat[8]*result.mMat[2] + mMat[12]*result.mMat[3];
+
+ if (Math.abs(det) < 1e-6) {
+ return false;
+ }
+
+ det = 1.0f / det;
+ for (int i = 0; i < 16; ++i) {
+ mMat[i] = result.mMat[i] * det;
+ }
+
+ return true;
+ }
+
+ public boolean inverseTranspose() {
+
+ Matrix4f result = new Matrix4f();
+
+ for (int i = 0; i < 4; ++i) {
+ for (int j = 0; j < 4; ++j) {
+ result.mMat[4*j + i] = computeCofactor(i, j);
+ }
+ }
+
+ float det = mMat[0]*result.mMat[0] + mMat[4]*result.mMat[4] +
+ mMat[8]*result.mMat[8] + mMat[12]*result.mMat[12];
+
+ if (Math.abs(det) < 1e-6) {
+ return false;
+ }
+
+ det = 1.0f / det;
+ for (int i = 0; i < 16; ++i) {
+ mMat[i] = result.mMat[i] * det;
+ }
+
+ return true;
+ }
+
public void transpose() {
for(int i = 0; i < 3; ++i) {
for(int j = i + 1; j < 4; ++j) {
diff --git a/include/android_runtime/android_content_res_Configuration.h b/include/android_runtime/android_content_res_Configuration.h
new file mode 100644
index 0000000..2f5a982
--- /dev/null
+++ b/include/android_runtime/android_content_res_Configuration.h
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef _ANDROID_CONTENT_RES_CONFIGURATION_H
+#define _ANDROID_CONTENT_RES_CONFIGURATION_H
+
+#include <utils/ResourceTypes.h>
+#include <android/configuration.h>
+
+#include "jni.h"
+
+struct AConfiguration : android::ResTable_config {
+};
+
+namespace android {
+
+extern void android_Configuration_getFromJava(
+ JNIEnv* env, jobject clazz, struct AConfiguration* out);
+
+} // namespace android
+
+
+#endif // _ANDROID_CONTENT_RES_CONFIGURATION_H
diff --git a/include/utils/AssetManager.h b/include/utils/AssetManager.h
index 97694ff..9e2bf37 100644
--- a/include/utils/AssetManager.h
+++ b/include/utils/AssetManager.h
@@ -129,6 +129,8 @@ public:
*/
void setConfiguration(const ResTable_config& config, const char* locale = NULL);
+ void getConfiguration(ResTable_config* outConfig) const;
+
typedef Asset::AccessMode AccessMode; // typing shortcut
/*
diff --git a/include/utils/ObbFile.h b/include/utils/ObbFile.h
index 075927c..d2ca82e 100644
--- a/include/utils/ObbFile.h
+++ b/include/utils/ObbFile.h
@@ -35,6 +35,8 @@ public:
bool readFrom(int fd);
bool writeTo(const char* filename);
bool writeTo(int fd);
+ bool removeFrom(const char* filename);
+ bool removeFrom(int fd);
const char* getFileName() const {
return mFileName;
@@ -78,6 +80,8 @@ private:
size_t mFileSize;
+ size_t mFooterStart;
+
unsigned char* mReadBuf;
bool parseObbFile(int fd);
diff --git a/include/utils/ResourceTypes.h b/include/utils/ResourceTypes.h
index c7d9ff1..da86da4 100644
--- a/include/utils/ResourceTypes.h
+++ b/include/utils/ResourceTypes.h
@@ -31,6 +31,8 @@
#include <stdint.h>
#include <sys/types.h>
+#include <android/configuration.h>
+
namespace android {
/** ********************************************************************
@@ -822,25 +824,25 @@ struct ResTable_config
};
enum {
- ORIENTATION_ANY = 0x0000,
- ORIENTATION_PORT = 0x0001,
- ORIENTATION_LAND = 0x0002,
- ORIENTATION_SQUARE = 0x0003,
+ ORIENTATION_ANY = ACONFIGURATION_ORIENTATION_ANY,
+ ORIENTATION_PORT = ACONFIGURATION_ORIENTATION_PORT,
+ ORIENTATION_LAND = ACONFIGURATION_ORIENTATION_LAND,
+ ORIENTATION_SQUARE = ACONFIGURATION_ORIENTATION_SQUARE,
};
enum {
- TOUCHSCREEN_ANY = 0x0000,
- TOUCHSCREEN_NOTOUCH = 0x0001,
- TOUCHSCREEN_STYLUS = 0x0002,
- TOUCHSCREEN_FINGER = 0x0003,
+ TOUCHSCREEN_ANY = ACONFIGURATION_TOUCHSCREEN_ANY,
+ TOUCHSCREEN_NOTOUCH = ACONFIGURATION_TOUCHSCREEN_NOTOUCH,
+ TOUCHSCREEN_STYLUS = ACONFIGURATION_TOUCHSCREEN_STYLUS,
+ TOUCHSCREEN_FINGER = ACONFIGURATION_TOUCHSCREEN_FINGER,
};
enum {
- DENSITY_DEFAULT = 0,
- DENSITY_LOW = 120,
- DENSITY_MEDIUM = 160,
- DENSITY_HIGH = 240,
- DENSITY_NONE = 0xffff
+ DENSITY_DEFAULT = ACONFIGURATION_DENSITY_DEFAULT,
+ DENSITY_LOW = ACONFIGURATION_DENSITY_LOW,
+ DENSITY_MEDIUM = ACONFIGURATION_DENSITY_MEDIUM,
+ DENSITY_HIGH = ACONFIGURATION_DENSITY_HIGH,
+ DENSITY_NONE = ACONFIGURATION_DENSITY_NONE
};
union {
@@ -853,33 +855,34 @@ struct ResTable_config
};
enum {
- KEYBOARD_ANY = 0x0000,
- KEYBOARD_NOKEYS = 0x0001,
- KEYBOARD_QWERTY = 0x0002,
- KEYBOARD_12KEY = 0x0003,
+ KEYBOARD_ANY = ACONFIGURATION_KEYBOARD_ANY,
+ KEYBOARD_NOKEYS = ACONFIGURATION_KEYBOARD_NOKEYS,
+ KEYBOARD_QWERTY = ACONFIGURATION_KEYBOARD_QWERTY,
+ KEYBOARD_12KEY = ACONFIGURATION_KEYBOARD_12KEY,
};
enum {
- NAVIGATION_ANY = 0x0000,
- NAVIGATION_NONAV = 0x0001,
- NAVIGATION_DPAD = 0x0002,
- NAVIGATION_TRACKBALL = 0x0003,
- NAVIGATION_WHEEL = 0x0004,
+ NAVIGATION_ANY = ACONFIGURATION_NAVIGATION_ANY,
+ NAVIGATION_NONAV = ACONFIGURATION_NAVIGATION_NONAV,
+ NAVIGATION_DPAD = ACONFIGURATION_NAVIGATION_DPAD,
+ NAVIGATION_TRACKBALL = ACONFIGURATION_NAVIGATION_TRACKBALL,
+ NAVIGATION_WHEEL = ACONFIGURATION_NAVIGATION_WHEEL,
};
enum {
MASK_KEYSHIDDEN = 0x0003,
- KEYSHIDDEN_ANY = 0x0000,
- KEYSHIDDEN_NO = 0x0001,
- KEYSHIDDEN_YES = 0x0002,
- KEYSHIDDEN_SOFT = 0x0003,
+ KEYSHIDDEN_ANY = ACONFIGURATION_KEYSHIDDEN_ANY,
+ KEYSHIDDEN_NO = ACONFIGURATION_KEYSHIDDEN_NO,
+ KEYSHIDDEN_YES = ACONFIGURATION_KEYSHIDDEN_YES,
+ KEYSHIDDEN_SOFT = ACONFIGURATION_KEYSHIDDEN_SOFT,
};
enum {
MASK_NAVHIDDEN = 0x000c,
- NAVHIDDEN_ANY = 0x0000,
- NAVHIDDEN_NO = 0x0004,
- NAVHIDDEN_YES = 0x0008,
+ SHIFT_NAVHIDDEN = 2,
+ NAVHIDDEN_ANY = ACONFIGURATION_NAVHIDDEN_ANY << SHIFT_NAVHIDDEN,
+ NAVHIDDEN_NO = ACONFIGURATION_NAVHIDDEN_NO << SHIFT_NAVHIDDEN,
+ NAVHIDDEN_YES = ACONFIGURATION_NAVHIDDEN_YES << SHIFT_NAVHIDDEN,
};
union {
@@ -929,32 +932,34 @@ struct ResTable_config
enum {
// screenLayout bits for screen size class.
MASK_SCREENSIZE = 0x0f,
- SCREENSIZE_ANY = 0x00,
- SCREENSIZE_SMALL = 0x01,
- SCREENSIZE_NORMAL = 0x02,
- SCREENSIZE_LARGE = 0x03,
- SCREENSIZE_XLARGE = 0x04,
+ SCREENSIZE_ANY = ACONFIGURATION_SCREENSIZE_ANY,
+ SCREENSIZE_SMALL = ACONFIGURATION_SCREENSIZE_SMALL,
+ SCREENSIZE_NORMAL = ACONFIGURATION_SCREENSIZE_NORMAL,
+ SCREENSIZE_LARGE = ACONFIGURATION_SCREENSIZE_LARGE,
+ SCREENSIZE_XLARGE = ACONFIGURATION_SCREENSIZE_XLARGE,
// screenLayout bits for wide/long screen variation.
MASK_SCREENLONG = 0x30,
- SCREENLONG_ANY = 0x00,
- SCREENLONG_NO = 0x10,
- SCREENLONG_YES = 0x20,
+ SHIFT_SCREENLONG = 4,
+ SCREENLONG_ANY = ACONFIGURATION_SCREENLONG_ANY << SHIFT_SCREENLONG,
+ SCREENLONG_NO = ACONFIGURATION_SCREENLONG_NO << SHIFT_SCREENLONG,
+ SCREENLONG_YES = ACONFIGURATION_SCREENLONG_YES << SHIFT_SCREENLONG,
};
enum {
// uiMode bits for the mode type.
MASK_UI_MODE_TYPE = 0x0f,
- UI_MODE_TYPE_ANY = 0x00,
- UI_MODE_TYPE_NORMAL = 0x01,
- UI_MODE_TYPE_DESK = 0x02,
- UI_MODE_TYPE_CAR = 0x03,
+ UI_MODE_TYPE_ANY = ACONFIGURATION_UI_MODE_TYPE_ANY,
+ UI_MODE_TYPE_NORMAL = ACONFIGURATION_UI_MODE_TYPE_NORMAL,
+ UI_MODE_TYPE_DESK = ACONFIGURATION_UI_MODE_TYPE_DESK,
+ UI_MODE_TYPE_CAR = ACONFIGURATION_UI_MODE_TYPE_CAR,
// uiMode bits for the night switch.
MASK_UI_MODE_NIGHT = 0x30,
- UI_MODE_NIGHT_ANY = 0x00,
- UI_MODE_NIGHT_NO = 0x10,
- UI_MODE_NIGHT_YES = 0x20,
+ SHIFT_UI_MODE_NIGHT = 4,
+ UI_MODE_NIGHT_ANY = ACONFIGURATION_UI_MODE_NIGHT_ANY << SHIFT_UI_MODE_NIGHT,
+ UI_MODE_NIGHT_NO = ACONFIGURATION_UI_MODE_NIGHT_NO << SHIFT_UI_MODE_NIGHT,
+ UI_MODE_NIGHT_YES = ACONFIGURATION_UI_MODE_NIGHT_YES << SHIFT_UI_MODE_NIGHT,
};
union {
@@ -1023,19 +1028,19 @@ struct ResTable_config
// match the corresponding ones in android.content.pm.ActivityInfo and
// attrs_manifest.xml.
enum {
- CONFIG_MCC = 0x0001,
- CONFIG_MNC = 0x0002,
- CONFIG_LOCALE = 0x0004,
- CONFIG_TOUCHSCREEN = 0x0008,
- CONFIG_KEYBOARD = 0x0010,
- CONFIG_KEYBOARD_HIDDEN = 0x0020,
- CONFIG_NAVIGATION = 0x0040,
- CONFIG_ORIENTATION = 0x0080,
- CONFIG_DENSITY = 0x0100,
- CONFIG_SCREEN_SIZE = 0x0200,
- CONFIG_VERSION = 0x0400,
- CONFIG_SCREEN_LAYOUT = 0x0800,
- CONFIG_UI_MODE = 0x1000
+ CONFIG_MCC = ACONFIGURATION_MCC,
+ CONFIG_MNC = ACONFIGURATION_MCC,
+ CONFIG_LOCALE = ACONFIGURATION_LOCALE,
+ CONFIG_TOUCHSCREEN = ACONFIGURATION_TOUCHSCREEN,
+ CONFIG_KEYBOARD = ACONFIGURATION_KEYBOARD,
+ CONFIG_KEYBOARD_HIDDEN = ACONFIGURATION_KEYBOARD_HIDDEN,
+ CONFIG_NAVIGATION = ACONFIGURATION_NAVIGATION,
+ CONFIG_ORIENTATION = ACONFIGURATION_ORIENTATION,
+ CONFIG_DENSITY = ACONFIGURATION_DENSITY,
+ CONFIG_SCREEN_SIZE = ACONFIGURATION_SCREEN_SIZE,
+ CONFIG_VERSION = ACONFIGURATION_VERSION,
+ CONFIG_SCREEN_LAYOUT = ACONFIGURATION_SCREEN_LAYOUT,
+ CONFIG_UI_MODE = ACONFIGURATION_UI_MODE
};
// Compare two configuration, returning CONFIG_* flags set for each value
diff --git a/libs/rs/rsAllocation.cpp b/libs/rs/rsAllocation.cpp
index d62fa55..7d31bd6 100644
--- a/libs/rs/rsAllocation.cpp
+++ b/libs/rs/rsAllocation.cpp
@@ -391,7 +391,8 @@ Allocation *Allocation::createFromStream(Context *rsc, IStream *stream)
alloc->setName(name.string(), name.size());
// Read in all of our allocation data
- stream->loadByteArray(alloc->getPtr(), dataSize);
+ alloc->data(stream->getPtr() + stream->getPos(), dataSize);
+ stream->reset(stream->getPos() + dataSize);
return alloc;
}
diff --git a/libs/rs/rsElement.cpp b/libs/rs/rsElement.cpp
index 05902f9..5dee1fb 100644
--- a/libs/rs/rsElement.cpp
+++ b/libs/rs/rsElement.cpp
@@ -114,6 +114,7 @@ Element *Element::createFromStream(Context *rsc, IStream *stream)
Element *elem = new Element(rsc);
elem->mComponent.loadFromStream(stream);
elem->mBits = elem->mComponent.getBits();
+ elem->mHasReference = elem->mComponent.isReference();
elem->mFieldCount = stream->loadU32();
if(elem->mFieldCount) {
@@ -125,6 +126,10 @@ Element *Element::createFromStream(Context *rsc, IStream *stream)
elem->mFields[ct].e.set(fieldElem);
elem->mFields[ct].offsetBits = offset;
offset += fieldElem->getSizeBits();
+ // Check if our sub-elements have references
+ if(fieldElem->mHasReference) {
+ elem->mHasReference = true;
+ }
}
}
diff --git a/libs/rs/scriptc/rs_core.rsh b/libs/rs/scriptc/rs_core.rsh
index 85f3b25..aa9aebc 100644
--- a/libs/rs/scriptc/rs_core.rsh
+++ b/libs/rs/scriptc/rs_core.rsh
@@ -602,6 +602,171 @@ rsMatrixTranspose(rs_matrix2x2 *m) {
m->m[2] = temp;
}
+/////////////////////////////////////////////////////
+// quaternion ops
+/////////////////////////////////////////////////////
+
+static void __attribute__((overloadable))
+rsQuaternionSet(rs_quaternion *q, float w, float x, float y, float z) {
+ q->w = w;
+ q->x = x;
+ q->y = y;
+ q->z = z;
+}
+
+static void __attribute__((overloadable))
+rsQuaternionSet(rs_quaternion *q, const rs_quaternion *rhs) {
+ q->w = rhs->w;
+ q->x = rhs->x;
+ q->y = rhs->y;
+ q->z = rhs->z;
+}
+
+static void __attribute__((overloadable))
+rsQuaternionMultiply(rs_quaternion *q, float s) {
+ q->w *= s;
+ q->x *= s;
+ q->y *= s;
+ q->z *= s;
+}
+
+static void __attribute__((overloadable))
+rsQuaternionMultiply(rs_quaternion *q, const rs_quaternion *rhs) {
+ q->w = -q->x*rhs->x - q->y*rhs->y - q->z*rhs->z + q->w*rhs->w;
+ q->x = q->x*rhs->w + q->y*rhs->z - q->z*rhs->y + q->w*rhs->x;
+ q->y = -q->x*rhs->z + q->y*rhs->w + q->z*rhs->z + q->w*rhs->y;
+ q->z = q->x*rhs->y - q->y*rhs->x + q->z*rhs->w + q->w*rhs->z;
+}
+
+static void
+rsQuaternionAdd(rs_quaternion *q, const rs_quaternion *rhs) {
+ q->w *= rhs->w;
+ q->x *= rhs->x;
+ q->y *= rhs->y;
+ q->z *= rhs->z;
+}
+
+static void
+rsQuaternionLoadRotateUnit(rs_quaternion *q, float rot, float x, float y, float z) {
+ rot *= (float)(M_PI / 180.0f) * 0.5f;
+ float c = cos(rot);
+ float s = sin(rot);
+
+ q->w = c;
+ q->x = x * s;
+ q->y = y * s;
+ q->z = z * s;
+}
+
+static void
+rsQuaternionLoadRotate(rs_quaternion *q, float rot, float x, float y, float z) {
+ const float len = x*x + y*y + z*z;
+ if (len != 1) {
+ const float recipLen = 1.f / sqrt(len);
+ x *= recipLen;
+ y *= recipLen;
+ z *= recipLen;
+ }
+ rsQuaternionLoadRotateUnit(q, rot, x, y, z);
+}
+
+static void
+rsQuaternionConjugate(rs_quaternion *q) {
+ q->x = -q->x;
+ q->y = -q->y;
+ q->z = -q->z;
+}
+
+static float
+rsQuaternionDot(const rs_quaternion *q0, const rs_quaternion *q1) {
+ return q0->w*q1->w + q0->x*q1->x + q0->y*q1->y + q0->z*q1->z;
+}
+
+static void
+rsQuaternionNormalize(rs_quaternion *q) {
+ const float len = rsQuaternionDot(q, q);
+ if (len != 1) {
+ const float recipLen = 1.f / sqrt(len);
+ rsQuaternionMultiply(q, recipLen);
+ }
+}
+
+static void
+rsQuaternionSlerp(rs_quaternion *q, const rs_quaternion *q0, const rs_quaternion *q1, float t) {
+ if(t <= 0.0f) {
+ rsQuaternionSet(q, q0);
+ return;
+ }
+ if(t >= 1.0f) {
+ rsQuaternionSet(q, q1);
+ return;
+ }
+
+ rs_quaternion tempq0, tempq1;
+ rsQuaternionSet(&tempq0, q0);
+ rsQuaternionSet(&tempq1, q1);
+
+ float angle = rsQuaternionDot(q0, q1);
+ if(angle < 0) {
+ rsQuaternionMultiply(&tempq0, -1.0f);
+ angle *= -1.0f;
+ }
+
+ float scale, invScale;
+ if (angle + 1.0f > 0.05f) {
+ if (1.0f - angle >= 0.05f) {
+ float theta = acos(angle);
+ float invSinTheta = 1.0f / sin(theta);
+ scale = sin(theta * (1.0f - t)) * invSinTheta;
+ invScale = sin(theta * t) * invSinTheta;
+ }
+ else {
+ scale = 1.0f - t;
+ invScale = t;
+ }
+ }
+ else {
+ rsQuaternionSet(&tempq1, tempq0.z, -tempq0.y, tempq0.x, -tempq0.w);
+ scale = sin(M_PI * (0.5f - t));
+ invScale = sin(M_PI * t);
+ }
+
+ rsQuaternionSet(q, tempq0.w*scale + tempq1.w*invScale, tempq0.x*scale + tempq1.x*invScale,
+ tempq0.y*scale + tempq1.y*invScale, tempq0.z*scale + tempq1.z*invScale);
+}
+
+static void rsQuaternionGetMatrixUnit(rs_matrix4x4 *m, const rs_quaternion *q) {
+ float x2 = 2.0f * q->x * q->x;
+ float y2 = 2.0f * q->y * q->y;
+ float z2 = 2.0f * q->z * q->z;
+ float xy = 2.0f * q->x * q->y;
+ float wz = 2.0f * q->w * q->z;
+ float xz = 2.0f * q->x * q->z;
+ float wy = 2.0f * q->w * q->y;
+ float wx = 2.0f * q->w * q->x;
+ float yz = 2.0f * q->y * q->z;
+
+ m->m[0] = 1.0f - y2 - z2;
+ m->m[1] = xy - wz;
+ m->m[2] = xz + wy;
+ m->m[3] = 0.0f;
+
+ m->m[4] = xy + wz;
+ m->m[5] = 1.0f - x2 - z2;
+ m->m[6] = yz - wx;
+ m->m[7] = 0.0f;
+
+ m->m[8] = xz - wy;
+ m->m[9] = yz - wx;
+ m->m[10] = 1.0f - x2 - y2;
+ m->m[11] = 0.0f;
+
+ m->m[12] = 0.0f;
+ m->m[13] = 0.0f;
+ m->m[14] = 0.0f;
+ m->m[15] = 1.0f;
+}
+
/////////////////////////////////////////////////////
// int ops
diff --git a/libs/rs/scriptc/rs_types.rsh b/libs/rs/scriptc/rs_types.rsh
index 69e1aed..ddae7eb 100644
--- a/libs/rs/scriptc/rs_types.rsh
+++ b/libs/rs/scriptc/rs_types.rsh
@@ -67,6 +67,10 @@ typedef struct {
float m[4];
} rs_matrix2x2;
+typedef struct {
+ float w, x, y, z;
+} rs_quaternion;
+
#define RS_PACKED __attribute__((packed, aligned(4)))
diff --git a/libs/utils/AssetManager.cpp b/libs/utils/AssetManager.cpp
index 60a0d82..e09e755 100644
--- a/libs/utils/AssetManager.cpp
+++ b/libs/utils/AssetManager.cpp
@@ -232,6 +232,12 @@ void AssetManager::setConfiguration(const ResTable_config& config, const char* l
}
}
+void AssetManager::getConfiguration(ResTable_config* outConfig) const
+{
+ AutoMutex _l(mLock);
+ *outConfig = *mConfig;
+}
+
/*
* Open an asset.
*
diff --git a/libs/utils/ObbFile.cpp b/libs/utils/ObbFile.cpp
index fe49300..adedf0c 100644
--- a/libs/utils/ObbFile.cpp
+++ b/libs/utils/ObbFile.cpp
@@ -156,9 +156,9 @@ bool ObbFile::parseObbFile(int fd)
return false;
}
- if (footerSize < kFooterMinSize) {
- LOGW("claimed footer size is too small (%08zx; minimum size is 0x%x)\n",
- footerSize, kFooterMinSize);
+ if (footerSize < (kFooterMinSize - kFooterTagSize)) {
+ LOGW("claimed footer size is too small (0x%zx; minimum size is 0x%x)\n",
+ footerSize, kFooterMinSize - kFooterTagSize);
return false;
}
}
@@ -169,6 +169,8 @@ bool ObbFile::parseObbFile(int fd)
return false;
}
+ mFooterStart = fileOffset;
+
char* scanBuf = (char*)malloc(footerSize);
if (scanBuf == NULL) {
LOGW("couldn't allocate scanBuf: %s\n", strerror(errno));
@@ -293,4 +295,38 @@ bool ObbFile::writeTo(int fd)
return true;
}
+bool ObbFile::removeFrom(const char* filename)
+{
+ int fd;
+ bool success = false;
+
+ fd = ::open(filename, O_RDWR);
+ if (fd < 0) {
+ goto out;
+ }
+ success = removeFrom(fd);
+ close(fd);
+
+out:
+ if (!success) {
+ LOGW("failed to remove signature from %s: %s\n", filename, strerror(errno));
+ }
+ return success;
+}
+
+bool ObbFile::removeFrom(int fd)
+{
+ if (fd < 0) {
+ return false;
+ }
+
+ if (!readFrom(fd)) {
+ return false;
+ }
+
+ ftruncate(fd, mFooterStart);
+
+ return true;
+}
+
}
diff --git a/media/libstagefright/CameraSource.cpp b/media/libstagefright/CameraSource.cpp
index 5e7dd5c..9ccd140 100644
--- a/media/libstagefright/CameraSource.cpp
+++ b/media/libstagefright/CameraSource.cpp
@@ -260,6 +260,7 @@ void CameraSource::releaseOneRecordingFrame(const sp<IMemory>& frame) {
void CameraSource::signalBufferReturned(MediaBuffer *buffer) {
LOGV("signalBufferReturned: %p", buffer->data());
+ Mutex::Autolock autoLock(mLock);
for (List<sp<IMemory> >::iterator it = mFramesBeingEncoded.begin();
it != mFramesBeingEncoded.end(); ++it) {
if ((*it)->pointer() == buffer->data()) {
@@ -327,6 +328,7 @@ status_t CameraSource::read(
(*buffer)->setObserver(this);
(*buffer)->add_ref();
(*buffer)->meta_data()->setInt64(kKeyTime, frameTime);
+
return OK;
}
}
diff --git a/media/libstagefright/CameraSourceTimeLapse.cpp b/media/libstagefright/CameraSourceTimeLapse.cpp
index 1fd256a..ba99501 100644
--- a/media/libstagefright/CameraSourceTimeLapse.cpp
+++ b/media/libstagefright/CameraSourceTimeLapse.cpp
@@ -187,6 +187,7 @@ void CameraSourceTimeLapse::stopCameraRecording() {
if (mUseStillCameraForTimeLapse) {
void *dummy;
pthread_join(mThreadTimeLapse, &dummy);
+ CHECK_EQ(OK, mCamera->startPreview());
} else {
mCamera->stopRecording();
}
diff --git a/native/android/Android.mk b/native/android/Android.mk
index 950a1e9..bd2b27a 100644
--- a/native/android/Android.mk
+++ b/native/android/Android.mk
@@ -7,6 +7,7 @@ include $(CLEAR_VARS)
#
LOCAL_SRC_FILES:= \
asset_manager.cpp \
+ configuration.cpp \
input.cpp \
looper.cpp \
native_activity.cpp \
diff --git a/native/android/asset_manager.cpp b/native/android/asset_manager.cpp
index 36c381e..3f7c1b6 100644
--- a/native/android/asset_manager.cpp
+++ b/native/android/asset_manager.cpp
@@ -17,7 +17,7 @@
#define LOG_TAG "NAsset"
#include <utils/Log.h>
-#include <android/asset_manager.h>
+#include <android/asset_manager_jni.h>
#include <utils/AssetManager.h>
#include <utils/AssetDir.h>
#include <utils/Asset.h>
diff --git a/native/android/configuration.cpp b/native/android/configuration.cpp
new file mode 100644
index 0000000..d76164f
--- /dev/null
+++ b/native/android/configuration.cpp
@@ -0,0 +1,202 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "Configuration"
+#include <utils/Log.h>
+
+#include <utils/AssetManager.h>
+
+#include <android_runtime/android_content_res_Configuration.h>
+
+using namespace android;
+
+AConfiguration* AConfiguration_new() {
+ AConfiguration* config = new AConfiguration;
+ memset(config, 0, sizeof(AConfiguration));
+ return config;
+}
+
+void AConfiguration_delete(AConfiguration* config) {
+ delete config;
+}
+
+void AConfiguration_fromAssetManager(AConfiguration* out, AAssetManager* am) {
+ ((AssetManager*)am)->getConfiguration(out);
+}
+
+void AConfiguration_copy(AConfiguration* dest, AConfiguration* src) {
+ *dest = *src;
+}
+
+int32_t AConfiguration_getMcc(AConfiguration* config) {
+ return config->mcc;
+}
+
+int32_t AConfiguration_getMnc(AConfiguration* config) {
+ return config->mnc;
+}
+
+void AConfiguration_getLanguage(AConfiguration* config, char* outLanguage) {
+ outLanguage[0] = config->language[0];
+ outLanguage[1] = config->language[1];
+}
+
+void AConfiguration_getCountry(AConfiguration* config, char* outCountry) {
+ outCountry[0] = config->country[0];
+ outCountry[1] = config->country[1];
+}
+
+int32_t AConfiguration_getOrientation(AConfiguration* config) {
+ return config->orientation;
+}
+
+int32_t AConfiguration_getTouchscreen(AConfiguration* config) {
+ return config->touchscreen;
+}
+
+int32_t AConfiguration_getDensity(AConfiguration* config) {
+ return config->density;
+}
+
+int32_t AConfiguration_getKeyboard(AConfiguration* config) {
+ return config->keyboard;
+}
+
+int32_t AConfiguration_getNavigation(AConfiguration* config) {
+ return config->navigation;
+}
+
+int32_t AConfiguration_getKeysHidden(AConfiguration* config) {
+ return config->inputFlags&ResTable_config::MASK_KEYSHIDDEN;
+}
+
+int32_t AConfiguration_getNavHidden(AConfiguration* config) {
+ return (config->inputFlags&ResTable_config::MASK_NAVHIDDEN)
+ >> ResTable_config::SHIFT_NAVHIDDEN;
+}
+
+int32_t AConfiguration_getSdkVersion(AConfiguration* config) {
+ return config->sdkVersion;
+}
+
+int32_t AConfiguration_getScreenSize(AConfiguration* config) {
+ return config->screenLayout&ResTable_config::MASK_SCREENSIZE;
+}
+
+int32_t AConfiguration_getScreenLong(AConfiguration* config) {
+ return (config->screenLayout&ResTable_config::MASK_SCREENLONG)
+ >> ResTable_config::SHIFT_SCREENLONG;
+}
+
+int32_t AConfiguration_getUiModeType(AConfiguration* config) {
+ return config->uiMode&ResTable_config::MASK_UI_MODE_TYPE;
+}
+
+int32_t AConfiguration_getUiModeNight(AConfiguration* config) {
+ return (config->uiMode&ResTable_config::MASK_UI_MODE_NIGHT)
+ >> ResTable_config::SHIFT_UI_MODE_NIGHT;
+
+}
+
+// ----------------------------------------------------------------------
+
+void AConfiguration_setMcc(AConfiguration* config, int32_t mcc) {
+ config->mcc = mcc;
+}
+
+void AConfiguration_setMnc(AConfiguration* config, int32_t mnc) {
+ config->mnc = mnc;
+}
+
+void AConfiguration_setLanguage(AConfiguration* config, const char* language) {
+ config->language[0] = language[0];
+ config->language[1] = language[1];
+}
+
+void AConfiguration_setCountry(AConfiguration* config, const char* country) {
+ config->country[0] = country[0];
+ config->country[1] = country[1];
+}
+
+void AConfiguration_setOrientation(AConfiguration* config, int32_t orientation) {
+ config->orientation = orientation;
+}
+
+void AConfiguration_setTouchscreen(AConfiguration* config, int32_t touchscreen) {
+ config->touchscreen = touchscreen;
+}
+
+void AConfiguration_setDensity(AConfiguration* config, int32_t density) {
+ config->density = density;
+}
+
+void AConfiguration_setKeyboard(AConfiguration* config, int32_t keyboard) {
+ config->keyboard = keyboard;
+}
+
+void AConfiguration_setNavigation(AConfiguration* config, int32_t navigation) {
+ config->navigation = navigation;
+}
+
+void AConfiguration_setKeysHidden(AConfiguration* config, int32_t keysHidden) {
+ config->inputFlags = (config->inputFlags&~ResTable_config::MASK_KEYSHIDDEN)
+ | (keysHidden&ResTable_config::MASK_KEYSHIDDEN);
+}
+
+void AConfiguration_setNavHidden(AConfiguration* config, int32_t navHidden) {
+ config->inputFlags = (config->inputFlags&~ResTable_config::MASK_NAVHIDDEN)
+ | ((navHidden<<ResTable_config::SHIFT_NAVHIDDEN)&ResTable_config::MASK_NAVHIDDEN);
+}
+
+void AConfiguration_setSdkVersion(AConfiguration* config, int32_t sdkVersion) {
+ config->sdkVersion = sdkVersion;
+}
+
+void AConfiguration_setScreenSize(AConfiguration* config, int32_t screenSize) {
+ config->screenLayout = (config->screenLayout&~ResTable_config::MASK_SCREENSIZE)
+ | (screenSize&ResTable_config::MASK_SCREENSIZE);
+}
+
+void AConfiguration_setScreenLong(AConfiguration* config, int32_t screenLong) {
+ config->screenLayout = (config->screenLayout&~ResTable_config::MASK_SCREENLONG)
+ | ((screenLong<<ResTable_config::SHIFT_SCREENLONG)&ResTable_config::MASK_SCREENLONG);
+}
+
+void AConfiguration_setUiModeType(AConfiguration* config, int32_t uiModeType) {
+ config->uiMode = (config->uiMode&~ResTable_config::MASK_UI_MODE_TYPE)
+ | (uiModeType&ResTable_config::MASK_UI_MODE_TYPE);
+}
+
+void AConfiguration_setUiModeNight(AConfiguration* config, int32_t uiModeNight) {
+ config->uiMode = (config->uiMode&~ResTable_config::MASK_UI_MODE_NIGHT)
+ | ((uiModeNight<<ResTable_config::SHIFT_UI_MODE_NIGHT)&ResTable_config::MASK_UI_MODE_NIGHT);
+
+}
+
+// ----------------------------------------------------------------------
+
+int32_t AConfiguration_diff(AConfiguration* config1, AConfiguration* config2) {
+ return (config1->diff(*config2));
+}
+
+int32_t AConfiguration_match(AConfiguration* base, AConfiguration* requested) {
+ return base->match(*requested);
+}
+
+int32_t AConfiguration_isBetterThan(AConfiguration* base, AConfiguration* test,
+ AConfiguration* requested) {
+ return base->isBetterThan(*test, requested);
+}
diff --git a/native/copy-to-ndk.sh b/native/copy-to-ndk.sh
new file mode 100644
index 0000000..4f5a16a
--- /dev/null
+++ b/native/copy-to-ndk.sh
@@ -0,0 +1,55 @@
+# Take care of copying current header files over to the correct
+# location in the NDK.
+
+copyndkheaders() {
+ local CURR_PLATFORM=android-9
+ local ALL_PLATFORMS="$CURR_PLATFORM android-8 android-5 android-4 android-3"
+
+ local SRC_HEADERS=$ANDROID_BUILD_TOP/frameworks/base/native/include/android
+ local NDK_PLATFORMS=$ANDROID_BUILD_TOP/development/ndk/platforms
+ local DST_HEADERS=$NDK_PLATFORMS/$CURR_PLATFORM
+
+ local SRC_LIB_ANDROID=$ANDROID_PRODUCT_OUT/system/lib/libandroid.so
+ local DST_LIB_ANDROID=$NDK_PLATFORMS/$CURR_PLATFORM/arch-arm/usr/lib/libandroid.so
+
+ local didsomething=""
+
+ #echo "SRC_HEADERS: $SRC_HEADERS"
+
+ for i in $(cd $SRC_HEADERS; ls *.h); do
+ local src=$SRC_HEADERS/$i
+ local changed=""
+ for j in $ALL_PLATFORMS; do
+ local dst=$NDK_PLATFORMS/$j/arch-arm/usr/include/android/$i
+ if [ "$changed" == "" -a -e $dst ]; then
+ #echo "Exists: $dst"
+ if diff $src $dst >/dev/null; then
+ echo "$i: has not changed from $j" >/dev/null
+ changed="false"
+ else
+ changed="true"
+ echo "$i: has changed from $j" >/dev/null
+ fi
+ fi
+ done
+ if [ "$changed" == "true" -o "$changed" == "" ]; then
+ echo "Updating: $i"
+ cp $src $NDK_PLATFORMS/$CURR_PLATFORM/arch-arm/usr/include/android/$i
+ didsomething="true"
+ fi
+ done
+
+ if diff $SRC_LIB_ANDROID $DST_LIB_ANDROID >/dev/null; then
+ echo "libandroid.so: has not changed" >/dev/null
+ else
+ echo "Updating: $DST_LIB_ANDROID"
+ cp $SRC_LIB_ANDROID $DST_LIB_ANDROID
+ didsomething="true"
+ fi
+ if [ "$didsomething" != "" ]; then
+ echo "Headers changed... rebuilding platforms."
+ sh $ANDROID_BUILD_TOP/ndk/build/tools/build-platforms.sh
+ fi
+}
+
+copyndkheaders
diff --git a/native/include/android/asset_manager.h b/native/include/android/asset_manager.h
index 89989f8..4fa0ef3 100644
--- a/native/include/android/asset_manager.h
+++ b/native/include/android/asset_manager.h
@@ -18,8 +18,6 @@
#ifndef ANDROID_ASSET_MANAGER_H
#define ANDROID_ASSET_MANAGER_H
-#include <jni.h>
-
#ifdef __cplusplus
extern "C" {
#endif
@@ -43,14 +41,6 @@ enum {
/**
- * Given a Dalvik AssetManager object, obtain the corresponding native AAssetManager
- * object. Note that the caller is responsible for obtaining and holding a VM reference
- * to the jobject to prevent its being garbage collected while the native object is
- * in use.
- */
-AAssetManager* AAssetManager_fromJava(JNIEnv* env, jobject assetManager);
-
-/**
* Open the named directory within the asset hierarchy. The directory can then
* be inspected with the AAssetDir functions. To open the top-level directory,
* pass in "" as the dirName.
diff --git a/native/include/android/asset_manager_jni.h b/native/include/android/asset_manager_jni.h
new file mode 100644
index 0000000..aec2d3c
--- /dev/null
+++ b/native/include/android/asset_manager_jni.h
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+#ifndef ANDROID_ASSET_MANAGER_JNI_H
+#define ANDROID_ASSET_MANAGER_JNI_H
+
+#include <android/asset_manager.h>
+#include <jni.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * Given a Dalvik AssetManager object, obtain the corresponding native AAssetManager
+ * object. Note that the caller is responsible for obtaining and holding a VM reference
+ * to the jobject to prevent its being garbage collected while the native object is
+ * in use.
+ */
+AAssetManager* AAssetManager_fromJava(JNIEnv* env, jobject assetManager);
+
+#ifdef __cplusplus
+};
+#endif
+
+#endif // ANDROID_ASSET_MANAGER_JNI_H
diff --git a/native/include/android/configuration.h b/native/include/android/configuration.h
new file mode 100644
index 0000000..79b9b1e
--- /dev/null
+++ b/native/include/android/configuration.h
@@ -0,0 +1,319 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_CONFIGURATION_H
+#define ANDROID_CONFIGURATION_H
+
+#include <android/asset_manager.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct AConfiguration;
+typedef struct AConfiguration AConfiguration;
+
+enum {
+ ACONFIGURATION_ORIENTATION_ANY = 0x0000,
+ ACONFIGURATION_ORIENTATION_PORT = 0x0001,
+ ACONFIGURATION_ORIENTATION_LAND = 0x0002,
+ ACONFIGURATION_ORIENTATION_SQUARE = 0x0003,
+
+ ACONFIGURATION_TOUCHSCREEN_ANY = 0x0000,
+ ACONFIGURATION_TOUCHSCREEN_NOTOUCH = 0x0001,
+ ACONFIGURATION_TOUCHSCREEN_STYLUS = 0x0002,
+ ACONFIGURATION_TOUCHSCREEN_FINGER = 0x0003,
+
+ ACONFIGURATION_DENSITY_DEFAULT = 0,
+ ACONFIGURATION_DENSITY_LOW = 120,
+ ACONFIGURATION_DENSITY_MEDIUM = 160,
+ ACONFIGURATION_DENSITY_HIGH = 240,
+ ACONFIGURATION_DENSITY_NONE = 0xffff,
+
+ ACONFIGURATION_KEYBOARD_ANY = 0x0000,
+ ACONFIGURATION_KEYBOARD_NOKEYS = 0x0001,
+ ACONFIGURATION_KEYBOARD_QWERTY = 0x0002,
+ ACONFIGURATION_KEYBOARD_12KEY = 0x0003,
+
+ ACONFIGURATION_NAVIGATION_ANY = 0x0000,
+ ACONFIGURATION_NAVIGATION_NONAV = 0x0001,
+ ACONFIGURATION_NAVIGATION_DPAD = 0x0002,
+ ACONFIGURATION_NAVIGATION_TRACKBALL = 0x0003,
+ ACONFIGURATION_NAVIGATION_WHEEL = 0x0004,
+
+ ACONFIGURATION_KEYSHIDDEN_ANY = 0x0000,
+ ACONFIGURATION_KEYSHIDDEN_NO = 0x0001,
+ ACONFIGURATION_KEYSHIDDEN_YES = 0x0002,
+ ACONFIGURATION_KEYSHIDDEN_SOFT = 0x0003,
+
+ ACONFIGURATION_NAVHIDDEN_ANY = 0x0000,
+ ACONFIGURATION_NAVHIDDEN_NO = 0x0001,
+ ACONFIGURATION_NAVHIDDEN_YES = 0x0002,
+
+ ACONFIGURATION_SCREENSIZE_ANY = 0x00,
+ ACONFIGURATION_SCREENSIZE_SMALL = 0x01,
+ ACONFIGURATION_SCREENSIZE_NORMAL = 0x02,
+ ACONFIGURATION_SCREENSIZE_LARGE = 0x03,
+ ACONFIGURATION_SCREENSIZE_XLARGE = 0x04,
+
+ ACONFIGURATION_SCREENLONG_ANY = 0x00,
+ ACONFIGURATION_SCREENLONG_NO = 0x1,
+ ACONFIGURATION_SCREENLONG_YES = 0x2,
+
+ ACONFIGURATION_UI_MODE_TYPE_ANY = 0x00,
+ ACONFIGURATION_UI_MODE_TYPE_NORMAL = 0x01,
+ ACONFIGURATION_UI_MODE_TYPE_DESK = 0x02,
+ ACONFIGURATION_UI_MODE_TYPE_CAR = 0x03,
+
+ ACONFIGURATION_UI_MODE_NIGHT_ANY = 0x00,
+ ACONFIGURATION_UI_MODE_NIGHT_NO = 0x10,
+ ACONFIGURATION_UI_MODE_NIGHT_YES = 0x20,
+
+ ACONFIGURATION_MCC = 0x0001,
+ ACONFIGURATION_MNC = 0x0002,
+ ACONFIGURATION_LOCALE = 0x0004,
+ ACONFIGURATION_TOUCHSCREEN = 0x0008,
+ ACONFIGURATION_KEYBOARD = 0x0010,
+ ACONFIGURATION_KEYBOARD_HIDDEN = 0x0020,
+ ACONFIGURATION_NAVIGATION = 0x0040,
+ ACONFIGURATION_ORIENTATION = 0x0080,
+ ACONFIGURATION_DENSITY = 0x0100,
+ ACONFIGURATION_SCREEN_SIZE = 0x0200,
+ ACONFIGURATION_VERSION = 0x0400,
+ ACONFIGURATION_SCREEN_LAYOUT = 0x0800,
+ ACONFIGURATION_UI_MODE = 0x1000,
+};
+
+/**
+ * Create a new AConfiguration, initialized with no values set.
+ */
+AConfiguration* AConfiguration_new();
+
+/**
+ * Free an AConfiguration that was previously created with
+ * AConfiguration_new().
+ */
+void AConfiguration_delete(AConfiguration* config);
+
+/**
+ * Create and return a new AConfiguration based on the current configuration in
+ * use in the given AssetManager.
+ */
+void AConfiguration_fromAssetManager(AConfiguration* out, AAssetManager* am);
+
+/**
+ * Copy the contents of 'src' to 'dest'.
+ */
+void AConfiguration_copy(AConfiguration* dest, AConfiguration* src);
+
+/**
+ * Return the current MCC set in the configuration. 0 if not set.
+ */
+int32_t AConfiguration_getMcc(AConfiguration* config);
+
+/**
+ * Set the current MCC in the configuration. 0 to clear.
+ */
+void AConfiguration_setMcc(AConfiguration* config, int32_t mcc);
+
+/**
+ * Return the current MNC set in the configuration. 0 if not set.
+ */
+int32_t AConfiguration_getMnc(AConfiguration* config);
+
+/**
+ * Set the current MNC in the configuration. 0 to clear.
+ */
+void AConfiguration_setMnc(AConfiguration* config, int32_t mnc);
+
+/**
+ * Return the current language code set in the configuration. The output will
+ * be filled with an array of two characters. They are not 0-terminated. If
+ * a language is not set, they will be 0.
+ */
+void AConfiguration_getLanguage(AConfiguration* config, char* outLanguage);
+
+/**
+ * Set the current language code in the configuration, from the first two
+ * characters in the string.
+ */
+void AConfiguration_setLanguage(AConfiguration* config, const char* language);
+
+/**
+ * Return the current country code set in the configuration. The output will
+ * be filled with an array of two characters. They are not 0-terminated. If
+ * a country is not set, they will be 0.
+ */
+void AConfiguration_getCountry(AConfiguration* config, char* outCountry);
+
+/**
+ * Set the current country code in the configuration, from the first two
+ * characters in the string.
+ */
+void AConfiguration_setCountry(AConfiguration* config, const char* country);
+
+/**
+ * Return the current ACONFIGURATION_ORIENTATION_* set in the configuration.
+ */
+int32_t AConfiguration_getOrientation(AConfiguration* config);
+
+/**
+ * Set the current orientation in the configuration.
+ */
+void AConfiguration_setOrientation(AConfiguration* config, int32_t orientation);
+
+/**
+ * Return the current ACONFIGURATION_TOUCHSCREEN_* set in the configuration.
+ */
+int32_t AConfiguration_getTouchscreen(AConfiguration* config);
+
+/**
+ * Set the current touchscreen in the configuration.
+ */
+void AConfiguration_setTouchscreen(AConfiguration* config, int32_t touchscreen);
+
+/**
+ * Return the current ACONFIGURATION_DENSITY_* set in the configuration.
+ */
+int32_t AConfiguration_getDensity(AConfiguration* config);
+
+/**
+ * Set the current density in the configuration.
+ */
+void AConfiguration_setDensity(AConfiguration* config, int32_t density);
+
+/**
+ * Return the current ACONFIGURATION_KEYBOARD_* set in the configuration.
+ */
+int32_t AConfiguration_getKeyboard(AConfiguration* config);
+
+/**
+ * Set the current keyboard in the configuration.
+ */
+void AConfiguration_setKeyboard(AConfiguration* config, int32_t keyboard);
+
+/**
+ * Return the current ACONFIGURATION_NAVIGATION_* set in the configuration.
+ */
+int32_t AConfiguration_getNavigation(AConfiguration* config);
+
+/**
+ * Set the current navigation in the configuration.
+ */
+void AConfiguration_setNavigation(AConfiguration* config, int32_t navigation);
+
+/**
+ * Return the current ACONFIGURATION_KEYSHIDDEN_* set in the configuration.
+ */
+int32_t AConfiguration_getKeysHidden(AConfiguration* config);
+
+/**
+ * Set the current keys hidden in the configuration.
+ */
+void AConfiguration_setKeysHidden(AConfiguration* config, int32_t keysHidden);
+
+/**
+ * Return the current ACONFIGURATION_NAVHIDDEN_* set in the configuration.
+ */
+int32_t AConfiguration_getNavHidden(AConfiguration* config);
+
+/**
+ * Set the current nav hidden in the configuration.
+ */
+void AConfiguration_setNavHidden(AConfiguration* config, int32_t navHidden);
+
+/**
+ * Return the current SDK (API) version set in the configuration.
+ */
+int32_t AConfiguration_getSdkVersion(AConfiguration* config);
+
+/**
+ * Set the current SDK version in the configuration.
+ */
+void AConfiguration_setSdkVersion(AConfiguration* config, int32_t sdkVersion);
+
+/**
+ * Return the current ACONFIGURATION_SCREENSIZE_* set in the configuration.
+ */
+int32_t AConfiguration_getScreenSize(AConfiguration* config);
+
+/**
+ * Set the current screen size in the configuration.
+ */
+void AConfiguration_setScreenSize(AConfiguration* config, int32_t screenSize);
+
+/**
+ * Return the current ACONFIGURATION_SCREENLONG_* set in the configuration.
+ */
+int32_t AConfiguration_getScreenLong(AConfiguration* config);
+
+/**
+ * Set the current screen long in the configuration.
+ */
+void AConfiguration_setScreenLong(AConfiguration* config, int32_t screenLong);
+
+/**
+ * Return the current ACONFIGURATION_UI_MODE_TYPE_* set in the configuration.
+ */
+int32_t AConfiguration_getUiModeType(AConfiguration* config);
+
+/**
+ * Set the current UI mode type in the configuration.
+ */
+void AConfiguration_setUiModeType(AConfiguration* config, int32_t uiModeType);
+
+/**
+ * Return the current ACONFIGURATION_UI_MODE_NIGHT_* set in the configuration.
+ */
+int32_t AConfiguration_getUiModeNight(AConfiguration* config);
+
+/**
+ * Set the current UI mode night in the configuration.
+ */
+void AConfiguration_setUiModeNight(AConfiguration* config, int32_t uiModeNight);
+
+/**
+ * Perform a diff between two configurations. Returns a bit mask of
+ * ACONFIGURATION_* constants, each bit set meaning that configuration element
+ * is different between them.
+ */
+int32_t AConfiguration_diff(AConfiguration* config1, AConfiguration* config2);
+
+/**
+ * Determine whether 'base' is a valid configuration for use within the
+ * environment 'requested'. Returns 0 if there are any values in 'base'
+ * that conflict with 'requested'. Returns 1 if it does not conflict.
+ */
+int32_t AConfiguration_match(AConfiguration* base, AConfiguration* requested);
+
+/**
+ * Determine whether the configuration in 'test' is better than the existing
+ * configuration in 'base'. If 'requested' is non-NULL, this decision is based
+ * on the overall configuration given there. If it is NULL, this decision is
+ * simply based on which configuration is more specific. Returns non-0 if
+ * 'test' is better than 'base'.
+ *
+ * This assumes you have already filtered the configurations with
+ * AConfiguration_match().
+ */
+int32_t AConfiguration_isBetterThan(AConfiguration* base, AConfiguration* test,
+ AConfiguration* requested);
+
+#ifdef __cplusplus
+};
+#endif
+
+#endif // ANDROID_CONFIGURATION_H
diff --git a/native/include/android/native_activity.h b/native/include/android/native_activity.h
index ee4204d..d74e1ce 100644
--- a/native/include/android/native_activity.h
+++ b/native/include/android/native_activity.h
@@ -197,6 +197,12 @@ typedef struct ANativeActivityCallbacks {
void (*onContentRectChanged)(ANativeActivity* activity, const ARect* rect);
/**
+ * The current device AConfiguration has changed. The new configuration can
+ * be retrieved from assetManager.
+ */
+ void (*onConfigurationChanged)(ANativeActivity* activity);
+
+ /**
* The system is running low on memory. Use this callback to release
* resources you do not need, to help the system avoid killing more
* important processes.
@@ -208,7 +214,9 @@ typedef struct ANativeActivityCallbacks {
* This is the function that must be in the native code to instantiate the
* application's native activity. It is called with the activity instance (see
* above); if the code is being instantiated from a previously saved instance,
- * the savedState will be non-NULL and point to the saved data.
+ * the savedState will be non-NULL and point to the saved data. You must make
+ * any copy of this data you need -- it will be released after you return from
+ * this function.
*/
typedef void ANativeActivity_createFunc(ANativeActivity* activity,
void* savedState, size_t savedStateSize);
diff --git a/native/include/android/native_window.h b/native/include/android/native_window.h
index 7599d7e..ad03d0e 100644
--- a/native/include/android/native_window.h
+++ b/native/include/android/native_window.h
@@ -36,12 +36,23 @@ struct ANativeWindow;
typedef struct ANativeWindow ANativeWindow;
typedef struct ANativeWindow_Buffer {
+ // The number of pixels that are show horizontally.
int32_t width;
+
+ // The number of pixels that are shown vertically.
int32_t height;
+
+ // The number of *pixels* that a line in the buffer takes in
+ // memory. This may be >= width.
int32_t stride;
+
+ // The format of the buffer. One of WINDOW_FORMAT_*
int32_t format;
+
+ // The actual bits.
void* bits;
+ // Do not touch.
uint32_t reserved[6];
} ANativeWindow_Buffer;
diff --git a/packages/DefaultContainerService/src/com/android/defcontainer/DefaultContainerService.java b/packages/DefaultContainerService/src/com/android/defcontainer/DefaultContainerService.java
index f1c6532..c6e0a24 100644
--- a/packages/DefaultContainerService/src/com/android/defcontainer/DefaultContainerService.java
+++ b/packages/DefaultContainerService/src/com/android/defcontainer/DefaultContainerService.java
@@ -24,6 +24,8 @@ import android.content.pm.PackageInfo;
import android.content.pm.PackageInfoLite;
import android.content.pm.PackageManager;
import android.content.pm.PackageParser;
+import android.content.res.ObbInfo;
+import android.content.res.ObbScanner;
import android.net.Uri;
import android.os.Environment;
import android.os.IBinder;
@@ -142,6 +144,10 @@ public class DefaultContainerService extends IntentService {
public boolean checkFreeStorage(boolean external, Uri fileUri) {
return checkFreeStorageInner(external, fileUri);
}
+
+ public ObbInfo getObbInfo(String filename) {
+ return ObbScanner.getObbInfo(filename);
+ }
};
public DefaultContainerService() {
diff --git a/packages/SystemUI/res/layout-xlarge/status_bar_center.xml b/packages/SystemUI/res/layout-xlarge/status_bar_center.xml
index dc2357f..c32e997 100644
--- a/packages/SystemUI/res/layout-xlarge/status_bar_center.xml
+++ b/packages/SystemUI/res/layout-xlarge/status_bar_center.xml
@@ -27,9 +27,10 @@
<com.android.systemui.statusbar.Clock
style="@*android:style/TextAppearance.StatusBar.Icon"
android:id="@+id/clock"
- android:layout_width="wrap_content"
+ android:layout_width="match_parent"
android:layout_height="wrap_content"
android:singleLine="true"
+ android:gravity="center"
android:textSize="16sp"
android:textStyle="bold"
android:padding="2dip"
diff --git a/services/java/com/android/server/ConnectivityService.java b/services/java/com/android/server/ConnectivityService.java
index cc1566b..ae4e168 100644
--- a/services/java/com/android/server/ConnectivityService.java
+++ b/services/java/com/android/server/ConnectivityService.java
@@ -314,14 +314,14 @@ public class ConnectivityService extends IConnectivityManager.Stub {
case ConnectivityManager.TYPE_WIFI:
if (DBG) Slog.v(TAG, "Starting Wifi Service.");
WifiStateTracker wst = new WifiStateTracker(context, mHandler);
- WifiService wifiService = new WifiService(context, wst);
+ WifiService wifiService = new WifiService(context);
ServiceManager.addService(Context.WIFI_SERVICE, wifiService);
- wifiService.startWifi();
+ wifiService.checkAndStartWifi();
mNetTrackers[ConnectivityManager.TYPE_WIFI] = wst;
wst.startMonitoring();
//TODO: as part of WWS refactor, create only when needed
- mWifiWatchdogService = new WifiWatchdogService(context, wst);
+ mWifiWatchdogService = new WifiWatchdogService(context);
break;
case ConnectivityManager.TYPE_MOBILE:
@@ -1205,16 +1205,6 @@ public class ConnectivityService extends IConnectivityManager.Stub {
sendConnectedBroadcast(info);
}
- private void handleScanResultsAvailable(NetworkInfo info) {
- int networkType = info.getType();
- if (networkType != ConnectivityManager.TYPE_WIFI) {
- if (DBG) Slog.v(TAG, "Got ScanResultsAvailable for " +
- info.getTypeName() + " network. Don't know how to handle.");
- }
-
- mNetTrackers[networkType].interpretScanResultsAvailable();
- }
-
private void handleNotificationChange(boolean visible, int id,
Notification notification) {
NotificationManager notificationManager = (NotificationManager) mContext
@@ -1619,11 +1609,6 @@ public class ConnectivityService extends IConnectivityManager.Stub {
}
break;
- case NetworkStateTracker.EVENT_SCAN_RESULTS_AVAILABLE:
- info = (NetworkInfo) msg.obj;
- handleScanResultsAvailable(info);
- break;
-
case NetworkStateTracker.EVENT_NOTIFICATION_CHANGED:
handleNotificationChange(msg.arg1 == 1, msg.arg2,
(Notification) msg.obj);
diff --git a/services/java/com/android/server/InputMethodManagerService.java b/services/java/com/android/server/InputMethodManagerService.java
index 3fd9907..164142e 100644
--- a/services/java/com/android/server/InputMethodManagerService.java
+++ b/services/java/com/android/server/InputMethodManagerService.java
@@ -466,6 +466,9 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
screenOnOffFilt.addAction(Intent.ACTION_CLOSE_SYSTEM_DIALOGS);
mContext.registerReceiver(new ScreenOnOffReceiver(), screenOnOffFilt);
+ mStatusBar = statusBar;
+ statusBar.setIconVisibility("ime", false);
+
buildInputMethodListLocked(mMethodList, mMethodMap);
final String enabledStr = Settings.Secure.getString(
@@ -509,9 +512,6 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
}
}
- mStatusBar = statusBar;
- statusBar.setIconVisibility("ime", false);
-
mSettingsObserver = new SettingsObserver(mHandler);
updateFromSettingsLocked();
}
@@ -1220,6 +1220,7 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
if (mCurClient == null || client == null
|| mCurClient.client.asBinder() != client.asBinder()) {
Slog.w(TAG, "Ignoring showInputMethodDialogFromClient of: " + client);
+ return;
}
mHandler.sendEmptyMessage(MSG_SHOW_IM_PICKER);
diff --git a/services/java/com/android/server/MountService.java b/services/java/com/android/server/MountService.java
index ef5e9cc..d604886 100644
--- a/services/java/com/android/server/MountService.java
+++ b/services/java/com/android/server/MountService.java
@@ -16,34 +16,42 @@
package com.android.server;
+import com.android.internal.app.IMediaContainerService;
import com.android.server.am.ActivityManagerService;
import android.content.BroadcastReceiver;
+import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
+import android.content.ServiceConnection;
import android.content.pm.PackageManager;
import android.content.res.ObbInfo;
-import android.content.res.ObbScanner;
import android.net.Uri;
-import android.os.storage.IMountService;
-import android.os.storage.IMountServiceListener;
-import android.os.storage.IMountShutdownObserver;
-import android.os.storage.StorageResultCode;
import android.os.Binder;
+import android.os.Environment;
import android.os.Handler;
import android.os.HandlerThread;
+import android.os.IBinder;
import android.os.Looper;
import android.os.Message;
import android.os.RemoteException;
-import android.os.IBinder;
-import android.os.Environment;
import android.os.ServiceManager;
import android.os.SystemClock;
import android.os.SystemProperties;
+import android.os.storage.IMountService;
+import android.os.storage.IMountServiceListener;
+import android.os.storage.IMountShutdownObserver;
+import android.os.storage.IObbActionListener;
+import android.os.storage.StorageResultCode;
import android.util.Slog;
+
import java.util.ArrayList;
+import java.util.HashMap;
import java.util.HashSet;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
/**
* MountService implements back-end services for platform storage
@@ -137,9 +145,77 @@ class MountService extends IMountService.Stub
final private HashSet<String> mAsecMountSet = new HashSet<String>();
/**
- * Private hash of currently mounted filesystem images.
+ * Mounted OBB tracking information. Used to track the current state of all
+ * OBBs.
+ */
+ final private Map<IObbActionListener, ObbState> mObbMounts = new HashMap<IObbActionListener, ObbState>();
+ final private Map<String, ObbState> mObbPathToStateMap = new HashMap<String, ObbState>();
+
+ class ObbState implements IBinder.DeathRecipient {
+ public ObbState(String filename, IObbActionListener token, int callerUid) {
+ this.filename = filename;
+ this.token = token;
+ this.callerUid = callerUid;
+ mounted = false;
+ }
+
+ // OBB source filename
+ String filename;
+
+ // Token of remote Binder caller
+ IObbActionListener token;
+
+ // Binder.callingUid()
+ public int callerUid;
+
+ // Whether this is mounted currently.
+ boolean mounted;
+
+ @Override
+ public void binderDied() {
+ ObbAction action = new UnmountObbAction(this, true);
+ mObbActionHandler.sendMessage(mObbActionHandler.obtainMessage(OBB_RUN_ACTION, action));
+
+ removeObbState(this);
+
+ token.asBinder().unlinkToDeath(this, 0);
+ }
+ }
+
+ // OBB Action Handler
+ final private ObbActionHandler mObbActionHandler;
+
+ // OBB action handler messages
+ private static final int OBB_RUN_ACTION = 1;
+ private static final int OBB_MCS_BOUND = 2;
+ private static final int OBB_MCS_UNBIND = 3;
+ private static final int OBB_MCS_RECONNECT = 4;
+ private static final int OBB_MCS_GIVE_UP = 5;
+
+ /*
+ * Default Container Service information
*/
- final private HashSet<String> mObbMountSet = new HashSet<String>();
+ static final ComponentName DEFAULT_CONTAINER_COMPONENT = new ComponentName(
+ "com.android.defcontainer", "com.android.defcontainer.DefaultContainerService");
+
+ final private DefaultContainerConnection mDefContainerConn = new DefaultContainerConnection();
+
+ class DefaultContainerConnection implements ServiceConnection {
+ public void onServiceConnected(ComponentName name, IBinder service) {
+ if (DEBUG_OBB)
+ Slog.i(TAG, "onServiceConnected");
+ IMediaContainerService imcs = IMediaContainerService.Stub.asInterface(service);
+ mObbActionHandler.sendMessage(mObbActionHandler.obtainMessage(OBB_MCS_BOUND, imcs));
+ }
+
+ public void onServiceDisconnected(ComponentName name) {
+ if (DEBUG_OBB)
+ Slog.i(TAG, "onServiceDisconnected");
+ }
+ };
+
+ // Used in the ObbActionHandler
+ private IMediaContainerService mContainerService = null;
// Handler messages
private static final int H_UNMOUNT_PM_UPDATE = 1;
@@ -363,7 +439,7 @@ class MountService extends IMountService.Stub
public void binderDied() {
if (LOCAL_LOGD) Slog.d(TAG, "An IMountServiceListener has died!");
- synchronized(mListeners) {
+ synchronized (mListeners) {
mListeners.remove(this);
mListener.asBinder().unlinkToDeath(this, 0);
}
@@ -917,6 +993,9 @@ class MountService extends IMountService.Stub
mHandlerThread.start();
mHandler = new MountServiceHandler(mHandlerThread.getLooper());
+ // Add OBB Action Handler to MountService thread.
+ mObbActionHandler = new ObbActionHandler(mHandlerThread.getLooper());
+
/*
* Vold does not run in the simulator, so pretend the connector thread
* ran and did its thing.
@@ -1013,7 +1092,7 @@ class MountService extends IMountService.Stub
private void setUmsEnabling(boolean enable) {
synchronized (mListeners) {
- mUmsEnabling = true;
+ mUmsEnabling = enable;
}
}
@@ -1351,12 +1430,16 @@ class MountService extends IMountService.Stub
mHandler.sendEmptyMessage(H_UNMOUNT_PM_DONE);
}
- private boolean isCallerOwnerOfPackage(String packageName) {
+ private boolean isCallerOwnerOfPackageOrSystem(String packageName) {
final int callerUid = Binder.getCallingUid();
- return isUidOwnerOfPackage(packageName, callerUid);
+ return isUidOwnerOfPackageOrSystem(packageName, callerUid);
}
- private boolean isUidOwnerOfPackage(String packageName, int callerUid) {
+ private boolean isUidOwnerOfPackageOrSystem(String packageName, int callerUid) {
+ if (callerUid == android.os.Process.SYSTEM_UID) {
+ return true;
+ }
+
if (packageName == null) {
return false;
}
@@ -1375,12 +1458,6 @@ class MountService extends IMountService.Stub
waitForReady();
warnOnNotMounted();
- // XXX replace with call to IMediaContainerService
- ObbInfo obbInfo = ObbScanner.getObbInfo(filename);
- if (!isCallerOwnerOfPackage(obbInfo.packageName)) {
- throw new IllegalArgumentException("Caller package does not match OBB file");
- }
-
try {
ArrayList<String> rsp = mConnector.doCommand(String.format("obb path %s", filename));
String []tok = rsp.get(0).split(" ");
@@ -1392,7 +1469,7 @@ class MountService extends IMountService.Stub
} catch (NativeDaemonConnectorException e) {
int code = e.getCode();
if (code == VoldResponseCode.OpFailedStorageNotFound) {
- throw new IllegalArgumentException(String.format("OBB '%s' not found", filename));
+ return null;
} else {
throw new IllegalStateException(String.format("Unexpected response code %d", code));
}
@@ -1400,95 +1477,390 @@ class MountService extends IMountService.Stub
}
public boolean isObbMounted(String filename) {
+ synchronized (mObbMounts) {
+ return mObbPathToStateMap.containsKey(filename);
+ }
+ }
+
+ public void mountObb(String filename, String key, IObbActionListener token) {
waitForReady();
warnOnNotMounted();
- // XXX replace with call to IMediaContainerService
- ObbInfo obbInfo = ObbScanner.getObbInfo(filename);
- if (!isCallerOwnerOfPackage(obbInfo.packageName)) {
- throw new IllegalArgumentException("Caller package does not match OBB file");
+ final ObbState obbState;
+
+ synchronized (mObbMounts) {
+ if (isObbMounted(filename)) {
+ throw new IllegalArgumentException("OBB file is already mounted");
+ }
+
+ if (mObbMounts.containsKey(token)) {
+ throw new IllegalArgumentException("You may only have one OBB mounted at a time");
+ }
+
+ final int callerUid = Binder.getCallingUid();
+ obbState = new ObbState(filename, token, callerUid);
+ addObbState(obbState);
}
- synchronized (mObbMountSet) {
- return mObbMountSet.contains(filename);
+ try {
+ token.asBinder().linkToDeath(obbState, 0);
+ } catch (RemoteException rex) {
+ Slog.e(TAG, "Failed to link to listener death");
}
+
+ MountObbAction action = new MountObbAction(obbState, key);
+ mObbActionHandler.sendMessage(mObbActionHandler.obtainMessage(OBB_RUN_ACTION, action));
+
+ if (DEBUG_OBB)
+ Slog.i(TAG, "Send to OBB handler: " + action.toString());
}
- public int mountObb(String filename, String key) {
- waitForReady();
- warnOnNotMounted();
+ public void unmountObb(String filename, boolean force, IObbActionListener token) {
+ final ObbState obbState;
- synchronized (mObbMountSet) {
- if (mObbMountSet.contains(filename)) {
- return StorageResultCode.OperationFailedStorageMounted;
+ synchronized (mObbMounts) {
+ if (!isObbMounted(filename)) {
+ throw new IllegalArgumentException("OBB is not mounted");
}
+ obbState = mObbPathToStateMap.get(filename);
}
- final int callerUid = Binder.getCallingUid();
+ UnmountObbAction action = new UnmountObbAction(obbState, force);
+ mObbActionHandler.sendMessage(mObbActionHandler.obtainMessage(OBB_RUN_ACTION, action));
+
+ if (DEBUG_OBB)
+ Slog.i(TAG, "Send to OBB handler: " + action.toString());
+ }
- // XXX replace with call to IMediaContainerService
- ObbInfo obbInfo = ObbScanner.getObbInfo(filename);
- if (!isUidOwnerOfPackage(obbInfo.packageName, callerUid)) {
- throw new IllegalArgumentException("Caller package does not match OBB file");
+ private void addObbState(ObbState obbState) {
+ synchronized (mObbMounts) {
+ mObbMounts.put(obbState.token, obbState);
+ mObbPathToStateMap.put(obbState.filename, obbState);
}
+ }
- if (key == null) {
- key = "none";
+ private void removeObbState(ObbState obbState) {
+ synchronized (mObbMounts) {
+ mObbMounts.remove(obbState.token);
+ mObbPathToStateMap.remove(obbState.filename);
}
+ }
- int rc = StorageResultCode.OperationSucceeded;
- String cmd = String.format("obb mount %s %s %d", filename, key, callerUid);
- try {
- mConnector.doCommand(cmd);
- } catch (NativeDaemonConnectorException e) {
- int code = e.getCode();
- if (code != VoldResponseCode.OpFailedStorageBusy) {
- rc = StorageResultCode.OperationFailedInternalError;
+ private class ObbActionHandler extends Handler {
+ private boolean mBound = false;
+ private List<ObbAction> mActions = new LinkedList<ObbAction>();
+
+ ObbActionHandler(Looper l) {
+ super(l);
+ }
+
+ @Override
+ public void handleMessage(Message msg) {
+ switch (msg.what) {
+ case OBB_RUN_ACTION: {
+ ObbAction action = (ObbAction) msg.obj;
+
+ if (DEBUG_OBB)
+ Slog.i(TAG, "OBB_RUN_ACTION: " + action.toString());
+
+ // If a bind was already initiated we don't really
+ // need to do anything. The pending install
+ // will be processed later on.
+ if (!mBound) {
+ // If this is the only one pending we might
+ // have to bind to the service again.
+ if (!connectToService()) {
+ Slog.e(TAG, "Failed to bind to media container service");
+ action.handleError();
+ return;
+ } else {
+ // Once we bind to the service, the first
+ // pending request will be processed.
+ mActions.add(action);
+ }
+ } else {
+ // Already bound to the service. Just make
+ // sure we trigger off processing the first request.
+ if (mActions.size() == 0) {
+ mObbActionHandler.sendEmptyMessage(OBB_MCS_BOUND);
+ }
+
+ mActions.add(action);
+ }
+ break;
+ }
+ case OBB_MCS_BOUND: {
+ if (DEBUG_OBB)
+ Slog.i(TAG, "OBB_MCS_BOUND");
+ if (msg.obj != null) {
+ mContainerService = (IMediaContainerService) msg.obj;
+ }
+ if (mContainerService == null) {
+ // Something seriously wrong. Bail out
+ Slog.e(TAG, "Cannot bind to media container service");
+ for (ObbAction action : mActions) {
+ // Indicate service bind error
+ action.handleError();
+ }
+ mActions.clear();
+ } else if (mActions.size() > 0) {
+ ObbAction action = mActions.get(0);
+ if (action != null) {
+ action.execute(this);
+ }
+ } else {
+ // Should never happen ideally.
+ Slog.w(TAG, "Empty queue");
+ }
+ break;
+ }
+ case OBB_MCS_RECONNECT: {
+ if (DEBUG_OBB)
+ Slog.i(TAG, "OBB_MCS_RECONNECT");
+ if (mActions.size() > 0) {
+ if (mBound) {
+ disconnectService();
+ }
+ if (!connectToService()) {
+ Slog.e(TAG, "Failed to bind to media container service");
+ for (ObbAction action : mActions) {
+ // Indicate service bind error
+ action.handleError();
+ }
+ mActions.clear();
+ }
+ }
+ break;
+ }
+ case OBB_MCS_UNBIND: {
+ if (DEBUG_OBB)
+ Slog.i(TAG, "OBB_MCS_UNBIND");
+
+ // Delete pending install
+ if (mActions.size() > 0) {
+ mActions.remove(0);
+ }
+ if (mActions.size() == 0) {
+ if (mBound) {
+ disconnectService();
+ }
+ } else {
+ // There are more pending requests in queue.
+ // Just post MCS_BOUND message to trigger processing
+ // of next pending install.
+ mObbActionHandler.sendEmptyMessage(OBB_MCS_BOUND);
+ }
+ break;
+ }
+ case OBB_MCS_GIVE_UP: {
+ if (DEBUG_OBB)
+ Slog.i(TAG, "OBB_MCS_GIVE_UP");
+ mActions.remove(0);
+ break;
+ }
}
}
- if (rc == StorageResultCode.OperationSucceeded) {
- synchronized (mObbMountSet) {
- mObbMountSet.add(filename);
+ private boolean connectToService() {
+ if (DEBUG_OBB)
+ Slog.i(TAG, "Trying to bind to DefaultContainerService");
+
+ Intent service = new Intent().setComponent(DEFAULT_CONTAINER_COMPONENT);
+ if (mContext.bindService(service, mDefContainerConn, Context.BIND_AUTO_CREATE)) {
+ mBound = true;
+ return true;
}
+ return false;
+ }
+
+ private void disconnectService() {
+ mContainerService = null;
+ mBound = false;
+ mContext.unbindService(mDefContainerConn);
}
- return rc;
}
- public int unmountObb(String filename, boolean force) {
- waitForReady();
- warnOnNotMounted();
+ abstract class ObbAction {
+ private static final int MAX_RETRIES = 3;
+ private int mRetries;
+
+ ObbState mObbState;
- ObbInfo obbInfo = ObbScanner.getObbInfo(filename);
- if (!isCallerOwnerOfPackage(obbInfo.packageName)) {
- throw new IllegalArgumentException("Caller package does not match OBB file");
+ ObbAction(ObbState obbState) {
+ mObbState = obbState;
}
- synchronized (mObbMountSet) {
- if (!mObbMountSet.contains(filename)) {
- return StorageResultCode.OperationFailedStorageNotMounted;
+ public void execute(ObbActionHandler handler) {
+ try {
+ if (DEBUG_OBB)
+ Slog.i(TAG, "Starting to execute action: " + this.toString());
+ mRetries++;
+ if (mRetries > MAX_RETRIES) {
+ Slog.w(TAG, "Failed to invoke remote methods on default container service. Giving up");
+ mObbActionHandler.sendEmptyMessage(OBB_MCS_GIVE_UP);
+ handleError();
+ return;
+ } else {
+ handleExecute();
+ if (DEBUG_OBB)
+ Slog.i(TAG, "Posting install MCS_UNBIND");
+ mObbActionHandler.sendEmptyMessage(OBB_MCS_UNBIND);
+ }
+ } catch (RemoteException e) {
+ if (DEBUG_OBB)
+ Slog.i(TAG, "Posting install MCS_RECONNECT");
+ mObbActionHandler.sendEmptyMessage(OBB_MCS_RECONNECT);
+ } catch (Exception e) {
+ if (DEBUG_OBB)
+ Slog.d(TAG, "Error handling OBB action", e);
+ handleError();
}
- }
+ }
- int rc = StorageResultCode.OperationSucceeded;
- String cmd = String.format("obb unmount %s%s", filename, (force ? " force" : ""));
- try {
- mConnector.doCommand(cmd);
- } catch (NativeDaemonConnectorException e) {
- int code = e.getCode();
- if (code == VoldResponseCode.OpFailedStorageBusy) {
- rc = StorageResultCode.OperationFailedStorageBusy;
+ abstract void handleExecute() throws RemoteException;
+ abstract void handleError();
+ }
+
+ class MountObbAction extends ObbAction {
+ private String mKey;
+
+ MountObbAction(ObbState obbState, String key) {
+ super(obbState);
+ mKey = key;
+ }
+
+ public void handleExecute() throws RemoteException {
+ ObbInfo obbInfo = mContainerService.getObbInfo(mObbState.filename);
+ if (!isUidOwnerOfPackageOrSystem(obbInfo.packageName, mObbState.callerUid)) {
+ throw new IllegalArgumentException("Caller package does not match OBB file");
+ }
+
+ if (mKey == null) {
+ mKey = "none";
+ }
+
+ int rc = StorageResultCode.OperationSucceeded;
+ String cmd = String.format("obb mount %s %s %d", mObbState.filename, mKey,
+ mObbState.callerUid);
+ try {
+ mConnector.doCommand(cmd);
+ } catch (NativeDaemonConnectorException e) {
+ int code = e.getCode();
+ if (code != VoldResponseCode.OpFailedStorageBusy) {
+ rc = StorageResultCode.OperationFailedInternalError;
+ }
+ }
+
+ if (rc == StorageResultCode.OperationSucceeded) {
+ try {
+ mObbState.token.onObbResult(mObbState.filename, "mounted");
+ } catch (RemoteException e) {
+ Slog.w(TAG, "MountServiceListener went away while calling onObbStateChanged");
+ }
} else {
- rc = StorageResultCode.OperationFailedInternalError;
+ Slog.e(TAG, "Couldn't mount OBB file");
+
+ // We didn't succeed, so remove this from the mount-set.
+ removeObbState(mObbState);
}
}
- if (rc == StorageResultCode.OperationSucceeded) {
- synchronized (mObbMountSet) {
- mObbMountSet.remove(filename);
+ public void handleError() {
+ removeObbState(mObbState);
+
+ try {
+ mObbState.token.onObbResult(mObbState.filename, "error");
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Couldn't send back OBB mount error for " + mObbState.filename);
}
}
- return rc;
+
+ @Override
+ public String toString() {
+ StringBuilder sb = new StringBuilder();
+ sb.append("MountObbAction{");
+ sb.append("filename=");
+ sb.append(mObbState.filename);
+ sb.append(",callerUid=");
+ sb.append(mObbState.callerUid);
+ sb.append(",token=");
+ sb.append(mObbState.token != null ? mObbState.token.toString() : "NULL");
+ sb.append('}');
+ return sb.toString();
+ }
+ }
+
+ class UnmountObbAction extends ObbAction {
+ private boolean mForceUnmount;
+
+ UnmountObbAction(ObbState obbState, boolean force) {
+ super(obbState);
+ mForceUnmount = force;
+ }
+
+ public void handleExecute() throws RemoteException {
+ ObbInfo obbInfo = mContainerService.getObbInfo(mObbState.filename);
+
+ if (!isCallerOwnerOfPackageOrSystem(obbInfo.packageName)) {
+ throw new IllegalArgumentException("Caller package does not match OBB file");
+ }
+
+ int rc = StorageResultCode.OperationSucceeded;
+ String cmd = String.format("obb unmount %s%s", mObbState.filename,
+ (mForceUnmount ? " force" : ""));
+ try {
+ mConnector.doCommand(cmd);
+ } catch (NativeDaemonConnectorException e) {
+ int code = e.getCode();
+ if (code == VoldResponseCode.OpFailedStorageBusy) {
+ rc = StorageResultCode.OperationFailedStorageBusy;
+ } else {
+ rc = StorageResultCode.OperationFailedInternalError;
+ }
+ }
+
+ if (rc == StorageResultCode.OperationSucceeded) {
+ removeObbState(mObbState);
+
+ try {
+ mObbState.token.onObbResult(mObbState.filename, "unmounted");
+ } catch (RemoteException e) {
+ Slog.w(TAG, "MountServiceListener went away while calling onObbStateChanged");
+ }
+ } else {
+ try {
+ mObbState.token.onObbResult(mObbState.filename, "error");
+ } catch (RemoteException e) {
+ Slog.w(TAG, "MountServiceListener went away while calling onObbStateChanged");
+ }
+ }
+ }
+
+ public void handleError() {
+ removeObbState(mObbState);
+
+ try {
+ mObbState.token.onObbResult(mObbState.filename, "error");
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Couldn't send back OBB unmount error for " + mObbState.filename);
+ }
+ }
+
+ @Override
+ public String toString() {
+ StringBuilder sb = new StringBuilder();
+ sb.append("UnmountObbAction{");
+ sb.append("filename=");
+ sb.append(mObbState.filename != null ? mObbState.filename : "null");
+ sb.append(",force=");
+ sb.append(mForceUnmount);
+ sb.append(",callerUid=");
+ sb.append(mObbState.callerUid);
+ sb.append(",token=");
+ sb.append(mObbState.token != null ? mObbState.token.toString() : "null");
+ sb.append('}');
+ return sb.toString();
+ }
}
}
diff --git a/services/java/com/android/server/WifiService.java b/services/java/com/android/server/WifiService.java
index 15080b2..b43b33e 100644
--- a/services/java/com/android/server/WifiService.java
+++ b/services/java/com/android/server/WifiService.java
@@ -17,6 +17,8 @@
package com.android.server;
import android.app.AlarmManager;
+import android.app.Notification;
+import android.app.NotificationManager;
import android.app.PendingIntent;
import android.bluetooth.BluetoothA2dp;
import android.bluetooth.BluetoothDevice;
@@ -26,25 +28,30 @@ import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.PackageManager;
+import android.database.ContentObserver;
import android.net.wifi.IWifiManager;
import android.net.wifi.WifiInfo;
import android.net.wifi.WifiManager;
-import android.net.wifi.WifiStateTracker;
+import android.net.wifi.WifiStateMachine;
import android.net.wifi.ScanResult;
import android.net.wifi.WifiConfiguration;
import android.net.wifi.SupplicantState;
import android.net.wifi.WifiConfiguration.KeyMgmt;
import android.net.ConnectivityManager;
import android.net.InterfaceConfiguration;
-import android.net.NetworkStateTracker;
import android.net.DhcpInfo;
+import android.net.NetworkInfo;
+import android.net.NetworkInfo.State;
import android.os.Binder;
+import android.os.Handler;
import android.os.HandlerThread;
import android.os.IBinder;
import android.os.INetworkManagementService;
+import android.os.Message;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.provider.Settings;
+import android.text.TextUtils;
import android.util.Slog;
import java.util.ArrayList;
@@ -72,7 +79,7 @@ public class WifiService extends IWifiManager.Stub {
private static final String TAG = "WifiService";
private static final boolean DBG = true;
- private final WifiStateTracker mWifiStateTracker;
+ private final WifiStateMachine mWifiStateMachine;
private Context mContext;
@@ -123,10 +130,63 @@ public class WifiService extends IWifiManager.Stub {
private boolean mIsReceiverRegistered = false;
- WifiService(Context context, WifiStateTracker tracker) {
+
+ NetworkInfo mNetworkInfo = new NetworkInfo(ConnectivityManager.TYPE_WIFI, 0, "WIFI", "");
+
+ // Variables relating to the 'available networks' notification
+ /**
+ * The icon to show in the 'available networks' notification. This will also
+ * be the ID of the Notification given to the NotificationManager.
+ */
+ private static final int ICON_NETWORKS_AVAILABLE =
+ com.android.internal.R.drawable.stat_notify_wifi_in_range;
+ /**
+ * When a notification is shown, we wait this amount before possibly showing it again.
+ */
+ private final long NOTIFICATION_REPEAT_DELAY_MS;
+ /**
+ * Whether the user has set the setting to show the 'available networks' notification.
+ */
+ private boolean mNotificationEnabled;
+ /**
+ * Observes the user setting to keep {@link #mNotificationEnabled} in sync.
+ */
+ private NotificationEnabledSettingObserver mNotificationEnabledSettingObserver;
+ /**
+ * The {@link System#currentTimeMillis()} must be at least this value for us
+ * to show the notification again.
+ */
+ private long mNotificationRepeatTime;
+ /**
+ * The Notification object given to the NotificationManager.
+ */
+ private Notification mNotification;
+ /**
+ * Whether the notification is being shown, as set by us. That is, if the
+ * user cancels the notification, we will not receive the callback so this
+ * will still be true. We only guarantee if this is false, then the
+ * notification is not showing.
+ */
+ private boolean mNotificationShown;
+ /**
+ * The number of continuous scans that must occur before consider the
+ * supplicant in a scanning state. This allows supplicant to associate with
+ * remembered networks that are in the scan results.
+ */
+ private static final int NUM_SCANS_BEFORE_ACTUALLY_SCANNING = 3;
+ /**
+ * The number of scans since the last network state change. When this
+ * exceeds {@link #NUM_SCANS_BEFORE_ACTUALLY_SCANNING}, we consider the
+ * supplicant to actually be scanning. When the network state changes to
+ * something other than scanning, we reset this to 0.
+ */
+ private int mNumScansSinceNetworkStateChange;
+
+
+ WifiService(Context context) {
mContext = context;
- mWifiStateTracker = tracker;
- mWifiStateTracker.enableRssiPolling(true);
+ mWifiStateMachine = new WifiStateMachine(mContext);
+ mWifiStateMachine.enableRssiPolling(true);
mBatteryStats = BatteryStatsService.getService();
mAlarmManager = (AlarmManager)mContext.getSystemService(Context.ALARM_SERVICE);
@@ -164,6 +224,42 @@ public class WifiService extends IWifiManager.Stub {
}
},new IntentFilter(ConnectivityManager.ACTION_TETHER_STATE_CHANGED));
+
+ IntentFilter filter = new IntentFilter();
+ filter.addAction(WifiManager.WIFI_STATE_CHANGED_ACTION);
+ filter.addAction(WifiManager.NETWORK_STATE_CHANGED_ACTION);
+ filter.addAction(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION);
+
+ mContext.registerReceiver(
+ new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ if (intent.getAction().equals(WifiManager.WIFI_STATE_CHANGED_ACTION)) {
+ // reset & clear notification on any wifi state change
+ resetNotification();
+ } else if (intent.getAction().equals(
+ WifiManager.NETWORK_STATE_CHANGED_ACTION)) {
+ mNetworkInfo = (NetworkInfo) intent.getParcelableExtra(
+ WifiManager.EXTRA_NETWORK_INFO);
+ // reset & clear notification on a network connect & disconnect
+ switch(mNetworkInfo.getDetailedState()) {
+ case CONNECTED:
+ case DISCONNECTED:
+ resetNotification();
+ break;
+ }
+ } else if (intent.getAction().equals(
+ WifiManager.SCAN_RESULTS_AVAILABLE_ACTION)) {
+ checkAndSetNotification();
+ }
+ }
+ }, filter);
+
+ // Setting is in seconds
+ NOTIFICATION_REPEAT_DELAY_MS = Settings.Secure.getInt(context.getContentResolver(),
+ Settings.Secure.WIFI_NETWORKS_AVAILABLE_REPEAT_DELAY, 900) * 1000l;
+ mNotificationEnabledSettingObserver = new NotificationEnabledSettingObserver(new Handler());
+ mNotificationEnabledSettingObserver.register();
}
/**
@@ -172,7 +268,7 @@ public class WifiService extends IWifiManager.Stub {
*
* This function is used only at boot time
*/
- public void startWifi() {
+ public void checkAndStartWifi() {
/* Start if Wi-Fi is enabled or the saved state indicates Wi-Fi was on */
boolean wifiEnabled = !isAirplaneModeOn()
&& (getPersistedWifiEnabled() || testAndClearWifiSavedState());
@@ -255,17 +351,13 @@ public class WifiService extends IWifiManager.Stub {
Settings.Secure.putInt(cr, Settings.Secure.WIFI_ON, enabled ? 1 : 0);
}
- NetworkStateTracker getNetworkStateTracker() {
- return mWifiStateTracker;
- }
-
/**
* see {@link android.net.wifi.WifiManager#pingSupplicant()}
* @return {@code true} if the operation succeeds, {@code false} otherwise
*/
public boolean pingSupplicant() {
enforceAccessPermission();
- return mWifiStateTracker.pingSupplicant();
+ return mWifiStateMachine.pingSupplicant();
}
/**
@@ -274,7 +366,7 @@ public class WifiService extends IWifiManager.Stub {
*/
public boolean startScan(boolean forceActive) {
enforceChangePermission();
- return mWifiStateTracker.startScan(forceActive);
+ return mWifiStateMachine.startScan(forceActive);
}
private void enforceAccessPermission() {
@@ -304,7 +396,7 @@ public class WifiService extends IWifiManager.Stub {
enforceChangePermission();
if (DBG) {
- Slog.e(TAG, "Invoking mWifiStateTracker.setWifiEnabled\n");
+ Slog.e(TAG, "Invoking mWifiStateMachine.setWifiEnabled\n");
}
// set a flag if the user is enabling Wifi while in airplane mode
@@ -312,7 +404,7 @@ public class WifiService extends IWifiManager.Stub {
mAirplaneModeOverwridden.set(true);
}
- mWifiStateTracker.setWifiEnabled(enable);
+ mWifiStateMachine.setWifiEnabled(enable);
persistWifiEnabled(enable);
if (enable) {
@@ -338,7 +430,7 @@ public class WifiService extends IWifiManager.Stub {
*/
public int getWifiEnabledState() {
enforceAccessPermission();
- return mWifiStateTracker.getWifiState();
+ return mWifiStateMachine.getWifiState();
}
/**
@@ -362,7 +454,7 @@ public class WifiService extends IWifiManager.Stub {
setWifiApConfiguration(wifiConfig);
}
- mWifiStateTracker.setWifiApEnabled(wifiConfig, enabled);
+ mWifiStateMachine.setWifiApEnabled(wifiConfig, enabled);
return true;
}
@@ -377,7 +469,7 @@ public class WifiService extends IWifiManager.Stub {
*/
public int getWifiApEnabledState() {
enforceAccessPermission();
- return mWifiStateTracker.getWifiApState();
+ return mWifiStateMachine.getWifiApState();
}
/**
@@ -427,7 +519,7 @@ public class WifiService extends IWifiManager.Stub {
*/
public boolean disconnect() {
enforceChangePermission();
- return mWifiStateTracker.disconnectCommand();
+ return mWifiStateMachine.disconnectCommand();
}
/**
@@ -436,7 +528,7 @@ public class WifiService extends IWifiManager.Stub {
*/
public boolean reconnect() {
enforceChangePermission();
- return mWifiStateTracker.reconnectCommand();
+ return mWifiStateMachine.reconnectCommand();
}
/**
@@ -445,7 +537,7 @@ public class WifiService extends IWifiManager.Stub {
*/
public boolean reassociate() {
enforceChangePermission();
- return mWifiStateTracker.reassociateCommand();
+ return mWifiStateMachine.reassociateCommand();
}
/**
@@ -454,7 +546,7 @@ public class WifiService extends IWifiManager.Stub {
*/
public List<WifiConfiguration> getConfiguredNetworks() {
enforceAccessPermission();
- return mWifiStateTracker.getConfiguredNetworks();
+ return mWifiStateMachine.getConfiguredNetworks();
}
/**
@@ -464,7 +556,7 @@ public class WifiService extends IWifiManager.Stub {
*/
public int addOrUpdateNetwork(WifiConfiguration config) {
enforceChangePermission();
- return mWifiStateTracker.addOrUpdateNetwork(config);
+ return mWifiStateMachine.addOrUpdateNetwork(config);
}
/**
@@ -475,7 +567,7 @@ public class WifiService extends IWifiManager.Stub {
*/
public boolean removeNetwork(int netId) {
enforceChangePermission();
- return mWifiStateTracker.removeNetwork(netId);
+ return mWifiStateMachine.removeNetwork(netId);
}
/**
@@ -487,7 +579,7 @@ public class WifiService extends IWifiManager.Stub {
*/
public boolean enableNetwork(int netId, boolean disableOthers) {
enforceChangePermission();
- return mWifiStateTracker.enableNetwork(netId, disableOthers);
+ return mWifiStateMachine.enableNetwork(netId, disableOthers);
}
/**
@@ -498,7 +590,7 @@ public class WifiService extends IWifiManager.Stub {
*/
public boolean disableNetwork(int netId) {
enforceChangePermission();
- return mWifiStateTracker.disableNetwork(netId);
+ return mWifiStateMachine.disableNetwork(netId);
}
/**
@@ -511,7 +603,7 @@ public class WifiService extends IWifiManager.Stub {
* Make sure we have the latest information, by sending
* a status request to the supplicant.
*/
- return mWifiStateTracker.requestConnectionInfo();
+ return mWifiStateMachine.requestConnectionInfo();
}
/**
@@ -521,7 +613,7 @@ public class WifiService extends IWifiManager.Stub {
*/
public List<ScanResult> getScanResults() {
enforceAccessPermission();
- return mWifiStateTracker.getScanResultsList();
+ return mWifiStateMachine.getScanResultsList();
}
/**
@@ -533,7 +625,7 @@ public class WifiService extends IWifiManager.Stub {
public boolean saveConfiguration() {
boolean result = true;
enforceChangePermission();
- return mWifiStateTracker.saveConfig();
+ return mWifiStateMachine.saveConfig();
}
/**
@@ -576,7 +668,7 @@ public class WifiService extends IWifiManager.Stub {
numChannels);
}
- mWifiStateTracker.setNumAllowedChannels(numChannels);
+ mWifiStateMachine.setNumAllowedChannels(numChannels);
return true;
}
@@ -596,7 +688,7 @@ public class WifiService extends IWifiManager.Stub {
* Wi-Fi is not currently enabled), get the value from
* Settings.
*/
- numChannels = mWifiStateTracker.getNumAllowedChannels();
+ numChannels = mWifiStateMachine.getNumAllowedChannels();
if (numChannels < 0) {
numChannels = Settings.Secure.getInt(mContext.getContentResolver(),
Settings.Secure.WIFI_NUM_ALLOWED_CHANNELS,
@@ -622,9 +714,59 @@ public class WifiService extends IWifiManager.Stub {
*/
public DhcpInfo getDhcpInfo() {
enforceAccessPermission();
- return mWifiStateTracker.getDhcpInfo();
+ return mWifiStateMachine.getDhcpInfo();
+ }
+
+ /**
+ * see {@link android.net.wifi.WifiManager#startWifi}
+ *
+ */
+ public void startWifi() {
+ enforceChangePermission();
+ /* TODO: may be add permissions for access only to connectivity service
+ * TODO: if a start issued, keep wifi alive until a stop issued irrespective
+ * of WifiLock & device idle status unless wifi enabled status is toggled
+ */
+
+ mWifiStateMachine.setDriverStart(true);
+ mWifiStateMachine.reconnectCommand();
+ }
+
+ /**
+ * see {@link android.net.wifi.WifiManager#stopWifi}
+ *
+ */
+ public void stopWifi() {
+ enforceChangePermission();
+ /* TODO: may be add permissions for access only to connectivity service
+ * TODO: if a stop is issued, wifi is brought up only by startWifi
+ * unless wifi enabled status is toggled
+ */
+ mWifiStateMachine.setDriverStart(false);
+ }
+
+
+ /**
+ * see {@link android.net.wifi.WifiManager#addToBlacklist}
+ *
+ */
+ public void addToBlacklist(String bssid) {
+ enforceChangePermission();
+
+ mWifiStateMachine.addToBlacklist(bssid);
+ }
+
+ /**
+ * see {@link android.net.wifi.WifiManager#clearBlacklist}
+ *
+ */
+ public void clearBlacklist() {
+ enforceChangePermission();
+
+ mWifiStateMachine.clearBlacklist();
}
+
private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
@@ -641,11 +783,11 @@ public class WifiService extends IWifiManager.Stub {
mAlarmManager.cancel(mIdleIntent);
mDeviceIdle = false;
mScreenOff = false;
- mWifiStateTracker.enableRssiPolling(true);
+ mWifiStateMachine.enableRssiPolling(true);
} else if (action.equals(Intent.ACTION_SCREEN_OFF)) {
Slog.d(TAG, "ACTION_SCREEN_OFF");
mScreenOff = true;
- mWifiStateTracker.enableRssiPolling(false);
+ mWifiStateMachine.enableRssiPolling(false);
/*
* Set a timer to put Wi-Fi to sleep, but only if the screen is off
* AND the "stay on while plugged in" setting doesn't match the
@@ -653,7 +795,7 @@ public class WifiService extends IWifiManager.Stub {
* or plugged in to AC).
*/
if (!shouldWifiStayAwake(stayAwakeConditions, mPluggedType)) {
- WifiInfo info = mWifiStateTracker.requestConnectionInfo();
+ WifiInfo info = mWifiStateMachine.requestConnectionInfo();
if (info.getSupplicantState() != SupplicantState.COMPLETED) {
// we used to go to sleep immediately, but this caused some race conditions
// we don't have time to track down for this release. Delay instead,
@@ -704,7 +846,7 @@ public class WifiService extends IWifiManager.Stub {
isBluetoothPlaying = true;
}
}
- mWifiStateTracker.setBluetoothScanMode(isBluetoothPlaying);
+ mWifiStateMachine.setBluetoothScanMode(isBluetoothPlaying);
} else {
return;
@@ -771,21 +913,21 @@ public class WifiService extends IWifiManager.Stub {
/* Disable tethering when airplane mode is enabled */
if (airplaneMode) {
- mWifiStateTracker.setWifiApEnabled(null, false);
+ mWifiStateMachine.setWifiApEnabled(null, false);
}
if (wifiShouldBeEnabled) {
if (wifiShouldBeStarted) {
- mWifiStateTracker.setWifiEnabled(true);
- mWifiStateTracker.setScanOnlyMode(
+ mWifiStateMachine.setWifiEnabled(true);
+ mWifiStateMachine.setScanOnlyMode(
strongestLockMode == WifiManager.WIFI_MODE_SCAN_ONLY);
- mWifiStateTracker.startWifi(true);
+ mWifiStateMachine.setDriverStart(true);
} else {
- mWifiStateTracker.requestCmWakeLock();
- mWifiStateTracker.disconnectAndStop();
+ mWifiStateMachine.requestCmWakeLock();
+ mWifiStateMachine.setDriverStart(false);
}
} else {
- mWifiStateTracker.setWifiEnabled(false);
+ mWifiStateMachine.setWifiEnabled(false);
}
}
@@ -832,17 +974,17 @@ public class WifiService extends IWifiManager.Stub {
+ ", uid=" + Binder.getCallingUid());
return;
}
- pw.println("Wi-Fi is " + mWifiStateTracker.getWifiStateByName());
+ pw.println("Wi-Fi is " + mWifiStateMachine.getWifiStateByName());
pw.println("Stay-awake conditions: " +
Settings.System.getInt(mContext.getContentResolver(),
Settings.System.STAY_ON_WHILE_PLUGGED_IN, 0));
pw.println();
pw.println("Internal state:");
- pw.println(mWifiStateTracker);
+ pw.println(mWifiStateMachine);
pw.println();
pw.println("Latest scan results:");
- List<ScanResult> scanResults = mWifiStateTracker.getScanResultsList();
+ List<ScanResult> scanResults = mWifiStateMachine.getScanResultsList();
if (scanResults != null && scanResults.size() != 0) {
pw.println(" BSSID Frequency RSSI Flags SSID");
for (ScanResult r : scanResults) {
@@ -1069,7 +1211,7 @@ public class WifiService extends IWifiManager.Stub {
if (mMulticasters.size() != 0) {
return;
} else {
- mWifiStateTracker.startPacketFiltering();
+ mWifiStateMachine.startPacketFiltering();
}
}
}
@@ -1084,7 +1226,7 @@ public class WifiService extends IWifiManager.Stub {
// our new size == 1 (first call), but this function won't
// be called often and by making the stopPacket call each
// time we're less fragile and self-healing.
- mWifiStateTracker.stopPacketFiltering();
+ mWifiStateMachine.stopPacketFiltering();
}
int uid = Binder.getCallingUid();
@@ -1121,7 +1263,7 @@ public class WifiService extends IWifiManager.Stub {
removed.unlinkDeathRecipient();
}
if (mMulticasters.size() == 0) {
- mWifiStateTracker.startPacketFiltering();
+ mWifiStateMachine.startPacketFiltering();
}
Long ident = Binder.clearCallingIdentity();
@@ -1140,4 +1282,166 @@ public class WifiService extends IWifiManager.Stub {
return (mMulticasters.size() > 0);
}
}
+
+ private void checkAndSetNotification() {
+ // If we shouldn't place a notification on available networks, then
+ // don't bother doing any of the following
+ if (!mNotificationEnabled) return;
+
+ State state = mNetworkInfo.getState();
+ if ((state == NetworkInfo.State.DISCONNECTED)
+ || (state == NetworkInfo.State.UNKNOWN)) {
+ // Look for an open network
+ List<ScanResult> scanResults = mWifiStateMachine.getScanResultsList();
+ if (scanResults != null) {
+ int numOpenNetworks = 0;
+ for (int i = scanResults.size() - 1; i >= 0; i--) {
+ ScanResult scanResult = scanResults.get(i);
+
+ if (TextUtils.isEmpty(scanResult.capabilities)) {
+ numOpenNetworks++;
+ }
+ }
+
+ if (numOpenNetworks > 0) {
+ if (++mNumScansSinceNetworkStateChange >= NUM_SCANS_BEFORE_ACTUALLY_SCANNING) {
+ /*
+ * We've scanned continuously at least
+ * NUM_SCANS_BEFORE_NOTIFICATION times. The user
+ * probably does not have a remembered network in range,
+ * since otherwise supplicant would have tried to
+ * associate and thus resetting this counter.
+ */
+ setNotificationVisible(true, numOpenNetworks, false, 0);
+ }
+ return;
+ }
+ }
+ }
+
+ // No open networks in range, remove the notification
+ setNotificationVisible(false, 0, false, 0);
+ }
+
+ /**
+ * Clears variables related to tracking whether a notification has been
+ * shown recently and clears the current notification.
+ */
+ private void resetNotification() {
+ mNotificationRepeatTime = 0;
+ mNumScansSinceNetworkStateChange = 0;
+ setNotificationVisible(false, 0, false, 0);
+ }
+
+ /**
+ * Display or don't display a notification that there are open Wi-Fi networks.
+ * @param visible {@code true} if notification should be visible, {@code false} otherwise
+ * @param numNetworks the number networks seen
+ * @param force {@code true} to force notification to be shown/not-shown,
+ * even if it is already shown/not-shown.
+ * @param delay time in milliseconds after which the notification should be made
+ * visible or invisible.
+ */
+ private void setNotificationVisible(boolean visible, int numNetworks, boolean force,
+ int delay) {
+
+ // Since we use auto cancel on the notification, when the
+ // mNetworksAvailableNotificationShown is true, the notification may
+ // have actually been canceled. However, when it is false we know
+ // for sure that it is not being shown (it will not be shown any other
+ // place than here)
+
+ // If it should be hidden and it is already hidden, then noop
+ if (!visible && !mNotificationShown && !force) {
+ return;
+ }
+
+ NotificationManager notificationManager = (NotificationManager) mContext
+ .getSystemService(Context.NOTIFICATION_SERVICE);
+
+ Message message;
+ if (visible) {
+
+ // Not enough time has passed to show the notification again
+ if (System.currentTimeMillis() < mNotificationRepeatTime) {
+ return;
+ }
+
+ if (mNotification == null) {
+ // Cache the Notification mainly so we can remove the
+ // EVENT_NOTIFICATION_CHANGED message with this Notification from
+ // the queue later
+ mNotification = new Notification();
+ mNotification.when = 0;
+ mNotification.icon = ICON_NETWORKS_AVAILABLE;
+ mNotification.flags = Notification.FLAG_AUTO_CANCEL;
+ mNotification.contentIntent = PendingIntent.getActivity(mContext, 0,
+ new Intent(WifiManager.ACTION_PICK_WIFI_NETWORK), 0);
+ }
+
+ CharSequence title = mContext.getResources().getQuantityText(
+ com.android.internal.R.plurals.wifi_available, numNetworks);
+ CharSequence details = mContext.getResources().getQuantityText(
+ com.android.internal.R.plurals.wifi_available_detailed, numNetworks);
+ mNotification.tickerText = title;
+ mNotification.setLatestEventInfo(mContext, title, details, mNotification.contentIntent);
+
+ mNotificationRepeatTime = System.currentTimeMillis() + NOTIFICATION_REPEAT_DELAY_MS;
+
+ notificationManager.notify(ICON_NETWORKS_AVAILABLE, mNotification);
+ /*
+ * TODO: Clean up connectivity service & remove this
+ */
+ /* message = mCsHandler.obtainMessage(EVENT_NOTIFICATION_CHANGED, 1,
+ ICON_NETWORKS_AVAILABLE, mNotification); */
+
+
+ } else {
+
+ notificationManager.cancel(ICON_NETWORKS_AVAILABLE);
+ /*
+ * TODO: Clean up connectivity service & remove this
+ */
+ /*
+ // Remove any pending messages to show the notification
+ mCsHandler.removeMessages(EVENT_NOTIFICATION_CHANGED, mNotification);
+
+ message = mCsHandler.obtainMessage(EVENT_NOTIFICATION_CHANGED, 0,
+ ICON_NETWORKS_AVAILABLE);
+ */
+ }
+
+ //mCsHandler.sendMessageDelayed(message, delay);
+
+ mNotificationShown = visible;
+ }
+
+ private class NotificationEnabledSettingObserver extends ContentObserver {
+
+ public NotificationEnabledSettingObserver(Handler handler) {
+ super(handler);
+ }
+
+ public void register() {
+ ContentResolver cr = mContext.getContentResolver();
+ cr.registerContentObserver(Settings.Secure.getUriFor(
+ Settings.Secure.WIFI_NETWORKS_AVAILABLE_NOTIFICATION_ON), true, this);
+ mNotificationEnabled = getValue();
+ }
+
+ @Override
+ public void onChange(boolean selfChange) {
+ super.onChange(selfChange);
+
+ mNotificationEnabled = getValue();
+ resetNotification();
+ }
+
+ private boolean getValue() {
+ return Settings.Secure.getInt(mContext.getContentResolver(),
+ Settings.Secure.WIFI_NETWORKS_AVAILABLE_NOTIFICATION_ON, 1) == 1;
+ }
+ }
+
+
}
diff --git a/services/java/com/android/server/WifiWatchdogService.java b/services/java/com/android/server/WifiWatchdogService.java
index be14cd3..46d6bef 100644
--- a/services/java/com/android/server/WifiWatchdogService.java
+++ b/services/java/com/android/server/WifiWatchdogService.java
@@ -27,7 +27,6 @@ import android.net.DhcpInfo;
import android.net.wifi.ScanResult;
import android.net.wifi.WifiInfo;
import android.net.wifi.WifiManager;
-import android.net.wifi.WifiStateTracker;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
@@ -77,7 +76,6 @@ public class WifiWatchdogService {
private Context mContext;
private ContentResolver mContentResolver;
- private WifiStateTracker mWifiStateTracker;
private WifiManager mWifiManager;
/**
@@ -108,10 +106,9 @@ public class WifiWatchdogService {
/** Whether the current AP check should be canceled. */
private boolean mShouldCancel;
- WifiWatchdogService(Context context, WifiStateTracker wifiStateTracker) {
+ WifiWatchdogService(Context context) {
mContext = context;
mContentResolver = context.getContentResolver();
- mWifiStateTracker = wifiStateTracker;
mWifiManager = (WifiManager) context.getSystemService(Context.WIFI_SERVICE);
createThread();
@@ -752,7 +749,7 @@ public class WifiWatchdogService {
// Black list this "bad" AP, this will cause an attempt to connect to another
blacklistAp(ap.bssid);
// Initiate an association to an alternate AP
- mWifiStateTracker.reassociateCommand();
+ mWifiManager.reassociate();
}
private void blacklistAp(String bssid) {
@@ -763,7 +760,7 @@ public class WifiWatchdogService {
// Before taking action, make sure we should not cancel our processing
if (shouldCancel()) return;
- mWifiStateTracker.addToBlacklist(bssid);
+ mWifiManager.addToBlacklist(bssid);
if (D) {
myLogD("Blacklisting " + bssid);
@@ -858,7 +855,7 @@ public class WifiWatchdogService {
* (and blacklisted them). Clear the blacklist so the AP with best
* signal is chosen.
*/
- mWifiStateTracker.clearBlacklist();
+ mWifiManager.clearBlacklist();
if (V) {
myLogV("handleSleep: Set state to SLEEP and cleared blacklist");
@@ -929,7 +926,7 @@ public class WifiWatchdogService {
* should revert anything done by the watchdog monitoring.
*/
private void handleReset() {
- mWifiStateTracker.clearBlacklist();
+ mWifiManager.clearBlacklist();
setIdleState(true);
}
diff --git a/services/surfaceflinger/LayerBuffer.cpp b/services/surfaceflinger/LayerBuffer.cpp
index 5f83636..e8b2ebf 100644
--- a/services/surfaceflinger/LayerBuffer.cpp
+++ b/services/surfaceflinger/LayerBuffer.cpp
@@ -495,7 +495,7 @@ status_t LayerBuffer::BufferSource::initTempBuffer() const
const ISurface::BufferHeap& buffers(mBufferHeap);
uint32_t w = mLayer.mTransformedBounds.width();
uint32_t h = mLayer.mTransformedBounds.height();
- if (buffers.w * h != buffers.h * w) {
+ if (mLayer.getOrientation() & (Transform::ROT_90 | Transform::ROT_270)) {
int t = w; w = h; h = t;
}
diff --git a/telephony/java/com/android/internal/telephony/CallManager.java b/telephony/java/com/android/internal/telephony/CallManager.java
index 63bdb99..2934e6a 100644
--- a/telephony/java/com/android/internal/telephony/CallManager.java
+++ b/telephony/java/com/android/internal/telephony/CallManager.java
@@ -215,7 +215,7 @@ public final class CallManager {
* @param phone
*/
public void unregisterPhone(Phone phone) {
- if (phone != null && !mPhones.contains(phone)) {
+ if (phone != null && mPhones.contains(phone)) {
mPhones.remove(phone);
mRingingCalls.remove(phone.getRingingCall());
mBackgroundCalls.remove(phone.getBackgroundCall());
diff --git a/telephony/java/com/android/internal/telephony/cat/AppInterface.java b/telephony/java/com/android/internal/telephony/cat/AppInterface.java
index 0ba3e11..2eb6ccb 100644
--- a/telephony/java/com/android/internal/telephony/cat/AppInterface.java
+++ b/telephony/java/com/android/internal/telephony/cat/AppInterface.java
@@ -58,7 +58,8 @@ public interface AppInterface {
SET_UP_EVENT_LIST(0x05),
SET_UP_IDLE_MODE_TEXT(0x28),
SET_UP_MENU(0x25),
- SET_UP_CALL(0x10);
+ SET_UP_CALL(0x10),
+ PROVIDE_LOCAL_INFORMATION(0x26);
private int mValue;
diff --git a/telephony/java/com/android/internal/telephony/cat/CatService.java b/telephony/java/com/android/internal/telephony/cat/CatService.java
index b916713..1e23e34 100644
--- a/telephony/java/com/android/internal/telephony/cat/CatService.java
+++ b/telephony/java/com/android/internal/telephony/cat/CatService.java
@@ -22,6 +22,7 @@ import android.os.AsyncResult;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.Message;
+import android.os.SystemProperties;
import com.android.internal.telephony.IccUtils;
import com.android.internal.telephony.CommandsInterface;
@@ -245,48 +246,46 @@ public class CatService extends Handler implements AppInterface {
CatCmdMessage cmdMsg = new CatCmdMessage(cmdParams);
switch (cmdParams.getCommandType()) {
- case SET_UP_MENU:
- if (removeMenu(cmdMsg.getMenu())) {
- mMenuCmd = null;
- } else {
- mMenuCmd = cmdMsg;
- }
- sendTerminalResponse(cmdParams.cmdDet, ResultCode.OK, false, 0,
- null);
- break;
- case DISPLAY_TEXT:
- // when application is not required to respond, send an immediate
- // response.
- if (!cmdMsg.geTextMessage().responseNeeded) {
- sendTerminalResponse(cmdParams.cmdDet, ResultCode.OK, false,
- 0, null);
- }
- break;
- case REFRESH:
- // ME side only handles refresh commands which meant to remove IDLE
- // MODE TEXT.
- cmdParams.cmdDet.typeOfCommand = CommandType.SET_UP_IDLE_MODE_TEXT
- .value();
- break;
- case SET_UP_IDLE_MODE_TEXT:
- sendTerminalResponse(cmdParams.cmdDet, ResultCode.OK, false,
- 0, null);
- break;
- case LAUNCH_BROWSER:
- case SELECT_ITEM:
- case GET_INPUT:
- case GET_INKEY:
- case SEND_DTMF:
- case SEND_SMS:
- case SEND_SS:
- case SEND_USSD:
- case PLAY_TONE:
- case SET_UP_CALL:
- // nothing to do on telephony!
- break;
- default:
- CatLog.d(this, "Unsupported command");
- return;
+ case SET_UP_MENU:
+ if (removeMenu(cmdMsg.getMenu())) {
+ mMenuCmd = null;
+ } else {
+ mMenuCmd = cmdMsg;
+ }
+ sendTerminalResponse(cmdParams.cmdDet, ResultCode.OK, false, 0, null);
+ break;
+ case DISPLAY_TEXT:
+ // when application is not required to respond, send an immediate response.
+ if (!cmdMsg.geTextMessage().responseNeeded) {
+ sendTerminalResponse(cmdParams.cmdDet, ResultCode.OK, false, 0, null);
+ }
+ break;
+ case REFRESH:
+ // ME side only handles refresh commands which meant to remove IDLE
+ // MODE TEXT.
+ cmdParams.cmdDet.typeOfCommand = CommandType.SET_UP_IDLE_MODE_TEXT.value();
+ break;
+ case SET_UP_IDLE_MODE_TEXT:
+ sendTerminalResponse(cmdParams.cmdDet, ResultCode.OK, false, 0, null);
+ break;
+ case PROVIDE_LOCAL_INFORMATION:
+ sendTerminalResponse(cmdParams.cmdDet, ResultCode.OK, false, 0, null);
+ return;
+ case LAUNCH_BROWSER:
+ case SELECT_ITEM:
+ case GET_INPUT:
+ case GET_INKEY:
+ case SEND_DTMF:
+ case SEND_SMS:
+ case SEND_SS:
+ case SEND_USSD:
+ case PLAY_TONE:
+ case SET_UP_CALL:
+ // nothing to do on telephony!
+ break;
+ default:
+ CatLog.d(this, "Unsupported command");
+ return;
}
mCurrntCmd = cmdMsg;
Intent intent = new Intent(AppInterface.CAT_CMD_ACTION);
@@ -315,6 +314,11 @@ public class CatService extends Handler implements AppInterface {
}
ByteArrayOutputStream buf = new ByteArrayOutputStream();
+ Input cmdInput = null;
+ if (mCurrntCmd != null) {
+ cmdInput = mCurrntCmd.geInput();
+ }
+
// command details
int tag = ComprehensionTlvTag.COMMAND_DETAILS.value();
if (cmdDet.compRequired) {
@@ -327,7 +331,13 @@ public class CatService extends Handler implements AppInterface {
buf.write(cmdDet.commandQualifier);
// device identities
- tag = 0x80 | ComprehensionTlvTag.DEVICE_IDENTITIES.value();
+ // According to TS102.223/TS31.111 section 6.8 Structure of
+ // TERMINAL RESPONSE, "For all SIMPLE-TLV objects with Min=N,
+ // the ME should set the CR(comprehension required) flag to
+ // comprehension not required.(CR=0)"
+ // Since DEVICE_IDENTITIES and DURATION TLVs have Min=N,
+ // the CR flag is not set.
+ tag = ComprehensionTlvTag.DEVICE_IDENTITIES.value();
buf.write(tag);
buf.write(0x02); // length
buf.write(DEV_ID_TERMINAL); // source device id
@@ -348,6 +358,8 @@ public class CatService extends Handler implements AppInterface {
// Fill optional data for each corresponding command
if (resp != null) {
resp.format(buf);
+ } else {
+ encodeOptionalTags(cmdDet, resultCode, cmdInput, buf);
}
byte[] rawData = buf.toByteArray();
@@ -359,6 +371,52 @@ public class CatService extends Handler implements AppInterface {
mCmdIf.sendTerminalResponse(hexString, null);
}
+ private void encodeOptionalTags(CommandDetails cmdDet,
+ ResultCode resultCode, Input cmdInput, ByteArrayOutputStream buf) {
+ switch (AppInterface.CommandType.fromInt(cmdDet.typeOfCommand)) {
+ case GET_INKEY:
+ // ETSI TS 102 384,27.22.4.2.8.4.2.
+ // If it is a response for GET_INKEY command and the response timeout
+ // occured, then add DURATION TLV for variable timeout case.
+ if ((resultCode.value() == ResultCode.NO_RESPONSE_FROM_USER.value()) &&
+ (cmdInput != null) && (cmdInput.duration != null)) {
+ getInKeyResponse(buf, cmdInput);
+ }
+ break;
+ case PROVIDE_LOCAL_INFORMATION:
+ if ((cmdDet.commandQualifier == CommandParamsFactory.LANGUAGE_SETTING) &&
+ (resultCode.value() == ResultCode.OK.value())) {
+ getPliResponse(buf);
+ }
+ break;
+ default:
+ CatLog.d(this, "encodeOptionalTags() Unsupported Cmd:" + cmdDet.typeOfCommand);
+ break;
+ }
+ }
+
+ private void getInKeyResponse(ByteArrayOutputStream buf, Input cmdInput) {
+ int tag = ComprehensionTlvTag.DURATION.value();
+
+ buf.write(tag);
+ buf.write(0x02); // length
+ buf.write(cmdInput.duration.timeUnit.SECOND.value()); // Time (Unit,Seconds)
+ buf.write(cmdInput.duration.timeInterval); // Time Duration
+ }
+
+ private void getPliResponse(ByteArrayOutputStream buf) {
+
+ // Locale Language Setting
+ String lang = SystemProperties.get("persist.sys.language");
+
+ if (lang != null) {
+ // tag
+ int tag = ComprehensionTlvTag.LANGUAGE.value();
+ buf.write(tag);
+ ResponseData.writeLength(buf, lang.length());
+ buf.write(lang.getBytes(), 0, lang.length());
+ }
+ }
private void sendMenuSelection(int menuId, boolean helpRequired) {
diff --git a/telephony/java/com/android/internal/telephony/cat/CommandParamsFactory.java b/telephony/java/com/android/internal/telephony/cat/CommandParamsFactory.java
index edb2dc8..12204a0 100644
--- a/telephony/java/com/android/internal/telephony/cat/CommandParamsFactory.java
+++ b/telephony/java/com/android/internal/telephony/cat/CommandParamsFactory.java
@@ -52,6 +52,9 @@ class CommandParamsFactory extends Handler {
static final int REFRESH_NAA_INIT = 0x03;
static final int REFRESH_UICC_RESET = 0x04;
+ // Command Qualifier values for PLI command
+ static final int LANGUAGE_SETTING = 0x04;
+
static synchronized CommandParamsFactory getInstance(RilMessageDecoder caller,
IccFileHandler fh) {
if (sInstance != null) {
@@ -112,7 +115,10 @@ class CommandParamsFactory extends Handler {
AppInterface.CommandType cmdType = AppInterface.CommandType
.fromInt(cmdDet.typeOfCommand);
if (cmdType == null) {
- sendCmdParams(ResultCode.CMD_TYPE_NOT_UNDERSTOOD);
+ // This PROACTIVE COMMAND is presently not handled. Hence set
+ // result code as BEYOND_TERMINAL_CAPABILITY in TR.
+ mCmdParams = new CommandParams(cmdDet);
+ sendCmdParams(ResultCode.BEYOND_TERMINAL_CAPABILITY);
return;
}
@@ -155,10 +161,13 @@ class CommandParamsFactory extends Handler {
case PLAY_TONE:
cmdPending = processPlayTone(cmdDet, ctlvs);
break;
+ case PROVIDE_LOCAL_INFORMATION:
+ cmdPending = processProvideLocalInfo(cmdDet, ctlvs);
+ break;
default:
// unsupported proactive commands
mCmdParams = new CommandParams(cmdDet);
- sendCmdParams(ResultCode.CMD_TYPE_NOT_UNDERSTOOD);
+ sendCmdParams(ResultCode.BEYOND_TERMINAL_CAPABILITY);
return;
}
} catch (ResultException e) {
@@ -380,6 +389,12 @@ class CommandParamsFactory extends Handler {
iconId = ValueParser.retrieveIconId(ctlv);
}
+ // parse duration
+ ctlv = searchForTag(ComprehensionTlvTag.DURATION, ctlvs);
+ if (ctlv != null) {
+ input.duration = ValueParser.retrieveDuration(ctlv);
+ }
+
input.minLen = 1;
input.maxLen = 1;
@@ -863,4 +878,20 @@ class CommandParamsFactory extends Handler {
}
return false;
}
+
+ private boolean processProvideLocalInfo(CommandDetails cmdDet, List<ComprehensionTlv> ctlvs)
+ throws ResultException {
+ CatLog.d(this, "process ProvideLocalInfo");
+ switch (cmdDet.commandQualifier) {
+ case LANGUAGE_SETTING:
+ CatLog.d(this, "PLI [LANGUAGE_SETTING]");
+ mCmdParams = new CommandParams(cmdDet);
+ break;
+ default:
+ CatLog.d(this, "PLI[" + cmdDet.commandQualifier + "] Command Not Supported");
+ mCmdParams = new CommandParams(cmdDet);
+ throw new ResultException(ResultCode.BEYOND_TERMINAL_CAPABILITY);
+ }
+ return false;
+ }
}
diff --git a/telephony/java/com/android/internal/telephony/cat/Input.java b/telephony/java/com/android/internal/telephony/cat/Input.java
index 8bcaab9..13a5ad4 100644
--- a/telephony/java/com/android/internal/telephony/cat/Input.java
+++ b/telephony/java/com/android/internal/telephony/cat/Input.java
@@ -36,6 +36,7 @@ public class Input implements Parcelable {
public boolean echo;
public boolean yesNo;
public boolean helpAvailable;
+ public Duration duration;
Input() {
text = "";
@@ -49,6 +50,7 @@ public class Input implements Parcelable {
echo = false;
yesNo = false;
helpAvailable = false;
+ duration = null;
}
private Input(Parcel in) {
@@ -63,6 +65,7 @@ public class Input implements Parcelable {
echo = in.readInt() == 1 ? true : false;
yesNo = in.readInt() == 1 ? true : false;
helpAvailable = in.readInt() == 1 ? true : false;
+ duration = in.readParcelable(null);
}
public int describeContents() {
@@ -81,6 +84,7 @@ public class Input implements Parcelable {
dest.writeInt(echo ? 1 : 0);
dest.writeInt(yesNo ? 1 : 0);
dest.writeInt(helpAvailable ? 1 : 0);
+ dest.writeParcelable(duration, 0);
}
public static final Parcelable.Creator<Input> CREATOR = new Parcelable.Creator<Input>() {
diff --git a/telephony/java/com/android/internal/telephony/cat/ResponseData.java b/telephony/java/com/android/internal/telephony/cat/ResponseData.java
index 84c08f8..677d66b 100644
--- a/telephony/java/com/android/internal/telephony/cat/ResponseData.java
+++ b/telephony/java/com/android/internal/telephony/cat/ResponseData.java
@@ -28,6 +28,16 @@ abstract class ResponseData {
* the ByteArrayOutputStream object.
*/
public abstract void format(ByteArrayOutputStream buf);
+
+ public static void writeLength(ByteArrayOutputStream buf, int length) {
+ // As per ETSI 102.220 Sec7.1.2, if the total length is greater
+ // than 0x7F, it should be coded in two bytes and the first byte
+ // should be 0x81.
+ if (length > 0x7F) {
+ buf.write(0x81);
+ }
+ buf.write(length);
+ }
}
class SelectItemResponseData extends ResponseData {
@@ -120,7 +130,7 @@ class GetInkeyInputResponseData extends ResponseData {
}
// length - one more for data coding scheme.
- buf.write(data.length + 1);
+ writeLength(buf, data.length + 1);
// data coding scheme
if (mIsUcs2) {
diff --git a/telephony/java/com/android/internal/telephony/gsm/GSMPhone.java b/telephony/java/com/android/internal/telephony/gsm/GSMPhone.java
index 876c223..2ae5a3c 100644
--- a/telephony/java/com/android/internal/telephony/gsm/GSMPhone.java
+++ b/telephony/java/com/android/internal/telephony/gsm/GSMPhone.java
@@ -974,7 +974,9 @@ public class GSMPhone extends PhoneBase {
}
public void getCallWaiting(Message onComplete) {
- mCM.queryCallWaiting(CommandsInterface.SERVICE_CLASS_VOICE, onComplete);
+ //As per 3GPP TS 24.083, section 1.6 UE doesn't need to send service
+ //class parameter in call waiting interrogation to network
+ mCM.queryCallWaiting(CommandsInterface.SERVICE_CLASS_NONE, onComplete);
}
public void setCallWaiting(boolean enable, Message onComplete) {
diff --git a/tests/DumpRenderTree2/Android.mk b/tests/DumpRenderTree2/Android.mk
index 948ad72..eddbb4b 100644
--- a/tests/DumpRenderTree2/Android.mk
+++ b/tests/DumpRenderTree2/Android.mk
@@ -5,6 +5,8 @@ LOCAL_MODULE_TAGS := tests
LOCAL_SRC_FILES := $(call all-subdir-java-files)
+LOCAL_JAVA_LIBRARIES := android.test.runner
+
LOCAL_STATIC_JAVA_LIBRARIES := diff_match_patch
LOCAL_PACKAGE_NAME := DumpRenderTree2
diff --git a/tests/DumpRenderTree2/AndroidManifest.xml b/tests/DumpRenderTree2/AndroidManifest.xml
index e4bfd59..dd0c4e9 100644
--- a/tests/DumpRenderTree2/AndroidManifest.xml
+++ b/tests/DumpRenderTree2/AndroidManifest.xml
@@ -16,6 +16,8 @@ limitations under the License.
-->
<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.android.dumprendertree2">
<application>
+ <uses-library android:name="android.test.runner" />
+
<activity android:name=".ui.DirListActivity"
android:label="Dump Render Tree 2"
android:configChanges="orientation">
@@ -45,6 +47,10 @@ limitations under the License.
</service>
</application>
+ <instrumentation android:name="com.android.dumprendertree2.scriptsupport.ScriptTestRunner"
+ android:targetPackage="com.android.dumprendertree2"
+ android:label="Layout tests script runner" />
+
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.WRITE_SDCARD" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
diff --git a/tests/DumpRenderTree2/assets/run_layout_tests.py b/tests/DumpRenderTree2/assets/run_layout_tests.py
new file mode 100644
index 0000000..b13d8c9
--- /dev/null
+++ b/tests/DumpRenderTree2/assets/run_layout_tests.py
@@ -0,0 +1,65 @@
+#!/usr/bin/python
+
+"""Run layout tests on the device.
+
+ It runs the specified tests on the device, downloads the summaries to the temporary directory
+ and opens html details in the default browser.
+
+ Usage:
+ run_layout_tests.py PATH
+"""
+
+import sys
+import os
+import subprocess
+import logging
+import webbrowser
+import tempfile
+
+#TODO: These should not be hardcoded
+RESULTS_ABSOLUTE_PATH = "/sdcard/android/LayoutTests-results/"
+DETAILS_HTML = "details.html"
+SUMMARY_TXT = "summary.txt"
+
+def main():
+ if len(sys.argv) > 1:
+ path = sys.argv[1]
+ else:
+ path = ""
+
+ logging.basicConfig(level=logging.INFO, format='%(message)s')
+
+ tmpdir = tempfile.gettempdir()
+
+ # Run the tests in path
+ cmd = "adb shell am instrument "
+ cmd += "-e class com.android.dumprendertree2.scriptsupport.Starter#startLayoutTests "
+ cmd += "-e path \"" + path + "\" "
+ cmd +="-w com.android.dumprendertree2/com.android.dumprendertree2.scriptsupport.ScriptTestRunner"
+
+ logging.info("Running the tests...")
+ subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE).communicate()
+
+ logging.info("Downloading the summaries...")
+
+ # Download the txt summary to tmp folder
+ summary_txt_tmp_path = os.path.join(tmpdir, SUMMARY_TXT)
+ cmd = "adb pull " + RESULTS_ABSOLUTE_PATH + SUMMARY_TXT + " " + summary_txt_tmp_path
+ subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE).communicate()
+
+ # Download the html summary to tmp folder
+ details_html_tmp_path = os.path.join(tmpdir, DETAILS_HTML)
+ cmd = "adb pull " + RESULTS_ABSOLUTE_PATH + DETAILS_HTML + " " + details_html_tmp_path
+ subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE).communicate()
+
+ # Print summary to console
+ logging.info("All done.\n")
+ cmd = "cat " + summary_txt_tmp_path
+ os.system(cmd)
+ logging.info("")
+
+ # Open the browser with summary
+ webbrowser.open(details_html_tmp_path)
+
+if __name__ == "__main__":
+ main();
diff --git a/tests/DumpRenderTree2/src/com/android/dumprendertree2/ManagerService.java b/tests/DumpRenderTree2/src/com/android/dumprendertree2/ManagerService.java
index a8695a0..7ec3dd7 100644
--- a/tests/DumpRenderTree2/src/com/android/dumprendertree2/ManagerService.java
+++ b/tests/DumpRenderTree2/src/com/android/dumprendertree2/ManagerService.java
@@ -82,6 +82,7 @@ public class ManagerService extends Service {
public void handleMessage(Message msg) {
switch (msg.what) {
case MSG_FIRST_TEST:
+ mSummarizer.reset();
Bundle bundle = msg.getData();
ensureNextTestSetup(bundle.getString("firstTest"), bundle.getInt("index"));
break;
diff --git a/tests/DumpRenderTree2/src/com/android/dumprendertree2/Summarizer.java b/tests/DumpRenderTree2/src/com/android/dumprendertree2/Summarizer.java
index d9e7ec0..e27ecc9 100644
--- a/tests/DumpRenderTree2/src/com/android/dumprendertree2/Summarizer.java
+++ b/tests/DumpRenderTree2/src/com/android/dumprendertree2/Summarizer.java
@@ -166,7 +166,7 @@ public class Summarizer {
"</script>";
/** TODO: Make it a setting */
- private static final String HTML_SUMMARY_RELATIVE_PATH = "summary.html";
+ private static final String HTML_DETAILS_RELATIVE_PATH = "details.html";
private static final String TXT_SUMMARY_RELATIVE_PATH = "summary.txt";
private int mCrashedTestsCount = 0;
@@ -201,10 +201,18 @@ public class Summarizer {
}
public void summarize() {
- createHtmlSummary();
+ createHtmlDetails();
createTxtSummary();
}
+ public void reset() {
+ mCrashedTestsCount = 0;
+ mFailedNotIgnoredTests.clear();
+ mIgnoredTests.clear();
+ mPassedNotIgnoredTests.clear();
+ mTitleString = null;
+ }
+
private void createTxtSummary() {
StringBuilder txt = new StringBuilder();
@@ -221,7 +229,7 @@ public class Summarizer {
txt.toString().getBytes(), false);
}
- private void createHtmlSummary() {
+ private void createHtmlDetails() {
StringBuilder html = new StringBuilder();
html.append("<html><head>");
@@ -239,7 +247,7 @@ public class Summarizer {
html.append("</body></html>");
- FsUtils.writeDataToStorage(new File(mResultsRootDirPath, HTML_SUMMARY_RELATIVE_PATH),
+ FsUtils.writeDataToStorage(new File(mResultsRootDirPath, HTML_DETAILS_RELATIVE_PATH),
html.toString().getBytes(), false);
}
diff --git a/tests/DumpRenderTree2/src/com/android/dumprendertree2/TestsListActivity.java b/tests/DumpRenderTree2/src/com/android/dumprendertree2/TestsListActivity.java
index 982fe10..c95199f 100644
--- a/tests/DumpRenderTree2/src/com/android/dumprendertree2/TestsListActivity.java
+++ b/tests/DumpRenderTree2/src/com/android/dumprendertree2/TestsListActivity.java
@@ -24,6 +24,8 @@ import android.os.Handler;
import android.os.Message;
import android.view.Window;
+import com.android.dumprendertree2.scriptsupport.OnEverythingFinishedCallback;
+
import java.util.ArrayList;
/**
@@ -57,6 +59,9 @@ public class TestsListActivity extends Activity {
private ArrayList<String> mTestsList;
private int mTotalTestCount;
+ private OnEverythingFinishedCallback mOnEverythingFinishedCallback;
+ private boolean mEverythingFinished;
+
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
@@ -110,8 +115,19 @@ public class TestsListActivity extends Activity {
}
}
+ public void registerOnEverythingFinishedCallback(OnEverythingFinishedCallback callback) {
+ mOnEverythingFinishedCallback = callback;
+ if (mEverythingFinished) {
+ mOnEverythingFinishedCallback.onFinished();
+ }
+ }
+
private void onEverythingFinishedIntent(Intent intent) {
/** TODO: Show some kind of summary to the user */
+ mEverythingFinished = true;
+ if (mOnEverythingFinishedCallback != null) {
+ mOnEverythingFinishedCallback.onFinished();
+ }
}
@Override
diff --git a/tests/DumpRenderTree2/src/com/android/dumprendertree2/TestsListPreloaderThread.java b/tests/DumpRenderTree2/src/com/android/dumprendertree2/TestsListPreloaderThread.java
index f76105d..2145af7 100644
--- a/tests/DumpRenderTree2/src/com/android/dumprendertree2/TestsListPreloaderThread.java
+++ b/tests/DumpRenderTree2/src/com/android/dumprendertree2/TestsListPreloaderThread.java
@@ -68,15 +68,15 @@ public class TestsListPreloaderThread extends Thread {
File file = new File(TESTS_ROOT_DIR_PATH, mRelativePath);
if (!file.exists()) {
Log.e(LOG_TAG + "::run", "Path does not exist: " + mRelativePath);
- return;
- }
-
- /** Populate the tests' list accordingly */
- if (file.isDirectory()) {
- preloadTests(mRelativePath);
} else {
- mTestsList.add(mRelativePath);
+ /** Populate the tests' list accordingly */
+ if (file.isDirectory()) {
+ preloadTests(mRelativePath);
+ } else {
+ mTestsList.add(mRelativePath);
+ }
}
+
mDoneMsg.obj = mTestsList;
mDoneMsg.sendToTarget();
}
diff --git a/tests/DumpRenderTree2/src/com/android/dumprendertree2/scriptsupport/OnEverythingFinishedCallback.java b/tests/DumpRenderTree2/src/com/android/dumprendertree2/scriptsupport/OnEverythingFinishedCallback.java
new file mode 100644
index 0000000..e1d4364
--- /dev/null
+++ b/tests/DumpRenderTree2/src/com/android/dumprendertree2/scriptsupport/OnEverythingFinishedCallback.java
@@ -0,0 +1,25 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dumprendertree2.scriptsupport;
+
+/**
+ * Callback used to inform scriptsupport.Starter that everything is finished and
+ * we can exit
+ */
+public interface OnEverythingFinishedCallback {
+ public void onFinished();
+} \ No newline at end of file
diff --git a/tests/DumpRenderTree2/src/com/android/dumprendertree2/scriptsupport/ScriptTestRunner.java b/tests/DumpRenderTree2/src/com/android/dumprendertree2/scriptsupport/ScriptTestRunner.java
new file mode 100644
index 0000000..78f58d5
--- /dev/null
+++ b/tests/DumpRenderTree2/src/com/android/dumprendertree2/scriptsupport/ScriptTestRunner.java
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dumprendertree2.scriptsupport;
+
+import android.os.Bundle;
+import android.test.InstrumentationTestRunner;
+
+/**
+ * Extends InstrumentationTestRunner to allow the script to pass arguments to the application
+ */
+public class ScriptTestRunner extends InstrumentationTestRunner {
+ String mTestsRelativePath;
+
+ @Override
+ public void onCreate(Bundle arguments) {
+ mTestsRelativePath = arguments.getString("path");
+ super.onCreate(arguments);
+ }
+
+ public String getTestsRelativePath() {
+ return mTestsRelativePath;
+ }
+} \ No newline at end of file
diff --git a/tests/DumpRenderTree2/src/com/android/dumprendertree2/scriptsupport/Starter.java b/tests/DumpRenderTree2/src/com/android/dumprendertree2/scriptsupport/Starter.java
new file mode 100644
index 0000000..ddfae69
--- /dev/null
+++ b/tests/DumpRenderTree2/src/com/android/dumprendertree2/scriptsupport/Starter.java
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dumprendertree2.scriptsupport;
+
+import android.content.Intent;
+import android.test.ActivityInstrumentationTestCase2;
+import android.util.Log;
+
+import com.android.dumprendertree2.TestsListActivity;
+
+/**
+ * A class which provides methods that can be invoked by a script running on the host machine to
+ * run the tests.
+ *
+ * It starts a TestsListActivity and does not return until all the tests finish executing.
+ */
+public class Starter extends ActivityInstrumentationTestCase2<TestsListActivity> {
+ private static final String LOG_TAG = "Starter";
+ private boolean mEverythingFinished;
+
+ public Starter() {
+ super(TestsListActivity.class);
+ }
+
+ /**
+ * This method is called from adb to start executing the tests. It doesn't return
+ * until everything is finished so that the script can wait for the end if it needs
+ * to.
+ */
+ public void startLayoutTests() {
+ ScriptTestRunner runner = (ScriptTestRunner)getInstrumentation();
+ String relativePath = runner.getTestsRelativePath();
+
+ Intent intent = new Intent();
+ intent.setClassName("com.android.dumprendertree2", "TestsListActivity");
+ intent.setAction(Intent.ACTION_RUN);
+ intent.putExtra(TestsListActivity.EXTRA_TEST_PATH, relativePath);
+ setActivityIntent(intent);
+ getActivity().registerOnEverythingFinishedCallback(new OnEverythingFinishedCallback() {
+ /** This method is safe to call on any thread */
+ @Override
+ public void onFinished() {
+ synchronized (Starter.this) {
+ mEverythingFinished = true;
+ Starter.this.notifyAll();
+ }
+ }
+ });
+
+ synchronized (this) {
+ while (!mEverythingFinished) {
+ try {
+ this.wait();
+ } catch (InterruptedException e) {
+ Log.e(LOG_TAG + "::startLayoutTests", e.getMessage());
+ }
+ }
+ }
+ }
+} \ No newline at end of file
diff --git a/tests/DumpRenderTree2/src/com/android/dumprendertree2/ui/DirListActivity.java b/tests/DumpRenderTree2/src/com/android/dumprendertree2/ui/DirListActivity.java
index 661a8ec..af0d7d1 100644
--- a/tests/DumpRenderTree2/src/com/android/dumprendertree2/ui/DirListActivity.java
+++ b/tests/DumpRenderTree2/src/com/android/dumprendertree2/ui/DirListActivity.java
@@ -378,6 +378,10 @@ public class DirListActivity extends ListActivity {
private ListItem[] getDirList(String dirPath) {
File dir = new File(mRootDirPath, dirPath);
+ if (!dir.exists()) {
+ return new ListItem[0];
+ }
+
List<ListItem> subDirs = new ArrayList<ListItem>();
List<ListItem> subFiles = new ArrayList<ListItem>();
diff --git a/tools/aapt/Android.mk b/tools/aapt/Android.mk
index b339a2c..094b7db 100644
--- a/tools/aapt/Android.mk
+++ b/tools/aapt/Android.mk
@@ -41,7 +41,7 @@ LOCAL_STATIC_LIBRARIES := \
libpng
ifeq ($(HOST_OS),linux)
-LOCAL_LDLIBS += -lrt
+LOCAL_LDLIBS += -lrt -lpthread
endif
# Statically link libz for MinGW (Win SDK under Linux),
diff --git a/tools/localize/Android.mk b/tools/localize/Android.mk
index ab79f8d..f284e86 100644
--- a/tools/localize/Android.mk
+++ b/tools/localize/Android.mk
@@ -34,7 +34,7 @@ LOCAL_STATIC_LIBRARIES := \
libcutils
ifeq ($(HOST_OS),linux)
-LOCAL_LDLIBS += -lrt
+LOCAL_LDLIBS += -lrt -lpthread
endif
diff --git a/tools/obbtool/Android.mk b/tools/obbtool/Android.mk
new file mode 100644
index 0000000..b02c1cb
--- /dev/null
+++ b/tools/obbtool/Android.mk
@@ -0,0 +1,30 @@
+#
+# Copyright 2010 The Android Open Source Project
+#
+# Opaque Binary Blob (OBB) Tool
+#
+
+# This tool is prebuilt if we're doing an app-only build.
+ifeq ($(TARGET_BUILD_APPS),)
+
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := \
+ Main.cpp
+
+#LOCAL_C_INCLUDES +=
+
+LOCAL_STATIC_LIBRARIES := \
+ libutils \
+ libcutils
+
+ifeq ($(HOST_OS),linux)
+LOCAL_LDLIBS += -lpthread
+endif
+
+LOCAL_MODULE := obbtool
+
+include $(BUILD_HOST_EXECUTABLE)
+
+endif # TARGET_BUILD_APPS
diff --git a/tools/obbtool/Main.cpp b/tools/obbtool/Main.cpp
new file mode 100644
index 0000000..2a9bf04
--- /dev/null
+++ b/tools/obbtool/Main.cpp
@@ -0,0 +1,225 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <utils/ObbFile.h>
+#include <utils/String8.h>
+
+#include <getopt.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+using namespace android;
+
+static const char* gProgName = "obbtool";
+static const char* gProgVersion = "1.0";
+
+static int wantUsage = 0;
+static int wantVersion = 0;
+
+#define ADD_OPTS "n:v:f:c:"
+static const struct option longopts[] = {
+ {"help", no_argument, &wantUsage, 1},
+ {"version", no_argument, &wantVersion, 1},
+
+ /* Args for "add" */
+ {"name", required_argument, NULL, 'n'},
+ {"version", required_argument, NULL, 'v'},
+ {"filesystem", required_argument, NULL, 'f'},
+ {"crypto", required_argument, NULL, 'c'},
+
+ {NULL, 0, NULL, '\0'}
+};
+
+struct package_info_t {
+ char* packageName;
+ int packageVersion;
+ char* filesystem;
+ char* crypto;
+};
+
+/*
+ * Print usage info.
+ */
+void usage(void)
+{
+ fprintf(stderr, "Opaque Binary Blob (OBB) Tool\n\n");
+ fprintf(stderr, "Usage:\n");
+ fprintf(stderr,
+ " %s a[dd] [ OPTIONS ] FILENAME\n"
+ " Adds an OBB signature to the file.\n\n", gProgName);
+ fprintf(stderr,
+ " %s r[emove] FILENAME\n"
+ " Removes the OBB signature from the file.\n\n", gProgName);
+ fprintf(stderr,
+ " %s i[nfo] FILENAME\n"
+ " Prints the OBB signature information of a file.\n\n", gProgName);
+}
+
+void doAdd(const char* filename, struct package_info_t* info) {
+ ObbFile *obb = new ObbFile();
+ if (obb->readFrom(filename)) {
+ fprintf(stderr, "ERROR: %s: OBB signature already present\n", filename);
+ return;
+ }
+
+ obb->setPackageName(String8(info->packageName));
+ obb->setVersion(info->packageVersion);
+
+ if (!obb->writeTo(filename)) {
+ fprintf(stderr, "ERROR: %s: couldn't write OBB signature: %s\n",
+ filename, strerror(errno));
+ return;
+ }
+
+ fprintf(stderr, "OBB signature successfully written\n");
+}
+
+void doRemove(const char* filename) {
+ ObbFile *obb = new ObbFile();
+ if (!obb->readFrom(filename)) {
+ fprintf(stderr, "ERROR: %s: no OBB signature present\n", filename);
+ return;
+ }
+
+ if (!obb->removeFrom(filename)) {
+ fprintf(stderr, "ERROR: %s: couldn't remove OBB signature\n", filename);
+ return;
+ }
+
+ fprintf(stderr, "OBB signature successfully removed\n");
+}
+
+void doInfo(const char* filename) {
+ ObbFile *obb = new ObbFile();
+ if (!obb->readFrom(filename)) {
+ fprintf(stderr, "ERROR: %s: couldn't read OBB signature\n", filename);
+ return;
+ }
+
+ printf("OBB info for '%s':\n", filename);
+ printf("Package name: %s\n", obb->getPackageName().string());
+ printf(" Version: %d\n", obb->getVersion());
+}
+
+/*
+ * Parse args.
+ */
+int main(int argc, char* const argv[])
+{
+ const char *prog = argv[0];
+ struct options *options;
+ int opt;
+ int option_index = 0;
+ struct package_info_t package_info;
+
+ int result = 1; // pessimistically assume an error.
+
+ if (argc < 2) {
+ wantUsage = 1;
+ goto bail;
+ }
+
+ while ((opt = getopt_long(argc, argv, ADD_OPTS, longopts, &option_index)) != -1) {
+ switch (opt) {
+ case 0:
+ if (longopts[option_index].flag)
+ break;
+ fprintf(stderr, "'%s' requires an argument\n", longopts[option_index].name);
+ wantUsage = 1;
+ goto bail;
+ case 'n':
+ package_info.packageName = optarg;
+ break;
+ case 'v':
+ char *end;
+ package_info.packageVersion = strtol(optarg, &end, 10);
+ if (*optarg == '\0' || *end != '\0') {
+ fprintf(stderr, "ERROR: invalid version; should be integer!\n\n");
+ wantUsage = 1;
+ goto bail;
+ }
+ break;
+ case 'f':
+ package_info.filesystem = optarg;
+ break;
+ case 'c':
+ package_info.crypto = optarg;
+ break;
+ case '?':
+ wantUsage = 1;
+ goto bail;
+ }
+ }
+
+ if (wantVersion) {
+ fprintf(stderr, "%s %s\n", gProgName, gProgVersion);
+ }
+
+ if (wantUsage) {
+ goto bail;
+ }
+
+#define CHECK_OP(name) \
+ if (strncmp(op, name, opsize)) { \
+ fprintf(stderr, "ERROR: unknown function '%s'!\n\n", op); \
+ wantUsage = 1; \
+ goto bail; \
+ }
+
+ if (optind < argc) {
+ const char* op = argv[optind++];
+ const int opsize = strlen(op);
+
+ if (optind >= argc) {
+ fprintf(stderr, "ERROR: filename required!\n\n");
+ wantUsage = 1;
+ goto bail;
+ }
+
+ const char* filename = argv[optind++];
+
+ switch (op[0]) {
+ case 'a':
+ CHECK_OP("add");
+ if (package_info.packageName == NULL) {
+ fprintf(stderr, "ERROR: arguments required 'packageName' and 'version'\n");
+ goto bail;
+ }
+ doAdd(filename, &package_info);
+ break;
+ case 'r':
+ CHECK_OP("remove");
+ doRemove(filename);
+ break;
+ case 'i':
+ CHECK_OP("info");
+ doInfo(filename);
+ break;
+ default:
+ fprintf(stderr, "ERROR: unknown command '%s'!\n\n", op);
+ wantUsage = 1;
+ goto bail;
+ }
+ }
+
+bail:
+ if (wantUsage) {
+ usage();
+ result = 2;
+ }
+
+ return result;
+}
diff --git a/wifi/java/android/net/wifi/IWifiManager.aidl b/wifi/java/android/net/wifi/IWifiManager.aidl
index 6e0bc9d..3426af7 100644
--- a/wifi/java/android/net/wifi/IWifiManager.aidl
+++ b/wifi/java/android/net/wifi/IWifiManager.aidl
@@ -85,5 +85,13 @@ interface IWifiManager
WifiConfiguration getWifiApConfiguration();
void setWifiApConfiguration(in WifiConfiguration wifiConfig);
+
+ void startWifi();
+
+ void stopWifi();
+
+ void addToBlacklist(String bssid);
+
+ void clearBlacklist();
}
diff --git a/wifi/java/android/net/wifi/WifiManager.java b/wifi/java/android/net/wifi/WifiManager.java
index 6fac902..339763a 100644
--- a/wifi/java/android/net/wifi/WifiManager.java
+++ b/wifi/java/android/net/wifi/WifiManager.java
@@ -293,6 +293,21 @@ public class WifiManager {
public static final String EXTRA_NEW_RSSI = "newRssi";
/**
+ * Broadcast intent action indicating that the IP configuration
+ * changed on wifi.
+ * @hide
+ */
+ @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
+ public static final String CONFIG_CHANGED_ACTION = "android.net.wifi.CONFIG_CHANGED";
+ /**
+ * The lookup key for a {@link android.net.NetworkProperties} object associated with the
+ * Wi-Fi network. Retrieve with
+ * {@link android.content.Intent#getParcelableExtra(String)}.
+ * @hide
+ */
+ public static final String EXTRA_NETWORK_PROPERTIES = "networkProperties";
+
+ /**
* The network IDs of the configured networks could have changed.
*/
@SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
@@ -838,6 +853,82 @@ public class WifiManager {
}
}
+ /**
+ * Start the driver and connect to network.
+ *
+ * This function will over-ride WifiLock and device idle status. For example,
+ * even if the device is idle or there is only a scan-only lock held,
+ * a start wifi would mean that wifi connection is kept active until
+ * a stopWifi() is sent.
+ *
+ * This API is used by WifiStateTracker
+ *
+ * @return {@code true} if the operation succeeds else {@code false}
+ * @hide
+ */
+ public boolean startWifi() {
+ try {
+ mService.startWifi();
+ return true;
+ } catch (RemoteException e) {
+ return false;
+ }
+ }
+
+ /**
+ * Disconnect from a network (if any) and stop the driver.
+ *
+ * This function will over-ride WifiLock and device idle status. Wi-Fi
+ * stays inactive until a startWifi() is issued.
+ *
+ * This API is used by WifiStateTracker
+ *
+ * @return {@code true} if the operation succeeds else {@code false}
+ * @hide
+ */
+ public boolean stopWifi() {
+ try {
+ mService.stopWifi();
+ return true;
+ } catch (RemoteException e) {
+ return false;
+ }
+ }
+
+ /**
+ * Add a bssid to the supplicant blacklist
+ *
+ * This API is used by WifiWatchdogService
+ *
+ * @return {@code true} if the operation succeeds else {@code false}
+ * @hide
+ */
+ public boolean addToBlacklist(String bssid) {
+ try {
+ mService.addToBlacklist(bssid);
+ return true;
+ } catch (RemoteException e) {
+ return false;
+ }
+ }
+
+ /**
+ * Clear the supplicant blacklist
+ *
+ * This API is used by WifiWatchdogService
+ *
+ * @return {@code true} if the operation succeeds else {@code false}
+ * @hide
+ */
+ public boolean clearBlacklist() {
+ try {
+ mService.clearBlacklist();
+ return true;
+ } catch (RemoteException e) {
+ return false;
+ }
+ }
+
/**
* Allows an application to keep the Wi-Fi radio awake.
* Normally the Wi-Fi radio may turn off when the user has not used the device in a while.
diff --git a/wifi/java/android/net/wifi/WifiMonitor.java b/wifi/java/android/net/wifi/WifiMonitor.java
index f2f8343..af3132f 100644
--- a/wifi/java/android/net/wifi/WifiMonitor.java
+++ b/wifi/java/android/net/wifi/WifiMonitor.java
@@ -19,14 +19,13 @@ package android.net.wifi;
import android.util.Log;
import android.util.Config;
import android.net.NetworkInfo;
-import android.net.NetworkStateTracker;
import java.util.regex.Pattern;
import java.util.regex.Matcher;
/**
* Listens for events from the wpa_supplicant server, and passes them on
- * to the {@link WifiStateTracker} for handling. Runs in its own thread.
+ * to the {@link WifiStateMachine} for handling. Runs in its own thread.
*
* @hide
*/
@@ -117,7 +116,7 @@ public class WifiMonitor {
private static Pattern mConnectedEventPattern =
Pattern.compile("((?:[0-9a-f]{2}:){5}[0-9a-f]{2}) .* \\[id=([0-9]+) ");
- private final WifiStateTracker mWifiStateTracker;
+ private final WifiStateMachine mWifiStateMachine;
/**
* This indicates the supplicant connection for the monitor is closed
@@ -139,18 +138,14 @@ public class WifiMonitor {
*/
private static final int MAX_RECV_ERRORS = 10;
- public WifiMonitor(WifiStateTracker tracker) {
- mWifiStateTracker = tracker;
+ public WifiMonitor(WifiStateMachine wifiStateMachine) {
+ mWifiStateMachine = wifiStateMachine;
}
public void startMonitoring() {
new MonitorThread().start();
}
- public NetworkStateTracker getNetworkStateTracker() {
- return mWifiStateTracker;
- }
-
class MonitorThread extends Thread {
public MonitorThread() {
super("WifiMonitor");
@@ -161,9 +156,9 @@ public class WifiMonitor {
if (connectToSupplicant()) {
// Send a message indicating that it is now possible to send commands
// to the supplicant
- mWifiStateTracker.notifySupplicantConnection();
+ mWifiStateMachine.notifySupplicantConnection();
} else {
- mWifiStateTracker.notifySupplicantLost();
+ mWifiStateMachine.notifySupplicantLost();
return;
}
@@ -259,7 +254,7 @@ public class WifiMonitor {
}
// notify and exit
- mWifiStateTracker.notifySupplicantLost();
+ mWifiStateMachine.notifySupplicantLost();
break;
} else {
handleEvent(event, eventData);
@@ -285,7 +280,7 @@ public class WifiMonitor {
}
private void handlePasswordKeyMayBeIncorrect() {
- mWifiStateTracker.notifyPasswordKeyMayBeIncorrect();
+ mWifiStateMachine.notifyPasswordKeyMayBeIncorrect();
}
private void handleDriverEvent(String state) {
@@ -293,11 +288,11 @@ public class WifiMonitor {
return;
}
if (state.equals("STOPPED")) {
- mWifiStateTracker.notifyDriverStopped();
+ mWifiStateMachine.notifyDriverStopped();
} else if (state.equals("STARTED")) {
- mWifiStateTracker.notifyDriverStarted();
+ mWifiStateMachine.notifyDriverStarted();
} else if (state.equals("HANGED")) {
- mWifiStateTracker.notifyDriverHung();
+ mWifiStateMachine.notifyDriverHung();
}
}
@@ -318,7 +313,7 @@ public class WifiMonitor {
break;
case SCAN_RESULTS:
- mWifiStateTracker.notifyScanResultsAvailable();
+ mWifiStateMachine.notifyScanResultsAvailable();
break;
case UNKNOWN:
@@ -375,7 +370,7 @@ public class WifiMonitor {
if (newSupplicantState == SupplicantState.INVALID) {
Log.w(TAG, "Invalid supplicant state: " + newState);
}
- mWifiStateTracker.notifySupplicantStateChange(networkId, BSSID, newSupplicantState);
+ mWifiStateMachine.notifySupplicantStateChange(networkId, BSSID, newSupplicantState);
}
}
@@ -395,7 +390,7 @@ public class WifiMonitor {
}
}
}
- mWifiStateTracker.notifyNetworkStateChange(newState, BSSID, networkId);
+ mWifiStateMachine.notifyNetworkStateChange(newState, BSSID, networkId);
}
/**
diff --git a/wifi/java/android/net/wifi/WifiStateMachine.java b/wifi/java/android/net/wifi/WifiStateMachine.java
new file mode 100644
index 0000000..845508b
--- /dev/null
+++ b/wifi/java/android/net/wifi/WifiStateMachine.java
@@ -0,0 +1,3571 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net.wifi;
+
+import static android.net.wifi.WifiManager.WIFI_STATE_DISABLED;
+import static android.net.wifi.WifiManager.WIFI_STATE_DISABLING;
+import static android.net.wifi.WifiManager.WIFI_STATE_ENABLED;
+import static android.net.wifi.WifiManager.WIFI_STATE_ENABLING;
+import static android.net.wifi.WifiManager.WIFI_STATE_UNKNOWN;
+
+/**
+ * TODO: Add soft AP states as part of WIFI_STATE_XXX
+ * Retain WIFI_STATE_ENABLING that indicates driver is loading
+ * Add WIFI_STATE_AP_ENABLED to indicate soft AP has started
+ * and WIFI_STATE_FAILED for failure
+ * Deprecate WIFI_STATE_UNKNOWN
+ *
+ * Doing this will simplify the logic for sending broadcasts
+ */
+import static android.net.wifi.WifiManager.WIFI_AP_STATE_DISABLED;
+import static android.net.wifi.WifiManager.WIFI_AP_STATE_DISABLING;
+import static android.net.wifi.WifiManager.WIFI_AP_STATE_ENABLED;
+import static android.net.wifi.WifiManager.WIFI_AP_STATE_ENABLING;
+import static android.net.wifi.WifiManager.WIFI_AP_STATE_FAILED;
+
+import android.app.ActivityManagerNative;
+import android.net.NetworkInfo;
+import android.net.DhcpInfo;
+import android.net.NetworkUtils;
+import android.net.ConnectivityManager;
+import android.net.NetworkInfo.DetailedState;
+import android.net.NetworkProperties;
+import android.os.Binder;
+import android.os.Message;
+import android.os.Parcelable;
+import android.os.Handler;
+import android.os.IBinder;
+import android.os.INetworkManagementService;
+import android.os.PowerManager;
+import android.os.SystemProperties;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+import android.os.Process;
+import android.provider.Settings;
+import android.text.TextUtils;
+import android.util.EventLog;
+import android.util.Log;
+import android.util.Slog;
+import android.app.backup.IBackupManager;
+import android.bluetooth.BluetoothDevice;
+import android.bluetooth.BluetoothHeadset;
+import android.bluetooth.BluetoothA2dp;
+import android.content.ContentResolver;
+import android.content.Intent;
+import android.content.Context;
+import android.database.ContentObserver;
+import com.android.internal.app.IBatteryStats;
+import com.android.internal.util.HierarchicalState;
+import com.android.internal.util.HierarchicalStateMachine;
+
+import java.net.InetAddress;
+import java.net.NetworkInterface;
+import java.net.SocketException;
+import java.net.UnknownHostException;
+import java.util.ArrayList;
+import java.util.BitSet;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.concurrent.atomic.AtomicInteger;
+import java.util.regex.Pattern;
+
+/**
+ * Track the state of Wifi connectivity. All event handling is done here,
+ * and all changes in connectivity state are initiated here.
+ *
+ * @hide
+ */
+//TODO: we still need frequent scanning for the case when
+// we issue disconnect but need scan results for open network notification
+public class WifiStateMachine extends HierarchicalStateMachine {
+
+ private static final String TAG = "WifiStateMachine";
+ private static final String NETWORKTYPE = "WIFI";
+ private static final boolean DBG = false;
+
+ /* TODO: fetch a configurable interface */
+ private static final String SOFTAP_IFACE = "wl0.1";
+
+ private WifiMonitor mWifiMonitor;
+ private INetworkManagementService nwService;
+ private ConnectivityManager mCm;
+
+ /* Scan results handling */
+ private List<ScanResult> mScanResults;
+ private static final Pattern scanResultPattern = Pattern.compile("\t+");
+ private static final int SCAN_RESULT_CACHE_SIZE = 80;
+ private final LinkedHashMap<String, ScanResult> mScanResultCache;
+
+ private String mInterfaceName;
+
+ private int mNumAllowedChannels = 0;
+ private int mLastSignalLevel = -1;
+ private String mLastBssid;
+ private int mLastNetworkId;
+ private boolean mEnableRssiPolling = false;
+ private boolean mPasswordKeyMayBeIncorrect = false;
+ private boolean mUseStaticIp = false;
+ private int mReconnectCount = 0;
+ private boolean mIsScanMode = false;
+ private boolean mConfigChanged = false;
+
+ /**
+ * Instance of the bluetooth headset helper. This needs to be created
+ * early because there is a delay before it actually 'connects', as
+ * noted by its javadoc. If we check before it is connected, it will be
+ * in an error state and we will not disable coexistence.
+ */
+ private BluetoothHeadset mBluetoothHeadset;
+
+ private BluetoothA2dp mBluetoothA2dp;
+
+ /**
+ * Observes the static IP address settings.
+ */
+ private SettingsObserver mSettingsObserver;
+ private NetworkProperties mNetworkProperties;
+
+ // Held during driver load and unload
+ private static PowerManager.WakeLock sWakeLock;
+
+ private Context mContext;
+
+ private DhcpInfo mDhcpInfo;
+ private WifiInfo mWifiInfo;
+ private NetworkInfo mNetworkInfo;
+ private SupplicantStateTracker mSupplicantStateTracker;
+
+ // Event log tags (must be in sync with event-log-tags)
+ private static final int EVENTLOG_WIFI_STATE_CHANGED = 50021;
+ private static final int EVENTLOG_WIFI_EVENT_HANDLED = 50022;
+ private static final int EVENTLOG_SUPPLICANT_STATE_CHANGED = 50023;
+
+ /* Load the driver */
+ private static final int CMD_LOAD_DRIVER = 1;
+ /* Unload the driver */
+ private static final int CMD_UNLOAD_DRIVER = 2;
+ /* Indicates driver load succeeded */
+ private static final int CMD_LOAD_DRIVER_SUCCESS = 3;
+ /* Indicates driver load failed */
+ private static final int CMD_LOAD_DRIVER_FAILURE = 4;
+ /* Indicates driver unload succeeded */
+ private static final int CMD_UNLOAD_DRIVER_SUCCESS = 5;
+ /* Indicates driver unload failed */
+ private static final int CMD_UNLOAD_DRIVER_FAILURE = 6;
+
+ /* Start the supplicant */
+ private static final int CMD_START_SUPPLICANT = 11;
+ /* Stop the supplicant */
+ private static final int CMD_STOP_SUPPLICANT = 12;
+ /* Start the driver */
+ private static final int CMD_START_DRIVER = 13;
+ /* Start the driver */
+ private static final int CMD_STOP_DRIVER = 14;
+ /* Indicates DHCP succeded */
+ private static final int CMD_IP_CONFIG_SUCCESS = 15;
+ /* Indicates DHCP failed */
+ private static final int CMD_IP_CONFIG_FAILURE = 16;
+ /* Re-configure interface */
+ private static final int CMD_RECONFIGURE_IP = 17;
+
+
+ /* Start the soft access point */
+ private static final int CMD_START_AP = 21;
+ /* Stop the soft access point */
+ private static final int CMD_STOP_AP = 22;
+
+
+ /* Supplicant events */
+ /* Connection to supplicant established */
+ private static final int SUP_CONNECTION_EVENT = 31;
+ /* Connection to supplicant lost */
+ private static final int SUP_DISCONNECTION_EVENT = 32;
+ /* Driver start completed */
+ private static final int DRIVER_START_EVENT = 33;
+ /* Driver stop completed */
+ private static final int DRIVER_STOP_EVENT = 34;
+ /* Network connection completed */
+ private static final int NETWORK_CONNECTION_EVENT = 36;
+ /* Network disconnection completed */
+ private static final int NETWORK_DISCONNECTION_EVENT = 37;
+ /* Scan results are available */
+ private static final int SCAN_RESULTS_EVENT = 38;
+ /* Supplicate state changed */
+ private static final int SUPPLICANT_STATE_CHANGE_EVENT = 39;
+ /* Password may be incorrect */
+ private static final int PASSWORD_MAY_BE_INCORRECT_EVENT = 40;
+
+ /* Supplicant commands */
+ /* Is supplicant alive ? */
+ private static final int CMD_PING_SUPPLICANT = 51;
+ /* Add/update a network configuration */
+ private static final int CMD_ADD_OR_UPDATE_NETWORK = 52;
+ /* Delete a network */
+ private static final int CMD_REMOVE_NETWORK = 53;
+ /* Enable a network. The device will attempt a connection to the given network. */
+ private static final int CMD_ENABLE_NETWORK = 54;
+ /* Disable a network. The device does not attempt a connection to the given network. */
+ private static final int CMD_DISABLE_NETWORK = 55;
+ /* Blacklist network. De-prioritizes the given BSSID for connection. */
+ private static final int CMD_BLACKLIST_NETWORK = 56;
+ /* Clear the blacklist network list */
+ private static final int CMD_CLEAR_BLACKLIST = 57;
+ /* Get the configured networks */
+ private static final int CMD_GET_NETWORK_CONFIG = 58;
+ /* Save configuration */
+ private static final int CMD_SAVE_CONFIG = 59;
+ /* Connection status */
+ private static final int CMD_CONNECTION_STATUS = 60;
+
+ /* Supplicant commands after driver start*/
+ /* Initiate a scan */
+ private static final int CMD_START_SCAN = 71;
+ /* Set scan mode. CONNECT_MODE or SCAN_ONLY_MODE */
+ private static final int CMD_SET_SCAN_MODE = 72;
+ /* Set scan type. SCAN_ACTIVE or SCAN_PASSIVE */
+ private static final int CMD_SET_SCAN_TYPE = 73;
+ /* Disconnect from a network */
+ private static final int CMD_DISCONNECT = 74;
+ /* Reconnect to a network */
+ private static final int CMD_RECONNECT = 75;
+ /* Reassociate to a network */
+ private static final int CMD_REASSOCIATE = 76;
+ /* Set power mode
+ * POWER_MODE_ACTIVE
+ * POWER_MODE_AUTO
+ */
+ private static final int CMD_SET_POWER_MODE = 77;
+ /* Set bluetooth co-existence
+ * BLUETOOTH_COEXISTENCE_MODE_ENABLED
+ * BLUETOOTH_COEXISTENCE_MODE_DISABLED
+ * BLUETOOTH_COEXISTENCE_MODE_SENSE
+ */
+ private static final int CMD_SET_BLUETOOTH_COEXISTENCE = 78;
+ /* Enable/disable bluetooth scan mode
+ * true(1)
+ * false(0)
+ */
+ private static final int CMD_SET_BLUETOOTH_SCAN_MODE = 79;
+ /* Set number of allowed channels */
+ private static final int CMD_SET_NUM_ALLOWED_CHANNELS = 80;
+ /* Request connectivity manager wake lock before driver stop */
+ private static final int CMD_REQUEST_CM_WAKELOCK = 81;
+ /* Enables RSSI poll */
+ private static final int CMD_ENABLE_RSSI_POLL = 82;
+ /* RSSI poll */
+ private static final int CMD_RSSI_POLL = 83;
+ /* Get current RSSI */
+ private static final int CMD_GET_RSSI = 84;
+ /* Get approx current RSSI */
+ private static final int CMD_GET_RSSI_APPROX = 85;
+ /* Get link speed on connection */
+ private static final int CMD_GET_LINK_SPEED = 86;
+ /* Radio mac address */
+ private static final int CMD_GET_MAC_ADDR = 87;
+ /* Set up packet filtering */
+ private static final int CMD_START_PACKET_FILTERING = 88;
+ /* Clear packet filter */
+ private static final int CMD_STOP_PACKET_FILTERING = 89;
+
+ /**
+ * Interval in milliseconds between polling for connection
+ * status items that are not sent via asynchronous events.
+ * An example is RSSI (signal strength).
+ */
+ private static final int POLL_RSSI_INTERVAL_MSECS = 3000;
+
+ private static final int CONNECT_MODE = 1;
+ private static final int SCAN_ONLY_MODE = 2;
+
+ private static final int SCAN_ACTIVE = 1;
+ private static final int SCAN_PASSIVE = 2;
+
+ /**
+ * The maximum number of times we will retry a connection to an access point
+ * for which we have failed in acquiring an IP address from DHCP. A value of
+ * N means that we will make N+1 connection attempts in all.
+ * <p>
+ * See {@link Settings.Secure#WIFI_MAX_DHCP_RETRY_COUNT}. This is the default
+ * value if a Settings value is not present.
+ */
+ private static final int DEFAULT_MAX_DHCP_RETRIES = 9;
+
+ private static final int DRIVER_POWER_MODE_ACTIVE = 1;
+ private static final int DRIVER_POWER_MODE_AUTO = 0;
+
+ /* Default parent state */
+ private HierarchicalState mDefaultState = new DefaultState();
+ /* Temporary initial state */
+ private HierarchicalState mInitialState = new InitialState();
+ /* Unloading the driver */
+ private HierarchicalState mDriverUnloadingState = new DriverUnloadingState();
+ /* Loading the driver */
+ private HierarchicalState mDriverUnloadedState = new DriverUnloadedState();
+ /* Driver load/unload failed */
+ private HierarchicalState mDriverFailedState = new DriverFailedState();
+ /* Driver loading */
+ private HierarchicalState mDriverLoadingState = new DriverLoadingState();
+ /* Driver loaded */
+ private HierarchicalState mDriverLoadedState = new DriverLoadedState();
+ /* Driver loaded, waiting for supplicant to start */
+ private HierarchicalState mWaitForSupState = new WaitForSupState();
+
+ /* Driver loaded and supplicant ready */
+ private HierarchicalState mDriverSupReadyState = new DriverSupReadyState();
+ /* Driver start issued, waiting for completed event */
+ private HierarchicalState mDriverStartingState = new DriverStartingState();
+ /* Driver started */
+ private HierarchicalState mDriverStartedState = new DriverStartedState();
+ /* Driver stopping */
+ private HierarchicalState mDriverStoppingState = new DriverStoppingState();
+ /* Driver stopped */
+ private HierarchicalState mDriverStoppedState = new DriverStoppedState();
+ /* Scan for networks, no connection will be established */
+ private HierarchicalState mScanModeState = new ScanModeState();
+ /* Connecting to an access point */
+ private HierarchicalState mConnectModeState = new ConnectModeState();
+ /* Fetching IP after network connection (assoc+auth complete) */
+ private HierarchicalState mConnectingState = new ConnectingState();
+ /* Connected with IP addr */
+ private HierarchicalState mConnectedState = new ConnectedState();
+ /* disconnect issued, waiting for network disconnect confirmation */
+ private HierarchicalState mDisconnectingState = new DisconnectingState();
+ /* Network is not connected, supplicant assoc+auth is not complete */
+ private HierarchicalState mDisconnectedState = new DisconnectedState();
+
+ /* Soft Ap is running */
+ private HierarchicalState mSoftApStartedState = new SoftApStartedState();
+
+ /* Argument for Message object to indicate a synchronous call */
+ private static final int SYNCHRONOUS_CALL = 1;
+ private static final int ASYNCHRONOUS_CALL = 0;
+
+
+ /**
+ * One of {@link WifiManager#WIFI_STATE_DISABLED},
+ * {@link WifiManager#WIFI_STATE_DISABLING},
+ * {@link WifiManager#WIFI_STATE_ENABLED},
+ * {@link WifiManager#WIFI_STATE_ENABLING},
+ * {@link WifiManager#WIFI_STATE_UNKNOWN}
+ *
+ */
+ private final AtomicInteger mWifiState = new AtomicInteger(WIFI_STATE_DISABLED);
+
+ /**
+ * One of {@link WifiManager#WIFI_AP_STATE_DISABLED},
+ * {@link WifiManager#WIFI_AP_STATE_DISABLING},
+ * {@link WifiManager#WIFI_AP_STATE_ENABLED},
+ * {@link WifiManager#WIFI_AP_STATE_ENABLING},
+ * {@link WifiManager#WIFI_AP_STATE_FAILED}
+ *
+ */
+ private final AtomicInteger mWifiApState = new AtomicInteger(WIFI_AP_STATE_DISABLED);
+
+ private final AtomicInteger mLastEnableUid = new AtomicInteger(Process.myUid());
+ private final AtomicInteger mLastApEnableUid = new AtomicInteger(Process.myUid());
+
+ private final IBatteryStats mBatteryStats;
+
+ public WifiStateMachine(Context context) {
+ super(TAG);
+
+ mContext = context;
+
+ mNetworkInfo = new NetworkInfo(ConnectivityManager.TYPE_WIFI, 0, NETWORKTYPE, "");
+ mBatteryStats = IBatteryStats.Stub.asInterface(ServiceManager.getService("batteryinfo"));
+
+ IBinder b = ServiceManager.getService(Context.NETWORKMANAGEMENT_SERVICE);
+ nwService = INetworkManagementService.Stub.asInterface(b);
+
+ mWifiMonitor = new WifiMonitor(this);
+ mDhcpInfo = new DhcpInfo();
+ mWifiInfo = new WifiInfo();
+ mInterfaceName = SystemProperties.get("wifi.interface", "tiwlan0");
+ mSupplicantStateTracker = new SupplicantStateTracker(context, getHandler());
+
+ mBluetoothHeadset = new BluetoothHeadset(mContext, null);
+ mNetworkProperties = new NetworkProperties();
+
+ mNetworkInfo.setIsAvailable(false);
+ mNetworkProperties.clear();
+ mLastBssid = null;
+ mLastNetworkId = -1;
+ mLastSignalLevel = -1;
+
+ mScanResultCache = new LinkedHashMap<String, ScanResult>(
+ SCAN_RESULT_CACHE_SIZE, 0.75f, true) {
+ /*
+ * Limit the cache size by SCAN_RESULT_CACHE_SIZE
+ * elements
+ */
+ @Override
+ public boolean removeEldestEntry(Map.Entry eldest) {
+ return SCAN_RESULT_CACHE_SIZE < this.size();
+ }
+ };
+
+ mSettingsObserver = new SettingsObserver(new Handler());
+
+ PowerManager powerManager = (PowerManager)mContext.getSystemService(Context.POWER_SERVICE);
+ sWakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, TAG);
+
+ addState(mDefaultState);
+ addState(mInitialState, mDefaultState);
+ addState(mDriverUnloadingState, mDefaultState);
+ addState(mDriverUnloadedState, mDefaultState);
+ addState(mDriverFailedState, mDriverUnloadedState);
+ addState(mDriverLoadingState, mDefaultState);
+ addState(mDriverLoadedState, mDefaultState);
+ addState(mWaitForSupState, mDriverLoadedState);
+ addState(mDriverSupReadyState, mDefaultState);
+ addState(mDriverStartingState, mDriverSupReadyState);
+ addState(mDriverStartedState, mDriverSupReadyState);
+ addState(mScanModeState, mDriverStartedState);
+ addState(mConnectModeState, mDriverStartedState);
+ addState(mConnectingState, mConnectModeState);
+ addState(mConnectedState, mConnectModeState);
+ addState(mDisconnectingState, mConnectModeState);
+ addState(mDisconnectedState, mConnectModeState);
+ addState(mDriverStoppingState, mDriverSupReadyState);
+ addState(mDriverStoppedState, mDriverSupReadyState);
+ addState(mSoftApStartedState, mDefaultState);
+
+ setInitialState(mInitialState);
+
+ if (DBG) setDbg(true);
+
+ //start the state machine
+ start();
+ }
+
+ /*********************************************************
+ * Methods exposed for public use
+ ********************************************************/
+
+ /**
+ * TODO: doc
+ */
+ public boolean pingSupplicant() {
+ return sendSyncMessage(CMD_PING_SUPPLICANT).boolValue;
+ }
+
+ /**
+ * TODO: doc
+ */
+ public boolean startScan(boolean forceActive) {
+ return sendSyncMessage(obtainMessage(CMD_START_SCAN, forceActive ?
+ SCAN_ACTIVE : SCAN_PASSIVE, 0)).boolValue;
+ }
+
+ /**
+ * TODO: doc
+ */
+ public void setWifiEnabled(boolean enable) {
+ mLastEnableUid.set(Binder.getCallingUid());
+ if (enable) {
+ /* Argument is the state that is entered prior to load */
+ sendMessage(obtainMessage(CMD_LOAD_DRIVER, WIFI_STATE_ENABLING, 0));
+ sendMessage(CMD_START_SUPPLICANT);
+ } else {
+ sendMessage(CMD_STOP_SUPPLICANT);
+ /* Argument is the state that is entered upon success */
+ sendMessage(obtainMessage(CMD_UNLOAD_DRIVER, WIFI_STATE_DISABLED, 0));
+ }
+ }
+
+ /**
+ * TODO: doc
+ */
+ public void setWifiApEnabled(WifiConfiguration wifiConfig, boolean enable) {
+ mLastApEnableUid.set(Binder.getCallingUid());
+ if (enable) {
+ /* Argument is the state that is entered prior to load */
+ sendMessage(obtainMessage(CMD_LOAD_DRIVER, WIFI_AP_STATE_ENABLING, 0));
+ sendMessage(obtainMessage(CMD_START_AP, wifiConfig));
+ } else {
+ sendMessage(CMD_STOP_AP);
+ /* Argument is the state that is entered upon success */
+ sendMessage(obtainMessage(CMD_UNLOAD_DRIVER, WIFI_AP_STATE_DISABLED, 0));
+ }
+ }
+
+ /**
+ * TODO: doc
+ */
+ public int getWifiState() {
+ return mWifiState.get();
+ }
+
+ /**
+ * TODO: doc
+ */
+ public String getWifiStateByName() {
+ switch (mWifiState.get()) {
+ case WIFI_STATE_DISABLING:
+ return "disabling";
+ case WIFI_STATE_DISABLED:
+ return "disabled";
+ case WIFI_STATE_ENABLING:
+ return "enabling";
+ case WIFI_STATE_ENABLED:
+ return "enabled";
+ case WIFI_STATE_UNKNOWN:
+ return "unknown state";
+ default:
+ return "[invalid state]";
+ }
+ }
+
+ /**
+ * TODO: doc
+ */
+ public int getWifiApState() {
+ return mWifiApState.get();
+ }
+
+ /**
+ * TODO: doc
+ */
+ public String getWifiApStateByName() {
+ switch (mWifiApState.get()) {
+ case WIFI_AP_STATE_DISABLING:
+ return "disabling";
+ case WIFI_AP_STATE_DISABLED:
+ return "disabled";
+ case WIFI_AP_STATE_ENABLING:
+ return "enabling";
+ case WIFI_AP_STATE_ENABLED:
+ return "enabled";
+ case WIFI_AP_STATE_FAILED:
+ return "failed";
+ default:
+ return "[invalid state]";
+ }
+ }
+
+ /**
+ * Get status information for the current connection, if any.
+ * @return a {@link WifiInfo} object containing information about the current connection
+ *
+ */
+ public WifiInfo requestConnectionInfo() {
+ return mWifiInfo;
+ }
+
+ public DhcpInfo getDhcpInfo() {
+ return mDhcpInfo;
+ }
+
+ /**
+ * TODO: doc
+ */
+ public void setDriverStart(boolean enable) {
+ if (enable) {
+ sendMessage(CMD_START_DRIVER);
+ } else {
+ sendMessage(CMD_STOP_DRIVER);
+ }
+ }
+
+ /**
+ * TODO: doc
+ */
+ public void setScanOnlyMode(boolean enable) {
+ if (enable) {
+ sendMessage(obtainMessage(CMD_SET_SCAN_MODE, SCAN_ONLY_MODE, 0));
+ } else {
+ sendMessage(obtainMessage(CMD_SET_SCAN_MODE, CONNECT_MODE, 0));
+ }
+ }
+
+ /**
+ * TODO: doc
+ */
+ public void setScanType(boolean active) {
+ if (active) {
+ sendMessage(obtainMessage(CMD_SET_SCAN_TYPE, SCAN_ACTIVE, 0));
+ } else {
+ sendMessage(obtainMessage(CMD_SET_SCAN_TYPE, SCAN_PASSIVE, 0));
+ }
+ }
+
+ /**
+ * TODO: doc
+ */
+ public List<ScanResult> getScanResultsList() {
+ return mScanResults;
+ }
+
+ /**
+ * Disconnect from Access Point
+ */
+ public boolean disconnectCommand() {
+ return sendSyncMessage(CMD_DISCONNECT).boolValue;
+ }
+
+ /**
+ * Initiate a reconnection to AP
+ */
+ public boolean reconnectCommand() {
+ return sendSyncMessage(CMD_RECONNECT).boolValue;
+ }
+
+ /**
+ * Initiate a re-association to AP
+ */
+ public boolean reassociateCommand() {
+ return sendSyncMessage(CMD_REASSOCIATE).boolValue;
+ }
+
+ /**
+ * Add a network synchronously
+ *
+ * @return network id of the new network
+ */
+ public int addOrUpdateNetwork(WifiConfiguration config) {
+ return sendSyncMessage(CMD_ADD_OR_UPDATE_NETWORK, config).intValue;
+ }
+
+ public List<WifiConfiguration> getConfiguredNetworks() {
+ return sendSyncMessage(CMD_GET_NETWORK_CONFIG).configList;
+ }
+
+ /**
+ * Delete a network
+ *
+ * @param networkId id of the network to be removed
+ */
+ public boolean removeNetwork(int networkId) {
+ return sendSyncMessage(obtainMessage(CMD_REMOVE_NETWORK, networkId, 0)).boolValue;
+ }
+
+ private class EnableNetParams {
+ private int netId;
+ private boolean disableOthers;
+ EnableNetParams(int n, boolean b) {
+ netId = n;
+ disableOthers = b;
+ }
+ }
+ /**
+ * Enable a network
+ *
+ * @param netId network id of the network
+ * @param disableOthers true, if all other networks have to be disabled
+ * @return {@code true} if the operation succeeds, {@code false} otherwise
+ */
+ public boolean enableNetwork(int netId, boolean disableOthers) {
+ return sendSyncMessage(CMD_ENABLE_NETWORK,
+ new EnableNetParams(netId, disableOthers)).boolValue;
+ }
+
+ /**
+ * Disable a network
+ *
+ * @param netId network id of the network
+ * @return {@code true} if the operation succeeds, {@code false} otherwise
+ */
+ public boolean disableNetwork(int netId) {
+ return sendSyncMessage(obtainMessage(CMD_DISABLE_NETWORK, netId, 0)).boolValue;
+ }
+
+ /**
+ * Blacklist a BSSID. This will avoid the AP if there are
+ * alternate APs to connect
+ *
+ * @param bssid BSSID of the network
+ */
+ public void addToBlacklist(String bssid) {
+ sendMessage(obtainMessage(CMD_BLACKLIST_NETWORK, bssid));
+ }
+
+ /**
+ * Clear the blacklist list
+ *
+ */
+ public void clearBlacklist() {
+ sendMessage(obtainMessage(CMD_CLEAR_BLACKLIST));
+ }
+
+ /**
+ * Get detailed status of the connection
+ *
+ * @return Example status result
+ * bssid=aa:bb:cc:dd:ee:ff
+ * ssid=TestNet
+ * id=3
+ * pairwise_cipher=NONE
+ * group_cipher=NONE
+ * key_mgmt=NONE
+ * wpa_state=COMPLETED
+ * ip_address=X.X.X.X
+ */
+ public String status() {
+ return sendSyncMessage(CMD_CONNECTION_STATUS).stringValue;
+ }
+
+ public void enableRssiPolling(boolean enabled) {
+ sendMessage(obtainMessage(CMD_ENABLE_RSSI_POLL, enabled ? 1 : 0, 0));
+ }
+ /**
+ * Get RSSI to currently connected network
+ *
+ * @return RSSI value, -1 on failure
+ */
+ public int getRssi() {
+ return sendSyncMessage(CMD_GET_RSSI).intValue;
+ }
+
+ /**
+ * Get approx RSSI to currently connected network
+ *
+ * @return RSSI value, -1 on failure
+ */
+ public int getRssiApprox() {
+ return sendSyncMessage(CMD_GET_RSSI_APPROX).intValue;
+ }
+
+ /**
+ * Get link speed to currently connected network
+ *
+ * @return link speed, -1 on failure
+ */
+ public int getLinkSpeed() {
+ return sendSyncMessage(CMD_GET_LINK_SPEED).intValue;
+ }
+
+ /**
+ * Get MAC address of radio
+ *
+ * @return MAC address, null on failure
+ */
+ public String getMacAddress() {
+ return sendSyncMessage(CMD_GET_MAC_ADDR).stringValue;
+ }
+
+ /**
+ * Start packet filtering
+ */
+ public void startPacketFiltering() {
+ sendMessage(CMD_START_PACKET_FILTERING);
+ }
+
+ /**
+ * Stop packet filtering
+ */
+ public void stopPacketFiltering() {
+ sendMessage(CMD_STOP_PACKET_FILTERING);
+ }
+
+ /**
+ * Set power mode
+ * @param mode
+ * DRIVER_POWER_MODE_AUTO
+ * DRIVER_POWER_MODE_ACTIVE
+ */
+ public void setPowerMode(int mode) {
+ sendMessage(obtainMessage(CMD_SET_POWER_MODE, mode, 0));
+ }
+
+ /**
+ * Set the number of allowed radio frequency channels from the system
+ * setting value, if any.
+ */
+ public void setNumAllowedChannels() {
+ try {
+ setNumAllowedChannels(
+ Settings.Secure.getInt(mContext.getContentResolver(),
+ Settings.Secure.WIFI_NUM_ALLOWED_CHANNELS));
+ } catch (Settings.SettingNotFoundException e) {
+ if (mNumAllowedChannels != 0) {
+ setNumAllowedChannels(mNumAllowedChannels);
+ }
+ // otherwise, use the driver default
+ }
+ }
+
+ /**
+ * Set the number of radio frequency channels that are allowed to be used
+ * in the current regulatory domain.
+ * @param numChannels the number of allowed channels. Must be greater than 0
+ * and less than or equal to 16.
+ */
+ public void setNumAllowedChannels(int numChannels) {
+ sendMessage(obtainMessage(CMD_SET_NUM_ALLOWED_CHANNELS, numChannels, 0));
+ }
+
+ /**
+ * Get number of allowed channels
+ *
+ * @return channel count, -1 on failure
+ *
+ * TODO: this is not a public API and needs to be removed in favor
+ * of asynchronous reporting. unused for now.
+ */
+ public int getNumAllowedChannels() {
+ return -1;
+ }
+
+ /**
+ * Set bluetooth coex mode:
+ *
+ * @param mode
+ * BLUETOOTH_COEXISTENCE_MODE_ENABLED
+ * BLUETOOTH_COEXISTENCE_MODE_DISABLED
+ * BLUETOOTH_COEXISTENCE_MODE_SENSE
+ */
+ public void setBluetoothCoexistenceMode(int mode) {
+ sendMessage(obtainMessage(CMD_SET_BLUETOOTH_COEXISTENCE, mode, 0));
+ }
+
+ /**
+ * Enable or disable Bluetooth coexistence scan mode. When this mode is on,
+ * some of the low-level scan parameters used by the driver are changed to
+ * reduce interference with A2DP streaming.
+ *
+ * @param isBluetoothPlaying whether to enable or disable this mode
+ */
+ public void setBluetoothScanMode(boolean isBluetoothPlaying) {
+ sendMessage(obtainMessage(CMD_SET_BLUETOOTH_SCAN_MODE, isBluetoothPlaying ? 1 : 0, 0));
+ }
+
+ /**
+ * Save configuration on supplicant
+ *
+ * @return {@code true} if the operation succeeds, {@code false} otherwise
+ *
+ * TODO: deprecate this
+ */
+ public boolean saveConfig() {
+ return sendSyncMessage(CMD_SAVE_CONFIG).boolValue;
+ }
+
+ /**
+ * TODO: doc
+ */
+ public void requestCmWakeLock() {
+ sendMessage(CMD_REQUEST_CM_WAKELOCK);
+ }
+
+ /*********************************************************
+ * Internal private functions
+ ********************************************************/
+
+ class SyncReturn {
+ boolean boolValue;
+ int intValue;
+ String stringValue;
+ Object objValue;
+ List<WifiConfiguration> configList;
+ }
+
+ class SyncParams {
+ Object mParameter;
+ SyncReturn mSyncReturn;
+ SyncParams() {
+ mSyncReturn = new SyncReturn();
+ }
+ SyncParams(Object p) {
+ mParameter = p;
+ mSyncReturn = new SyncReturn();
+ }
+ }
+
+ /**
+ * message.arg2 is reserved to indicate synchronized
+ * message.obj is used to store SyncParams
+ */
+ private SyncReturn syncedSend(Message msg) {
+ SyncParams syncParams = (SyncParams) msg.obj;
+ msg.arg2 = SYNCHRONOUS_CALL;
+ synchronized(syncParams) {
+ if (DBG) Log.d(TAG, "syncedSend " + msg);
+ sendMessage(msg);
+ try {
+ syncParams.wait();
+ } catch (InterruptedException e) {
+ Log.e(TAG, "sendSyncMessage: unexpected interruption of wait()");
+ return null;
+ }
+ }
+ return syncParams.mSyncReturn;
+ }
+
+ private SyncReturn sendSyncMessage(Message msg) {
+ SyncParams syncParams = new SyncParams();
+ msg.obj = syncParams;
+ return syncedSend(msg);
+ }
+
+ private SyncReturn sendSyncMessage(int what, Object param) {
+ SyncParams syncParams = new SyncParams(param);
+ Message msg = obtainMessage(what, syncParams);
+ return syncedSend(msg);
+ }
+
+
+ private SyncReturn sendSyncMessage(int what) {
+ return sendSyncMessage(obtainMessage(what));
+ }
+
+ private void notifyOnMsgObject(Message msg) {
+ SyncParams syncParams = (SyncParams) msg.obj;
+ if (syncParams != null) {
+ synchronized(syncParams) {
+ if (DBG) Log.d(TAG, "notifyOnMsgObject " + msg);
+ syncParams.notify();
+ }
+ }
+ else {
+ Log.e(TAG, "Error! syncParams in notifyOnMsgObject is null");
+ }
+ }
+
+ private void setWifiState(int wifiState) {
+ final int previousWifiState = mWifiState.get();
+
+ try {
+ if (wifiState == WIFI_STATE_ENABLED) {
+ mBatteryStats.noteWifiOn(mLastEnableUid.get());
+ } else if (wifiState == WIFI_STATE_DISABLED) {
+ mBatteryStats.noteWifiOff(mLastEnableUid.get());
+ }
+ } catch (RemoteException e) {
+ Log.e(TAG, "Failed to note battery stats in wifi");
+ }
+
+ mWifiState.set(wifiState);
+
+ if (DBG) Log.d(TAG, "setWifiState: " + getWifiStateByName());
+
+ final Intent intent = new Intent(WifiManager.WIFI_STATE_CHANGED_ACTION);
+ intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
+ intent.putExtra(WifiManager.EXTRA_WIFI_STATE, wifiState);
+ intent.putExtra(WifiManager.EXTRA_PREVIOUS_WIFI_STATE, previousWifiState);
+ mContext.sendStickyBroadcast(intent);
+ }
+
+ private void setWifiApState(int wifiApState) {
+ final int previousWifiApState = mWifiApState.get();
+
+ try {
+ if (wifiApState == WIFI_AP_STATE_ENABLED) {
+ mBatteryStats.noteWifiOn(mLastApEnableUid.get());
+ } else if (wifiApState == WIFI_AP_STATE_DISABLED) {
+ mBatteryStats.noteWifiOff(mLastApEnableUid.get());
+ }
+ } catch (RemoteException e) {
+ Log.d(TAG, "Failed to note battery stats in wifi");
+ }
+
+ // Update state
+ mWifiApState.set(wifiApState);
+
+ if (DBG) Log.d(TAG, "setWifiApState: " + getWifiApStateByName());
+
+ final Intent intent = new Intent(WifiManager.WIFI_AP_STATE_CHANGED_ACTION);
+ intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
+ intent.putExtra(WifiManager.EXTRA_WIFI_AP_STATE, wifiApState);
+ intent.putExtra(WifiManager.EXTRA_PREVIOUS_WIFI_AP_STATE, previousWifiApState);
+ mContext.sendStickyBroadcast(intent);
+ }
+
+ /**
+ * Parse the scan result line passed to us by wpa_supplicant (helper).
+ * @param line the line to parse
+ * @return the {@link ScanResult} object
+ */
+ private ScanResult parseScanResult(String line) {
+ ScanResult scanResult = null;
+ if (line != null) {
+ /*
+ * Cache implementation (LinkedHashMap) is not synchronized, thus,
+ * must synchronized here!
+ */
+ synchronized (mScanResultCache) {
+ String[] result = scanResultPattern.split(line);
+ if (3 <= result.length && result.length <= 5) {
+ String bssid = result[0];
+ // bssid | frequency | level | flags | ssid
+ int frequency;
+ int level;
+ try {
+ frequency = Integer.parseInt(result[1]);
+ level = Integer.parseInt(result[2]);
+ /* some implementations avoid negative values by adding 256
+ * so we need to adjust for that here.
+ */
+ if (level > 0) level -= 256;
+ } catch (NumberFormatException e) {
+ frequency = 0;
+ level = 0;
+ }
+
+ /*
+ * The formatting of the results returned by
+ * wpa_supplicant is intended to make the fields
+ * line up nicely when printed,
+ * not to make them easy to parse. So we have to
+ * apply some heuristics to figure out which field
+ * is the SSID and which field is the flags.
+ */
+ String ssid;
+ String flags;
+ if (result.length == 4) {
+ if (result[3].charAt(0) == '[') {
+ flags = result[3];
+ ssid = "";
+ } else {
+ flags = "";
+ ssid = result[3];
+ }
+ } else if (result.length == 5) {
+ flags = result[3];
+ ssid = result[4];
+ } else {
+ // Here, we must have 3 fields: no flags and ssid
+ // set
+ flags = "";
+ ssid = "";
+ }
+
+ // bssid + ssid is the hash key
+ String key = bssid + ssid;
+ scanResult = mScanResultCache.get(key);
+ if (scanResult != null) {
+ scanResult.level = level;
+ scanResult.SSID = ssid;
+ scanResult.capabilities = flags;
+ scanResult.frequency = frequency;
+ } else {
+ // Do not add scan results that have no SSID set
+ if (0 < ssid.trim().length()) {
+ scanResult =
+ new ScanResult(
+ ssid, bssid, flags, level, frequency);
+ mScanResultCache.put(key, scanResult);
+ }
+ }
+ } else {
+ Log.w(TAG, "Misformatted scan result text with " +
+ result.length + " fields: " + line);
+ }
+ }
+ }
+
+ return scanResult;
+ }
+
+ /**
+ * scanResults input format
+ * 00:bb:cc:dd:cc:ee 2427 166 [WPA-EAP-TKIP][WPA2-EAP-CCMP] Net1
+ * 00:bb:cc:dd:cc:ff 2412 165 [WPA-EAP-TKIP][WPA2-EAP-CCMP] Net2
+ */
+ private void setScanResults(String scanResults) {
+ if (scanResults == null) {
+ return;
+ }
+
+ List<ScanResult> scanList = new ArrayList<ScanResult>();
+
+ int lineCount = 0;
+
+ int scanResultsLen = scanResults.length();
+ // Parse the result string, keeping in mind that the last line does
+ // not end with a newline.
+ for (int lineBeg = 0, lineEnd = 0; lineEnd <= scanResultsLen; ++lineEnd) {
+ if (lineEnd == scanResultsLen || scanResults.charAt(lineEnd) == '\n') {
+ ++lineCount;
+
+ if (lineCount == 1) {
+ lineBeg = lineEnd + 1;
+ continue;
+ }
+ if (lineEnd > lineBeg) {
+ String line = scanResults.substring(lineBeg, lineEnd);
+ ScanResult scanResult = parseScanResult(line);
+ if (scanResult != null) {
+ scanList.add(scanResult);
+ } else {
+ Log.w(TAG, "misformatted scan result for: " + line);
+ }
+ }
+ lineBeg = lineEnd + 1;
+ }
+ }
+
+ mScanResults = scanList;
+ }
+
+ private void configureNetworkProperties() {
+ try {
+ mNetworkProperties.setInterface(NetworkInterface.getByName(mInterfaceName));
+ } catch (SocketException e) {
+ Log.e(TAG, "SocketException creating NetworkInterface from " + mInterfaceName +
+ ". e=" + e);
+ return;
+ } catch (NullPointerException e) {
+ Log.e(TAG, "NPE creating NetworkInterface. e=" + e);
+ return;
+ }
+ // TODO - fix this for v6
+ try {
+ mNetworkProperties.addAddress(InetAddress.getByAddress(
+ NetworkUtils.v4IntToArray(mDhcpInfo.ipAddress)));
+ } catch (UnknownHostException e) {
+ Log.e(TAG, "Exception setting IpAddress using " + mDhcpInfo + ", e=" + e);
+ }
+
+ try {
+ mNetworkProperties.setGateway(InetAddress.getByAddress(NetworkUtils.v4IntToArray(
+ mDhcpInfo.gateway)));
+ } catch (UnknownHostException e) {
+ Log.e(TAG, "Exception setting Gateway using " + mDhcpInfo + ", e=" + e);
+ }
+
+ try {
+ mNetworkProperties.addDns(InetAddress.getByAddress(
+ NetworkUtils.v4IntToArray(mDhcpInfo.dns1)));
+ } catch (UnknownHostException e) {
+ Log.e(TAG, "Exception setting Dns1 using " + mDhcpInfo + ", e=" + e);
+ }
+ try {
+ mNetworkProperties.addDns(InetAddress.getByAddress(
+ NetworkUtils.v4IntToArray(mDhcpInfo.dns2)));
+
+ } catch (UnknownHostException e) {
+ Log.e(TAG, "Exception setting Dns2 using " + mDhcpInfo + ", e=" + e);
+ }
+ // TODO - add proxy info
+ }
+
+
+ private void checkUseStaticIp() {
+ mUseStaticIp = false;
+ final ContentResolver cr = mContext.getContentResolver();
+ try {
+ if (Settings.System.getInt(cr, Settings.System.WIFI_USE_STATIC_IP) == 0) {
+ return;
+ }
+ } catch (Settings.SettingNotFoundException e) {
+ return;
+ }
+
+ try {
+ String addr = Settings.System.getString(cr, Settings.System.WIFI_STATIC_IP);
+ if (addr != null) {
+ mDhcpInfo.ipAddress = stringToIpAddr(addr);
+ } else {
+ return;
+ }
+ addr = Settings.System.getString(cr, Settings.System.WIFI_STATIC_GATEWAY);
+ if (addr != null) {
+ mDhcpInfo.gateway = stringToIpAddr(addr);
+ } else {
+ return;
+ }
+ addr = Settings.System.getString(cr, Settings.System.WIFI_STATIC_NETMASK);
+ if (addr != null) {
+ mDhcpInfo.netmask = stringToIpAddr(addr);
+ } else {
+ return;
+ }
+ addr = Settings.System.getString(cr, Settings.System.WIFI_STATIC_DNS1);
+ if (addr != null) {
+ mDhcpInfo.dns1 = stringToIpAddr(addr);
+ } else {
+ return;
+ }
+ addr = Settings.System.getString(cr, Settings.System.WIFI_STATIC_DNS2);
+ if (addr != null) {
+ mDhcpInfo.dns2 = stringToIpAddr(addr);
+ } else {
+ mDhcpInfo.dns2 = 0;
+ }
+ } catch (UnknownHostException e) {
+ return;
+ }
+ mUseStaticIp = true;
+ }
+
+ private static int stringToIpAddr(String addrString) throws UnknownHostException {
+ try {
+ String[] parts = addrString.split("\\.");
+ if (parts.length != 4) {
+ throw new UnknownHostException(addrString);
+ }
+
+ int a = Integer.parseInt(parts[0]) ;
+ int b = Integer.parseInt(parts[1]) << 8;
+ int c = Integer.parseInt(parts[2]) << 16;
+ int d = Integer.parseInt(parts[3]) << 24;
+
+ return a | b | c | d;
+ } catch (NumberFormatException ex) {
+ throw new UnknownHostException(addrString);
+ }
+ }
+
+ private int getMaxDhcpRetries() {
+ return Settings.Secure.getInt(mContext.getContentResolver(),
+ Settings.Secure.WIFI_MAX_DHCP_RETRY_COUNT,
+ DEFAULT_MAX_DHCP_RETRIES);
+ }
+
+ private class SettingsObserver extends ContentObserver {
+ public SettingsObserver(Handler handler) {
+ super(handler);
+ ContentResolver cr = mContext.getContentResolver();
+ cr.registerContentObserver(Settings.System.getUriFor(
+ Settings.System.WIFI_USE_STATIC_IP), false, this);
+ cr.registerContentObserver(Settings.System.getUriFor(
+ Settings.System.WIFI_STATIC_IP), false, this);
+ cr.registerContentObserver(Settings.System.getUriFor(
+ Settings.System.WIFI_STATIC_GATEWAY), false, this);
+ cr.registerContentObserver(Settings.System.getUriFor(
+ Settings.System.WIFI_STATIC_NETMASK), false, this);
+ cr.registerContentObserver(Settings.System.getUriFor(
+ Settings.System.WIFI_STATIC_DNS1), false, this);
+ cr.registerContentObserver(Settings.System.getUriFor(
+ Settings.System.WIFI_STATIC_DNS2), false, this);
+ }
+
+ @Override
+ public void onChange(boolean selfChange) {
+ super.onChange(selfChange);
+
+ boolean wasStaticIp = mUseStaticIp;
+ int oIp, oGw, oMsk, oDns1, oDns2;
+ oIp = oGw = oMsk = oDns1 = oDns2 = 0;
+ if (wasStaticIp) {
+ oIp = mDhcpInfo.ipAddress;
+ oGw = mDhcpInfo.gateway;
+ oMsk = mDhcpInfo.netmask;
+ oDns1 = mDhcpInfo.dns1;
+ oDns2 = mDhcpInfo.dns2;
+ }
+ checkUseStaticIp();
+
+ if (mWifiInfo.getSupplicantState() == SupplicantState.UNINITIALIZED) {
+ return;
+ }
+
+ boolean changed =
+ (wasStaticIp != mUseStaticIp) ||
+ (wasStaticIp && (
+ oIp != mDhcpInfo.ipAddress ||
+ oGw != mDhcpInfo.gateway ||
+ oMsk != mDhcpInfo.netmask ||
+ oDns1 != mDhcpInfo.dns1 ||
+ oDns2 != mDhcpInfo.dns2));
+
+ if (changed) {
+ sendMessage(CMD_RECONFIGURE_IP);
+ mConfigChanged = true;
+ }
+ }
+ }
+
+ /**
+ * Whether to disable coexistence mode while obtaining IP address. This
+ * logic will return true only if the current bluetooth
+ * headset/handsfree state is disconnected. This means if it is in an
+ * error state, we will NOT disable coexistence mode to err on the side
+ * of safety.
+ *
+ * @return Whether to disable coexistence mode.
+ */
+ private boolean shouldDisableCoexistenceMode() {
+ int state = mBluetoothHeadset.getState(mBluetoothHeadset.getCurrentHeadset());
+ return state == BluetoothHeadset.STATE_DISCONNECTED;
+ }
+
+ private void checkIsBluetoothPlaying() {
+ boolean isBluetoothPlaying = false;
+ Set<BluetoothDevice> connected = mBluetoothA2dp.getConnectedSinks();
+
+ for (BluetoothDevice device : connected) {
+ if (mBluetoothA2dp.getSinkState(device) == BluetoothA2dp.STATE_PLAYING) {
+ isBluetoothPlaying = true;
+ break;
+ }
+ }
+ setBluetoothScanMode(isBluetoothPlaying);
+ }
+
+ private void sendScanResultsAvailableBroadcast() {
+ if (!ActivityManagerNative.isSystemReady()) return;
+
+ mContext.sendBroadcast(new Intent(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION));
+ }
+
+ private void sendRssiChangeBroadcast(final int newRssi) {
+ if (!ActivityManagerNative.isSystemReady()) return;
+
+ Intent intent = new Intent(WifiManager.RSSI_CHANGED_ACTION);
+ intent.putExtra(WifiManager.EXTRA_NEW_RSSI, newRssi);
+ mContext.sendBroadcast(intent);
+ }
+
+ private void sendNetworkStateChangeBroadcast(String bssid) {
+ Intent intent = new Intent(WifiManager.NETWORK_STATE_CHANGED_ACTION);
+ intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT
+ | Intent.FLAG_RECEIVER_REPLACE_PENDING);
+ intent.putExtra(WifiManager.EXTRA_NETWORK_INFO, mNetworkInfo);
+ intent.putExtra(WifiManager.EXTRA_NETWORK_PROPERTIES, mNetworkProperties);
+ if (bssid != null)
+ intent.putExtra(WifiManager.EXTRA_BSSID, bssid);
+ mContext.sendStickyBroadcast(intent);
+ }
+
+ private void sendConfigChangeBroadcast() {
+ Intent intent = new Intent(WifiManager.CONFIG_CHANGED_ACTION);
+ intent.putExtra(WifiManager.EXTRA_NETWORK_PROPERTIES, mNetworkProperties);
+ mContext.sendBroadcast(intent);
+ }
+
+ private void sendSupplicantStateChangedBroadcast(StateChangeResult sc, boolean failedAuth) {
+ Intent intent = new Intent(WifiManager.SUPPLICANT_STATE_CHANGED_ACTION);
+ intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT
+ | Intent.FLAG_RECEIVER_REPLACE_PENDING);
+ intent.putExtra(WifiManager.EXTRA_NEW_STATE, (Parcelable)sc.state);
+ if (failedAuth) {
+ intent.putExtra(
+ WifiManager.EXTRA_SUPPLICANT_ERROR,
+ WifiManager.ERROR_AUTHENTICATING);
+ }
+ mContext.sendStickyBroadcast(intent);
+ }
+
+ private void sendSupplicantConnectionChangedBroadcast(boolean connected) {
+ if (!ActivityManagerNative.isSystemReady()) return;
+
+ Intent intent = new Intent(WifiManager.SUPPLICANT_CONNECTION_CHANGE_ACTION);
+ intent.putExtra(WifiManager.EXTRA_SUPPLICANT_CONNECTED, connected);
+ mContext.sendBroadcast(intent);
+ }
+
+ /**
+ * Record the detailed state of a network.
+ * @param state the new @{code DetailedState}
+ */
+ private void setDetailedState(NetworkInfo.DetailedState state) {
+ Log.d(TAG, "setDetailed state, old ="
+ + mNetworkInfo.getDetailedState() + " and new state=" + state);
+ if (state != mNetworkInfo.getDetailedState()) {
+ mNetworkInfo.setDetailedState(state, null, null);
+ }
+ }
+
+ private static String removeDoubleQuotes(String string) {
+ if (string.length() <= 2) return "";
+ return string.substring(1, string.length() - 1);
+ }
+
+ private static String convertToQuotedString(String string) {
+ return "\"" + string + "\"";
+ }
+
+ private static String makeString(BitSet set, String[] strings) {
+ StringBuffer buf = new StringBuffer();
+ int nextSetBit = -1;
+
+ /* Make sure all set bits are in [0, strings.length) to avoid
+ * going out of bounds on strings. (Shouldn't happen, but...) */
+ set = set.get(0, strings.length);
+
+ while ((nextSetBit = set.nextSetBit(nextSetBit + 1)) != -1) {
+ buf.append(strings[nextSetBit].replace('_', '-')).append(' ');
+ }
+
+ // remove trailing space
+ if (set.cardinality() > 0) {
+ buf.setLength(buf.length() - 1);
+ }
+
+ return buf.toString();
+ }
+
+ private static int lookupString(String string, String[] strings) {
+ int size = strings.length;
+
+ string = string.replace('-', '_');
+
+ for (int i = 0; i < size; i++)
+ if (string.equals(strings[i]))
+ return i;
+
+ // if we ever get here, we should probably add the
+ // value to WifiConfiguration to reflect that it's
+ // supported by the WPA supplicant
+ Log.w(TAG, "Failed to look-up a string: " + string);
+
+ return -1;
+ }
+
+ private int addOrUpdateNetworkNative(WifiConfiguration config) {
+ /*
+ * If the supplied networkId is -1, we create a new empty
+ * network configuration. Otherwise, the networkId should
+ * refer to an existing configuration.
+ */
+ int netId = config.networkId;
+ boolean newNetwork = netId == -1;
+ // networkId of -1 means we want to create a new network
+
+ if (newNetwork) {
+ netId = WifiNative.addNetworkCommand();
+ if (netId < 0) {
+ Log.e(TAG, "Failed to add a network!");
+ return -1;
+ }
+ }
+
+ setVariables: {
+
+ if (config.SSID != null &&
+ !WifiNative.setNetworkVariableCommand(
+ netId,
+ WifiConfiguration.ssidVarName,
+ config.SSID)) {
+ Log.d(TAG, "failed to set SSID: "+config.SSID);
+ break setVariables;
+ }
+
+ if (config.BSSID != null &&
+ !WifiNative.setNetworkVariableCommand(
+ netId,
+ WifiConfiguration.bssidVarName,
+ config.BSSID)) {
+ Log.d(TAG, "failed to set BSSID: "+config.BSSID);
+ break setVariables;
+ }
+
+ String allowedKeyManagementString =
+ makeString(config.allowedKeyManagement, WifiConfiguration.KeyMgmt.strings);
+ if (config.allowedKeyManagement.cardinality() != 0 &&
+ !WifiNative.setNetworkVariableCommand(
+ netId,
+ WifiConfiguration.KeyMgmt.varName,
+ allowedKeyManagementString)) {
+ Log.d(TAG, "failed to set key_mgmt: "+
+ allowedKeyManagementString);
+ break setVariables;
+ }
+
+ String allowedProtocolsString =
+ makeString(config.allowedProtocols, WifiConfiguration.Protocol.strings);
+ if (config.allowedProtocols.cardinality() != 0 &&
+ !WifiNative.setNetworkVariableCommand(
+ netId,
+ WifiConfiguration.Protocol.varName,
+ allowedProtocolsString)) {
+ Log.d(TAG, "failed to set proto: "+
+ allowedProtocolsString);
+ break setVariables;
+ }
+
+ String allowedAuthAlgorithmsString =
+ makeString(config.allowedAuthAlgorithms, WifiConfiguration.AuthAlgorithm.strings);
+ if (config.allowedAuthAlgorithms.cardinality() != 0 &&
+ !WifiNative.setNetworkVariableCommand(
+ netId,
+ WifiConfiguration.AuthAlgorithm.varName,
+ allowedAuthAlgorithmsString)) {
+ Log.d(TAG, "failed to set auth_alg: "+
+ allowedAuthAlgorithmsString);
+ break setVariables;
+ }
+
+ String allowedPairwiseCiphersString =
+ makeString(config.allowedPairwiseCiphers,
+ WifiConfiguration.PairwiseCipher.strings);
+ if (config.allowedPairwiseCiphers.cardinality() != 0 &&
+ !WifiNative.setNetworkVariableCommand(
+ netId,
+ WifiConfiguration.PairwiseCipher.varName,
+ allowedPairwiseCiphersString)) {
+ Log.d(TAG, "failed to set pairwise: "+
+ allowedPairwiseCiphersString);
+ break setVariables;
+ }
+
+ String allowedGroupCiphersString =
+ makeString(config.allowedGroupCiphers, WifiConfiguration.GroupCipher.strings);
+ if (config.allowedGroupCiphers.cardinality() != 0 &&
+ !WifiNative.setNetworkVariableCommand(
+ netId,
+ WifiConfiguration.GroupCipher.varName,
+ allowedGroupCiphersString)) {
+ Log.d(TAG, "failed to set group: "+
+ allowedGroupCiphersString);
+ break setVariables;
+ }
+
+ // Prevent client screw-up by passing in a WifiConfiguration we gave it
+ // by preventing "*" as a key.
+ if (config.preSharedKey != null && !config.preSharedKey.equals("*") &&
+ !WifiNative.setNetworkVariableCommand(
+ netId,
+ WifiConfiguration.pskVarName,
+ config.preSharedKey)) {
+ Log.d(TAG, "failed to set psk: "+config.preSharedKey);
+ break setVariables;
+ }
+
+ boolean hasSetKey = false;
+ if (config.wepKeys != null) {
+ for (int i = 0; i < config.wepKeys.length; i++) {
+ // Prevent client screw-up by passing in a WifiConfiguration we gave it
+ // by preventing "*" as a key.
+ if (config.wepKeys[i] != null && !config.wepKeys[i].equals("*")) {
+ if (!WifiNative.setNetworkVariableCommand(
+ netId,
+ WifiConfiguration.wepKeyVarNames[i],
+ config.wepKeys[i])) {
+ Log.d(TAG,
+ "failed to set wep_key"+i+": " +
+ config.wepKeys[i]);
+ break setVariables;
+ }
+ hasSetKey = true;
+ }
+ }
+ }
+
+ if (hasSetKey) {
+ if (!WifiNative.setNetworkVariableCommand(
+ netId,
+ WifiConfiguration.wepTxKeyIdxVarName,
+ Integer.toString(config.wepTxKeyIndex))) {
+ Log.d(TAG,
+ "failed to set wep_tx_keyidx: "+
+ config.wepTxKeyIndex);
+ break setVariables;
+ }
+ }
+
+ if (!WifiNative.setNetworkVariableCommand(
+ netId,
+ WifiConfiguration.priorityVarName,
+ Integer.toString(config.priority))) {
+ Log.d(TAG, config.SSID + ": failed to set priority: "
+ +config.priority);
+ break setVariables;
+ }
+
+ if (config.hiddenSSID && !WifiNative.setNetworkVariableCommand(
+ netId,
+ WifiConfiguration.hiddenSSIDVarName,
+ Integer.toString(config.hiddenSSID ? 1 : 0))) {
+ Log.d(TAG, config.SSID + ": failed to set hiddenSSID: "+
+ config.hiddenSSID);
+ break setVariables;
+ }
+
+ for (WifiConfiguration.EnterpriseField field
+ : config.enterpriseFields) {
+ String varName = field.varName();
+ String value = field.value();
+ if (value != null) {
+ if (field != config.eap) {
+ value = (value.length() == 0) ? "NULL" : convertToQuotedString(value);
+ }
+ if (!WifiNative.setNetworkVariableCommand(
+ netId,
+ varName,
+ value)) {
+ Log.d(TAG, config.SSID + ": failed to set " + varName +
+ ": " + value);
+ break setVariables;
+ }
+ }
+ }
+ return netId;
+ }
+
+ if (newNetwork) {
+ WifiNative.removeNetworkCommand(netId);
+ Log.d(TAG,
+ "Failed to set a network variable, removed network: "
+ + netId);
+ }
+
+ return -1;
+ }
+
+ private List<WifiConfiguration> getConfiguredNetworksNative() {
+ String listStr = WifiNative.listNetworksCommand();
+
+ List<WifiConfiguration> networks =
+ new ArrayList<WifiConfiguration>();
+ if (listStr == null)
+ return networks;
+
+ String[] lines = listStr.split("\n");
+ // Skip the first line, which is a header
+ for (int i = 1; i < lines.length; i++) {
+ String[] result = lines[i].split("\t");
+ // network-id | ssid | bssid | flags
+ WifiConfiguration config = new WifiConfiguration();
+ try {
+ config.networkId = Integer.parseInt(result[0]);
+ } catch(NumberFormatException e) {
+ continue;
+ }
+ if (result.length > 3) {
+ if (result[3].indexOf("[CURRENT]") != -1)
+ config.status = WifiConfiguration.Status.CURRENT;
+ else if (result[3].indexOf("[DISABLED]") != -1)
+ config.status = WifiConfiguration.Status.DISABLED;
+ else
+ config.status = WifiConfiguration.Status.ENABLED;
+ } else {
+ config.status = WifiConfiguration.Status.ENABLED;
+ }
+ readNetworkVariables(config);
+ networks.add(config);
+ }
+ return networks;
+ }
+
+ /**
+ * Read the variables from the supplicant daemon that are needed to
+ * fill in the WifiConfiguration object.
+ *
+ * @param config the {@link WifiConfiguration} object to be filled in.
+ */
+ private void readNetworkVariables(WifiConfiguration config) {
+
+ int netId = config.networkId;
+ if (netId < 0)
+ return;
+
+ /*
+ * TODO: maybe should have a native method that takes an array of
+ * variable names and returns an array of values. But we'd still
+ * be doing a round trip to the supplicant daemon for each variable.
+ */
+ String value;
+
+ value = WifiNative.getNetworkVariableCommand(netId, WifiConfiguration.ssidVarName);
+ if (!TextUtils.isEmpty(value)) {
+ config.SSID = removeDoubleQuotes(value);
+ } else {
+ config.SSID = null;
+ }
+
+ value = WifiNative.getNetworkVariableCommand(netId, WifiConfiguration.bssidVarName);
+ if (!TextUtils.isEmpty(value)) {
+ config.BSSID = value;
+ } else {
+ config.BSSID = null;
+ }
+
+ value = WifiNative.getNetworkVariableCommand(netId, WifiConfiguration.priorityVarName);
+ config.priority = -1;
+ if (!TextUtils.isEmpty(value)) {
+ try {
+ config.priority = Integer.parseInt(value);
+ } catch (NumberFormatException ignore) {
+ }
+ }
+
+ value = WifiNative.getNetworkVariableCommand(netId, WifiConfiguration.hiddenSSIDVarName);
+ config.hiddenSSID = false;
+ if (!TextUtils.isEmpty(value)) {
+ try {
+ config.hiddenSSID = Integer.parseInt(value) != 0;
+ } catch (NumberFormatException ignore) {
+ }
+ }
+
+ value = WifiNative.getNetworkVariableCommand(netId, WifiConfiguration.wepTxKeyIdxVarName);
+ config.wepTxKeyIndex = -1;
+ if (!TextUtils.isEmpty(value)) {
+ try {
+ config.wepTxKeyIndex = Integer.parseInt(value);
+ } catch (NumberFormatException ignore) {
+ }
+ }
+
+ for (int i = 0; i < 4; i++) {
+ value = WifiNative.getNetworkVariableCommand(netId,
+ WifiConfiguration.wepKeyVarNames[i]);
+ if (!TextUtils.isEmpty(value)) {
+ config.wepKeys[i] = value;
+ } else {
+ config.wepKeys[i] = null;
+ }
+ }
+
+ value = WifiNative.getNetworkVariableCommand(netId, WifiConfiguration.pskVarName);
+ if (!TextUtils.isEmpty(value)) {
+ config.preSharedKey = value;
+ } else {
+ config.preSharedKey = null;
+ }
+
+ value = WifiNative.getNetworkVariableCommand(config.networkId,
+ WifiConfiguration.Protocol.varName);
+ if (!TextUtils.isEmpty(value)) {
+ String vals[] = value.split(" ");
+ for (String val : vals) {
+ int index =
+ lookupString(val, WifiConfiguration.Protocol.strings);
+ if (0 <= index) {
+ config.allowedProtocols.set(index);
+ }
+ }
+ }
+
+ value = WifiNative.getNetworkVariableCommand(config.networkId,
+ WifiConfiguration.KeyMgmt.varName);
+ if (!TextUtils.isEmpty(value)) {
+ String vals[] = value.split(" ");
+ for (String val : vals) {
+ int index =
+ lookupString(val, WifiConfiguration.KeyMgmt.strings);
+ if (0 <= index) {
+ config.allowedKeyManagement.set(index);
+ }
+ }
+ }
+
+ value = WifiNative.getNetworkVariableCommand(config.networkId,
+ WifiConfiguration.AuthAlgorithm.varName);
+ if (!TextUtils.isEmpty(value)) {
+ String vals[] = value.split(" ");
+ for (String val : vals) {
+ int index =
+ lookupString(val, WifiConfiguration.AuthAlgorithm.strings);
+ if (0 <= index) {
+ config.allowedAuthAlgorithms.set(index);
+ }
+ }
+ }
+
+ value = WifiNative.getNetworkVariableCommand(config.networkId,
+ WifiConfiguration.PairwiseCipher.varName);
+ if (!TextUtils.isEmpty(value)) {
+ String vals[] = value.split(" ");
+ for (String val : vals) {
+ int index =
+ lookupString(val, WifiConfiguration.PairwiseCipher.strings);
+ if (0 <= index) {
+ config.allowedPairwiseCiphers.set(index);
+ }
+ }
+ }
+
+ value = WifiNative.getNetworkVariableCommand(config.networkId,
+ WifiConfiguration.GroupCipher.varName);
+ if (!TextUtils.isEmpty(value)) {
+ String vals[] = value.split(" ");
+ for (String val : vals) {
+ int index =
+ lookupString(val, WifiConfiguration.GroupCipher.strings);
+ if (0 <= index) {
+ config.allowedGroupCiphers.set(index);
+ }
+ }
+ }
+
+ for (WifiConfiguration.EnterpriseField field :
+ config.enterpriseFields) {
+ value = WifiNative.getNetworkVariableCommand(netId,
+ field.varName());
+ if (!TextUtils.isEmpty(value)) {
+ if (field != config.eap) value = removeDoubleQuotes(value);
+ field.setValue(value);
+ }
+ }
+
+ }
+
+ /**
+ * Poll for info not reported via events
+ * RSSI & Linkspeed
+ */
+ private void requestPolledInfo() {
+ int newRssi = WifiNative.getRssiCommand();
+ if (newRssi != -1 && -200 < newRssi && newRssi < 256) { // screen out invalid values
+ /* some implementations avoid negative values by adding 256
+ * so we need to adjust for that here.
+ */
+ if (newRssi > 0) newRssi -= 256;
+ mWifiInfo.setRssi(newRssi);
+ /*
+ * Rather then sending the raw RSSI out every time it
+ * changes, we precalculate the signal level that would
+ * be displayed in the status bar, and only send the
+ * broadcast if that much more coarse-grained number
+ * changes. This cuts down greatly on the number of
+ * broadcasts, at the cost of not mWifiInforming others
+ * interested in RSSI of all the changes in signal
+ * level.
+ */
+ // TODO: The second arg to the call below needs to be a symbol somewhere, but
+ // it's actually the size of an array of icons that's private
+ // to StatusBar Policy.
+ int newSignalLevel = WifiManager.calculateSignalLevel(newRssi, 4);
+ if (newSignalLevel != mLastSignalLevel) {
+ sendRssiChangeBroadcast(newRssi);
+ }
+ mLastSignalLevel = newSignalLevel;
+ } else {
+ mWifiInfo.setRssi(-200);
+ }
+ int newLinkSpeed = WifiNative.getLinkSpeedCommand();
+ if (newLinkSpeed != -1) {
+ mWifiInfo.setLinkSpeed(newLinkSpeed);
+ }
+ }
+
+ /**
+ * Resets the Wi-Fi Connections by clearing any state, resetting any sockets
+ * using the interface, stopping DHCP & disabling interface
+ */
+ private void handleNetworkDisconnect() {
+ Log.d(TAG, "Reset connections and stopping DHCP");
+
+ /*
+ * Reset connections & stop DHCP
+ */
+ NetworkUtils.resetConnections(mInterfaceName);
+
+ if (!NetworkUtils.stopDhcp(mInterfaceName)) {
+ Log.e(TAG, "Could not stop DHCP");
+ }
+
+ /* Disable interface */
+ NetworkUtils.disableInterface(mInterfaceName);
+
+ /* send event to CM & network change broadcast */
+ setDetailedState(DetailedState.DISCONNECTED);
+ sendNetworkStateChangeBroadcast(mLastBssid);
+
+ /* Reset data structures */
+ mWifiInfo.setIpAddress(0);
+ mWifiInfo.setBSSID(null);
+ mWifiInfo.setSSID(null);
+ mWifiInfo.setNetworkId(-1);
+
+ /* Clear network properties */
+ mNetworkProperties.clear();
+
+ mLastBssid= null;
+ mLastNetworkId = -1;
+
+ }
+
+
+ /*********************************************************
+ * Notifications from WifiMonitor
+ ********************************************************/
+
+ /**
+ * A structure for supplying information about a supplicant state
+ * change in the STATE_CHANGE event message that comes from the
+ * WifiMonitor
+ * thread.
+ */
+ private static class StateChangeResult {
+ StateChangeResult(int networkId, String BSSID, Object state) {
+ this.state = state;
+ this.BSSID = BSSID;
+ this.networkId = networkId;
+ }
+ int networkId;
+ String BSSID;
+ Object state;
+ }
+
+ /**
+ * Send the tracker a notification that a user-entered password key
+ * may be incorrect (i.e., caused authentication to fail).
+ */
+ void notifyPasswordKeyMayBeIncorrect() {
+ sendMessage(PASSWORD_MAY_BE_INCORRECT_EVENT);
+ }
+
+ /**
+ * Send the tracker a notification that a connection to the supplicant
+ * daemon has been established.
+ */
+ void notifySupplicantConnection() {
+ sendMessage(SUP_CONNECTION_EVENT);
+ }
+
+ /**
+ * Send the tracker a notification that a connection to the supplicant
+ * daemon has been established.
+ */
+ void notifySupplicantLost() {
+ sendMessage(SUP_DISCONNECTION_EVENT);
+ }
+
+ /**
+ * Send the tracker a notification that the state of Wifi connectivity
+ * has changed.
+ * @param networkId the configured network on which the state change occurred
+ * @param newState the new network state
+ * @param BSSID when the new state is {@link DetailedState#CONNECTED
+ * NetworkInfo.DetailedState.CONNECTED},
+ * this is the MAC address of the access point. Otherwise, it
+ * is {@code null}.
+ */
+ void notifyNetworkStateChange(DetailedState newState, String BSSID, int networkId) {
+ if (newState == NetworkInfo.DetailedState.CONNECTED) {
+ sendMessage(obtainMessage(NETWORK_CONNECTION_EVENT,
+ new StateChangeResult(networkId, BSSID, newState)));
+ } else {
+ sendMessage(obtainMessage(NETWORK_DISCONNECTION_EVENT,
+ new StateChangeResult(networkId, BSSID, newState)));
+ }
+ }
+
+ /**
+ * Send the tracker a notification that the state of the supplicant
+ * has changed.
+ * @param networkId the configured network on which the state change occurred
+ * @param newState the new {@code SupplicantState}
+ */
+ void notifySupplicantStateChange(int networkId, String BSSID, SupplicantState newState) {
+ sendMessage(obtainMessage(SUPPLICANT_STATE_CHANGE_EVENT,
+ new StateChangeResult(networkId, BSSID, newState)));
+ }
+
+ /**
+ * Send the tracker a notification that a scan has completed, and results
+ * are available.
+ */
+ void notifyScanResultsAvailable() {
+ /**
+ * Switch scan mode over to passive.
+ * Turning off scan-only mode happens only in "Connect" mode
+ */
+ setScanType(false);
+ sendMessage(SCAN_RESULTS_EVENT);
+ }
+
+ void notifyDriverStarted() {
+ sendMessage(DRIVER_START_EVENT);
+ }
+
+ void notifyDriverStopped() {
+ sendMessage(DRIVER_STOP_EVENT);
+ }
+
+ void notifyDriverHung() {
+ setWifiEnabled(false);
+ setWifiEnabled(true);
+ }
+
+
+ /********************************************************
+ * HSM states
+ *******************************************************/
+
+ class DefaultState extends HierarchicalState {
+ @Override
+ public boolean processMessage(Message message) {
+ if (DBG) Log.d(TAG, getName() + message.toString() + "\n");
+ SyncParams syncParams;
+ switch (message.what) {
+ /* Synchronous call returns */
+ case CMD_PING_SUPPLICANT:
+ case CMD_START_SCAN:
+ case CMD_DISCONNECT:
+ case CMD_RECONNECT:
+ case CMD_REASSOCIATE:
+ case CMD_REMOVE_NETWORK:
+ case CMD_ENABLE_NETWORK:
+ case CMD_DISABLE_NETWORK:
+ case CMD_ADD_OR_UPDATE_NETWORK:
+ case CMD_GET_RSSI:
+ case CMD_GET_RSSI_APPROX:
+ case CMD_GET_LINK_SPEED:
+ case CMD_GET_MAC_ADDR:
+ case CMD_SAVE_CONFIG:
+ case CMD_CONNECTION_STATUS:
+ case CMD_GET_NETWORK_CONFIG:
+ if (message.arg2 == SYNCHRONOUS_CALL) {
+ syncParams = (SyncParams) message.obj;
+ syncParams.mSyncReturn.boolValue = false;
+ syncParams.mSyncReturn.intValue = -1;
+ syncParams.mSyncReturn.stringValue = null;
+ syncParams.mSyncReturn.configList = null;
+ notifyOnMsgObject(message);
+ }
+ break;
+ case CMD_ENABLE_RSSI_POLL:
+ mEnableRssiPolling = (message.arg1 == 1);
+ mSupplicantStateTracker.sendMessage(CMD_ENABLE_RSSI_POLL);
+ break;
+ /* Discard */
+ case CMD_LOAD_DRIVER:
+ case CMD_UNLOAD_DRIVER:
+ case CMD_START_SUPPLICANT:
+ case CMD_STOP_SUPPLICANT:
+ case CMD_START_DRIVER:
+ case CMD_STOP_DRIVER:
+ case CMD_START_AP:
+ case CMD_STOP_AP:
+ case CMD_RECONFIGURE_IP:
+ case SUP_CONNECTION_EVENT:
+ case SUP_DISCONNECTION_EVENT:
+ case DRIVER_START_EVENT:
+ case DRIVER_STOP_EVENT:
+ case NETWORK_CONNECTION_EVENT:
+ case NETWORK_DISCONNECTION_EVENT:
+ case SCAN_RESULTS_EVENT:
+ case SUPPLICANT_STATE_CHANGE_EVENT:
+ case PASSWORD_MAY_BE_INCORRECT_EVENT:
+ case CMD_BLACKLIST_NETWORK:
+ case CMD_CLEAR_BLACKLIST:
+ case CMD_SET_SCAN_MODE:
+ case CMD_SET_SCAN_TYPE:
+ case CMD_SET_POWER_MODE:
+ case CMD_SET_BLUETOOTH_COEXISTENCE:
+ case CMD_SET_BLUETOOTH_SCAN_MODE:
+ case CMD_SET_NUM_ALLOWED_CHANNELS:
+ case CMD_REQUEST_CM_WAKELOCK:
+ break;
+ default:
+ Log.e(TAG, "Error! unhandled message" + message);
+ break;
+ }
+ return HANDLED;
+ }
+ }
+
+ class InitialState extends HierarchicalState {
+ @Override
+ //TODO: could move logging into a common class
+ public void enter() {
+ if (DBG) Log.d(TAG, getName() + "\n");
+ // [31-8] Reserved for future use
+ // [7 - 0] HSM state change
+ // 50021 wifi_state_changed (custom|1|5)
+ EventLog.writeEvent(EVENTLOG_WIFI_STATE_CHANGED, getName());
+
+ if (WifiNative.isDriverLoaded()) {
+ transitionTo(mDriverLoadedState);
+ }
+ else {
+ transitionTo(mDriverUnloadedState);
+ }
+ }
+ }
+
+ class DriverLoadingState extends HierarchicalState {
+ @Override
+ public void enter() {
+ if (DBG) Log.d(TAG, getName() + "\n");
+ EventLog.writeEvent(EVENTLOG_WIFI_STATE_CHANGED, getName());
+
+ final Message message = new Message();
+ message.copyFrom(getCurrentMessage());
+ /* TODO: add a timeout to fail when driver load is hung.
+ * Similarly for driver unload.
+ */
+ new Thread(new Runnable() {
+ public void run() {
+ sWakeLock.acquire();
+ //enabling state
+ switch(message.arg1) {
+ case WIFI_STATE_ENABLING:
+ setWifiState(WIFI_STATE_ENABLING);
+ break;
+ case WIFI_AP_STATE_ENABLING:
+ setWifiApState(WIFI_AP_STATE_ENABLING);
+ break;
+ }
+
+ if(WifiNative.loadDriver()) {
+ Log.d(TAG, "Driver load successful");
+ sendMessage(CMD_LOAD_DRIVER_SUCCESS);
+ } else {
+ Log.e(TAG, "Failed to load driver!");
+ switch(message.arg1) {
+ case WIFI_STATE_ENABLING:
+ setWifiState(WIFI_STATE_UNKNOWN);
+ break;
+ case WIFI_AP_STATE_ENABLING:
+ setWifiApState(WIFI_AP_STATE_FAILED);
+ break;
+ }
+ sendMessage(CMD_LOAD_DRIVER_FAILURE);
+ }
+ sWakeLock.release();
+ }
+ }).start();
+ }
+
+ @Override
+ public boolean processMessage(Message message) {
+ if (DBG) Log.d(TAG, getName() + message.toString() + "\n");
+ switch (message.what) {
+ case CMD_LOAD_DRIVER_SUCCESS:
+ transitionTo(mDriverLoadedState);
+ break;
+ case CMD_LOAD_DRIVER_FAILURE:
+ transitionTo(mDriverFailedState);
+ break;
+ case CMD_LOAD_DRIVER:
+ case CMD_UNLOAD_DRIVER:
+ case CMD_START_SUPPLICANT:
+ case CMD_STOP_SUPPLICANT:
+ case CMD_START_AP:
+ case CMD_STOP_AP:
+ case CMD_START_DRIVER:
+ case CMD_STOP_DRIVER:
+ case CMD_SET_SCAN_MODE:
+ case CMD_SET_SCAN_TYPE:
+ case CMD_SET_POWER_MODE:
+ case CMD_SET_BLUETOOTH_COEXISTENCE:
+ case CMD_SET_BLUETOOTH_SCAN_MODE:
+ case CMD_SET_NUM_ALLOWED_CHANNELS:
+ case CMD_START_PACKET_FILTERING:
+ case CMD_STOP_PACKET_FILTERING:
+ deferMessage(message);
+ break;
+ default:
+ return NOT_HANDLED;
+ }
+ EventLog.writeEvent(EVENTLOG_WIFI_EVENT_HANDLED, message.what);
+ return HANDLED;
+ }
+ }
+
+ class DriverLoadedState extends HierarchicalState {
+ @Override
+ public void enter() {
+ if (DBG) Log.d(TAG, getName() + "\n");
+ EventLog.writeEvent(EVENTLOG_WIFI_STATE_CHANGED, getName());
+ }
+ @Override
+ public boolean processMessage(Message message) {
+ if (DBG) Log.d(TAG, getName() + message.toString() + "\n");
+ switch(message.what) {
+ case CMD_UNLOAD_DRIVER:
+ transitionTo(mDriverUnloadingState);
+ break;
+ case CMD_START_SUPPLICANT:
+ if(WifiNative.startSupplicant()) {
+ Log.d(TAG, "Supplicant start successful");
+ mWifiMonitor.startMonitoring();
+ setWifiState(WIFI_STATE_ENABLED);
+ transitionTo(mWaitForSupState);
+ } else {
+ Log.e(TAG, "Failed to start supplicant!");
+ sendMessage(obtainMessage(CMD_UNLOAD_DRIVER, WIFI_STATE_UNKNOWN, 0));
+ }
+ break;
+ case CMD_START_AP:
+ try {
+ nwService.startAccessPoint((WifiConfiguration) message.obj,
+ mInterfaceName,
+ SOFTAP_IFACE);
+ } catch(Exception e) {
+ Log.e(TAG, "Exception in startAccessPoint()");
+ sendMessage(obtainMessage(CMD_UNLOAD_DRIVER, WIFI_AP_STATE_FAILED, 0));
+ break;
+ }
+ Log.d(TAG, "Soft AP start successful");
+ setWifiApState(WIFI_AP_STATE_ENABLED);
+ transitionTo(mSoftApStartedState);
+ break;
+ default:
+ return NOT_HANDLED;
+ }
+ EventLog.writeEvent(EVENTLOG_WIFI_EVENT_HANDLED, message.what);
+ return HANDLED;
+ }
+ }
+
+ class DriverUnloadingState extends HierarchicalState {
+ @Override
+ public void enter() {
+ if (DBG) Log.d(TAG, getName() + "\n");
+ EventLog.writeEvent(EVENTLOG_WIFI_STATE_CHANGED, getName());
+
+ final Message message = new Message();
+ message.copyFrom(getCurrentMessage());
+ new Thread(new Runnable() {
+ public void run() {
+ if (DBG) Log.d(TAG, getName() + message.toString() + "\n");
+ sWakeLock.acquire();
+ if(WifiNative.unloadDriver()) {
+ Log.d(TAG, "Driver unload successful");
+ sendMessage(CMD_UNLOAD_DRIVER_SUCCESS);
+
+ switch(message.arg1) {
+ case WIFI_STATE_DISABLED:
+ case WIFI_STATE_UNKNOWN:
+ setWifiState(message.arg1);
+ break;
+ case WIFI_AP_STATE_DISABLED:
+ case WIFI_AP_STATE_FAILED:
+ setWifiApState(message.arg1);
+ break;
+ }
+ } else {
+ Log.e(TAG, "Failed to unload driver!");
+ sendMessage(CMD_UNLOAD_DRIVER_FAILURE);
+
+ switch(message.arg1) {
+ case WIFI_STATE_DISABLED:
+ case WIFI_STATE_UNKNOWN:
+ setWifiState(WIFI_STATE_UNKNOWN);
+ break;
+ case WIFI_AP_STATE_DISABLED:
+ case WIFI_AP_STATE_FAILED:
+ setWifiApState(WIFI_AP_STATE_FAILED);
+ break;
+ }
+ }
+ sWakeLock.release();
+ }
+ }).start();
+ }
+
+ @Override
+ public boolean processMessage(Message message) {
+ if (DBG) Log.d(TAG, getName() + message.toString() + "\n");
+ switch (message.what) {
+ case CMD_UNLOAD_DRIVER_SUCCESS:
+ transitionTo(mDriverUnloadedState);
+ break;
+ case CMD_UNLOAD_DRIVER_FAILURE:
+ transitionTo(mDriverFailedState);
+ break;
+ case CMD_LOAD_DRIVER:
+ case CMD_UNLOAD_DRIVER:
+ case CMD_START_SUPPLICANT:
+ case CMD_STOP_SUPPLICANT:
+ case CMD_START_AP:
+ case CMD_STOP_AP:
+ case CMD_START_DRIVER:
+ case CMD_STOP_DRIVER:
+ case CMD_SET_SCAN_MODE:
+ case CMD_SET_SCAN_TYPE:
+ case CMD_SET_POWER_MODE:
+ case CMD_SET_BLUETOOTH_COEXISTENCE:
+ case CMD_SET_BLUETOOTH_SCAN_MODE:
+ case CMD_SET_NUM_ALLOWED_CHANNELS:
+ case CMD_START_PACKET_FILTERING:
+ case CMD_STOP_PACKET_FILTERING:
+ deferMessage(message);
+ break;
+ default:
+ return NOT_HANDLED;
+ }
+ EventLog.writeEvent(EVENTLOG_WIFI_EVENT_HANDLED, message.what);
+ return HANDLED;
+ }
+ }
+
+ class DriverUnloadedState extends HierarchicalState {
+ @Override
+ public void enter() {
+ if (DBG) Log.d(TAG, getName() + "\n");
+ EventLog.writeEvent(EVENTLOG_WIFI_STATE_CHANGED, getName());
+ }
+ @Override
+ public boolean processMessage(Message message) {
+ if (DBG) Log.d(TAG, getName() + message.toString() + "\n");
+ switch (message.what) {
+ case CMD_LOAD_DRIVER:
+ transitionTo(mDriverLoadingState);
+ break;
+ default:
+ return NOT_HANDLED;
+ }
+ EventLog.writeEvent(EVENTLOG_WIFI_EVENT_HANDLED, message.what);
+ return HANDLED;
+ }
+ }
+
+ class DriverFailedState extends HierarchicalState {
+ @Override
+ public void enter() {
+ Log.e(TAG, getName() + "\n");
+ EventLog.writeEvent(EVENTLOG_WIFI_STATE_CHANGED, getName());
+ }
+ @Override
+ public boolean processMessage(Message message) {
+ if (DBG) Log.d(TAG, getName() + message.toString() + "\n");
+ return NOT_HANDLED;
+ }
+ }
+
+
+ class WaitForSupState extends HierarchicalState {
+ @Override
+ public void enter() {
+ if (DBG) Log.d(TAG, getName() + "\n");
+ EventLog.writeEvent(EVENTLOG_WIFI_STATE_CHANGED, getName());
+ }
+ @Override
+ public boolean processMessage(Message message) {
+ if (DBG) Log.d(TAG, getName() + message.toString() + "\n");
+ switch(message.what) {
+ case SUP_CONNECTION_EVENT:
+ Log.d(TAG, "Supplicant connection established");
+ mSupplicantStateTracker.resetSupplicantState();
+ /* Initialize data structures */
+ mLastBssid = null;
+ mLastNetworkId = -1;
+ mLastSignalLevel = -1;
+
+ mWifiInfo.setMacAddress(WifiNative.getMacAddressCommand());
+
+ //TODO: initialize and fix multicast filtering
+ //mWM.initializeMulticastFiltering();
+
+ if (mBluetoothA2dp == null) {
+ mBluetoothA2dp = new BluetoothA2dp(mContext);
+ }
+ checkIsBluetoothPlaying();
+
+ checkUseStaticIp();
+ sendSupplicantConnectionChangedBroadcast(true);
+ transitionTo(mDriverSupReadyState);
+ break;
+ case CMD_STOP_SUPPLICANT:
+ Log.d(TAG, "Stop supplicant received");
+ WifiNative.stopSupplicant();
+ transitionTo(mDriverLoadedState);
+ break;
+ /* Fail soft ap when waiting for supplicant start */
+ case CMD_START_AP:
+ Log.d(TAG, "Failed to start soft AP with a running supplicant");
+ setWifiApState(WIFI_AP_STATE_FAILED);
+ break;
+ case CMD_START_DRIVER:
+ case CMD_STOP_DRIVER:
+ case CMD_SET_SCAN_MODE:
+ case CMD_SET_SCAN_TYPE:
+ case CMD_SET_POWER_MODE:
+ case CMD_SET_BLUETOOTH_COEXISTENCE:
+ case CMD_SET_BLUETOOTH_SCAN_MODE:
+ case CMD_SET_NUM_ALLOWED_CHANNELS:
+ case CMD_START_PACKET_FILTERING:
+ case CMD_STOP_PACKET_FILTERING:
+ deferMessage(message);
+ break;
+ case CMD_STOP_AP:
+ case CMD_START_SUPPLICANT:
+ case CMD_UNLOAD_DRIVER:
+ break;
+ default:
+ return NOT_HANDLED;
+ }
+ EventLog.writeEvent(EVENTLOG_WIFI_EVENT_HANDLED, message.what);
+ return HANDLED;
+ }
+ }
+
+ class DriverSupReadyState extends HierarchicalState {
+ @Override
+ public void enter() {
+ if (DBG) Log.d(TAG, getName() + "\n");
+ EventLog.writeEvent(EVENTLOG_WIFI_STATE_CHANGED, getName());
+ /* Initialize for connect mode operation at start */
+ mIsScanMode = false;
+ }
+ @Override
+ public boolean processMessage(Message message) {
+ if (DBG) Log.d(TAG, getName() + message.toString() + "\n");
+ SyncParams syncParams;
+ switch(message.what) {
+ case CMD_STOP_SUPPLICANT: /* Supplicant stopped by user */
+ Log.d(TAG, "Stop supplicant received");
+ WifiNative.stopSupplicant();
+ //$FALL-THROUGH$
+ case SUP_DISCONNECTION_EVENT: /* Supplicant died */
+ EventLog.writeEvent(EVENTLOG_WIFI_EVENT_HANDLED, message.what);
+ WifiNative.closeSupplicantConnection();
+ handleNetworkDisconnect();
+ sendSupplicantConnectionChangedBroadcast(false);
+ mSupplicantStateTracker.resetSupplicantState();
+ transitionTo(mDriverLoadedState);
+
+ /* When supplicant dies, unload driver and enter failed state */
+ //TODO: consider bringing up supplicant again
+ if (message.what == SUP_DISCONNECTION_EVENT) {
+ Log.d(TAG, "Supplicant died, unloading driver");
+ sendMessage(obtainMessage(CMD_UNLOAD_DRIVER, WIFI_STATE_UNKNOWN, 0));
+ }
+ break;
+ case CMD_START_DRIVER:
+ EventLog.writeEvent(EVENTLOG_WIFI_EVENT_HANDLED, message.what);
+ WifiNative.startDriverCommand();
+ transitionTo(mDriverStartingState);
+ break;
+ case SCAN_RESULTS_EVENT:
+ setScanResults(WifiNative.scanResultsCommand());
+ sendScanResultsAvailableBroadcast();
+ break;
+ case CMD_PING_SUPPLICANT:
+ syncParams = (SyncParams) message.obj;
+ syncParams.mSyncReturn.boolValue = WifiNative.pingCommand();
+ notifyOnMsgObject(message);
+ break;
+ case CMD_ADD_OR_UPDATE_NETWORK:
+ EventLog.writeEvent(EVENTLOG_WIFI_EVENT_HANDLED, message.what);
+ syncParams = (SyncParams) message.obj;
+ WifiConfiguration config = (WifiConfiguration) syncParams.mParameter;
+ syncParams.mSyncReturn.intValue = addOrUpdateNetworkNative(config);
+ notifyOnMsgObject(message);
+ break;
+ case CMD_REMOVE_NETWORK:
+ EventLog.writeEvent(EVENTLOG_WIFI_EVENT_HANDLED, message.what);
+ if (message.arg2 == SYNCHRONOUS_CALL) {
+ syncParams = (SyncParams) message.obj;
+ syncParams.mSyncReturn.boolValue = WifiNative.removeNetworkCommand(
+ message.arg1);
+ notifyOnMsgObject(message);
+ } else {
+ /* asynchronous handling */
+ WifiNative.removeNetworkCommand(message.arg1);
+ }
+ break;
+ case CMD_ENABLE_NETWORK:
+ EventLog.writeEvent(EVENTLOG_WIFI_EVENT_HANDLED, message.what);
+ if (message.arg2 == SYNCHRONOUS_CALL) {
+ syncParams = (SyncParams) message.obj;
+ EnableNetParams enableNetParams = (EnableNetParams) syncParams.mParameter;
+ syncParams.mSyncReturn.boolValue = WifiNative.enableNetworkCommand(
+ enableNetParams.netId, enableNetParams.disableOthers);
+ notifyOnMsgObject(message);
+ } else {
+ /* asynchronous handling */
+ WifiNative.enableNetworkCommand(message.arg1, message.arg2 == 1);
+ }
+ break;
+ case CMD_DISABLE_NETWORK:
+ EventLog.writeEvent(EVENTLOG_WIFI_EVENT_HANDLED, message.what);
+ if (message.arg2 == SYNCHRONOUS_CALL) {
+ syncParams = (SyncParams) message.obj;
+ syncParams.mSyncReturn.boolValue = WifiNative.disableNetworkCommand(
+ message.arg1);
+ notifyOnMsgObject(message);
+ } else {
+ /* asynchronous handling */
+ WifiNative.disableNetworkCommand(message.arg1);
+ }
+ break;
+ case CMD_BLACKLIST_NETWORK:
+ EventLog.writeEvent(EVENTLOG_WIFI_EVENT_HANDLED, message.what);
+ WifiNative.addToBlacklistCommand((String)message.obj);
+ break;
+ case CMD_CLEAR_BLACKLIST:
+ WifiNative.clearBlacklistCommand();
+ break;
+ case CMD_GET_NETWORK_CONFIG:
+ syncParams = (SyncParams) message.obj;
+ syncParams.mSyncReturn.configList = getConfiguredNetworksNative();
+ notifyOnMsgObject(message);
+ break;
+ case CMD_SAVE_CONFIG:
+ if (message.arg2 == SYNCHRONOUS_CALL) {
+ syncParams = (SyncParams) message.obj;
+ syncParams.mSyncReturn.boolValue = WifiNative.saveConfigCommand();
+ notifyOnMsgObject(message);
+ } else {
+ /* asynchronous handling */
+ WifiNative.saveConfigCommand();
+ }
+ // Inform the backup manager about a data change
+ IBackupManager ibm = IBackupManager.Stub.asInterface(
+ ServiceManager.getService(Context.BACKUP_SERVICE));
+ if (ibm != null) {
+ try {
+ ibm.dataChanged("com.android.providers.settings");
+ } catch (Exception e) {
+ // Try again later
+ }
+ }
+ break;
+ case CMD_CONNECTION_STATUS:
+ syncParams = (SyncParams) message.obj;
+ syncParams.mSyncReturn.stringValue = WifiNative.statusCommand();
+ notifyOnMsgObject(message);
+ break;
+ case CMD_GET_MAC_ADDR:
+ syncParams = (SyncParams) message.obj;
+ syncParams.mSyncReturn.stringValue = WifiNative.getMacAddressCommand();
+ notifyOnMsgObject(message);
+ break;
+ /* Cannot start soft AP while in client mode */
+ case CMD_START_AP:
+ Log.d(TAG, "Failed to start soft AP with a running supplicant");
+ EventLog.writeEvent(EVENTLOG_WIFI_EVENT_HANDLED, message.what);
+ setWifiApState(WIFI_AP_STATE_FAILED);
+ break;
+ case CMD_SET_SCAN_MODE:
+ mIsScanMode = (message.arg1 == SCAN_ONLY_MODE);
+ break;
+ default:
+ return NOT_HANDLED;
+ }
+ return HANDLED;
+ }
+ }
+
+ class DriverStartingState extends HierarchicalState {
+ @Override
+ public void enter() {
+ if (DBG) Log.d(TAG, getName() + "\n");
+ EventLog.writeEvent(EVENTLOG_WIFI_STATE_CHANGED, getName());
+ }
+ @Override
+ public boolean processMessage(Message message) {
+ if (DBG) Log.d(TAG, getName() + message.toString() + "\n");
+ switch(message.what) {
+ case DRIVER_START_EVENT:
+ transitionTo(mDriverStartedState);
+ break;
+ /* Queue driver commands & connection events */
+ case CMD_START_DRIVER:
+ case CMD_STOP_DRIVER:
+ case SUPPLICANT_STATE_CHANGE_EVENT:
+ case NETWORK_CONNECTION_EVENT:
+ case NETWORK_DISCONNECTION_EVENT:
+ case PASSWORD_MAY_BE_INCORRECT_EVENT:
+ case CMD_SET_SCAN_TYPE:
+ case CMD_SET_POWER_MODE:
+ case CMD_SET_BLUETOOTH_COEXISTENCE:
+ case CMD_SET_BLUETOOTH_SCAN_MODE:
+ case CMD_SET_NUM_ALLOWED_CHANNELS:
+ case CMD_START_PACKET_FILTERING:
+ case CMD_STOP_PACKET_FILTERING:
+ deferMessage(message);
+ break;
+ /* Queue the asynchronous version of these commands */
+ case CMD_START_SCAN:
+ case CMD_DISCONNECT:
+ case CMD_REASSOCIATE:
+ case CMD_RECONNECT:
+ if (message.arg2 != SYNCHRONOUS_CALL) {
+ deferMessage(message);
+ }
+ break;
+ default:
+ return NOT_HANDLED;
+ }
+ EventLog.writeEvent(EVENTLOG_WIFI_EVENT_HANDLED, message.what);
+ return HANDLED;
+ }
+ }
+
+ class DriverStartedState extends HierarchicalState {
+ @Override
+ public void enter() {
+ if (DBG) Log.d(TAG, getName() + "\n");
+ EventLog.writeEvent(EVENTLOG_WIFI_STATE_CHANGED, getName());
+
+ try {
+ mBatteryStats.noteWifiRunning();
+ } catch (RemoteException ignore) {}
+
+ /* Initialize channel count */
+ setNumAllowedChannels();
+
+ if (mIsScanMode) {
+ WifiNative.setScanResultHandlingCommand(SCAN_ONLY_MODE);
+ WifiNative.disconnectCommand();
+ transitionTo(mScanModeState);
+ } else {
+ WifiNative.setScanResultHandlingCommand(CONNECT_MODE);
+ /* If supplicant has already connected, before we could finish establishing
+ * the control channel connection, we miss all the supplicant events.
+ * Disconnect and reconnect when driver has started to ensure we receive
+ * all supplicant events.
+ *
+ * TODO: This is a bit unclean, ideally the supplicant should never
+ * connect until told to do so by the framework
+ */
+ WifiNative.disconnectCommand();
+ WifiNative.reconnectCommand();
+ transitionTo(mConnectModeState);
+ }
+ }
+ @Override
+ public boolean processMessage(Message message) {
+ if (DBG) Log.d(TAG, getName() + message.toString() + "\n");
+ SyncParams syncParams;
+ switch(message.what) {
+ case CMD_SET_SCAN_TYPE:
+ if (message.arg1 == SCAN_ACTIVE) {
+ WifiNative.setScanModeCommand(true);
+ } else {
+ WifiNative.setScanModeCommand(false);
+ }
+ break;
+ case CMD_SET_POWER_MODE:
+ WifiNative.setPowerModeCommand(message.arg1);
+ break;
+ case CMD_SET_BLUETOOTH_COEXISTENCE:
+ WifiNative.setBluetoothCoexistenceModeCommand(message.arg1);
+ break;
+ case CMD_SET_BLUETOOTH_SCAN_MODE:
+ WifiNative.setBluetoothCoexistenceScanModeCommand(message.arg1 == 1);
+ break;
+ case CMD_SET_NUM_ALLOWED_CHANNELS:
+ mNumAllowedChannels = message.arg1;
+ WifiNative.setNumAllowedChannelsCommand(message.arg1);
+ break;
+ case CMD_START_DRIVER:
+ /* Ignore another driver start */
+ break;
+ case CMD_STOP_DRIVER:
+ WifiNative.stopDriverCommand();
+ transitionTo(mDriverStoppingState);
+ break;
+ case CMD_REQUEST_CM_WAKELOCK:
+ if (mCm == null) {
+ mCm = (ConnectivityManager)mContext.getSystemService(
+ Context.CONNECTIVITY_SERVICE);
+ }
+ mCm.requestNetworkTransitionWakelock(TAG);
+ break;
+ case CMD_START_PACKET_FILTERING:
+ WifiNative.startPacketFiltering();
+ break;
+ case CMD_STOP_PACKET_FILTERING:
+ WifiNative.stopPacketFiltering();
+ break;
+ default:
+ return NOT_HANDLED;
+ }
+ EventLog.writeEvent(EVENTLOG_WIFI_EVENT_HANDLED, message.what);
+ return HANDLED;
+ }
+ @Override
+ public void exit() {
+ if (DBG) Log.d(TAG, getName() + "\n");
+ try {
+ mBatteryStats.noteWifiStopped();
+ } catch (RemoteException ignore) { }
+ }
+ }
+
+ class DriverStoppingState extends HierarchicalState {
+ @Override
+ public void enter() {
+ if (DBG) Log.d(TAG, getName() + "\n");
+ EventLog.writeEvent(EVENTLOG_WIFI_STATE_CHANGED, getName());
+ }
+ @Override
+ public boolean processMessage(Message message) {
+ if (DBG) Log.d(TAG, getName() + message.toString() + "\n");
+ switch(message.what) {
+ case DRIVER_STOP_EVENT:
+ transitionTo(mDriverStoppedState);
+ break;
+ /* Queue driver commands */
+ case CMD_START_DRIVER:
+ case CMD_STOP_DRIVER:
+ case CMD_SET_SCAN_TYPE:
+ case CMD_SET_POWER_MODE:
+ case CMD_SET_BLUETOOTH_COEXISTENCE:
+ case CMD_SET_BLUETOOTH_SCAN_MODE:
+ case CMD_SET_NUM_ALLOWED_CHANNELS:
+ case CMD_START_PACKET_FILTERING:
+ case CMD_STOP_PACKET_FILTERING:
+ deferMessage(message);
+ break;
+ /* Queue the asynchronous version of these commands */
+ case CMD_START_SCAN:
+ case CMD_DISCONNECT:
+ case CMD_REASSOCIATE:
+ case CMD_RECONNECT:
+ if (message.arg2 != SYNCHRONOUS_CALL) {
+ deferMessage(message);
+ }
+ break;
+ default:
+ return NOT_HANDLED;
+ }
+ EventLog.writeEvent(EVENTLOG_WIFI_EVENT_HANDLED, message.what);
+ return HANDLED;
+ }
+ }
+
+ class DriverStoppedState extends HierarchicalState {
+ @Override
+ public void enter() {
+ if (DBG) Log.d(TAG, getName() + "\n");
+ EventLog.writeEvent(EVENTLOG_WIFI_STATE_CHANGED, getName());
+ }
+ @Override
+ public boolean processMessage(Message message) {
+ if (DBG) Log.d(TAG, getName() + message.toString() + "\n");
+ return NOT_HANDLED;
+ }
+ }
+
+ class ScanModeState extends HierarchicalState {
+ @Override
+ public void enter() {
+ if (DBG) Log.d(TAG, getName() + "\n");
+ EventLog.writeEvent(EVENTLOG_WIFI_STATE_CHANGED, getName());
+ }
+ @Override
+ public boolean processMessage(Message message) {
+ if (DBG) Log.d(TAG, getName() + message.toString() + "\n");
+ SyncParams syncParams;
+ switch(message.what) {
+ case CMD_SET_SCAN_MODE:
+ if (message.arg1 == SCAN_ONLY_MODE) {
+ /* Ignore */
+ return HANDLED;
+ } else {
+ WifiNative.setScanResultHandlingCommand(message.arg1);
+ WifiNative.reconnectCommand();
+ mIsScanMode = false;
+ transitionTo(mDisconnectedState);
+ }
+ break;
+ case CMD_START_SCAN:
+ if (message.arg2 == SYNCHRONOUS_CALL) {
+ syncParams = (SyncParams) message.obj;
+ syncParams.mSyncReturn.boolValue = WifiNative.scanCommand(
+ message.arg1 == SCAN_ACTIVE);
+ notifyOnMsgObject(message);
+ } else {
+ /* asynchronous handling */
+ WifiNative.scanCommand(message.arg1 == SCAN_ACTIVE);
+ }
+ break;
+ /* Ignore */
+ case CMD_DISCONNECT:
+ case CMD_RECONNECT:
+ case CMD_REASSOCIATE:
+ case SUPPLICANT_STATE_CHANGE_EVENT:
+ case NETWORK_CONNECTION_EVENT:
+ case NETWORK_DISCONNECTION_EVENT:
+ break;
+ default:
+ return NOT_HANDLED;
+ }
+ EventLog.writeEvent(EVENTLOG_WIFI_EVENT_HANDLED, message.what);
+ return HANDLED;
+ }
+ }
+
+ class ConnectModeState extends HierarchicalState {
+ @Override
+ public void enter() {
+ if (DBG) Log.d(TAG, getName() + "\n");
+ EventLog.writeEvent(EVENTLOG_WIFI_STATE_CHANGED, getName());
+ }
+ @Override
+ public boolean processMessage(Message message) {
+ if (DBG) Log.d(TAG, getName() + message.toString() + "\n");
+ SyncParams syncParams;
+ StateChangeResult stateChangeResult;
+ switch(message.what) {
+ case PASSWORD_MAY_BE_INCORRECT_EVENT:
+ mPasswordKeyMayBeIncorrect = true;
+ break;
+ case SUPPLICANT_STATE_CHANGE_EVENT:
+ stateChangeResult = (StateChangeResult) message.obj;
+ mSupplicantStateTracker.handleEvent(stateChangeResult);
+ break;
+ case CMD_START_SCAN:
+ if (message.arg2 == SYNCHRONOUS_CALL) {
+ syncParams = (SyncParams) message.obj;
+ syncParams.mSyncReturn.boolValue = true;
+ notifyOnMsgObject(message);
+ }
+ /* We need to set scan type in completed state */
+ Message newMsg = obtainMessage();
+ newMsg.copyFrom(message);
+ mSupplicantStateTracker.sendMessage(newMsg);
+ break;
+ /* Do a redundant disconnect without transition */
+ case CMD_DISCONNECT:
+ if (message.arg2 == SYNCHRONOUS_CALL) {
+ syncParams = (SyncParams) message.obj;
+ syncParams.mSyncReturn.boolValue = WifiNative.disconnectCommand();
+ notifyOnMsgObject(message);
+ } else {
+ /* asynchronous handling */
+ WifiNative.disconnectCommand();
+ }
+ break;
+ case CMD_RECONNECT:
+ if (message.arg2 == SYNCHRONOUS_CALL) {
+ syncParams = (SyncParams) message.obj;
+ syncParams.mSyncReturn.boolValue = WifiNative.reconnectCommand();
+ notifyOnMsgObject(message);
+ } else {
+ /* asynchronous handling */
+ WifiNative.reconnectCommand();
+ }
+ break;
+ case CMD_REASSOCIATE:
+ if (message.arg2 == SYNCHRONOUS_CALL) {
+ syncParams = (SyncParams) message.obj;
+ syncParams.mSyncReturn.boolValue = WifiNative.reassociateCommand();
+ notifyOnMsgObject(message);
+ } else {
+ /* asynchronous handling */
+ WifiNative.reassociateCommand();
+ }
+ break;
+ case SCAN_RESULTS_EVENT:
+ /* Set the scan setting back to "connect" mode */
+ WifiNative.setScanResultHandlingCommand(CONNECT_MODE);
+ /* Handle scan results */
+ return NOT_HANDLED;
+ case NETWORK_CONNECTION_EVENT:
+ Log.d(TAG,"Network connection established");
+ stateChangeResult = (StateChangeResult) message.obj;
+
+ mWifiInfo.setBSSID(mLastBssid = stateChangeResult.BSSID);
+ mWifiInfo.setNetworkId(stateChangeResult.networkId);
+ mLastNetworkId = stateChangeResult.networkId;
+
+ /* send event to CM & network change broadcast */
+ setDetailedState(DetailedState.OBTAINING_IPADDR);
+ sendNetworkStateChangeBroadcast(mLastBssid);
+
+ transitionTo(mConnectingState);
+ break;
+ case NETWORK_DISCONNECTION_EVENT:
+ Log.d(TAG,"Network connection lost");
+ handleNetworkDisconnect();
+ transitionTo(mDisconnectedState);
+ break;
+ case CMD_GET_RSSI:
+ syncParams = (SyncParams) message.obj;
+ syncParams.mSyncReturn.intValue = WifiNative.getRssiCommand();
+ notifyOnMsgObject(message);
+ break;
+ case CMD_GET_RSSI_APPROX:
+ syncParams = (SyncParams) message.obj;
+ syncParams.mSyncReturn.intValue = WifiNative.getRssiApproxCommand();
+ notifyOnMsgObject(message);
+ break;
+ case CMD_GET_LINK_SPEED:
+ syncParams = (SyncParams) message.obj;
+ syncParams.mSyncReturn.intValue = WifiNative.getLinkSpeedCommand();
+ notifyOnMsgObject(message);
+ break;
+ default:
+ return NOT_HANDLED;
+ }
+ EventLog.writeEvent(EVENTLOG_WIFI_EVENT_HANDLED, message.what);
+ return HANDLED;
+ }
+ }
+
+ class ConnectingState extends HierarchicalState {
+ boolean modifiedBluetoothCoexistenceMode;
+ int powerMode;
+ Thread mDhcpThread;
+
+ @Override
+ public void enter() {
+ if (DBG) Log.d(TAG, getName() + "\n");
+ EventLog.writeEvent(EVENTLOG_WIFI_STATE_CHANGED, getName());
+
+ if (!mUseStaticIp) {
+
+ mDhcpThread = null;
+ modifiedBluetoothCoexistenceMode = false;
+ powerMode = DRIVER_POWER_MODE_AUTO;
+
+ if (shouldDisableCoexistenceMode()) {
+ /*
+ * There are problems setting the Wi-Fi driver's power
+ * mode to active when bluetooth coexistence mode is
+ * enabled or sense.
+ * <p>
+ * We set Wi-Fi to active mode when
+ * obtaining an IP address because we've found
+ * compatibility issues with some routers with low power
+ * mode.
+ * <p>
+ * In order for this active power mode to properly be set,
+ * we disable coexistence mode until we're done with
+ * obtaining an IP address. One exception is if we
+ * are currently connected to a headset, since disabling
+ * coexistence would interrupt that connection.
+ */
+ modifiedBluetoothCoexistenceMode = true;
+
+ // Disable the coexistence mode
+ WifiNative.setBluetoothCoexistenceModeCommand(
+ WifiNative.BLUETOOTH_COEXISTENCE_MODE_DISABLED);
+ }
+
+ powerMode = WifiNative.getPowerModeCommand();
+ if (powerMode < 0) {
+ // Handle the case where supplicant driver does not support
+ // getPowerModeCommand.
+ powerMode = DRIVER_POWER_MODE_AUTO;
+ }
+ if (powerMode != DRIVER_POWER_MODE_ACTIVE) {
+ WifiNative.setPowerModeCommand(DRIVER_POWER_MODE_ACTIVE);
+ }
+
+ Log.d(TAG, "DHCP request started");
+ mDhcpThread = new Thread(new Runnable() {
+ public void run() {
+ if (NetworkUtils.runDhcp(mInterfaceName, mDhcpInfo)) {
+ Log.d(TAG, "DHCP request succeeded");
+ sendMessage(CMD_IP_CONFIG_SUCCESS);
+ } else {
+ Log.d(TAG, "DHCP request failed: " +
+ NetworkUtils.getDhcpError());
+ sendMessage(CMD_IP_CONFIG_FAILURE);
+ }
+ }
+ });
+ mDhcpThread.start();
+ } else {
+ if (NetworkUtils.configureInterface(mInterfaceName, mDhcpInfo)) {
+ Log.v(TAG, "Static IP configuration succeeded");
+ sendMessage(CMD_IP_CONFIG_SUCCESS);
+ } else {
+ Log.v(TAG, "Static IP configuration failed");
+ sendMessage(CMD_IP_CONFIG_FAILURE);
+ }
+ }
+ }
+ @Override
+ public boolean processMessage(Message message) {
+ if (DBG) Log.d(TAG, getName() + message.toString() + "\n");
+
+ switch(message.what) {
+ case CMD_IP_CONFIG_SUCCESS:
+ mReconnectCount = 0;
+ mLastSignalLevel = -1; // force update of signal strength
+ mWifiInfo.setIpAddress(mDhcpInfo.ipAddress);
+ Log.d(TAG, "IP configuration: " + mDhcpInfo);
+ configureNetworkProperties();
+ setDetailedState(DetailedState.CONNECTED);
+ sendNetworkStateChangeBroadcast(mLastBssid);
+ //TODO: we could also detect an IP config change
+ // from a DHCP renewal and send out a config change
+ // broadcast
+ if (mConfigChanged) {
+ sendConfigChangeBroadcast();
+ mConfigChanged = false;
+ }
+ transitionTo(mConnectedState);
+ break;
+ case CMD_IP_CONFIG_FAILURE:
+ mWifiInfo.setIpAddress(0);
+
+ Log.e(TAG, "IP configuration failed");
+ /**
+ * If we've exceeded the maximum number of retries for DHCP
+ * to a given network, disable the network
+ */
+ if (++mReconnectCount > getMaxDhcpRetries()) {
+ Log.e(TAG, "Failed " +
+ mReconnectCount + " times, Disabling " + mLastNetworkId);
+ WifiNative.disableNetworkCommand(mLastNetworkId);
+ }
+
+ /* DHCP times out after about 30 seconds, we do a
+ * disconnect and an immediate reconnect to try again
+ */
+ WifiNative.disconnectCommand();
+ WifiNative.reconnectCommand();
+ transitionTo(mDisconnectingState);
+ break;
+ case CMD_DISCONNECT:
+ if (message.arg2 == SYNCHRONOUS_CALL) {
+ SyncParams syncParams = (SyncParams) message.obj;
+ syncParams.mSyncReturn.boolValue = WifiNative.disconnectCommand();
+ notifyOnMsgObject(message);
+ } else {
+ /* asynchronous handling */
+ WifiNative.disconnectCommand();
+ }
+ transitionTo(mDisconnectingState);
+ break;
+ /* Ignore */
+ case NETWORK_CONNECTION_EVENT:
+ break;
+ case CMD_STOP_DRIVER:
+ sendMessage(CMD_DISCONNECT);
+ deferMessage(message);
+ break;
+ case CMD_SET_SCAN_MODE:
+ if (message.arg1 == SCAN_ONLY_MODE) {
+ sendMessage(CMD_DISCONNECT);
+ deferMessage(message);
+ }
+ break;
+ case CMD_RECONFIGURE_IP:
+ deferMessage(message);
+ break;
+ default:
+ return NOT_HANDLED;
+ }
+ EventLog.writeEvent(EVENTLOG_WIFI_EVENT_HANDLED, message.what);
+ return HANDLED;
+ }
+
+ @Override
+ public void exit() {
+ /* reset power state & bluetooth coexistence if on DHCP */
+ if (!mUseStaticIp) {
+ if (powerMode != DRIVER_POWER_MODE_ACTIVE) {
+ WifiNative.setPowerModeCommand(powerMode);
+ }
+
+ if (modifiedBluetoothCoexistenceMode) {
+ // Set the coexistence mode back to its default value
+ WifiNative.setBluetoothCoexistenceModeCommand(
+ WifiNative.BLUETOOTH_COEXISTENCE_MODE_SENSE);
+ }
+ }
+
+ }
+ }
+
+ class ConnectedState extends HierarchicalState {
+ @Override
+ public void enter() {
+ if (DBG) Log.d(TAG, getName() + "\n");
+ EventLog.writeEvent(EVENTLOG_WIFI_STATE_CHANGED, getName());
+ }
+ @Override
+ public boolean processMessage(Message message) {
+ if (DBG) Log.d(TAG, getName() + message.toString() + "\n");
+ switch (message.what) {
+ case CMD_DISCONNECT:
+ if (message.arg2 == SYNCHRONOUS_CALL) {
+ SyncParams syncParams = (SyncParams) message.obj;
+ syncParams.mSyncReturn.boolValue = WifiNative.disconnectCommand();
+ notifyOnMsgObject(message);
+ } else {
+ /* asynchronous handling */
+ WifiNative.disconnectCommand();
+ }
+ transitionTo(mDisconnectingState);
+ break;
+ case CMD_RECONFIGURE_IP:
+ Log.d(TAG,"Reconfiguring IP on connection");
+ NetworkUtils.resetConnections(mInterfaceName);
+ transitionTo(mConnectingState);
+ break;
+ case CMD_STOP_DRIVER:
+ sendMessage(CMD_DISCONNECT);
+ deferMessage(message);
+ break;
+ case CMD_SET_SCAN_MODE:
+ if (message.arg1 == SCAN_ONLY_MODE) {
+ sendMessage(CMD_DISCONNECT);
+ deferMessage(message);
+ }
+ break;
+ /* Ignore */
+ case NETWORK_CONNECTION_EVENT:
+ break;
+ default:
+ return NOT_HANDLED;
+ }
+ EventLog.writeEvent(EVENTLOG_WIFI_EVENT_HANDLED, message.what);
+ return HANDLED;
+ }
+ }
+
+ class DisconnectingState extends HierarchicalState {
+ @Override
+ public void enter() {
+ if (DBG) Log.d(TAG, getName() + "\n");
+ EventLog.writeEvent(EVENTLOG_WIFI_STATE_CHANGED, getName());
+ }
+ @Override
+ public boolean processMessage(Message message) {
+ if (DBG) Log.d(TAG, getName() + message.toString() + "\n");
+ switch (message.what) {
+ case CMD_STOP_DRIVER: /* Stop driver only after disconnect handled */
+ deferMessage(message);
+ break;
+ case CMD_SET_SCAN_MODE:
+ if (message.arg1 == SCAN_ONLY_MODE) {
+ deferMessage(message);
+ }
+ break;
+ default:
+ return NOT_HANDLED;
+ }
+ EventLog.writeEvent(EVENTLOG_WIFI_EVENT_HANDLED, message.what);
+ return HANDLED;
+ }
+ }
+
+ class DisconnectedState extends HierarchicalState {
+ @Override
+ public void enter() {
+ if (DBG) Log.d(TAG, getName() + "\n");
+ EventLog.writeEvent(EVENTLOG_WIFI_STATE_CHANGED, getName());
+ }
+ @Override
+ public boolean processMessage(Message message) {
+ if (DBG) Log.d(TAG, getName() + message.toString() + "\n");
+ switch (message.what) {
+ case CMD_SET_SCAN_MODE:
+ if (message.arg1 == SCAN_ONLY_MODE) {
+ WifiNative.setScanResultHandlingCommand(message.arg1);
+ //Supplicant disconnect to prevent further connects
+ WifiNative.disconnectCommand();
+ mIsScanMode = true;
+ transitionTo(mScanModeState);
+ }
+ break;
+ /* Ignore network disconnect */
+ case NETWORK_DISCONNECTION_EVENT:
+ break;
+ default:
+ return NOT_HANDLED;
+ }
+ EventLog.writeEvent(EVENTLOG_WIFI_EVENT_HANDLED, message.what);
+ return HANDLED;
+ }
+ }
+
+ class SoftApStartedState extends HierarchicalState {
+ @Override
+ public void enter() {
+ if (DBG) Log.d(TAG, getName() + "\n");
+ EventLog.writeEvent(EVENTLOG_WIFI_STATE_CHANGED, getName());
+ }
+ @Override
+ public boolean processMessage(Message message) {
+ if (DBG) Log.d(TAG, getName() + message.toString() + "\n");
+ switch(message.what) {
+ case CMD_STOP_AP:
+ Log.d(TAG,"Stopping Soft AP");
+ setWifiApState(WIFI_AP_STATE_DISABLING);
+ try {
+ nwService.stopAccessPoint();
+ } catch(Exception e) {
+ Log.e(TAG, "Exception in stopAccessPoint()");
+ }
+ transitionTo(mDriverLoadedState);
+ break;
+ case CMD_START_AP:
+ Log.d(TAG,"SoftAP set on a running access point");
+ try {
+ nwService.setAccessPoint((WifiConfiguration) message.obj,
+ mInterfaceName,
+ SOFTAP_IFACE);
+ } catch(Exception e) {
+ Log.e(TAG, "Exception in nwService during soft AP set");
+ try {
+ nwService.stopAccessPoint();
+ } catch (Exception ee) {
+ Slog.e(TAG, "Could not stop AP, :" + ee);
+ }
+ sendMessage(obtainMessage(CMD_UNLOAD_DRIVER, WIFI_AP_STATE_FAILED, 0));
+ }
+ break;
+ /* Fail client mode operation when soft AP is enabled */
+ case CMD_START_SUPPLICANT:
+ Log.e(TAG,"Cannot start supplicant with a running soft AP");
+ setWifiState(WIFI_STATE_UNKNOWN);
+ break;
+ default:
+ return NOT_HANDLED;
+ }
+ EventLog.writeEvent(EVENTLOG_WIFI_EVENT_HANDLED, message.what);
+ return HANDLED;
+ }
+ }
+
+
+ class SupplicantStateTracker extends HierarchicalStateMachine {
+
+ private int mRssiPollToken = 0;
+
+ /**
+ * The max number of the WPA supplicant loop iterations before we
+ * decide that the loop should be terminated:
+ */
+ private static final int MAX_SUPPLICANT_LOOP_ITERATIONS = 4;
+ private int mLoopDetectIndex = 0;
+ private int mLoopDetectCount = 0;
+
+ /**
+ * Supplicant state change commands follow
+ * the ordinal values defined in SupplicantState.java
+ */
+ private static final int DISCONNECTED = 0;
+ private static final int INACTIVE = 1;
+ private static final int SCANNING = 2;
+ private static final int ASSOCIATING = 3;
+ private static final int ASSOCIATED = 4;
+ private static final int FOUR_WAY_HANDSHAKE = 5;
+ private static final int GROUP_HANDSHAKE = 6;
+ private static final int COMPLETED = 7;
+ private static final int DORMANT = 8;
+ private static final int UNINITIALIZED = 9;
+ private static final int INVALID = 10;
+
+ private HierarchicalState mUninitializedState = new UninitializedState();
+ private HierarchicalState mInitializedState = new InitializedState();;
+ private HierarchicalState mInactiveState = new InactiveState();
+ private HierarchicalState mDisconnectState = new DisconnectedState();
+ private HierarchicalState mScanState = new ScanState();
+ private HierarchicalState mConnectState = new ConnectState();
+ private HierarchicalState mHandshakeState = new HandshakeState();
+ private HierarchicalState mCompletedState = new CompletedState();
+ private HierarchicalState mDormantState = new DormantState();
+
+ public SupplicantStateTracker(Context context, Handler target) {
+ super(TAG, target.getLooper());
+
+ addState(mUninitializedState);
+ addState(mInitializedState);
+ addState(mInactiveState, mInitializedState);
+ addState(mDisconnectState, mInitializedState);
+ addState(mScanState, mInitializedState);
+ addState(mConnectState, mInitializedState);
+ addState(mHandshakeState, mConnectState);
+ addState(mCompletedState, mConnectState);
+ addState(mDormantState, mInitializedState);
+
+ setInitialState(mUninitializedState);
+
+ //start the state machine
+ start();
+ }
+
+ public void handleEvent(StateChangeResult stateChangeResult) {
+ SupplicantState newState = (SupplicantState) stateChangeResult.state;
+
+ // Supplicant state change
+ // [31-13] Reserved for future use
+ // [8 - 0] Supplicant state (as defined in SupplicantState.java)
+ // 50023 supplicant_state_changed (custom|1|5)
+ EventLog.writeEvent(EVENTLOG_SUPPLICANT_STATE_CHANGED, newState.ordinal());
+
+ sendMessage(obtainMessage(newState.ordinal(), stateChangeResult));
+ }
+
+ public void resetSupplicantState() {
+ transitionTo(mUninitializedState);
+ }
+
+ private void resetLoopDetection() {
+ mLoopDetectCount = 0;
+ mLoopDetectIndex = 0;
+ }
+
+ private boolean handleTransition(Message msg) {
+ if (DBG) Log.d(TAG, getName() + msg.toString() + "\n");
+ switch (msg.what) {
+ case DISCONNECTED:
+ transitionTo(mDisconnectState);
+ break;
+ case SCANNING:
+ transitionTo(mScanState);
+ break;
+ case ASSOCIATING:
+ StateChangeResult stateChangeResult = (StateChangeResult) msg.obj;
+ /* BSSID is valid only in ASSOCIATING state */
+ mWifiInfo.setBSSID(stateChangeResult.BSSID);
+ //$FALL-THROUGH$
+ case ASSOCIATED:
+ case FOUR_WAY_HANDSHAKE:
+ case GROUP_HANDSHAKE:
+ transitionTo(mHandshakeState);
+ break;
+ case COMPLETED:
+ transitionTo(mCompletedState);
+ break;
+ case DORMANT:
+ transitionTo(mDormantState);
+ break;
+ case INACTIVE:
+ transitionTo(mInactiveState);
+ break;
+ case UNINITIALIZED:
+ case INVALID:
+ transitionTo(mUninitializedState);
+ break;
+ default:
+ return NOT_HANDLED;
+ }
+ StateChangeResult stateChangeResult = (StateChangeResult) msg.obj;
+ SupplicantState supState = (SupplicantState) stateChangeResult.state;
+ setDetailedState(WifiInfo.getDetailedStateOf(supState));
+ mWifiInfo.setSupplicantState(supState);
+ mWifiInfo.setNetworkId(stateChangeResult.networkId);
+ //TODO: Modify WifiMonitor to report SSID on events
+ //mWifiInfo.setSSID()
+ return HANDLED;
+ }
+
+ /********************************************************
+ * HSM states
+ *******************************************************/
+
+ class InitializedState extends HierarchicalState {
+ @Override
+ public void enter() {
+ if (DBG) Log.d(TAG, getName() + "\n");
+ }
+ @Override
+ public boolean processMessage(Message message) {
+ if (DBG) Log.d(TAG, getName() + message.toString() + "\n");
+ switch (message.what) {
+ case CMD_START_SCAN:
+ WifiNative.scanCommand(message.arg1 == SCAN_ACTIVE);
+ break;
+ default:
+ if (DBG) Log.w(TAG, "Ignoring " + message);
+ break;
+ }
+ return HANDLED;
+ }
+ }
+
+ class UninitializedState extends HierarchicalState {
+ @Override
+ public void enter() {
+ if (DBG) Log.d(TAG, getName() + "\n");
+ mNetworkInfo.setIsAvailable(false);
+ resetLoopDetection();
+ mPasswordKeyMayBeIncorrect = false;
+ }
+ @Override
+ public boolean processMessage(Message message) {
+ switch(message.what) {
+ default:
+ if (!handleTransition(message)) {
+ if (DBG) Log.w(TAG, "Ignoring " + message);
+ }
+ break;
+ }
+ return HANDLED;
+ }
+ @Override
+ public void exit() {
+ mNetworkInfo.setIsAvailable(true);
+ }
+ }
+
+ class InactiveState extends HierarchicalState {
+ @Override
+ public void enter() {
+ if (DBG) Log.d(TAG, getName() + "\n");
+ Message message = getCurrentMessage();
+ StateChangeResult stateChangeResult = (StateChangeResult) message.obj;
+
+ mNetworkInfo.setIsAvailable(false);
+ resetLoopDetection();
+ mPasswordKeyMayBeIncorrect = false;
+
+ sendSupplicantStateChangedBroadcast(stateChangeResult, false);
+ }
+ @Override
+ public boolean processMessage(Message message) {
+ return handleTransition(message);
+ }
+ @Override
+ public void exit() {
+ mNetworkInfo.setIsAvailable(true);
+ }
+ }
+
+
+ class DisconnectedState extends HierarchicalState {
+ @Override
+ public void enter() {
+ if (DBG) Log.d(TAG, getName() + "\n");
+ Message message = getCurrentMessage();
+ StateChangeResult stateChangeResult = (StateChangeResult) message.obj;
+
+ resetLoopDetection();
+
+ /* If a disconnect event happens after a password key failure
+ * event, disable the network
+ */
+ if (mPasswordKeyMayBeIncorrect) {
+ Log.d(TAG, "Failed to authenticate, disabling network " +
+ mWifiInfo.getNetworkId());
+ WifiNative.disableNetworkCommand(mWifiInfo.getNetworkId());
+ mPasswordKeyMayBeIncorrect = false;
+ sendSupplicantStateChangedBroadcast(stateChangeResult, true);
+ }
+ else {
+ sendSupplicantStateChangedBroadcast(stateChangeResult, false);
+ }
+ }
+ @Override
+ public boolean processMessage(Message message) {
+ return handleTransition(message);
+ }
+ }
+
+ class ScanState extends HierarchicalState {
+ @Override
+ public void enter() {
+ if (DBG) Log.d(TAG, getName() + "\n");
+ Message message = getCurrentMessage();
+ StateChangeResult stateChangeResult = (StateChangeResult) message.obj;
+
+ mPasswordKeyMayBeIncorrect = false;
+ resetLoopDetection();
+ sendSupplicantStateChangedBroadcast(stateChangeResult, false);
+ }
+ @Override
+ public boolean processMessage(Message message) {
+ return handleTransition(message);
+ }
+ }
+
+ class ConnectState extends HierarchicalState {
+ @Override
+ public void enter() {
+ if (DBG) Log.d(TAG, getName() + "\n");
+ }
+ @Override
+ public boolean processMessage(Message message) {
+ switch (message.what) {
+ case CMD_START_SCAN:
+ WifiNative.setScanResultHandlingCommand(SCAN_ONLY_MODE);
+ WifiNative.scanCommand(message.arg1 == SCAN_ACTIVE);
+ break;
+ default:
+ return NOT_HANDLED;
+ }
+ return HANDLED;
+ }
+ }
+
+ class HandshakeState extends HierarchicalState {
+ @Override
+ public void enter() {
+ if (DBG) Log.d(TAG, getName() + "\n");
+ final Message message = getCurrentMessage();
+ StateChangeResult stateChangeResult = (StateChangeResult) message.obj;
+
+ if (mLoopDetectIndex > message.what) {
+ mLoopDetectCount++;
+ }
+ if (mLoopDetectCount > MAX_SUPPLICANT_LOOP_ITERATIONS) {
+ WifiNative.disableNetworkCommand(stateChangeResult.networkId);
+ mLoopDetectCount = 0;
+ }
+
+ mLoopDetectIndex = message.what;
+
+ mPasswordKeyMayBeIncorrect = false;
+ sendSupplicantStateChangedBroadcast(stateChangeResult, false);
+ }
+ @Override
+ public boolean processMessage(Message message) {
+ return handleTransition(message);
+ }
+ }
+
+ class CompletedState extends HierarchicalState {
+ @Override
+ public void enter() {
+ if (DBG) Log.d(TAG, getName() + "\n");
+ Message message = getCurrentMessage();
+ StateChangeResult stateChangeResult = (StateChangeResult) message.obj;
+
+ mRssiPollToken++;
+ if (mEnableRssiPolling) {
+ sendMessageDelayed(obtainMessage(CMD_RSSI_POLL, mRssiPollToken, 0),
+ POLL_RSSI_INTERVAL_MSECS);
+ }
+
+ resetLoopDetection();
+
+ mPasswordKeyMayBeIncorrect = false;
+ sendSupplicantStateChangedBroadcast(stateChangeResult, false);
+ }
+ @Override
+ public boolean processMessage(Message message) {
+ switch(message.what) {
+ case ASSOCIATING:
+ case ASSOCIATED:
+ case FOUR_WAY_HANDSHAKE:
+ case GROUP_HANDSHAKE:
+ case COMPLETED:
+ break;
+ case CMD_RSSI_POLL:
+ if (message.arg1 == mRssiPollToken) {
+ // Get Info and continue polling
+ requestPolledInfo();
+ sendMessageDelayed(obtainMessage(CMD_RSSI_POLL, mRssiPollToken, 0),
+ POLL_RSSI_INTERVAL_MSECS);
+ } else {
+ // Polling has completed
+ }
+ break;
+ case CMD_ENABLE_RSSI_POLL:
+ mRssiPollToken++;
+ if (mEnableRssiPolling) {
+ // first poll
+ requestPolledInfo();
+ sendMessageDelayed(obtainMessage(CMD_RSSI_POLL, mRssiPollToken, 0),
+ POLL_RSSI_INTERVAL_MSECS);
+ }
+ break;
+ default:
+ return handleTransition(message);
+ }
+ return HANDLED;
+ }
+ }
+
+ class DormantState extends HierarchicalState {
+ @Override
+ public void enter() {
+ if (DBG) Log.d(TAG, getName() + "\n");
+ Message message = getCurrentMessage();
+ StateChangeResult stateChangeResult = (StateChangeResult) message.obj;
+
+ resetLoopDetection();
+ mPasswordKeyMayBeIncorrect = false;
+
+ sendSupplicantStateChangedBroadcast(stateChangeResult, false);
+
+ /* TODO: reconnect is now being handled at DHCP failure handling
+ * If we run into issues with staying in Dormant state, might
+ * need a reconnect here
+ */
+ }
+ @Override
+ public boolean processMessage(Message message) {
+ return handleTransition(message);
+ }
+ }
+ }
+}
diff --git a/wifi/java/android/net/wifi/WifiStateTracker.java b/wifi/java/android/net/wifi/WifiStateTracker.java
index 388beea..8e1b236 100644
--- a/wifi/java/android/net/wifi/WifiStateTracker.java
+++ b/wifi/java/android/net/wifi/WifiStateTracker.java
@@ -16,524 +16,59 @@
package android.net.wifi;
-import static android.net.wifi.WifiManager.WIFI_STATE_DISABLED;
-import static android.net.wifi.WifiManager.WIFI_STATE_DISABLING;
-import static android.net.wifi.WifiManager.WIFI_STATE_ENABLED;
-import static android.net.wifi.WifiManager.WIFI_STATE_ENABLING;
-import static android.net.wifi.WifiManager.WIFI_STATE_UNKNOWN;
-/**
- * TODO: Add soft AP states as part of WIFI_STATE_XXX
- * Retain WIFI_STATE_ENABLING that indicates driver is loading
- * Add WIFI_STATE_AP_ENABLED to indicate soft AP has started
- * and WIFI_STATE_FAILED for failure
- * Deprecate WIFI_STATE_UNKNOWN
- *
- * Doing this will simplify the logic for sending broadcasts
- */
-import static android.net.wifi.WifiManager.WIFI_AP_STATE_DISABLED;
-import static android.net.wifi.WifiManager.WIFI_AP_STATE_DISABLING;
-import static android.net.wifi.WifiManager.WIFI_AP_STATE_ENABLED;
-import static android.net.wifi.WifiManager.WIFI_AP_STATE_ENABLING;
-import static android.net.wifi.WifiManager.WIFI_AP_STATE_FAILED;
-import android.app.ActivityManagerNative;
-import android.net.NetworkInfo;
-import android.net.NetworkStateTracker;
-import android.net.DhcpInfo;
-import android.net.NetworkUtils;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
import android.net.ConnectivityManager;
-import android.net.NetworkInfo.DetailedState;
-import android.net.NetworkInfo.State;
+import android.net.NetworkInfo;
import android.net.NetworkProperties;
-import android.os.Binder;
-import android.os.Message;
-import android.os.Parcelable;
+import android.net.NetworkStateTracker;
import android.os.Handler;
-import android.os.IBinder;
-import android.os.INetworkManagementService;
-import android.os.PowerManager;
-import android.os.SystemProperties;
-import android.os.RemoteException;
-import android.os.ServiceManager;
-import android.os.Process;
-import android.provider.Settings;
-import android.text.TextUtils;
-import android.util.EventLog;
-import android.util.Log;
-import android.util.Slog;
-import android.app.Notification;
-import android.app.PendingIntent;
-import android.app.backup.IBackupManager;
-import android.bluetooth.BluetoothDevice;
-import android.bluetooth.BluetoothHeadset;
-import android.bluetooth.BluetoothA2dp;
-import android.content.ContentResolver;
-import android.content.Intent;
-import android.content.Context;
-import android.database.ContentObserver;
-import com.android.internal.app.IBatteryStats;
-import com.android.internal.util.HierarchicalState;
-import com.android.internal.util.HierarchicalStateMachine;
+import android.os.Message;
-import java.net.InetAddress;
-import java.net.NetworkInterface;
-import java.net.SocketException;
-import java.net.UnknownHostException;
-import java.util.ArrayList;
-import java.util.BitSet;
-import java.util.LinkedHashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;
-import java.util.regex.Pattern;
/**
- * Track the state of Wifi connectivity. All event handling is done here,
- * and all changes in connectivity state are initiated here.
+ * Track the state of wifi for connectivity service.
*
* @hide
*/
-//TODO: we still need frequent scanning for the case when
-// we issue disconnect but need scan results for open network notification
-public class WifiStateTracker extends HierarchicalStateMachine implements NetworkStateTracker {
+public class WifiStateTracker implements NetworkStateTracker {
- private static final String TAG = "WifiStateTracker";
private static final String NETWORKTYPE = "WIFI";
- private static final boolean DBG = false;
-
- /* TODO: fetch a configurable interface */
- private static final String SOFTAP_IFACE = "wl0.1";
-
- private WifiMonitor mWifiMonitor;
- private INetworkManagementService nwService;
- private ConnectivityManager mCm;
-
- /* Scan results handling */
- private List<ScanResult> mScanResults;
- private static final Pattern scanResultPattern = Pattern.compile("\t+");
- private static final int SCAN_RESULT_CACHE_SIZE = 80;
- private final LinkedHashMap<String, ScanResult> mScanResultCache;
+ private static final String TAG = "WifiStateTracker";
- private String mInterfaceName;
private AtomicBoolean mTeardownRequested = new AtomicBoolean(false);
private AtomicBoolean mPrivateDnsRouteSet = new AtomicBoolean(false);
private AtomicInteger mDefaultGatewayAddr = new AtomicInteger(0);
private AtomicBoolean mDefaultRouteSet = new AtomicBoolean(false);
- private int mNumAllowedChannels = 0;
- private int mLastSignalLevel = -1;
- private String mLastBssid;
- private int mLastNetworkId;
- private boolean mEnableRssiPolling = false;
- private boolean mPasswordKeyMayBeIncorrect = false;
- private boolean mUseStaticIp = false;
- private int mReconnectCount = 0;
- private boolean mIsScanMode = false;
-
- /**
- * Instance of the bluetooth headset helper. This needs to be created
- * early because there is a delay before it actually 'connects', as
- * noted by its javadoc. If we check before it is connected, it will be
- * in an error state and we will not disable coexistence.
- */
- private BluetoothHeadset mBluetoothHeadset;
-
- private BluetoothA2dp mBluetoothA2dp;
-
- /**
- * Observes the static IP address settings.
- */
- private SettingsObserver mSettingsObserver;
private NetworkProperties mNetworkProperties;
-
-
- // Variables relating to the 'available networks' notification
- /**
- * The icon to show in the 'available networks' notification. This will also
- * be the ID of the Notification given to the NotificationManager.
- */
- private static final int ICON_NETWORKS_AVAILABLE =
- com.android.internal.R.drawable.stat_notify_wifi_in_range;
- /**
- * When a notification is shown, we wait this amount before possibly showing it again.
- */
- private final long NOTIFICATION_REPEAT_DELAY_MS;
- /**
- * Whether the user has set the setting to show the 'available networks' notification.
- */
- private boolean mNotificationEnabled;
- /**
- * Observes the user setting to keep {@link #mNotificationEnabled} in sync.
- */
- private NotificationEnabledSettingObserver mNotificationEnabledSettingObserver;
- /**
- * The {@link System#currentTimeMillis()} must be at least this value for us
- * to show the notification again.
- */
- private long mNotificationRepeatTime;
- /**
- * The Notification object given to the NotificationManager.
- */
- private Notification mNotification;
- /**
- * Whether the notification is being shown, as set by us. That is, if the
- * user cancels the notification, we will not receive the callback so this
- * will still be true. We only guarantee if this is false, then the
- * notification is not showing.
- */
- private boolean mNotificationShown;
- /**
- * The number of continuous scans that must occur before consider the
- * supplicant in a scanning state. This allows supplicant to associate with
- * remembered networks that are in the scan results.
- */
- private static final int NUM_SCANS_BEFORE_ACTUALLY_SCANNING = 3;
- /**
- * The number of scans since the last network state change. When this
- * exceeds {@link #NUM_SCANS_BEFORE_ACTUALLY_SCANNING}, we consider the
- * supplicant to actually be scanning. When the network state changes to
- * something other than scanning, we reset this to 0.
- */
- private int mNumScansSinceNetworkStateChange;
-
- // Held during driver load and unload
- private static PowerManager.WakeLock sWakeLock;
+ private NetworkInfo mNetworkInfo;
/* For sending events to connectivity service handler */
private Handler mCsHandler;
private Context mContext;
-
- private DhcpInfo mDhcpInfo;
- private WifiInfo mWifiInfo;
- private NetworkInfo mNetworkInfo;
- private SupplicantStateTracker mSupplicantStateTracker;
-
- // Event log tags (must be in sync with event-log-tags)
- private static final int EVENTLOG_WIFI_STATE_CHANGED = 50021;
- private static final int EVENTLOG_WIFI_EVENT_HANDLED = 50022;
- private static final int EVENTLOG_SUPPLICANT_STATE_CHANGED = 50023;
-
- /* Load the driver */
- private static final int CMD_LOAD_DRIVER = 1;
- /* Unload the driver */
- private static final int CMD_UNLOAD_DRIVER = 2;
- /* Indicates driver load succeeded */
- private static final int CMD_LOAD_DRIVER_SUCCESS = 3;
- /* Indicates driver load failed */
- private static final int CMD_LOAD_DRIVER_FAILURE = 4;
- /* Indicates driver unload succeeded */
- private static final int CMD_UNLOAD_DRIVER_SUCCESS = 5;
- /* Indicates driver unload failed */
- private static final int CMD_UNLOAD_DRIVER_FAILURE = 6;
-
- /* Start the supplicant */
- private static final int CMD_START_SUPPLICANT = 11;
- /* Stop the supplicant */
- private static final int CMD_STOP_SUPPLICANT = 12;
- /* Start the driver */
- private static final int CMD_START_DRIVER = 13;
- /* Start the driver */
- private static final int CMD_STOP_DRIVER = 14;
- /* Indicates DHCP succeded */
- private static final int CMD_IP_CONFIG_SUCCESS = 15;
- /* Indicates DHCP failed */
- private static final int CMD_IP_CONFIG_FAILURE = 16;
- /* Re-configure interface */
- private static final int CMD_RECONFIGURE_IP = 17;
-
-
- /* Start the soft access point */
- private static final int CMD_START_AP = 21;
- /* Stop the soft access point */
- private static final int CMD_STOP_AP = 22;
-
-
- /* Supplicant events */
- /* Connection to supplicant established */
- private static final int SUP_CONNECTION_EVENT = 31;
- /* Connection to supplicant lost */
- private static final int SUP_DISCONNECTION_EVENT = 32;
- /* Driver start completed */
- private static final int DRIVER_START_EVENT = 33;
- /* Driver stop completed */
- private static final int DRIVER_STOP_EVENT = 34;
- /* Network connection completed */
- private static final int NETWORK_CONNECTION_EVENT = 36;
- /* Network disconnection completed */
- private static final int NETWORK_DISCONNECTION_EVENT = 37;
- /* Scan results are available */
- private static final int SCAN_RESULTS_EVENT = 38;
- /* Supplicate state changed */
- private static final int SUPPLICANT_STATE_CHANGE_EVENT = 39;
- /* Password may be incorrect */
- private static final int PASSWORD_MAY_BE_INCORRECT_EVENT = 40;
-
- /* Supplicant commands */
- /* Is supplicant alive ? */
- private static final int CMD_PING_SUPPLICANT = 51;
- /* Add/update a network configuration */
- private static final int CMD_ADD_OR_UPDATE_NETWORK = 52;
- /* Delete a network */
- private static final int CMD_REMOVE_NETWORK = 53;
- /* Enable a network. The device will attempt a connection to the given network. */
- private static final int CMD_ENABLE_NETWORK = 54;
- /* Disable a network. The device does not attempt a connection to the given network. */
- private static final int CMD_DISABLE_NETWORK = 55;
- /* Blacklist network. De-prioritizes the given BSSID for connection. */
- private static final int CMD_BLACKLIST_NETWORK = 56;
- /* Clear the blacklist network list */
- private static final int CMD_CLEAR_BLACKLIST = 57;
- /* Get the configured networks */
- private static final int CMD_GET_NETWORK_CONFIG = 58;
- /* Save configuration */
- private static final int CMD_SAVE_CONFIG = 59;
- /* Connection status */
- private static final int CMD_CONNECTION_STATUS = 60;
-
- /* Supplicant commands after driver start*/
- /* Initiate a scan */
- private static final int CMD_START_SCAN = 71;
- /* Set scan mode. CONNECT_MODE or SCAN_ONLY_MODE */
- private static final int CMD_SET_SCAN_MODE = 72;
- /* Set scan type. SCAN_ACTIVE or SCAN_PASSIVE */
- private static final int CMD_SET_SCAN_TYPE = 73;
- /* Disconnect from a network */
- private static final int CMD_DISCONNECT = 74;
- /* Reconnect to a network */
- private static final int CMD_RECONNECT = 75;
- /* Reassociate to a network */
- private static final int CMD_REASSOCIATE = 76;
- /* Set power mode
- * POWER_MODE_ACTIVE
- * POWER_MODE_AUTO
- */
- private static final int CMD_SET_POWER_MODE = 77;
- /* Set bluetooth co-existence
- * BLUETOOTH_COEXISTENCE_MODE_ENABLED
- * BLUETOOTH_COEXISTENCE_MODE_DISABLED
- * BLUETOOTH_COEXISTENCE_MODE_SENSE
- */
- private static final int CMD_SET_BLUETOOTH_COEXISTENCE = 78;
- /* Enable/disable bluetooth scan mode
- * true(1)
- * false(0)
- */
- private static final int CMD_SET_BLUETOOTH_SCAN_MODE = 79;
- /* Set number of allowed channels */
- private static final int CMD_SET_NUM_ALLOWED_CHANNELS = 80;
- /* Request connectivity manager wake lock before driver stop */
- private static final int CMD_REQUEST_CM_WAKELOCK = 81;
- /* Enables RSSI poll */
- private static final int CMD_ENABLE_RSSI_POLL = 82;
- /* RSSI poll */
- private static final int CMD_RSSI_POLL = 83;
- /* Get current RSSI */
- private static final int CMD_GET_RSSI = 84;
- /* Get approx current RSSI */
- private static final int CMD_GET_RSSI_APPROX = 85;
- /* Get link speed on connection */
- private static final int CMD_GET_LINK_SPEED = 86;
- /* Radio mac address */
- private static final int CMD_GET_MAC_ADDR = 87;
- /* Set up packet filtering */
- private static final int CMD_START_PACKET_FILTERING = 88;
- /* Clear packet filter */
- private static final int CMD_STOP_PACKET_FILTERING = 89;
-
- /* Connectivity service commands */
- /* Bring down wifi connection */
- private static final int CM_CMD_TEARDOWN = 110;
- /* Reconnect to wifi */
- private static final int CM_CMD_RECONNECT = 111;
-
- /**
- * Interval in milliseconds between polling for connection
- * status items that are not sent via asynchronous events.
- * An example is RSSI (signal strength).
- */
- private static final int POLL_RSSI_INTERVAL_MSECS = 3000;
-
- private static final int CONNECT_MODE = 1;
- private static final int SCAN_ONLY_MODE = 2;
-
- private static final int SCAN_ACTIVE = 1;
- private static final int SCAN_PASSIVE = 2;
-
- /**
- * The maximum number of times we will retry a connection to an access point
- * for which we have failed in acquiring an IP address from DHCP. A value of
- * N means that we will make N+1 connection attempts in all.
- * <p>
- * See {@link Settings.Secure#WIFI_MAX_DHCP_RETRY_COUNT}. This is the default
- * value if a Settings value is not present.
- */
- private static final int DEFAULT_MAX_DHCP_RETRIES = 9;
-
- private static final int DRIVER_POWER_MODE_ACTIVE = 1;
- private static final int DRIVER_POWER_MODE_AUTO = 0;
-
- /* Default parent state */
- private HierarchicalState mDefaultState = new DefaultState();
- /* Temporary initial state */
- private HierarchicalState mInitialState = new InitialState();
- /* Unloading the driver */
- private HierarchicalState mDriverUnloadingState = new DriverUnloadingState();
- /* Loading the driver */
- private HierarchicalState mDriverUnloadedState = new DriverUnloadedState();
- /* Driver load/unload failed */
- private HierarchicalState mDriverFailedState = new DriverFailedState();
- /* Driver loading */
- private HierarchicalState mDriverLoadingState = new DriverLoadingState();
- /* Driver loaded */
- private HierarchicalState mDriverLoadedState = new DriverLoadedState();
- /* Driver loaded, waiting for supplicant to start */
- private HierarchicalState mWaitForSupState = new WaitForSupState();
-
- /* Driver loaded and supplicant ready */
- private HierarchicalState mDriverSupReadyState = new DriverSupReadyState();
- /* Driver start issued, waiting for completed event */
- private HierarchicalState mDriverStartingState = new DriverStartingState();
- /* Driver started */
- private HierarchicalState mDriverStartedState = new DriverStartedState();
- /* Driver stopping */
- private HierarchicalState mDriverStoppingState = new DriverStoppingState();
- /* Driver stopped */
- private HierarchicalState mDriverStoppedState = new DriverStoppedState();
- /* Scan for networks, no connection will be established */
- private HierarchicalState mScanModeState = new ScanModeState();
- /* Connecting to an access point */
- private HierarchicalState mConnectModeState = new ConnectModeState();
- /* Fetching IP after network connection (assoc+auth complete) */
- private HierarchicalState mConnectingState = new ConnectingState();
- /* Connected with IP addr */
- private HierarchicalState mConnectedState = new ConnectedState();
- /* disconnect issued, waiting for network disconnect confirmation */
- private HierarchicalState mDisconnectingState = new DisconnectingState();
- /* Network is not connected, supplicant assoc+auth is not complete */
- private HierarchicalState mDisconnectedState = new DisconnectedState();
-
- /* Soft Ap is running */
- private HierarchicalState mSoftApStartedState = new SoftApStartedState();
-
- /* Argument for Message object to indicate a synchronous call */
- private static final int SYNCHRONOUS_CALL = 1;
- private static final int ASYNCHRONOUS_CALL = 0;
-
-
- /**
- * One of {@link WifiManager#WIFI_STATE_DISABLED},
- * {@link WifiManager#WIFI_STATE_DISABLING},
- * {@link WifiManager#WIFI_STATE_ENABLED},
- * {@link WifiManager#WIFI_STATE_ENABLING},
- * {@link WifiManager#WIFI_STATE_UNKNOWN}
- *
- */
- private final AtomicInteger mWifiState = new AtomicInteger(WIFI_STATE_DISABLED);
-
- /**
- * One of {@link WifiManager#WIFI_AP_STATE_DISABLED},
- * {@link WifiManager#WIFI_AP_STATE_DISABLING},
- * {@link WifiManager#WIFI_AP_STATE_ENABLED},
- * {@link WifiManager#WIFI_AP_STATE_ENABLING},
- * {@link WifiManager#WIFI_AP_STATE_FAILED}
- *
- */
- private final AtomicInteger mWifiApState = new AtomicInteger(WIFI_AP_STATE_DISABLED);
-
- private final AtomicInteger mLastEnableUid = new AtomicInteger(Process.myUid());
- private final AtomicInteger mLastApEnableUid = new AtomicInteger(Process.myUid());
-
- private final IBatteryStats mBatteryStats;
+ private BroadcastReceiver mWifiStateReceiver;
+ private WifiManager mWifiManager;
public WifiStateTracker(Context context, Handler target) {
- super(NETWORKTYPE);
-
mCsHandler = target;
mContext = context;
mNetworkInfo = new NetworkInfo(ConnectivityManager.TYPE_WIFI, 0, NETWORKTYPE, "");
- mBatteryStats = IBatteryStats.Stub.asInterface(ServiceManager.getService("batteryinfo"));
-
- IBinder b = ServiceManager.getService(Context.NETWORKMANAGEMENT_SERVICE);
- nwService = INetworkManagementService.Stub.asInterface(b);
-
- mWifiMonitor = new WifiMonitor(this);
- mDhcpInfo = new DhcpInfo();
- mWifiInfo = new WifiInfo();
- mInterfaceName = SystemProperties.get("wifi.interface", "tiwlan0");
- mSupplicantStateTracker = new SupplicantStateTracker(context, getHandler());
-
- mBluetoothHeadset = new BluetoothHeadset(mContext, null);
mNetworkProperties = new NetworkProperties();
mNetworkInfo.setIsAvailable(false);
mNetworkProperties.clear();
- resetNotificationTimer();
setTeardownRequested(false);
- mLastBssid = null;
- mLastNetworkId = -1;
- mLastSignalLevel = -1;
-
- mScanResultCache = new LinkedHashMap<String, ScanResult>(
- SCAN_RESULT_CACHE_SIZE, 0.75f, true) {
- /*
- * Limit the cache size by SCAN_RESULT_CACHE_SIZE
- * elements
- */
- @Override
- public boolean removeEldestEntry(Map.Entry eldest) {
- return SCAN_RESULT_CACHE_SIZE < this.size();
- }
- };
-
- // Setting is in seconds
- NOTIFICATION_REPEAT_DELAY_MS = Settings.Secure.getInt(context.getContentResolver(),
- Settings.Secure.WIFI_NETWORKS_AVAILABLE_REPEAT_DELAY, 900) * 1000l;
- mNotificationEnabledSettingObserver = new NotificationEnabledSettingObserver(target);
- mNotificationEnabledSettingObserver.register();
-
- mSettingsObserver = new SettingsObserver(new Handler());
-
- PowerManager powerManager = (PowerManager)mContext.getSystemService(Context.POWER_SERVICE);
- sWakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, TAG);
-
- addState(mDefaultState);
- addState(mInitialState, mDefaultState);
- addState(mDriverUnloadingState, mDefaultState);
- addState(mDriverUnloadedState, mDefaultState);
- addState(mDriverFailedState, mDriverUnloadedState);
- addState(mDriverLoadingState, mDefaultState);
- addState(mDriverLoadedState, mDefaultState);
- addState(mWaitForSupState, mDriverLoadedState);
- addState(mDriverSupReadyState, mDefaultState);
- addState(mDriverStartingState, mDriverSupReadyState);
- addState(mDriverStartedState, mDriverSupReadyState);
- addState(mScanModeState, mDriverStartedState);
- addState(mConnectModeState, mDriverStartedState);
- addState(mConnectingState, mConnectModeState);
- addState(mConnectedState, mConnectModeState);
- addState(mDisconnectingState, mConnectModeState);
- addState(mDisconnectedState, mConnectModeState);
- addState(mDriverStoppingState, mDriverSupReadyState);
- addState(mDriverStoppedState, mDriverSupReadyState);
- addState(mSoftApStartedState, mDefaultState);
-
- setInitialState(mInitialState);
-
- if (DBG) setDbg(true);
-
- //start the state machine
- start();
}
- /*********************************************************
- * NetworkStateTracker interface implementation
- ********************************************************/
-
public void setTeardownRequested(boolean isRequested) {
mTeardownRequested.set(isRequested);
}
@@ -544,11 +79,17 @@ public class WifiStateTracker extends HierarchicalStateMachine implements Networ
/**
* Begin monitoring wifi connectivity
- * @deprecated
- *
- * TODO: remove this from callers
*/
public void startMonitoring() {
+ mWifiManager = (WifiManager) mContext.getSystemService(Context.WIFI_SERVICE);
+ IntentFilter filter = new IntentFilter();
+ filter.addAction(WifiManager.WIFI_STATE_CHANGED_ACTION);
+ filter.addAction(WifiManager.NETWORK_STATE_CHANGED_ACTION);
+ filter.addAction(WifiManager.CONFIG_CHANGED_ACTION);
+ filter.addAction(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION);
+
+ mWifiStateReceiver = new WifiStateReceiver();
+ mContext.registerReceiver(mWifiStateReceiver, filter);
}
/**
@@ -556,7 +97,8 @@ public class WifiStateTracker extends HierarchicalStateMachine implements Networ
* TODO: do away with return value after making MobileDataStateTracker async
*/
public boolean teardown() {
- sendMessage(CM_CMD_TEARDOWN);
+ mTeardownRequested.set(true);
+ mWifiManager.stopWifi();
return true;
}
@@ -565,7 +107,8 @@ public class WifiStateTracker extends HierarchicalStateMachine implements Networ
* TODO: do away with return value after making MobileDataStateTracker async
*/
public boolean reconnect() {
- sendMessage(CM_CMD_RECONNECT);
+ mTeardownRequested.set(false);
+ mWifiManager.startWifi();
return true;
}
@@ -575,7 +118,7 @@ public class WifiStateTracker extends HierarchicalStateMachine implements Networ
* TODO: do away with return value after making MobileDataStateTracker async
*/
public boolean setRadio(boolean turnOn) {
- setWifiEnabled(turnOn);
+ mWifiManager.setWifiEnabled(turnOn);
return true;
}
@@ -626,21 +169,6 @@ public class WifiStateTracker extends HierarchicalStateMachine implements Networ
return -1;
}
- /* TODO: will go away.
- * Notifications are directly handled in WifiStateTracker at checkAndSetNotification()
- */
- public void interpretScanResultsAvailable() {
-
- }
-
- /**
- * Return the name of our WLAN network interface.
- * @return the name of our interface.
- */
- public String getInterfaceName() {
- return mInterfaceName;
- }
-
/**
* Check if private DNS route is set for the network
*/
@@ -698,3279 +226,23 @@ public class WifiStateTracker extends HierarchicalStateMachine implements Networ
return "net.tcp.buffersize.wifi";
}
-
- /*********************************************************
- * Methods exposed for public use
- ********************************************************/
-
- /**
- * TODO: doc
- */
- public boolean pingSupplicant() {
- return sendSyncMessage(CMD_PING_SUPPLICANT).boolValue;
- }
-
- /**
- * TODO: doc
- */
- public boolean startScan(boolean forceActive) {
- return sendSyncMessage(obtainMessage(CMD_START_SCAN, forceActive ?
- SCAN_ACTIVE : SCAN_PASSIVE, 0)).boolValue;
- }
-
- /**
- * TODO: doc
- */
- public void setWifiEnabled(boolean enable) {
- mLastEnableUid.set(Binder.getCallingUid());
- if (enable) {
- /* Argument is the state that is entered prior to load */
- sendMessage(obtainMessage(CMD_LOAD_DRIVER, WIFI_STATE_ENABLING, 0));
- sendMessage(CMD_START_SUPPLICANT);
- } else {
- sendMessage(CMD_STOP_SUPPLICANT);
- /* Argument is the state that is entered upon success */
- sendMessage(obtainMessage(CMD_UNLOAD_DRIVER, WIFI_STATE_DISABLED, 0));
- }
- }
-
- /**
- * TODO: doc
- */
- public void setWifiApEnabled(WifiConfiguration wifiConfig, boolean enable) {
- mLastApEnableUid.set(Binder.getCallingUid());
- if (enable) {
- /* Argument is the state that is entered prior to load */
- sendMessage(obtainMessage(CMD_LOAD_DRIVER, WIFI_AP_STATE_ENABLING, 0));
- sendMessage(obtainMessage(CMD_START_AP, wifiConfig));
- } else {
- sendMessage(CMD_STOP_AP);
- /* Argument is the state that is entered upon success */
- sendMessage(obtainMessage(CMD_UNLOAD_DRIVER, WIFI_AP_STATE_DISABLED, 0));
- }
- }
-
- /**
- * TODO: doc
- */
- public int getWifiState() {
- return mWifiState.get();
- }
-
- /**
- * TODO: doc
- */
- public String getWifiStateByName() {
- switch (mWifiState.get()) {
- case WIFI_STATE_DISABLING:
- return "disabling";
- case WIFI_STATE_DISABLED:
- return "disabled";
- case WIFI_STATE_ENABLING:
- return "enabling";
- case WIFI_STATE_ENABLED:
- return "enabled";
- case WIFI_STATE_UNKNOWN:
- return "unknown state";
- default:
- return "[invalid state]";
- }
- }
-
- /**
- * TODO: doc
- */
- public int getWifiApState() {
- return mWifiApState.get();
- }
-
- /**
- * TODO: doc
- */
- public String getWifiApStateByName() {
- switch (mWifiApState.get()) {
- case WIFI_AP_STATE_DISABLING:
- return "disabling";
- case WIFI_AP_STATE_DISABLED:
- return "disabled";
- case WIFI_AP_STATE_ENABLING:
- return "enabling";
- case WIFI_AP_STATE_ENABLED:
- return "enabled";
- case WIFI_AP_STATE_FAILED:
- return "failed";
- default:
- return "[invalid state]";
- }
- }
-
- /**
- * Get status information for the current connection, if any.
- * @return a {@link WifiInfo} object containing information about the current connection
- *
- */
- public WifiInfo requestConnectionInfo() {
- return mWifiInfo;
- }
-
- public DhcpInfo getDhcpInfo() {
- return mDhcpInfo;
- }
-
- /**
- * TODO: doc
- */
- public void startWifi(boolean enable) {
- if (enable) {
- sendMessage(CMD_START_DRIVER);
- } else {
- sendMessage(CMD_STOP_DRIVER);
- }
- }
-
- /**
- * TODO: doc
- */
- public void disconnectAndStop() {
- sendMessage(CMD_DISCONNECT);
- sendMessage(CMD_STOP_DRIVER);
- }
-
- /**
- * TODO: doc
- */
- public void setScanOnlyMode(boolean enable) {
- if (enable) {
- sendMessage(obtainMessage(CMD_SET_SCAN_MODE, SCAN_ONLY_MODE, 0));
- } else {
- sendMessage(obtainMessage(CMD_SET_SCAN_MODE, CONNECT_MODE, 0));
- }
- }
-
- /**
- * TODO: doc
- */
- public void setScanType(boolean active) {
- if (active) {
- sendMessage(obtainMessage(CMD_SET_SCAN_TYPE, SCAN_ACTIVE, 0));
- } else {
- sendMessage(obtainMessage(CMD_SET_SCAN_TYPE, SCAN_PASSIVE, 0));
- }
- }
-
- /**
- * TODO: doc
- */
- public List<ScanResult> getScanResultsList() {
- return mScanResults;
- }
-
- /**
- * Disconnect from Access Point
- */
- public boolean disconnectCommand() {
- return sendSyncMessage(CMD_DISCONNECT).boolValue;
- }
-
- /**
- * Initiate a reconnection to AP
- */
- public boolean reconnectCommand() {
- return sendSyncMessage(CMD_RECONNECT).boolValue;
- }
-
- /**
- * Initiate a re-association to AP
- */
- public boolean reassociateCommand() {
- return sendSyncMessage(CMD_REASSOCIATE).boolValue;
- }
-
- /**
- * Add a network synchronously
- *
- * @return network id of the new network
- */
- public int addOrUpdateNetwork(WifiConfiguration config) {
- return sendSyncMessage(CMD_ADD_OR_UPDATE_NETWORK, config).intValue;
- }
-
- public List<WifiConfiguration> getConfiguredNetworks() {
- return sendSyncMessage(CMD_GET_NETWORK_CONFIG).configList;
- }
-
- /**
- * Delete a network
- *
- * @param networkId id of the network to be removed
- */
- public boolean removeNetwork(int networkId) {
- return sendSyncMessage(obtainMessage(CMD_REMOVE_NETWORK, networkId, 0)).boolValue;
- }
-
- private class EnableNetParams {
- private int netId;
- private boolean disableOthers;
- EnableNetParams(int n, boolean b) {
- netId = n;
- disableOthers = b;
- }
- }
- /**
- * Enable a network
- *
- * @param netId network id of the network
- * @param disableOthers true, if all other networks have to be disabled
- * @return {@code true} if the operation succeeds, {@code false} otherwise
- */
- public boolean enableNetwork(int netId, boolean disableOthers) {
- return sendSyncMessage(CMD_ENABLE_NETWORK,
- new EnableNetParams(netId, disableOthers)).boolValue;
- }
-
- /**
- * Disable a network
- *
- * @param netId network id of the network
- * @return {@code true} if the operation succeeds, {@code false} otherwise
- */
- public boolean disableNetwork(int netId) {
- return sendSyncMessage(obtainMessage(CMD_DISABLE_NETWORK, netId, 0)).boolValue;
- }
-
- /**
- * Blacklist a BSSID. This will avoid the AP if there are
- * alternate APs to connect
- *
- * @param bssid BSSID of the network
- */
- public void addToBlacklist(String bssid) {
- sendMessage(obtainMessage(CMD_BLACKLIST_NETWORK, bssid));
- }
-
- /**
- * Clear the blacklist list
- *
- */
- public void clearBlacklist() {
- sendMessage(obtainMessage(CMD_CLEAR_BLACKLIST));
- }
-
- /**
- * Get detailed status of the connection
- *
- * @return Example status result
- * bssid=aa:bb:cc:dd:ee:ff
- * ssid=TestNet
- * id=3
- * pairwise_cipher=NONE
- * group_cipher=NONE
- * key_mgmt=NONE
- * wpa_state=COMPLETED
- * ip_address=X.X.X.X
- */
- public String status() {
- return sendSyncMessage(CMD_CONNECTION_STATUS).stringValue;
- }
-
- public void enableRssiPolling(boolean enabled) {
- sendMessage(obtainMessage(CMD_ENABLE_RSSI_POLL, enabled ? 1 : 0, 0));
- }
- /**
- * Get RSSI to currently connected network
- *
- * @return RSSI value, -1 on failure
- */
- public int getRssi() {
- return sendSyncMessage(CMD_GET_RSSI).intValue;
- }
-
- /**
- * Get approx RSSI to currently connected network
- *
- * @return RSSI value, -1 on failure
- */
- public int getRssiApprox() {
- return sendSyncMessage(CMD_GET_RSSI_APPROX).intValue;
- }
-
- /**
- * Get link speed to currently connected network
- *
- * @return link speed, -1 on failure
- */
- public int getLinkSpeed() {
- return sendSyncMessage(CMD_GET_LINK_SPEED).intValue;
- }
-
- /**
- * Get MAC address of radio
- *
- * @return MAC address, null on failure
- */
- public String getMacAddress() {
- return sendSyncMessage(CMD_GET_MAC_ADDR).stringValue;
- }
-
- /**
- * Start packet filtering
- */
- public void startPacketFiltering() {
- sendMessage(CMD_START_PACKET_FILTERING);
- }
-
- /**
- * Stop packet filtering
- */
- public void stopPacketFiltering() {
- sendMessage(CMD_STOP_PACKET_FILTERING);
- }
-
- /**
- * Set power mode
- * @param mode
- * DRIVER_POWER_MODE_AUTO
- * DRIVER_POWER_MODE_ACTIVE
- */
- public void setPowerMode(int mode) {
- sendMessage(obtainMessage(CMD_SET_POWER_MODE, mode, 0));
- }
-
- /**
- * Set the number of allowed radio frequency channels from the system
- * setting value, if any.
- */
- public void setNumAllowedChannels() {
- try {
- setNumAllowedChannels(
- Settings.Secure.getInt(mContext.getContentResolver(),
- Settings.Secure.WIFI_NUM_ALLOWED_CHANNELS));
- } catch (Settings.SettingNotFoundException e) {
- if (mNumAllowedChannels != 0) {
- setNumAllowedChannels(mNumAllowedChannels);
- }
- // otherwise, use the driver default
- }
- }
-
- /**
- * Set the number of radio frequency channels that are allowed to be used
- * in the current regulatory domain.
- * @param numChannels the number of allowed channels. Must be greater than 0
- * and less than or equal to 16.
- */
- public void setNumAllowedChannels(int numChannels) {
- sendMessage(obtainMessage(CMD_SET_NUM_ALLOWED_CHANNELS, numChannels, 0));
- }
-
- /**
- * Get number of allowed channels
- *
- * @return channel count, -1 on failure
- *
- * TODO: this is not a public API and needs to be removed in favor
- * of asynchronous reporting. unused for now.
- */
- public int getNumAllowedChannels() {
- return -1;
- }
-
- /**
- * Set bluetooth coex mode:
- *
- * @param mode
- * BLUETOOTH_COEXISTENCE_MODE_ENABLED
- * BLUETOOTH_COEXISTENCE_MODE_DISABLED
- * BLUETOOTH_COEXISTENCE_MODE_SENSE
- */
- public void setBluetoothCoexistenceMode(int mode) {
- sendMessage(obtainMessage(CMD_SET_BLUETOOTH_COEXISTENCE, mode, 0));
- }
-
- /**
- * Enable or disable Bluetooth coexistence scan mode. When this mode is on,
- * some of the low-level scan parameters used by the driver are changed to
- * reduce interference with A2DP streaming.
- *
- * @param isBluetoothPlaying whether to enable or disable this mode
- */
- public void setBluetoothScanMode(boolean isBluetoothPlaying) {
- sendMessage(obtainMessage(CMD_SET_BLUETOOTH_SCAN_MODE, isBluetoothPlaying ? 1 : 0, 0));
- }
-
- /**
- * Save configuration on supplicant
- *
- * @return {@code true} if the operation succeeds, {@code false} otherwise
- *
- * TODO: deprecate this
- */
- public boolean saveConfig() {
- return sendSyncMessage(CMD_SAVE_CONFIG).boolValue;
- }
-
- /**
- * TODO: doc
- */
- public void requestCmWakeLock() {
- sendMessage(CMD_REQUEST_CM_WAKELOCK);
- }
-
- /*********************************************************
- * Internal private functions
- ********************************************************/
-
- class SyncReturn {
- boolean boolValue;
- int intValue;
- String stringValue;
- Object objValue;
- List<WifiConfiguration> configList;
- }
-
- class SyncParams {
- Object mParameter;
- SyncReturn mSyncReturn;
- SyncParams() {
- mSyncReturn = new SyncReturn();
- }
- SyncParams(Object p) {
- mParameter = p;
- mSyncReturn = new SyncReturn();
- }
- }
-
- /**
- * message.arg2 is reserved to indicate synchronized
- * message.obj is used to store SyncParams
- */
- private SyncReturn syncedSend(Message msg) {
- SyncParams syncParams = (SyncParams) msg.obj;
- msg.arg2 = SYNCHRONOUS_CALL;
- synchronized(syncParams) {
- if (DBG) Log.d(TAG, "syncedSend " + msg);
- sendMessage(msg);
- try {
- syncParams.wait();
- } catch (InterruptedException e) {
- Log.e(TAG, "sendSyncMessage: unexpected interruption of wait()");
- return null;
- }
- }
- return syncParams.mSyncReturn;
- }
-
- private SyncReturn sendSyncMessage(Message msg) {
- SyncParams syncParams = new SyncParams();
- msg.obj = syncParams;
- return syncedSend(msg);
- }
-
- private SyncReturn sendSyncMessage(int what, Object param) {
- SyncParams syncParams = new SyncParams(param);
- Message msg = obtainMessage(what, syncParams);
- return syncedSend(msg);
- }
-
-
- private SyncReturn sendSyncMessage(int what) {
- return sendSyncMessage(obtainMessage(what));
- }
-
- private void notifyOnMsgObject(Message msg) {
- SyncParams syncParams = (SyncParams) msg.obj;
- if (syncParams != null) {
- synchronized(syncParams) {
- if (DBG) Log.d(TAG, "notifyOnMsgObject " + msg);
- syncParams.notify();
- }
- }
- else {
- Log.e(TAG, "Error! syncParams in notifyOnMsgObject is null");
- }
- }
-
- private void setWifiState(int wifiState) {
- final int previousWifiState = mWifiState.get();
-
- try {
- if (wifiState == WIFI_STATE_ENABLED) {
- mBatteryStats.noteWifiOn(mLastEnableUid.get());
- } else if (wifiState == WIFI_STATE_DISABLED) {
- mBatteryStats.noteWifiOff(mLastEnableUid.get());
- }
- } catch (RemoteException e) {
- Log.e(TAG, "Failed to note battery stats in wifi");
- }
-
- mWifiState.set(wifiState);
-
- if (DBG) Log.d(TAG, "setWifiState: " + getWifiStateByName());
-
- final Intent intent = new Intent(WifiManager.WIFI_STATE_CHANGED_ACTION);
- intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
- intent.putExtra(WifiManager.EXTRA_WIFI_STATE, wifiState);
- intent.putExtra(WifiManager.EXTRA_PREVIOUS_WIFI_STATE, previousWifiState);
- mContext.sendStickyBroadcast(intent);
- }
-
- private void setWifiApState(int wifiApState) {
- final int previousWifiApState = mWifiApState.get();
-
- try {
- if (wifiApState == WIFI_AP_STATE_ENABLED) {
- mBatteryStats.noteWifiOn(mLastApEnableUid.get());
- } else if (wifiApState == WIFI_AP_STATE_DISABLED) {
- mBatteryStats.noteWifiOff(mLastApEnableUid.get());
- }
- } catch (RemoteException e) {
- Log.d(TAG, "Failed to note battery stats in wifi");
- }
-
- // Update state
- mWifiApState.set(wifiApState);
-
- if (DBG) Log.d(TAG, "setWifiApState: " + getWifiApStateByName());
-
- // Broadcast
- final Intent intent = new Intent(WifiManager.WIFI_AP_STATE_CHANGED_ACTION);
- intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
- intent.putExtra(WifiManager.EXTRA_WIFI_AP_STATE, wifiApState);
- intent.putExtra(WifiManager.EXTRA_PREVIOUS_WIFI_AP_STATE, previousWifiApState);
- mContext.sendStickyBroadcast(intent);
- }
-
- /**
- * Parse the scan result line passed to us by wpa_supplicant (helper).
- * @param line the line to parse
- * @return the {@link ScanResult} object
- */
- private ScanResult parseScanResult(String line) {
- ScanResult scanResult = null;
- if (line != null) {
- /*
- * Cache implementation (LinkedHashMap) is not synchronized, thus,
- * must synchronized here!
- */
- synchronized (mScanResultCache) {
- String[] result = scanResultPattern.split(line);
- if (3 <= result.length && result.length <= 5) {
- String bssid = result[0];
- // bssid | frequency | level | flags | ssid
- int frequency;
- int level;
- try {
- frequency = Integer.parseInt(result[1]);
- level = Integer.parseInt(result[2]);
- /* some implementations avoid negative values by adding 256
- * so we need to adjust for that here.
- */
- if (level > 0) level -= 256;
- } catch (NumberFormatException e) {
- frequency = 0;
- level = 0;
- }
-
- /*
- * The formatting of the results returned by
- * wpa_supplicant is intended to make the fields
- * line up nicely when printed,
- * not to make them easy to parse. So we have to
- * apply some heuristics to figure out which field
- * is the SSID and which field is the flags.
- */
- String ssid;
- String flags;
- if (result.length == 4) {
- if (result[3].charAt(0) == '[') {
- flags = result[3];
- ssid = "";
- } else {
- flags = "";
- ssid = result[3];
- }
- } else if (result.length == 5) {
- flags = result[3];
- ssid = result[4];
- } else {
- // Here, we must have 3 fields: no flags and ssid
- // set
- flags = "";
- ssid = "";
- }
-
- // bssid + ssid is the hash key
- String key = bssid + ssid;
- scanResult = mScanResultCache.get(key);
- if (scanResult != null) {
- scanResult.level = level;
- scanResult.SSID = ssid;
- scanResult.capabilities = flags;
- scanResult.frequency = frequency;
- } else {
- // Do not add scan results that have no SSID set
- if (0 < ssid.trim().length()) {
- scanResult =
- new ScanResult(
- ssid, bssid, flags, level, frequency);
- mScanResultCache.put(key, scanResult);
- }
- }
- } else {
- Log.w(TAG, "Misformatted scan result text with " +
- result.length + " fields: " + line);
- }
- }
- }
-
- return scanResult;
- }
-
- /**
- * scanResults input format
- * 00:bb:cc:dd:cc:ee 2427 166 [WPA-EAP-TKIP][WPA2-EAP-CCMP] Net1
- * 00:bb:cc:dd:cc:ff 2412 165 [WPA-EAP-TKIP][WPA2-EAP-CCMP] Net2
- */
- private void setScanResults(String scanResults) {
- if (scanResults == null) {
- return;
- }
-
- List<ScanResult> scanList = new ArrayList<ScanResult>();
-
- int lineCount = 0;
-
- int scanResultsLen = scanResults.length();
- // Parse the result string, keeping in mind that the last line does
- // not end with a newline.
- for (int lineBeg = 0, lineEnd = 0; lineEnd <= scanResultsLen; ++lineEnd) {
- if (lineEnd == scanResultsLen || scanResults.charAt(lineEnd) == '\n') {
- ++lineCount;
-
- if (lineCount == 1) {
- lineBeg = lineEnd + 1;
- continue;
- }
- if (lineEnd > lineBeg) {
- String line = scanResults.substring(lineBeg, lineEnd);
- ScanResult scanResult = parseScanResult(line);
- if (scanResult != null) {
- scanList.add(scanResult);
- } else {
- Log.w(TAG, "misformatted scan result for: " + line);
- }
- }
- lineBeg = lineEnd + 1;
- }
- }
-
- mScanResults = scanList;
- }
-
- private void checkAndSetNotification() {
- // If we shouldn't place a notification on available networks, then
- // don't bother doing any of the following
- if (!mNotificationEnabled) return;
-
- State state = mNetworkInfo.getState();
- if ((state == NetworkInfo.State.DISCONNECTED)
- || (state == NetworkInfo.State.UNKNOWN)) {
- // Look for an open network
- List<ScanResult> scanResults = mScanResults;
- if (scanResults != null) {
- int numOpenNetworks = 0;
- for (int i = scanResults.size() - 1; i >= 0; i--) {
- ScanResult scanResult = scanResults.get(i);
-
- if (TextUtils.isEmpty(scanResult.capabilities)) {
- numOpenNetworks++;
- }
- }
-
- if (numOpenNetworks > 0) {
- if (++mNumScansSinceNetworkStateChange >= NUM_SCANS_BEFORE_ACTUALLY_SCANNING) {
- /*
- * We've scanned continuously at least
- * NUM_SCANS_BEFORE_NOTIFICATION times. The user
- * probably does not have a remembered network in range,
- * since otherwise supplicant would have tried to
- * associate and thus resetting this counter.
- */
- setNotificationVisible(true, numOpenNetworks, false, 0);
- }
- return;
- }
- }
- }
-
- // No open networks in range, remove the notification
- setNotificationVisible(false, 0, false, 0);
- }
-
- /**
- * Display or don't display a notification that there are open Wi-Fi networks.
- * @param visible {@code true} if notification should be visible, {@code false} otherwise
- * @param numNetworks the number networks seen
- * @param force {@code true} to force notification to be shown/not-shown,
- * even if it is already shown/not-shown.
- * @param delay time in milliseconds after which the notification should be made
- * visible or invisible.
- */
- private void setNotificationVisible(boolean visible, int numNetworks, boolean force,
- int delay) {
-
- // Since we use auto cancel on the notification, when the
- // mNetworksAvailableNotificationShown is true, the notification may
- // have actually been canceled. However, when it is false we know
- // for sure that it is not being shown (it will not be shown any other
- // place than here)
-
- // If it should be hidden and it is already hidden, then noop
- if (!visible && !mNotificationShown && !force) {
- return;
- }
-
- Message message;
- if (visible) {
-
- // Not enough time has passed to show the notification again
- if (System.currentTimeMillis() < mNotificationRepeatTime) {
- return;
- }
-
- if (mNotification == null) {
- // Cache the Notification mainly so we can remove the
- // EVENT_NOTIFICATION_CHANGED message with this Notification from
- // the queue later
- mNotification = new Notification();
- mNotification.when = 0;
- mNotification.icon = ICON_NETWORKS_AVAILABLE;
- mNotification.flags = Notification.FLAG_AUTO_CANCEL;
- mNotification.contentIntent = PendingIntent.getActivity(mContext, 0,
- new Intent(WifiManager.ACTION_PICK_WIFI_NETWORK), 0);
- }
-
- CharSequence title = mContext.getResources().getQuantityText(
- com.android.internal.R.plurals.wifi_available, numNetworks);
- CharSequence details = mContext.getResources().getQuantityText(
- com.android.internal.R.plurals.wifi_available_detailed, numNetworks);
- mNotification.tickerText = title;
- mNotification.setLatestEventInfo(mContext, title, details, mNotification.contentIntent);
-
- mNotificationRepeatTime = System.currentTimeMillis() + NOTIFICATION_REPEAT_DELAY_MS;
-
- message = mCsHandler.obtainMessage(EVENT_NOTIFICATION_CHANGED, 1,
- ICON_NETWORKS_AVAILABLE, mNotification);
-
- } else {
-
- // Remove any pending messages to show the notification
- mCsHandler.removeMessages(EVENT_NOTIFICATION_CHANGED, mNotification);
-
- message = mCsHandler.obtainMessage(EVENT_NOTIFICATION_CHANGED, 0,
- ICON_NETWORKS_AVAILABLE);
- }
-
- mCsHandler.sendMessageDelayed(message, delay);
-
- mNotificationShown = visible;
- }
-
- private void configureNetworkProperties() {
- try {
- mNetworkProperties.setInterface(NetworkInterface.getByName(mInterfaceName));
- } catch (SocketException e) {
- Log.e(TAG, "SocketException creating NetworkInterface from " + mInterfaceName +
- ". e=" + e);
- return;
- } catch (NullPointerException e) {
- Log.e(TAG, "NPE creating NetworkInterface. e=" + e);
- return;
- }
- // TODO - fix this for v6
- try {
- mNetworkProperties.addAddress(InetAddress.getByAddress(
- NetworkUtils.v4IntToArray(mDhcpInfo.ipAddress)));
- } catch (UnknownHostException e) {
- Log.e(TAG, "Exception setting IpAddress using " + mDhcpInfo + ", e=" + e);
- }
-
- try {
- mNetworkProperties.setGateway(InetAddress.getByAddress(NetworkUtils.v4IntToArray(
- mDhcpInfo.gateway)));
- } catch (UnknownHostException e) {
- Log.e(TAG, "Exception setting Gateway using " + mDhcpInfo + ", e=" + e);
- }
-
- try {
- mNetworkProperties.addDns(InetAddress.getByAddress(
- NetworkUtils.v4IntToArray(mDhcpInfo.dns1)));
- } catch (UnknownHostException e) {
- Log.e(TAG, "Exception setting Dns1 using " + mDhcpInfo + ", e=" + e);
- }
- try {
- mNetworkProperties.addDns(InetAddress.getByAddress(
- NetworkUtils.v4IntToArray(mDhcpInfo.dns2)));
-
- } catch (UnknownHostException e) {
- Log.e(TAG, "Exception setting Dns2 using " + mDhcpInfo + ", e=" + e);
- }
- // TODO - add proxy info
- }
-
-
- private void checkUseStaticIp() {
- mUseStaticIp = false;
- final ContentResolver cr = mContext.getContentResolver();
- try {
- if (Settings.System.getInt(cr, Settings.System.WIFI_USE_STATIC_IP) == 0) {
- return;
- }
- } catch (Settings.SettingNotFoundException e) {
- return;
- }
-
- try {
- String addr = Settings.System.getString(cr, Settings.System.WIFI_STATIC_IP);
- if (addr != null) {
- mDhcpInfo.ipAddress = stringToIpAddr(addr);
- } else {
- return;
- }
- addr = Settings.System.getString(cr, Settings.System.WIFI_STATIC_GATEWAY);
- if (addr != null) {
- mDhcpInfo.gateway = stringToIpAddr(addr);
- } else {
- return;
- }
- addr = Settings.System.getString(cr, Settings.System.WIFI_STATIC_NETMASK);
- if (addr != null) {
- mDhcpInfo.netmask = stringToIpAddr(addr);
- } else {
- return;
- }
- addr = Settings.System.getString(cr, Settings.System.WIFI_STATIC_DNS1);
- if (addr != null) {
- mDhcpInfo.dns1 = stringToIpAddr(addr);
- } else {
- return;
- }
- addr = Settings.System.getString(cr, Settings.System.WIFI_STATIC_DNS2);
- if (addr != null) {
- mDhcpInfo.dns2 = stringToIpAddr(addr);
- } else {
- mDhcpInfo.dns2 = 0;
- }
- } catch (UnknownHostException e) {
- return;
- }
- mUseStaticIp = true;
- }
-
- private static int stringToIpAddr(String addrString) throws UnknownHostException {
- try {
- String[] parts = addrString.split("\\.");
- if (parts.length != 4) {
- throw new UnknownHostException(addrString);
- }
-
- int a = Integer.parseInt(parts[0]) ;
- int b = Integer.parseInt(parts[1]) << 8;
- int c = Integer.parseInt(parts[2]) << 16;
- int d = Integer.parseInt(parts[3]) << 24;
-
- return a | b | c | d;
- } catch (NumberFormatException ex) {
- throw new UnknownHostException(addrString);
- }
- }
-
- private int getMaxDhcpRetries() {
- return Settings.Secure.getInt(mContext.getContentResolver(),
- Settings.Secure.WIFI_MAX_DHCP_RETRY_COUNT,
- DEFAULT_MAX_DHCP_RETRIES);
- }
-
- private class SettingsObserver extends ContentObserver {
- public SettingsObserver(Handler handler) {
- super(handler);
- ContentResolver cr = mContext.getContentResolver();
- cr.registerContentObserver(Settings.System.getUriFor(
- Settings.System.WIFI_USE_STATIC_IP), false, this);
- cr.registerContentObserver(Settings.System.getUriFor(
- Settings.System.WIFI_STATIC_IP), false, this);
- cr.registerContentObserver(Settings.System.getUriFor(
- Settings.System.WIFI_STATIC_GATEWAY), false, this);
- cr.registerContentObserver(Settings.System.getUriFor(
- Settings.System.WIFI_STATIC_NETMASK), false, this);
- cr.registerContentObserver(Settings.System.getUriFor(
- Settings.System.WIFI_STATIC_DNS1), false, this);
- cr.registerContentObserver(Settings.System.getUriFor(
- Settings.System.WIFI_STATIC_DNS2), false, this);
- }
-
+ private class WifiStateReceiver extends BroadcastReceiver {
@Override
- public void onChange(boolean selfChange) {
- super.onChange(selfChange);
-
- boolean wasStaticIp = mUseStaticIp;
- int oIp, oGw, oMsk, oDns1, oDns2;
- oIp = oGw = oMsk = oDns1 = oDns2 = 0;
- if (wasStaticIp) {
- oIp = mDhcpInfo.ipAddress;
- oGw = mDhcpInfo.gateway;
- oMsk = mDhcpInfo.netmask;
- oDns1 = mDhcpInfo.dns1;
- oDns2 = mDhcpInfo.dns2;
- }
- checkUseStaticIp();
-
- if (mWifiInfo.getSupplicantState() == SupplicantState.UNINITIALIZED) {
- return;
- }
-
- boolean changed =
- (wasStaticIp != mUseStaticIp) ||
- (wasStaticIp && (
- oIp != mDhcpInfo.ipAddress ||
- oGw != mDhcpInfo.gateway ||
- oMsk != mDhcpInfo.netmask ||
- oDns1 != mDhcpInfo.dns1 ||
- oDns2 != mDhcpInfo.dns2));
-
- if (changed) {
- sendMessage(CMD_RECONFIGURE_IP);
- if (mUseStaticIp) {
- mCsHandler.sendEmptyMessage(EVENT_CONFIGURATION_CHANGED);
- }
+ public void onReceive(Context context, Intent intent) {
+ if (intent.getAction().equals(WifiManager.NETWORK_STATE_CHANGED_ACTION)) {
+ mNetworkInfo = (NetworkInfo) intent.getParcelableExtra(
+ WifiManager.EXTRA_NETWORK_INFO);
+ mNetworkProperties = (NetworkProperties) intent.getParcelableExtra(
+ WifiManager.EXTRA_NETWORK_PROPERTIES);
+ Message msg = mCsHandler.obtainMessage(EVENT_STATE_CHANGED, mNetworkInfo);
+ msg.sendToTarget();
+ } else if (intent.getAction().equals(WifiManager.CONFIG_CHANGED_ACTION)) {
+ mNetworkProperties = (NetworkProperties) intent.getParcelableExtra(
+ WifiManager.EXTRA_NETWORK_PROPERTIES);
+ Message msg = mCsHandler.obtainMessage(EVENT_CONFIGURATION_CHANGED, mNetworkInfo);
+ msg.sendToTarget();
}
}
}
-
- /**
- * Clears variables related to tracking whether a notification has been
- * shown recently.
- * <p>
- * After calling this method, the timer that prevents notifications from
- * being shown too often will be cleared.
- */
- private void resetNotificationTimer() {
- mNotificationRepeatTime = 0;
- mNumScansSinceNetworkStateChange = 0;
- }
-
-
- /**
- * Whether to disable coexistence mode while obtaining IP address. This
- * logic will return true only if the current bluetooth
- * headset/handsfree state is disconnected. This means if it is in an
- * error state, we will NOT disable coexistence mode to err on the side
- * of safety.
- *
- * @return Whether to disable coexistence mode.
- */
- private boolean shouldDisableCoexistenceMode() {
- int state = mBluetoothHeadset.getState(mBluetoothHeadset.getCurrentHeadset());
- return state == BluetoothHeadset.STATE_DISCONNECTED;
- }
-
- private void checkIsBluetoothPlaying() {
- boolean isBluetoothPlaying = false;
- Set<BluetoothDevice> connected = mBluetoothA2dp.getConnectedSinks();
-
- for (BluetoothDevice device : connected) {
- if (mBluetoothA2dp.getSinkState(device) == BluetoothA2dp.STATE_PLAYING) {
- isBluetoothPlaying = true;
- break;
- }
- }
- setBluetoothScanMode(isBluetoothPlaying);
- }
-
- private void sendScanResultsAvailableBroadcast() {
- if (!ActivityManagerNative.isSystemReady()) return;
-
- mContext.sendBroadcast(new Intent(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION));
- }
-
- private void sendRssiChangeBroadcast(final int newRssi) {
- if (!ActivityManagerNative.isSystemReady()) return;
-
- Intent intent = new Intent(WifiManager.RSSI_CHANGED_ACTION);
- intent.putExtra(WifiManager.EXTRA_NEW_RSSI, newRssi);
- mContext.sendBroadcast(intent);
- }
-
- private void sendNetworkStateChangeBroadcast(String bssid) {
- Intent intent = new Intent(WifiManager.NETWORK_STATE_CHANGED_ACTION);
- intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT
- | Intent.FLAG_RECEIVER_REPLACE_PENDING);
- intent.putExtra(WifiManager.EXTRA_NETWORK_INFO, mNetworkInfo);
- if (bssid != null)
- intent.putExtra(WifiManager.EXTRA_BSSID, bssid);
- mContext.sendStickyBroadcast(intent);
- }
-
- private void sendSupplicantStateChangedBroadcast(StateChangeResult sc, boolean failedAuth) {
- Intent intent = new Intent(WifiManager.SUPPLICANT_STATE_CHANGED_ACTION);
- intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT
- | Intent.FLAG_RECEIVER_REPLACE_PENDING);
- intent.putExtra(WifiManager.EXTRA_NEW_STATE, (Parcelable)sc.state);
- if (failedAuth) {
- intent.putExtra(
- WifiManager.EXTRA_SUPPLICANT_ERROR,
- WifiManager.ERROR_AUTHENTICATING);
- }
- mContext.sendStickyBroadcast(intent);
- }
-
- private void sendSupplicantConnectionChangedBroadcast(boolean connected) {
- if (!ActivityManagerNative.isSystemReady()) return;
-
- Intent intent = new Intent(WifiManager.SUPPLICANT_CONNECTION_CHANGE_ACTION);
- intent.putExtra(WifiManager.EXTRA_SUPPLICANT_CONNECTED, connected);
- mContext.sendBroadcast(intent);
- }
-
- /**
- * Record the detailed state of a network, and if it is a
- * change from the previous state, send a notification to
- * any listeners.
- * @param state the new @{code DetailedState}
- */
- private void setDetailedState(NetworkInfo.DetailedState state) {
- Log.d(TAG, "setDetailed state, old ="
- + mNetworkInfo.getDetailedState() + " and new state=" + state);
- if (state != mNetworkInfo.getDetailedState()) {
- mNetworkInfo.setDetailedState(state, null, null);
- Message msg = mCsHandler.obtainMessage(EVENT_STATE_CHANGED, mNetworkInfo);
- msg.sendToTarget();
- }
- }
-
- private static String removeDoubleQuotes(String string) {
- if (string.length() <= 2) return "";
- return string.substring(1, string.length() - 1);
- }
-
- private static String convertToQuotedString(String string) {
- return "\"" + string + "\"";
- }
-
- private static String makeString(BitSet set, String[] strings) {
- StringBuffer buf = new StringBuffer();
- int nextSetBit = -1;
-
- /* Make sure all set bits are in [0, strings.length) to avoid
- * going out of bounds on strings. (Shouldn't happen, but...) */
- set = set.get(0, strings.length);
-
- while ((nextSetBit = set.nextSetBit(nextSetBit + 1)) != -1) {
- buf.append(strings[nextSetBit].replace('_', '-')).append(' ');
- }
-
- // remove trailing space
- if (set.cardinality() > 0) {
- buf.setLength(buf.length() - 1);
- }
-
- return buf.toString();
- }
-
- private static int lookupString(String string, String[] strings) {
- int size = strings.length;
-
- string = string.replace('-', '_');
-
- for (int i = 0; i < size; i++)
- if (string.equals(strings[i]))
- return i;
-
- // if we ever get here, we should probably add the
- // value to WifiConfiguration to reflect that it's
- // supported by the WPA supplicant
- Log.w(TAG, "Failed to look-up a string: " + string);
-
- return -1;
- }
-
- private int addOrUpdateNetworkNative(WifiConfiguration config) {
- /*
- * If the supplied networkId is -1, we create a new empty
- * network configuration. Otherwise, the networkId should
- * refer to an existing configuration.
- */
- int netId = config.networkId;
- boolean newNetwork = netId == -1;
- // networkId of -1 means we want to create a new network
-
- if (newNetwork) {
- netId = WifiNative.addNetworkCommand();
- if (netId < 0) {
- Log.e(TAG, "Failed to add a network!");
- return -1;
- }
- }
-
- setVariables: {
-
- if (config.SSID != null &&
- !WifiNative.setNetworkVariableCommand(
- netId,
- WifiConfiguration.ssidVarName,
- config.SSID)) {
- Log.d(TAG, "failed to set SSID: "+config.SSID);
- break setVariables;
- }
-
- if (config.BSSID != null &&
- !WifiNative.setNetworkVariableCommand(
- netId,
- WifiConfiguration.bssidVarName,
- config.BSSID)) {
- Log.d(TAG, "failed to set BSSID: "+config.BSSID);
- break setVariables;
- }
-
- String allowedKeyManagementString =
- makeString(config.allowedKeyManagement, WifiConfiguration.KeyMgmt.strings);
- if (config.allowedKeyManagement.cardinality() != 0 &&
- !WifiNative.setNetworkVariableCommand(
- netId,
- WifiConfiguration.KeyMgmt.varName,
- allowedKeyManagementString)) {
- Log.d(TAG, "failed to set key_mgmt: "+
- allowedKeyManagementString);
- break setVariables;
- }
-
- String allowedProtocolsString =
- makeString(config.allowedProtocols, WifiConfiguration.Protocol.strings);
- if (config.allowedProtocols.cardinality() != 0 &&
- !WifiNative.setNetworkVariableCommand(
- netId,
- WifiConfiguration.Protocol.varName,
- allowedProtocolsString)) {
- Log.d(TAG, "failed to set proto: "+
- allowedProtocolsString);
- break setVariables;
- }
-
- String allowedAuthAlgorithmsString =
- makeString(config.allowedAuthAlgorithms, WifiConfiguration.AuthAlgorithm.strings);
- if (config.allowedAuthAlgorithms.cardinality() != 0 &&
- !WifiNative.setNetworkVariableCommand(
- netId,
- WifiConfiguration.AuthAlgorithm.varName,
- allowedAuthAlgorithmsString)) {
- Log.d(TAG, "failed to set auth_alg: "+
- allowedAuthAlgorithmsString);
- break setVariables;
- }
-
- String allowedPairwiseCiphersString =
- makeString(config.allowedPairwiseCiphers,
- WifiConfiguration.PairwiseCipher.strings);
- if (config.allowedPairwiseCiphers.cardinality() != 0 &&
- !WifiNative.setNetworkVariableCommand(
- netId,
- WifiConfiguration.PairwiseCipher.varName,
- allowedPairwiseCiphersString)) {
- Log.d(TAG, "failed to set pairwise: "+
- allowedPairwiseCiphersString);
- break setVariables;
- }
-
- String allowedGroupCiphersString =
- makeString(config.allowedGroupCiphers, WifiConfiguration.GroupCipher.strings);
- if (config.allowedGroupCiphers.cardinality() != 0 &&
- !WifiNative.setNetworkVariableCommand(
- netId,
- WifiConfiguration.GroupCipher.varName,
- allowedGroupCiphersString)) {
- Log.d(TAG, "failed to set group: "+
- allowedGroupCiphersString);
- break setVariables;
- }
-
- // Prevent client screw-up by passing in a WifiConfiguration we gave it
- // by preventing "*" as a key.
- if (config.preSharedKey != null && !config.preSharedKey.equals("*") &&
- !WifiNative.setNetworkVariableCommand(
- netId,
- WifiConfiguration.pskVarName,
- config.preSharedKey)) {
- Log.d(TAG, "failed to set psk: "+config.preSharedKey);
- break setVariables;
- }
-
- boolean hasSetKey = false;
- if (config.wepKeys != null) {
- for (int i = 0; i < config.wepKeys.length; i++) {
- // Prevent client screw-up by passing in a WifiConfiguration we gave it
- // by preventing "*" as a key.
- if (config.wepKeys[i] != null && !config.wepKeys[i].equals("*")) {
- if (!WifiNative.setNetworkVariableCommand(
- netId,
- WifiConfiguration.wepKeyVarNames[i],
- config.wepKeys[i])) {
- Log.d(TAG,
- "failed to set wep_key"+i+": " +
- config.wepKeys[i]);
- break setVariables;
- }
- hasSetKey = true;
- }
- }
- }
-
- if (hasSetKey) {
- if (!WifiNative.setNetworkVariableCommand(
- netId,
- WifiConfiguration.wepTxKeyIdxVarName,
- Integer.toString(config.wepTxKeyIndex))) {
- Log.d(TAG,
- "failed to set wep_tx_keyidx: "+
- config.wepTxKeyIndex);
- break setVariables;
- }
- }
-
- if (!WifiNative.setNetworkVariableCommand(
- netId,
- WifiConfiguration.priorityVarName,
- Integer.toString(config.priority))) {
- Log.d(TAG, config.SSID + ": failed to set priority: "
- +config.priority);
- break setVariables;
- }
-
- if (config.hiddenSSID && !WifiNative.setNetworkVariableCommand(
- netId,
- WifiConfiguration.hiddenSSIDVarName,
- Integer.toString(config.hiddenSSID ? 1 : 0))) {
- Log.d(TAG, config.SSID + ": failed to set hiddenSSID: "+
- config.hiddenSSID);
- break setVariables;
- }
-
- for (WifiConfiguration.EnterpriseField field
- : config.enterpriseFields) {
- String varName = field.varName();
- String value = field.value();
- if (value != null) {
- if (field != config.eap) {
- value = (value.length() == 0) ? "NULL" : convertToQuotedString(value);
- }
- if (!WifiNative.setNetworkVariableCommand(
- netId,
- varName,
- value)) {
- Log.d(TAG, config.SSID + ": failed to set " + varName +
- ": " + value);
- break setVariables;
- }
- }
- }
- return netId;
- }
-
- if (newNetwork) {
- WifiNative.removeNetworkCommand(netId);
- Log.d(TAG,
- "Failed to set a network variable, removed network: "
- + netId);
- }
-
- return -1;
- }
-
- private List<WifiConfiguration> getConfiguredNetworksNative() {
- String listStr = WifiNative.listNetworksCommand();
-
- List<WifiConfiguration> networks =
- new ArrayList<WifiConfiguration>();
- if (listStr == null)
- return networks;
-
- String[] lines = listStr.split("\n");
- // Skip the first line, which is a header
- for (int i = 1; i < lines.length; i++) {
- String[] result = lines[i].split("\t");
- // network-id | ssid | bssid | flags
- WifiConfiguration config = new WifiConfiguration();
- try {
- config.networkId = Integer.parseInt(result[0]);
- } catch(NumberFormatException e) {
- continue;
- }
- if (result.length > 3) {
- if (result[3].indexOf("[CURRENT]") != -1)
- config.status = WifiConfiguration.Status.CURRENT;
- else if (result[3].indexOf("[DISABLED]") != -1)
- config.status = WifiConfiguration.Status.DISABLED;
- else
- config.status = WifiConfiguration.Status.ENABLED;
- } else {
- config.status = WifiConfiguration.Status.ENABLED;
- }
- readNetworkVariables(config);
- networks.add(config);
- }
- return networks;
- }
-
- /**
- * Read the variables from the supplicant daemon that are needed to
- * fill in the WifiConfiguration object.
- *
- * @param config the {@link WifiConfiguration} object to be filled in.
- */
- private void readNetworkVariables(WifiConfiguration config) {
-
- int netId = config.networkId;
- if (netId < 0)
- return;
-
- /*
- * TODO: maybe should have a native method that takes an array of
- * variable names and returns an array of values. But we'd still
- * be doing a round trip to the supplicant daemon for each variable.
- */
- String value;
-
- value = WifiNative.getNetworkVariableCommand(netId, WifiConfiguration.ssidVarName);
- if (!TextUtils.isEmpty(value)) {
- config.SSID = removeDoubleQuotes(value);
- } else {
- config.SSID = null;
- }
-
- value = WifiNative.getNetworkVariableCommand(netId, WifiConfiguration.bssidVarName);
- if (!TextUtils.isEmpty(value)) {
- config.BSSID = value;
- } else {
- config.BSSID = null;
- }
-
- value = WifiNative.getNetworkVariableCommand(netId, WifiConfiguration.priorityVarName);
- config.priority = -1;
- if (!TextUtils.isEmpty(value)) {
- try {
- config.priority = Integer.parseInt(value);
- } catch (NumberFormatException ignore) {
- }
- }
-
- value = WifiNative.getNetworkVariableCommand(netId, WifiConfiguration.hiddenSSIDVarName);
- config.hiddenSSID = false;
- if (!TextUtils.isEmpty(value)) {
- try {
- config.hiddenSSID = Integer.parseInt(value) != 0;
- } catch (NumberFormatException ignore) {
- }
- }
-
- value = WifiNative.getNetworkVariableCommand(netId, WifiConfiguration.wepTxKeyIdxVarName);
- config.wepTxKeyIndex = -1;
- if (!TextUtils.isEmpty(value)) {
- try {
- config.wepTxKeyIndex = Integer.parseInt(value);
- } catch (NumberFormatException ignore) {
- }
- }
-
- for (int i = 0; i < 4; i++) {
- value = WifiNative.getNetworkVariableCommand(netId,
- WifiConfiguration.wepKeyVarNames[i]);
- if (!TextUtils.isEmpty(value)) {
- config.wepKeys[i] = value;
- } else {
- config.wepKeys[i] = null;
- }
- }
-
- value = WifiNative.getNetworkVariableCommand(netId, WifiConfiguration.pskVarName);
- if (!TextUtils.isEmpty(value)) {
- config.preSharedKey = value;
- } else {
- config.preSharedKey = null;
- }
-
- value = WifiNative.getNetworkVariableCommand(config.networkId,
- WifiConfiguration.Protocol.varName);
- if (!TextUtils.isEmpty(value)) {
- String vals[] = value.split(" ");
- for (String val : vals) {
- int index =
- lookupString(val, WifiConfiguration.Protocol.strings);
- if (0 <= index) {
- config.allowedProtocols.set(index);
- }
- }
- }
-
- value = WifiNative.getNetworkVariableCommand(config.networkId,
- WifiConfiguration.KeyMgmt.varName);
- if (!TextUtils.isEmpty(value)) {
- String vals[] = value.split(" ");
- for (String val : vals) {
- int index =
- lookupString(val, WifiConfiguration.KeyMgmt.strings);
- if (0 <= index) {
- config.allowedKeyManagement.set(index);
- }
- }
- }
-
- value = WifiNative.getNetworkVariableCommand(config.networkId,
- WifiConfiguration.AuthAlgorithm.varName);
- if (!TextUtils.isEmpty(value)) {
- String vals[] = value.split(" ");
- for (String val : vals) {
- int index =
- lookupString(val, WifiConfiguration.AuthAlgorithm.strings);
- if (0 <= index) {
- config.allowedAuthAlgorithms.set(index);
- }
- }
- }
-
- value = WifiNative.getNetworkVariableCommand(config.networkId,
- WifiConfiguration.PairwiseCipher.varName);
- if (!TextUtils.isEmpty(value)) {
- String vals[] = value.split(" ");
- for (String val : vals) {
- int index =
- lookupString(val, WifiConfiguration.PairwiseCipher.strings);
- if (0 <= index) {
- config.allowedPairwiseCiphers.set(index);
- }
- }
- }
-
- value = WifiNative.getNetworkVariableCommand(config.networkId,
- WifiConfiguration.GroupCipher.varName);
- if (!TextUtils.isEmpty(value)) {
- String vals[] = value.split(" ");
- for (String val : vals) {
- int index =
- lookupString(val, WifiConfiguration.GroupCipher.strings);
- if (0 <= index) {
- config.allowedGroupCiphers.set(index);
- }
- }
- }
-
- for (WifiConfiguration.EnterpriseField field :
- config.enterpriseFields) {
- value = WifiNative.getNetworkVariableCommand(netId,
- field.varName());
- if (!TextUtils.isEmpty(value)) {
- if (field != config.eap) value = removeDoubleQuotes(value);
- field.setValue(value);
- }
- }
-
- }
-
- /**
- * Poll for info not reported via events
- * RSSI & Linkspeed
- */
- private void requestPolledInfo() {
- int newRssi = WifiNative.getRssiCommand();
- if (newRssi != -1 && -200 < newRssi && newRssi < 256) { // screen out invalid values
- /* some implementations avoid negative values by adding 256
- * so we need to adjust for that here.
- */
- if (newRssi > 0) newRssi -= 256;
- mWifiInfo.setRssi(newRssi);
- /*
- * Rather then sending the raw RSSI out every time it
- * changes, we precalculate the signal level that would
- * be displayed in the status bar, and only send the
- * broadcast if that much more coarse-grained number
- * changes. This cuts down greatly on the number of
- * broadcasts, at the cost of not mWifiInforming others
- * interested in RSSI of all the changes in signal
- * level.
- */
- // TODO: The second arg to the call below needs to be a symbol somewhere, but
- // it's actually the size of an array of icons that's private
- // to StatusBar Policy.
- int newSignalLevel = WifiManager.calculateSignalLevel(newRssi, 4);
- if (newSignalLevel != mLastSignalLevel) {
- sendRssiChangeBroadcast(newRssi);
- }
- mLastSignalLevel = newSignalLevel;
- } else {
- mWifiInfo.setRssi(-200);
- }
- int newLinkSpeed = WifiNative.getLinkSpeedCommand();
- if (newLinkSpeed != -1) {
- mWifiInfo.setLinkSpeed(newLinkSpeed);
- }
- }
-
- /**
- * Resets the Wi-Fi Connections by clearing any state, resetting any sockets
- * using the interface, stopping DHCP & disabling interface
- */
- private void handleNetworkDisconnect() {
- Log.d(TAG, "Reset connections and stopping DHCP");
-
- /*
- * Reset connections & stop DHCP
- */
- NetworkUtils.resetConnections(mInterfaceName);
-
- if (!NetworkUtils.stopDhcp(mInterfaceName)) {
- Log.e(TAG, "Could not stop DHCP");
- }
-
- /* Disable interface */
- NetworkUtils.disableInterface(mInterfaceName);
-
- /* send event to CM & network change broadcast */
- setDetailedState(DetailedState.DISCONNECTED);
- sendNetworkStateChangeBroadcast(mLastBssid);
-
- /* Reset data structures */
- mWifiInfo.setIpAddress(0);
- mWifiInfo.setBSSID(null);
- mWifiInfo.setSSID(null);
- mWifiInfo.setNetworkId(-1);
-
- /* Clear network properties */
- mNetworkProperties.clear();
-
- mLastBssid= null;
- mLastNetworkId = -1;
-
- }
-
-
- /*********************************************************
- * Notifications from WifiMonitor
- ********************************************************/
-
- /**
- * A structure for supplying information about a supplicant state
- * change in the STATE_CHANGE event message that comes from the
- * WifiMonitor
- * thread.
- */
- private static class StateChangeResult {
- StateChangeResult(int networkId, String BSSID, Object state) {
- this.state = state;
- this.BSSID = BSSID;
- this.networkId = networkId;
- }
- int networkId;
- String BSSID;
- Object state;
- }
-
- /**
- * Send the tracker a notification that a user-entered password key
- * may be incorrect (i.e., caused authentication to fail).
- */
- void notifyPasswordKeyMayBeIncorrect() {
- sendMessage(PASSWORD_MAY_BE_INCORRECT_EVENT);
- }
-
- /**
- * Send the tracker a notification that a connection to the supplicant
- * daemon has been established.
- */
- void notifySupplicantConnection() {
- sendMessage(SUP_CONNECTION_EVENT);
- }
-
- /**
- * Send the tracker a notification that a connection to the supplicant
- * daemon has been established.
- */
- void notifySupplicantLost() {
- sendMessage(SUP_DISCONNECTION_EVENT);
- }
-
- /**
- * Send the tracker a notification that the state of Wifi connectivity
- * has changed.
- * @param networkId the configured network on which the state change occurred
- * @param newState the new network state
- * @param BSSID when the new state is {@link DetailedState#CONNECTED
- * NetworkInfo.DetailedState.CONNECTED},
- * this is the MAC address of the access point. Otherwise, it
- * is {@code null}.
- */
- void notifyNetworkStateChange(DetailedState newState, String BSSID, int networkId) {
- if (newState == NetworkInfo.DetailedState.CONNECTED) {
- sendMessage(obtainMessage(NETWORK_CONNECTION_EVENT,
- new StateChangeResult(networkId, BSSID, newState)));
- } else {
- sendMessage(obtainMessage(NETWORK_DISCONNECTION_EVENT,
- new StateChangeResult(networkId, BSSID, newState)));
- }
- }
-
- /**
- * Send the tracker a notification that the state of the supplicant
- * has changed.
- * @param networkId the configured network on which the state change occurred
- * @param newState the new {@code SupplicantState}
- */
- void notifySupplicantStateChange(int networkId, String BSSID, SupplicantState newState) {
- sendMessage(obtainMessage(SUPPLICANT_STATE_CHANGE_EVENT,
- new StateChangeResult(networkId, BSSID, newState)));
- }
-
- /**
- * Send the tracker a notification that a scan has completed, and results
- * are available.
- */
- void notifyScanResultsAvailable() {
- /**
- * Switch scan mode over to passive.
- * Turning off scan-only mode happens only in "Connect" mode
- */
- setScanType(false);
- sendMessage(SCAN_RESULTS_EVENT);
- }
-
- void notifyDriverStarted() {
- sendMessage(DRIVER_START_EVENT);
- }
-
- void notifyDriverStopped() {
- sendMessage(DRIVER_STOP_EVENT);
- }
-
- void notifyDriverHung() {
- setWifiEnabled(false);
- setWifiEnabled(true);
- }
-
-
- /********************************************************
- * HSM states
- *******************************************************/
-
- class DefaultState extends HierarchicalState {
- @Override
- public boolean processMessage(Message message) {
- if (DBG) Log.d(TAG, getName() + message.toString() + "\n");
- SyncParams syncParams;
- switch (message.what) {
- /* Synchronous call returns */
- case CMD_PING_SUPPLICANT:
- case CMD_START_SCAN:
- case CMD_DISCONNECT:
- case CMD_RECONNECT:
- case CMD_REASSOCIATE:
- case CMD_REMOVE_NETWORK:
- case CMD_ENABLE_NETWORK:
- case CMD_DISABLE_NETWORK:
- case CMD_ADD_OR_UPDATE_NETWORK:
- case CMD_GET_RSSI:
- case CMD_GET_RSSI_APPROX:
- case CMD_GET_LINK_SPEED:
- case CMD_GET_MAC_ADDR:
- case CMD_SAVE_CONFIG:
- case CMD_CONNECTION_STATUS:
- case CMD_GET_NETWORK_CONFIG:
- if (message.arg2 == SYNCHRONOUS_CALL) {
- syncParams = (SyncParams) message.obj;
- syncParams.mSyncReturn.boolValue = false;
- syncParams.mSyncReturn.intValue = -1;
- syncParams.mSyncReturn.stringValue = null;
- syncParams.mSyncReturn.configList = null;
- notifyOnMsgObject(message);
- }
- break;
- case CM_CMD_TEARDOWN:
- EventLog.writeEvent(EVENTLOG_WIFI_EVENT_HANDLED, message.what);
- mTeardownRequested.set(true);
- sendMessage(CMD_DISCONNECT);
- sendMessage(CMD_STOP_DRIVER);
- /* Mark wifi available when CM tears down */
- mNetworkInfo.setIsAvailable(true);
- break;
- case CM_CMD_RECONNECT:
- EventLog.writeEvent(EVENTLOG_WIFI_EVENT_HANDLED, message.what);
- mTeardownRequested.set(false);
- sendMessage(CMD_START_DRIVER);
- sendMessage(CMD_RECONNECT);
- break;
- case CMD_ENABLE_RSSI_POLL:
- mEnableRssiPolling = (message.arg1 == 1);
- mSupplicantStateTracker.sendMessage(CMD_ENABLE_RSSI_POLL);
- break;
- default:
- if (DBG) Log.w(TAG, "Unhandled " + message);
- break;
- }
- return HANDLED;
- }
- }
-
- class InitialState extends HierarchicalState {
- @Override
- //TODO: could move logging into a common class
- public void enter() {
- if (DBG) Log.d(TAG, getName() + "\n");
- // [31-8] Reserved for future use
- // [7 - 0] HSM state change
- // 50021 wifi_state_changed (custom|1|5)
- EventLog.writeEvent(EVENTLOG_WIFI_STATE_CHANGED, getName());
-
- if (WifiNative.isDriverLoaded()) {
- transitionTo(mDriverLoadedState);
- }
- else {
- transitionTo(mDriverUnloadedState);
- }
- }
- }
-
- class DriverLoadingState extends HierarchicalState {
- @Override
- public void enter() {
- if (DBG) Log.d(TAG, getName() + "\n");
- EventLog.writeEvent(EVENTLOG_WIFI_STATE_CHANGED, getName());
-
- final Message message = new Message();
- message.copyFrom(getCurrentMessage());
- new Thread(new Runnable() {
- public void run() {
- sWakeLock.acquire();
- //enabling state
- switch(message.arg1) {
- case WIFI_STATE_ENABLING:
- setWifiState(WIFI_STATE_ENABLING);
- break;
- case WIFI_AP_STATE_ENABLING:
- setWifiApState(WIFI_AP_STATE_ENABLING);
- break;
- }
-
- if(WifiNative.loadDriver()) {
- Log.d(TAG, "Driver load successful");
- sendMessage(CMD_LOAD_DRIVER_SUCCESS);
- } else {
- Log.e(TAG, "Failed to load driver!");
- switch(message.arg1) {
- case WIFI_STATE_ENABLING:
- setWifiState(WIFI_STATE_UNKNOWN);
- break;
- case WIFI_AP_STATE_ENABLING:
- setWifiApState(WIFI_AP_STATE_FAILED);
- break;
- }
- sendMessage(CMD_LOAD_DRIVER_FAILURE);
- }
- sWakeLock.release();
- }
- }).start();
- }
-
- @Override
- public boolean processMessage(Message message) {
- if (DBG) Log.d(TAG, getName() + message.toString() + "\n");
- switch (message.what) {
- case CMD_LOAD_DRIVER_SUCCESS:
- transitionTo(mDriverLoadedState);
- break;
- case CMD_LOAD_DRIVER_FAILURE:
- transitionTo(mDriverFailedState);
- break;
- case CMD_LOAD_DRIVER:
- case CMD_UNLOAD_DRIVER:
- case CMD_START_SUPPLICANT:
- case CMD_STOP_SUPPLICANT:
- case CMD_START_AP:
- case CMD_STOP_AP:
- case CMD_START_DRIVER:
- case CMD_STOP_DRIVER:
- case CMD_SET_SCAN_MODE:
- case CMD_SET_SCAN_TYPE:
- case CMD_SET_POWER_MODE:
- case CMD_SET_BLUETOOTH_COEXISTENCE:
- case CMD_SET_BLUETOOTH_SCAN_MODE:
- case CMD_SET_NUM_ALLOWED_CHANNELS:
- case CMD_START_PACKET_FILTERING:
- case CMD_STOP_PACKET_FILTERING:
- deferMessage(message);
- break;
- default:
- return NOT_HANDLED;
- }
- EventLog.writeEvent(EVENTLOG_WIFI_EVENT_HANDLED, message.what);
- return HANDLED;
- }
- }
-
- class DriverLoadedState extends HierarchicalState {
- @Override
- public void enter() {
- if (DBG) Log.d(TAG, getName() + "\n");
- EventLog.writeEvent(EVENTLOG_WIFI_STATE_CHANGED, getName());
- }
- @Override
- public boolean processMessage(Message message) {
- if (DBG) Log.d(TAG, getName() + message.toString() + "\n");
- switch(message.what) {
- case CMD_UNLOAD_DRIVER:
- transitionTo(mDriverUnloadingState);
- break;
- case CMD_START_SUPPLICANT:
- if(WifiNative.startSupplicant()) {
- Log.d(TAG, "Supplicant start successful");
- mWifiMonitor.startMonitoring();
- setWifiState(WIFI_STATE_ENABLED);
- transitionTo(mWaitForSupState);
- } else {
- Log.e(TAG, "Failed to start supplicant!");
- sendMessage(obtainMessage(CMD_UNLOAD_DRIVER, WIFI_STATE_UNKNOWN, 0));
- }
- break;
- case CMD_START_AP:
- try {
- nwService.startAccessPoint((WifiConfiguration) message.obj,
- mInterfaceName,
- SOFTAP_IFACE);
- } catch(Exception e) {
- Log.e(TAG, "Exception in startAccessPoint()");
- sendMessage(obtainMessage(CMD_UNLOAD_DRIVER, WIFI_AP_STATE_FAILED, 0));
- break;
- }
- Log.d(TAG, "Soft AP start successful");
- setWifiApState(WIFI_AP_STATE_ENABLED);
- transitionTo(mSoftApStartedState);
- break;
- default:
- return NOT_HANDLED;
- }
- EventLog.writeEvent(EVENTLOG_WIFI_EVENT_HANDLED, message.what);
- return HANDLED;
- }
- }
-
- class DriverUnloadingState extends HierarchicalState {
- @Override
- public void enter() {
- if (DBG) Log.d(TAG, getName() + "\n");
- EventLog.writeEvent(EVENTLOG_WIFI_STATE_CHANGED, getName());
-
- final Message message = new Message();
- message.copyFrom(getCurrentMessage());
- new Thread(new Runnable() {
- public void run() {
- if (DBG) Log.d(TAG, getName() + message.toString() + "\n");
- sWakeLock.acquire();
- if(WifiNative.unloadDriver()) {
- Log.d(TAG, "Driver unload successful");
- sendMessage(CMD_UNLOAD_DRIVER_SUCCESS);
-
- switch(message.arg1) {
- case WIFI_STATE_DISABLED:
- case WIFI_STATE_UNKNOWN:
- setWifiState(message.arg1);
- break;
- case WIFI_AP_STATE_DISABLED:
- case WIFI_AP_STATE_FAILED:
- setWifiApState(message.arg1);
- break;
- }
- } else {
- Log.e(TAG, "Failed to unload driver!");
- sendMessage(CMD_UNLOAD_DRIVER_FAILURE);
-
- switch(message.arg1) {
- case WIFI_STATE_DISABLED:
- case WIFI_STATE_UNKNOWN:
- setWifiState(WIFI_STATE_UNKNOWN);
- break;
- case WIFI_AP_STATE_DISABLED:
- case WIFI_AP_STATE_FAILED:
- setWifiApState(WIFI_AP_STATE_FAILED);
- break;
- }
- }
- sWakeLock.release();
- }
- }).start();
- }
-
- @Override
- public boolean processMessage(Message message) {
- if (DBG) Log.d(TAG, getName() + message.toString() + "\n");
- switch (message.what) {
- case CMD_UNLOAD_DRIVER_SUCCESS:
- transitionTo(mDriverUnloadedState);
- break;
- case CMD_UNLOAD_DRIVER_FAILURE:
- transitionTo(mDriverFailedState);
- break;
- case CMD_LOAD_DRIVER:
- case CMD_UNLOAD_DRIVER:
- case CMD_START_SUPPLICANT:
- case CMD_STOP_SUPPLICANT:
- case CMD_START_AP:
- case CMD_STOP_AP:
- case CMD_START_DRIVER:
- case CMD_STOP_DRIVER:
- case CMD_SET_SCAN_MODE:
- case CMD_SET_SCAN_TYPE:
- case CMD_SET_POWER_MODE:
- case CMD_SET_BLUETOOTH_COEXISTENCE:
- case CMD_SET_BLUETOOTH_SCAN_MODE:
- case CMD_SET_NUM_ALLOWED_CHANNELS:
- case CMD_START_PACKET_FILTERING:
- case CMD_STOP_PACKET_FILTERING:
- deferMessage(message);
- break;
- default:
- return NOT_HANDLED;
- }
- EventLog.writeEvent(EVENTLOG_WIFI_EVENT_HANDLED, message.what);
- return HANDLED;
- }
- }
-
- class DriverUnloadedState extends HierarchicalState {
- @Override
- public void enter() {
- if (DBG) Log.d(TAG, getName() + "\n");
- EventLog.writeEvent(EVENTLOG_WIFI_STATE_CHANGED, getName());
- }
- @Override
- public boolean processMessage(Message message) {
- if (DBG) Log.d(TAG, getName() + message.toString() + "\n");
- switch (message.what) {
- case CMD_LOAD_DRIVER:
- transitionTo(mDriverLoadingState);
- break;
- default:
- return NOT_HANDLED;
- }
- EventLog.writeEvent(EVENTLOG_WIFI_EVENT_HANDLED, message.what);
- return HANDLED;
- }
- }
-
- class DriverFailedState extends HierarchicalState {
- @Override
- public void enter() {
- Log.e(TAG, getName() + "\n");
- EventLog.writeEvent(EVENTLOG_WIFI_STATE_CHANGED, getName());
- }
- @Override
- public boolean processMessage(Message message) {
- if (DBG) Log.d(TAG, getName() + message.toString() + "\n");
- return NOT_HANDLED;
- }
- }
-
-
- class WaitForSupState extends HierarchicalState {
- @Override
- public void enter() {
- if (DBG) Log.d(TAG, getName() + "\n");
- EventLog.writeEvent(EVENTLOG_WIFI_STATE_CHANGED, getName());
- }
- @Override
- public boolean processMessage(Message message) {
- if (DBG) Log.d(TAG, getName() + message.toString() + "\n");
- switch(message.what) {
- case SUP_CONNECTION_EVENT:
- Log.d(TAG, "Supplicant connection established");
- mSupplicantStateTracker.resetSupplicantState();
- /* Initialize data structures */
- resetNotificationTimer();
- setTeardownRequested(false);
- mLastBssid = null;
- mLastNetworkId = -1;
- mLastSignalLevel = -1;
-
- mWifiInfo.setMacAddress(WifiNative.getMacAddressCommand());
-
- //TODO: initialize and fix multicast filtering
- //mWM.initializeMulticastFiltering();
-
- if (mBluetoothA2dp == null) {
- mBluetoothA2dp = new BluetoothA2dp(mContext);
- }
- checkIsBluetoothPlaying();
-
- checkUseStaticIp();
- sendSupplicantConnectionChangedBroadcast(true);
- transitionTo(mDriverSupReadyState);
- break;
- case CMD_STOP_SUPPLICANT:
- Log.d(TAG, "Stop supplicant received");
- WifiNative.stopSupplicant();
- transitionTo(mDriverLoadedState);
- break;
- /* Fail soft ap when waiting for supplicant start */
- case CMD_START_AP:
- Log.d(TAG, "Failed to start soft AP with a running supplicant");
- setWifiApState(WIFI_AP_STATE_FAILED);
- break;
- case CMD_START_DRIVER:
- case CMD_STOP_DRIVER:
- case CMD_SET_SCAN_MODE:
- case CMD_SET_SCAN_TYPE:
- case CMD_SET_POWER_MODE:
- case CMD_SET_BLUETOOTH_COEXISTENCE:
- case CMD_SET_BLUETOOTH_SCAN_MODE:
- case CMD_SET_NUM_ALLOWED_CHANNELS:
- case CMD_START_PACKET_FILTERING:
- case CMD_STOP_PACKET_FILTERING:
- deferMessage(message);
- break;
- case CMD_STOP_AP:
- case CMD_START_SUPPLICANT:
- case CMD_UNLOAD_DRIVER:
- break;
- default:
- return NOT_HANDLED;
- }
- EventLog.writeEvent(EVENTLOG_WIFI_EVENT_HANDLED, message.what);
- return HANDLED;
- }
- }
-
- class DriverSupReadyState extends HierarchicalState {
- @Override
- public void enter() {
- if (DBG) Log.d(TAG, getName() + "\n");
- EventLog.writeEvent(EVENTLOG_WIFI_STATE_CHANGED, getName());
- /* Initialize for connect mode operation at start */
- mIsScanMode = false;
- }
- @Override
- public boolean processMessage(Message message) {
- if (DBG) Log.d(TAG, getName() + message.toString() + "\n");
- SyncParams syncParams;
- switch(message.what) {
- case CMD_STOP_SUPPLICANT: /* Supplicant stopped by user */
- Log.d(TAG, "Stop supplicant received");
- WifiNative.stopSupplicant();
- //$FALL-THROUGH$
- case SUP_DISCONNECTION_EVENT: /* Supplicant died */
- EventLog.writeEvent(EVENTLOG_WIFI_EVENT_HANDLED, message.what);
- //Remove any notifications on disconnection
- setNotificationVisible(false, 0, false, 0);
- WifiNative.closeSupplicantConnection();
- handleNetworkDisconnect();
- sendSupplicantConnectionChangedBroadcast(false);
- mSupplicantStateTracker.resetSupplicantState();
- transitionTo(mDriverLoadedState);
-
- /* When supplicant dies, unload driver and enter failed state */
- //TODO: consider bringing up supplicant again
- if (message.what == SUP_DISCONNECTION_EVENT) {
- Log.d(TAG, "Supplicant died, unloading driver");
- sendMessage(obtainMessage(CMD_UNLOAD_DRIVER, WIFI_STATE_UNKNOWN, 0));
- }
- break;
- case CMD_START_DRIVER:
- EventLog.writeEvent(EVENTLOG_WIFI_EVENT_HANDLED, message.what);
- WifiNative.startDriverCommand();
- transitionTo(mDriverStartingState);
- break;
- case SCAN_RESULTS_EVENT:
- setScanResults(WifiNative.scanResultsCommand());
- sendScanResultsAvailableBroadcast();
- checkAndSetNotification();
- break;
- case CMD_PING_SUPPLICANT:
- syncParams = (SyncParams) message.obj;
- syncParams.mSyncReturn.boolValue = WifiNative.pingCommand();
- notifyOnMsgObject(message);
- break;
- case CMD_ADD_OR_UPDATE_NETWORK:
- EventLog.writeEvent(EVENTLOG_WIFI_EVENT_HANDLED, message.what);
- syncParams = (SyncParams) message.obj;
- WifiConfiguration config = (WifiConfiguration) syncParams.mParameter;
- syncParams.mSyncReturn.intValue = addOrUpdateNetworkNative(config);
- notifyOnMsgObject(message);
- break;
- case CMD_REMOVE_NETWORK:
- EventLog.writeEvent(EVENTLOG_WIFI_EVENT_HANDLED, message.what);
- if (message.arg2 == SYNCHRONOUS_CALL) {
- syncParams = (SyncParams) message.obj;
- syncParams.mSyncReturn.boolValue = WifiNative.removeNetworkCommand(
- message.arg1);
- notifyOnMsgObject(message);
- } else {
- /* asynchronous handling */
- WifiNative.removeNetworkCommand(message.arg1);
- }
- break;
- case CMD_ENABLE_NETWORK:
- EventLog.writeEvent(EVENTLOG_WIFI_EVENT_HANDLED, message.what);
- if (message.arg2 == SYNCHRONOUS_CALL) {
- syncParams = (SyncParams) message.obj;
- EnableNetParams enableNetParams = (EnableNetParams) syncParams.mParameter;
- syncParams.mSyncReturn.boolValue = WifiNative.enableNetworkCommand(
- enableNetParams.netId, enableNetParams.disableOthers);
- notifyOnMsgObject(message);
- } else {
- /* asynchronous handling */
- WifiNative.enableNetworkCommand(message.arg1, message.arg2 == 1);
- }
- break;
- case CMD_DISABLE_NETWORK:
- EventLog.writeEvent(EVENTLOG_WIFI_EVENT_HANDLED, message.what);
- if (message.arg2 == SYNCHRONOUS_CALL) {
- syncParams = (SyncParams) message.obj;
- syncParams.mSyncReturn.boolValue = WifiNative.disableNetworkCommand(
- message.arg1);
- notifyOnMsgObject(message);
- } else {
- /* asynchronous handling */
- WifiNative.disableNetworkCommand(message.arg1);
- }
- break;
- case CMD_BLACKLIST_NETWORK:
- EventLog.writeEvent(EVENTLOG_WIFI_EVENT_HANDLED, message.what);
- WifiNative.addToBlacklistCommand((String)message.obj);
- break;
- case CMD_CLEAR_BLACKLIST:
- WifiNative.clearBlacklistCommand();
- break;
- case CMD_GET_NETWORK_CONFIG:
- syncParams = (SyncParams) message.obj;
- syncParams.mSyncReturn.configList = getConfiguredNetworksNative();
- notifyOnMsgObject(message);
- break;
- case CMD_SAVE_CONFIG:
- if (message.arg2 == SYNCHRONOUS_CALL) {
- syncParams = (SyncParams) message.obj;
- syncParams.mSyncReturn.boolValue = WifiNative.saveConfigCommand();
- notifyOnMsgObject(message);
- } else {
- /* asynchronous handling */
- WifiNative.saveConfigCommand();
- }
- // Inform the backup manager about a data change
- IBackupManager ibm = IBackupManager.Stub.asInterface(
- ServiceManager.getService(Context.BACKUP_SERVICE));
- if (ibm != null) {
- try {
- ibm.dataChanged("com.android.providers.settings");
- } catch (Exception e) {
- // Try again later
- }
- }
- break;
- case CMD_CONNECTION_STATUS:
- syncParams = (SyncParams) message.obj;
- syncParams.mSyncReturn.stringValue = WifiNative.statusCommand();
- notifyOnMsgObject(message);
- break;
- case CMD_GET_MAC_ADDR:
- syncParams = (SyncParams) message.obj;
- syncParams.mSyncReturn.stringValue = WifiNative.getMacAddressCommand();
- notifyOnMsgObject(message);
- break;
- /* Cannot start soft AP while in client mode */
- case CMD_START_AP:
- Log.d(TAG, "Failed to start soft AP with a running supplicant");
- EventLog.writeEvent(EVENTLOG_WIFI_EVENT_HANDLED, message.what);
- setWifiApState(WIFI_AP_STATE_FAILED);
- break;
- case CMD_SET_SCAN_MODE:
- mIsScanMode = (message.arg1 == SCAN_ONLY_MODE);
- break;
- default:
- return NOT_HANDLED;
- }
- return HANDLED;
- }
- }
-
- class DriverStartingState extends HierarchicalState {
- @Override
- public void enter() {
- if (DBG) Log.d(TAG, getName() + "\n");
- EventLog.writeEvent(EVENTLOG_WIFI_STATE_CHANGED, getName());
- }
- @Override
- public boolean processMessage(Message message) {
- if (DBG) Log.d(TAG, getName() + message.toString() + "\n");
- switch(message.what) {
- case DRIVER_START_EVENT:
- transitionTo(mDriverStartedState);
- break;
- /* Queue driver commands & connection events */
- case CMD_START_DRIVER:
- case CMD_STOP_DRIVER:
- case SUPPLICANT_STATE_CHANGE_EVENT:
- case NETWORK_CONNECTION_EVENT:
- case NETWORK_DISCONNECTION_EVENT:
- case PASSWORD_MAY_BE_INCORRECT_EVENT:
- case CMD_SET_SCAN_TYPE:
- case CMD_SET_POWER_MODE:
- case CMD_SET_BLUETOOTH_COEXISTENCE:
- case CMD_SET_BLUETOOTH_SCAN_MODE:
- case CMD_SET_NUM_ALLOWED_CHANNELS:
- case CMD_START_PACKET_FILTERING:
- case CMD_STOP_PACKET_FILTERING:
- deferMessage(message);
- break;
- /* Queue the asynchronous version of these commands */
- case CMD_START_SCAN:
- case CMD_DISCONNECT:
- case CMD_REASSOCIATE:
- case CMD_RECONNECT:
- if (message.arg2 != SYNCHRONOUS_CALL) {
- deferMessage(message);
- }
- break;
- default:
- return NOT_HANDLED;
- }
- EventLog.writeEvent(EVENTLOG_WIFI_EVENT_HANDLED, message.what);
- return HANDLED;
- }
- }
-
- class DriverStartedState extends HierarchicalState {
- @Override
- public void enter() {
- if (DBG) Log.d(TAG, getName() + "\n");
- EventLog.writeEvent(EVENTLOG_WIFI_STATE_CHANGED, getName());
-
- try {
- mBatteryStats.noteWifiRunning();
- } catch (RemoteException ignore) {}
-
- /* Initialize channel count */
- setNumAllowedChannels();
-
- if (mIsScanMode) {
- WifiNative.setScanResultHandlingCommand(SCAN_ONLY_MODE);
- WifiNative.disconnectCommand();
- transitionTo(mScanModeState);
- } else {
- WifiNative.setScanResultHandlingCommand(CONNECT_MODE);
- /* If supplicant has already connected, before we could finish establishing
- * the control channel connection, we miss all the supplicant events.
- * Disconnect and reconnect when driver has started to ensure we receive
- * all supplicant events.
- *
- * TODO: This is a bit unclean, ideally the supplicant should never
- * connect until told to do so by the framework
- */
- WifiNative.disconnectCommand();
- WifiNative.reconnectCommand();
- transitionTo(mConnectModeState);
- }
- }
- @Override
- public boolean processMessage(Message message) {
- if (DBG) Log.d(TAG, getName() + message.toString() + "\n");
- SyncParams syncParams;
- switch(message.what) {
- case CMD_SET_SCAN_TYPE:
- if (message.arg1 == SCAN_ACTIVE) {
- WifiNative.setScanModeCommand(true);
- } else {
- WifiNative.setScanModeCommand(false);
- }
- break;
- case CMD_SET_POWER_MODE:
- WifiNative.setPowerModeCommand(message.arg1);
- break;
- case CMD_SET_BLUETOOTH_COEXISTENCE:
- WifiNative.setBluetoothCoexistenceModeCommand(message.arg1);
- break;
- case CMD_SET_BLUETOOTH_SCAN_MODE:
- WifiNative.setBluetoothCoexistenceScanModeCommand(message.arg1 == 1);
- break;
- case CMD_SET_NUM_ALLOWED_CHANNELS:
- mNumAllowedChannels = message.arg1;
- WifiNative.setNumAllowedChannelsCommand(message.arg1);
- break;
- case CMD_START_DRIVER:
- /* Ignore another driver start */
- break;
- case CMD_STOP_DRIVER:
- WifiNative.stopDriverCommand();
- transitionTo(mDriverStoppingState);
- break;
- case CMD_REQUEST_CM_WAKELOCK:
- if (mCm == null) {
- mCm = (ConnectivityManager)mContext.getSystemService(
- Context.CONNECTIVITY_SERVICE);
- }
- mCm.requestNetworkTransitionWakelock(TAG);
- break;
- case CMD_START_PACKET_FILTERING:
- WifiNative.startPacketFiltering();
- break;
- case CMD_STOP_PACKET_FILTERING:
- WifiNative.stopPacketFiltering();
- break;
- default:
- return NOT_HANDLED;
- }
- EventLog.writeEvent(EVENTLOG_WIFI_EVENT_HANDLED, message.what);
- return HANDLED;
- }
- @Override
- public void exit() {
- if (DBG) Log.d(TAG, getName() + "\n");
- try {
- mBatteryStats.noteWifiStopped();
- } catch (RemoteException ignore) { }
- }
- }
-
- class DriverStoppingState extends HierarchicalState {
- @Override
- public void enter() {
- if (DBG) Log.d(TAG, getName() + "\n");
- EventLog.writeEvent(EVENTLOG_WIFI_STATE_CHANGED, getName());
- }
- @Override
- public boolean processMessage(Message message) {
- if (DBG) Log.d(TAG, getName() + message.toString() + "\n");
- switch(message.what) {
- case DRIVER_STOP_EVENT:
- transitionTo(mDriverStoppedState);
- break;
- /* Queue driver commands */
- case CMD_START_DRIVER:
- case CMD_STOP_DRIVER:
- case CMD_SET_SCAN_TYPE:
- case CMD_SET_POWER_MODE:
- case CMD_SET_BLUETOOTH_COEXISTENCE:
- case CMD_SET_BLUETOOTH_SCAN_MODE:
- case CMD_SET_NUM_ALLOWED_CHANNELS:
- case CMD_START_PACKET_FILTERING:
- case CMD_STOP_PACKET_FILTERING:
- deferMessage(message);
- break;
- /* Queue the asynchronous version of these commands */
- case CMD_START_SCAN:
- case CMD_DISCONNECT:
- case CMD_REASSOCIATE:
- case CMD_RECONNECT:
- if (message.arg2 != SYNCHRONOUS_CALL) {
- deferMessage(message);
- }
- break;
- default:
- return NOT_HANDLED;
- }
- EventLog.writeEvent(EVENTLOG_WIFI_EVENT_HANDLED, message.what);
- return HANDLED;
- }
- }
-
- class DriverStoppedState extends HierarchicalState {
- @Override
- public void enter() {
- if (DBG) Log.d(TAG, getName() + "\n");
- EventLog.writeEvent(EVENTLOG_WIFI_STATE_CHANGED, getName());
-
- // Take down any open network notifications on driver stop
- setNotificationVisible(false, 0, false, 0);
- }
- @Override
- public boolean processMessage(Message message) {
- if (DBG) Log.d(TAG, getName() + message.toString() + "\n");
- return NOT_HANDLED;
- }
- }
-
- class ScanModeState extends HierarchicalState {
- @Override
- public void enter() {
- if (DBG) Log.d(TAG, getName() + "\n");
- EventLog.writeEvent(EVENTLOG_WIFI_STATE_CHANGED, getName());
- }
- @Override
- public boolean processMessage(Message message) {
- if (DBG) Log.d(TAG, getName() + message.toString() + "\n");
- SyncParams syncParams;
- switch(message.what) {
- case CMD_SET_SCAN_MODE:
- if (message.arg1 == SCAN_ONLY_MODE) {
- /* Ignore */
- return HANDLED;
- } else {
- WifiNative.setScanResultHandlingCommand(message.arg1);
- WifiNative.reconnectCommand();
- mIsScanMode = false;
- transitionTo(mDisconnectedState);
- }
- break;
- case CMD_START_SCAN:
- if (message.arg2 == SYNCHRONOUS_CALL) {
- syncParams = (SyncParams) message.obj;
- syncParams.mSyncReturn.boolValue = WifiNative.scanCommand(
- message.arg1 == SCAN_ACTIVE);
- notifyOnMsgObject(message);
- } else {
- /* asynchronous handling */
- WifiNative.scanCommand(message.arg1 == SCAN_ACTIVE);
- }
- break;
- /* Ignore */
- case CMD_DISCONNECT:
- case CMD_RECONNECT:
- case CMD_REASSOCIATE:
- case SUPPLICANT_STATE_CHANGE_EVENT:
- case NETWORK_CONNECTION_EVENT:
- case NETWORK_DISCONNECTION_EVENT:
- break;
- default:
- return NOT_HANDLED;
- }
- EventLog.writeEvent(EVENTLOG_WIFI_EVENT_HANDLED, message.what);
- return HANDLED;
- }
- }
-
- class ConnectModeState extends HierarchicalState {
- @Override
- public void enter() {
- if (DBG) Log.d(TAG, getName() + "\n");
- EventLog.writeEvent(EVENTLOG_WIFI_STATE_CHANGED, getName());
- }
- @Override
- public boolean processMessage(Message message) {
- if (DBG) Log.d(TAG, getName() + message.toString() + "\n");
- SyncParams syncParams;
- StateChangeResult stateChangeResult;
- switch(message.what) {
- case PASSWORD_MAY_BE_INCORRECT_EVENT:
- mPasswordKeyMayBeIncorrect = true;
- break;
- case SUPPLICANT_STATE_CHANGE_EVENT:
- stateChangeResult = (StateChangeResult) message.obj;
- mSupplicantStateTracker.handleEvent(stateChangeResult);
- break;
- case CMD_START_SCAN:
- if (message.arg2 == SYNCHRONOUS_CALL) {
- syncParams = (SyncParams) message.obj;
- syncParams.mSyncReturn.boolValue = true;
- notifyOnMsgObject(message);
- }
- /* We need to set scan type in completed state */
- Message newMsg = obtainMessage();
- newMsg.copyFrom(message);
- mSupplicantStateTracker.sendMessage(newMsg);
- break;
- /* Do a redundant disconnect without transition */
- case CMD_DISCONNECT:
- if (message.arg2 == SYNCHRONOUS_CALL) {
- syncParams = (SyncParams) message.obj;
- syncParams.mSyncReturn.boolValue = WifiNative.disconnectCommand();
- notifyOnMsgObject(message);
- } else {
- /* asynchronous handling */
- WifiNative.disconnectCommand();
- }
- break;
- case CMD_RECONNECT:
- if (message.arg2 == SYNCHRONOUS_CALL) {
- syncParams = (SyncParams) message.obj;
- syncParams.mSyncReturn.boolValue = WifiNative.reconnectCommand();
- notifyOnMsgObject(message);
- } else {
- /* asynchronous handling */
- WifiNative.reconnectCommand();
- }
- break;
- case CMD_REASSOCIATE:
- if (message.arg2 == SYNCHRONOUS_CALL) {
- syncParams = (SyncParams) message.obj;
- syncParams.mSyncReturn.boolValue = WifiNative.reassociateCommand();
- notifyOnMsgObject(message);
- } else {
- /* asynchronous handling */
- WifiNative.reassociateCommand();
- }
- break;
- case SCAN_RESULTS_EVENT:
- /* Set the scan setting back to "connect" mode */
- WifiNative.setScanResultHandlingCommand(CONNECT_MODE);
- /* Handle scan results */
- return NOT_HANDLED;
- case NETWORK_CONNECTION_EVENT:
- Log.d(TAG,"Network connection established");
- stateChangeResult = (StateChangeResult) message.obj;
-
- /* Remove any notifications */
- setNotificationVisible(false, 0, false, 0);
- resetNotificationTimer();
-
- mWifiInfo.setBSSID(mLastBssid = stateChangeResult.BSSID);
- mWifiInfo.setNetworkId(stateChangeResult.networkId);
- mLastNetworkId = stateChangeResult.networkId;
-
- /* send event to CM & network change broadcast */
- setDetailedState(DetailedState.OBTAINING_IPADDR);
- sendNetworkStateChangeBroadcast(mLastBssid);
-
- transitionTo(mConnectingState);
- break;
- case NETWORK_DISCONNECTION_EVENT:
- Log.d(TAG,"Network connection lost");
- handleNetworkDisconnect();
- transitionTo(mDisconnectedState);
- break;
- case CMD_GET_RSSI:
- syncParams = (SyncParams) message.obj;
- syncParams.mSyncReturn.intValue = WifiNative.getRssiCommand();
- notifyOnMsgObject(message);
- break;
- case CMD_GET_RSSI_APPROX:
- syncParams = (SyncParams) message.obj;
- syncParams.mSyncReturn.intValue = WifiNative.getRssiApproxCommand();
- notifyOnMsgObject(message);
- break;
- case CMD_GET_LINK_SPEED:
- syncParams = (SyncParams) message.obj;
- syncParams.mSyncReturn.intValue = WifiNative.getLinkSpeedCommand();
- notifyOnMsgObject(message);
- break;
- default:
- return NOT_HANDLED;
- }
- EventLog.writeEvent(EVENTLOG_WIFI_EVENT_HANDLED, message.what);
- return HANDLED;
- }
- }
-
- class ConnectingState extends HierarchicalState {
- boolean modifiedBluetoothCoexistenceMode;
- int powerMode;
- Thread mDhcpThread;
-
- @Override
- public void enter() {
- if (DBG) Log.d(TAG, getName() + "\n");
- EventLog.writeEvent(EVENTLOG_WIFI_STATE_CHANGED, getName());
-
- if (!mUseStaticIp) {
-
- mDhcpThread = null;
- modifiedBluetoothCoexistenceMode = false;
- powerMode = DRIVER_POWER_MODE_AUTO;
-
- if (shouldDisableCoexistenceMode()) {
- /*
- * There are problems setting the Wi-Fi driver's power
- * mode to active when bluetooth coexistence mode is
- * enabled or sense.
- * <p>
- * We set Wi-Fi to active mode when
- * obtaining an IP address because we've found
- * compatibility issues with some routers with low power
- * mode.
- * <p>
- * In order for this active power mode to properly be set,
- * we disable coexistence mode until we're done with
- * obtaining an IP address. One exception is if we
- * are currently connected to a headset, since disabling
- * coexistence would interrupt that connection.
- */
- modifiedBluetoothCoexistenceMode = true;
-
- // Disable the coexistence mode
- WifiNative.setBluetoothCoexistenceModeCommand(
- WifiNative.BLUETOOTH_COEXISTENCE_MODE_DISABLED);
- }
-
- powerMode = WifiNative.getPowerModeCommand();
- if (powerMode < 0) {
- // Handle the case where supplicant driver does not support
- // getPowerModeCommand.
- powerMode = DRIVER_POWER_MODE_AUTO;
- }
- if (powerMode != DRIVER_POWER_MODE_ACTIVE) {
- WifiNative.setPowerModeCommand(DRIVER_POWER_MODE_ACTIVE);
- }
-
- Log.d(TAG, "DHCP request started");
- mDhcpThread = new Thread(new Runnable() {
- public void run() {
- if (NetworkUtils.runDhcp(mInterfaceName, mDhcpInfo)) {
- Log.d(TAG, "DHCP request succeeded");
- sendMessage(CMD_IP_CONFIG_SUCCESS);
- } else {
- Log.d(TAG, "DHCP request failed: " +
- NetworkUtils.getDhcpError());
- sendMessage(CMD_IP_CONFIG_FAILURE);
- }
- }
- });
- mDhcpThread.start();
- } else {
- if (NetworkUtils.configureInterface(mInterfaceName, mDhcpInfo)) {
- Log.v(TAG, "Static IP configuration succeeded");
- sendMessage(CMD_IP_CONFIG_SUCCESS);
- } else {
- Log.v(TAG, "Static IP configuration failed");
- sendMessage(CMD_IP_CONFIG_FAILURE);
- }
- }
- }
- @Override
- public boolean processMessage(Message message) {
- if (DBG) Log.d(TAG, getName() + message.toString() + "\n");
-
- switch(message.what) {
- case CMD_IP_CONFIG_SUCCESS:
- mReconnectCount = 0;
- mLastSignalLevel = -1; // force update of signal strength
- mWifiInfo.setIpAddress(mDhcpInfo.ipAddress);
- Log.d(TAG, "IP configuration: " + mDhcpInfo);
- configureNetworkProperties();
- setDetailedState(DetailedState.CONNECTED);
- sendNetworkStateChangeBroadcast(mLastBssid);
- transitionTo(mConnectedState);
- break;
- case CMD_IP_CONFIG_FAILURE:
- mWifiInfo.setIpAddress(0);
-
- Log.e(TAG, "IP configuration failed");
- /**
- * If we've exceeded the maximum number of retries for DHCP
- * to a given network, disable the network
- */
- if (++mReconnectCount > getMaxDhcpRetries()) {
- Log.e(TAG, "Failed " +
- mReconnectCount + " times, Disabling " + mLastNetworkId);
- WifiNative.disableNetworkCommand(mLastNetworkId);
- }
-
- /* DHCP times out after about 30 seconds, we do a
- * disconnect and an immediate reconnect to try again
- */
- WifiNative.disconnectCommand();
- WifiNative.reconnectCommand();
- transitionTo(mDisconnectingState);
- break;
- case CMD_DISCONNECT:
- if (message.arg2 == SYNCHRONOUS_CALL) {
- SyncParams syncParams = (SyncParams) message.obj;
- syncParams.mSyncReturn.boolValue = WifiNative.disconnectCommand();
- notifyOnMsgObject(message);
- } else {
- /* asynchronous handling */
- WifiNative.disconnectCommand();
- }
- transitionTo(mDisconnectingState);
- break;
- /* Ignore */
- case NETWORK_CONNECTION_EVENT:
- break;
- case CMD_STOP_DRIVER:
- sendMessage(CMD_DISCONNECT);
- deferMessage(message);
- break;
- case CMD_SET_SCAN_MODE:
- if (message.arg1 == SCAN_ONLY_MODE) {
- sendMessage(CMD_DISCONNECT);
- deferMessage(message);
- }
- break;
- case CMD_RECONFIGURE_IP:
- deferMessage(message);
- break;
- default:
- return NOT_HANDLED;
- }
- EventLog.writeEvent(EVENTLOG_WIFI_EVENT_HANDLED, message.what);
- return HANDLED;
- }
-
- @Override
- public void exit() {
- /* reset power state & bluetooth coexistence if on DHCP */
- if (!mUseStaticIp) {
- if (powerMode != DRIVER_POWER_MODE_ACTIVE) {
- WifiNative.setPowerModeCommand(powerMode);
- }
-
- if (modifiedBluetoothCoexistenceMode) {
- // Set the coexistence mode back to its default value
- WifiNative.setBluetoothCoexistenceModeCommand(
- WifiNative.BLUETOOTH_COEXISTENCE_MODE_SENSE);
- }
- }
-
- }
- }
-
- class ConnectedState extends HierarchicalState {
- @Override
- public void enter() {
- if (DBG) Log.d(TAG, getName() + "\n");
- EventLog.writeEvent(EVENTLOG_WIFI_STATE_CHANGED, getName());
- }
- @Override
- public boolean processMessage(Message message) {
- if (DBG) Log.d(TAG, getName() + message.toString() + "\n");
- switch (message.what) {
- case CMD_DISCONNECT:
- if (message.arg2 == SYNCHRONOUS_CALL) {
- SyncParams syncParams = (SyncParams) message.obj;
- syncParams.mSyncReturn.boolValue = WifiNative.disconnectCommand();
- notifyOnMsgObject(message);
- } else {
- /* asynchronous handling */
- WifiNative.disconnectCommand();
- }
- transitionTo(mDisconnectingState);
- break;
- case CMD_RECONFIGURE_IP:
- Log.d(TAG,"Reconfiguring IP on connection");
- NetworkUtils.resetConnections(mInterfaceName);
- transitionTo(mConnectingState);
- break;
- case CMD_STOP_DRIVER:
- sendMessage(CMD_DISCONNECT);
- deferMessage(message);
- break;
- case CMD_SET_SCAN_MODE:
- if (message.arg1 == SCAN_ONLY_MODE) {
- sendMessage(CMD_DISCONNECT);
- deferMessage(message);
- }
- break;
- /* Ignore */
- case NETWORK_CONNECTION_EVENT:
- break;
- default:
- return NOT_HANDLED;
- }
- EventLog.writeEvent(EVENTLOG_WIFI_EVENT_HANDLED, message.what);
- return HANDLED;
- }
- }
-
- class DisconnectingState extends HierarchicalState {
- @Override
- public void enter() {
- if (DBG) Log.d(TAG, getName() + "\n");
- EventLog.writeEvent(EVENTLOG_WIFI_STATE_CHANGED, getName());
- }
- @Override
- public boolean processMessage(Message message) {
- if (DBG) Log.d(TAG, getName() + message.toString() + "\n");
- switch (message.what) {
- case CMD_STOP_DRIVER: /* Stop driver only after disconnect handled */
- deferMessage(message);
- break;
- case CMD_SET_SCAN_MODE:
- if (message.arg1 == SCAN_ONLY_MODE) {
- deferMessage(message);
- }
- break;
- default:
- return NOT_HANDLED;
- }
- EventLog.writeEvent(EVENTLOG_WIFI_EVENT_HANDLED, message.what);
- return HANDLED;
- }
- }
-
- class DisconnectedState extends HierarchicalState {
- @Override
- public void enter() {
- if (DBG) Log.d(TAG, getName() + "\n");
- EventLog.writeEvent(EVENTLOG_WIFI_STATE_CHANGED, getName());
- }
- @Override
- public boolean processMessage(Message message) {
- if (DBG) Log.d(TAG, getName() + message.toString() + "\n");
- switch (message.what) {
- case CMD_SET_SCAN_MODE:
- if (message.arg1 == SCAN_ONLY_MODE) {
- WifiNative.setScanResultHandlingCommand(message.arg1);
- //Supplicant disconnect to prevent further connects
- WifiNative.disconnectCommand();
- mIsScanMode = true;
- transitionTo(mScanModeState);
- }
- break;
- /* Ignore network disconnect */
- case NETWORK_DISCONNECTION_EVENT:
- break;
- default:
- return NOT_HANDLED;
- }
- EventLog.writeEvent(EVENTLOG_WIFI_EVENT_HANDLED, message.what);
- return HANDLED;
- }
- }
-
- class SoftApStartedState extends HierarchicalState {
- @Override
- public void enter() {
- if (DBG) Log.d(TAG, getName() + "\n");
- EventLog.writeEvent(EVENTLOG_WIFI_STATE_CHANGED, getName());
- }
- @Override
- public boolean processMessage(Message message) {
- if (DBG) Log.d(TAG, getName() + message.toString() + "\n");
- switch(message.what) {
- case CMD_STOP_AP:
- Log.d(TAG,"Stopping Soft AP");
- setWifiApState(WIFI_AP_STATE_DISABLING);
- try {
- nwService.stopAccessPoint();
- } catch(Exception e) {
- Log.e(TAG, "Exception in stopAccessPoint()");
- }
- transitionTo(mDriverLoadedState);
- break;
- case CMD_START_AP:
- Log.d(TAG,"SoftAP set on a running access point");
- try {
- nwService.setAccessPoint((WifiConfiguration) message.obj,
- mInterfaceName,
- SOFTAP_IFACE);
- } catch(Exception e) {
- Log.e(TAG, "Exception in nwService during soft AP set");
- try {
- nwService.stopAccessPoint();
- } catch (Exception ee) {
- Slog.e(TAG, "Could not stop AP, :" + ee);
- }
- sendMessage(obtainMessage(CMD_UNLOAD_DRIVER, WIFI_AP_STATE_FAILED, 0));
- }
- break;
- /* Fail client mode operation when soft AP is enabled */
- case CMD_START_SUPPLICANT:
- Log.e(TAG,"Cannot start supplicant with a running soft AP");
- setWifiState(WIFI_STATE_UNKNOWN);
- break;
- default:
- return NOT_HANDLED;
- }
- EventLog.writeEvent(EVENTLOG_WIFI_EVENT_HANDLED, message.what);
- return HANDLED;
- }
- }
-
-
- class SupplicantStateTracker extends HierarchicalStateMachine {
-
- private int mRssiPollToken = 0;
-
- /**
- * The max number of the WPA supplicant loop iterations before we
- * decide that the loop should be terminated:
- */
- private static final int MAX_SUPPLICANT_LOOP_ITERATIONS = 4;
- private int mLoopDetectIndex = 0;
- private int mLoopDetectCount = 0;
-
- /**
- * Supplicant state change commands follow
- * the ordinal values defined in SupplicantState.java
- */
- private static final int DISCONNECTED = 0;
- private static final int INACTIVE = 1;
- private static final int SCANNING = 2;
- private static final int ASSOCIATING = 3;
- private static final int ASSOCIATED = 4;
- private static final int FOUR_WAY_HANDSHAKE = 5;
- private static final int GROUP_HANDSHAKE = 6;
- private static final int COMPLETED = 7;
- private static final int DORMANT = 8;
- private static final int UNINITIALIZED = 9;
- private static final int INVALID = 10;
-
- private HierarchicalState mUninitializedState;
- private HierarchicalState mInitializedState;
- private HierarchicalState mInactiveState;
- private HierarchicalState mDisconnectState;
- private HierarchicalState mScanState;
- private HierarchicalState mConnectState;
- private HierarchicalState mHandshakeState;
- private HierarchicalState mCompletedState;
- private HierarchicalState mDormantState;
-
-
- public SupplicantStateTracker(Context context, Handler target) {
- super(TAG, target.getLooper());
-
- mUninitializedState = new UninitializedState();
- mInitializedState = new InitializedState();
- mInactiveState = new InactiveState();
- mDisconnectState = new DisconnectedState();
- mScanState = new ScanState();
- mConnectState = new ConnectState();
- mHandshakeState = new HandshakeState();
- mCompletedState = new CompletedState();
- mDormantState = new DormantState();
-
-
- addState(mUninitializedState);
- addState(mInitializedState);
- addState(mInactiveState, mInitializedState);
- addState(mDisconnectState, mInitializedState);
- addState(mScanState, mInitializedState);
- addState(mConnectState, mInitializedState);
- addState(mHandshakeState, mConnectState);
- addState(mCompletedState, mConnectState);
- addState(mDormantState, mInitializedState);
-
- setInitialState(mUninitializedState);
-
- //start the state machine
- start();
- }
-
- public void handleEvent(StateChangeResult stateChangeResult) {
- SupplicantState newState = (SupplicantState) stateChangeResult.state;
-
- // Supplicant state change
- // [31-13] Reserved for future use
- // [8 - 0] Supplicant state (as defined in SupplicantState.java)
- // 50023 supplicant_state_changed (custom|1|5)
- EventLog.writeEvent(EVENTLOG_SUPPLICANT_STATE_CHANGED, newState.ordinal());
-
- sendMessage(obtainMessage(newState.ordinal(), stateChangeResult));
- }
-
- public void resetSupplicantState() {
- transitionTo(mUninitializedState);
- }
-
- private void resetLoopDetection() {
- mLoopDetectCount = 0;
- mLoopDetectIndex = 0;
- }
-
- private boolean handleTransition(Message msg) {
- if (DBG) Log.d(TAG, getName() + msg.toString() + "\n");
- switch (msg.what) {
- case DISCONNECTED:
- transitionTo(mDisconnectState);
- break;
- case SCANNING:
- transitionTo(mScanState);
- break;
- case ASSOCIATING:
- StateChangeResult stateChangeResult = (StateChangeResult) msg.obj;
- /* BSSID is valid only in ASSOCIATING state */
- mWifiInfo.setBSSID(stateChangeResult.BSSID);
- //$FALL-THROUGH$
- case ASSOCIATED:
- case FOUR_WAY_HANDSHAKE:
- case GROUP_HANDSHAKE:
- transitionTo(mHandshakeState);
- break;
- case COMPLETED:
- transitionTo(mCompletedState);
- break;
- case DORMANT:
- transitionTo(mDormantState);
- break;
- case INACTIVE:
- transitionTo(mInactiveState);
- break;
- case UNINITIALIZED:
- case INVALID:
- transitionTo(mUninitializedState);
- break;
- default:
- return NOT_HANDLED;
- }
- StateChangeResult stateChangeResult = (StateChangeResult) msg.obj;
- SupplicantState supState = (SupplicantState) stateChangeResult.state;
- setDetailedState(WifiInfo.getDetailedStateOf(supState));
- mWifiInfo.setSupplicantState(supState);
- mWifiInfo.setNetworkId(stateChangeResult.networkId);
- //TODO: Modify WifiMonitor to report SSID on events
- //mWifiInfo.setSSID()
- return HANDLED;
- }
-
- /********************************************************
- * HSM states
- *******************************************************/
-
- class InitializedState extends HierarchicalState {
- @Override
- public void enter() {
- if (DBG) Log.d(TAG, getName() + "\n");
- }
- @Override
- public boolean processMessage(Message message) {
- if (DBG) Log.d(TAG, getName() + message.toString() + "\n");
- switch (message.what) {
- case CMD_START_SCAN:
- WifiNative.scanCommand(message.arg1 == SCAN_ACTIVE);
- break;
- default:
- if (DBG) Log.w(TAG, "Ignoring " + message);
- break;
- }
- return HANDLED;
- }
- }
-
- class UninitializedState extends HierarchicalState {
- @Override
- public void enter() {
- if (DBG) Log.d(TAG, getName() + "\n");
- mNetworkInfo.setIsAvailable(false);
- resetLoopDetection();
- mPasswordKeyMayBeIncorrect = false;
- }
- @Override
- public boolean processMessage(Message message) {
- switch(message.what) {
- default:
- if (!handleTransition(message)) {
- if (DBG) Log.w(TAG, "Ignoring " + message);
- }
- break;
- }
- return HANDLED;
- }
- }
-
- class InactiveState extends HierarchicalState {
- @Override
- public void enter() {
- if (DBG) Log.d(TAG, getName() + "\n");
- Message message = getCurrentMessage();
- StateChangeResult stateChangeResult = (StateChangeResult) message.obj;
-
- mNetworkInfo.setIsAvailable(false);
- resetLoopDetection();
- mPasswordKeyMayBeIncorrect = false;
-
- sendSupplicantStateChangedBroadcast(stateChangeResult, false);
- }
- @Override
- public boolean processMessage(Message message) {
- return handleTransition(message);
- }
- }
-
-
- class DisconnectedState extends HierarchicalState {
- @Override
- public void enter() {
- if (DBG) Log.d(TAG, getName() + "\n");
- Message message = getCurrentMessage();
- StateChangeResult stateChangeResult = (StateChangeResult) message.obj;
-
- mNetworkInfo.setIsAvailable(true);
- resetLoopDetection();
-
- /* If a disconnect event happens after a password key failure
- * event, disable the network
- */
- if (mPasswordKeyMayBeIncorrect) {
- Log.d(TAG, "Failed to authenticate, disabling network " +
- mWifiInfo.getNetworkId());
- WifiNative.disableNetworkCommand(mWifiInfo.getNetworkId());
- mPasswordKeyMayBeIncorrect = false;
- sendSupplicantStateChangedBroadcast(stateChangeResult, true);
- }
- else {
- sendSupplicantStateChangedBroadcast(stateChangeResult, false);
- }
- }
- @Override
- public boolean processMessage(Message message) {
- return handleTransition(message);
- }
- }
-
- class ScanState extends HierarchicalState {
- @Override
- public void enter() {
- if (DBG) Log.d(TAG, getName() + "\n");
- Message message = getCurrentMessage();
- StateChangeResult stateChangeResult = (StateChangeResult) message.obj;
-
- mNetworkInfo.setIsAvailable(true);
- mPasswordKeyMayBeIncorrect = false;
- resetLoopDetection();
- sendSupplicantStateChangedBroadcast(stateChangeResult, false);
- }
- @Override
- public boolean processMessage(Message message) {
- return handleTransition(message);
- }
- }
-
- class ConnectState extends HierarchicalState {
- @Override
- public void enter() {
- if (DBG) Log.d(TAG, getName() + "\n");
- }
- @Override
- public boolean processMessage(Message message) {
- switch (message.what) {
- case CMD_START_SCAN:
- WifiNative.setScanResultHandlingCommand(SCAN_ONLY_MODE);
- WifiNative.scanCommand(message.arg1 == SCAN_ACTIVE);
- break;
- default:
- return NOT_HANDLED;
- }
- return HANDLED;
- }
- }
-
- class HandshakeState extends HierarchicalState {
- @Override
- public void enter() {
- if (DBG) Log.d(TAG, getName() + "\n");
- final Message message = getCurrentMessage();
- StateChangeResult stateChangeResult = (StateChangeResult) message.obj;
-
- mNetworkInfo.setIsAvailable(true);
-
- if (mLoopDetectIndex > message.what) {
- mLoopDetectCount++;
- }
- if (mLoopDetectCount > MAX_SUPPLICANT_LOOP_ITERATIONS) {
- WifiNative.disableNetworkCommand(stateChangeResult.networkId);
- mLoopDetectCount = 0;
- }
-
- mLoopDetectIndex = message.what;
-
- mPasswordKeyMayBeIncorrect = false;
- sendSupplicantStateChangedBroadcast(stateChangeResult, false);
- }
- @Override
- public boolean processMessage(Message message) {
- return handleTransition(message);
- }
- }
-
- class CompletedState extends HierarchicalState {
- @Override
- public void enter() {
- if (DBG) Log.d(TAG, getName() + "\n");
- Message message = getCurrentMessage();
- StateChangeResult stateChangeResult = (StateChangeResult) message.obj;
-
- mNetworkInfo.setIsAvailable(true);
-
- mRssiPollToken++;
- if (mEnableRssiPolling) {
- sendMessageDelayed(obtainMessage(CMD_RSSI_POLL, mRssiPollToken, 0),
- POLL_RSSI_INTERVAL_MSECS);
- }
-
- resetLoopDetection();
-
- mPasswordKeyMayBeIncorrect = false;
- sendSupplicantStateChangedBroadcast(stateChangeResult, false);
- }
- @Override
- public boolean processMessage(Message message) {
- switch(message.what) {
- case ASSOCIATING:
- case ASSOCIATED:
- case FOUR_WAY_HANDSHAKE:
- case GROUP_HANDSHAKE:
- case COMPLETED:
- break;
- case CMD_RSSI_POLL:
- if (message.arg1 == mRssiPollToken) {
- // Get Info and continue polling
- requestPolledInfo();
- sendMessageDelayed(obtainMessage(CMD_RSSI_POLL, mRssiPollToken, 0),
- POLL_RSSI_INTERVAL_MSECS);
- } else {
- // Polling has completed
- }
- break;
- case CMD_ENABLE_RSSI_POLL:
- mRssiPollToken++;
- if (mEnableRssiPolling) {
- // first poll
- requestPolledInfo();
- sendMessageDelayed(obtainMessage(CMD_RSSI_POLL, mRssiPollToken, 0),
- POLL_RSSI_INTERVAL_MSECS);
- }
- break;
- default:
- return handleTransition(message);
- }
- return HANDLED;
- }
- }
-
- class DormantState extends HierarchicalState {
- @Override
- public void enter() {
- if (DBG) Log.d(TAG, getName() + "\n");
- Message message = getCurrentMessage();
- StateChangeResult stateChangeResult = (StateChangeResult) message.obj;
-
- mNetworkInfo.setIsAvailable(true);
- resetLoopDetection();
- mPasswordKeyMayBeIncorrect = false;
-
- sendSupplicantStateChangedBroadcast(stateChangeResult, false);
-
- /* TODO: reconnect is now being handled at DHCP failure handling
- * If we run into issues with staying in Dormant state, might
- * need a reconnect here
- */
- }
- @Override
- public boolean processMessage(Message message) {
- return handleTransition(message);
- }
- }
- }
-
- private class NotificationEnabledSettingObserver extends ContentObserver {
-
- public NotificationEnabledSettingObserver(Handler handler) {
- super(handler);
- }
-
- public void register() {
- ContentResolver cr = mContext.getContentResolver();
- cr.registerContentObserver(Settings.Secure.getUriFor(
- Settings.Secure.WIFI_NETWORKS_AVAILABLE_NOTIFICATION_ON), true, this);
- mNotificationEnabled = getValue();
- }
-
- @Override
- public void onChange(boolean selfChange) {
- super.onChange(selfChange);
-
- mNotificationEnabled = getValue();
- if (!mNotificationEnabled) {
- // Remove any notification that may be showing
- setNotificationVisible(false, 0, true, 0);
- }
-
- resetNotificationTimer();
- }
-
- private boolean getValue() {
- return Settings.Secure.getInt(mContext.getContentResolver(),
- Settings.Secure.WIFI_NETWORKS_AVAILABLE_NOTIFICATION_ON, 1) == 1;
- }
- }
-}
+} \ No newline at end of file