add on adapter, add on items, add on activity now populated

pull/14/head
Tim Su 16 years ago
parent 2735c80979
commit ad4e1db7a4

@ -4,6 +4,7 @@
package com.todoroo.andlib.service;
import android.content.Context;
import android.content.res.Resources;
/**
* Singleton class to manage current application context
@ -43,4 +44,14 @@ public final class ContextManager {
public static String getString(int resId, Object... formatArgs) {
return context.getString(resId, formatArgs);
}
/**
* Convenience method to read resources
*
* @return
*/
public static Resources getResources() {
return context.getResources();
}
}

@ -14,7 +14,7 @@ import com.todoroo.astrid.api.TaskAction;
import com.todoroo.astrid.api.TaskDecoration;
import com.todoroo.astrid.core.PluginServices;
import com.todoroo.astrid.model.Task;
import com.todoroo.astrid.service.AddonService;
import com.todoroo.astrid.service.AddOnService;
/**
* Exposes {@link TaskDecoration} for timers
@ -32,7 +32,7 @@ public class TimerActionExposer extends BroadcastReceiver {
if(taskId == -1)
return;
if(!AddonService.isPowerPack())
if(!AddOnService.isPowerPack())
return;
Task task = PluginServices.getTaskService().fetchById(taskId, Task.ID, Task.TIMER_START,

Binary file not shown.

Before

Width:  |  Height:  |  Size: 15 KiB

After

Width:  |  Height:  |  Size: 12 KiB

@ -7,32 +7,18 @@
<!-- =================================================== tab: installed == -->
<ScrollView android:id="@+id/installed_tab"
android:layout_width="fill_parent"
android:layout_height="fill_parent">
<LinearLayout android:id="@+id/installed_container"
<ListView android:id="@+id/installed"
android:paddingRight="8dip"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent">
</LinearLayout>
</ScrollView>
android:layout_height="fill_parent" />
<!-- =================================================== tab: available == -->
<ScrollView android:id="@+id/availble_tab"
android:layout_width="fill_parent"
android:layout_height="fill_parent">
<LinearLayout android:id="@+id/available_container"
<ListView android:id="@+id/available"
android:paddingRight="8dip"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent">
</LinearLayout>
</ScrollView>
android:layout_height="fill_parent" />
</FrameLayout>

@ -0,0 +1,67 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- See the file "LICENSE" for the full license governing this code. -->
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:background="@android:drawable/list_selector_background"
android:paddingTop="4dip"
android:paddingBottom="4dip"
android:paddingLeft="4dip"
android:paddingRight="4dip">
<!-- icon -->
<ImageView android:id="@+id/icon"
android:layout_width="34dip"
android:layout_height="fill_parent"
android:gravity="center"
android:paddingLeft="5dip"
android:scaleType="fitCenter"/>
<LinearLayout
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_weight="100"
android:paddingLeft="8dip"
android:paddingRight="3dip"
android:orientation="vertical">
<!-- add-on name -->
<TextView android:id="@+id/title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentTop="true"
android:layout_toRightOf="@id/icon"
android:singleLine="true"
style="@style/TextAppearance.TAd_ItemTitle"/>
<!-- description -->
<TextView android:id="@+id/description"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@id/title"
android:layout_toRightOf="@id/icon"
android:singleLine="true"
style="@style/TextAppearance.TAd_ItemDetails"/>
</LinearLayout>
<!-- buttons -->
<ImageButton android:id="@+id/button_web"
android:layout_width="32dip"
android:layout_height="32dip"
android:layout_gravity="center" />
<ImageButton android:id="@+id/button_market"
android:layout_width="32dip"
android:layout_height="32dip"
android:layout_gravity="center" />
<ImageView android:id="@+id/check"
android:layout_width="32dip"
android:layout_height="32dip"
android:layout_gravity="center"
android:src="@android:drawable/checkbox_on_background"/>
</LinearLayout>

@ -236,40 +236,61 @@
<!-- ===================================================== tab: add-ons == -->
<ScrollView
<LinearLayout
android:id="@+id/tab_addons"
android:layout_width="fill_parent"
android:layout_height="fill_parent">
android:layout_height="fill_parent"
android:orientation="vertical">
<LinearLayout
android:paddingRight="8dip"
android:orientation="vertical"
<ScrollView
android:layout_width="fill_parent"
android:layout_height="fill_parent">
android:layout_height="fill_parent"
android:layout_weight="100">
<!-- add-ons -->
<LinearLayout android:id="@+id/tab_addons_addons"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:layout_weight="100"
android:orientation="vertical" />
<!-- separator -->
<View
</ScrollView>
<LinearLayout android:id="@+id/addons_empty"
android:layout_width="fill_parent"
android:layout_height="1dip"
android:layout_weight="1"
android:padding="5dip"
android:background="@android:drawable/divider_horizontal_dark" />
android:layout_height="fill_parent"
android:layout_weight="100"
android:visibility="gone"
android:orientation="vertical">
<ImageView
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:padding="10dip"
android:src="@drawable/icon_pp" />
<TextView
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="@string/TEA_no_addons"
android:gravity="center"
style="@style/TextAppearance.TLA_NoItems" />
<Button android:id="@+id/addons_button"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="@string/TEA_addons_button" />
</LinearLayout>
<LinearLayout
android:orientation="horizontal"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_weight="1"
android:gravity="bottom"
android:paddingTop="5dip"
android:orientation="horizontal"
android:background="@drawable/edit_header"
android:padding="5dip"
android:baselineAligned="false">
<ImageButton
android:id="@+id/save_addons"
android:layout_width="fill_parent"
@ -283,6 +304,7 @@
android:layout_weight="1"
android:src="@drawable/tango_stop" />
</LinearLayout>
</LinearLayout>
</ScrollView>
</FrameLayout>

@ -446,10 +446,14 @@ to the plugin creator for fastest service.
<!-- Add-on Activity - available add-ons tab -->
<string name="AOA_tab_available">Available</string>
<!-- Dialog for Astrid Power Pack -->
<string name="AOA_power_pack">Support Astrid and get more productive with
the Astrid Power Pack backup, widgets, no ads, and calendar integration.
Power up today!</string>
<!-- Add-on Activity - free add-ons label -->
<string name="AOA_free">Free</string>
<!-- Add-on Activity - menu item to visit add-on website -->
<string name="AOA_visit_website">Visit Website</string>
<!-- Add-on Activity - menu item to visit android market -->
<string name="AOA_visit_market">Android Market</string>
<!-- ========================================== SynchronizationProvider == -->

@ -1,16 +1,40 @@
package com.todoroo.astrid.activity;
import java.util.ArrayList;
import android.app.TabActivity;
import android.content.res.Resources;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.widget.ListView;
import android.widget.TabHost;
import android.widget.TextView;
import com.timsu.astrid.R;
import com.todoroo.andlib.service.Autowired;
import com.todoroo.andlib.service.DependencyInjectionService;
import com.todoroo.astrid.adapter.AddOnAdapter;
import com.todoroo.astrid.model.AddOn;
import com.todoroo.astrid.service.AddOnService;
import com.todoroo.astrid.service.AstridDependencyInjector;
public class AddOnActivity extends TabActivity {
/** boolean: whether to start on available page */
public static final String TOKEN_START_WITH_AVAILABLE = "av"; //$NON-NLS-1$
@Autowired
AddOnService addOnService;
static {
AstridDependencyInjector.initialize();
}
public AddOnActivity() {
DependencyInjectionService.getInstance().inject(this);
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
@ -24,13 +48,47 @@ public class AddOnActivity extends TabActivity {
tabHost.addTab(tabHost.newTabSpec(r.getString(R.string.AOA_tab_installed)).
setIndicator(r.getString(R.string.AOA_tab_installed),
r.getDrawable(R.drawable.tab_addons)).setContent(
R.id.installed_tab));
R.id.installed));
tabHost.addTab(tabHost.newTabSpec(r.getString(R.string.AOA_tab_available)).
setIndicator(r.getString(R.string.AOA_tab_available),
r.getDrawable(R.drawable.tab_add)).setContent(
R.id.availble_tab));
R.id.available));
setTitle(R.string.AOA_title);
populate();
}
private void populate() {
AddOn[] list = addOnService.getAddOns();
if(list == null)
return;
ArrayList<AddOn> installed = new ArrayList<AddOn>();
ArrayList<AddOn> available = new ArrayList<AddOn>();
for(AddOn addOn : list) {
if(addOnService.isInstalled(addOn))
installed.add(addOn);
else
available.add(addOn);
}
if(installed.size() == 0 || getIntent().getBooleanExtra(TOKEN_START_WITH_AVAILABLE, false))
getTabHost().setCurrentTab(1);
TextView noAddons = new TextView(this);
noAddons.setText(R.string.TEA_no_addons);
noAddons.setTextAppearance(this, R.style.TextAppearance_TLA_NoItems);
ListView installedList = (ListView) findViewById(R.id.installed);
installedList.setEmptyView(noAddons);
installedList.setAdapter(new AddOnAdapter(this, true, installed));
ListView availableList = (ListView) findViewById(R.id.available);
availableList.setEmptyView(noAddons);
availableList.setAdapter(new AddOnAdapter(this, false, available));
}
}

@ -37,7 +37,6 @@ import android.content.IntentFilter;
import android.content.DialogInterface.OnCancelListener;
import android.content.res.Resources;
import android.os.Bundle;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuItem;
@ -51,17 +50,14 @@ import android.widget.CompoundButton;
import android.widget.DatePicker;
import android.widget.EditText;
import android.widget.ImageButton;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.RemoteViews;
import android.widget.Spinner;
import android.widget.TabHost;
import android.widget.TextView;
import android.widget.TimePicker;
import android.widget.Toast;
import android.widget.ToggleButton;
import android.widget.AdapterView.OnItemSelectedListener;
import android.widget.ImageView.ScaleType;
import com.flurry.android.FlurryAgent;
import com.timsu.astrid.R;
@ -76,7 +72,7 @@ import com.todoroo.astrid.dao.Database;
import com.todoroo.astrid.gcal.GCalControlSet;
import com.todoroo.astrid.model.Task;
import com.todoroo.astrid.repeats.RepeatControlSet;
import com.todoroo.astrid.service.AddonService;
import com.todoroo.astrid.service.AddOnService;
import com.todoroo.astrid.service.StartupService;
import com.todoroo.astrid.service.TaskService;
import com.todoroo.astrid.tags.TagsControlSet;
@ -215,30 +211,15 @@ public final class TaskEditActivity extends TabActivity {
controls.add(new RepeatControlSet(this, extrasAddons));
LinearLayout addonsAddons = (LinearLayout) findViewById(R.id.tab_addons_addons);
if(AddonService.isPowerPack()) {
if(AddOnService.isPowerPack()) {
controls.add(new GCalControlSet(this, addonsAddons));
controls.add(new TimerControlSet(this, addonsAddons));
}
// show add-on help if necessary
if(addonsAddons.getChildCount() == 0) {
ImageView ppIcon = new ImageView(this);
ppIcon.setImageResource(R.drawable.icon_pp);
ppIcon.setScaleType(ScaleType.CENTER);
ppIcon.setPadding(5, 10, 5, 10);
addonsAddons.addView(ppIcon);
TextView addOnText = new TextView(this);
addOnText.setText(R.string.TEA_no_addons);
addOnText.setTextAppearance(this, R.style.TextAppearance_TLA_NoItems);
addOnText.setGravity(Gravity.CENTER);
addOnText.setPadding(5, 10, 5, 10);
addonsAddons.addView(addOnText);
Button addOnButton = new Button(this);
addOnButton.setText(R.string.TEA_addons_button);
addonsAddons.addView(addOnButton);
addOnButton.setOnClickListener(new View.OnClickListener() {
findViewById(R.id.addons_empty).setVisibility(View.VISIBLE);
((Button)findViewById(R.id.addons_button)).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
startActivity(new Intent(TaskEditActivity.this, AddOnActivity.class));

@ -64,7 +64,7 @@ import com.todoroo.astrid.model.Task;
import com.todoroo.astrid.reminders.Notifications;
import com.todoroo.astrid.reminders.ReminderService;
import com.todoroo.astrid.reminders.ReminderService.AlarmScheduler;
import com.todoroo.astrid.service.AddonService;
import com.todoroo.astrid.service.AddOnService;
import com.todoroo.astrid.service.MetadataService;
import com.todoroo.astrid.service.StartupService;
import com.todoroo.astrid.service.TaskService;
@ -158,7 +158,7 @@ public class TaskListActivity extends ListActivity implements OnScrollListener {
if(database == null)
return;
AddonService.checkForUpgrades(this);
AddOnService.checkForUpgrades(this);
database.openForWriting();
setUpUiComponents();

@ -0,0 +1,147 @@
/**
* See the file "LICENSE" for the full license governing this code.
*/
package com.todoroo.astrid.adapter;
import java.util.List;
import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.graphics.drawable.Drawable;
import android.net.Uri;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.ImageButton;
import android.widget.ImageView;
import android.widget.TextView;
import com.timsu.astrid.R;
import com.todoroo.astrid.model.AddOn;
/**
* Adapter for {@link AddOn}s
*
* @author Tim Su <tim@todoroo.com>
*
*/
public class AddOnAdapter extends ArrayAdapter<AddOn> {
// --- instance variables
private final Activity activity;
private final LayoutInflater inflater;
private final boolean installed;
public AddOnAdapter(Activity activity, boolean installed, List<AddOn> objects) {
super(activity, R.id.title, objects);
this.installed = installed;
this.activity = activity;
inflater = (LayoutInflater) activity.getSystemService(
Context.LAYOUT_INFLATER_SERVICE);
}
// --- view construction
View.OnClickListener intentClickListener = new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent intent = (Intent) v.getTag();
activity.startActivity(intent);
}
};
@Override
public View getView(int position, View convertView, ViewGroup parent) {
if(convertView == null) {
convertView = inflater.inflate(R.layout.addon_adapter_row, parent, false);
ViewHolder viewHolder = new ViewHolder();
viewHolder.icon = (ImageView) convertView.findViewById(R.id.icon);
viewHolder.title = (TextView) convertView.findViewById(R.id.title);
viewHolder.description = (TextView) convertView.findViewById(R.id.description);
viewHolder.web = (ImageButton) convertView.findViewById(R.id.button_web);
viewHolder.market = (ImageButton) convertView.findViewById(R.id.button_market);
viewHolder.installedIcon = (ImageView) convertView.findViewById(R.id.check);
convertView.setTag(viewHolder);
viewHolder.web.setOnClickListener(intentClickListener);
viewHolder.market.setOnClickListener(intentClickListener);
}
((ViewHolder)convertView.getTag()).item = getItem(position);
initializeView(convertView);
return convertView;
}
private class ViewHolder {
public AddOn item;
public ImageView icon;
public TextView title;
public TextView description;
public ImageButton web;
public ImageButton market;
public ImageView installedIcon;
}
private void initializeView(View convertView) {
ViewHolder viewHolder = (ViewHolder) convertView.getTag();
AddOn item = viewHolder.item;
viewHolder.icon.setImageBitmap(item.getIcon());
viewHolder.title.setText(item.getTitle());
viewHolder.description.setText(item.getDescription());
// populate buttons
if(item.getWebPage() != null) {
viewHolder.web.setVisibility(View.VISIBLE);
Intent webPageIntent = new Intent(Intent.ACTION_VIEW,
Uri.parse(item.getWebPage()));
Drawable icon = getIntentIcon(webPageIntent);
if(icon == null)
viewHolder.web.setImageResource(
android.R.drawable.presence_online);
else
viewHolder.web.setImageDrawable(icon);
viewHolder.web.setTag(webPageIntent);
} else {
viewHolder.web.setVisibility(View.GONE);
}
if(installed) {
viewHolder.market.setVisibility(View.GONE);
viewHolder.installedIcon.setVisibility(View.VISIBLE);
} else {
viewHolder.market.setVisibility(View.VISIBLE);
viewHolder.installedIcon.setVisibility(View.GONE);
Intent marketIntent = new Intent(Intent.ACTION_VIEW,
Uri.parse("market://search?q=pname:" + //$NON-NLS-1$
item.getPackageName()));
marketIntent.setClassName("com.android.vending", //$NON-NLS-1$
"com.android.vending.SearchAssetListActivity"); //$NON-NLS-1$
Drawable icon = getIntentIcon(marketIntent);
if(icon == null)
viewHolder.web.setImageResource(
android.R.drawable.stat_sys_download);
else
viewHolder.web.setImageDrawable(icon);
}
}
public Drawable getIntentIcon(Intent intent) {
PackageManager pm = activity.getPackageManager();
List<ResolveInfo> resolveInfoList = pm.queryIntentActivities(intent, 0);
// if options > 1, display open with...
if(resolveInfoList.size() > 0) {
return resolveInfoList.get(0).activityInfo.loadIcon(pm);
}
return null;
}
}

@ -0,0 +1,90 @@
package com.todoroo.astrid.model;
import android.graphics.Bitmap;
/**
* An add-on installable by Astrid
*
* @author Tim Su <tim@todoroo.com>
*
*/
public class AddOn {
private final boolean free;
private final boolean internal;
private final String title;
private final String author;
private final String description;
private final String packageName;
private final String webPage;
private final Bitmap icon;
public AddOn(boolean free, boolean internal, String title, String author, String description,
String packageName, String webPage, Bitmap icon) {
this.free = free;
this.internal = internal;
this.title = title;
this.author = author;
this.description = description;
this.packageName = packageName;
this.webPage = webPage;
this.icon = icon;
}
/**
* @return whether this add-on is available for free
*/
public boolean isFree() {
return free;
}
/**
* @return whether this add-on is signed with the same key as Astrid
*/
public boolean isInternal() {
return internal;
}
/**
* @return add-on title
*/
public String getTitle() {
return title;
}
/**
* @return add-on author
*/
public String getAuthor() {
return author;
}
/**
* @return add-on description
*/
public String getDescription() {
return description;
}
/**
* @return add-on java package name
*/
public String getPackageName() {
return packageName;
}
/**
* @return add-on web-page
*/
public String getWebPage() {
return webPage;
}
/**
* @return add-on icon
*/
public Bitmap getIcon() {
return icon;
}
}

@ -11,11 +11,14 @@ import android.content.DialogInterface;
import android.content.Intent;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.content.res.Resources;
import android.graphics.drawable.BitmapDrawable;
import android.net.Uri;
import com.timsu.astrid.R;
import com.todoroo.andlib.service.ContextManager;
import com.todoroo.andlib.utility.DateUtilities;
import com.todoroo.astrid.model.AddOn;
import com.todoroo.astrid.utility.Constants;
import com.todoroo.astrid.utility.Preferences;
@ -26,13 +29,16 @@ import com.todoroo.astrid.utility.Preferences;
*
*/
@SuppressWarnings("nls")
public class AddonService {
public class AddOnService {
/** OEM preference key */
private static final String PREF_OEM = "poem";
/** Astrid Power Pack package */
private static final String POWER_PACK_PACKAGE = "com.todoroo.astrid.ppack";
public static final String POWER_PACK_PACKAGE = "com.todoroo.astrid.ppack";
/** Astrid Locale package */
public static final String LOCALE_PACKAGE = "com.todoroo.astrid.locale";
/** Astrid Power Pack label */
public static final String POWER_PACK_LABEL = "Astrid Power Pack";
@ -135,4 +141,48 @@ public class AddonService {
Preferences.setBoolean(PREF_OEM, true);
}
/**
* Check whether a given add-on is installed
* @param addOn
* @return
*/
public boolean isInstalled(AddOn addOn) {
Context context = ContextManager.getContext();
ApplicationInfo applicationInfo;
try {
applicationInfo = context.getPackageManager().getApplicationInfo(
addOn.getPackageName(), 0);
} catch (Exception e) {
return false;
}
if(applicationInfo == null)
return false;
if(!addOn.isInternal())
return true;
return applicationInfo.uid == context.getApplicationInfo().uid;
}
/**
* Get a list of add-ons
*
* @return available add-ons
*/
public AddOn[] getAddOns() {
Resources r = ContextManager.getContext().getResources();
// temporary temporary
AddOn[] list = new AddOn[2];
list[0] = new AddOn(false, true, "Astrid Power Pack", null,
"Support Astrid and get more productive with the Astrid Power Pack backup, widgets, no ads, and calendar integration. Power up today!",
POWER_PACK_PACKAGE, "http://www.weloveastrid.com/store",
((BitmapDrawable)r.getDrawable(R.drawable.icon_pp)).getBitmap());
list[1] = new AddOn(false, true, "Astrid Locale Plugin", null,
"Allows Astrid to make use of the Locale application to send you notifications based on filter conditions",
LOCALE_PACKAGE, "http://www.weloveastrid.com/store",
((BitmapDrawable)r.getDrawable(R.drawable.icon_pp)).getBitmap());
return list;
}
}

@ -102,6 +102,7 @@ public class AstridDependencyInjector implements AbstractDependencyInjector {
injectables.put("taskService", TaskService.class);
injectables.put("metadataService", MetadataService.class);
injectables.put("upgradeService", UpgradeService.class);
injectables.put("addonService", AddOnService.class);
// com.timsu.astrid.data
injectables.put("tasksTable", "tasks");

@ -23,7 +23,7 @@ public final class UpgradeService {
return;
if(from == 135)
AddonService.recordOem();
AddOnService.recordOem();
if(from < 136)
new Astrid2To3UpgradeHelper().upgrade2To3();

Loading…
Cancel
Save