Caller ID

Posted by emrys404 on Fri, 04 Mar 2022 12:22:57 +0100

Caller show - caller tagging

The company's office app has its own address book. Sometimes when others call, the contact information of this contact is not saved in the mobile phone, and they are afraid of harassment after receiving the call. Therefore, I want to add an incoming call tag of our company, that is, the incoming call show function.
When a colleague of our company calls, a call show page will pop up on the mobile phone, showing the avatar, name and department information. It can be clear at a glance and reduce the frequency of answering harassing calls. At the same time, this has also become a postcard of our company. Only the phone (mobile phone, Landline) of our colleagues will trigger the call show function.

difficulty

As we all know, with the version upgrade of android system, the restrictions on third-party apps become more and more severe. After the app enters the background, it will be killed soon, and the network requests will be frozen. Therefore, when your app is killed, the tasks performed in the background cannot be completed. The call show function requires the app to survive in the background and the network request is not frozen to complete. Therefore, keeping the process alive is a difficulty that needs to be considered.

1, Principle analysis

When the mobile phone calls, get the call number, send it to the office background for query, find the returned avatar, name and department information, and pop up a floating window to cover the call interface for display; If it is not found, it will not be displayed. When the phone is connected, just eliminate the suspension window.

2, Effect style

Design episode: the style of this card has been discussed for many times, such as location, background color, under what circumstances to show, etc. in fact, we didn't reach an agreement in the end, because there are too many scenes to consider, and none of them can fully meet all the scenes. In the end, we can only compromise.

3, Code implementation

Register the broadcast receiver and process the broadcast logic. Most of the Internet uses the telephone manager In the listen (phonestatelistener) mode, the callback will be disordered in the case of some mobile phones with dual cards after testing, and there are bug s in the system processing logic, so the system interface is not adopted in this paper. Instead, listen to the broadcast and deal with it by yourself.
Some main codes are as follows:

  @Override
    public void onReceive(Context context, Intent intent) {
        mcontext = context;
        if (hanler == null) {
            hanler = new Handler();
        }
        String action = intent.getAction();
        inflate = LayoutInflater.from(context);
        if (intent.getAction().equals(Intent.ACTION_NEW_OUTGOING_CALL)) {
            Log.e("TAG", "Dial out");
        } else {
            Log.e("TAG", "Call ");
            // Get current phone status
            String state = intent.getStringExtra(TelephonyManager.EXTRA_STATE);
            String number = intent.getStringExtra(TelephonyManager.EXTRA_INCOMING_NUMBER);
            Log.d("TAG", " onReceive state: " + state + " number==" + number);
            if ("RINGING".equals(state)) {
                Log.e("TAG", "Call RINGING ");
                String incomingNumber = intent.getStringExtra(TelephonyManager.EXTRA_INCOMING_NUMBER);
                if(!TextUtils.isEmpty(number)){
                    Log.e("TAG", "Call RINGING incomingNumber=="+incomingNumber);
                    queryNumber(incomingNumber);
                }
            }else if ("OFFHOOK".equals(state)) {
                try{
                    Log.d("TAG", "Call OFFHOOK ");
                    if (wm != null && phoneView != null && phoneView.getParent() != null) {  //The current strategy is connected and eliminated
                        if (animator != null) {
                            animator.cancel();
                        }
                        wm.removeViewImmediate(phoneView);
                        hanler.removeCallbacks(runnable);
                    }
                 }catch (Exception e){
                    e.printStackTrace();
                 }
            }else if ("IDLE".equals(state)) {
                try {
                    Log.d("TAG", "Call IDLE ");
                    if (wm != null && phoneView != null && phoneView.getParent() != null) {
                        if (animator != null) {
                            animator.cancel();
                        }
                        wm.removeViewImmediate(phoneView);
                        hanler.removeCallbacks(runnable);
                    }
                 } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }
    }

In the case of only using the receiver mode, even if the application may not be killed in the background, the network request may be frozen, resulting in the inability to query the number. When you open your application again, the query request will continue and the result will return, resulting in a floating window covering the application, resulting in a bug
In order to avoid this situation as far as possible, keep alive mode is adopted, and broadcast registration is carried out in ListenInCallService.

 @Override
    public void onCreate() {
        super.onCreate();
        if (mScreenOnOffReceiver == null) {
            mScreenOnOffReceiver = new ScreenOnOffReceiver();
        }
        IntentFilter intentFilter = new IntentFilter();
        intentFilter.addAction("android.intent.action.SCREEN_OFF");
        intentFilter.addAction("android.intent.action.SCREEN_ON");
        intentFilter.setPriority(IntentFilter.SYSTEM_HIGH_PRIORITY);
        registerReceiver(mScreenOnOffReceiver, intentFilter);

        if (phoneReceiver == null) {
            phoneReceiver = new PhoneReceiver();
        }
        IntentFilter intentFilter1 = new IntentFilter();
        intentFilter1.addAction("android.intent.action.PHONE_STATE");
        intentFilter1.addAction("android.intent.action.PHONE_STATE_2");
        intentFilter1.addAction("android.intent.action.NEW_OUTGOING_CALL");
        intentFilter1.setPriority(IntentFilter.SYSTEM_HIGH_PRIORITY);
        registerReceiver(phoneReceiver, intentFilter1);

       ......
    }

Finally, combined with the keep alive scheme, make the application survive and the ListenInCallService survive as much as possible, and improve the process priority to prevent the network request from being frozen. Finally, don't forget all kinds of permissions.

Topics: Java Android Design Pattern app