diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index a93a40cf7..f9c1e7a43 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -8,6 +8,8 @@
android:name="android.permission.READ_EXTERNAL_STORAGE"/>
+
+ android:windowSoftInputMode="stateHidden"
+ android:exported="true"/>
-
-
-
-
-
-
-
-
-
-
-
-
-
0 && barcodeTypeField.getText().length() > 0)
{
String formatString = barcodeTypeField.getText().toString();
@@ -274,6 +302,7 @@ public class LoyaltyCardViewActivity extends AppCompatActivity
{
String store = storeFieldEdit.getText().toString();
String note = noteFieldEdit.getText().toString();
+ boolean shouldAddShortcut = shortcutCheckbox.isChecked();
String cardId = cardIdFieldView.getText().toString();
String barcodeType = barcodeTypeField.getText().toString();
@@ -296,19 +325,45 @@ public class LoyaltyCardViewActivity extends AppCompatActivity
}
else
{
- db.insertLoyaltyCard(store, note, cardId, barcodeType);
+ loyaltyCardId = (int)db.insertLoyaltyCard(store, note, cardId, barcodeType);
+ }
+
+ if(shouldAddShortcut)
+ {
+ addShortcut(loyaltyCardId, store);
}
finish();
}
+ private void addShortcut(int id, String name)
+ {
+ Intent shortcutIntent = new Intent(this, LoyaltyCardViewActivity.class);
+ shortcutIntent.setAction(Intent.ACTION_MAIN);
+ // Prevent instances of the view activity from piling up; if one exists let this
+ // one replace it.
+ shortcutIntent.setFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);
+ Bundle bundle = new Bundle();
+ bundle.putInt("id", id);
+ bundle.putBoolean("view", true);
+ shortcutIntent.putExtras(bundle);
+
+ Intent intent = new Intent();
+ intent.putExtra(Intent.EXTRA_SHORTCUT_INTENT, shortcutIntent);
+ intent.putExtra(Intent.EXTRA_SHORTCUT_NAME, name);
+ intent.putExtra(Intent.EXTRA_SHORTCUT_ICON_RESOURCE, Intent.ShortcutIconResource
+ .fromContext(this, R.mipmap.ic_launcher));
+ intent.setAction("com.android.launcher.action.INSTALL_SHORTCUT");
+ // Do not duplicate the shortcut if it is already there
+ intent.putExtra("duplicate", false);
+ getApplicationContext().sendBroadcast(intent);
+
+ Toast.makeText(this, R.string.addedShortcut, Toast.LENGTH_LONG).show();
+ }
+
@Override
public boolean onCreateOptionsMenu(Menu menu)
{
- final Bundle b = getIntent().getExtras();
- final boolean updateLoyaltyCard = b != null && b.getBoolean("update", false);
- final boolean viewLoyaltyCard = b != null && b.getBoolean("view", false);
-
if(viewLoyaltyCard)
{
getMenuInflater().inflate(R.menu.card_view_menu, menu);
@@ -332,9 +387,6 @@ public class LoyaltyCardViewActivity extends AppCompatActivity
{
int id = item.getItemId();
- final Bundle b = getIntent().getExtras();
- final int loyaltyCardId = b != null ? b.getInt("id") : 0;
-
switch(id)
{
case android.R.id.home:
diff --git a/app/src/main/java/protect/card_locker/ShortcutHelper.java b/app/src/main/java/protect/card_locker/ShortcutHelper.java
index 0b9dbc137..5773e5432 100644
--- a/app/src/main/java/protect/card_locker/ShortcutHelper.java
+++ b/app/src/main/java/protect/card_locker/ShortcutHelper.java
@@ -103,10 +103,16 @@ class ShortcutHelper
{
ShortcutInfo prevShortcut = list.get(index);
+ Intent shortcutIntent = prevShortcut.getIntent();
+
+ // Prevent instances of the view activity from piling up; if one exists let this
+ // one replace it.
+ shortcutIntent.setFlags(shortcutIntent.getFlags() | Intent.FLAG_ACTIVITY_SINGLE_TOP);
+
ShortcutInfo updatedShortcut = new ShortcutInfo.Builder(context, prevShortcut.getId())
.setShortLabel(prevShortcut.getShortLabel())
.setLongLabel(prevShortcut.getLongLabel())
- .setIntent(prevShortcut.getIntent())
+ .setIntent(shortcutIntent)
.setIcon(Icon.createWithResource(context, R.drawable.circle))
.setRank(index)
.build();
diff --git a/app/src/main/java/protect/card_locker/appwidget/CardAppWidgetConfigure.java b/app/src/main/java/protect/card_locker/appwidget/CardAppWidgetConfigure.java
deleted file mode 100644
index 1f611876f..000000000
--- a/app/src/main/java/protect/card_locker/appwidget/CardAppWidgetConfigure.java
+++ /dev/null
@@ -1,130 +0,0 @@
-package protect.card_locker.appwidget;
-
-import android.appwidget.AppWidgetManager;
-import android.content.Context;
-import android.content.Intent;
-import android.content.SharedPreferences;
-import android.database.Cursor;
-import android.os.Bundle;
-import android.support.v7.app.AppCompatActivity;
-import android.support.v7.widget.Toolbar;
-import android.util.Log;
-import android.view.View;
-import android.widget.AdapterView;
-import android.widget.ListView;
-
-import protect.card_locker.DBHelper;
-import protect.card_locker.LoyaltyCard;
-import protect.card_locker.LoyaltyCardCursorAdapter;
-import protect.card_locker.R;
-
-/**
- * The configuration screen for the CardAppWidgetProvider widget.
- */
-public class CardAppWidgetConfigure extends AppCompatActivity
-{
- static final String TAG = "LoyaltyCardLocker";
-
- private static final String PREFS_NAME
- = "protect.card_locker.appwidget.CardAppWidgetProvider";
- private static final String PREF_PREFIX_KEY = "prefix_";
-
- int appWidgetId_ = AppWidgetManager.INVALID_APPWIDGET_ID;
-
- @Override
- public void onCreate(Bundle bundle)
- {
- super.onCreate(bundle);
-
- // Set the result to CANCELED. This will cause the widget host to cancel
- // out of the widget placement if they press the back button.
- setResult(RESULT_CANCELED);
-
- setContentView(R.layout.main_activity);
- Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
- toolbar.setVisibility(View.GONE);
-
- setTitle(R.string.selectCardTitle);
-
- // Find the widget id from the intent.
- Intent intent = getIntent();
- Bundle extras = intent.getExtras();
- if (extras != null)
- {
- appWidgetId_ = extras.getInt(
- AppWidgetManager.EXTRA_APPWIDGET_ID, AppWidgetManager.INVALID_APPWIDGET_ID);
- }
-
- // If they gave us an intent without the widget id, just bail.
- if (appWidgetId_ == AppWidgetManager.INVALID_APPWIDGET_ID)
- {
- finish();
- }
-
- final DBHelper db = new DBHelper(this);
-
- // If there are no cards, bail
- if(db.getLoyaltyCardCount() == 0)
- {
- finish();
- }
-
- final ListView cardList = (ListView) findViewById(R.id.list);
- cardList.setVisibility(View.VISIBLE);
-
- Cursor cardCursor = db.getLoyaltyCardCursor();
-
- final LoyaltyCardCursorAdapter adapter = new LoyaltyCardCursorAdapter(this, cardCursor);
- cardList.setAdapter(adapter);
-
- cardList.setOnItemClickListener(new AdapterView.OnItemClickListener()
- {
- @Override
- public void onItemClick(AdapterView> parent, View view, int position, long id)
- {
- Context context = CardAppWidgetConfigure.this;
- Cursor selected = (Cursor) parent.getItemAtPosition(position);
- LoyaltyCard loyaltyCard = LoyaltyCard.toLoyaltyCard(selected);
-
- Log.d(TAG, "Saving card " + loyaltyCard.store + "," + loyaltyCard.id + " at " + appWidgetId_);
-
- // Save the association of the card to the widget
- saveIdPref(context, appWidgetId_, loyaltyCard.id);
-
- // Push widget update to surface with newly set association
- AppWidgetManager appWidgetManager = AppWidgetManager.getInstance(context);
- CardAppWidgetProvider.updateAppWidget(context, appWidgetManager, appWidgetId_);
-
- // Make sure we pass back the original appWidgetId
- Intent resultValue = new Intent();
- resultValue.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetId_);
- setResult(RESULT_OK, resultValue);
- finish();
- }
- });
- }
-
- // Write the prefix to the SharedPreferences object for this widget
- static void saveIdPref(Context context, int appWidgetId, int id)
- {
- SharedPreferences.Editor prefs = context.getSharedPreferences(PREFS_NAME, 0).edit();
- prefs.putInt(PREF_PREFIX_KEY + appWidgetId, id);
- prefs.commit();
- }
-
- // Read the prefix from the SharedPreferences object for this widget.
- // If there is no preference saved, get the default from a resource
- static Integer loadIdPref(Context context, int appWidgetId)
- {
- SharedPreferences prefs = context.getSharedPreferences(PREFS_NAME, 0);
- int id = prefs.getInt(PREF_PREFIX_KEY + appWidgetId, -1);
- if(id >= 0)
- {
- return id;
- }
- else
- {
- return null;
- }
- }
-}
diff --git a/app/src/main/java/protect/card_locker/appwidget/CardAppWidgetProvider.java b/app/src/main/java/protect/card_locker/appwidget/CardAppWidgetProvider.java
deleted file mode 100644
index 162e6ff90..000000000
--- a/app/src/main/java/protect/card_locker/appwidget/CardAppWidgetProvider.java
+++ /dev/null
@@ -1,79 +0,0 @@
-package protect.card_locker.appwidget;
-
-import android.app.PendingIntent;
-import android.appwidget.AppWidgetManager;
-import android.appwidget.AppWidgetProvider;
-import android.content.Context;
-import android.content.Intent;
-
-import android.os.Bundle;
-import android.util.Log;
-import android.widget.RemoteViews;
-
-import protect.card_locker.DBHelper;
-import protect.card_locker.LoyaltyCard;
-import protect.card_locker.LoyaltyCardViewActivity;
-import protect.card_locker.R;
-
-public class CardAppWidgetProvider extends AppWidgetProvider
-{
- private static final String TAG = "LoyaltyCardLocker";
-
- @Override
- public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds)
- {
- Log.d(TAG, "CardAppWidgetProvider onUpdate");
- // For each widget that needs an update, get the text that we should display:
- // - Create a RemoteViews object for it
- // - Set the text in the RemoteViews object
- // - Tell the AppWidgetManager to show that views object for the widget.
- for (int appWidgetId : appWidgetIds)
- {
- updateAppWidget(context, appWidgetManager, appWidgetId);
- }
- }
-
- static void updateAppWidget(Context context, AppWidgetManager appWidgetManager, int appWidgetId)
- {
- Log.d(TAG, "updateAppWidget appWidgetId=" + appWidgetId);
-
- LoyaltyCard card = null;
- DBHelper db = new DBHelper(context);
-
- Integer id = CardAppWidgetConfigure.loadIdPref(context, appWidgetId);
- if(id != null)
- {
- Log.d(TAG, "updateAppWidget Retrieved id " + id);
- card = db.getLoyaltyCard(id);
- }
-
- if(card != null)
- {
- Log.d(TAG, "updateAppWidget Updating widget " + appWidgetId + " to load " + card.store);
-
- // Construct the RemoteViews object. It takes the package name (in our case, it's our
- // package, but it needs this because on the other side it's the widget host inflating
- // the layout from our package).
- RemoteViews views = new RemoteViews(context.getPackageName(), R.layout.appwidget_provider);
- views.setTextViewText(R.id.title, card.store);
-
- // Launch the view activity when clicked
- Intent intent = new Intent(context, LoyaltyCardViewActivity.class);
- Bundle extras = new Bundle();
- extras.putInt("id", id);
- extras.putBoolean("view", true);
- intent.putExtras(extras);
- intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
- PendingIntent pendingIntent = PendingIntent.getActivity(context, 0, intent, 0);
- views.setOnClickPendingIntent(R.id.widget, pendingIntent);
-
- // Tell the widget manager
- appWidgetManager.updateAppWidget(appWidgetId, views);
- }
- else
- {
- Log.d(TAG, "updateAppWidget, no card ID associated with widget " + appWidgetId
- + ", ignoring update");
- }
- }
-}
diff --git a/app/src/main/res/layout/appwidget_provider.xml b/app/src/main/res/layout/appwidget_provider.xml
deleted file mode 100644
index 1c8c550e4..000000000
--- a/app/src/main/res/layout/appwidget_provider.xml
+++ /dev/null
@@ -1,23 +0,0 @@
-
-
-
-
-
-
diff --git a/app/src/main/res/layout/loyalty_card_view_activity.xml b/app/src/main/res/layout/loyalty_card_view_activity.xml
index 8e2a6da93..940a869d7 100644
--- a/app/src/main/res/layout/loyalty_card_view_activity.xml
+++ b/app/src/main/res/layout/loyalty_card_view_activity.xml
@@ -146,6 +146,55 @@
android:background="@color/inputBorder" />
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Store
Note
+ Add Shortcut
Card ID
Barcode Type
@@ -26,12 +27,12 @@
OK
Copy ID to clipboard
Send…
+ Added shortcut
Edit Loyalty Card
Add Loyalty Card
View Loyalty Card
Scan Card\'s Barcode
- Select Card
Image of card\'s barcode
diff --git a/app/src/main/res/xml/appwidget_provider.xml b/app/src/main/res/xml/appwidget_provider.xml
deleted file mode 100644
index 24c3b655d..000000000
--- a/app/src/main/res/xml/appwidget_provider.xml
+++ /dev/null
@@ -1,9 +0,0 @@
-
-
-
\ No newline at end of file
diff --git a/app/src/test/java/protect/card_locker/DatabaseTest.java b/app/src/test/java/protect/card_locker/DatabaseTest.java
index 7eab1444d..7d577469e 100644
--- a/app/src/test/java/protect/card_locker/DatabaseTest.java
+++ b/app/src/test/java/protect/card_locker/DatabaseTest.java
@@ -36,7 +36,8 @@ public class DatabaseTest
public void addRemoveOneGiftCard()
{
assertEquals(0, db.getLoyaltyCardCount());
- boolean result = db.insertLoyaltyCard("store", "note", "cardId", BarcodeFormat.UPC_A.toString());
+ long id = db.insertLoyaltyCard("store", "note", "cardId", BarcodeFormat.UPC_A.toString());
+ boolean result = (id != -1);
assertTrue(result);
assertEquals(1, db.getLoyaltyCardCount());
@@ -56,7 +57,8 @@ public class DatabaseTest
@Test
public void updateGiftCard()
{
- boolean result = db.insertLoyaltyCard("store", "note", "cardId", BarcodeFormat.UPC_A.toString());
+ long id = db.insertLoyaltyCard("store", "note", "cardId", BarcodeFormat.UPC_A.toString());
+ boolean result = (id != -1);
assertTrue(result);
assertEquals(1, db.getLoyaltyCardCount());
@@ -86,7 +88,8 @@ public class DatabaseTest
@Test
public void emptyGiftCardValues()
{
- boolean result = db.insertLoyaltyCard("", "", "", "");
+ long id = db.insertLoyaltyCard("", "", "", "");
+ boolean result = (id != -1);
assertTrue(result);
assertEquals(1, db.getLoyaltyCardCount());
@@ -107,8 +110,9 @@ public class DatabaseTest
// that they are sorted
for(int index = CARDS_TO_ADD-1; index >= 0; index--)
{
- boolean result = db.insertLoyaltyCard("store" + index, "note" + index, "cardId" + index,
+ long id = db.insertLoyaltyCard("store" + index, "note" + index, "cardId" + index,
BarcodeFormat.UPC_A.toString());
+ boolean result = (id != -1);
assertTrue(result);
}
diff --git a/app/src/test/java/protect/card_locker/ImportExportTest.java b/app/src/test/java/protect/card_locker/ImportExportTest.java
index 7f96e5519..858e37145 100644
--- a/app/src/test/java/protect/card_locker/ImportExportTest.java
+++ b/app/src/test/java/protect/card_locker/ImportExportTest.java
@@ -65,7 +65,8 @@ public class ImportExportTest
{
String storeName = String.format("store, \"%4d", index);
String note = String.format("note, \"%4d", index);
- boolean result = db.insertLoyaltyCard(storeName, note, BARCODE_DATA, BARCODE_TYPE);
+ long id = db.insertLoyaltyCard(storeName, note, BARCODE_DATA, BARCODE_TYPE);
+ boolean result = (id != -1);
assertTrue(result);
}
diff --git a/app/src/test/java/protect/card_locker/LoyaltyCardViewActivityTest.java b/app/src/test/java/protect/card_locker/LoyaltyCardViewActivityTest.java
index 81320604c..6f7b56731 100644
--- a/app/src/test/java/protect/card_locker/LoyaltyCardViewActivityTest.java
+++ b/app/src/test/java/protect/card_locker/LoyaltyCardViewActivityTest.java
@@ -9,6 +9,7 @@ import android.os.Bundle;
import android.view.Menu;
import android.view.View;
import android.widget.Button;
+import android.widget.CheckBox;
import android.widget.EditText;
import android.widget.TextView;
@@ -29,6 +30,7 @@ import org.robolectric.android.controller.ActivityController;
import java.io.IOException;
+import static junit.framework.Assert.assertNull;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
@@ -87,6 +89,7 @@ public class LoyaltyCardViewActivityTest
*/
private void saveLoyaltyCardWithArguments(final Activity activity,
final String store, final String note,
+ final boolean addShortcut,
final String cardId,
final String barcodeType,
boolean creatingNewCard)
@@ -103,18 +106,25 @@ public class LoyaltyCardViewActivityTest
final EditText storeField = (EditText) activity.findViewById(R.id.storeNameEdit);
final EditText noteField = (EditText) activity.findViewById(R.id.noteEdit);
+ final CheckBox shortcutCheckbox = (CheckBox) activity.findViewById(R.id.shortcutCheckbox);
final TextView cardIdField = (TextView) activity.findViewById(R.id.cardIdView);
final TextView barcodeTypeField = (TextView) activity.findViewById(R.id.barcodeType);
storeField.setText(store);
noteField.setText(note);
+ shortcutCheckbox.setChecked(addShortcut);
cardIdField.setText(cardId);
barcodeTypeField.setText(barcodeType);
+ ShortcutAddedReceiver shortcutAddedReceiver = new ShortcutAddedReceiver();
+ shortcutAddedReceiver.registerReceiver(activity);
+
assertEquals(false, activity.isFinishing());
shadowOf(activity).clickMenuItem(R.id.action_save);
assertEquals(true, activity.isFinishing());
+ shortcutAddedReceiver.unregisterReceiver(activity);
+
assertEquals(1, db.getLoyaltyCardCount());
LoyaltyCard card = db.getLoyaltyCard(1);
@@ -122,6 +132,28 @@ public class LoyaltyCardViewActivityTest
assertEquals(note, card.note);
assertEquals(cardId, card.cardId);
assertEquals(barcodeType, card.barcodeType);
+
+ Intent shortcutRequest = shortcutAddedReceiver.lastRequest();
+
+ if(addShortcut)
+ {
+ assertNotNull(shortcutRequest);
+
+ String name = shortcutRequest.getStringExtra(Intent.EXTRA_SHORTCUT_NAME);
+ assertEquals(card.store, name);
+
+ Intent startIntent = shortcutRequest.getParcelableExtra(Intent.EXTRA_SHORTCUT_INTENT);
+ assertNotNull(startIntent);
+ Bundle startBundle = startIntent.getExtras();
+ assertNotNull(startBundle);
+
+ assertEquals(card.id, startBundle.getInt("id", -1));
+ assertEquals(true, startBundle.getBoolean("view", false));
+ }
+ else
+ {
+ assertNull(shortcutRequest);
+ }
}
/**
@@ -184,6 +216,8 @@ public class LoyaltyCardViewActivityTest
checkFieldProperties(activity, R.id.storeNameEdit, editVisibility, store);
checkFieldProperties(activity, R.id.storeNameView, viewVisibility, store);
checkFieldProperties(activity, R.id.noteEdit, editVisibility, note);
+ checkFieldProperties(activity, R.id.shortcutBorder, editVisibility, null);
+ checkFieldProperties(activity, R.id.shortcutTablerow, editVisibility, null);
checkFieldProperties(activity, R.id.noteView, viewVisibility, note);
checkFieldProperties(activity, R.id.cardIdView, View.VISIBLE, cardId);
checkFieldProperties(activity, R.id.cardIdDivider, cardId.isEmpty() ? View.GONE : View.VISIBLE, null);
@@ -274,7 +308,30 @@ public class LoyaltyCardViewActivityTest
checkAllFields(activity, ViewMode.ADD_CARD, "", "", BARCODE_DATA, BARCODE_TYPE);
// Save and check the gift card
- saveLoyaltyCardWithArguments(activity, "store", "note", BARCODE_DATA, BARCODE_TYPE, true);
+ saveLoyaltyCardWithArguments(activity, "store", "note", false, BARCODE_DATA, BARCODE_TYPE, true);
+ }
+
+ @Test
+ public void startWithoutParametersCaptureBarcodeCreateLoyaltyCardSaveShortcut() throws IOException
+ {
+ registerMediaStoreIntentHandler();
+
+ ActivityController activityController = Robolectric.buildActivity(LoyaltyCardViewActivity.class).create();
+ activityController.start();
+ activityController.visible();
+ activityController.resume();
+
+ Activity activity = (Activity)activityController.get();
+
+ checkAllFields(activity, ViewMode.ADD_CARD, "", "", "", "");
+
+ // Complete barcode capture successfully
+ captureBarcodeWithResult(activity, R.id.captureButton, true);
+
+ checkAllFields(activity, ViewMode.ADD_CARD, "", "", BARCODE_DATA, BARCODE_TYPE);
+
+ // Save and check the gift card
+ saveLoyaltyCardWithArguments(activity, "store", "note", true, BARCODE_DATA, BARCODE_TYPE, true);
}
@Test
diff --git a/app/src/test/java/protect/card_locker/ShortcutAddedReceiver.java b/app/src/test/java/protect/card_locker/ShortcutAddedReceiver.java
new file mode 100644
index 000000000..d29c17eac
--- /dev/null
+++ b/app/src/test/java/protect/card_locker/ShortcutAddedReceiver.java
@@ -0,0 +1,39 @@
+package protect.card_locker;
+
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+
+public class ShortcutAddedReceiver extends BroadcastReceiver
+{
+ public static final String SHORTCUT_ADD_REQUEST = "com.android.launcher.action.INSTALL_SHORTCUT";
+
+ private Intent _request = null;
+
+ @Override
+ public void onReceive(Context context, Intent intent)
+ {
+ _request = intent;
+ }
+
+ public void registerReceiver(Context context)
+ {
+ context.registerReceiver(this, new IntentFilter(SHORTCUT_ADD_REQUEST));
+ }
+
+ public void unregisterReceiver(Context context)
+ {
+ context.unregisterReceiver(this);
+ }
+
+ public Intent lastRequest()
+ {
+ return _request;
+ }
+
+ public void reset()
+ {
+ _request = null;
+ }
+}