* #26029 First implementation of expanding/retracting
diff --git a/src/com/savoirfairelinux/sflphone/adapters/ContactPictureLoader.java b/src/com/savoirfairelinux/sflphone/adapters/ContactPictureLoader.java
index 9254e8c..70cae8e 100644
--- a/src/com/savoirfairelinux/sflphone/adapters/ContactPictureLoader.java
+++ b/src/com/savoirfairelinux/sflphone/adapters/ContactPictureLoader.java
@@ -73,8 +73,12 @@
@Override
public void run() {
- Bitmap photo_bmp = loadContactPhoto(cr, cid);
-
+ Bitmap photo_bmp;
+ try{
+ photo_bmp = loadContactPhoto(cr, cid);
+ }catch(IllegalArgumentException e){
+ photo_bmp = null;
+ }
if (photo_bmp == null) {
photo_bmp = BitmapFactory.decodeResource(view.getResources(), R.drawable.ic_contact_picture);
}
diff --git a/src/com/savoirfairelinux/sflphone/adapters/HistoryAdapter.java b/src/com/savoirfairelinux/sflphone/adapters/HistoryAdapter.java
index 27aee1f..628d6cb 100644
--- a/src/com/savoirfairelinux/sflphone/adapters/HistoryAdapter.java
+++ b/src/com/savoirfairelinux/sflphone/adapters/HistoryAdapter.java
@@ -6,48 +6,66 @@
import java.util.HashMap;
import java.util.Locale;
import java.util.TimeZone;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
import android.app.Activity;
import android.content.Context;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
+import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
+import android.widget.ImageButton;
import android.widget.ImageView;
import android.widget.TextView;
import com.savoirfairelinux.sflphone.R;
+import com.savoirfairelinux.sflphone.fragments.HistoryFragment;
+import com.savoirfairelinux.sflphone.model.HistoryEntry;
import com.savoirfairelinux.sflphone.service.ServiceConstants;
public class HistoryAdapter extends BaseAdapter {
- Context mContext;
- ArrayList<HashMap<String, String>> dataset;
+ HistoryFragment mContext;
+ ArrayList<HistoryEntry> dataset;
private static final String TAG = HistoryAdapter.class.getSimpleName();
+ private ExecutorService infos_fetcher = Executors.newCachedThreadPool();
- public HistoryAdapter(Activity activity, ArrayList<HashMap<String, String>> entries) {
+
+
+ public HistoryAdapter(HistoryFragment activity, ArrayList<HistoryEntry> history) {
mContext = activity;
- dataset = entries;
+ dataset = history;
}
@Override
- public View getView(int pos, View convertView, ViewGroup arg2) {
+ public View getView(final int pos, View convertView, ViewGroup arg2) {
View rowView = convertView;
HistoryView entryView = null;
if (rowView == null) {
// Get a new instance of the row layout view
- LayoutInflater inflater = LayoutInflater.from(mContext);
+ LayoutInflater inflater = LayoutInflater.from(mContext.getActivity());
rowView = inflater.inflate(R.layout.item_history, null);
// Hold the view objects in an object
// so they don't need to be re-fetched
entryView = new HistoryView();
+ entryView.photo = (ImageView) rowView.findViewById(R.id.photo);
entryView.displayName = (TextView) rowView.findViewById(R.id.display_name);
entryView.duration = (TextView) rowView.findViewById(R.id.duration);
entryView.date = (TextView) rowView.findViewById(R.id.date_start);
-
+ entryView.call_button = (ImageButton) rowView.findViewById(R.id.action_call);
+ entryView.call_button.setOnClickListener(new OnClickListener() {
+
+ @Override
+ public void onClick(View v) {
+ mContext.makeNewCall(pos);
+
+ }
+ } );
rowView.setTag(entryView);
} else {
entryView = (HistoryView) rowView.getTag();
@@ -57,40 +75,31 @@
// to the view objects
// SipCall call = (SipCall) mCallList.values().toArray()[position];
- entryView.displayName.setText(dataset.get(pos).get(ServiceConstants.HISTORY_ACCOUNT_ID_KEY));
+ entryView.displayName.setText(dataset.get(pos).getContact().getmDisplayName());
+
+ infos_fetcher.execute(new ContactPictureLoader(mContext.getActivity(), entryView.photo, dataset.get(pos).getContact().getId()));
- long timestampEnd = Long.parseLong(dataset.get(pos).get(ServiceConstants.HISTORY_TIMESTAMP_STOP_KEY));
- long timestampStart = Long.parseLong(dataset.get(pos).get(ServiceConstants.HISTORY_TIMESTAMP_START_KEY));
- entryView.date.setText(getDate(timestampStart,"yyyy-MM-dd"));
-
- long duration = timestampEnd - timestampStart;
- entryView.duration.setText("Duration: "+duration);
+
+ entryView.date.setText(dataset.get(pos).getCalls().lastEntry().getValue().getDate("yyyy-MM-dd"));
+ entryView.duration.setText(dataset.get(pos).getTotalDuration());
+
return rowView;
}
- private String getDate(long timeStamp, String format) {
- Calendar cal = Calendar.getInstance();
- TimeZone tz = cal.getTimeZone();
- SimpleDateFormat objFormatter = new SimpleDateFormat(format, Locale.CANADA);
- objFormatter.setTimeZone(tz);
-
- Calendar objCalendar = Calendar.getInstance(tz);
- objCalendar.setTimeInMillis(timeStamp*1000);
- String result = objFormatter.format(objCalendar.getTime());
- objCalendar.clear();
- return result;
- }
+
/*********************
* ViewHolder Pattern
*********************/
public class HistoryView {
+ public ImageView photo;
protected TextView displayName;
protected TextView date;
public TextView duration;
+ private ImageButton call_button;
}
@Override
@@ -100,7 +109,7 @@
}
@Override
- public HashMap<String, String> getItem(int pos) {
+ public HistoryEntry getItem(int pos) {
return dataset.get(pos);
}
@@ -115,7 +124,7 @@
}
public void addAll(ArrayList<HashMap<String, String>> history) {
- dataset.addAll(history);
+// dataset.addAll(history);
}
diff --git a/src/com/savoirfairelinux/sflphone/client/SFLPhoneHomeActivity.java b/src/com/savoirfairelinux/sflphone/client/SFLPhoneHomeActivity.java
index eb43a96..9b6ec03 100644
--- a/src/com/savoirfairelinux/sflphone/client/SFLPhoneHomeActivity.java
+++ b/src/com/savoirfairelinux/sflphone/client/SFLPhoneHomeActivity.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2004-2012 Savoir-Faire Linux Inc.
+ * Copyright (C) 2004-2013 Savoir-Faire Linux Inc.
*
* Author: Adrien Beraud <adrien.beraud@gmail.com>
* Alexandre Lision <alexandre.lision@savoirfairelinux.com>
@@ -71,6 +71,7 @@
import com.savoirfairelinux.sflphone.fragments.MenuFragment;
import com.savoirfairelinux.sflphone.interfaces.AccountsInterface;
import com.savoirfairelinux.sflphone.interfaces.CallInterface;
+import com.savoirfairelinux.sflphone.loaders.LoaderConstants;
import com.savoirfairelinux.sflphone.model.CallContact;
import com.savoirfairelinux.sflphone.model.SipCall;
import com.savoirfairelinux.sflphone.receivers.AccountsReceiver;
@@ -162,36 +163,12 @@
bindService(intent, mConnection, Context.BIND_AUTO_CREATE);
}
- /* getFragment(Bundle, String) */
- // if (savedInstanceState != null) {
- // Log.w(TAG, "Activity restarted, recreating PagerAdapter...");
- // /* getFragment (Bundle bundle, String key) */
- // mDialingFragment = (DialingFragment) getFragmentManager().getFragment(savedInstanceState,
- // mSectionsPagerAdapter.getClassName(ACTION_BAR_TAB_DIALING));
- // mCallElementList = (CallElementListFragment) getFragmentManager().getFragment(savedInstanceState,
- // mSectionsPagerAdapter.getClassName(ACTION_BAR_TAB_CALL));
- // mHistorySectionFragment = (HistoryFragment) getFragmentManager().getFragment(savedInstanceState,
- // mSectionsPagerAdapter.getClassName(ACTION_BAR_TAB_HISTORY));
- // }
-
- // if (mDialingFragment == null) {
- // mDialingFragment = new DialingFragment();
- // Log.w(TAG, "Recreated mDialingFragment=" + mDialingFragment);
- // }
- //
if (mContactsFragment == null) {
mContactsFragment = new ContactListFragment();
Log.w(TAG, "Recreated mContactListFragment=" + mContactsFragment);
getFragmentManager().beginTransaction().replace(R.id.contacts_frame, mContactsFragment).commit();
}
- // if (mCallElementList == null) {
- // mCallElementList = new CallElementListFragment();
- // Log.w(TAG, "Recreated mCallElementList=" + mCallElementList);
- // }
- // if (mHistorySectionFragment == null) {
- // mHistorySectionFragment = new HistoryFragment();
- // Log.w(TAG, "Recreated mHistorySectionFragment=" + mHistorySectionFragment);
- // }
+
mDrawer = (CustomSlidingDrawer) findViewById(R.id.custom_sliding_drawer);
@@ -242,34 +219,6 @@
}
});
- // getActionBar().setCustomView(R.layout.actionbar);
- // spinnerAccounts = (Spinner) getActionBar().getCustomView().findViewById(R.id.account_selection);
- // spinnerAccounts.setOnItemSelectedListener(new OnItemSelectedListener() {
- //
- // @Override
- // public void onItemSelected(AdapterView<?> arg0, View view, int pos, long arg3) {
- // // public void onClick(DialogInterface dialog, int which) {
- //
- // Log.i(TAG, "Selected Account: " + mAdapter.getItem(pos));
- // if (null != view) {
- // ((RadioButton) view.findViewById(R.id.account_checked)).toggle();
- // }
- // mAdapter.setSelectedAccount(pos);
- // // accountSelectedNotifyAccountList(mAdapter.getItem(pos));
- // // setSelection(cursor.getPosition(),true);
- //
- // }
- //
- // @Override
- // public void onNothingSelected(AdapterView<?> arg0) {
- // // TODO Auto-generated method stub
- //
- // }
- // });
- // ((TextView) getActionBar().getCustomView().findViewById(R.id.activity_title)).setText(getTitle());
- // getActionBar().setDisplayShowCustomEnabled(true);
-
-
fMenu = new MenuFragment();
getFragmentManager().beginTransaction().replace(R.id.left_drawer, fMenu).commit();
@@ -350,11 +299,20 @@
@Override
public void onBackPressed() {
+
+ if(getActionBar().getCustomView() != null){
+ getActionBar().setDisplayShowCustomEnabled(false);
+ getActionBar().setCustomView(null);
+ // Display all the contacts again
+ getLoaderManager().restartLoader(LoaderConstants.CONTACT_LOADER, null, mContactsFragment);
+ return;
+ }
+
if (mDrawer.isOpened()) {
mDrawer.animateClose();
return;
}
-
+
if (isClosing) {
super.onBackPressed();
t.cancel();
@@ -473,6 +431,7 @@
break;
case REQUEST_CODE_CALL:
Log.w(TAG, "Result out of CallActivity");
+ getLoaderManager().restartLoader(LoaderConstants.HISTORY_LOADER, null, (HistoryFragment)mSectionsPagerAdapter.getItem(2));
break;
}
diff --git a/src/com/savoirfairelinux/sflphone/fragments/AudioManagementFragment.java b/src/com/savoirfairelinux/sflphone/fragments/AudioManagementFragment.java
index 954eb49..022cf2e 100644
--- a/src/com/savoirfairelinux/sflphone/fragments/AudioManagementFragment.java
+++ b/src/com/savoirfairelinux/sflphone/fragments/AudioManagementFragment.java
@@ -1,7 +1,8 @@
/*
- * Copyright (C) 2004-2012 Savoir-Faire Linux Inc.
+ * Copyright (C) 2004-2013 Savoir-Faire Linux Inc.
*
* Author: Alexandre Savard <alexandre.savard@savoirfairelinux.com>
+ * Alexandre Lision <alexandre.lision@savoirfairelinux.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
diff --git a/src/com/savoirfairelinux/sflphone/fragments/CallFragment.java b/src/com/savoirfairelinux/sflphone/fragments/CallFragment.java
index e8df782..124e806 100644
--- a/src/com/savoirfairelinux/sflphone/fragments/CallFragment.java
+++ b/src/com/savoirfairelinux/sflphone/fragments/CallFragment.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2004-2012 Savoir-Faire Linux Inc.
+ * Copyright (C) 2004-2013 Savoir-Faire Linux Inc.
*
* Author: Alexandre Lision <alexandre.lision@savoirfairelinux.com>
*
@@ -75,7 +75,7 @@
private HashMap<CallContact, Bubble> contacts = new HashMap<CallContact, Bubble>();
- private CallContact myself = CallContact.ContactBuilder.buildUserContact("Me");
+ private CallContact myself;
private Bitmap hangup_icon;
private Bitmap call_icon;
@@ -177,6 +177,8 @@
//rootView.requestDisallowInterceptTouchEvent(true);
mCallbacks = (Callbacks) activity;
+ myself = CallContact.ContactBuilder.buildUserContact(activity.getContentResolver(), "");
+
}
@Override
@@ -208,8 +210,8 @@
callStatusTxt.setText("0 min");
- getBubbleFor(mCall.getContacts().get(0), model.width/2, model.height/2);
- getBubbleFor(myself, model.width/2, model.height/3);
+ getBubbleFor(mCall.getContacts().get(0), model.width/2, model.height/3);
+ getBubbleFor(myself, model.width/2, model.height/2);
model.clearAttractors();
model.addAttractor(new Attractor(new PointF(model.width / 2, model.height * .8f), ATTRACTOR_SIZE, new Attractor.Callback() {
@@ -256,7 +258,8 @@
callStatusTxt.setText("Calling...");
// TODO off-thread image loading
- getBubbleFor(mCall.getContacts().get(0), model.width/2, model.height/2);
+ getBubbleFor(mCall.getContacts().get(0), model.width/2, model.height/3);
+ getBubbleFor(myself, model.width/2, model.height/2);
model.clearAttractors();
model.addAttractor(new Attractor(new PointF(model.width / 2, model.height * .8f), 40, new Attractor.Callback() {
@@ -288,7 +291,7 @@
// TODO off-thread image loading
if (contact.getPhoto_id() > 0) {
- Bitmap photo = ContactPictureLoader.loadContactPhoto(getActivity().getContentResolver(), mCall.getContacts().get(0).getId());
+ Bitmap photo = ContactPictureLoader.loadContactPhoto(getActivity().getContentResolver(), contact.getId());
contact_bubble = new Bubble(x, y, BUBBLE_SIZE, photo);
} else {
contact_bubble = new Bubble(x, y, BUBBLE_SIZE, getActivity(), R.drawable.ic_contact_picture);
diff --git a/src/com/savoirfairelinux/sflphone/fragments/CallListFragment.java b/src/com/savoirfairelinux/sflphone/fragments/CallListFragment.java
index b1d175c..ac9d10e 100644
--- a/src/com/savoirfairelinux/sflphone/fragments/CallListFragment.java
+++ b/src/com/savoirfairelinux/sflphone/fragments/CallListFragment.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2004-2012 Savoir-Faire Linux Inc.
+ * Copyright (C) 2004-2013 Savoir-Faire Linux Inc.
*
* Author: Alexandre Lision <alexandre.lision@savoirfairelinux.com>
*
diff --git a/src/com/savoirfairelinux/sflphone/fragments/ContactListFragment.java b/src/com/savoirfairelinux/sflphone/fragments/ContactListFragment.java
index d50fbdd..1f40bd9 100644
--- a/src/com/savoirfairelinux/sflphone/fragments/ContactListFragment.java
+++ b/src/com/savoirfairelinux/sflphone/fragments/ContactListFragment.java
@@ -52,7 +52,6 @@
import android.view.View.OnClickListener;
import android.view.View.OnDragListener;
import android.view.ViewGroup;
-import android.view.ViewGroup.LayoutParams;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.AdapterView.OnItemLongClickListener;
@@ -61,13 +60,13 @@
import android.widget.ListView;
import android.widget.RelativeLayout;
import android.widget.SearchView;
-import android.widget.SearchView.OnCloseListener;
import android.widget.SearchView.OnQueryTextListener;
import com.savoirfairelinux.sflphone.R;
import com.savoirfairelinux.sflphone.adapters.ContactsAdapter;
import com.savoirfairelinux.sflphone.adapters.StarredContactsAdapter;
import com.savoirfairelinux.sflphone.loaders.ContactsLoader;
+import com.savoirfairelinux.sflphone.loaders.LoaderConstants;
import com.savoirfairelinux.sflphone.model.CallContact;
import com.savoirfairelinux.sflphone.service.ISipService;
import com.savoirfairelinux.sflphone.views.TACGridView;
@@ -79,10 +78,6 @@
String mCurFilter;
- private RelativeLayout mHandle;
-
- public static final int CONTACT_LOADER = 555;
-
@Override
public void onCreate(Bundle savedInBundle) {
super.onCreate(savedInBundle);
@@ -148,7 +143,7 @@
// In order to onCreateOptionsMenu be called
setHasOptionsMenu(true);
- getLoaderManager().initLoader(CONTACT_LOADER, null, this);
+ getLoaderManager().initLoader(LoaderConstants.CONTACT_LOADER, null, this);
}
@@ -259,7 +254,9 @@
return true;
}
mCurFilter = newFilter;
- getLoaderManager().restartLoader(CONTACT_LOADER, null, this);
+ Bundle b = new Bundle();
+ b.putString("filter", mCurFilter);
+ getLoaderManager().restartLoader(LoaderConstants.CONTACT_LOADER, b, this);
return true;
}
@@ -273,8 +270,8 @@
public Loader<Bundle> onCreateLoader(int id, Bundle args) {
Uri baseUri;
- if (mCurFilter != null) {
- baseUri = Uri.withAppendedPath(Contacts.CONTENT_FILTER_URI, Uri.encode(mCurFilter));
+ if (args != null) {
+ baseUri = Uri.withAppendedPath(Contacts.CONTENT_FILTER_URI, Uri.encode(args.getString("filter")));
} else {
baseUri = Contacts.CONTENT_URI;
}
@@ -304,7 +301,7 @@
}
public void setHandleView(RelativeLayout handle) {
- mHandle = handle;
+// mHandle = handle;
diff --git a/src/com/savoirfairelinux/sflphone/fragments/DialingFragment.java b/src/com/savoirfairelinux/sflphone/fragments/DialingFragment.java
index 8711384..e3dcebe 100644
--- a/src/com/savoirfairelinux/sflphone/fragments/DialingFragment.java
+++ b/src/com/savoirfairelinux/sflphone/fragments/DialingFragment.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2004-2012 Savoir-Faire Linux Inc.
+ * Copyright (C) 2004-2013 Savoir-Faire Linux Inc.
*
* Author: Alexandre Lision <alexandre.lision@savoirfairelinux.com>
*
@@ -58,6 +58,7 @@
import com.savoirfairelinux.sflphone.R;
import com.savoirfairelinux.sflphone.adapters.AccountSelectionAdapter;
import com.savoirfairelinux.sflphone.loaders.AccountsLoader;
+import com.savoirfairelinux.sflphone.loaders.LoaderConstants;
import com.savoirfairelinux.sflphone.model.Account;
import com.savoirfairelinux.sflphone.service.ISipService;
import com.savoirfairelinux.sflphone.views.ClearableEditText;
@@ -76,7 +77,7 @@
private Callbacks mCallbacks = sDummyCallbacks;
private Spinner spinnerAccounts;
- private static final int ACCOUNTS_LOADER = 555;
+
/**
* A dummy implementation of the {@link Callbacks} interface that does nothing. Used only when this fragment is not attached to an activity.
@@ -228,7 +229,7 @@
mAdapter = new AccountSelectionAdapter(getActivity(), service, new ArrayList<Account>());
spinnerAccounts.setAdapter(mAdapter);
- getActivity().getLoaderManager().initLoader(ACCOUNTS_LOADER, null, this);
+ getActivity().getLoaderManager().initLoader(LoaderConstants.ACCOUNTS_LOADER, null, this);
}
}
@@ -255,7 +256,7 @@
public void updateAllAccounts() {
if (getActivity() != null)
- getActivity().getLoaderManager().restartLoader(ACCOUNTS_LOADER, null, this);
+ getActivity().getLoaderManager().restartLoader(LoaderConstants.ACCOUNTS_LOADER, null, this);
}
diff --git a/src/com/savoirfairelinux/sflphone/fragments/HistoryFragment.java b/src/com/savoirfairelinux/sflphone/fragments/HistoryFragment.java
index e0fd151..ed2c410 100644
--- a/src/com/savoirfairelinux/sflphone/fragments/HistoryFragment.java
+++ b/src/com/savoirfairelinux/sflphone/fragments/HistoryFragment.java
@@ -1,3 +1,33 @@
+/*
+ * Copyright (C) 2004-2013 Savoir-Faire Linux Inc.
+ *
+ * Author: Alexandre Lision <alexandre.lision@savoirfairelinux.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * Additional permission under GNU GPL version 3 section 7:
+ *
+ * If you modify this program, or any covered work, by linking or
+ * combining it with the OpenSSL project's OpenSSL library (or a
+ * modified version of that library), containing parts covered by the
+ * terms of the OpenSSL or SSLeay licenses, Savoir-Faire Linux Inc.
+ * grants you additional permission to convey the resulting work.
+ * Corresponding Source for a non-source form of such a combination
+ * shall include the source code for the parts of OpenSSL used as well
+ * as that of the covered work.
+ */
package com.savoirfairelinux.sflphone.fragments;
import java.util.ArrayList;
@@ -5,24 +35,32 @@
import android.app.Activity;
import android.app.ListFragment;
+import android.app.LoaderManager.LoaderCallbacks;
+import android.content.Loader;
import android.os.Bundle;
import android.os.RemoteException;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
+import android.widget.AdapterView;
+import android.widget.ListView;
+import android.widget.AdapterView.OnItemClickListener;
import com.savoirfairelinux.sflphone.R;
import com.savoirfairelinux.sflphone.adapters.HistoryAdapter;
+import com.savoirfairelinux.sflphone.loaders.HistoryLoader;
+import com.savoirfairelinux.sflphone.loaders.LoaderConstants;
+import com.savoirfairelinux.sflphone.model.CallContact;
+import com.savoirfairelinux.sflphone.model.HistoryEntry;
import com.savoirfairelinux.sflphone.model.SipCall;
import com.savoirfairelinux.sflphone.service.ISipService;
-public class HistoryFragment extends ListFragment {
+public class HistoryFragment extends ListFragment implements LoaderCallbacks<ArrayList<HistoryEntry>> {
private static final String TAG = HistoryFragment.class.getSimpleName();
public static final String ARG_SECTION_NUMBER = "section_number";
- private boolean isReady;
- private ISipService service;
+
HistoryAdapter mAdapter;
private Callbacks mCallbacks = sDummyCallbacks;
/**
@@ -30,7 +68,7 @@
*/
private static Callbacks sDummyCallbacks = new Callbacks() {
@Override
- public void onCallSelected(SipCall c) {
+ public void onCallDialed(String account, String to) {
}
@Override
@@ -42,7 +80,7 @@
};
public interface Callbacks {
- public void onCallSelected(SipCall c);
+ public void onCallDialed(String account, String to);
public ISipService getService();
@@ -51,7 +89,7 @@
@Override
public void onAttach(Activity activity) {
super.onAttach(activity);
- isReady = false;
+
if (!(activity instanceof Callbacks)) {
throw new IllegalStateException("Activity must implement fragment's callbacks.");
}
@@ -74,10 +112,14 @@
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup parent, Bundle savedInstanceState) {
View inflatedView = inflater.inflate(R.layout.frag_history, parent, false);
- isReady = true;
- if (isReady) {
- Log.i(TAG, "C PRET");
- }
+
+ ((ListView)inflatedView.findViewById(android.R.id.list)).setOnItemClickListener(new OnItemClickListener() {
+
+ @Override
+ public void onItemClick(AdapterView<?> arg0, View arg1, int pos, long arg3) {
+ mAdapter.getItem(pos);
+ }
+ });
return inflatedView;
}
@@ -85,36 +127,31 @@
public void onStart() {
super.onStart();
Log.w(TAG, "onStart");
- if (mCallbacks.getService() != null) {
-
- Log.i(TAG, "oncreateview");
- onServiceSipBinded(mCallbacks.getService());
- }
+ getLoaderManager().initLoader(LoaderConstants.HISTORY_LOADER, null, this);
}
- /**
- * Called by activity to pass a reference to sipservice to Fragment.
- *
- * @param isip
- */
- public void onServiceSipBinded(ISipService isip) {
- Log.w(TAG, "onServiceSipBinded");
- if (isReady) {
- service = isip;
- ArrayList<HashMap<String, String>> history;
- try {
- history = (ArrayList<HashMap<String, String>>) mCallbacks.getService().getHistory();
- Log.i(TAG, "history size:" + history.size());
- mAdapter = new HistoryAdapter(getActivity(), history);
- getListView().setAdapter(mAdapter);
- mAdapter.notifyDataSetChanged();
+ public void makeNewCall(int position){
+ mCallbacks.onCallDialed(String.valueOf(mAdapter.getItem(position).getAccountID()), mAdapter.getItem(position).getNumber());
+ }
- } catch (RemoteException e) {
- Log.i(TAG, e.toString());
- }
- } else {
- Log.w(TAG, "nor Ready");
- }
+ @Override
+ public Loader<ArrayList<HistoryEntry>> onCreateLoader(int id, Bundle args) {
+ HistoryLoader loader = new HistoryLoader(getActivity(), mCallbacks.getService());
+ loader.forceLoad();
+ return loader;
+ }
+
+ @Override
+ public void onLoadFinished(Loader<ArrayList<HistoryEntry>> arg0, ArrayList<HistoryEntry> history) {
+ mAdapter = new HistoryAdapter(this, history);
+ getListView().setAdapter(mAdapter);
+ mAdapter.notifyDataSetChanged();
+
+ }
+
+ @Override
+ public void onLoaderReset(Loader<ArrayList<HistoryEntry>> arg0) {
+ // TODO Auto-generated method stub
}
}
diff --git a/src/com/savoirfairelinux/sflphone/fragments/HomeFragment.java b/src/com/savoirfairelinux/sflphone/fragments/HomeFragment.java
index a3dcdd7..d47fc82 100644
--- a/src/com/savoirfairelinux/sflphone/fragments/HomeFragment.java
+++ b/src/com/savoirfairelinux/sflphone/fragments/HomeFragment.java
@@ -1,7 +1,7 @@
/*
- * Copyright (C) 2004-2012 Savoir-Faire Linux Inc.
+ * Copyright (C) 2004-2013 Savoir-Faire Linux Inc.
*
- * Author: Adrien Beraud <adrien.beraud@gmail.com>
+ * Author: Alexandre Lision <alexandre.lision@savoirfairelinux.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -211,23 +211,7 @@
@Override
public void onClick(DialogInterface dialog, int item) {
Log.i(TAG, "Selected " + items[item]);
- // switch (item) {
- // case 0:
- // call.notifyServiceHangup(service);
- // break;
- // case 1:
- // call.sendTextMessage();
- // // Need to hangup this call immediately since no way to do it after this action
- // call.notifyServiceHangup(service);
- // break;
- // case 2:
- // call.addToConference();
- // // Need to hangup this call immediately since no way to do it after this action
- // call.notifyServiceHangup(service);
- // break;
- // default:
- // break;
- // }
+
}
});
AlertDialog alert = builder.create();
@@ -237,15 +221,6 @@
}
});
- lv.setOnItemClickListener(new OnItemClickListener() {
-
- @Override
- public void onItemClick(AdapterView<?> arg0, View v, int pos, long arg3) {
- mCallbacks.onCallSelected(mAdapter.getItem(pos));
-
- }
-
- });
}
@Override
diff --git a/src/com/savoirfairelinux/sflphone/fragments/MenuFragment.java b/src/com/savoirfairelinux/sflphone/fragments/MenuFragment.java
index 3cac94e..8a64d0b 100644
--- a/src/com/savoirfairelinux/sflphone/fragments/MenuFragment.java
+++ b/src/com/savoirfairelinux/sflphone/fragments/MenuFragment.java
@@ -1,3 +1,33 @@
+/*
+ * Copyright (C) 2004-2013 Savoir-Faire Linux Inc.
+ *
+ * Author: Alexandre Lision <alexandre.lision@savoirfairelinux.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * Additional permission under GNU GPL version 3 section 7:
+ *
+ * If you modify this program, or any covered work, by linking or
+ * combining it with the OpenSSL project's OpenSSL library (or a
+ * modified version of that library), containing parts covered by the
+ * terms of the OpenSSL or SSLeay licenses, Savoir-Faire Linux Inc.
+ * grants you additional permission to convey the resulting work.
+ * Corresponding Source for a non-source form of such a combination
+ * shall include the source code for the parts of OpenSSL used as well
+ * as that of the covered work.
+ */
package com.savoirfairelinux.sflphone.fragments;
import java.util.concurrent.ExecutorService;
@@ -62,8 +92,6 @@
}
- private ExecutorService infos_fetcher = Executors.newCachedThreadPool();
-
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup parent, Bundle savedInstanceState) {
View inflatedView = inflater.inflate(R.layout.frag_menu, parent, false);
diff --git a/src/com/savoirfairelinux/sflphone/loaders/ContactsLoader.java b/src/com/savoirfairelinux/sflphone/loaders/ContactsLoader.java
index dd793c2..de15e6b 100644
--- a/src/com/savoirfairelinux/sflphone/loaders/ContactsLoader.java
+++ b/src/com/savoirfairelinux/sflphone/loaders/ContactsLoader.java
@@ -10,13 +10,12 @@
import android.provider.ContactsContract.CommonDataKinds.Phone;
import android.provider.ContactsContract.CommonDataKinds.SipAddress;
import android.provider.ContactsContract.Contacts;
-import android.util.Log;
import com.savoirfairelinux.sflphone.model.CallContact;
public class ContactsLoader extends AsyncTaskLoader<Bundle> {
- private static final String TAG = ContactsLoader.class.getSimpleName();
+// private static final String TAG = ContactsLoader.class.getSimpleName();
// These are the Contacts rows that we will retrieve.
static final String[] CONTACTS_SUMMARY_PROJECTION = new String[] { Contacts._ID, Contacts.DISPLAY_NAME, Contacts.PHOTO_ID, Contacts.LOOKUP_KEY, Contacts.STARRED };
diff --git a/src/com/savoirfairelinux/sflphone/loaders/HistoryLoader.java b/src/com/savoirfairelinux/sflphone/loaders/HistoryLoader.java
new file mode 100644
index 0000000..91a83bf
--- /dev/null
+++ b/src/com/savoirfairelinux/sflphone/loaders/HistoryLoader.java
@@ -0,0 +1,99 @@
+package com.savoirfairelinux.sflphone.loaders;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import android.content.AsyncTaskLoader;
+import android.content.Context;
+import android.database.Cursor;
+import android.os.RemoteException;
+import android.provider.ContactsContract;
+import android.provider.ContactsContract.Contacts;
+import android.util.Log;
+
+import com.savoirfairelinux.sflphone.model.CallContact;
+import com.savoirfairelinux.sflphone.model.CallContact.ContactBuilder;
+import com.savoirfairelinux.sflphone.model.HistoryEntry;
+import com.savoirfairelinux.sflphone.model.HistoryEntry.HistoryCall;
+import com.savoirfairelinux.sflphone.service.ISipService;
+import com.savoirfairelinux.sflphone.service.ServiceConstants;
+
+public class HistoryLoader extends AsyncTaskLoader<ArrayList<HistoryEntry>> {
+
+ private static final String TAG = HistoryLoader.class.getSimpleName();
+ private ISipService service;
+ HashMap<String, HistoryEntry> historyEntries;
+
+ static final String[] CONTACTS_SUMMARY_PROJECTION = new String[] { Contacts._ID, Contacts.DISPLAY_NAME, Contacts.PHOTO_ID, Contacts.LOOKUP_KEY,
+ Contacts.STARRED };
+
+ public HistoryLoader(Context context, ISipService isip) {
+ super(context);
+ service = isip;
+ }
+
+ @Override
+ public ArrayList<HistoryEntry> loadInBackground() {
+
+ historyEntries = new HashMap<String, HistoryEntry>();
+
+ try {
+ ArrayList<HashMap<String, String>> history = (ArrayList<HashMap<String, String>>) service.getHistory();
+ Log.i(TAG, "history size:" + history.size());
+ CallContact.ContactBuilder builder = new CallContact.ContactBuilder();
+ for (HashMap<String, String> entry : history) {
+ entry.get(ServiceConstants.HISTORY_ACCOUNT_ID_KEY);
+ long timestampEnd = Long.parseLong(entry.get(ServiceConstants.HISTORY_TIMESTAMP_STOP_KEY));
+ long timestampStart = Long.parseLong(entry.get(ServiceConstants.HISTORY_TIMESTAMP_START_KEY));
+
+ System.out.println("HISTORY_TIMESTAMP_START_KEY" + entry.get(ServiceConstants.HISTORY_TIMESTAMP_START_KEY));
+ System.out.println("HISTORY_INCOMING_STRING" + entry.get(ServiceConstants.HISTORY_INCOMING_STRING));
+ System.out.println("HISTORY_OUTGOING_STRING" + entry.get(ServiceConstants.HISTORY_OUTGOING_STRING));
+ System.out.println("HISTORY_MISSED_STRING" + entry.get(ServiceConstants.HISTORY_MISSED_STRING));
+
+ System.out.println("HISTORY_STATE_KEY" + entry.get(ServiceConstants.HISTORY_STATE_KEY));
+
+ String number_called = entry.get(ServiceConstants.HISTORY_PEER_NUMBER_KEY);
+ CallContact c = null;
+ if (historyEntries.containsKey(number_called)) {
+ historyEntries.get(number_called).addHistoryCall(new HistoryCall(timestampStart, timestampEnd, number_called));
+ } else {
+
+ Pattern p = Pattern.compile("<sip:([^@]+)@([^>]+)>");
+ Matcher m = p.matcher(number_called);
+ if (m.find()) {
+ String s1 = m.group(1);
+ System.out.println(s1);
+ String s2 = m.group(2);
+ System.out.println(s2);
+
+ Cursor result = getContext().getContentResolver().query(ContactsContract.CommonDataKinds.Phone.CONTENT_URI, null,
+ ContactsContract.CommonDataKinds.Phone.NUMBER + " = " + m.group(1), null, null);
+
+ if (result.getCount() > 0) {
+ result.moveToFirst();
+ builder.startNewContact(result.getLong(result.getColumnIndex(ContactsContract.CommonDataKinds.Phone.CONTACT_ID)),
+ result.getString(result.getColumnIndex(ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME)),
+ result.getLong(result.getColumnIndex(ContactsContract.CommonDataKinds.Phone.PHOTO_ID)));
+ builder.addPhoneNumber(number_called, 0);
+ c = builder.build();
+ }
+ result.close();
+ } else {
+ c = ContactBuilder.buildUnknownContact(number_called);
+ }
+ HistoryEntry e = new HistoryEntry(entry.get(ServiceConstants.HISTORY_ACCOUNT_ID_KEY), c, timestampStart, timestampEnd,
+ number_called);
+ historyEntries.put(number_called, e);
+ }
+
+ }
+
+ } catch (RemoteException e) {
+ Log.i(TAG, e.toString());
+ }
+ return new ArrayList<HistoryEntry>(historyEntries.values());
+ }
+}
diff --git a/src/com/savoirfairelinux/sflphone/loaders/LoaderConstants.java b/src/com/savoirfairelinux/sflphone/loaders/LoaderConstants.java
new file mode 100644
index 0000000..3fd27ee
--- /dev/null
+++ b/src/com/savoirfairelinux/sflphone/loaders/LoaderConstants.java
@@ -0,0 +1,9 @@
+package com.savoirfairelinux.sflphone.loaders;
+
+public class LoaderConstants {
+
+ public static final int CONTACT_LOADER = 0;
+ public static final int ACCOUNTS_LOADER = 1;
+ public static final int HISTORY_LOADER = 2;
+
+}
diff --git a/src/com/savoirfairelinux/sflphone/model/Bubble.java b/src/com/savoirfairelinux/sflphone/model/Bubble.java
index a45b746..6294dab 100644
--- a/src/com/savoirfairelinux/sflphone/model/Bubble.java
+++ b/src/com/savoirfairelinux/sflphone/model/Bubble.java
@@ -4,6 +4,7 @@
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
+import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.PointF;
@@ -13,127 +14,200 @@
import com.savoirfairelinux.sflphone.R;
-public class Bubble
-{
- public CallContact contact;
- // A Bitmap object that is going to be passed to the BitmapShader
- private Bitmap internalBMP, externalBMP;
+public class Bubble {
+ public CallContact contact;
+ // A Bitmap object that is going to be passed to the BitmapShader
+ private Bitmap internalBMP, externalBMP;
- private PointF pos = new PointF();
- private RectF bounds;
- public float target_scale = 1.f;
- private final float radius;
- private float scale = 1.f;
- private float density = 1.f;
- public PointF speed = new PointF(0, 0);
- public PointF last_speed = new PointF();
- public PointF attractor = null;
+ private PointF pos = new PointF();
+ private RectF bounds;
+ public float target_scale = 1.f;
+ private float radius;
+ private float scale = 1.f;
+ private float density = 1.f;
+ public PointF speed = new PointF(0, 0);
+ public PointF last_speed = new PointF();
+ public PointF attractor = null;
- public boolean dragged = false;
- public long last_drag;
+ public boolean dragged = false;
+ public long last_drag;
+ public boolean expanded; // determine if we draw the buttons around the bubble
+ private Bitmap saved_photo;
+ private float expanded_radius = 250;
+ public void setAttractor(PointF attractor) {
+ this.attractor = attractor;
+ }
- public void setAttractor(PointF attractor) {
- this.attractor = attractor;
- }
+ public Bubble(float x, float y, float size, Bitmap photo) {
+ saved_photo = photo;
+ internalBMP = Bitmap.createScaledBitmap(photo, (int) size, (int) size, false);
+ int w = internalBMP.getWidth(), h = internalBMP.getHeight();
- public Bubble(float x, float y, float size, Bitmap photo) {
- internalBMP = Bitmap.createScaledBitmap(photo, (int) size, (int) size, false);
- int w = internalBMP.getWidth(), h = internalBMP.getHeight();
+ pos.set(x, y);
+ radius = w / 2;
+ bounds = new RectF(pos.x - radius, pos.y - radius, pos.x + radius, pos.y + radius);
+ attractor = new PointF(x, y);
- pos.set(x, y);
- radius = w / 2;
- bounds = new RectF(pos.x - radius, pos.y - radius, pos.x + radius, pos.y + radius);
- attractor = new PointF(x, y);
+ Paint circlePaint = new Paint(Paint.ANTI_ALIAS_FLAG);
+ circlePaint.setStyle(Paint.Style.FILL);
+ Bitmap circle = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);
+ Canvas circle_drawer = new Canvas(circle);
+ circle_drawer.drawOval(new RectF(0, 0, w, h), circlePaint);
- Path path = new Path();
- path.addCircle(radius, radius, radius, Path.Direction.CW);
+ externalBMP = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);
+ Canvas canvas = new Canvas(externalBMP);
- Paint circlePaint = new Paint(Paint.ANTI_ALIAS_FLAG);
- circlePaint.setStyle(Paint.Style.FILL);
- Bitmap circle = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);
- Canvas circle_drawer = new Canvas(circle);
- circle_drawer.drawOval(new RectF(0, 0, w, h), circlePaint);
+ circlePaint.setFilterBitmap(false);
+ canvas.drawBitmap(internalBMP, 0, 0, circlePaint);
- externalBMP = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);
- Canvas canvas = new Canvas(externalBMP);
+ circlePaint.setXfermode(new PorterDuffXfermode(Mode.DST_IN));
+ canvas.drawBitmap(circle, 0, 0, circlePaint);
+ }
- circlePaint.setFilterBitmap(false);
- canvas.drawBitmap(internalBMP, 0, 0, circlePaint);
+ public Bubble(float x, float y, float rad, Context c, int resID) {
+ // Initialize the bitmap object by loading an image from the resources folder
+ this(x, y, rad, BitmapFactory.decodeResource(c.getResources(), resID == -1 ? resID : R.drawable.ic_contact_picture));
+ }
- circlePaint.setXfermode(new PorterDuffXfermode(Mode.DST_IN));
- canvas.drawBitmap(circle, 0, 0, circlePaint);
- }
+ public Bitmap getBitmap() {
+ return externalBMP;
+ }
- public Bubble(float x, float y, float rad, Context c, int resID) {
- // Initialize the bitmap object by loading an image from the resources folder
- this(x, y, rad, BitmapFactory.decodeResource(c.getResources(), resID==-1 ? resID : R.drawable.ic_contact_picture));
- }
+ public RectF getBounds() {
+ return bounds;
+ }
- public Bitmap getBitmap() {
- return externalBMP;
- }
+ public void set(float x, float y, float s) {
+ scale = s;
+ pos.x = x;
+ pos.y = y;
+ float rad = scale * getRadius() * density;
+ bounds.set(pos.x - rad, pos.y - rad, pos.x + rad, pos.y + rad);
+ }
- public RectF getBounds() {
- return bounds;
- }
+ public float getPosX() {
+ return pos.x;
+ }
- public void set(float x, float y, float s) {
- scale = s;
- pos.x = x;
- pos.y = y;
- float rad = scale*radius*density;
- bounds.set(pos.x-rad, pos.y-rad, pos.x+rad, pos.y+rad);
- }
+ public float getPosY() {
+ return pos.y;
+ }
- public float getPosX() {
- return pos.x;
- }
+ public void setPos(float x, float y) {
+ set(x, y, scale);
+ }
- public float getPosY() {
- return pos.y;
- }
+ public PointF getPos() {
+ return pos;
+ }
- public void setPos(float x, float y) {
- set(x, y, scale);
- }
+ public float getScale() {
+ return scale;
+ }
- public PointF getPos()
- {
- return pos;
- }
+ public void setScale(float s) {
+ set(pos.x, pos.y, s);
+ }
- public float getScale() {
- return scale;
- }
+ public float getRadius() {
+ return expanded ? expanded_radius : radius;
+ }
- public void setScale(float s) {
- set(pos.x, pos.y, s);
- }
+ /**
+ * Point intersection test.
+ */
+ boolean intersects(float x, float y) {
+ float dx = x - pos.x, dy = y - pos.y;
+ return dx * dx + dy * dy < getRadius() * getRadius();
+ }
- public float getRadius() {
- return radius;
- }
+ /**
+ * Other circle intersection test.
+ */
+ boolean intersects(float x, float y, float radius) {
+ float dx = x - pos.x, dy = y - pos.y;
+ float tot_radius = getRadius() + radius;
+ return dx * dx + dy * dy < tot_radius * tot_radius;
+ }
- /**
- * Point intersection test.
- */
- boolean intersects(float x, float y) {
- float dx = x-pos.x, dy = y-pos.y;
- return dx*dx + dy*dy < radius*radius;
- }
+ public void setDensity(float density) {
+ this.density = density;
+ }
- /**
- * Other circle intersection test.
- */
- boolean intersects(float x, float y, float radius) {
- float dx = x-pos.x, dy = y-pos.y;
- float tot_radius = this.radius + radius;
- return dx*dx + dy*dy < tot_radius*tot_radius;
- }
+ public void expand(int i) {
- public void setDensity(float density)
- {
- this.density = density;
- }
+ // bounds = new RectF(pos.x - 200, pos.y - 200, pos.x + 200, pos.y + 200);
+ // Path path = new Path();
+ // path.addCircle(radius, radius, radius, Path.Direction.CW);
+ //
+ // Paint circlePaint = new Paint(Paint.ANTI_ALIAS_FLAG);
+ // circlePaint.setStyle(Paint.Style.FILL);
+ // Bitmap circle = Bitmap.createBitmap((int) (2 * radius), (int) (2 * radius), Bitmap.Config.ARGB_8888);
+ // Canvas circle_drawer = new Canvas(circle);
+ // circle_drawer.drawOval(new RectF(800 - radius, 800 - radius, 2 * radius, 2 * radius), circlePaint);
+ //
+ // externalBMP = Bitmap.createBitmap(400, 400, Bitmap.Config.ARGB_8888);
+ // Canvas canvas = new Canvas(externalBMP);
+ //
+ // circlePaint.setFilterBitmap(false);
+ // canvas.drawBitmap(internalBMP, 200 - radius, 200 - radius, circlePaint);
+ //
+ // circlePaint.setXfermode(new PorterDuffXfermode(Mode.DST_IN));
+ // canvas.drawBitmap(circle, 200 - radius, 200 - radius, circlePaint);
+
+ expanded_radius = i;
+ expanded = true;
+ internalBMP = Bitmap.createScaledBitmap(saved_photo, (int) (2 * radius), (int) (2 * radius), false);
+ int w = internalBMP.getWidth(), h = internalBMP.getHeight();
+
+ bounds = new RectF(pos.x - getRadius(), pos.y - getRadius(), pos.x + getRadius(), pos.y + getRadius());
+
+ Paint circlePaint = new Paint(Paint.ANTI_ALIAS_FLAG);
+ circlePaint.setStyle(Paint.Style.FILL);
+ Bitmap circle = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);
+ Canvas circle_drawer = new Canvas(circle);
+ circle_drawer.drawOval(new RectF((float) (getRadius() - radius), (float) (getRadius() - radius), w, h), circlePaint);
+
+ externalBMP = Bitmap.createBitmap((int) (getRadius()*2), (int) (getRadius()*2), Bitmap.Config.ARGB_8888);
+ Canvas canvas = new Canvas(externalBMP);
+
+ circlePaint.setFilterBitmap(false);
+ canvas.drawBitmap(internalBMP, (float) (getRadius() - radius), (float) (getRadius() - radius), circlePaint);
+
+ Paint mPaintPath = new Paint(Paint.ANTI_ALIAS_FLAG);
+ mPaintPath.setStyle(Paint.Style.FILL);
+ mPaintPath.setColor(Color.BLUE);
+// mPaintPath.setXfermode(new PorterDuffXfermode(Mode.DST_IN));
+
+ canvas.drawOval(new RectF(0, 0, getRadius()*2, getRadius()*2), mPaintPath);
+
+ circlePaint.setXfermode(new PorterDuffXfermode(Mode.DST_IN));
+ canvas.drawBitmap(circle, (float) (getRadius() - radius), (float) (getRadius() - radius), circlePaint);
+
+ }
+
+ public void retract() {
+ expanded = false;
+ internalBMP = Bitmap.createScaledBitmap(saved_photo, (int) (2 * radius), (int) (2 * radius), false);
+ int w = internalBMP.getWidth(), h = internalBMP.getHeight();
+
+ bounds = new RectF(pos.x - getRadius(), pos.y - getRadius(), pos.x + getRadius(), pos.y + getRadius());
+
+ Paint circlePaint = new Paint(Paint.ANTI_ALIAS_FLAG);
+ circlePaint.setStyle(Paint.Style.FILL);
+ Bitmap circle = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);
+ Canvas circle_drawer = new Canvas(circle);
+ circle_drawer.drawOval(new RectF(0, 0, w, h), circlePaint);
+
+ externalBMP = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);
+ Canvas canvas = new Canvas(externalBMP);
+
+ circlePaint.setFilterBitmap(false);
+ canvas.drawBitmap(internalBMP, 0, 0, circlePaint);
+
+ circlePaint.setXfermode(new PorterDuffXfermode(Mode.DST_IN));
+ canvas.drawBitmap(circle, 0, 0, circlePaint);
+
+ }
}
diff --git a/src/com/savoirfairelinux/sflphone/model/BubblesView.java b/src/com/savoirfairelinux/sflphone/model/BubblesView.java
index 6aab070..1beb761 100644
--- a/src/com/savoirfairelinux/sflphone/model/BubblesView.java
+++ b/src/com/savoirfairelinux/sflphone/model/BubblesView.java
@@ -39,6 +39,8 @@
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Paint.Align;
+import android.graphics.PointF;
+import android.graphics.RectF;
import android.os.Handler;
import android.os.Message;
import android.util.AttributeSet;
@@ -255,6 +257,7 @@
Bubble b = bubbles.get(i);
canvas.drawBitmap(b.getBitmap(), null, b.getBounds(), null);
canvas.drawText(b.contact.getmDisplayName(), b.getPosX(), b.getPosY() - 50 * density, name_paint);
+
}
} catch (IndexOutOfBoundsException e) {
@@ -296,11 +299,19 @@
return gDetector.onTouchEvent(event);
}
+ RectF intern;
+ RectF external;
+
class MyOnGestureListener implements OnGestureListener {
@Override
public boolean onDown(MotionEvent event) {
List<Bubble> bubbles = model.getBubbles();
final int n_bubbles = bubbles.size();
+ Bubble expand = getExpandedBubble();
+ if (expand != null && !expand.intersects(event.getX(), event.getY())) {
+
+ expand.retract();
+ }
Log.d("Main", "onDown");
for (int i = 0; i < n_bubbles; i++) {
Bubble b = bubbles.get(i);
@@ -315,6 +326,18 @@
return true;
}
+ private Bubble getExpandedBubble() {
+ List<Bubble> bubbles = model.getBubbles();
+ final int n_bubbles = bubbles.size();
+ for (int i = 0; i < n_bubbles; i++) {
+ Bubble b = bubbles.get(i);
+ if (b.expanded) {
+ return b;
+ }
+ }
+ return null;
+ }
+
@Override
public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
Log.d("Main", "onFling");
@@ -324,6 +347,36 @@
@Override
public void onLongPress(MotionEvent e) {
Log.d("Main", "onLongPress");
+ if (isDraggingBubble()) {
+ Bubble b = getDraggedBubble(e);
+
+ calculateBounds(b.getPos(), b.getRadius());
+
+ b.expand(100);
+ }
+ }
+
+ private void calculateBounds(PointF pointF, float radius) {
+ // intern = new RectF();
+ // float half_square = (float) (radius / Math.sqrt(2));
+ // intern.set(pointF.x - half_square, pointF.y - half_square, pointF.x + half_square, pointF.y + half_square);
+
+ external = new RectF();
+ float large_half_square = 200;
+ external.set(pointF.x - large_half_square, pointF.y - large_half_square, pointF.x + large_half_square, pointF.y + large_half_square);
+
+ }
+
+ private Bubble getDraggedBubble(MotionEvent e) {
+ List<Bubble> bubbles = model.getBubbles();
+ final int n_bubbles = bubbles.size();
+ for (int i = 0; i < n_bubbles; i++) {
+ Bubble b = bubbles.get(i);
+ if (b.intersects(e.getX(), e.getY())) {
+ return b;
+ }
+ }
+ return null;
}
@Override
diff --git a/src/com/savoirfairelinux/sflphone/model/CallContact.java b/src/com/savoirfairelinux/sflphone/model/CallContact.java
index 0603185..75c8b6b 100644
--- a/src/com/savoirfairelinux/sflphone/model/CallContact.java
+++ b/src/com/savoirfairelinux/sflphone/model/CallContact.java
@@ -32,8 +32,12 @@
import java.util.ArrayList;
+import android.content.ContentResolver;
+import android.database.Cursor;
import android.os.Parcel;
import android.os.Parcelable;
+import android.provider.ContactsContract.Profile;
+import android.util.Log;
public class CallContact implements Parcelable {
@@ -155,14 +159,25 @@
public static CallContact buildUnknownContact(String to) {
ArrayList<Phone> phones = new ArrayList<Phone>();
phones.add(new Phone(to, 0));
-
+
return new CallContact(-1, to, 0, phones, new ArrayList<CallContact.Phone>(), "");
}
-
- public static CallContact buildUserContact(String displayName) {
- ArrayList<Phone> phones = new ArrayList<Phone>();
-
- return new CallContact(-1, displayName, 0, phones, new ArrayList<CallContact.Phone>(), "");
+
+ public static CallContact buildUserContact(ContentResolver cr, String displayName) {
+ String[] mProjection = new String[] { Profile._ID, Profile.PHOTO_ID };
+ Cursor mProfileCursor = cr.query(Profile.CONTENT_URI, mProjection, null, null, null);
+ CallContact result = null;
+ if (mProfileCursor.getCount() > 0) {
+ mProfileCursor.moveToFirst();
+ Log.i("CallContact", "THERE IS AN ENTRY");
+ result = new CallContact(mProfileCursor.getLong(mProfileCursor.getColumnIndex(Profile._ID)), displayName,
+ mProfileCursor.getLong(mProfileCursor.getColumnIndex(Profile.PHOTO_ID)), new ArrayList<Phone>(),
+ new ArrayList<CallContact.Phone>(), "");
+ } else {
+ result = new CallContact(-1, displayName, 0, new ArrayList<Phone>(), new ArrayList<CallContact.Phone>(), "");
+ }
+ mProfileCursor.close();
+ return result;
}
}
@@ -180,9 +195,8 @@
dest.writeTypedList(phones);
dest.writeTypedList(sip_phones);
-
+
dest.writeString(mEmail);
-
}
@@ -272,12 +286,12 @@
public void addPhoneNumber(String tel, int type) {
phones.add(new Phone(tel, type));
-
+
}
public void addSipNumber(String tel, int type) {
sip_phones.add(new Phone(tel, type));
-
+
}
}
diff --git a/src/com/savoirfairelinux/sflphone/model/HistoryEntry.java b/src/com/savoirfairelinux/sflphone/model/HistoryEntry.java
new file mode 100644
index 0000000..640016c
--- /dev/null
+++ b/src/com/savoirfairelinux/sflphone/model/HistoryEntry.java
@@ -0,0 +1,105 @@
+package com.savoirfairelinux.sflphone.model;
+
+import java.text.SimpleDateFormat;
+import java.util.ArrayList;
+import java.util.Calendar;
+import java.util.Locale;
+import java.util.NavigableMap;
+import java.util.TimeZone;
+import java.util.TreeMap;
+
+public class HistoryEntry {
+
+ private CallContact contact;
+ private NavigableMap<Long, HistoryCall> calls;
+ private String accountID;
+
+ public String getAccountID() {
+ return accountID;
+ }
+
+ public void setAccountID(String accountID) {
+ this.accountID = accountID;
+ }
+
+ public NavigableMap<Long, HistoryCall> getCalls() {
+ return calls;
+ }
+
+ public HistoryEntry(String account, CallContact c, long call_start, long call_end, String number) {
+ contact = c;
+ calls = new TreeMap<Long, HistoryEntry.HistoryCall>();
+ calls.put(call_start, new HistoryCall(call_start, call_end, number));
+ accountID = account;
+ }
+
+ public static class HistoryCall {
+ long call_start;
+ long call_end;
+ String number;
+
+ public HistoryCall(long start, long end, String n) {
+ call_start = start;
+ call_end = end;
+ number = n;
+ }
+
+ public String getDate(String format) {
+ Calendar cal = Calendar.getInstance();
+ TimeZone tz = cal.getTimeZone();
+ SimpleDateFormat objFormatter = new SimpleDateFormat(format, Locale.CANADA);
+ objFormatter.setTimeZone(tz);
+
+ Calendar objCalendar = Calendar.getInstance(tz);
+ objCalendar.setTimeInMillis(call_start * 1000);
+ String result = objFormatter.format(objCalendar.getTime());
+ objCalendar.clear();
+ return result;
+ }
+
+ public String getDurationString() {
+ long duration = call_end - call_start;
+ if (duration < 60)
+ return duration + "s";
+
+ return duration / 60 + "min";
+
+ }
+
+ public long getDuration() {
+ return call_end - call_start;
+
+ }
+
+ }
+
+ public CallContact getContact() {
+ return contact;
+ }
+
+ public void setContact(CallContact contact) {
+ this.contact = contact;
+ }
+
+ public void addHistoryCall(HistoryCall historyCall) {
+ calls.put(historyCall.call_start, historyCall);
+
+ }
+
+ public String getNumber() {
+ return calls.lastEntry().getValue().number;
+ }
+
+ public String getTotalDuration() {
+ int duration = 0;
+ ArrayList<HistoryCall> all_calls = new ArrayList<HistoryEntry.HistoryCall>(calls.values());
+ for(int i = 0 ; i < all_calls.size() ; ++i){
+ duration += all_calls.get(i).getDuration();
+ }
+
+ if (duration < 60)
+ return duration + "s";
+
+ return duration / 60 + "min";
+ }
+}