Practical Exercise – Intercepting Stitch’s Broadcast

Table of Contents

Table of Contents

1.MainActivity

2.MainActivity2

3.MyHelper

4.OutCallReceiver

5.activity_main.xml

6.activity_main2.xml

7.item.xml

8.themes.xml

9. Project code layout

10. Operation status display

11. Common errors reported in this project and their solutions


Complete an app that intercepts dialing, including the following functions:

  1. Main functions: Save the number set by the user and intercept dialing to the number.
  2. Database: Save intercepted information, number, time or number of times, etc.
  1. Broadcast receiver: Perform dialing interception based on the saved number, save the interception information to the database, and jump to interface 2.
  1. Contains two interfaces:

Interface 1 (main interface) content: save interception numbers and display historical interception information;

Interface 2 content: Prompts the user that the dial-up has been intercepted, and the interface theme is set to a dialog-type theme.

Tip: Permissions required




Dynamic permission application:

public final void requestPermissions(

String[] permissions,

int requestCode)

When jumping to Activity2, you need to set intent1.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);

1.MainActivity


import androidx.appcompat.app.AppCompatActivity;

import android.os.Bundle;

import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;

import android.content.IntentFilter;
import android.content.SharedPreferences;
import android.content.pm.PackageManager;
import android.os.Bundle;
import android.os.health.PackageHealthStats;
import android.view.Display;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;
import android.widget.Toast;

import java.util.List;
import java.util.Map;

public class MainActivity extends AppCompatActivity {

    private EditText et_ipnumber;
    private SharedPreferences sp;
    private RecyclerView rv;
    private TextView update;
    private MyAdapter myAdapter;
    private List<Map<String, String>> datas;
    private OutCallReceiver receiver;
    private static final int FlatRequestCode = 1002;
    private final String[] permissions = {"android.permission.READ_PHONE_STATE","android.permission.PROCESS_OUTGOING_CALLS","android.permission.SYSTEM_ALERT_WINDOW","android.permission.SYSTEM_OVERLAY_WINDOW"};

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        if (!checkPermission()) {
            requestPermissions(permissions, 1);
        }

        MyHelper myHelper = new MyHelper(this);
        datas = myHelper.getAll();

        IntentFilter intentFilter = new IntentFilter();
        intentFilter.addAction("android.intent.action.NEW_OUTGOING_CALLS");
        intentFilter.addAction("android.intent.action.READ_PHONE_STATE");
        receiver = new OutCallReceiver();
        registerReceiver(receiver, intentFilter);

        rv = findViewById(R.id.rv);
        myAdapter = new MyAdapter();
        rv.setAdapter(myAdapter);
        rv.setLayoutManager(new LinearLayoutManager(this));

        Button button = findViewById(R.id.btn_intercept);
        button.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {

                et_ipnumber = findViewById(R.id.et_ipnumber);
                String number = et_ipnumber.getText().toString().trim();
                sp = getSharedPreferences("itercept", MODE_PRIVATE);

                SharedPreferences.Editor editor = sp.edit();
                editor.putString("number", number);
                editor.commit();
                Toast.makeText(MainActivity.this, "Save successfully", Toast.LENGTH_SHORT).show();
            }
        });

        update = findViewById(R.id.tv_update);
        update.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                datas = myHelper.getAll();
                myAdapter.notifyDataSetChanged();
            }
        });

    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        unregisterReceiver(receiver);
    }


    private boolean checkPermission() {
        for (String p:permissions) {
            if (checkSelfPermission(p) != PackageManager.PERMISSION_GRANTED) {
                return false;
            }
        }
        return true;
    }

    class MyAdapter extends RecyclerView.Adapter<MyHolder> {

        @NonNull
        @Override
        public MyHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
            View view = LayoutInflater.from(MainActivity.this).inflate(R.layout.item, parent, false);
            MyHolder holder = new MyHolder(view);
            return holder;
        }

        @Override
        public void onBindViewHolder(@NonNull MyHolder holder, int position) {
            String number = (String) datas.get(position).get("number");
            String time = (String) datas.get(position).get("time");
            holder.tv_number.setText(number);
            holder.tv_time.setText(time);
        }

        @Override
        public int getItemCount() {
            return datas.size();
        }
    }

    class MyHolder extends RecyclerView.ViewHolder {
        TextView tv_number;
        TextView tv_time;
        public MyHolder(@NonNull View itemView) {
            super(itemView);
            tv_number = itemView.findViewById(R.id.tv_number);
            tv_time = itemView.findViewById(R.id.tv_time);
        }
    }

}

2.MainActivity2

import androidx.appcompat.app.AppCompatActivity;

import android.os.Bundle;

public class MainActivity2 extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main2);
    }
}

3.MyHelper

import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;

import androidx.appcompat.widget.ActionBarContextView;

import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class MyHelper extends SQLiteOpenHelper {

    private static final int version = 1;
    private static final String db_name = "intercept.db";
    MyHelper(Context context) {
        super(context, db_name, null, 1);
    }
    @Override
    public void onCreate(SQLiteDatabase db) {
        db.execSQL("CREATE TABLE call(_id INTEGER PRIMARY KEY AUTOINCREMENT, number VARCHAR(20), time VARCHAR(20))");
    }

    @Override
    public void onUpgrade(SQLiteDatabase sqLiteDatabase, int oldVersion, int newVersion) {

    }

    public void insert(String number) {
        Calendar calendar = Calendar.getInstance();
        Date date = calendar.getTime();
        SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        String formattedDate = dateFormat.format(date);
        SQLiteDatabase db = getWritableDatabase();
        ContentValues value = new ContentValues();
        value.put("number", number);
        value.put("time", formattedDate);
        db.insert("call", null, value);
        db.close();
    }

    public void delete(String number) {
        SQLiteDatabase db = getWritableDatabase();
        db.delete("call", "number=?", new String[]{number + ""});
        db.close();
    }

    public List<Map<String, String>> getAll() {
        List<Map<String, String>> result = new ArrayList<>();
        SQLiteDatabase db = getReadableDatabase();
        Cursor cursor = db.query("call", null, null, null, null, null, null);
        if (cursor.getCount() != 0) {
            while (cursor.moveToNext()) {
                Map<String, String> map = new HashMap<>();
                String number = cursor.getString(1);
                String time = cursor.getString(2);
                map.put("number", number);
                map.put("time", time);
                result.add(map);
            }
        }
        cursor.close();
        db.close();
        return result;
    }

}

4.OutCallReceiver

import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;

public class OutCallReceiver extends BroadcastReceiver {

    @Override
    public void onReceive(Context context, Intent intent) {
        // TODO: This method is called when the BroadcastReceiver is receiving
        // an Intent broadcast.
        SharedPreferences sp = context.getSharedPreferences("itercept", context.MODE_PRIVATE);
        String number = sp.getString("number", "");
        String outcallnumber = intent.getStringExtra(Intent.EXTRA_PHONE_NUMBER);
        if (outcallnumber.equals(number)) {
            setResultData(null);
            MyHelper myHelper = new MyHelper(context);
            myHelper.insert(number);
        }

        Intent intent1 = new Intent();
        intent1.setClass(context, MainActivity2.class);
        intent1.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
        context.startActivity(intent1);
    }
}

5.activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="#FFFFF0"
    android:padding="15dp"
    tools:context=".MainActivity"
    android:orientation="vertical">
    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginBottom="10dp">
        <EditText
            android:id="@ + id/et_ipnumber"
            android:layout_width="0dp"
            android:layout_weight="1"
            android:layout_height="wrap_content"
            android:hint="Please enter the blocking number"/>
        <Button
            android:id="@ + id/btn_intercept"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:background="#ACD6FF"
            android:text="Save interception number"
            android:textSize="16sp"/>
    </LinearLayout>
    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="vertical"
        android:background="#ACD6FF">
        <TextView
            android:id="@ + id/tv_update"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:paddingTop="5dp"
            android:paddingRight="8dp"
            android:paddingBottom="2dp"
            android:text="Historical interception information"
            android:textColor="#330000"
            android:textSize="18sp"
            android:layout_gravity="center"/>
        <androidx.recyclerview.widget.RecyclerView
            android:id="@ + id/rv"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"/>
    </LinearLayout>
</LinearLayout>

6.activity_main2.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="#FFFFF0"
    tools:context=".MainActivity2">

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:padding="15dp"
        android:text="Don't make trouble, study hard, and take class seriously! Don't make phone calls!"
        android:textSize="26sp"/>

</LinearLayout>

7.item.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:padding="5dp">

    <TextView
        android:id="@ + id/tv_number"
        android:text="phone number"
        android:layout_width="0dp"
        android:layout_weight="2"
        android:layout_height="wrap_content"/>

    <TextView
        android:id="@ + id/tv_time"
        android:text="Interception time"
        android:layout_width="0dp"
        android:layout_weight="1"
        android:layout_height="wrap_content"/>

</LinearLayout>

8.themes.xml

<resources xmlns:tools="http://schemas.android.com/tools">
    <!-- Base application theme. -->
    <style name="Theme.Assess" parent="Theme.MaterialComponents.DayNight.DarkActionBar">
        <!-- Primary brand color. -->
        <item name="colorPrimary">@color/purple_500</item>
        <item name="colorPrimaryVariant">@color/purple_700</item>
        <item name="colorOnPrimary">@color/white</item>
        <!-- Secondary brand color. -->
        <item name="colorSecondary">@color/teal_200</item>
        <item name="colorSecondaryVariant">@color/teal_700</item>
        <item name="colorOnSecondary">@color/black</item>
        <!-- Status bar color. -->
        <item name="android:statusBarColor">?attr/colorPrimaryVariant</item>
        <!-- Customize your theme here. -->
    </style>
    <style name="DialogActivity" parent="Theme.AppCompat.Light.Dialog">
        <item name="colorPrimary">@color/purple_200</item>
        <item name="colorPrimaryVariant">@color/purple_500</item>
        <item name="colorOnPrimary">@color/black</item>
        <!-- Secondary brand color. -->
        <item name="colorSecondary">@color/teal_200</item>
        <item name="colorSecondaryVariant">@color/teal_700</item>
        <item name="colorOnSecondary">@color/black</item>
        <!-- Status bar color. -->
        <item name="android:statusBarColor">?attr/colorPrimaryVariant</item>
        <!-- Customize your theme here. -->
    </style>
</resources>

8.AndroidManifest.xml

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools">

    <uses-feature
        android:name="android.hardware.telephony"
        android:required="false" />

    <uses-permission android:name="android.permission.READ_PHONE_STATE" />
    <uses-permission android:name="android.permission.PROCESS_OUTGOING_CALLS" />
    <uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
    <uses-permission android:name="android.permission.SYSTEM_OVERLAY_WINDOW" />

    <application
        android:allowBackup="true"
        android:dataExtractionRules="@xml/data_extraction_rules"
        android:fullBackupContent="@xml/backup_rules"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/Theme.Assess"
        tools:targetApi="31">

        <activity
            android:name=".MainActivity2"
            android:exported="false"
            android:theme="@style/DialogActivity"/>
        <activity
            android:name=".MainActivity"
            android:exported="true">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>

        <receiver
            android:name=".OutCallReceiver"
            android:enabled="true"
            android:exported="true">
            <intent-filter android:priority="1000">
                <action android:name="android.intent.action.NEW_OUTGOING_CALL"/>
            </intent-filter>
        </receiver>
    </application>

</manifest>

9. Project code layout

10. Operation status display

11. Common errors and solutions for this project

1. The theme in the values folder must be written well, as it is easy to make mistakes here.

2. Learn to check the error messages displayed in logcat