I use this code for enabling or disabling Internet 3G Data in my application. I read several questions of it about hidden reflection functions and all that, but it was working very well in thousands of phones with very different android releases (my application is in PlayStore and I had no problems with it). But I am worried because I found a person whose phone is not able to do this. Let me first show the code I use:
try
{ final ConnectivityManager conman = (ConnectivityManager) MyContext.getSystemService(Context.CONNECTIVITY_SERVICE);
if(conman == null) return false;
Class conmanClass = Class.forName(conman.getClass().getName());
if(conmanClass == null) return false;
Field iConnectivityManagerField = conmanClass.getDeclaredField("mService");
if(iConnectivityManagerField == null) return false;
iConnectivityManagerField.setAccessible(true);
Object iConnectivityManager = iConnectivityManagerField.get(conman);
if(iConnectivityManager == null) return false;
Class iConnectivityManagerClass = Class.forName(iConnectivityManager.getClass().getName());
if(iConnectivityManagerClass == null) return false;
Method setMobileDataEnabledMethod = iConnectivityManagerClass.getDeclaredMethod("setMobileDataEnabled", Boolean.TYPE);
if(setMobileDataEnabledMethod == null) return false;
setMobileDataEnabledMethod.setAccessible(true);
setMobileDataEnabledMethod.invoke(iConnectivityManager, true/false); //Here is where you choose to enable or to disable
return true; //Everything went OK
}catch(Exception e)
{ return false;
}
The error is in line:
Field iConnectivityManagerField = conmanClass.getDeclaredField("mService");
With this result:
java.lang.NoSuchFieldException: mService
That phone is a Samsung Galaxy SII using Jelly Bean 4.1.1
Any ideas? I am afraid of people starting to report same issue.
Apparently, Samsung (or possibly a ROM mod author) rewrote that class and no longer has a data member named mService. This is completely within their rights. So long as their change does not break anything covered by the CTS, they can do what they want with the internal implementations of framework classes. This is why I and other Android experts tell developers not to rely on script-kiddie tricks like what you are using.
If "enabling or disabling Internet 3G Data" is crucial to your app, and you determine that this is affecting stock ROMs on the Samsung Galaxy SII, you will need to block distribution to such devices through the Play Store.
If "enabling or disabling Internet 3G Data" is not crucial to your app, add in a better exception handler to say "sorry, this feature is not available", or some such.
Related
I have recently added a system volume controller to my app & i have overlooked Casting.
The app detects a volume button click using an accessibility service, intercepts the system volume panel by broadcasting the close system dialogues intent and pops my overlay panel, allowing the user to control audio directly from the panel (alarm, music & ring).
I have already added stop checks if the user is in call or the screen is off.
Is there a way to determine if the android device is currently casting video or audio?
I have dug through several API's and they all seem to point to methods within the context of the app, nothing system wide.
The solution was to create a MediaSessionManager instance and check for active controllers, then get the PlaybackType.
MediaController = null;
boolean isCasting = false;
MediaSessionManager mediaSessionManager = (MediaSessionManager) getSystemService(MEDIA_SESSION_SERVICE);
assert mediaSessionManager != null;
List<MediaController> sessions = mediaSessionManager.getActiveSessions(new ComponentName(this, NotificationListener.class));
for(MediaController controller : sessions) {
try {
isCasting = Objects.requireNonNull(controller.getPlaybackInfo()).getPlaybackType() == MediaController.PlaybackInfo.PLAYBACK_TYPE_REMOTE;
} catch (Exception e) {
e.printStackTrace();
}
if(isCasting){
mediaController = controller;
break;
}
}
Check if an app, for example, Instagram is started by user.
Note: My app is targeting lollipop and above versions in android
Yeah the only way you can do it is through the Accessibility Service. Look at this page to understand how to create it. https://developer.android.com/training/accessibility/service.html They will also need to enable the service via the services -> accessibility screen.
AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED you can probably interrogate the package in front to figure out if Instigram is on top.
You definitely don't want to use getRunningTasks since the function was modified in Android 5.0+
I figured out that I can do this by using usage access feature.
#TargetApi(Build.VERSION_CODES.LOLLIPOP)
public static String getForegroundProcess(Context context) {
String topPackageName = null;
UsageStatsManager usage = (UsageStatsManager) context.getSystemService(Context.USAGE_STATS_SERVICE);
long time = System.currentTimeMillis();
List<UsageStats> stats = usage.queryUsageStats(UsageStatsManager.INTERVAL_DAILY, time - 1000*1000, time);
if (stats != null) {
SortedMap<Long, UsageStats> runningTask = new TreeMap<Long,UsageStats>();
for (UsageStats usageStats : stats) {
runningTask.put(usageStats.getLastTimeUsed(), usageStats);
}
if (runningTask.isEmpty()) {
return null;
}
topPackageName = runningTask.get(runningTask.lastKey()).getPackageName();
}
if(topPackageName==null) {
Intent intent = new Intent(Settings.ACTION_USAGE_ACCESS_SETTINGS);
context.startActivity(intent);
}
return topPackageName;
}
Now continuously check if the desired app is in the foreground.
String fg=getForegroundProcess(getApplicationContext());
if(fg != null && fg.contains("com.instagram.android")){
//Instagram is in foreground
}else {
}
I continuously run the above code with a job service.Which is available for
lollipop and above.
I have a small functionality. Switching on the torch and keeping it on, till the user switches it off from my app or my app exits. Using :
params = camera.getParameters();
if (params.getFlashMode().equals(Parameters.FLASH_MODE_TORCH)) {
isFlashOn = true;
return;
}
params.setFlashMode(Parameters.FLASH_MODE_TORCH);
camera.setParameters(params);
camera.startPreview();
And to switch off :
if (params.getFlashMode().equals(Parameters.FLASH_MODE_OFF)) {
isFlashOn = false;
return;
}
params.setFlashMode(Parameters.FLASH_MODE_OFF);
camera.setParameters(params);
camera.stopPreview();
But I notice that this is not very robust. Works fine the first time, but after that (especially on my API levle 22 phone) might not work. I was thinking of testing with the android.hardware.camera2 as suggested here
Plan to use if (android.os.Build.VERSION.SDK_INT >20) and a strategy (a base interface implemented by two classes, one using old API and one the new camera2 API.
Is this safe on all devices? I saw that we can do it for android classes, but is it okay for our own classes too? Or are there devices which scan all our code and reject it if it has code that refers to API it does not know about?
I do not want to make two APKs as its a small functionality.
I make sure flash is available like this , not tested on all devices but in an emulator by Genymotion app did not crash.
public boolean torchInit() {
try {
PackageManager pm = app.getPackageManager();
// First check if device supports flashlight
boolean hasFlash = pm.hasSystemFeature(PackageManager.FEATURE_CAMERA_FLASH);
if (!hasFlash) {
Toast.makeText(app, "Flash not found or can\'t get hold of it. No torch", Toast.LENGTH_LONG).show();
return false;
}
camera = Camera.open();
Camera.Parameters params = camera.getParameters();
Log.i(LogId, "camera params flash: " + params.getFlashMode());
return true;
} catch (Throwable e) {
Log.e(LogId, "cameraFlashSetup " + e, e);
Toast.makeText(app, "Flash error, no torch. Description : " + e, Toast.LENGTH_LONG).show();
camera = null;
}
return false;
}
The flash interface to change between the two classes is :
public abstract class TorchInterface {
protected AppCompatActivity app;
public void init(AppCompatActivity ap){
app = ap;
}
public abstract boolean torchInit();
public boolean torchReInit(){
return torchInit();//if re init is not different than init
}
public abstract boolean torchOn();
public abstract boolean torchOff();
}
Update: new code worked but only if I:
mBuilder = camera.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);
Instead of:
mBuilder = camera.createCaptureRequest(CameraDevice.TEMPLATE_MANUAL);
But then switches on flash as soon as init the app. I was going to chuck it, then realised on my Camera2Impl I can :
public boolean torchInit() {
//do nothing on usual init that app calls on create
return true;
}
And instead do the init on torch on (flash on):
public boolean torchOn() {
//if not in it, try first 3 times
if(mBuilder == null || mSession == null){
if(firstFewTimesTorchOn > 0){
firstFewTimesTorchOn--;
torchInit2();
try{
Thread.sleep(150);
}catch(Exception e){}
if(mBuilder == null || mSession == null) {
return false;
}
}
}
try {
mBuilder.set(CaptureRequest.FLASH_MODE, CameraMetadata.FLASH_MODE_TORCH);//and etc
Android devices do not "scan" code - compiler does. Therefore, I don't see any issue with your idea. On contrary - using Strategy pattern is way better then if-else all over the code.
Something along these lines should work:
if (Build.VERSION.SDK_INT > Build.VERSION_CODES.LOLLIPOP) {
mFlashlightStrategy = new PostLollipopStrategy();
} else {
mFlashlightStrategy = new PreLollipopStrategy();
}
Is this safe on all devices?
Why dont't you put one check whether flash is available or not.
context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_CAMERA_FLASH);
which will return true if a flash is available, false if not. You can write your further code in true block.
This question already has answers here:
How the "SHAREit" android application works technically?
(2 answers)
Closed 1 year ago.
I'm want to create a file sharing app like shareit but I'm really confused about how shareit discovers the nearby devices.
When you click receive button shareit creates a hotspot at the receiver side and the sender without connecting to the hotspot shows the receiver name. How is that possible?
If shareit uses Wi-Fi direct then what's the point of creating hotspot?
And to use Network Service Discovery (NSD) both server and client should be on same network so I think shareit is using something else
If anyone can explain this concept of shareit it will be very helpful.
I finally found the answer! SHAREit uses WiFi SSID to identify the nearby app users.
The SSID Consist of two partslike this. BAHD-bXViYQ WHERE 'B' Stands for ANDROID DEVICE and the AHD for the user icon. the second part is the user name encoded in Base64. In this example my name muba.
I hope this answer helps save some time.
Well I have found how to enable the hotspot from one sharing app and find the list of available wifi enabled by that sharing app into another one. just like shareIt receiver enables the wifi hotspot and sender discovers the list of available receivers.
First of all You have to scan all available wifi network using WifiManager
public void startScan(){
mWifiManager.startScan();
mScanResultList = mWifiManager.getScanResults();
mWifiConfigurations = mWifiManager.getConfiguredNetworks();
}
now pass this mScanResultList to a method which finds the network according to your requirement.
public static List<ScanResult> filterWithNoPassword(List<ScanResult> scanResultList){
if(scanResultList == null || scanResultList.size() == 0){
return scanResultList;
}
List<ScanResult> resultList = new ArrayList<>();
for(ScanResult scanResult : scanResultList){
if(scanResult.capabilities != null && scanResult.capabilities.equals(NO_PASSWORD) || scanResult.capabilities != null && scanResult.capabilities.equals(NO_PASSWORD_WPS)){
resultList.add(scanResult);
}
}
return resultList;
}
Now pass the resultList to arraylist adapter to show the network in list. Inside adapter's convertView method just pass that dataList to scanner to get ssid and mac address of the network
#Override
public View convertView(int position, View convertView) {
ScanResultHolder viewHolder = null;
if(convertView == null){
convertView = View.inflate(getContext(), R.layout.item_wifi_scan_result, null);
viewHolder = new ScanResultHolder();
viewHolder.iv_device = (ImageView) convertView.findViewById(R.id.iv_device);
viewHolder.tv_name = (TextView) convertView.findViewById(R.id.tv_name);
viewHolder.tv_mac = (TextView) convertView.findViewById(R.id.tv_mac);
convertView.setTag(viewHolder);
}else{
viewHolder = (ScanResultHolder) convertView.getTag();
}
ScanResult scanResult = getDataList().get(position);
if(scanResult != null){
viewHolder.tv_name.setText(scanResult.SSID);
viewHolder.tv_mac.setText(scanResult.BSSID);
}
return convertView;
}
This is the code to enable the hotspot
public static boolean configApState(Context context, String apName) {
WifiManager wifimanager = (WifiManager) context.getSystemService(context.WIFI_SERVICE);
WifiConfiguration wificonfiguration = null;
try {
wificonfiguration = new WifiConfiguration();
wificonfiguration.SSID = apName;
// if WiFi is on, turn it off
if(isApOn(context)) {
wifimanager.setWifiEnabled(false);
// if ap is on and then disable ap
disableAp(context);
}
Method method = wifimanager.getClass().getMethod("setWifiApEnabled", WifiConfiguration.class, boolean.class);
method.invoke(wifimanager, wificonfiguration, !isApOn(context));
return true;
}
catch (Exception e) {
e.printStackTrace();
}
return false;
}
I am attempting to integrate the Dropbox chooser drop-in api into my application. I am running into an abnormal issue. In my app when I launch the dbx chooser, anytime that I select a file the application fails with the following error code:
Sorry, an error has occurred. Please try again later.
Here is the portion of my code that implements the Dropbox API. This portion of the code is where the dropbox api is initially invoked.
public void StartDropboxApplication() {
// create the chooser
DbxChooser chooser = new DbxChooser(APP_KEY);
DbxChooser.ResultType result;
// determine which mode to be in // TODO REMOVE ALL BUT FILE CONTENT TODO SIMPLIFY by making this a setting
switch(( (RadioGroup) ParentActivity.findViewById(R.id.link_type)).getCheckedRadioButtonId() ) {
case R.id.link_type_content:
result = DbxChooser.ResultType.DIRECT_LINK;
break;
default:
throw new RuntimeException("Radio Group Related error.");
}
// launch the new activity
chooser.forResultType(result).launch(ParentActivity, 0);
}
Here is the position where the code should then pick it up although it never does.
protected void onActivityResult( int request, int result, Intent data ) {
Log.i(fileName, "result: " + result);
// check to see if the camera took a picture
if (request == 1) {
// check to see if the picture was successfully taken
if (result == Activity.RESULT_OK) {
onPicture();
} else {
Log.i(fileName, "Camera App cancelled.");
}
} else if (request == 0) {
if ( result == Activity.RESULT_OK ) {
onDropbox(data);
} else {
Log.i(fileName, "dropbox related issue.");
}
}
}
Thank you for any help or suggestions that you are able to provide.
I was able to solve my own issues and get this working. On the off chance that someone else has a similar problem I will detail the solution. The first issue was I was that my APP_KEY was incorrect.
The next issue was that I was attempting to read from a direct link instead of a content link. The direct link provides the application with a link to the file on the Dropbox server whereas the content link provides the application with a cached version of the file. If the file is not present on the device, the SDK downloads a copy for you.