/**
* Copyright (C) 2010-2012 Regis Montoya (aka r3gis - www.r3gis.fr)
* This file is part of CSipSimple.
*
* CSipSimple 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.
* If you own a pjsip commercial license you can also redistribute it
* and/or modify it under the terms of the GNU Lesser General Public License
* as an android library.
*
* CSipSimple 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 CSipSimple. If not, see <http://www.gnu.org/licenses/>.
*/
package com.csipsimple.ui.favorites;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.database.ContentObserver;
import android.os.Handler;
import android.os.IBinder;
import android.os.RemoteException;
import android.util.AttributeSet;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.ImageView;
import android.widget.Spinner;
import android.widget.TextView;
import com.csipsimple.R;
import com.csipsimple.api.ISipService;
import com.csipsimple.api.SipManager.PresenceStatus;
import com.csipsimple.api.SipProfile;
import com.csipsimple.service.SipService;
import com.csipsimple.utils.AccountListUtils;
import com.csipsimple.utils.AccountListUtils.AccountStatusDisplay;
import com.csipsimple.utils.Log;
import java.util.ArrayList;
import java.util.List;
public class PresenceStatusSpinner extends Spinner implements android.widget.AdapterView.OnItemSelectedListener {
private static final String THIS_FILE = "PresenceStatusSpinner";
private long profileId = SipProfile.INVALID_ID;
private boolean hasPresenceRegistration = false;
private boolean isValid = false;
private PresencesAdapter mAdapter;
public PresenceStatusSpinner(Context context, AttributeSet attrs) {
super(context, attrs);
List<CharSequence> list = new ArrayList<CharSequence>();
if(!isInEditMode()) {
String[] fromRes = context.getResources().getStringArray(R.array.presence_status_names);
for(CharSequence str : fromRes) {
list.add(str);
}
}
mAdapter = new PresencesAdapter(getContext(), list);
mAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
setAdapter(mAdapter);
updateRegistration();
setOnItemSelectedListener(this);
}
private class PresencesAdapter extends ArrayAdapter<CharSequence> {
private LayoutInflater inflater;
public PresencesAdapter(Context context, List<CharSequence> datas) {
super(context, android.R.layout.simple_spinner_item, datas);
inflater = (LayoutInflater) getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
}
/**
* {@inheritDoc}
*/
@Override
public View getDropDownView(int position, View convertView, ViewGroup parent) {
return getCustomView(position, convertView, parent, true);
}
/**
* {@inheritDoc}
*/
@Override
public View getView(int position, View convertView, ViewGroup parent) {
return getCustomView(position, convertView, parent, false);
}
/**
* Get the custom view for the presence spinner.
* @param position position of the item
* @param convertView view to convert
* @param parent Group to open to
* @param choiceMode true if it's part of drop down
* @return the view recycled.
*/
public View getCustomView(int position, View convertView, ViewGroup parent, boolean choiceMode) {
View row = inflater.inflate(R.layout.fav_presence_item, parent, false);
TextView label = (TextView) row.findViewById(R.id.item_status_text);
ImageView icon = (ImageView) row.findViewById(R.id.item_status_icon);
//TextView contactName = (TextView) row.findViewById(R.id.contact_name);
// Show / hide
//contactName.setVisibility(/*dropDownMode ? View.VISIBLE : */View.GONE);
int padding = choiceMode ? 15 : 5;
row.setPadding(padding, padding, padding, padding);
// Content binding
if(hasPresenceRegistration) {
label.setText(getItem(position));
icon.setImageResource(position == 0 ? android.R.drawable.presence_online : android.R.drawable.presence_invisible);
icon.setVisibility(View.VISIBLE);
}else {
label.setText(choiceMode ? getItem(position) : getContext().getString(R.string.presence));
icon.setVisibility(View.GONE);
}
return row;
}
}
/**
* {@inheritDoc}
*/
@Override
public void onItemSelected(AdapterView<?> adapter, View v, int position, long id) {
if(profileId != SipProfile.INVALID_ID) {
if(hasPresenceRegistration && isValid) {
if(position < PRESENCES_ITEMS_LENGTH) {
if(service != null) {
try {
service.setPresence(getSelectedPresence().ordinal(), "Test", profileId);
} catch (RemoteException e) {
Log.e(THIS_FILE, "Error while trying to set presence through service", e);
}
}
}
}
}
}
/**
* Set the account profile that this spinner controls
* @param accId
*/
public void setProfileId(long accId) {
profileId = accId;
}
private static final int PRESENCES_ITEMS_LENGTH = 2;
private PresenceStatus getSelectedPresence() {
switch (getSelectedItemPosition()) {
case 1:
return PresenceStatus.OFFLINE;
case 0:
default:
return PresenceStatus.ONLINE;
}
}
/**
* {@inheritDoc}
*/
@Override
public void onNothingSelected(AdapterView<?> adapter) {
// We have nothing to do in this case
}
/**
* Observer for changes of account registration status
*/
class AccountStatusContentObserver extends ContentObserver {
public AccountStatusContentObserver(Handler h) {
super(h);
}
public void onChange(boolean selfChange) {
Log.d(THIS_FILE, "Accounts status.onChange( " + selfChange + ")");
updateRegistration();
}
}
private static final String[] ACC_PROJECTION = new String[] {
SipProfile.FIELD_ID,
SipProfile.FIELD_ACC_ID, // Needed for default domain
SipProfile.FIELD_REG_URI, // Needed for default domain
SipProfile.FIELD_PROXY, // Needed for default domain
SipProfile.FIELD_DEFAULT_URI_SCHEME, // Needed for default scheme
SipProfile.FIELD_DISPLAY_NAME,
SipProfile.FIELD_WIZARD,
SipProfile.FIELD_PUBLISH_ENABLED
};
/**
* Update user interface when registration of account has changed
* This include change selected account if we are in canChangeIfValid mode
*/
private void updateRegistration() {
if(profileId < 0) {
return;
}
SipProfile acc = SipProfile.getProfileFromDbId(getContext(), profileId, ACC_PROJECTION);
isValid = false;
hasPresenceRegistration = false;
if(acc != null) {
AccountStatusDisplay accountStatusDisplay = AccountListUtils
.getAccountDisplay(getContext(), acc.id);
if(accountStatusDisplay.availableForCalls) {
isValid = true;
}
hasPresenceRegistration = (acc.publish_enabled == 1);
}
setEnabled(isValid);
setVisibility(hasPresenceRegistration ? View.VISIBLE : View.GONE);
}
// Service connection
private ISipService service;
private ServiceConnection connection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName arg0, IBinder arg1) {
service = ISipService.Stub.asInterface(arg1);
}
@Override
public void onServiceDisconnected(ComponentName arg0) {
service = null;
}
};
private final Handler mHandler = new Handler();
private AccountStatusContentObserver statusObserver = null;
protected void onAttachedToWindow() {
super.onAttachedToWindow();
getContext().bindService(new Intent(getContext(), SipService.class), connection, Context.BIND_AUTO_CREATE);
if(statusObserver == null) {
statusObserver = new AccountStatusContentObserver(mHandler);
getContext().getContentResolver().registerContentObserver(SipProfile.ACCOUNT_STATUS_URI,
true, statusObserver);
}
updateRegistration();
};
@Override
protected void onDetachedFromWindow() {
super.onDetachedFromWindow();
try {
getContext().unbindService(connection);
} catch (Exception e) {
// Just ignore that
}
if (statusObserver != null) {
getContext().getContentResolver().unregisterContentObserver(statusObserver);
statusObserver = null;
}
service = null;
}
}