From 9c9175fc3cf874d7b1e8f6334b8ba709a9e3a310 Mon Sep 17 00:00:00 2001 From: roldenburg Date: Thu, 15 Feb 2018 15:22:24 -0800 Subject: Show IMEI/MEID in hex, dec, and barcode when appropriate Bug: 69063060,71706655 Test: SpecialCharSequenceMgrTest PiperOrigin-RevId: 185910798 Change-Id: I60a614d5357809eb982991caa4765d08a53fe936 --- .../dialer/dialpadview/SpecialCharSequenceMgr.java | 147 +++++++++++++++++++-- .../dialpadview/res/layout/dialog_deviceids.xml | 26 ++++ .../dialer/dialpadview/res/layout/row_deviceid.xml | 49 +++++++ .../dialer/dialpadview/res/values/dimens.xml | 2 + .../dialer/dialpadview/res/values/strings.xml | 6 + .../dialer/dialpadview/res/values/styles.xml | 5 + 6 files changed, 226 insertions(+), 9 deletions(-) create mode 100644 java/com/android/dialer/dialpadview/res/layout/dialog_deviceids.xml create mode 100644 java/com/android/dialer/dialpadview/res/layout/row_deviceid.xml (limited to 'java') diff --git a/java/com/android/dialer/dialpadview/SpecialCharSequenceMgr.java b/java/com/android/dialer/dialpadview/SpecialCharSequenceMgr.java index 2b7209eb5..c349d2235 100644 --- a/java/com/android/dialer/dialpadview/SpecialCharSequenceMgr.java +++ b/java/com/android/dialer/dialpadview/SpecialCharSequenceMgr.java @@ -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 deviceIds = new ArrayList(); + 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( diff --git a/java/com/android/dialer/dialpadview/res/layout/dialog_deviceids.xml b/java/com/android/dialer/dialpadview/res/layout/dialog_deviceids.xml new file mode 100644 index 000000000..89e256bde --- /dev/null +++ b/java/com/android/dialer/dialpadview/res/layout/dialog_deviceids.xml @@ -0,0 +1,26 @@ + + + + + diff --git a/java/com/android/dialer/dialpadview/res/layout/row_deviceid.xml b/java/com/android/dialer/dialpadview/res/layout/row_deviceid.xml new file mode 100644 index 000000000..53f3e5d0d --- /dev/null +++ b/java/com/android/dialer/dialpadview/res/layout/row_deviceid.xml @@ -0,0 +1,49 @@ + + + + + + + + + diff --git a/java/com/android/dialer/dialpadview/res/values/dimens.xml b/java/com/android/dialer/dialpadview/res/values/dimens.xml index 4b386eeb5..6892fcf30 100644 --- a/java/com/android/dialer/dialpadview/res/values/dimens.xml +++ b/java/com/android/dialer/dialpadview/res/values/dimens.xml @@ -43,4 +43,6 @@ 10dp + + 100dp diff --git a/java/com/android/dialer/dialpadview/res/values/strings.xml b/java/com/android/dialer/dialpadview/res/values/strings.xml index 094ca6b8f..51367b644 100644 --- a/java/com/android/dialer/dialpadview/res/values/strings.xml +++ b/java/com/android/dialer/dialpadview/res/values/strings.xml @@ -77,6 +77,12 @@ MEID + + HEX: + + + DEC: + Loading from SIM card\u2026 diff --git a/java/com/android/dialer/dialpadview/res/values/styles.xml b/java/com/android/dialer/dialpadview/res/values/styles.xml index d69e6a832..75a54a305 100644 --- a/java/com/android/dialer/dialpadview/res/values/styles.xml +++ b/java/com/android/dialer/dialpadview/res/values/styles.xml @@ -116,4 +116,9 @@ ?attr/dialpad_text_color_secondary #00000000 + + -- cgit v1.2.3