I am working on an android web app. I am using PhoneGap Push Plugin to receive push notifications on device. I need to track if push notifications have been disabled for my app in the application manager settings. How do I achieve it?
Thanks.
You have to check in .java class whether the notification is enabled or no
I am posting reference java code for check whether notification is enabled or not
public class NotificationsUtils {
private static final String CHECK_OP_NO_THROW = "checkOpNoThrow";
private static final String OP_POST_NOTIFICATION = "OP_POST_NOTIFICATION";
public static boolean isNotificationEnabled(Context context) {
AppOpsManager mAppOps = (AppOpsManager) context.getSystemService(Context.APP_OPS_SERVICE);
ApplicationInfo appInfo = context.getApplicationInfo();
String pkg = context.getApplicationContext().getPackageName();
int uid = appInfo.uid;
Class appOpsClass = null; /* Context.APP_OPS_MANAGER */
try {
appOpsClass = Class.forName(AppOpsManager.class.getName());
Method checkOpNoThrowMethod = appOpsClass.getMethod(CHECK_OP_NO_THROW, Integer.TYPE, Integer.TYPE, String.class);
Field opPostNotificationValue = appOpsClass.getDeclaredField(OP_POST_NOTIFICATION);
int value = (int)opPostNotificationValue.get(Integer.class);
return ((int)checkOpNoThrowMethod.invoke(mAppOps,value, uid, pkg) == AppOpsManager.MODE_ALLOWED);
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (NoSuchFieldException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
return false;
}
}
Related
I want to control wifi hotspot dynamically in my Android app project. I have tired Reflection (which will not work in Android Oreo and later versions), startLocalOnyNetwork (but I want specific SSID and PASSWORD, which is not possible to configure it).
Then I rooted my phone, Is it possible if the device is rooted ?
Expecting an api to turn on/off wifi hotspot with specific SSID and PASSWORD or use the previous one.
Any possibilities or workarounds ?
Thanks in advance.
To turn on Wifi Hotspot, need some permissions
<uses-permission android:name="android.permission.WRITE_SETTINGS"
tools:ignore="ProtectedPermissions" />
and the permission should be dynamically granted by user
In apps advanced settings -> Modify system settings
/**
* This enables tethering using the ssid/password defined in Settings App>Hotspot & tethering
* Does not require app to have system/privileged access
* Credit: Vishal Sharma - https://stackoverflow.com/a/52219887
*/
public boolean startTethering() {
File outputDir = mContext.getCodeCacheDir();
Object proxy;
try {
proxy = ProxyBuilder.forClass(OnStartTetheringCallbackClass())
.dexCache(outputDir).handler(new InvocationHandler() {
#Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
return null;
}
}).build();
} catch (Exception e) {
Log.e(TAG, "Error in enableTethering ProxyBuilder");
e.printStackTrace();
return false;
}
Method method = null;
try {
method = mConnectivityManager.getClass().getDeclaredMethod("startTethering", int.class, boolean.class, OnStartTetheringCallbackClass(), Handler.class);
if (method == null) {
Log.e(TAG, "startTetheringMethod is null");
} else {
method.invoke(mConnectivityManager, ConnectivityManager.TYPE_MOBILE, false, proxy, null);
Log.d(TAG, "startTethering invoked");
}
return true;
} catch (Exception e) {
Log.e(TAG, "Error in enableTethering");
e.printStackTrace();
}
return false;
}
public void stopTethering() {
try {
Method method = mConnectivityManager.getClass().getDeclaredMethod("stopTethering", int.class);
if (method == null) {
Log.e(TAG, "stopTetheringMethod is null");
} else {
method.invoke(mConnectivityManager, ConnectivityManager.TYPE_MOBILE);
Log.d(TAG, "stopTethering invoked");
}
} catch (Exception e) {
Log.e(TAG, "stopTethering error: " + e.toString());
e.printStackTrace();
}
}
Use above methods to turn on/off Wifi Hotspot with SSID and password defined in the settings.
private int AP_STATE_DISABLED = 11;
private int AP_STATE_ENABLING = 12;
private int AP_STATE_ENABLED = 13;
private int AP_STATE_ERROR = 14;
/**
* #return status hot spot enabled or not
*/
public boolean isHotSpotEnabled(Context context) {
Method method = null;
int actualState = 0;
try {
WifiManager mWifiManager = (WifiManager) context.getApplicationContext().getSystemService(Context.WIFI_SERVICE);
method = mWifiManager.getClass().getDeclaredMethod("getWifiApState");
method.setAccessible(true);
actualState = (Integer) method.invoke(mWifiManager, (Object[]) null);
if (actualState == AP_STATE_ENABLING ||actualState == AP_STATE_ENABLED) {
return true;
}
} catch (IllegalArgumentException | NoSuchMethodException | IllegalAccessException | InvocationTargetException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
return false;
}
Above method can be used to get the current state of hotspot
I want to use Jacoco to collect code coverage for manually testing my Android apps. What I did was implement a Broadcast Receiver and ask Jacoco to collect coverage data when receiving the intent. Here is my receiver code:
public class CoverageReceiver extends BroadcastReceiver {
public static String TAG = "JacocoInstrumentation:";
private static final String DEFAULT_COVERAGE_FILE_PATH = "/sdcard/coverage.ec";
private static final boolean LOGD = true;
private String mCoverageFilePath;
#Override
public void onReceive(Context context, Intent intent) {
generateCoverageReport();
}
private void generateCoverageReport() {
if (LOGD)
Log.d(TAG, "generateCoverageReport()");
java.io.File coverageFile = new java.io.File(getCoverageFilePath());
OutputStream out = null;
// We may use this if we want to avoid refecltion and we include
// emma.jar
//RT.dumpCoverageData(coverageFile, false, false);
// Use reflection to call emma dump coverage method, to avoid
// always statically compiling against emma jar
try {
Object agent = Class.forName("org.jacoco.agent.rt.RT")
.getMethod("getAgent")
.invoke(null);
out = new FileOutputStream(coverageFile,false);
out.write((byte[]) agent.getClass().getMethod("getExecutionData", boolean.class)
.invoke(agent, false));
} catch (ClassNotFoundException e) {
reportJacocoError("Jacoco.jar not in the class path?", e);
} catch (SecurityException e) {
reportJacocoError(e);
} catch (NoSuchMethodException e) {
reportJacocoError(e);
} catch (IllegalArgumentException e) {
reportJacocoError(e);
} catch (IllegalAccessException e) {
reportJacocoError(e);
} catch (InvocationTargetException e) {
reportJacocoError(e);
} catch (FileNotFoundException e){
reportJacocoError(e);
} catch (IOException e) {
reportJacocoError(e);
} finally {
if (out != null) {
try {
out.close();
} catch (IOException e) {
reportJacocoError(e);
}
}
}
}
public String getCoverageFilePath() {
if (mCoverageFilePath == null) {
return DEFAULT_COVERAGE_FILE_PATH;
} else {
return mCoverageFilePath;
}
}
public boolean setCoverageFilePath(String filePath){
if(filePath != null && filePath.length() > 0) {
mCoverageFilePath = filePath;
return true;
}
return false;
}
private void reportJacocoError(Exception e) {
reportJacocoError("", e);
}
private void reportJacocoError(String hint, Exception e) {
String msg = "Failed to generate Jacoco coverage. " + hint;
Log.e(TAG, msg, e);
}
}
I also add apply the plugin: 'jacoco' and testCoverageEnabled = true in the Gradle file.
I have seen a few people do this, so it should work. However, when I tried to broadcast the triggering intent and my receiver began to work, I got a ClassNotFoundException:
java.lang.ClassNotFoundException: org.jacoco.agent.rt.RT
...
Caused by: java.lang.ClassNotFoundException: Didn't find class "org.jacoco.agent.rt.RT" on path:
...
Suppressed: java.lang.ClassNotFoundException: org.jacoco.agent.rt.RT
...
Caused by: java.lang.NoClassDefFoundError: Class not found using the boot class loader; no stack trace available
I have tried to specify the Jacoco version, or add Jacoco to the dependencies, but none of that worked. So what should I do?
I used this code it's working when i called from activity and fragment
import com.google.android.gms.ads.identifier.AdvertisingIdClient.Info;
Info adInfo = null;
try {
adInfo = AdvertisingIdClient.getAdvertisingIdInfo(mContext);
} catch (IOException e) {
e.printStackTrace();
} catch (GooglePlayServicesAvailabilityException e) {
e.printStackTrace();
} catch (GooglePlayServicesNotAvailableException e) {
e.printStackTrace();
}
String AdId = adInfo.getId();
But when i called from pending intent like Package Removed then i want to call the web service at that time i need advertising id but i got null.if you people had done previously please suggest me.thanks in advance.
try use app context
as receivers could use activity context or app context - depends who&how started the receiver
AdvertisingIdClient.getAdvertisingIdInfo(context.getApplicationContext());
You can try this code and call the bellow method on onCreate
public void getAAID()
{
AsyncTask.execute(new Runnable() {
#Override
public void run() {
try {
AdvertisingIdClient.Info adInfo = AdvertisingIdClient.getAdvertisingIdInfo(MyActivity.this);
String myId = adInfo != null ? adInfo.getId() : null;
Log.i("UIDMY",myId);
} catch (Exception e) {
Log.e("error", e);
}
}
});
}
Check complete post: how to get AAID programmatically
Is there any way to know (pro grammatically) in your Activity/Application that the user has enabled USB tethering on his phone?
you can also use reflection to access the hidden function for setting usb tethering.
Here is my code.
ConnectivityManager cm =
(ConnectivityManager)getSystemService(Context.CONNECTIVITY_SERVICE);
Log.d(TAG,"test enable usb tethering");
String[] available = null;
int code=-1;
Method[] wmMethods = cm.getClass().getDeclaredMethods();
for(Method method: wmMethods){
if(method.getName().equals("getTetherableIfaces")){
try {
available = (String[]) method.invoke(cm);
break;
} catch (IllegalArgumentException e) {
// TODO Auto-generated catch block
e.printStackTrace();
return;
} catch (IllegalAccessException e) {
// TODO Auto-generated catch block
e.printStackTrace();
return;
} catch (InvocationTargetException e) {
// TODO Auto-generated catch block
e.printStackTrace();
return;
}
}
}
for(Method method: wmMethods){
if(method.getName().equals("tether")){
try {
code = (Integer) method.invoke(cm, available[0]);
} catch (IllegalArgumentException e) {
// TODO Auto-generated catch block
e.printStackTrace();
return;
} catch (IllegalAccessException e) {
// TODO Auto-generated catch block
e.printStackTrace();
return;
} catch (InvocationTargetException e) {
// TODO Auto-generated catch block
e.printStackTrace();
return;
}
break;
}
}
if (code==0)
Log.d(TAG,"Enable usb tethering successfully!");
else
Log.d(TAG,"Enable usb tethering failed!");
For disabling usb tethering, you just need to change the reflection method name "getTetherableIfaces" to "getTetheredIfaces", change "tether" to "untether".
Please check.
Looking through the Settings.System documentation points to the answer being no, its not possible to do this.
Link to said documentation
This should work on all phones, confirmed on some Android 7,6 and 5 devices;
Method: interface rndisX (typically rndis0) only shows up when usb tethering is enabled.
Code Example:
private static boolean isTetheringActive(Context context){
try{
for(Enumeration<NetworkInterface> en = NetworkInterface.getNetworkInterfaces(); en.hasMoreElements();){
NetworkInterface intf=en.nextElement();
for(Enumeration<InetAddress> enumIpAddr = intf.getInetAddresses(); enumIpAddr.hasMoreElements();){
InetAddress inetAddress=enumIpAddr.nextElement();
if(!intf.isLoopback()){
if(intf.getName().contains("rndis")){
return true;
}
}
}
}
}catch(Exception e){e.printStackTrace();}
return false;
}
Here is a solution to Listen for tethering state changes :
First you need to be familiar with BroadcastReceiver.
you can find a lot of tutorial (google : how to listen for connectivity changes ...)
In order to get the Tethering state update, you need to use a hidden filter action of Android (see ConnectivityManager)
and in your BroadcastReceiver class :
IntentFilter filter = new IntentFilter("android.net.conn.TETHER_STATE_CHANGED");
then register the filter to your BroadcastReceiver :
myApplicationContext.registerReceiver(this, filter);
on your onReceive(final Context context,final Intent intent) method, the Intent.extras information contains 3 arrays filled with the corresponding tethered network interface :
erroredArray / availableArray / activeArray
It's a little bit tricky but you can get the tethering status information.
In addition, you can do some reflexion on hidden function of Android code :
Search for getTetherableIfaces() in the Connectivity Manager.
Here is a link : https://github.com/android/platform_frameworks_base/blob/master/core/java/android/net/ConnectivityManager.java#L1604
You can get the Network Interfaces and check what is active like this:
Enumeration<NetworkInterface> interfaces = NetworkInterface.getNetworkInterfaces();
NetworkInterface rndis = null;
NetworkInterface wlan = null;
while(interfaces.hasMoreElements()) {
NetworkInterface nif = interfaces.nextElement();
if(hasIP4Address(nif)) {
if(nif.getDisplayName().startsWith("rndis"))
rndis = nif;
else if (nif.getDisplayName().startsWith("wlan"))
wlan = nif;
}
}
// Let the user choose Wi-Fi or rndis connect
if (rndis != null) {
socket.setNetworkInterface(rndis);
Log.i(TAG, "Subscribe: with interface rndis");
} else if(wlan != null) {
socket.setNetworkInterface(wlan);
Log.i(TAG, "Subscribe: with interface wlan");
}
I have found that if I check for usb0 network interface
it only has an ip address once tethering has been set up.
public static String getIPAddressUsb(final boolean useIPv4) {
try {
final List<NetworkInterface> interfaces = Collections.list(NetworkInterface.getNetworkInterfaces());
for (final NetworkInterface intf : interfaces) {
if (intf.getDisplayName().startsWith("usb")) {
final List<InetAddress> addrs = Collections.list(intf.getInetAddresses());
for (final InetAddress addr : addrs) {
final String sAddr = addr.getHostAddress().toUpperCase();
final boolean isIPv4 = InetAddressUtils.isIPv4Address(sAddr);
if (useIPv4) {
if (isIPv4) { return sAddr; }
} else {
if (!isIPv4) {
final int delim = sAddr.indexOf('%');
return delim < 0 ? sAddr : sAddr.substring(0, delim);
}
}
}
}
}
} catch (final Exception ex) {
// for now eat exceptions
}
return "";
}
boolean isUsbTethered(){
String ipAddr = MipnAndroidApplication.getIPAddressUsb(true);
if (ipAddr.length() == 0) {
Log.i(LOG_TAG, "tethering not enabled");
return false;
} else {
Log.i(LOG_TAG, "tethering enabled :)");
return true;
}
}
Is it possible to retrieve the time an account was last synchronized, like the system Settings->Accounts&Sync app does? I'm using Android 2.2.
Looking at the 2.2 source for AccountSyncSettings.java, I see the status is retrieved using:
SyncStatusInfo status = ContentResolver.getSyncStatus(account, authority);
but SyncStatusInfo and getSyncStatus don't seem to be part of the public API (marked with #hide). Is there some other way to get at this info?
You can use reflection to achieve this purpose.Here is my code to implement this
private long getLasySyncTime() {
long result = 0;
try {
Method getSyncStatus = ContentResolver.class.getMethod(
"getSyncStatus", Account.class, String.class);
if (mAccount != null && mSyncAdapter != null) {
Object status = getSyncStatus.invoke(null, mAccount,
mSyncAdapter.authority);
Class<?> statusClass = Class
.forName("android.content.SyncStatusInfo");
boolean isStatusObject = statusClass.isInstance(status);
if (isStatusObject) {
Field successTime = statusClass.getField("lastSuccessTime");
result = successTime.getLong(status);
TLog.d(WeixinSetting.class, "get last sync time %d", result);
}
}
} catch (NoSuchMethodException e) {
} catch (IllegalAccessException e) {
} catch (InvocationTargetException e) {
TLog.d(WeixinSetting.class, e.getMessage() + e.getCause().getMessage());
} catch (IllegalArgumentException e) {
} catch (ClassNotFoundException e) {
} catch (NoSuchFieldException e) {
} catch (NullPointerException e) {
}
return result;
}
The Settings app uses ContentResolver.getSyncStatus(account, authority). However, this is not part of the public API. You can use it, but it could break with any future release.