Commit 58b152ca authored by Jeffrey I. Schiller's avatar Jeffrey I. Schiller

Merge branch 'ucr'

parents 0b500e91 b2794460
// -*- mode: java; c-basic-offset: 2; -*-
// Copyright 2017 MIT, All rights reserved
// Released under the Apache License, Version 2.0
// http://www.apache.org/licenses/LICENSE-2.0
package com.google.appinventor.components.runtime.util;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import android.content.Intent;
import android.provider.Telephony.Sms.Intents;
import android.telephony.SmsMessage;
/**
* Helper methods for calling APIs added in KITKAT (4.4, API level 19)
*
* @author Evan W. Patton (ewpatton@mit.edu)
*
*/
public final class KitkatUtil {
private KitkatUtil() {
}
/**
* Retrieve any SmsMessage objects encoded in the SMS_RECEIVED intent.
*
* @param intent An intent passed by Android to the SMS_RECEIVED receiver.
* @return A list of SmsMessages. The list will be non-null but zero length if the intent lacks
* SMS content.
*/
public static List<SmsMessage> getMessagesFromIntent(Intent intent) {
List<SmsMessage> result = new ArrayList<SmsMessage>();
SmsMessage[] messages = Intents.getMessagesFromIntent(intent);
if (messages != null && messages.length >= 0) {
Collections.addAll(result, messages);
}
return result;
}
}
// -*- mode: java; c-basic-offset: 2; -*-
// Copyright 2017 MIT, All rights reserved
// Released under the Apache License, Version 2.0
// http://www.apache.org/licenses/LICENSE-2.0
package com.google.appinventor.components.runtime.util;
import java.util.Locale;
import android.telephony.PhoneNumberUtils;
/**
* Helper methods for calling APIs added in LOLLIPOP (5.0, API Level 21)
*
* @author Evan W. Patton (ewpatton@mit.edu)
*
*/
public final class LollipopUtil {
private LollipopUtil() {
}
/**
* Format a phone number based on the number's country code, falling
* back to the format defined by the user's current locale. This is
* to replace calling {@link PhoneNumberUtils#formatNumber(String)},
* which was deprecated in the LOLLIPOP release.
*
* @see PhoneNumberUtils#formatNumber(String, String)
* @param number The phone number to be formatted
* @return The phone number, formatted based on the country code or
* user's locale.
*/
public static String formatNumber(String number) {
return PhoneNumberUtils.formatNumber(number, Locale.getDefault().getCountry());
}
}
......@@ -25,7 +25,8 @@ import android.view.Display;
import android.view.WindowManager;
import android.widget.VideoView;
import java.io.BufferedInputStream;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileDescriptor;
import java.io.FileInputStream;
......@@ -391,14 +392,55 @@ public class MediaUtil {
// When the app says to fetch the image, we need to get the latest image, not one that we
// cached previously.
BufferedInputStream is = null;
Log.d(LOG_TAG, "mediaPath = " + mediaPath);
InputStream is = null;
ByteArrayOutputStream bos = new ByteArrayOutputStream();
byte[] buf = new byte[4096];
int read;
try {
is = new BufferedInputStream(openMedia(form, mediaPath, mediaSource));
is.mark(8*1024*1024);
BitmapFactory.Options options = getBitmapOptions(form, is, mediaPath);
is.reset();
Log.d(LOG_TAG, "mediaPath = " + mediaPath);
BitmapDrawable originalBitmapDrawable = new BitmapDrawable(form.getResources(), decodeStream(is, null, options));
// copy the input stream to an in-memory buffer
is = openMedia(form, mediaPath, mediaSource);
while((read = is.read(buf)) > 0) {
bos.write(buf, 0, read);
}
buf = bos.toByteArray();
} catch(IOException e) {
if (mediaSource == MediaSource.CONTACT_URI) {
// There's no photo for this contact, return a placeholder image.
BitmapDrawable drawable = new BitmapDrawable(form.getResources(),
BitmapFactory.decodeResource(form.getResources(),
android.R.drawable.picture_frame, null));
continuation.onSuccess(drawable);
return;
}
Log.d(LOG_TAG, "IOException reading file.", e);
continuation.onFailure(e.getMessage());
return;
} finally {
if (is != null) {
try {
is.close();
} catch(IOException e) {
// suppress error on close
Log.w(LOG_TAG, "Unexpected error on close", e);
}
}
is = null;
try {
bos.close();
} catch(IOException e) {
// Should never fail to close a ByteArrayOutputStream
}
bos = null;
}
ByteArrayInputStream bis = new ByteArrayInputStream(buf);
read = buf.length;
buf = null;
try {
bis.mark(read);
BitmapFactory.Options options = getBitmapOptions(form, bis, mediaPath);
bis.reset();
BitmapDrawable originalBitmapDrawable = new BitmapDrawable(form.getResources(), decodeStream(bis, null, options));
// If options.inSampleSize == 1, then the image was not unreasonably large and may represent
// the actual size the user intended for the image. However we still have to scale it by
// the device density.
......@@ -429,21 +471,13 @@ public class MediaUtil {
originalBitmapDrawable = null; // So it will get GC'd on the next line
System.gc(); // We likely used a lot of memory, so gc now.
continuation.onSuccess(scaledBitmapDrawable);
} catch (IOException e) {
if (mediaSource == MediaSource.CONTACT_URI) {
// There's no photo for this contact, return a placeholder image.
BitmapDrawable drawable = new BitmapDrawable(form.getResources(),
BitmapFactory.decodeResource(form.getResources(),
android.R.drawable.picture_frame, null));
continuation.onSuccess(drawable);
}
continuation.onFailure(e.getMessage());
} catch(Exception e) {
Log.w(LOG_TAG, "Exception while loading media.", e);
continuation.onFailure(e.getMessage());
} finally {
if (is != null) {
if (bis != null) {
try {
is.close();
bis.close();
} catch(IOException e) {
// suppress error on close
Log.w(LOG_TAG, "Unexpected error on close", e);
......
......@@ -31,6 +31,8 @@ public class SdkLevel {
public static final int LEVEL_JELLYBEAN = 16; // a.k.a. 4.1
public static final int LEVEL_JELLYBEAN_MR1 = 17; // a.k.a. 4.2
public static final int LEVEL_JELLYBEAN_MR2 = 18; // a.k.a. 4.3
public static final int LEVEL_KITKAT = 19; // a.k.a. 4.4
public static final int LEVEL_LOLLIPOP = 21; // a.k.a. 5.0
private SdkLevel() {
}
......
......@@ -10,6 +10,8 @@
*/
package com.google.appinventor.components.runtime.util;
import java.util.List;
import com.google.appinventor.components.common.ComponentConstants;
import com.google.appinventor.components.runtime.Texting;
import com.google.appinventor.components.runtime.ReplForm;
......@@ -22,7 +24,7 @@ import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.telephony.PhoneNumberUtils;
import android.telephony.gsm.SmsMessage;
import android.telephony.SmsMessage;
import android.util.Log;
/**
......@@ -114,21 +116,39 @@ public class SmsBroadcastReceiver extends BroadcastReceiver {
private String getPhoneNumber(Intent intent) {
String phone = "";
// For Google Voice, phone and msg are stored in String extras. Pretty them up
if (intent.getAction().equals("com.google.android.apps.googlevoice.SMS_RECEIVED")) {
phone = intent.getExtras().getString(Texting.PHONE_NUMBER_TAG);
phone = PhoneNumberUtils.formatNumber(phone);
// For Telephony, phone and msg are stored in PDUs.
try {
if (intent.getAction().equals("com.google.android.apps.googlevoice.SMS_RECEIVED")) {
// For Google Voice, phone and msg are stored in String extras. Pretty them up
} else {
Object[] pdus = (Object[]) intent.getExtras().get("pdus");
for (Object pdu : pdus) {
SmsMessage smsMsg = SmsMessage.createFromPdu((byte[]) pdu);
phone = smsMsg.getOriginatingAddress();
phone = intent.getExtras().getString(Texting.PHONE_NUMBER_TAG);
phone = PhoneNumberUtils.formatNumber(phone);
} else if (SdkLevel.getLevel() >= SdkLevel.LEVEL_KITKAT) {
// On KitKat or higher, use the convience getMessageFromIntent method.
List<SmsMessage> messages = KitkatUtil.getMessagesFromIntent(intent);
for (SmsMessage smsMsg : messages) {
if (smsMsg != null) {
// getOriginatingAddress() can throw a NPE if its wrapped message is null, but there
// isn't an API to check whether this is the case.
phone = smsMsg.getOriginatingAddress();
if (SdkLevel.getLevel() >= SdkLevel.LEVEL_LOLLIPOP) {
phone = LollipopUtil.formatNumber(phone);
} else {
phone = PhoneNumberUtils.formatNumber(phone);
}
}
}
} else {
// On SDK older than KitKat, we have to manually process the PDUs.
Object[] pdus = (Object[]) intent.getExtras().get("pdus");
for (Object pdu : pdus) {
SmsMessage smsMsg = SmsMessage.createFromPdu((byte[]) pdu);
phone = smsMsg.getOriginatingAddress();
phone = PhoneNumberUtils.formatNumber(phone);
}
}
} catch(NullPointerException e) {
Log.w(TAG, "Unable to retrieve originating address from SmsMessage", e);
}
return phone;
}
......@@ -141,19 +161,32 @@ public class SmsBroadcastReceiver extends BroadcastReceiver {
private String getMessage(Intent intent) {
String msg = "";
// For Google Voice, msg is stored in String extras.
if (intent.getAction().equals("com.google.android.apps.googlevoice.SMS_RECEIVED")) {
msg = intent.getExtras().getString(Texting.MESSAGE_TAG);
// For Telephony, phone and msg are stored in PDUs.
} else {
Object[] pdus = (Object[]) intent.getExtras().get("pdus");
for (Object pdu : pdus) {
SmsMessage smsMsg = SmsMessage.createFromPdu((byte[]) pdu);
msg = smsMsg.getMessageBody();
try {
if (intent.getAction().equals("com.google.android.apps.googlevoice.SMS_RECEIVED")) {
// For Google Voice, msg is stored in String extras.
msg = intent.getExtras().getString(Texting.MESSAGE_TAG);
} else if (SdkLevel.getLevel() >= SdkLevel.LEVEL_KITKAT) {
// On KitKat or higher, use the convience getMessageFromIntent method.
List<SmsMessage> messages = KitkatUtil.getMessagesFromIntent(intent);
for (SmsMessage smsMsg : messages) {
if (smsMsg != null) {
msg = smsMsg.getMessageBody();
}
}
} else {
// On SDK older than KitKat, we have to manually process the PDUs.
Object[] pdus = (Object[]) intent.getExtras().get("pdus");
for (Object pdu : pdus) {
SmsMessage smsMsg = SmsMessage.createFromPdu((byte[]) pdu);
msg = smsMsg.getMessageBody();
}
}
} catch(NullPointerException e) {
// getMessageBody() can throw a NPE if its wrapped message is null, but there isn't an
// API to check whether this is the case.
Log.w(TAG, "Unable to retrieve message body from SmsMessage", e);
}
return msg;
}
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment