get access to com.android.internal.telephony.Call - android

I need to get access to com.android.internal.telephony.Call.
doing so:
// Initialize the telephony framework
PhoneFactory.makeDefaultPhones (this);
// Get the default phone
Phone phone = PhoneFactory.getDefaultPhone ();
CallManager mCM = CallManager.getInstance ();
mCM.registerPhone (phone);
Call call = mCM.getFirstActiveBgCall();
but does not extend to initialize the framework.
Help me to initialize Call.
I need to read the state of the call like:
IDLE, ACTIVE, HOLDING, DIALING, ALERTING, INCOMING, WAITING, DISCONNECTED, DISCONNECTING.

You need to make use of PhoneStateListener
It will provide you the facility to have your application listen for different state of a phone call. You will need to put <uses-permission android:name="android.permission.READ_PHONE_STATE"/> in your manifest file

You can but there is a critical requirement: the application must be signed at system level, meaning you are the manufacturer.
Here is how you write a Service that will broadcast an intent for every change in the foreground call state.
/*
* This implementation uses the com.android.internal.telephony package: you have
* to extract the framework classes .jar file from the platform (or the
* emulator) to compile this code. Also, add the jar file to the external
* libraries in the Java Build Path/libraries of the android project. </p>
*
* The jar file must match the android version you are building the application
* for. Because this implementation is using the internal packages it cannot be
* guaranteed to operate on later versions of android.
*/
public class CallStateNotificationService extends Service {
private static final String LOG_TAG = CallStateNotificationService.class.getSimpleName();
private Handler mHandler = new Handler() {
#Override
public void handleMessage(Message msg) {
// TODO Auto-generated method stub
super.handleMessage(msg);
if (msg.what == 101) {
CallManager callManager = CallManager.getInstance();
Call.State state = callManager.getActiveFgCallState();
Intent intent = new Intent(PhoneIntents.ACTION_PRECISE_CALL_STATE);
intent.putExtra(PhoneIntents.PRECISE_CALL_STATE, state.name());
Context context = getApplicationContext();
context.sendBroadcast(intent);
}
}
};
#Override
public void onCreate() {
super.onCreate();
try {
CallManager callManager = CallManager.getInstance();
if (callManager != null) {
callManager.registerForPreciseCallStateChanged(mHandler, 101, null);
} else {
Log.w(LOG_TAG, "Can't resolve CallManager reference"); //$NON-NLS-1$
}
} catch (Exception e) {
e.printStackTrace();
}
}
#Override
public void onDestroy() {
super.onDestroy();
CallManager callManager = CallManager.getInstance();
if (callManager != null) {
callManager.unregisterForPreciseCallStateChanged(mHandler);
} else {
Log.w(LOG_TAG, "Can't resolve CallManager reference"); //$NON-NLS-1$
}
}
And here is the definition of the custom broadcasted intents.
/** Intent action and extra argument names for CallStateNotificationService */
public final class PhoneIntents {
public static final String ACTION_PRECISE_CALL_STATE = "com.myorg.myapp.CALL_STATE";
public static final String PRECISE_CALL_STATE = "precise_call_state";
}
To have this code compile and link, you of course need to either build the program as part of the android distribution itself or import the class-framework by a method explained elsewhere on the Internet.
All of this is currently in an app under production.

Related

How to restrict bound service to be called by particular packages

I have written a bound service and I would like this service to be only called from particular app. I do not want other apps to be able to make calls to this service.
The options I know so far are:
Use a permission. There seems to be 3 secured permission, dangerous, signature and signatureOrSystem. Unfortunately, none of these permissions will work for me as I don't want users to accept this permission also both app does not have same signature and these are not system app.
Get app name on service bind or when making a call to service. I looked up a way to do this on stackoverflow here. This unfortunately does not works for me as it always returns the app ID in which the service resides.
Is there any other option for me or I can use the above mentioned options with some change to achieve the desired requirement.
Bound Service Code
public class SampleCommsService extends Service {
private static Messenger messanger;
#Override
public IBinder onBind(Intent intent) {
Log.e("TEST", "package intent: " + intent.getPackage());
String callingApp = MyApplication.getAppContext().getPackageManager().getNameForUid(Binder.getCallingUid());
Log.e("TEST", "onBind - package name: " + callingApp);
return getMyBinder();
}
private synchronized IBinder getMyBinder() {
if (messanger == null) {
messanger = new Messenger(new SettingsProcessor());
}
return messanger.getBinder();
}
class SettingsProcessor extends Handler {
private static final int GET_SETTINGS_REQUEST = 1;
private static final int UPDATE_SETTINGS_RESPONSE = 2;
private static final String SETTINGS = "settings";
#Override
public void handleMessage(Message msg) {
String callingApp = MyApplication.getAppContext().getPackageManager().getNameForUid(Binder.getCallingUid());
Log.e("TEST", "handle message - package name: " + callingApp);
switch (msg.what) {
case GET_SETTINGS_REQUEST:
sendSettingsValue(msg);
break;
default:
super.handleMessage(msg);
}
}
private void sendSettingsValue(Message msg) {
try {
Message resp = Message.obtain(null, UPDATE_SETTINGS_RESPONSE);
Bundle bundle = new Bundle();
bundle.putBoolean(SETTINGS, MyApplication.isSettingsEnabled());
resp.setData(bundle);
msg.replyTo.send(resp);
} catch (RemoteException e) {
// ignore
}
}
}
}
Output on calling api:
02-01 15:21:03.138 7704-7704/my.service.package E/TEST: package intent: null
02-01 15:21:03.139 7704-7704/my.service.package E/TEST: onBind - package name: my.service.package
02-01 15:21:12.429 7704-7704/my.service.package E/TEST: handle message - package name: my.service.package
OK, I was able to solve this problem based on a given answer here. The answer given in the link obviously does not works, but you can get the app ID from the Handler used for the bound service.
class SettingsProcessor extends Handler {
#Override
public void handleMessage(Message msg) {
String callingApp = MyApplication.getAppContext().getPackageManager().getNameForUid(msg.sendingUid);
Log.e("TEST", "handle message - package name: " + callingApp);
}
}
Instead of Binder.getCallingUid(), I am using msg.sendingUid and it works fine for me.

Interprocess or adb communication with AndroidJUnit

I want to know, does any way exist to communicate with system during instrumentation test execution.
For example:
I have a phone with IR port on onboard & I can work with it through private SDK, also I can tune it with my application. In my Instrumentation test cases I want test app behavior based on external events which I want to configure before test separate test execution.
It's looks like
#Test
public void test() throws Exception {
setupExternalCondition(condition1_ON); // setup external transiver
assertNotNull(IR.read());
assertTrue(assertIR.write());
setupExternalCondition(condition1_OFF);
assertNotNull(IR.read());
assertFalse(IR.write());
}
It's very simple example but there is a lot of "conditions", and sdk updating frequencies to high. I can't do all of this verification manually, and can't ask "transiver&SDK team" make a mock states list for writing just a unit test for coverage. So I want somehow inject external component execution to TestRuner for receiving events(or testName before test case execution) on local machine(or CI machine) to setup external condition.
Simple solution(I think) to run a tcp server on appUnderTest and request external condition change - I am not sure does it possible, and not sure about stable connection(wifi), so may be it's possible to do over adb.
Any suggestions?
P.S: test device has root permissions.
So, find not bad but not ideal solution.
Still wait for better proposition, if not may be this answer will be helpful for someone;
For "building the bridge" between local machine and AndroidJUnitTest I add next class to tests:
class IPCServiceBridge extends BroadcastReceiver {
private static final String FILTER_ID = "IPC_SERVICE";
private static IPCServiceBridge sInstance;
private boolean mIsPermitted;
#Override
public void onReceive(Context context, Intent intent) {
if (intent.getAction().equals("ipc.service.action")) {
mIsPermitted = true;
}
}
public static IPCServiceBridge getInstance() {
if (sInstance == null) {
sInstance = new IPCServiceBridge();
IntentFilter filter = new IntentFilter();
filter.addAction("ipc.service.action");
Context context = InstrumentationRegistry.getContext();
context.registerReceiver(sInstance, filter);
}
return sInstance;
}
public void sendIpcCommand(String commandName) {
try {
int i = 30;
mIsPermitted = false;
while (i > 0) {
pub("request:" + commandName);
Thread.sleep(1000);
if (mIsPermitted) {
break;
}
i--;
}
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
if (!mIsPermitted) {
throw new RuntimeException("IPC service does not respond");
}
}
private static void pub(String msg) {
Log.e(FILTER_ID, msg);
}
}
Than I start adb logcat -s "filter_name", parse and check which condition should be applied for InsttUnit test. When conditions is ready i send back broadcast receiver with required action.
#Test
public void test2() throws Exception {
IPCServiceBridge.getInstance().sendIpcCommand("CONDITION#123");
}
Work good, but I'm not sure that it will be super stable.

How to prevent config class from getting freed, when APP in background

I made an Android APP, which has an config structure, which contains data,and services I need throughout all activities.
I now face the issue, that if my APP is in the background for a while, my APP crash, because my config structure has been deleted.
In my config structure, I also have data, I can not easily recreate at runtime.
So in my first Activity, I create the config structure.
FreightWeightConfig config = new FreightWeightConfig(getApplicationContext()); // make sure our config is up and running
And the start of my config class looks like
public FreightWeightConfig(Context appContext) {
instance = this;
mApplicationContext = appContext;
tcBlue.setCallingContext(appContext);
tcBlueConfig = Config.getInstance(); // to make sure it is available straight away
mFirebaseAuth = FirebaseAuth.getInstance();
....
}
I have a second function in the config structure, which allows me to get the instance of my config class, which I need to get access to functions and interfaces in config and services.
public static synchronized FreightWeightConfig getInstance () {
//if (FreightWeightConfig.instance == null) {
// FreightWeightConfig.instance = new FreightWeightConfig(getApplication().getApplicationContext());
//}
if (FreightWeightConfig.instance == null){
FirebaseCrash.logcat(Log.ERROR, LOG_TAG, "Fatal Error : FreightWeightConfig.getInstance()==null. Try restarting the APP");
FirebaseCrash.logcat(Log.ERROR, LOG_TAG, "Fatal Error : Killing ourself, as we have no chance to go on");
//System.exit(0); // we are in a bad state
// Toast.makeText(mApplicationContext, "Fatal Error : FreightWeightConfig.getInstance()==null. Try restarting the APP", Toast.LENGTH_SHORT).show();
}
return FreightWeightConfig.instance;
}
In every Activity, I created a variable that hold a copy the instance. This is simply, because I thought it tells the system, I still need this class, do not kill it. Which does not seem to work.
I first thought, whenever I find my config class to be dead, I can recreate it. But it is not a simple task, as I need the APP context and need to recreate my services in the background. Also I store selections made, while navigating my APP
Anyone has a good Idea, how to solve the unloading / deleting my config class?
Based on the suggestion I extended Application like this:
public class FreightWeightApp extends Application implements DialogInterface.OnCancelListener {
private String LOG_TAG = "FreightWeightApp";
private FreightWeightConfig config;
public static int GOOGLE_PLAY_SERVIE_ABBORTED = 1001;
public void onCreate() {
super.onCreate();
// We first check if the google services are present, if not, better abort!!
int result = GoogleApiAvailability.getInstance().isGooglePlayServicesAvailable(this);
switch (result) {
case SUCCESS:
Log.d(LOG_TAG, "Google Services available");
break;
case SERVICE_MISSING:
Log.e(LOG_TAG, "Google Services missing, STOP");
googleServiceNotUpToDateDialog(result);
break;
case SERVICE_VERSION_UPDATE_REQUIRED:
Log.w(LOG_TAG, "Service update required");
googleServiceNotUpToDateDialog(result);
break;
case SERVICE_DISABLED:
Log.e(LOG_TAG, "Service disabled, STOP");
googleServiceNotUpToDateDialog(result);
break;
}
config = new FreightWeightConfig(getApplicationContext()); // make sure our config is up and running
}
private void googleServiceNotUpToDateDialog(int result) {
// Try to ask the user to update or finish off
// GoogleApiAvailability gaa = GoogleApiAvailability.getInstance();
// Dialog dialog = gaa.getErrorDialog(this, result, GOOGLE_PLAY_SERVIE_ABBORTED, this); //<==== Can not call this, as I have no Activity Context
// dialog.show();
}
#Override
public void onCancel(DialogInterface dialogInterface) {
// Now I should abbort the APP, or we will crash.
}
}
But now I have issues with verifying the GoogleService.
Dialog dialog = gaa.getErrorDialog(this, result, GOOGLE_PLAY_SERVIE_ABBORTED, this);
as I have no Activity Context.
Create your own implementation of Application, then initialize your config object in the onCreate() method(in this case the getInstance() method could also initialize the object).
public class MyApplication extends Application {
#Override
public void onCreate() {
super.onCreate();
FreightWeightConfig config = FreightWeightConfig.getInstance(getApplicationContext());
}
}
Declare your implementation in your app's module manifest:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="your.package">
<application
android:name="your.package.MyApplication"
android:icon="#mipmap/ic_launcher"
android:label="#string/app_name"
android:theme="#style/AppTheme">
...
</application>
</manifest>
Now you can use your config instance in the activities just like you do, calling getInstance(); the Application onCreate will do the load work. But there is no way to "unload the resources before the app process gets killed/cached", you just have to understand how Android components' lifecycle works.

One of my Application's view inside my second application in android

I got stuck in to the problem where I need to show my first application in to some area of second application's screen. Both codes are under my control. Can any one suggest me where should I proceed as I am not getting any clue about the situation.
if some one help me for the issue, it would be a great help for me.
Or
If I can open both of my applications using the multiscreen option available in S3.
Write a service on either of your application or a individual application. Have AIDL(Android Interface Definition Language) defined as IRemoteService.aidl, the below is my pseudo code or sample implementation. Using this approach you can start activity and handle events of another application through your application.
// IRemoteService.aidl
// Declare any non-default types here with import statements
/** Example service interface */
interface IAccountService {
String getLoggedInUserInfo(String appId);
void userLogin(String appId,ILoginCallback cb);
void signout(String appId);
}
interface ILoginCallback {
void loginSuccess(String userId);
void loginFailed();
}
In your service have some RemoteCallbacks
#Override
public IBinder onBind(Intent intent) {
final RemoteCallbackList<ILoginCallback> mCallbacks = new RemoteCallbackList<ILoginCallback>();
if(mCallbacks!=null){
int i = mCallbacks.beginBroadcast();
while(i>0){
i--;
try {
Log.e(TAG, "Callback ...");
mCallbacks.getBroadcastItem(i).loginSuccess(newUserId);
} catch (RemoteException e) {
// The RemoteCallbackList will take care of removing
// the dead object for us.
}
}
mCallbacks.finishBroadcast();
}
}
private final IAccountService.Stub mBinder = new IAccountService.Stub() {
#Override
public void userLogin(String appId,ILoginCallback cb) throws RemoteException {
String userId = Settings.getSettings().getUserId();
if(userId ==null||userId.length()==0){
mCallbacks.register(cb);
Intent intent = new Intent(getApplicationContext(), AccountLoginActivity.class);
intent.putExtra("deviceId", Settings.getSettings().getDeviceUniqueId());
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intent);
}
}
}
You can find detailed AIDL examples in the below links.
http://owenhuangtw.pixnet.net/blog/post/23760257-android-aidl-(android-interface-definition-language)
http://www.app-solut.com/blog/2011/04/using-the-android-interface-definition-language-aidl-to-make-a-remote-procedure-call-rpc-in-android/
https://github.com/afollestad/aidl-example

Android WebView No permission to modify given thread, which permission should I declare?

crash log:
java.lang.SecurityException: No permission to modify given thread
android.os.Process.setThreadPriority(Native Method)
android.webkit.WebViewCore$WebCoreThread$1.handleMessage(WebViewCore.java:764)
android.os.Handler.dispatchMessage(Handler.java:99)
android.os.Looper.loop(Looper.java:137)
android.webkit.WebViewCore$WebCoreThread.run(WebViewCore.java:829)
java.lang.Thread.run(Thread.java:856)
which permission should I declare?
http://developer.android.com/reference/android/Manifest.permission.html
edit:
I found a similar problem in WebView java.lang.SecurityException: No permission to modify given thread
The Answer say "It's cyanogen's fault."
However, in the thread http://code.google.com/p/cyanogenmod/issues/detail?id=5656&thanks=5656&ts=1341224425,cm menbers seem to deny it's CM's bug
Above all, my question is:
How to fix it from my app?
which permission should I declare?
There is no relevant permission for this AFAIK. Unfortunately, the implementation of setThreadPriority() is in native code, which makes it difficult for me to figure out what is going on.
cm menbers seem to deny it's CM's bug
No, they do not. Nobody has posted evidence that it is a problem in CM9 or higher, which is why they marked the issue as stale. If you are seeing this on CM9 or higher, I suggest that you update the issue. If you are seeing this on standard Android, please create a sample project that can reproduce the error.
How to fix it from my app?
You don't, in all likelihood. You could try running some experiments on your WebView, to see if there is some specific content that triggers this exception, and try to modify or eliminate that content.
I get dozens of crash log caused by this exception from my app (which depends on webview heavily), involved ROM version are 4.0.4 and 4.0.3.
It seems that there is no normal way to fix it, so i tried following hacking approach.
code snipet on 4.0.4:
private static Handler sWebCoreHandler;
// Class for providing Handler creation inside the WebCore thread.
private static class WebCoreThread implements Runnable {
// Message id for initializing a new WebViewCore.
private static final int INITIALIZE = 0;
private static final int REDUCE_PRIORITY = 1;
private static final int RESUME_PRIORITY = 2;
public void run() {
Looper.prepare();
Assert.assertNull(sWebCoreHandler);
synchronized (WebViewCore.class) {
sWebCoreHandler = new Handler() {
#Override
public void handleMessage(Message msg) {
// ...
// Process.setPriority(...)
}
};
// ...
}
// ...
}
}
I think this exception is thrown from sWebCoreHandler.handleMessage(), if we can wrap try/catch on handleMessage(), the problem could be fixed.
Handler class has four members:
final MessageQueue mQueue;
final Looper mLooper;
final Callback mCallback;
IMessenger mMessenger;
mQueue is set as mLooper.mQueue, mCallback is null in sWebCoreHandler, so we just need to set mLooper and mMessenger with values in sWebCoreHandler.
static Handler sProxyHandler = null;
static void tryTweakWebCoreHandler() {
// 4.0.3/4.0.4 rom
if (Build.VERSION.SDK_INT == Build.VERSION_CODES.ICE_CREAM_SANDWICH_MR1) {
tweakWebCoreHandle();
}
}
static private void tweakWebCoreHandle() {
if (sProxyHandler != null)
return;
try {
Field f = Class.forName("android.webkit.WebViewCore").getDeclaredField("sWebCoreHandler");
f.setAccessible(true);
Object h = f.get(null);
Object mMessenger = null;
Method m = Handler.class.getDeclaredMethod("getIMessenger", (Class<?>[])null);
m.setAccessible(true);
mMessenger = m.invoke(h, (Object[])null);
sProxyHandler = new WebCoreProxyHandler((Handler)h);
if (mMessenger != null) {
Field f1 = Handler.class.getDeclaredField("mMessenger");
f1.setAccessible(true);
f1.set(sProxyHandler, mMessenger);
}
f.set(null, sProxyHandler);
// Log.w(TAG, "sWebCoreHandler: " + h);
} catch (Throwable e) {
Log.w(TAG, "exception: " + e);
}
if (sProxyHandler == null)
sProxyHandler = new Handler();
}
static class WebCoreProxyHandler extends Handler {
final Handler handler;
public WebCoreProxyHandler(Handler handler) {
super(handler.getLooper());
this.handler = handler;
}
public void handleMessage(Message msg) {
// Log.w("WebCoreProxyHandler", "handle msg: " + msg.what);
try {
handler.handleMessage(msg);
} catch (Throwable tr) {
Log.w("WebCoreProxyHandler", "exception: " + tr);
}
}
}
Remain problem is when to invoke tryTweakWebCoreHandler(). I tried to invoke it after a WebView instance is created and tested on some devices, WebCoreProxyHandler.handleMessage() can be called.
Note: i just made some simple test, i'm not sure this problem is resolved as the origin exception can not be reproduced reliably.
If you decide to try this approach, please do enough test.

Categories

Resources