use of androidx.annotation.NonNull in project kdeconnect-android by KDE.
the class SMSHelper method getMessages.
/**
* Gets messages which match the selection
*
* @param uri Uri indicating the messages database to read
* @param context android.content.Context running the request.
* @param fetchColumns List of columns to fetch
* @param selection Parameterizable filter to use with the ContentResolver query. May be null.
* @param selectionArgs Parameters for selection. May be null.
* @param sortOrder Sort ordering passed to Android's content resolver. May be null for unspecified
* @param numberToGet Number of things to get from the result. Pass null to get all
* @return Returns List<Message> of all messages in the return set, either in the order of sortOrder or in an unspecified order
*/
@NonNull
private static List<Message> getMessages(@NonNull Uri uri, @NonNull Context context, @NonNull Collection<String> fetchColumns, @Nullable String selection, @Nullable String[] selectionArgs, @Nullable String sortOrder, @Nullable Long numberToGet) {
List<Message> toReturn = new ArrayList<>();
// Get all the active phone numbers so we can filter the user out of the list of targets
// of any MMSes
List<TelephonyHelper.LocalPhoneNumber> userPhoneNumbers = TelephonyHelper.getAllPhoneNumbers(context);
try (Cursor myCursor = context.getContentResolver().query(uri, fetchColumns.toArray(ArrayUtils.EMPTY_STRING_ARRAY), selection, selectionArgs, sortOrder)) {
if (myCursor != null && myCursor.moveToFirst()) {
do {
int transportTypeColumn = myCursor.getColumnIndex(getTransportTypeDiscriminatorColumn());
TransportType transportType;
if (transportTypeColumn < 0) {
// The column didn't actually exist. See https://issuetracker.google.com/issues/134592631
// Try to determine using other information
int messageBoxColumn = myCursor.getColumnIndex(Telephony.Mms.MESSAGE_BOX);
// MessageBoxColumn is defined for MMS only
boolean messageBoxExists = !myCursor.isNull(messageBoxColumn);
if (messageBoxExists) {
transportType = TransportType.MMS;
} else {
// There is room here for me to have made an assumption and we'll guess wrong
// The penalty is the user will potentially get some garbled data, so that's not too bad.
transportType = TransportType.SMS;
}
} else {
String transportTypeString = myCursor.getString(transportTypeColumn);
if ("mms".equals(transportTypeString)) {
transportType = TransportType.MMS;
} else if ("sms".equals(transportTypeString)) {
transportType = TransportType.SMS;
} else {
Log.w("SMSHelper", "Skipping message with unknown TransportType: " + transportTypeString);
continue;
}
}
HashMap<String, String> messageInfo = new HashMap<>();
for (int columnIdx = 0; columnIdx < myCursor.getColumnCount(); columnIdx++) {
String colName = myCursor.getColumnName(columnIdx);
String body = myCursor.getString(columnIdx);
messageInfo.put(colName, body);
}
try {
Message message;
if (transportType == TransportType.SMS) {
message = parseSMS(context, messageInfo);
} else if (transportType == TransportType.MMS) {
message = parseMMS(context, messageInfo, userPhoneNumbers);
} else {
// requires this line anyway
throw new UnsupportedOperationException("Unknown TransportType encountered");
}
toReturn.add(message);
} catch (Exception e) {
// Swallow exceptions in case we get an error reading one message so that we
// might be able to read some of them
Log.e("SMSHelper", "Got an error reading a message of type " + transportType, e);
}
} while ((numberToGet == null || toReturn.size() < numberToGet) && myCursor.moveToNext());
}
} catch (SQLiteException | IllegalArgumentException e) {
String[] unfilteredColumns = {};
try (Cursor unfilteredColumnsCursor = context.getContentResolver().query(uri, null, null, null, null)) {
if (unfilteredColumnsCursor != null) {
unfilteredColumns = unfilteredColumnsCursor.getColumnNames();
}
}
if (unfilteredColumns.length == 0) {
throw new MessageAccessException(uri, e);
} else {
throw new MessageAccessException(unfilteredColumns, uri, e);
}
}
return toReturn;
}
use of androidx.annotation.NonNull in project kdeconnect-android by KDE.
the class TelephonyHelper method getAllPhoneNumbers.
/**
* Try to get the phone number currently active on the phone
*
* Make sure that you have the READ_PHONE_STATE permission!
*
* Note that entries of the returned list might return null if the phone number is not known by the device
*/
@NonNull
public static List<LocalPhoneNumber> getAllPhoneNumbers(@NonNull Context context) throws SecurityException {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP_MR1) {
// Single-sim case
// From https://stackoverflow.com/a/25131061/3723163
// Android added support for multi-sim devices in Lollypop v5.1 (api 22)
// See: https://developer.android.com/about/versions/android-5.1.html#multisim
// There were vendor-specific implmentations before then, but those are very difficult to support
// S/O Reference: https://stackoverflow.com/a/28571835/3723163
TelephonyManager telephonyManager = ContextCompat.getSystemService(context, TelephonyManager.class);
if (telephonyManager == null) {
// I don't know why or when this happens...
Log.w(LOGGING_TAG, "Could not get TelephonyManager");
return Collections.emptyList();
}
LocalPhoneNumber phoneNumber = getPhoneNumber(telephonyManager);
return Collections.singletonList(phoneNumber);
} else {
// Potentially multi-sim case
SubscriptionManager subscriptionManager = ContextCompat.getSystemService(context, SubscriptionManager.class);
if (subscriptionManager == null) {
// I don't know why or when this happens...
Log.w(LOGGING_TAG, "Could not get SubscriptionManager");
return Collections.emptyList();
}
List<SubscriptionInfo> subscriptionInfos = subscriptionManager.getActiveSubscriptionInfoList();
if (subscriptionInfos == null) {
// This happens when there is no SIM card inserted
Log.w(LOGGING_TAG, "Could not get SubscriptionInfos");
return Collections.emptyList();
}
List<LocalPhoneNumber> phoneNumbers = new ArrayList<>(subscriptionInfos.size());
for (SubscriptionInfo info : subscriptionInfos) {
LocalPhoneNumber thisPhoneNumber = new LocalPhoneNumber(info.getNumber(), info.getSubscriptionId());
phoneNumbers.add(thisPhoneNumber);
}
return phoneNumbers.stream().filter(localPhoneNumber -> localPhoneNumber.number != null).collect(Collectors.toList());
}
}
use of androidx.annotation.NonNull in project CustomActivityOnCrash by Ereza.
the class CustomActivityOnCrash method getAllErrorDetailsFromIntent.
/**
* Given an Intent, returns several error details including the stack trace extra from the intent.
*
* @param context A valid context. Must not be null.
* @param intent The Intent. Must not be null.
* @return The full error details.
*/
@NonNull
public static String getAllErrorDetailsFromIntent(@NonNull Context context, @NonNull Intent intent) {
// I don't think that this needs localization because it's a development string...
Date currentDate = new Date();
DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.US);
// Get build date
String buildDateAsString = getBuildDateAsString(context, dateFormat);
// Get app version
String versionName = getVersionName(context);
String errorDetails = "";
errorDetails += "Build version: " + versionName + " \n";
if (buildDateAsString != null) {
errorDetails += "Build date: " + buildDateAsString + " \n";
}
errorDetails += "Current date: " + dateFormat.format(currentDate) + " \n";
// Added a space between line feeds to fix #18.
// Ideally, we should not use this method at all... It is only formatted this way because of coupling with the default error activity.
// We should move it to a method that returns a bean, and let anyone format it as they wish.
errorDetails += "Device: " + getDeviceModelName() + " \n";
errorDetails += "OS version: Android " + Build.VERSION.RELEASE + " (SDK " + Build.VERSION.SDK_INT + ") \n \n";
errorDetails += "Stack trace: \n";
errorDetails += getStackTraceFromIntent(intent);
String activityLog = getActivityLogFromIntent(intent);
if (activityLog != null) {
errorDetails += "\nUser actions: \n";
errorDetails += activityLog;
}
return errorDetails;
}
use of androidx.annotation.NonNull in project banner by youth5201314.
the class Vp2FragmentRecyclerviewActivity method onCreate.
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_vp2_fragment_recyclerview);
ButterKnife.bind(this);
viewPager2.setAdapter(new FragmentStateAdapter(this) {
@NonNull
@Override
public Fragment createFragment(int position) {
if (position == 0) {
return BannerListFragment.newInstance(position);
} else if (position == 1) {
return BlankFragment.newInstance();
} else {
return BannerFragment.newInstance();
}
}
@Override
public int getItemCount() {
return 3;
}
});
new TabLayoutMediator(mTabLayout, viewPager2, (tab, position) -> {
tab.setText("页面" + position);
}).attach();
mBanner.addBannerLifecycleObserver(this).setAdapter(new ImageAdapter(DataBean.getTestData())).setIntercept(false).setIndicator(new CircleIndicator(this));
}
use of androidx.annotation.NonNull in project kdeconnect-android by KDE.
the class SmsMmsUtils method sendMessage.
/**
* Sends SMS or MMS message.
*
* @param context context in which the method is called.
* @param textMessage text body of the message to be sent.
* @param addressList List of addresses.
* @param attachedFiles List of attachments. Pass empty list if none.
* @param subID Note that here subID is of type int and not long because klinker library requires it as int
* I don't really know the exact reason why they implemented it as int instead of long
*/
public static void sendMessage(Context context, String textMessage, @NonNull List<SMSHelper.Attachment> attachedFiles, List<SMSHelper.Address> addressList, int subID) {
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
boolean longTextAsMms = prefs.getBoolean(context.getString(R.string.set_long_text_as_mms), false);
boolean groupMessageAsMms = prefs.getBoolean(context.getString(R.string.set_group_message_as_mms), true);
int sendLongAsMmsAfter = Integer.parseInt(prefs.getString(context.getString(R.string.convert_to_mms_after), context.getString(R.string.convert_to_mms_after_default)));
TelephonyHelper.LocalPhoneNumber sendingPhoneNumber;
List<TelephonyHelper.LocalPhoneNumber> allPhoneNumbers = TelephonyHelper.getAllPhoneNumbers(context);
Optional<TelephonyHelper.LocalPhoneNumber> maybeSendingPhoneNumber = allPhoneNumbers.stream().filter(localPhoneNumber -> localPhoneNumber.subscriptionID == subID).findAny();
if (maybeSendingPhoneNumber.isPresent()) {
sendingPhoneNumber = maybeSendingPhoneNumber.get();
} else {
if (allPhoneNumbers.isEmpty()) {
// We were not able to get any phone number for the user's device
// Use a null "dummy" number instead. This should behave the same as not setting
// the FromAddress (below) since the default value there is null.
// The only more-correct thing we could do here is query the user (maybe in a
// persistent configuration) for their phone number(s).
sendingPhoneNumber = new TelephonyHelper.LocalPhoneNumber(null, subID);
Log.w(SENDING_MESSAGE, "We do not know *any* phone numbers for this device. " + "Attempting to send a message without knowing the local phone number is likely " + "to result in strange behavior, such as the message being sent to yourself, " + "or might entirely fail to send (or be received).");
} else {
// Pick an arbitrary phone number
sendingPhoneNumber = allPhoneNumbers.get(0);
}
Log.w(SENDING_MESSAGE, "Unable to determine correct outgoing address for sub ID " + subID + ". Using " + sendingPhoneNumber);
}
if (sendingPhoneNumber.number != null) {
// If the message is going to more than one target (to allow the user to send a message to themselves)
if (addressList.size() > 1) {
// Remove the user's phone number if present in the list of recipients
addressList.removeIf(address -> sendingPhoneNumber.isMatchingPhoneNumber(address.address));
}
}
try {
Settings settings = new Settings();
TelephonyHelper.ApnSetting apnSettings = TelephonyHelper.getPreferredApn(context, subID);
if (apnSettings != null) {
settings.setMmsc(apnSettings.getMmsc().toString());
settings.setProxy(apnSettings.getMmsProxyAddressAsString());
settings.setPort(Integer.toString(apnSettings.getMmsProxyPort()));
} else {
settings.setUseSystemSending(true);
}
settings.setSendLongAsMms(longTextAsMms);
settings.setSendLongAsMmsAfter(sendLongAsMmsAfter);
settings.setGroup(groupMessageAsMms);
if (subID != -1) {
settings.setSubscriptionId(subID);
}
Transaction transaction = new Transaction(context, settings);
List<String> addresses = new ArrayList<>();
for (SMSHelper.Address address : addressList) {
addresses.add(address.toString());
}
Message message = new Message(textMessage, addresses.toArray(ArrayUtils.EMPTY_STRING_ARRAY));
// If there are any attachment files add those into the message
for (SMSHelper.Attachment attachedFile : attachedFiles) {
byte[] file = Base64.decode(attachedFile.getBase64EncodedFile(), Base64.DEFAULT);
String mimeType = attachedFile.getMimeType();
String fileName = attachedFile.getUniqueIdentifier();
message.addMedia(file, mimeType, fileName);
}
message.setFromAddress(sendingPhoneNumber.number);
message.setSave(true);
// This is the reason why there are separate branch handling for SMS and MMS.
if (transaction.checkMMS(message)) {
Log.v("", "Sending new MMS");
// transaction.sendNewMessage(message, Transaction.NO_THREAD_ID);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP_MR1) {
sendMmsMessageNative(context, message, settings);
} else {
// Cross fingers and hope Klinker's library works for this case
transaction.sendNewMessage(message, Transaction.NO_THREAD_ID);
}
} else {
Log.v(SENDING_MESSAGE, "Sending new SMS");
transaction.sendNewMessage(message, Transaction.NO_THREAD_ID);
}
// TODO: Notify other end
} catch (Exception e) {
// TODO: Notify other end
Log.e(SENDING_MESSAGE, "Exception", e);
}
}
Aggregations