I downloaded source code, and seems that there is something connected with Android Settings. I want to implement some it's features in my application. How it works?
Finally I found a way to set Android system locale:
public void changeLanguage() {
IActivityManager am = ActivityManagerNative.getDefault();
Configuration config;
try {
config = am.getConfiguration();
config.locale = Locale.US; // Change it to your locale
config.userSetLocale = true;
am.updateConfiguration(config);
BackupManager.dataChanged("com.android.providers.settings");
} catch (RemoteException e) {
e.printStackTrace();
}
}
It also requires CHANGE_CONFIGURATION permission:
<uses-permission android:name="android.permission.CHANGE_CONFIGURATION" />
NOTE: In Android 4.2 or newer, permission policy has been changed, and 3rd party application can't get this permission. If you have root access, execute pm grant command:
String.format("pm grant $1%s android.permission.CHANGE_CONFIGURATION", new Object[]{getPackageName()})
Related
I am implementing a video streaming App and want to secure my content
I have used
getWindow().setFlags(LayoutParams.FLAG_SECURE, LayoutParams.FLAG_SECURE);
It stopped taking screenshot of app, but if recording app start before my app user can hear content
And some apps able to record video.
I thought to prevent other apps that has 'SYSTEM_ALERT_WINDOW' permission from capturing my content, so i want to know how to do that?
Note: MinSdk is 21
Checking if you have the drawOverlays permission is safer using this:
public static boolean canDrawOverlayViews(Context con){
if(Build.VERSION.SDK_INT< Build.VERSION_CODES.LOLLIPOP){return true;}
try {
return Settings.canDrawOverlays(con);
}
catch(NoSuchMethodError e){
return canDrawOverlaysUsingReflection(con);
}
}
public static boolean canDrawOverlaysUsingReflection(Context context) {
try {
AppOpsManager manager = (AppOpsManager) context.getSystemService(Context.APP_OPS_SERVICE);
Class clazz = AppOpsManager.class;
Method dispatchMethod = clazz.getMethod("checkOp", new Class[] { int.class, int.class, String.class });
//AppOpsManager.OP_SYSTEM_ALERT_WINDOW = 24
int mode = (Integer) dispatchMethod.invoke(manager, new Object[] { 24, Binder.getCallingUid(), context.getApplicationContext().getPackageName() });
return AppOpsManager.MODE_ALLOWED == mode;
} catch (Exception e) { return false; }
}
Requesting the permission:
public static void requestOverlayDrawPermission(Activity act, int requestCode){
Intent intent = new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION, Uri.parse("package:" + act.getPackageName()));
act.startActivityForResult(intent, requestCode);
}
It is possible if you on android 4.4+, you can specify MediaStore.EXTRA_OUTPUT
Starting in Android 4.4, the owner, group and modes of files on
external storage devices are now synthesized based on directory
structure. This enables apps to manage their package-specific
directories on external storage without requiring they hold the broad
WRITE_EXTERNAL_STORAGE permission. For example, the app with package
name com.example.foo can now freely access
Android/data/com.example.foo/ on external storage devices with no
permissions. These synthesized permissions are accomplished by
wrapping raw storage devices in a FUSE daemon.
I am developing an app which manages the Wi-Fi connections. My scenario is as follows: Let's say, the entire building has a Wi-Fi network named “testing-tls”. My app should be able to connect to only selected access points (based on BSSID or MAC ID). We use TLS authentication mechanism to verify the user (Custom CA Certificates).
I am able to establish a connection through the app, but failing when I try to connect to a different access point (different BSSID). Even though I created the Wi-Fi configuration programmatically, I am unable to update configuration after a first successful connection. I have tested my app in Oreo and Marshmallow. But, I am facing problems in Oreo (Not sure about Nougat). I am beginning to wonder if it is even possible to update the configuration once it is created.
These are the steps I am following:
1) Create a WifiConfiguration object
private WifiConfiguration createWifiConfiguration() {
WifiConfiguration config = new WifiConfiguration();
config.SSID = "\"testing-tls\"";
config.priority = 1;
config.status = WifiConfiguration.Status.ENABLED;
config.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.WPA_EAP;
config.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.IEEE8021X);
config.enterpriseConfig.setIdentity(identityName);
config.enterpriseConfig.setEapMethod(WifiEnterpriseConfig.Eap.TLS);
PKCS12ParseInfo parseInfo;
try {
parseInfo = CertificateUtils.parsePKCS12Certificate(
certificateFilePath, identityPassword);
if (parseInfo != null) {
config.enterpriseConfig.setClientKeyEntry(parseInfo.getPrivateKey(),
parseInfo.getCertificate());
return config;
}
return null;
} catch (KeyStoreException | NoSuchAlgorithmException | IOException |
CertificateException | UnrecoverableKeyException | KeyManagementException e1) {
Timber.e("WifiMonitorService, Fail to parse the input certificate: %s", e1.toString());
Toast.makeText(this, "Error occurred", Toast.LENGTH_SHORT).show();
return null;
}
}
2) Try to establish a connection
private void establishWifiConnection(String result) {
Timber.d("WifiMonitorService, establishing WifiConnection");
WifiConfiguration configuration = createWifiConfiguration();
if (configuration != null) {
// result contains a mac id - 00:45:69:c5:34:f2
configuration.BSSID = result;
int networkId = wifiManager.addNetwork(configuration);
if (networkId == -1) {
networkId = getExistingNetworkId(wifiSsid);
// Add a new configuration to the db
if (networkId == -1) {
Timber.e("Couldn't add network with SSID");
Toast.makeText(this, "Wifi configuration error", Toast.LENGTH_SHORT).show();
return;
}
}
Timber.i("WifiMonitorService, # addNetwork returned: %d", networkId);
wifiManager.saveConfiguration();
wifiManager.enableNetwork(networkId, true);
wifiManager.reassociate();
} else {
Toast.makeText(this, "Wifi conf Error occurred", Toast.LENGTH_SHORT).show();
}
}
3) Get Exiting network id if present
private int getExistingNetworkId(String ssid) {
List<WifiConfiguration> configuredNetworks =
wifiManager.getConfiguredNetworks();
if (configuredNetworks != null) {
for (WifiConfiguration existingConfig : configuredNetworks) {
if (existingConfig.SSID.equals("\"testing-tls\"")) {
return existingConfig.networkId;
}
}
}
return -1;
}
Manifest Permissions are as follows:
<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.VIBRATE" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.CHANGE_WIFI_STATE" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.CHANGE_NETWORK_STATE" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.WAKE_LOCK" />
<uses-permission android:name="android.permission.OVERRIDE_WIFI_CONFIG" />
<uses-permission android:name="android.permission.NETWORK_SETTINGS" />
<uses-feature android:name="android.hardware.wifi" />
<uses-feature android:name="android.hardware.camera" />
<permission
android:name="android.permission.INTERACT_ACROSS_USERS"
android:protectionLevel="signature" />
Error: I always get UID 10189 does not have permission to update configuration error in Oreo
2018-12-28 12:23:44.571 1320-1847/? E/WifiConfigManager: UID 10189 does not have permission to update configuration "testing-tls"WPA_EAP
2018-12-28 12:23:44.571 1320-1847/? I/WifiStateMachine: connectToUserSelectNetwork Allowing uid 10189 with insufficient permissions to connect=1
Investigation
After digging through the source code, I found the implementation of the addOrUpdateNetwork method in WifiConfigManager class.
The implementation addOrUpdateNetwork, in tag android_8.0.0_r21 (Build number OPD1.170816.010) is as follows:
First check if we already have a network with the provided network id or configKey
If no existing network found, validate the configuration, and add.
If existing network found, update the network configuration. Before that, check whether app has necesssary permissions to update the network.
AddOrUpdateNetwork internally calls a function called canModifyNetwork:
/**
* Checks if |uid| has permission to modify the provided configuration.
*
* #param config WifiConfiguration object corresponding to the network to be modified.
* #param uid UID of the app requesting the modification.
* #param ignoreLockdown Ignore the configuration lockdown checks for connection attempts.
*/
private boolean canModifyNetwork(WifiConfiguration config, int uid, boolean ignoreLockdown) {
// Passpoint configurations are generated and managed by PasspointManager. They can be
// added by either PasspointNetworkEvaluator (for auto connection) or Settings app
// (for manual connection), and need to be removed once the connection is completed.
// Since it is "owned" by us, so always allow us to modify them.
if (config.isPasspoint() && uid == Process.WIFI_UID) {
return true;
}
// EAP-SIM/AKA/AKA' network needs framework to update the anonymous identity provided
// by authenticator back to the WifiConfiguration object.
// Since it is "owned" by us, so always allow us to modify them.
if (config.enterpriseConfig != null
&& uid == Process.WIFI_UID
&& TelephonyUtil.isSimEapMethod(config.enterpriseConfig.getEapMethod())) {
return true;
}
final DevicePolicyManagerInternal dpmi = LocalServices.getService(
DevicePolicyManagerInternal.class);
final boolean isUidDeviceOwner = dpmi != null && dpmi.isActiveAdminWithPolicy(uid,
DeviceAdminInfo.USES_POLICY_DEVICE_OWNER);
// If |uid| corresponds to the device owner, allow all modifications.
if (isUidDeviceOwner) {
return true;
}
final boolean isCreator = (config.creatorUid == uid);
// Check if the |uid| holds the |NETWORK_SETTINGS| permission if the caller asks us to
// bypass the lockdown checks.
if (ignoreLockdown) {
return mWifiPermissionsUtil.checkNetworkSettingsPermission(uid);
}
// Check if device has DPM capability. If it has and |dpmi| is still null, then we
// treat this case with suspicion and bail out.
if (mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_DEVICE_ADMIN)
&& dpmi == null) {
Log.w(TAG, "Error retrieving DPMI service.");
return false;
}
// WiFi config lockdown related logic. At this point we know uid is NOT a Device Owner.
final boolean isConfigEligibleForLockdown = dpmi != null && dpmi.isActiveAdminWithPolicy(
config.creatorUid, DeviceAdminInfo.USES_POLICY_DEVICE_OWNER);
if (!isConfigEligibleForLockdown) {
return isCreator || mWifiPermissionsUtil.checkNetworkSettingsPermission(uid);
}
final ContentResolver resolver = mContext.getContentResolver();
final boolean isLockdownFeatureEnabled = Settings.Global.getInt(resolver,
Settings.Global.WIFI_DEVICE_OWNER_CONFIGS_LOCKDOWN, 0) != 0;
return !isLockdownFeatureEnabled
&& mWifiPermissionsUtil.checkNetworkSettingsPermission(uid);
}
As far I can see, only the following uids have access to modify network configurations.
System app
Device owner
Creator (It is failing for some reason)
I am getting the same behaviour in these two phones.
Pixel 2 (Oreo 8.0.0)
Samsung J8 (Oreo 8.0.0)
Additionally, Samsung J8 always shows this warning:
CertificateException: java.security.cert.CertPathValidatorException: Trust anchor for certificate path not found
Question:
How can an already created Wi-Fi configuration be updated programmatically?
Is it even possible to update the Wi-Fi configuration once it is created in the Wi-Fi's internal database?
Is it mandatory to disconnect Wi-Fi before updating or enabling the configuration?
After digging the source code, finally got answers to my questions.
Question: Is it possible to update the configurations once it is created?
Answer: Yes, Android os allows you to update the configuration created from your application. When I called wifiManager.addNetwork(), in the log window the following statements were printed.
2019-01-04 12:23:16.168 1328-3114/? I/addOrUpdateNetwork: uid = 10190 SSID "testing-tls" nid=-1
2019-01-04 12:23:16.169 1328-1851/? V/WifiConfigManager: Adding/Updating network testing-tls
2019-01-04 12:23:16.193 1328-1851/? D/WifiConfigManager: addOrUpdateNetworkInternal: added/updated config. netId=6 configKey="testing-tls"WPA_EAP uid=10190 name=in.ac.iisc.wifimonitoring vendorAP=false hiddenSSID=false autoReconnect=1
2019-01-04 12:23:16.204 1328-1851/? D/WifiConfigStore: Writing to stores completed in 7 ms.
2019-01-04 12:23:16.205 1328-1851/? D/WifiIssueDetector: report htime=2019-01-04_12:23:16 time=1546584796205 rid=105 callBy=in.ac.iisc.wifimonitoring apiName=addOrUpdateNetwork netid=6 callUid=in.ac.iisc.wifimonitoring
2019-01-04 12:23:16.206 15873-15873/in.ac.iisc.wifimonitoring I/WifiMonitorService: WifiMonitorService, #addNetwork returned: 6
Question: what is "UID 10189 does not have permission to update configuration error" in Oreo?
Answer: After updating the configuration, we have to call wifimanager.enableNetwork() method to establish a connection to the desired access point. Workflow of EnableNetwork() is as follows.
WifiManager.enableNetwork() internally calls SyncEnableNetwork() method of WifiStateMachine class.
WifiStateMachine is the core class which tracks the state of Wifi connectivity. All event handling and all changes in connectivity state are initiated in this class.
SyncEnableNetwork() method sends CMD_ENABLE_NETWORK message to ConnectModeState class.
If disableOthers is true, call connectToUserSelectNetwork() method and passes networkId, calling UID and force reconnect [always false - hardcoded value] as arguments.
If an app does not have all the necessary permissions to update the configuration [uses checkAndUpdateLastUid() method in WifiConfigManager class - returns true only for system settings/sysui app] or if enabling of a network is failed, the following statements will be printed.
2018-12-28 12:23:44.571 1320-1847/? E/WifiConfigManager: UID 10189 does not have permission to update configuration "testing-tls"WPA_EAP
2018-12-28 12:23:44.571 1320-1847/? I/WifiStateMachine: connectToUserSelectNetwork Allowing uid 10189 with insufficient permissions to connect=1
Note: checkAndUpdateLastUid() method has been renamed to updateLastConnectUid() in Android Pie. They have slightly modified its functionality as well.
For more information, please refer to the below diagram [I am no good in drawing flowcharts. Please bear with me or suggest if any changes required].
Question 3: Is it mandatory to disconnect wifi before updating or enabling the configuration?
Answer: OS triggers a connection/reconnection to a network under the following conditions:
Selected network id must be different from currently connected network id.
If forceReconnect argument is true, Android prepares for reconnection [True only for system settings/sysui app].
Since developer apps do not have the ability to a force connection, we should disconnect the wifi in order to connect/reconnect to the network after updating the configuration.
Hope this will help others.
hello i try to get the ssid and the password of the hotspot. i use in the method below and its work for android below to 8.
but in android 8.0 its throw exption , i read that i need to get some premisiion
permission:android.permission.OVERRIDE_WIFI_CONFIG.
but we cant get this premission
Method[] methods = m_wifiManager.getClass().getDeclaredMethods();
for (Method m : methods) {
if (m.getName().equals("getWifiApConfiguration")) {
try {
m_wifiConf = (WifiConfiguration) m.invoke(m_wifiManager);
message = m_wifiConf.SSID + '/' + m_wifiConf.preSharedKey + '/';
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
}
Not sure if this relates to your approach with reflection, but as of Android 8.1 you need to have at least ACCESS_COARSE_LOCATION permission and location services enabled in order to use getConnectionInfo() (see getScanResults()).
Anyway, that won't get you access to the wifi password.
As for the OVERRIDE_WIFI_CONFIG permission, it is defined as
<permission android:name="android.permission.OVERRIDE_WIFI_CONFIG"
android:protectionLevel="signature|privileged" />
This means that your app has to be signed by a platform key or to be added to the privileged whitelist in order to use this permission.
When I tried to enable wifi tethering from the following code it throws the exception
java.lang.reflect.InvocationTargetException at java.lang.reflect.Method.invoke(Native Method) at com.....
.... not granted this permission: android.permission.WRITE_SETTINGS
But this works fine in android 6.0 and below versions. And also tried with giving android.permission.WRITE_SETTINGS too.
Is there any limitation in accessing wifiAP in android 6.1?
Follow I attached the code sample that I used to enable hotspot.
WifiConfiguration netConfig = new WifiConfiguration();
netConfig.SSID = ssId;
netConfig.preSharedKey = passkey;
netConfig.allowedAuthAlgorithms.set(WifiConfiguration.AuthAlgorithm.SHARED);
netConfig.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.WPA_PSK);
try {
boolean apstatus = (Boolean) method.invoke(wifiManager, netConfig, true);
for (Method isWifiApEnabledmethod : wmMethods) {
if (isWifiApEnabledmethod.getName().equals("isWifiApEnabled")) {
while (!(Boolean) isWifiApEnabledmethod.invoke(wifiManager)) {}
for (Method method1 : wmMethods) {
if (method1.getName().equals("getWifiApState")) {
int apstate;
apstate = (Integer) method1.invoke(wifiManager);
Log.i(TAG, "Apstate ::: " + apstate);
}
}
}
}
if (apstatus) {
Log.d(TAG, "Access Point created");
} else {
Log.d(TAG, "Access Point creation failed");
}
} catch (IllegalArgumentException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
I think Android M don't support to create hotspot programmatically . You can take your Marshmallow user to settings page to create hotspot by himself. below code will help yo to go setting page.
startActivity(
new Intent(Settings.ACTION_SETTINGS));
This is not the correct way.But this fixed the issue.
Changed the target sdk version to 21. Then hotspot will start programmatically even in android 6.0.1. Think there should be a proper way to do this for android 6 and later versions. I think requesting runtime permissions needs to execute those kind of processess.
This talks about the android permission requesting in runtime
Set target SDK version 21 and ask for write_settings permission in your activity. Also add android.permission.WRITE_SETTINGS permission in manifest.
if (ActivityCompat.shouldShowRequestPermissionRationale(this,
Manifest.permission.WRITE_SETTINGS)){
}else {
ActivityCompat.requestPermissions(this,
new String[]{Manifest.permission.WRITE_SETTINGS},
121);
}
For more details please visit http://developer.android.com/training/permissions/requesting.html
Guys I tried everything and I wasn't able to start the hotspot in Android 6.0.
You can just check if Api is >= 23, and if so just take the user to settings page to create hotspot by himself.
if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
final Intent intent = new Intent(Intent.ACTION_MAIN, null);
intent.addCategory(Intent.CATEGORY_LAUNCHER);
final ComponentName cn = new ComponentName(
"com.android.settings",
"com.android.settings.TetherSettings");
intent.setComponent(cn);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity( intent);
}else{
createhotSpot();
}
Permission is not your problem. You need something like this code :
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
if (!Settings.System.canWrite(getApplicationContext())) {
Intent intent = new Intent(Settings.ACTION_MANAGE_WRITE_SETTINGS, Uri.parse("package:" + getPackageName()));
startActivityForResult(intent, 200); //You need a callback for activity result so that check if user enabled this feature, go for starting hotspot (google for it)
} else {
// Do your stuff about starting hotspot (in network thread)
}
}
I'm creating an android application that has a gesture to expand the status bar.. I used the following code to expand it.. :
try {
Object sbservice = getSystemService("statusbar");
Class<?> statusbarManager = Class.forName("android.app.StatusBarManager");
Method showsb;
if (Build.VERSION.SDK_INT >= 17) {
showsb = statusbarManager.getMethod("expandNotificationsPanel");
} else {
showsb = statusbarManager.getMethod("expand");
}
showsb.invoke(sbservice);
} catch (Exception e) {
e.printStackTrace();
}
I tried this on an emulator and it worked.. But when I tried on a real device this throws an exception
SecurityException: Permission Denial: get/set setting for user asks to
run as user -2 but is calling from user 0; this requires
android.permission.INTERACT_ACROSS_USERS_FULL
Any Idea ?
android.permission.INTERACT_ACROSS_USERS_FULL is a signature level permission. Your app will not be able to use it until and unless it has the same signature as the system.
you need to add permission in manifest.xml
<uses-permission android:name="android.permission.EXPAND_STATUS_BAR" />