summaryrefslogtreecommitdiff
path: root/java/com/android/voicemailomtp/utils
diff options
context:
space:
mode:
authorEric Erfanian <erfanian@google.com>2017-02-22 16:32:36 -0800
committerEric Erfanian <erfanian@google.com>2017-03-01 09:56:52 -0800
commitccca31529c07970e89419fb85a9e8153a5396838 (patch)
treea7034c0a01672b97728c13282a2672771cd28baa /java/com/android/voicemailomtp/utils
parente7ae4624ba6f25cb8e648db74e0d64c0113a16ba (diff)
Update dialer sources.
Test: Built package and system image. This change clobbers the old source, and is an export from an internal Google repository. The internal repository was forked form Android in March, and this change includes modifications since then, to near the v8 release. Since the fork, we've moved code from monolithic to independent modules. In addition, we've switched to Blaze/Bazel as the build sysetm. This export, however, still uses make. New dependencies have been added: - Dagger - Auto-Value - Glide - Libshortcutbadger Going forward, development will still be in Google3, and the Gerrit release will become an automated export, with the next drop happening in ~ two weeks. Android.mk includes local modifications from ToT. Abridged changelog: Bug fixes ● Not able to mute, add a call when using Phone app in multiwindow mode ● Double tap on keypad triggering multiple key and tones ● Reported spam numbers not showing as spam in the call log ● Crash when user tries to block number while Phone app is not set as default ● Crash when user picks a number from search auto-complete list Visual Voicemail (VVM) improvements ● Share Voicemail audio via standard exporting mechanisms that support file attachment (email, MMS, etc.) ● Make phone number, email and web sites in VVM transcript clickable ● Set PIN before declining VVM Terms of Service {Carrier} ● Set client type for outbound visual voicemail SMS {Carrier} New incoming call and incall UI on older devices (Android M) ● Updated Phone app icon ● New incall UI (large buttons, button labels) ● New and animated Answer/Reject gestures Accessibility ● Add custom answer/decline call buttons on answer screen for touch exploration accessibility services ● Increase size of touch target ● Add verbal feedback when a Voicemail fails to load ● Fix pressing of Phone buttons while in a phone call using Switch Access ● Fix selecting and opening contacts in talkback mode ● Split focus for ‘Learn More’ link in caller id & spam to help distinguish similar text Other ● Backup & Restore for App Preferences ● Prompt user to enable Wi-Fi calling if the call ends due to out of service and Wi-Fi is connected ● Rename “Dialpad” to “Keypad” ● Show "Private number" for restricted calls ● Delete unused items (vcard, add contact, call history) from Phone menu Change-Id: I2a7e53532a24c21bf308bf0a6d178d7ddbca4958
Diffstat (limited to 'java/com/android/voicemailomtp/utils')
-rw-r--r--java/com/android/voicemailomtp/utils/IndentingPrintWriter.java160
-rw-r--r--java/com/android/voicemailomtp/utils/VoicemailDatabaseUtil.java90
-rw-r--r--java/com/android/voicemailomtp/utils/VvmDumpHandler.java46
-rw-r--r--java/com/android/voicemailomtp/utils/XmlUtils.java245
4 files changed, 541 insertions, 0 deletions
diff --git a/java/com/android/voicemailomtp/utils/IndentingPrintWriter.java b/java/com/android/voicemailomtp/utils/IndentingPrintWriter.java
new file mode 100644
index 000000000..eda7c4ee3
--- /dev/null
+++ b/java/com/android/voicemailomtp/utils/IndentingPrintWriter.java
@@ -0,0 +1,160 @@
+/*
+ * Copyright (C) 2016 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
+ */
+
+package com.android.voicemailomtp.utils;
+
+import java.io.PrintWriter;
+import java.io.Writer;
+import java.util.Arrays;
+
+/**
+ * Lightweight wrapper around {@link PrintWriter} that automatically indents newlines based on
+ * internal state. It also automatically wraps long lines based on given line length. <p> Delays
+ * writing indent until first actual write on a newline, enabling indent modification after
+ * newline.
+ */
+public class IndentingPrintWriter extends PrintWriter {
+
+ private final String mSingleIndent;
+ private final int mWrapLength;
+
+ /**
+ * Mutable version of current indent
+ */
+ private StringBuilder mIndentBuilder = new StringBuilder();
+ /**
+ * Cache of current {@link #mIndentBuilder} value
+ */
+ private char[] mCurrentIndent;
+ /**
+ * Length of current line being built, excluding any indent
+ */
+ private int mCurrentLength;
+
+ /**
+ * Flag indicating if we're currently sitting on an empty line, and that next write should be
+ * prefixed with the current indent.
+ */
+ private boolean mEmptyLine = true;
+
+ private char[] mSingleChar = new char[1];
+
+ public IndentingPrintWriter(Writer writer, String singleIndent) {
+ this(writer, singleIndent, -1);
+ }
+
+ public IndentingPrintWriter(Writer writer, String singleIndent, int wrapLength) {
+ super(writer);
+ mSingleIndent = singleIndent;
+ mWrapLength = wrapLength;
+ }
+
+ public void increaseIndent() {
+ mIndentBuilder.append(mSingleIndent);
+ mCurrentIndent = null;
+ }
+
+ public void decreaseIndent() {
+ mIndentBuilder.delete(0, mSingleIndent.length());
+ mCurrentIndent = null;
+ }
+
+ public void printPair(String key, Object value) {
+ print(key + "=" + String.valueOf(value) + " ");
+ }
+
+ public void printPair(String key, Object[] value) {
+ print(key + "=" + Arrays.toString(value) + " ");
+ }
+
+ public void printHexPair(String key, int value) {
+ print(key + "=0x" + Integer.toHexString(value) + " ");
+ }
+
+ @Override
+ public void println() {
+ write('\n');
+ }
+
+ @Override
+ public void write(int c) {
+ mSingleChar[0] = (char) c;
+ write(mSingleChar, 0, 1);
+ }
+
+ @Override
+ public void write(String s, int off, int len) {
+ final char[] buf = new char[len];
+ s.getChars(off, len - off, buf, 0);
+ write(buf, 0, len);
+ }
+
+ @Override
+ public void write(char[] buf, int offset, int count) {
+ final int indentLength = mIndentBuilder.length();
+ final int bufferEnd = offset + count;
+ int lineStart = offset;
+ int lineEnd = offset;
+
+ // March through incoming buffer looking for newlines
+ while (lineEnd < bufferEnd) {
+ char ch = buf[lineEnd++];
+ mCurrentLength++;
+ if (ch == '\n') {
+ maybeWriteIndent();
+ super.write(buf, lineStart, lineEnd - lineStart);
+ lineStart = lineEnd;
+ mEmptyLine = true;
+ mCurrentLength = 0;
+ }
+
+ // Wrap if we've pushed beyond line length
+ if (mWrapLength > 0 && mCurrentLength >= mWrapLength - indentLength) {
+ if (!mEmptyLine) {
+ // Give ourselves a fresh line to work with
+ super.write('\n');
+ mEmptyLine = true;
+ mCurrentLength = lineEnd - lineStart;
+ } else {
+ // We need more than a dedicated line, slice it hard
+ maybeWriteIndent();
+ super.write(buf, lineStart, lineEnd - lineStart);
+ super.write('\n');
+ mEmptyLine = true;
+ lineStart = lineEnd;
+ mCurrentLength = 0;
+ }
+ }
+ }
+
+ if (lineStart != lineEnd) {
+ maybeWriteIndent();
+ super.write(buf, lineStart, lineEnd - lineStart);
+ }
+ }
+
+ private void maybeWriteIndent() {
+ if (mEmptyLine) {
+ mEmptyLine = false;
+ if (mIndentBuilder.length() != 0) {
+ if (mCurrentIndent == null) {
+ mCurrentIndent = mIndentBuilder.toString().toCharArray();
+ }
+ super.write(mCurrentIndent, 0, mCurrentIndent.length);
+ }
+ }
+ }
+} \ No newline at end of file
diff --git a/java/com/android/voicemailomtp/utils/VoicemailDatabaseUtil.java b/java/com/android/voicemailomtp/utils/VoicemailDatabaseUtil.java
new file mode 100644
index 000000000..f94070ecd
--- /dev/null
+++ b/java/com/android/voicemailomtp/utils/VoicemailDatabaseUtil.java
@@ -0,0 +1,90 @@
+/*
+ * Copyright (C) 2016 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
+ */
+
+package com.android.voicemailomtp.utils;
+
+import android.content.ContentResolver;
+import android.content.ContentValues;
+import android.content.Context;
+import android.net.Uri;
+import android.provider.VoicemailContract.Voicemails;
+import android.telecom.PhoneAccountHandle;
+import com.android.voicemailomtp.Voicemail;
+import java.util.List;
+
+public class VoicemailDatabaseUtil {
+
+ /**
+ * Inserts a new voicemail into the voicemail content provider.
+ *
+ * @param context The context of the app doing the inserting
+ * @param voicemail Data to be inserted
+ * @return {@link Uri} of the newly inserted {@link Voicemail}
+ * @hide
+ */
+ public static Uri insert(Context context, Voicemail voicemail) {
+ ContentResolver contentResolver = context.getContentResolver();
+ ContentValues contentValues = getContentValues(voicemail);
+ return contentResolver
+ .insert(Voicemails.buildSourceUri(context.getPackageName()), contentValues);
+ }
+
+ /**
+ * Inserts a list of voicemails into the voicemail content provider.
+ *
+ * @param context The context of the app doing the inserting
+ * @param voicemails Data to be inserted
+ * @return the number of voicemails inserted
+ * @hide
+ */
+ public static int insert(Context context, List<Voicemail> voicemails) {
+ ContentResolver contentResolver = context.getContentResolver();
+ int count = voicemails.size();
+ for (int i = 0; i < count; i++) {
+ ContentValues contentValues = getContentValues(voicemails.get(i));
+ contentResolver
+ .insert(Voicemails.buildSourceUri(context.getPackageName()), contentValues);
+ }
+ return count;
+ }
+
+
+ /**
+ * Maps structured {@link Voicemail} to {@link ContentValues} in content provider.
+ */
+ private static ContentValues getContentValues(Voicemail voicemail) {
+ ContentValues contentValues = new ContentValues();
+ contentValues.put(Voicemails.DATE, String.valueOf(voicemail.getTimestampMillis()));
+ contentValues.put(Voicemails.NUMBER, voicemail.getNumber());
+ contentValues.put(Voicemails.DURATION, String.valueOf(voicemail.getDuration()));
+ contentValues.put(Voicemails.SOURCE_PACKAGE, voicemail.getSourcePackage());
+ contentValues.put(Voicemails.SOURCE_DATA, voicemail.getSourceData());
+ contentValues.put(Voicemails.IS_READ, voicemail.isRead() ? 1 : 0);
+
+ PhoneAccountHandle phoneAccount = voicemail.getPhoneAccount();
+ if (phoneAccount != null) {
+ contentValues.put(Voicemails.PHONE_ACCOUNT_COMPONENT_NAME,
+ phoneAccount.getComponentName().flattenToString());
+ contentValues.put(Voicemails.PHONE_ACCOUNT_ID, phoneAccount.getId());
+ }
+
+ if (voicemail.getTranscription() != null) {
+ contentValues.put(Voicemails.TRANSCRIPTION, voicemail.getTranscription());
+ }
+
+ return contentValues;
+ }
+}
diff --git a/java/com/android/voicemailomtp/utils/VvmDumpHandler.java b/java/com/android/voicemailomtp/utils/VvmDumpHandler.java
new file mode 100644
index 000000000..5768a9c19
--- /dev/null
+++ b/java/com/android/voicemailomtp/utils/VvmDumpHandler.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2016 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
+ */
+
+package com.android.voicemailomtp.utils;
+
+import android.content.Context;
+import android.telecom.PhoneAccountHandle;
+import android.telecom.TelecomManager;
+
+import com.android.voicemailomtp.OmtpVvmCarrierConfigHelper;
+import com.android.voicemailomtp.VvmLog;
+
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
+
+public class VvmDumpHandler {
+
+ public static void dump(Context context, FileDescriptor fd, PrintWriter writer,
+ String[] args) {
+ IndentingPrintWriter indentedWriter = new IndentingPrintWriter(writer, " ");
+ indentedWriter.println("******* OmtpVvm *******");
+ indentedWriter.println("======= Configs =======");
+ indentedWriter.increaseIndent();
+ for (PhoneAccountHandle handle : context.getSystemService(TelecomManager.class)
+ .getCallCapablePhoneAccounts()) {
+ OmtpVvmCarrierConfigHelper config = new OmtpVvmCarrierConfigHelper(context, handle);
+ indentedWriter.println(config.toString());
+ }
+ indentedWriter.decreaseIndent();
+ indentedWriter.println("======== Logs =========");
+ VvmLog.dump(fd, indentedWriter, args);
+ }
+}
diff --git a/java/com/android/voicemailomtp/utils/XmlUtils.java b/java/com/android/voicemailomtp/utils/XmlUtils.java
new file mode 100644
index 000000000..768247e27
--- /dev/null
+++ b/java/com/android/voicemailomtp/utils/XmlUtils.java
@@ -0,0 +1,245 @@
+/*
+ * Copyright (C) 2016 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.
+ */
+
+package com.android.voicemailomtp.utils;
+
+import android.util.ArrayMap;
+
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+
+public class XmlUtils {
+
+ public static final ArrayMap<String, ?> readThisArrayMapXml(XmlPullParser parser, String endTag,
+ String[] name, ReadMapCallback callback)
+ throws XmlPullParserException, java.io.IOException {
+ ArrayMap<String, Object> map = new ArrayMap<>();
+
+ int eventType = parser.getEventType();
+ do {
+ if (eventType == XmlPullParser.START_TAG) {
+ Object val = readThisValueXml(parser, name, callback, true);
+ map.put(name[0], val);
+ } else if (eventType == XmlPullParser.END_TAG) {
+ if (parser.getName().equals(endTag)) {
+ return map;
+ }
+ throw new XmlPullParserException(
+ "Expected " + endTag + " end tag at: " + parser.getName());
+ }
+ eventType = parser.next();
+ } while (eventType != XmlPullParser.END_DOCUMENT);
+
+ throw new XmlPullParserException(
+ "Document ended before " + endTag + " end tag");
+ }
+
+ /**
+ * Read an ArrayList object from an XmlPullParser. The XML data could previously have been
+ * generated by writeListXml(). The XmlPullParser must be positioned <em>after</em> the tag
+ * that begins the list.
+ *
+ * @param parser The XmlPullParser from which to read the list data.
+ * @param endTag Name of the tag that will end the list, usually "list".
+ * @param name An array of one string, used to return the name attribute of the list's tag.
+ * @return HashMap The newly generated list.
+ */
+ public static final ArrayList readThisListXml(XmlPullParser parser, String endTag,
+ String[] name, ReadMapCallback callback, boolean arrayMap)
+ throws XmlPullParserException, java.io.IOException {
+ ArrayList list = new ArrayList();
+
+ int eventType = parser.getEventType();
+ do {
+ if (eventType == XmlPullParser.START_TAG) {
+ Object val = readThisValueXml(parser, name, callback, arrayMap);
+ list.add(val);
+ } else if (eventType == XmlPullParser.END_TAG) {
+ if (parser.getName().equals(endTag)) {
+ return list;
+ }
+ throw new XmlPullParserException(
+ "Expected " + endTag + " end tag at: " + parser.getName());
+ }
+ eventType = parser.next();
+ } while (eventType != XmlPullParser.END_DOCUMENT);
+
+ throw new XmlPullParserException(
+ "Document ended before " + endTag + " end tag");
+ }
+
+ /**
+ * Read a String[] object from an XmlPullParser. The XML data could previously have been
+ * generated by writeStringArrayXml(). The XmlPullParser must be positioned <em>after</em> the
+ * tag that begins the list.
+ *
+ * @param parser The XmlPullParser from which to read the list data.
+ * @param endTag Name of the tag that will end the list, usually "string-array".
+ * @param name An array of one string, used to return the name attribute of the list's tag.
+ * @return Returns a newly generated String[].
+ */
+ public static String[] readThisStringArrayXml(XmlPullParser parser, String endTag,
+ String[] name) throws XmlPullParserException, java.io.IOException {
+
+ parser.next();
+
+ List<String> array = new ArrayList<>();
+
+ int eventType = parser.getEventType();
+ do {
+ if (eventType == XmlPullParser.START_TAG) {
+ if (parser.getName().equals("item")) {
+ try {
+ array.add(parser.getAttributeValue(null, "value"));
+ } catch (NullPointerException e) {
+ throw new XmlPullParserException("Need value attribute in item");
+ } catch (NumberFormatException e) {
+ throw new XmlPullParserException("Not a number in value attribute in item");
+ }
+ } else {
+ throw new XmlPullParserException("Expected item tag at: " + parser.getName());
+ }
+ } else if (eventType == XmlPullParser.END_TAG) {
+ if (parser.getName().equals(endTag)) {
+ return array.toArray(new String[0]);
+ } else if (parser.getName().equals("item")) {
+
+ } else {
+ throw new XmlPullParserException("Expected " + endTag + " end tag at: " +
+ parser.getName());
+ }
+ }
+ eventType = parser.next();
+ } while (eventType != XmlPullParser.END_DOCUMENT);
+
+ throw new XmlPullParserException("Document ended before " + endTag + " end tag");
+ }
+
+ private static Object readThisValueXml(XmlPullParser parser, String[] name,
+ ReadMapCallback callback, boolean arrayMap)
+ throws XmlPullParserException, java.io.IOException {
+ final String valueName = parser.getAttributeValue(null, "name");
+ final String tagName = parser.getName();
+
+ Object res;
+
+ if (tagName.equals("null")) {
+ res = null;
+ } else if (tagName.equals("string")) {
+ String value = "";
+ int eventType;
+ while ((eventType = parser.next()) != XmlPullParser.END_DOCUMENT) {
+ if (eventType == XmlPullParser.END_TAG) {
+ if (parser.getName().equals("string")) {
+ name[0] = valueName;
+ return value;
+ }
+ throw new XmlPullParserException(
+ "Unexpected end tag in <string>: " + parser.getName());
+ } else if (eventType == XmlPullParser.TEXT) {
+ value += parser.getText();
+ } else if (eventType == XmlPullParser.START_TAG) {
+ throw new XmlPullParserException(
+ "Unexpected start tag in <string>: " + parser.getName());
+ }
+ }
+ throw new XmlPullParserException(
+ "Unexpected end of document in <string>");
+ } else if ((res = readThisPrimitiveValueXml(parser, tagName)) != null) {
+ // all work already done by readThisPrimitiveValueXml
+ } else if (tagName.equals("string-array")) {
+ res = readThisStringArrayXml(parser, "string-array", name);
+ name[0] = valueName;
+ return res;
+ } else if (tagName.equals("list")) {
+ parser.next();
+ res = readThisListXml(parser, "list", name, callback, arrayMap);
+ name[0] = valueName;
+ return res;
+ } else if (callback != null) {
+ res = callback.readThisUnknownObjectXml(parser, tagName);
+ name[0] = valueName;
+ return res;
+ } else {
+ throw new XmlPullParserException("Unknown tag: " + tagName);
+ }
+
+ // Skip through to end tag.
+ int eventType;
+ while ((eventType = parser.next()) != XmlPullParser.END_DOCUMENT) {
+ if (eventType == XmlPullParser.END_TAG) {
+ if (parser.getName().equals(tagName)) {
+ name[0] = valueName;
+ return res;
+ }
+ throw new XmlPullParserException(
+ "Unexpected end tag in <" + tagName + ">: " + parser.getName());
+ } else if (eventType == XmlPullParser.TEXT) {
+ throw new XmlPullParserException(
+ "Unexpected text in <" + tagName + ">: " + parser.getName());
+ } else if (eventType == XmlPullParser.START_TAG) {
+ throw new XmlPullParserException(
+ "Unexpected start tag in <" + tagName + ">: " + parser.getName());
+ }
+ }
+ throw new XmlPullParserException(
+ "Unexpected end of document in <" + tagName + ">");
+ }
+
+ private static final Object readThisPrimitiveValueXml(XmlPullParser parser, String tagName)
+ throws XmlPullParserException, java.io.IOException {
+ try {
+ if (tagName.equals("int")) {
+ return Integer.parseInt(parser.getAttributeValue(null, "value"));
+ } else if (tagName.equals("long")) {
+ return Long.valueOf(parser.getAttributeValue(null, "value"));
+ } else if (tagName.equals("float")) {
+ return Float.valueOf(parser.getAttributeValue(null, "value"));
+ } else if (tagName.equals("double")) {
+ return Double.valueOf(parser.getAttributeValue(null, "value"));
+ } else if (tagName.equals("boolean")) {
+ return Boolean.valueOf(parser.getAttributeValue(null, "value"));
+ } else {
+ return null;
+ }
+ } catch (NullPointerException e) {
+ throw new XmlPullParserException("Need value attribute in <" + tagName + ">");
+ } catch (NumberFormatException e) {
+ throw new XmlPullParserException(
+ "Not a number in value attribute in <" + tagName + ">");
+ }
+ }
+
+ public interface ReadMapCallback {
+
+ /**
+ * Called from readThisMapXml when a START_TAG is not recognized. The input stream is
+ * positioned within the start tag so that attributes can be read using in.getAttribute.
+ *
+ * @param in the XML input stream
+ * @param tag the START_TAG that was not recognized.
+ * @return the Object parsed from the stream which will be put into the map.
+ * @throws XmlPullParserException if the START_TAG is not recognized.
+ * @throws IOException on XmlPullParser serialization errors.
+ */
+ Object readThisUnknownObjectXml(XmlPullParser in, String tag)
+ throws XmlPullParserException, IOException;
+ }
+} \ No newline at end of file