Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 9c9175fc authored by roldenburg's avatar roldenburg Committed by Ryan Oldenburg
Browse files

Show IMEI/MEID in hex, dec, and barcode when appropriate

Bug: 69063060,71706655
Test: SpecialCharSequenceMgrTest
PiperOrigin-RevId: 185910798
Change-Id: I60a614d5357809eb982991caa4765d08a53fe936
parent c54ce265
Loading
Loading
Loading
Loading
+12 −0
Original line number Diff line number Diff line
@@ -111,6 +111,7 @@ LOCAL_STATIC_JAVA_LIBRARIES := \
	dialer-guava-target \
	dialer-glide-target \
	dialer-glide-annotation-target \
	dialer-zxing-target \
	jsr305 \
	libbackup \
	libphonenumber \
@@ -408,3 +409,14 @@ LOCAL_UNINSTALLABLE_MODULE := true
include $(BUILD_PREBUILT)

include $(CLEAR_VARS)

LOCAL_MODULE_CLASS := JAVA_LIBRARIES
LOCAL_MODULE := dialer-zxing-target
LOCAL_SDK_VERSION := current
LOCAL_SRC_FILES := ../../../external/zxing/core/core.jar
LOCAL_UNINSTALLABLE_MODULE := true

include $(BUILD_PREBUILT)

include $(CLEAR_VARS)
+138 −9
Original line number Diff line number Diff line
@@ -17,6 +17,7 @@
package com.android.dialer.dialpadview;

import android.Manifest;
import android.annotation.SuppressLint;
import android.app.Activity;
import android.app.AlertDialog;
import android.app.DialogFragment;
@@ -28,6 +29,9 @@ import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.database.Cursor;
import android.graphics.Bitmap;
import android.graphics.Bitmap.Config;
import android.graphics.Color;
import android.net.Uri;
import android.provider.Settings;
import android.support.annotation.Nullable;
@@ -37,8 +41,15 @@ import android.telecom.PhoneAccountHandle;
import android.telephony.PhoneNumberUtils;
import android.telephony.TelephonyManager;
import android.text.TextUtils;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.ViewGroup.LayoutParams;
import android.view.ViewTreeObserver.OnGlobalLayoutListener;
import android.view.WindowManager;
import android.widget.EditText;
import android.widget.ImageView;
import android.widget.TextView;
import android.widget.Toast;
import com.android.common.io.MoreCloseables;
import com.android.contacts.common.database.NoNullCursorAsyncQueryHandler;
@@ -51,8 +62,14 @@ import com.android.dialer.compat.telephony.TelephonyManagerCompat;
import com.android.dialer.oem.MotorolaUtils;
import com.android.dialer.telecom.TelecomUtil;
import com.android.dialer.util.PermissionsUtil;
import com.google.zxing.BarcodeFormat;
import com.google.zxing.MultiFormatWriter;
import com.google.zxing.WriterException;
import com.google.zxing.common.BitMatrix;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Locale;

/**
 * Helper class to listen for some magic character sequences that are handled specially by the
@@ -66,12 +83,9 @@ import java.util.List;
 * shared library?)
 */
public class SpecialCharSequenceMgr {

  private static final String TAG = "SpecialCharSequenceMgr";

  private static final String TAG_SELECT_ACCT_FRAGMENT = "tag_select_acct_fragment";

  private static final String MMI_IMEI_DISPLAY = "*#06#";
  @VisibleForTesting static final String MMI_IMEI_DISPLAY = "*#06#";
  private static final String MMI_REGULATORY_INFO_DISPLAY = "*#07#";
  /** ***** This code is used to handle SIM Contact queries ***** */
  private static final String ADN_PHONE_NUMBER_COLUMN_NAME = "number";
@@ -306,6 +320,7 @@ public class SpecialCharSequenceMgr {

  // TODO: Use TelephonyCapabilities.getDeviceIdLabel() to get the device id label instead of a
  // hard-coded string.
  @SuppressLint("HardwareIds")
  static boolean handleDeviceIdDisplay(Context context, String input) {
    if (!PermissionsUtil.hasPermission(context, Manifest.permission.READ_PHONE_STATE)) {
      return false;
@@ -319,29 +334,143 @@ public class SpecialCharSequenceMgr {
              ? R.string.imei
              : R.string.meid;

      List<String> deviceIds = new ArrayList<String>();
      View customView = LayoutInflater.from(context).inflate(R.layout.dialog_deviceids, null);
      ViewGroup holder = customView.findViewById(R.id.deviceids_holder);

      if (TelephonyManagerCompat.getPhoneCount(telephonyManager) > 1) {
        for (int slot = 0; slot < telephonyManager.getPhoneCount(); slot++) {
          String deviceId = telephonyManager.getDeviceId(slot);
          if (!TextUtils.isEmpty(deviceId)) {
            deviceIds.add(deviceId);
            addDeviceIdRow(holder, deviceId, /* showBarcode */ false);
          }
        }
      } else {
        deviceIds.add(telephonyManager.getDeviceId());
        addDeviceIdRow(holder, telephonyManager.getDeviceId(), /* showBarcode */ true);
      }

      new AlertDialog.Builder(context)
          .setTitle(labelResId)
          .setItems(deviceIds.toArray(new String[deviceIds.size()]), null)
          .setView(customView)
          .setPositiveButton(android.R.string.ok, null)
          .setCancelable(false)
          .show();
          .show()
          .getWindow()
          .setLayout(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT);
      return true;
    }
    return false;
  }

  private static void addDeviceIdRow(ViewGroup holder, String deviceId, boolean showBarcode) {
    if (TextUtils.isEmpty(deviceId)) {
      return;
    }

    ViewGroup row =
        (ViewGroup)
            LayoutInflater.from(holder.getContext()).inflate(R.layout.row_deviceid, holder, false);
    holder.addView(row);

    // Remove the check digit, if exists. This digit is a checksum of the ID.
    // See https://en.wikipedia.org/wiki/International_Mobile_Equipment_Identity
    // and https://en.wikipedia.org/wiki/Mobile_equipment_identifier
    String hex = deviceId.length() == 15 ? deviceId.substring(0, 14) : deviceId;

    // If this is the valid length IMEI or MEID (14 digits), show it in all formats, otherwise fall
    // back to just showing the raw hex
    if (hex.length() == 14) {
      ((TextView) row.findViewById(R.id.deviceid_hex)).setText(hex);
      ((TextView) row.findViewById(R.id.deviceid_dec)).setText(getDecimalFromHex(hex));
      row.findViewById(R.id.deviceid_dec_label).setVisibility(View.VISIBLE);
    } else {
      ((TextView) row.findViewById(R.id.deviceid_hex)).setText(deviceId);
    }

    final ImageView barcode = row.findViewById(R.id.deviceid_barcode);
    if (showBarcode) {
      // Wait until the layout pass has completed so we the barcode is measured before drawing. We
      // do this by adding a layout listener and setting the bitmap after getting the callback.
      barcode
          .getViewTreeObserver()
          .addOnGlobalLayoutListener(
              new OnGlobalLayoutListener() {
                @Override
                public void onGlobalLayout() {
                  barcode.getViewTreeObserver().removeOnGlobalLayoutListener(this);
                  Bitmap barcodeBitmap =
                      generateBarcode(hex, barcode.getWidth(), barcode.getHeight());
                  if (barcodeBitmap != null) {
                    barcode.setImageBitmap(barcodeBitmap);
                  }
                }
              });
    } else {
      barcode.setVisibility(View.GONE);
    }
  }

  private static String getDecimalFromHex(String hex) {
    final String part1 = hex.substring(0, 8);
    final String part2 = hex.substring(8);

    long dec1;
    try {
      dec1 = Long.parseLong(part1, 16);
    } catch (NumberFormatException e) {
      LogUtil.e("SpecialCharSequenceMgr.getDecimalFromHex", "unable to parse hex", e);
      return "";
    }

    final String manufacturerCode = String.format(Locale.US, "%010d", dec1);

    long dec2;
    try {
      dec2 = Long.parseLong(part2, 16);
    } catch (NumberFormatException e) {
      LogUtil.e("SpecialCharSequenceMgr.getDecimalFromHex", "unable to parse hex", e);
      return "";
    }

    final String serialNum = String.format(Locale.US, "%08d", dec2);

    StringBuilder builder = new StringBuilder(22);
    builder
        .append(manufacturerCode, 0, 5)
        .append(' ')
        .append(manufacturerCode, 5, manufacturerCode.length())
        .append(' ')
        .append(serialNum, 0, 4)
        .append(' ')
        .append(serialNum, 4, serialNum.length());
    return builder.toString();
  }

  /**
   * This method generates a 2d barcode using the zxing library. Each pixel of the bitmap is either
   * black or white painted vertically. We determine which color using the BitMatrix.get(x, y)
   * method.
   */
  private static Bitmap generateBarcode(String hex, int width, int height) {
    MultiFormatWriter writer = new MultiFormatWriter();
    String data = Uri.encode(hex);

    try {
      BitMatrix bitMatrix = writer.encode(data, BarcodeFormat.CODE_128, width, 1);
      Bitmap bitmap = Bitmap.createBitmap(bitMatrix.getWidth(), height, Config.RGB_565);

      for (int i = 0; i < bitMatrix.getWidth(); i++) {
        // Paint columns of width 1
        int[] column = new int[height];
        Arrays.fill(column, bitMatrix.get(i, 0) ? Color.BLACK : Color.WHITE);
        bitmap.setPixels(column, 0, 1, i, 0, 1, height);
      }
      return bitmap;
    } catch (WriterException e) {
      LogUtil.e("SpecialCharSequenceMgr.generateBarcode", "error generating barcode", e);
    }
    return null;
  }

  private static boolean handleRegulatoryInfoDisplay(Context context, String input) {
    if (input.equals(MMI_REGULATORY_INFO_DISPLAY)) {
      LogUtil.i(
+26 −0
Original line number Diff line number Diff line
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (C) 2018 The Android Open Source Project

     Licensed under the Apache License, Version 2.0 (the "License");
     you may not use this file except in compliance with the License.
     You may obtain a copy of the License at

          http://www.apache.org/licenses/LICENSE-2.0

     Unless required by applicable law or agreed to in writing, software
     distributed under the License is distributed on an "AS IS" BASIS,
     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     See the License for the specific language governing permissions and
     limitations under the License.
-->
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent">
  <LinearLayout
      android:id="@+id/deviceids_holder"
      android:layout_width="match_parent"
      android:layout_height="wrap_content"
      android:paddingStart="?dialogPreferredPadding"
      android:paddingEnd="?dialogPreferredPadding"
      android:orientation="vertical"/>
</ScrollView>
+49 −0
Original line number Diff line number Diff line
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (C) 2018 The Android Open Source Project

     Licensed under the Apache License, Version 2.0 (the "License");
     you may not use this file except in compliance with the License.
     You may obtain a copy of the License at

          http://www.apache.org/licenses/LICENSE-2.0

     Unless required by applicable law or agreed to in writing, software
     distributed under the License is distributed on an "AS IS" BASIS,
     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     See the License for the specific language governing permissions and
     limitations under the License.
-->
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:layout_marginTop="?dialogPreferredPadding"
    android:orientation="vertical">
  <TextView
      style="@style/DeviceIdBody"
      android:layout_width="wrap_content"
      android:layout_height="wrap_content"
      android:text="@string/hex"/>
  <TextView
      android:id="@+id/deviceid_hex"
      style="@style/DeviceIdBody"
      android:layout_width="wrap_content"
      android:layout_height="wrap_content"/>
  <TextView
      android:id="@+id/deviceid_dec_label"
      style="@style/DeviceIdBody"
      android:layout_width="wrap_content"
      android:layout_height="wrap_content"
      android:text="@string/dec"
      android:visibility="gone"/>
  <TextView
      android:id="@+id/deviceid_dec"
      style="@style/DeviceIdBody"
      android:layout_width="wrap_content"
      android:layout_height="wrap_content"/>
  <ImageView
      android:id="@+id/deviceid_barcode"
      android:layout_width="match_parent"
      android:layout_height="@dimen/barcode_height"
      android:layout_margin="24dp"
      android:layout_gravity="center_horizontal"/>
</LinearLayout>
+2 −0
Original line number Diff line number Diff line
@@ -43,4 +43,6 @@

  <!-- Length of dialpad's shadows in dialer. -->
  <dimen name="shadow_length">10dp</dimen>

  <dimen name="barcode_height">100dp</dimen>
</resources>
Loading