From c113e39dfeac7f80fd3e1342292839fcf74a919e Mon Sep 17 00:00:00 2001 From: Robert Horvath Date: Thu, 12 Mar 2020 15:32:24 +0100 Subject: Move TvSystem to /frameworks/opt/tv/tvsystem Bug: 151291114 Test: m com.android.libraries.tv.tvsystem Change-Id: I9c2a8670fe96bd466613b7196632c73b38420662 --- Android.bp | 27 +++ api/current.txt | 29 +++ api/removed.txt | 1 + api/system-current.txt | 28 +++ api/system-removed.txt | 1 + api/test-current.txt | 1 + api/test-removed.txt | 1 + .../tv/tvsystem/display/DeviceProductInfo.java | 154 ++++++++++++++ .../tv/tvsystem/display/DisplayCompatUtil.java | 67 ++++++ .../tv/tvsystem/display/WindowCompatUtil.java | 38 ++++ .../tv/tvsystem/wifi/SoftApConfiguration.java | 236 +++++++++++++++++++++ .../libraries/tv/tvsystem/wifi/TvWifiManager.java | 73 +++++++ 12 files changed, 656 insertions(+) create mode 100644 Android.bp create mode 100644 api/current.txt create mode 100644 api/removed.txt create mode 100644 api/system-current.txt create mode 100644 api/system-removed.txt create mode 100644 api/test-current.txt create mode 100644 api/test-removed.txt create mode 100644 java/com/android/libraries/tv/tvsystem/display/DeviceProductInfo.java create mode 100644 java/com/android/libraries/tv/tvsystem/display/DisplayCompatUtil.java create mode 100644 java/com/android/libraries/tv/tvsystem/display/WindowCompatUtil.java create mode 100644 java/com/android/libraries/tv/tvsystem/wifi/SoftApConfiguration.java create mode 100644 java/com/android/libraries/tv/tvsystem/wifi/TvWifiManager.java diff --git a/Android.bp b/Android.bp new file mode 100644 index 0000000..f1c2c84 --- /dev/null +++ b/Android.bp @@ -0,0 +1,27 @@ +// Copyright (C) 2020 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. + +java_sdk_library { + name: "com.android.libraries.tv.tvsystem", + srcs: ["java/**/*.java"], + api_packages: [ + "com.android.libraries.tv.tvsystem", + "com.android.libraries.tv.tvsystem.display", + "com.android.libraries.tv.tvsystem.wifi" + ], + dex_preopt: { + enabled: false, + } +} + diff --git a/api/current.txt b/api/current.txt new file mode 100644 index 0000000..fa68a6a --- /dev/null +++ b/api/current.txt @@ -0,0 +1,29 @@ +// Signature format: 2.0 +package com.android.libraries.tv.tvsystem.display { + + public final class DeviceProductInfo { + ctor public DeviceProductInfo(String, String, String, Integer, com.android.libraries.tv.tvsystem.display.DeviceProductInfo.ManufactureDate); + method public com.android.libraries.tv.tvsystem.display.DeviceProductInfo.ManufactureDate getManufactureDate(); + method public String getManufacturerPnpId(); + method public Integer getModelYear(); + method public String getName(); + method public String getProductId(); + } + + public static class DeviceProductInfo.ManufactureDate { + ctor public DeviceProductInfo.ManufactureDate(Integer, Integer); + method public Integer getWeek(); + method public Integer getYear(); + } + + public final class DisplayCompatUtil { + method public static com.android.libraries.tv.tvsystem.display.DeviceProductInfo getDeviceProductInfo(android.view.Display); + method public static boolean isMinimalPostProcessingSupported(android.view.Display); + } + + public final class WindowCompatUtil { + method public static void setPreferMinimalPostProcessing(android.view.Window, boolean); + } + +} + diff --git a/api/removed.txt b/api/removed.txt new file mode 100644 index 0000000..d802177 --- /dev/null +++ b/api/removed.txt @@ -0,0 +1 @@ +// Signature format: 2.0 diff --git a/api/system-current.txt b/api/system-current.txt new file mode 100644 index 0000000..aa0d1db --- /dev/null +++ b/api/system-current.txt @@ -0,0 +1,28 @@ +// Signature format: 2.0 +package com.android.libraries.tv.tvsystem.wifi { + + public final class SoftApConfiguration implements android.os.Parcelable { + method public int describeContents(); + method @Nullable public android.net.MacAddress getBssid(); + method @Nullable public String getSsid(); + method @Nullable public String getWpa2Passphrase(); + method public void writeToParcel(@NonNull android.os.Parcel, int); + field @NonNull public static final android.os.Parcelable.Creator CREATOR; + } + + public static final class SoftApConfiguration.Builder { + ctor public SoftApConfiguration.Builder(); + ctor public SoftApConfiguration.Builder(@NonNull com.android.libraries.tv.tvsystem.wifi.SoftApConfiguration); + method @NonNull public com.android.libraries.tv.tvsystem.wifi.SoftApConfiguration build(); + method @NonNull public com.android.libraries.tv.tvsystem.wifi.SoftApConfiguration.Builder setBssid(@Nullable android.net.MacAddress); + method @NonNull public com.android.libraries.tv.tvsystem.wifi.SoftApConfiguration.Builder setSsid(@Nullable String); + method @NonNull public com.android.libraries.tv.tvsystem.wifi.SoftApConfiguration.Builder setWpa2Passphrase(@Nullable String); + } + + public final class TvWifiManager { + ctor public TvWifiManager(@NonNull android.content.Context); + method @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.NETWORK_SETUP_WIZARD}) public void startLocalOnlyHotspot(@NonNull com.android.libraries.tv.tvsystem.wifi.SoftApConfiguration, @Nullable java.util.concurrent.Executor, @Nullable android.net.wifi.WifiManager.LocalOnlyHotspotCallback); + } + +} + diff --git a/api/system-removed.txt b/api/system-removed.txt new file mode 100644 index 0000000..d802177 --- /dev/null +++ b/api/system-removed.txt @@ -0,0 +1 @@ +// Signature format: 2.0 diff --git a/api/test-current.txt b/api/test-current.txt new file mode 100644 index 0000000..d802177 --- /dev/null +++ b/api/test-current.txt @@ -0,0 +1 @@ +// Signature format: 2.0 diff --git a/api/test-removed.txt b/api/test-removed.txt new file mode 100644 index 0000000..d802177 --- /dev/null +++ b/api/test-removed.txt @@ -0,0 +1 @@ +// Signature format: 2.0 diff --git a/java/com/android/libraries/tv/tvsystem/display/DeviceProductInfo.java b/java/com/android/libraries/tv/tvsystem/display/DeviceProductInfo.java new file mode 100644 index 0000000..7d9a120 --- /dev/null +++ b/java/com/android/libraries/tv/tvsystem/display/DeviceProductInfo.java @@ -0,0 +1,154 @@ +/* + * Copyright (C) 2020 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.libraries.tv.tvsystem.display; + +import java.util.Objects; + +/** + * Product-specific information about the display or the directly connected device on the + * display chain. For example, if the display is transitively connected, this field may contain + * product information about the intermediate device. + */ +public final class DeviceProductInfo { + private final String mName; + private final String mManufacturerPnpId; + private final String mProductId; + private final Integer mModelYear; + private final ManufactureDate mManufactureDate; + + public DeviceProductInfo( + String name, + String manufacturerPnpId, + String productId, + Integer modelYear, + ManufactureDate manufactureDate) { + this.mName = name; + this.mManufacturerPnpId = manufacturerPnpId; + this.mProductId = productId; + this.mModelYear = modelYear; + this.mManufactureDate = manufactureDate; + } + + /** + * @return Display name. + */ + public String getName() { + return mName; + } + + /** + * @return Manufacturer Plug and Play ID. + */ + public String getManufacturerPnpId() { + return mManufacturerPnpId; + } + + /** + * @return Manufacturer product ID. + */ + public String getProductId() { + return mProductId; + } + + /** + * @return Model year of the device. Typically exactly one of model year or + * manufacture date will be present. + */ + public Integer getModelYear() { + return mModelYear; + } + + /** + * @return Manufacture date. Typically exactly one of model year or manufacture + * date will be present. + */ + public ManufactureDate getManufactureDate() { + return mManufactureDate; + } + + @Override + public String toString() { + return "DeviceProductInfo{" + + "name=" + + mName + + ", manufacturerPnpId=" + + mManufacturerPnpId + + ", productId=" + + mProductId + + ", modelYear=" + + mModelYear + + ", manufactureDate=" + + mManufactureDate + + '}'; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + DeviceProductInfo that = (DeviceProductInfo) o; + return Objects.equals(mName, that.mName) + && Objects.equals(mManufacturerPnpId, that.mManufacturerPnpId) + && Objects.equals(mProductId, that.mProductId) + && Objects.equals(mModelYear, that.mModelYear) + && Objects.equals(mManufactureDate, that.mManufactureDate); + } + + @Override + public int hashCode() { + return Objects.hash(mName, mManufacturerPnpId, mProductId, mModelYear, mManufactureDate); + } + + /** + * Stores information about the date of manufacture. + */ + public static class ManufactureDate { + private final Integer mWeek; + private final Integer mYear; + + public ManufactureDate(Integer week, Integer year) { + mWeek = week; + mYear = year; + } + + public Integer getYear() { + return mYear; + } + + public Integer getWeek() { + return mWeek; + } + + @Override + public String toString() { + return "ManufactureDate{week=" + mWeek + ", year=" + mYear + '}'; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + ManufactureDate that = (ManufactureDate) o; + return Objects.equals(mWeek, that.mWeek) && Objects.equals(mYear, that.mYear); + } + + @Override + public int hashCode() { + return Objects.hash(mWeek, mYear); + } + } +} \ No newline at end of file diff --git a/java/com/android/libraries/tv/tvsystem/display/DisplayCompatUtil.java b/java/com/android/libraries/tv/tvsystem/display/DisplayCompatUtil.java new file mode 100644 index 0000000..4b8da67 --- /dev/null +++ b/java/com/android/libraries/tv/tvsystem/display/DisplayCompatUtil.java @@ -0,0 +1,67 @@ +/* + * Copyright (C) 2020 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.libraries.tv.tvsystem.display; + +import android.view.Display; +import android.view.DisplayInfo; + +public final class DisplayCompatUtil { + + /** + *

Returns true if the connected display can be switched into a mode with minimal + * post processing.

+ * + *

If the Display sink is connected via HDMI, this method will return true if the + * display supports either Auto Low Latency Mode or Game Content Type. + * + *

If the Display sink has an internal connection or uses some other protocol than + * HDMI, this method will return true if the sink can be switched into an + * implementation-defined low latency image processing mode.

+ * + *

The ability to switch to a mode with minimal post processing may be disabled + * by a user setting in the system settings menu. In that case, this method returns + * false.

+ * + * @see Display#isMinimalPostProcessingSupported + * @see WindowCompatUtil#setPreferMinimalPostProcessing + */ + public static boolean isMinimalPostProcessingSupported(Display display) { + return display.isMinimalPostProcessingSupported(); + } + + /** + *

Returns product-specific information about the display or the directly connected device + * on the display chain. For example, if the display is transitively connected, this field may + * contain product information about the intermediate device.

+ */ + public static DeviceProductInfo getDeviceProductInfo(Display display) { + DisplayInfo displayInfo = new DisplayInfo(); + display.getDisplayInfo(displayInfo); + android.hardware.display.DeviceProductInfo info = displayInfo.deviceProductInfo; + DeviceProductInfo.ManufactureDate manufactureDate; + if (info.getManufactureDate() == null) { + manufactureDate = null; + } else { + manufactureDate = new DeviceProductInfo.ManufactureDate( + info.getManufactureDate().getWeek(), info.getManufactureDate().getYear()); + } + return new DeviceProductInfo(info.getName(), info.getManufacturerPnpId(), + info.getProductId(), info.getModelYear(), manufactureDate); + } + + private DisplayCompatUtil() {} +} diff --git a/java/com/android/libraries/tv/tvsystem/display/WindowCompatUtil.java b/java/com/android/libraries/tv/tvsystem/display/WindowCompatUtil.java new file mode 100644 index 0000000..4a0fed9 --- /dev/null +++ b/java/com/android/libraries/tv/tvsystem/display/WindowCompatUtil.java @@ -0,0 +1,38 @@ +/* + * Copyright (C) 2020 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.libraries.tv.tvsystem.display; + +import android.view.Window; + +public final class WindowCompatUtil { + + /** + * Specify whether this Window should request the Display it's presented on to switch to the + * minimal post-processing mode, if the Display supports such mode. + * Usually minimal post-processing is backed by HDMI ContentType="game" and HDMI Auto + * Low-Latency Mode. However, different manufacturers may have their own implementations of + * similar features. + * + * @see Window#setPreferMinimalPostProcessing + * @see DisplayCompatUtil#isMinimalPostProcessingSupported + */ + public static void setPreferMinimalPostProcessing(Window window, boolean isPreferred) { + window.setPreferMinimalPostProcessing(isPreferred); + } + + private WindowCompatUtil() {} +} diff --git a/java/com/android/libraries/tv/tvsystem/wifi/SoftApConfiguration.java b/java/com/android/libraries/tv/tvsystem/wifi/SoftApConfiguration.java new file mode 100644 index 0000000..a467965 --- /dev/null +++ b/java/com/android/libraries/tv/tvsystem/wifi/SoftApConfiguration.java @@ -0,0 +1,236 @@ +/* + * Copyright (C) 2020 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.libraries.tv.tvsystem.wifi; + +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.annotation.SystemApi; +import android.net.MacAddress; +import android.net.wifi.WifiConfiguration; +import android.net.wifi.WifiManager; +import android.os.Parcel; +import android.os.Parcelable; + +import com.android.internal.util.Preconditions; + +import java.nio.charset.StandardCharsets; +import java.util.Objects; +import java.util.concurrent.Executor; + +/** + * WiFi configuration for a soft access point (a.k.a. Soft AP, SAP, Hotspot). + * + * This is input for the framework provided by a client app, i.e. it exposes knobs to instruct the + * framework how it should open a hotspot. It is not meant to describe the network as it will be + * seen by clients; this role is currently served by {@link WifiConfiguration} (see + * {@link WifiManager.LocalOnlyHotspotReservation#getWifiConfiguration()}). + * + * Apps can use this to configure a local-only hotspot using + * {@link TvWifiManager#startLocalOnlyHotspot(SoftApConfiguration, Executor, + * WifiManager.LocalOnlyHotspotCallback)}. + * + * Instances of this class are immutable; use {@link SoftApConfiguration.Builder} and its methods to + * create a new instance. + * + * @hide + */ +@SystemApi +public final class SoftApConfiguration implements Parcelable { + /** + * SSID for the AP, or null for a framework-determined SSID. + */ + private final @Nullable + String mSsid; + /** + * BSSID for the AP, or null to use a framework-determined BSSID. + */ + private final @Nullable + MacAddress mBssid; + /** + * Pre-shared key for WPA2-PSK encryption (non-null enables WPA2-PSK). + */ + private final @Nullable + String mWpa2Passphrase; + + /** Private constructor for Builder and Parcelable implementation. */ + private SoftApConfiguration( + @Nullable String ssid, @Nullable MacAddress bssid, String wpa2Passphrase) { + mSsid = ssid; + mBssid = bssid; + mWpa2Passphrase = wpa2Passphrase; + } + + @Override + public boolean equals(Object otherObj) { + if (this == otherObj) { + return true; + } + if (!(otherObj instanceof SoftApConfiguration)) { + return false; + } + SoftApConfiguration other = (SoftApConfiguration) otherObj; + return Objects.equals(mSsid, other.mSsid) + && Objects.equals(mBssid, other.mBssid) + && Objects.equals(mWpa2Passphrase, other.mWpa2Passphrase); + } + + @Override + public int hashCode() { + return Objects.hash(mSsid, mBssid, mWpa2Passphrase); + } + + @Override + public void writeToParcel(@NonNull Parcel dest, int flags) { + dest.writeString(mSsid); + dest.writeParcelable(mBssid, flags); + dest.writeString(mWpa2Passphrase); + } + + @Override + public int describeContents() { + return 0; + } + + @NonNull + public static final Creator CREATOR = new Creator() { + @Override + public SoftApConfiguration createFromParcel(Parcel in) { + return new SoftApConfiguration( + in.readString(), + in.readParcelable(MacAddress.class.getClassLoader()), + in.readString()); + } + + @Override + public SoftApConfiguration[] newArray(int size) { + return new SoftApConfiguration[size]; + } + }; + + @Nullable + public String getSsid() { + return mSsid; + } + + @Nullable + public MacAddress getBssid() { + return mBssid; + } + + @Nullable + public String getWpa2Passphrase() { + return mWpa2Passphrase; + } + + /** + * Builds a {@link SoftApConfiguration}, which allows an app to configure various aspects of a + * Soft AP. + * + * All fields are optional. By default, SSID and BSSID are automatically chosen by the + * framework, and an open network is created. + */ + public static final class Builder { + private String mSsid; + private MacAddress mBssid; + private String mWpa2Passphrase; + + /** + * Constructs a Builder with default values (see {@link Builder}). + */ + public Builder() { + mSsid = null; + mBssid = null; + mWpa2Passphrase = null; + } + + /** + * Constructs a Builder initialized from an existing {@link SoftApConfiguration} instance. + */ + public Builder(@NonNull SoftApConfiguration other) { + Objects.requireNonNull(other); + + mSsid = other.mSsid; + mBssid = other.mBssid; + mWpa2Passphrase = other.mWpa2Passphrase; + } + + /** + * Builds the {@link SoftApConfiguration}. + * + * @return A new {@link SoftApConfiguration}, as configured by previous method calls. + */ + @NonNull + public SoftApConfiguration build() { + return new SoftApConfiguration(mSsid, mBssid, mWpa2Passphrase); + } + + /** + * Specifies an SSID for the AP. + * + * @param ssid SSID of valid Unicode characters, or null to have the SSID automatically + * chosen by the framework. + * @return Builder for chaining. + * @throws IllegalArgumentException when the SSID is empty or not valid Unicode. + */ + @NonNull + public Builder setSsid(@Nullable String ssid) { + if (ssid != null) { + Preconditions.checkStringNotEmpty(ssid); + Preconditions.checkArgument(StandardCharsets.UTF_8.newEncoder().canEncode(ssid)); + } + mSsid = ssid; + return this; + } + + /** + * Specifies a BSSID for the AP. + * + * @param bssid BSSID, or null to have the BSSID chosen by the framework. The caller is + * responsible for avoiding collisions. + * @return Builder for chaining. + * @throws IllegalArgumentException when the given BSSID is the all-zero or broadcast MAC + * address. + */ + @NonNull + public Builder setBssid(@Nullable MacAddress bssid) { + if (bssid != null) { + Preconditions.checkArgument(!bssid.equals(MacAddress.ALL_ZEROS_ADDRESS)); + Preconditions.checkArgument(!bssid.equals(MacAddress.BROADCAST_ADDRESS)); + } + mBssid = bssid; + return this; + } + + /** + * Specifies that this AP should use WPA2-PSK with the given passphrase. When set to null + * and no other encryption method is configured, an open network is created. + * + * @param passphrase The passphrase to use, or null to unset a previously-set WPA2-PSK + * configuration. + * @return Builder for chaining. + * @throws IllegalArgumentException when the passphrase is the empty string + */ + @NonNull + public Builder setWpa2Passphrase(@Nullable String passphrase) { + if (passphrase != null) { + Preconditions.checkStringNotEmpty(passphrase); + } + mWpa2Passphrase = passphrase; + return this; + } + } +} diff --git a/java/com/android/libraries/tv/tvsystem/wifi/TvWifiManager.java b/java/com/android/libraries/tv/tvsystem/wifi/TvWifiManager.java new file mode 100644 index 0000000..2457584 --- /dev/null +++ b/java/com/android/libraries/tv/tvsystem/wifi/TvWifiManager.java @@ -0,0 +1,73 @@ +/* + * Copyright (C) 2020 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.libraries.tv.tvsystem.wifi; + +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.annotation.RequiresPermission; +import android.annotation.SystemApi; +import android.content.Context; +import android.net.wifi.WifiManager; +import android.os.Handler; + +import java.util.concurrent.Executor; + +/** + * Provides access to APIs in {@link WifiManager} that are otherwise @hidden. + * + * @hide + */ +@SystemApi +public final class TvWifiManager { + private final WifiManager mWifiManager; + + public TvWifiManager(@NonNull Context context) { + mWifiManager = context.getSystemService(WifiManager.class); + } + + /** + * Starts a local-only hotspot with a specific configuration applied. See + * {@link WifiManager#startLocalOnlyHotspot(WifiManager.LocalOnlyHotspotCallback, Handler)}. + * + * Applications need either {@link android.Manifest.permission#NETWORK_SETUP_WIZARD} or + * {@link android.Manifest.permission#NETWORK_SETTINGS} to call this method. + * + * Since custom configuration settings may be incompatible with each other, the hotspot started + * through this method cannot coexist with another hotspot created through + * startLocalOnlyHotspot. If this is attempted, the first hotspot request wins and others + * receive {@link WifiManager.LocalOnlyHotspotCallback#ERROR_GENERIC} through + * {@link WifiManager.LocalOnlyHotspotCallback#onFailed}. + * + * @param config Custom configuration for the hotspot. See {@link SoftApConfiguration}. + * @param executor Executor to run callback methods on, or null to use the main thread. + * @param callback Callback object for updates about hotspot status, or null for no updates. + */ + @RequiresPermission(anyOf = { + android.Manifest.permission.NETWORK_SETTINGS, + android.Manifest.permission.NETWORK_SETUP_WIZARD}) + public void startLocalOnlyHotspot(@NonNull SoftApConfiguration config, + @Nullable Executor executor, + @Nullable WifiManager.LocalOnlyHotspotCallback callback) { + android.net.wifi.SoftApConfiguration frameworkConfig = + new android.net.wifi.SoftApConfiguration.Builder() + .setBssid(config.getBssid()) + .setSsid(config.getSsid()) + .setWpa2Passphrase(config.getWpa2Passphrase()) + .build(); + mWifiManager.startLocalOnlyHotspot(frameworkConfig, executor, callback); + } +} -- cgit v1.2.3