Skip to content

Commit

Permalink
Closes #9 - Support issue reporting
Browse files Browse the repository at this point in the history
  • Loading branch information
salowenh committed Oct 13, 2019
1 parent 6697371 commit 5397250
Show file tree
Hide file tree
Showing 15 changed files with 235 additions and 49 deletions.
5 changes: 3 additions & 2 deletions app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,8 @@ android {
applicationId "com.lowenhardt.pickup"
minSdkVersion 16
targetSdkVersion 29
versionCode 4
versionName "1.1.1"
versionCode 5
versionName "1.1.2"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
setProperty("archivesBaseName", "pickup.${versionName}.vc.${versionCode}")
multiDexEnabled = true
Expand All @@ -37,6 +37,7 @@ dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])
implementation 'androidx.appcompat:appcompat:1.1.0'
implementation 'androidx.constraintlayout:constraintlayout:1.1.3'
implementation "androidx.preference:preference:1.1.0"
implementation 'com.google.android.material:material:1.0.0'
implementation 'com.google.firebase:firebase-analytics:17.2.0'
implementation 'com.crashlytics.sdk.android:crashlytics:2.10.1'
Expand Down
13 changes: 13 additions & 0 deletions app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/AppTheme.NoActionBar">

<activity
android:name=".MainActivity"
android:label="@string/app_name">
Expand All @@ -25,13 +26,25 @@
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>

<activity android:name=".ContactConfigActivity" />

<receiver android:name=".CallReceiver">
<intent-filter>
<action android:name="android.intent.action.PHONE_STATE" />
</intent-filter>
</receiver>

<provider
android:name="androidx.core.content.FileProvider"
android:authorities="com.lowenhardt.pickup.fileprovider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/paths" />
</provider>

</application>

</manifest>
3 changes: 1 addition & 2 deletions app/src/main/java/com/lowenhardt/pickup/CallReceiver.java
Original file line number Diff line number Diff line change
Expand Up @@ -58,8 +58,7 @@ private void unmute(Context c, ContactConfig matchingContact) {
changeVolume(c, matchingContact);
postUnmuteNotification(c, matchingContact);
} catch (Exception e) {
Crashlytics.log(Log.ERROR, TAG, "Failed to change ringer/volumes");
Crashlytics.logException(e);
ErrorLogger.log(c, TAG, "Failed to change ringer/volumes", e);
}
}

Expand Down
144 changes: 144 additions & 0 deletions app/src/main/java/com/lowenhardt/pickup/ContactUs.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,144 @@
package com.lowenhardt.pickup;

import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
import android.content.pm.ResolveInfo;
import android.net.Uri;
import android.os.Build;

import androidx.core.content.FileProvider;
import androidx.preference.PreferenceManager;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.List;

class ContactUs {
protected static String TAG = ContactUs.class.getName();

private final static String CONTACT_DIR_NAME = "contact_us_files"; // same as in paths.xml
private final static String REPORT_INFO_FILE_NAME = "info.txt";
private static final String AUTHORITY = "com.lowenhardt.pickup.fileprovider";

static void contact(Activity activity) {
contact(activity, null);
}

static void contact(Activity activity, String message) {

Intent emailIntent = new Intent(Intent.ACTION_SEND_MULTIPLE);
emailIntent.setType("text/plain");

String version = Version.appVersion(activity);
emailIntent.putExtra(Intent.EXTRA_EMAIL, new String[]{activity.getString(R.string.contact_email)});
emailIntent.putExtra(Intent.EXTRA_SUBJECT, activity.getString(R.string.app_name)+" ("+version+")");
if (message != null) {
emailIntent.putExtra(Intent.EXTRA_TEXT, message);
}

addInfoAttachment(emailIntent, activity);

String title = activity.getString(R.string.string_select_email_app);
activity.startActivity(Intent.createChooser(emailIntent, title));
}

private static void addInfoAttachment(Intent emailIntent, Context context) {
File infoFile = createInfoFile(context);
if (infoFile == null) {
return;
}

Uri uri = FileProvider.getUriForFile(context, AUTHORITY, infoFile);
ArrayList<Uri> uris = new ArrayList<>(1);
uris.add(uri);
emailIntent.putParcelableArrayListExtra(Intent.EXTRA_STREAM, uris);
emailIntent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
// Workaround for Android bug.
// grantUriPermission also needed for KITKAT
// see https://code.google.com/p/android/issues/detail?id=76683
if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.KITKAT) {
List<ResolveInfo> resInfoList = context.getPackageManager().queryIntentActivities(
emailIntent, PackageManager.MATCH_DEFAULT_ONLY);
for (ResolveInfo resolveInfo : resInfoList) {
String packageName = resolveInfo.activityInfo.packageName;
context.grantUriPermission(packageName, uri, Intent.FLAG_GRANT_READ_URI_PERMISSION);
}
}
}

private static String getInstaller(final Context context) {
return context.getPackageManager().getInstallerPackageName(context.getPackageName());
}

private static File createInfoFile(Context context) {
File dirpath = new File(context.getFilesDir(), CONTACT_DIR_NAME);
if (!dirpath.mkdirs() && (!dirpath.isDirectory())) {
ErrorLogger.log(context, TAG, "Failed to create info file path: " + dirpath.getAbsolutePath(), true);
return null;
}

File file = new File(dirpath, REPORT_INFO_FILE_NAME);
//noinspection ResultOfMethodCallIgnored
file.delete();

try {
if (!file.createNewFile() && !file.isFile()) {
Exception e = new Exception("Failed to create info file: " + file.getAbsolutePath());
ErrorLogger.log(context, TAG,
"Failed to create info file" + file.getAbsolutePath(), e);
return null;
}
} catch (IOException e) {
ErrorLogger.log(context, TAG,
"Failed to create info file" + file.getAbsolutePath(), e);
return null;
}

try {
FileOutputStream fos = new FileOutputStream(file);
String data = getInfo(context);
fos.write(data.getBytes());
fos.close();
return file;
} catch (IOException exception) {
ErrorLogger.log(context, TAG, "Failed to write cached file: " + REPORT_INFO_FILE_NAME, exception);
}
return null;
}

private static String getInfo(Context context) {
MyPreferenceManager mpm = new MyPreferenceManager(context);
String data ="";
data += "Android SDK version: " +android.os.Build.VERSION.SDK_INT + "\n";
data += "Android version: " + android.os.Build.VERSION.RELEASE + "\n";
data += "Google Play Services version: " + getGooglePlayServicesVersion(context) + "\n";
data += "Device: " + android.os.Build.MODEL + "\n";
data += "App Version: " + (Version.appVersion(context) + "\n");
data += "Code Version: " + (Version.codeVersion(context) + "\n");
data += "Installer: " + getInstaller(context) + "\n";
data += "Timestamp: " + Calendar.getInstance().getTime() + "\n";
SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(context);
data += "Error 1:" + sp.getString(context.getString(R.string.error_latest_1), "none") + "\n";
data += "Error 2:" + sp.getString(context.getString(R.string.error_latest_2), "none") + "\n";
data += "Error 3:" + sp.getString(context.getString(R.string.error_latest_3), "none") + "\n";
data += "Error 4:" + sp.getString(context.getString(R.string.error_latest_4), "none") + "\n";
data += "Error 5:" + sp.getString(context.getString(R.string.error_latest_5), "none") + "\n";
return data;
}

static private int getGooglePlayServicesVersion(Context c) {
try {
return c.getPackageManager().getPackageInfo("com.google.android.gms", 0 ).versionCode;
} catch (NameNotFoundException e) {
ErrorLogger.log(c, TAG, "Exception while trying to get play services version", e);
}
return -1;
}
}
23 changes: 8 additions & 15 deletions app/src/main/java/com/lowenhardt/pickup/Database.java
Original file line number Diff line number Diff line change
Expand Up @@ -91,8 +91,7 @@ public ContactConfig addOrUpdate(ContactConfig contactConfig, Context context) {
contactConfig.setId(id);
return contactConfig;
} catch (SQLiteException e) {
Crashlytics.log(Log.ERROR, TAG, "Exception while adding ContactConfig");
Crashlytics.logException(e);
ErrorLogger.log(context, TAG, "Exception while adding ContactConfig", e);
} finally {
if (db != null) {
db.close();
Expand All @@ -105,7 +104,7 @@ public ContactConfig addOrUpdate(ContactConfig contactConfig, Context context) {
// This will insert the reminder as a new row, even if it already exists with ID!
private ContactConfig addContactConfig(ContactConfig contactConfig, Context context) {
if (contactConfig == null) {
Crashlytics.log(Log.ERROR, TAG, "Tried to add null contactConfig");
ErrorLogger.log(context, TAG, "Tried to add null contactConfig", true);
return null;
}

Expand All @@ -118,8 +117,7 @@ private ContactConfig addContactConfig(ContactConfig contactConfig, Context cont
Crashlytics.log(Log.INFO, TAG, "Added new contactConfig to DB, reminder: "+contactConfig);
return contactConfig;
} catch (SQLiteException e) {
Crashlytics.log(Log.ERROR, TAG, "Exception while adding contactConfig");
Crashlytics.logException(e);
ErrorLogger.log(context, TAG, "Exception while adding contactConfig", e);
} finally {
if (db != null) {
db.close();
Expand Down Expand Up @@ -157,8 +155,7 @@ void removeContactConfig(long id, Context context) {
Crashlytics.log(Log.INFO, TAG, "Removed contact config from DB, id: "+id+", numRemoved: "+removed);
} catch (SQLiteException e) {
if (context != null) {
Crashlytics.log(Log.ERROR, TAG, "Exception while trying to remove scheduled reminder, id: " + id);
Crashlytics.logException(e);
ErrorLogger.log(context, TAG, "Exception while trying to remove scheduled reminder, id: " + id, e);
}
} finally {
if (db != null) {
Expand All @@ -176,8 +173,7 @@ void removeContactConfigs(List<Long> ids, Context context) {
Crashlytics.log(Log.INFO, TAG, "Removed contact configs, ids: "+args[0]+", deleted: "+deleted);
} catch (SQLiteException e) {
String idsStr = TextUtils.join(",", ids);
Crashlytics.log(Log.ERROR, TAG, "Exception while trying to remove scheduled reminders, ids: "+idsStr);
Crashlytics.logException(e);
ErrorLogger.log(context, TAG, "Exception while trying to remove scheduled reminders, ids: "+idsStr, e);
} finally {
if (db != null) {
db.close();
Expand Down Expand Up @@ -206,8 +202,7 @@ void removeContactConfigs(List<Long> ids, Context context) {
cursor.close();
}
} catch (SQLiteException e) {
Crashlytics.log(Log.ERROR, TAG, "Exception while trying to get reminders");
Crashlytics.logException(e);
ErrorLogger.log(context, TAG, "Exception while trying to get reminders", e);
} finally {
if (db != null) {
db.close();
Expand Down Expand Up @@ -238,8 +233,7 @@ void removeContactConfigs(List<Long> ids, Context context) {
cursor.close();
}
} catch (SQLiteException e) {
Crashlytics.log(Log.ERROR, TAG, "Exception while trying to get reminders");
Crashlytics.logException(e);
ErrorLogger.log(context, TAG, "Exception while trying to get reminders", e);
} finally {
if (db != null) {
db.close();
Expand All @@ -258,8 +252,7 @@ public void removeAll(Context context) {
Crashlytics.log(Log.INFO, TAG, "Deleted all reminders, num deleted: "+deleted);
}
} catch (SQLiteException e) {
Crashlytics.log(Log.ERROR, TAG, "Exception while trying to remove all reminders");
Crashlytics.logException(e);
ErrorLogger.log(context, TAG, "Exception while trying to remove all reminders", e);
} finally {
if (db != null) {
db.close();
Expand Down
5 changes: 3 additions & 2 deletions app/src/main/java/com/lowenhardt/pickup/ErrorLogger.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,10 @@

import android.content.Context;
import android.content.SharedPreferences;
import android.preference.PreferenceManager;
import android.util.Log;

import androidx.preference.PreferenceManager;

import com.crashlytics.android.Crashlytics;

import java.util.Calendar;
Expand Down Expand Up @@ -40,7 +41,7 @@ static private String toString(Exception e) {
return str;
}

// dont do anything that requires main thread
// don't do anything that requires main thread
static public void log(Context context, String tag, String msg, Exception e) {
String exceptionStr = toString(e);
if (context != null) {
Expand Down
15 changes: 6 additions & 9 deletions app/src/main/java/com/lowenhardt/pickup/MainActivity.java
Original file line number Diff line number Diff line change
Expand Up @@ -147,16 +147,13 @@ public boolean onCreateOptionsMenu(Menu menu) {

@Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle action bar item clicks here. The action bar will
// automatically handle clicks on the Home/Up button, so long
// as you specify a parent activity in AndroidManifest.xml.
int id = item.getItemId();

//noinspection SimplifiableIfStatement
if (id == R.id.action_settings) {
return true;
switch (id) {
case R.id.menu_contact:
ContactUs.contact(this);
return true;
default:
return super.onOptionsItemSelected(item);
}

return super.onOptionsItemSelected(item);
}
}
35 changes: 35 additions & 0 deletions app/src/main/java/com/lowenhardt/pickup/Version.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
package com.lowenhardt.pickup;

import android.content.Context;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;

class Version {

static String appVersion(Context context) {
try {
PackageInfo pInfo = context.getPackageManager().getPackageInfo(
context.getPackageName(), 0);
if (pInfo != null) {
return pInfo.versionName;
}
} catch (PackageManager.NameNotFoundException e) {
e.printStackTrace();
}
return "unknown";
}

static int codeVersion(Context context) {
try {
PackageInfo pInfo = context.getPackageManager().getPackageInfo(
context.getPackageName(), 0);
if (pInfo != null) {
return pInfo.versionCode;
}
} catch (PackageManager.NameNotFoundException e) {
e.printStackTrace();
}
return -1;
}

}
4 changes: 2 additions & 2 deletions app/src/main/res/layout/activity_main.xml
Original file line number Diff line number Diff line change
Expand Up @@ -11,14 +11,14 @@
<com.google.android.material.appbar.AppBarLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:theme="@style/AppTheme.NoActionBar.AppBarOverlay">
android:theme="@style/AppTheme.AppBarOverlay">

<androidx.appcompat.widget.Toolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:background="?attr/colorPrimary"
app:popupTheme="@style/AppTheme.NoActionBar.PopupOverlay" />
app:popupTheme="@style/AppTheme.PopupOverlay" />

</com.google.android.material.appbar.AppBarLayout>

Expand Down
2 changes: 1 addition & 1 deletion app/src/main/res/layout/dialog_contact_config.xml
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@
android:layout_height="wrap_content"
android:singleLine="true"
android:textSize="@dimen/contact_config_edittext_text_size"
android:hint="@string/name_auto_complete"/>
android:hint="@string/name"/>

</com.google.android.material.textfield.TextInputLayout>

Expand Down
Loading

0 comments on commit 5397250

Please sign in to comment.