package com.steamcommunity.siplus.steamscreenshots;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Comparator;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
import org.xmlpull.v1.XmlPullParserFactory;
import android.accounts.Account;
import android.accounts.AccountManager;
import android.app.Activity;
import android.content.Intent;
import android.content.res.Resources;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.os.AsyncTask;
import android.os.Bundle;
import android.util.Base64;
import android.util.DisplayMetrics;
import android.util.TypedValue;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.BaseAdapter;
import android.widget.LinearLayout;
import android.widget.ListView;
import android.widget.Toast;
public final class LoginSelectActivity extends Activity {
AccountManager mAccountManager;
SteamshotsAccount[] mAccounts;
LoginSelectAdapter mAdapter;
LoginSelectAvatarTask mAvatarTask;
Drawable mDefaultAvatar;
LinearLayout widgetEmpty;
ListView widgetList;
void avatarLoaded(long steamID, String address, byte[] avatar) {
int i;
long time = System.currentTimeMillis() + 86400000L;
SteamshotsAccount steamshotsAccount;
Account account;
AccountManager accountManager = mAccountManager;
Account[] accounts = accountManager.getAccountsByType(Utility.PACKAGE);
long accountSteamID;
for (i = 0; i < accounts.length; ++i) {
account = accounts[i];
try {
accountSteamID = Long.parseLong(accountManager.getUserData(account, SteamshotsAccount.DATA_STEAM_ID));
} catch (NumberFormatException e) {
continue;
}
if (accountSteamID != steamID) {
continue;
}
if (address == null) { // Failed to get the address - just delay for a hour and don't update anything
accountManager.setUserData(account, SteamshotsAccount.DATA_NEXT_AVATAR_UPDATE, Long.toString(time - 82800000L));
break;
}
accountManager.setUserData(account, SteamshotsAccount.DATA_NEXT_AVATAR_UPDATE, Long.toString(time));
if (address.equals(accountManager.getUserData(account, SteamshotsAccount.DATA_AVATAR_ADDRESS))) {
break;
}
if (avatar == null) {
accountManager.setUserData(account, SteamshotsAccount.DATA_AVATAR, null);
} else {
accountManager.setUserData(account, SteamshotsAccount.DATA_AVATAR,
Base64.encodeToString(avatar, Base64.NO_WRAP));
}
accountManager.setUserData(account, SteamshotsAccount.DATA_AVATAR_ADDRESS, address);
break;
}
SteamshotsAccount[] steamshotsAccounts = mAccounts;
for (i = 0; i < steamshotsAccounts.length; ++i) {
steamshotsAccount = steamshotsAccounts[i];
if (steamshotsAccount.mSteamID != steamID) {
continue;
}
// No need to set .mNextAvatarUpdate, because it's used only once when loading accounts and avatars
if (address == null) {
break;
}
if (avatar == null) {
steamshotsAccount.mAvatar = null;
} else {
steamshotsAccount.mAvatar = BitmapFactory.decodeByteArray(avatar, 0, avatar.length);
}
steamshotsAccount.mAvatarAddress = address;
break;
}
mAdapter.notifyDataSetChanged();
}
void loadAccounts() {
if (mAvatarTask != null) {
mAvatarTask.cancel(false);
return;
}
AccountManager accountManager = mAccountManager;
Account[] accounts = accountManager.getAccountsByType(Utility.PACKAGE);
int accountsLength = accounts.length;
int i;
SteamshotsAccount[] steamshotsAccounts = new SteamshotsAccount[accountsLength];
mAccounts = steamshotsAccounts;
for (i = 0; i < accountsLength; ++i) {
steamshotsAccounts[i] = new SteamshotsAccount(accountManager, accounts[i]);
}
Arrays.sort(steamshotsAccounts, new LoginSelectComparator());
if (Utility.isConnected(this)) {
ArrayList<SteamshotsAccount> avatarsToLoad = new ArrayList<SteamshotsAccount>(accountsLength);
SteamshotsAccount steamshotsAccount;
long time = System.currentTimeMillis();
for (i = 0; i < accountsLength; ++i) {
steamshotsAccount = steamshotsAccounts[i];
if (time > steamshotsAccount.mNextAvatarUpdate) {
avatarsToLoad.add(steamshotsAccount);
}
}
if (!avatarsToLoad.isEmpty()) {
LoginSelectAvatarTask task = new LoginSelectAvatarTask(this, avatarsToLoad);
mAvatarTask = task;
task.execute((Void)(null));
}
}
if (accountsLength == 0) {
widgetEmpty.setVisibility(View.VISIBLE);
widgetList.setVisibility(View.GONE);
} else {
widgetEmpty.setVisibility(View.GONE);
mAdapter = new LoginSelectAdapter(this);
widgetList.setAdapter(mAdapter);
widgetList.setOnItemClickListener(new LoginSelectOnItemClick(this));
widgetList.setVisibility(View.VISIBLE);
}
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if ((getIntent().getFlags() & Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT) != 0) {
finish();
return;
}
mAccountManager = AccountManager.get(this);
mDefaultAvatar = getResources().getDrawable(R.drawable.avatar);
setTitle(R.string.login_select_label);
setContentView(R.layout.view_login_select);
widgetEmpty = (LinearLayout)(findViewById(R.id.view_login_select_empty));
widgetList = (ListView)(findViewById(R.id.view_login_select_list));
loadAccounts();
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.login_select, menu);
return true;
}
@Override
protected void onDestroy() {
super.onDestroy();
if (mAvatarTask != null) {
mAvatarTask.cancel(false);
}
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
if (item.getItemId() != R.id.action_login_select_add) {
return super.onOptionsItemSelected(item);
}
startActivity(new Intent(getApplicationContext(), LoginAddActivity.class)
.putExtra(LoginAddActivity.EXTRASTATE_FROM_APP, true));
return true;
}
@Override
protected void onRestart() {
super.onRestart();
loadAccounts();
}
}
class LoginSelectAdapter extends BaseAdapter {
LoginSelectActivity mActivity;
float mDisabledAlpha;
LayoutInflater mLayoutInflater;
Resources mResources;
LoginSelectAdapter(LoginSelectActivity activity) {
mActivity = activity;
{
TypedValue outValue = new TypedValue();
activity.getTheme().resolveAttribute(android.R.attr.disabledAlpha, outValue, true);
mDisabledAlpha = outValue.getFloat();
}
mLayoutInflater = activity.getLayoutInflater();
mResources = activity.getResources();
}
@Override
public int getCount() {
return mActivity.mAccounts.length;
}
@Override
public Object getItem(int position) {
return mActivity.mAccounts[position];
}
@Override
public long getItemId(int position) {
return position;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
LoginSelectActivity activity = mActivity;
SteamshotsAccount account = activity.mAccounts[position];
Drawable avatar;
Bitmap avatarBitmap = account.mAvatar;
if (avatarBitmap != null) {
avatar = new BitmapDrawable(mResources, avatarBitmap);
} else {
avatar = activity.mDefaultAvatar;
}
View view = Utility.inflateImageTextListItem(mLayoutInflater, parent, avatar, account.mName);
if (!account.mValid) {
view.setAlpha(mDisabledAlpha);
}
return view;
}
}
class LoginSelectAvatarTask extends AsyncTask<Void, Object, Void> {
SteamshotsAccount[] mAccounts;
LoginSelectActivity mActivity;
String mAddressElement;
LoginSelectAvatarTask(LoginSelectActivity activity, ArrayList<SteamshotsAccount> accounts) {
mActivity = activity;
mAccounts = new SteamshotsAccount[accounts.size()];
accounts.toArray(mAccounts);
DisplayMetrics metrics = new DisplayMetrics();
activity.getWindowManager().getDefaultDisplay().getMetrics(metrics);
int density = metrics.densityDpi;
if (density <= DisplayMetrics.DENSITY_LOW) {
mAddressElement = "avatarIcon";
} else if (density >= DisplayMetrics.DENSITY_XHIGH) {
mAddressElement = "avatarFull";
} else {
mAddressElement = "avatarMedium";
}
}
@Override
protected Void doInBackground(Void... params) {
int i;
SteamshotsAccount account;
String address;
SteamshotsAccount[] accounts = mAccounts;
byte[] avatar;
long steamID;
for (i = 0; i < accounts.length; ++i) {
account = accounts[i];
steamID = account.mSteamID;
address = requestAddress(steamID);
if (isCancelled()) {return null;}
if (address == null) {
publishProgress(steamID, null, null);
continue;
}
if (address.indexOf("fef49e7fa7e1997310d705b2a6158ff8dc1cdfeb") >= 0) {
publishProgress(steamID, address, null);
continue;
}
avatar = downloadFile(address, "image/jpeg");
if (isCancelled()) {return null;}
if (avatar == null) {
publishProgress(steamID, null, null);
} else {
publishProgress(steamID, address, avatar);
}
}
return null;
}
byte[] downloadFile(String address, String contentType) {
URL url;
try {
url = new URL(address);
} catch (MalformedURLException e) {
return null;
}
HttpURLConnection connection = null;
try {
connection = (HttpURLConnection)(url.openConnection());
connection.setInstanceFollowRedirects(true);
connection.connect();
if (isCancelled() ||
(connection.getResponseCode() != HttpURLConnection.HTTP_OK) ||
!contentType.equals(connection.getContentType())) {
connection.disconnect();
return null;
}
byte[] buffer = new byte[16384];
InputStream inputStream = connection.getInputStream();
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
int read;
for (;;) {
if (isCancelled()) {
connection.disconnect();
return null;
}
read = inputStream.read(buffer);
if (read < 0) {
break;
}
outputStream.write(buffer, 0, read);
}
connection.disconnect();
return outputStream.toByteArray();
} catch (IOException e) {
if (connection != null) {
connection.disconnect();
}
return null;
}
}
@Override
protected void onProgressUpdate(Object... progress) {
if (!isCancelled()) {
mActivity.avatarLoaded((Long)(progress[0]), (String)(progress[1]), (byte[])(progress[2]));
}
}
String requestAddress(long steamID) {
byte[] data = downloadFile(String.format("http://steamcommunity.com/profiles/%d?xml=1", steamID),
"text/xml; charset=utf-8");
if ((data == null) || isCancelled()) {
return null;
}
try {
XmlPullParser parser = XmlPullParserFactory.newInstance().newPullParser();
parser.setInput(new ByteArrayInputStream(data), "UTF-8");
String element = mAddressElement;
int event;
for (;;) {
event = parser.next();
if (event == XmlPullParser.END_DOCUMENT) {
return null;
}
if ((event != XmlPullParser.START_TAG) || (!element.equals(parser.getName()))) {
continue;
}
return parser.nextText();
}
} catch (IOException e) {
return null;
} catch (XmlPullParserException e) {
return null;
}
}
}
class LoginSelectComparator implements Comparator<SteamshotsAccount> {
@Override
public int compare(SteamshotsAccount lhs, SteamshotsAccount rhs) {
return lhs.mName.compareTo(rhs.mName);
}
}
class LoginSelectOnItemClick implements OnItemClickListener {
LoginSelectActivity mActivity;
LoginSelectOnItemClick(LoginSelectActivity activity) {
mActivity = activity;
}
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
LoginSelectActivity activity = mActivity;
SteamshotsAccount account = activity.mAccounts[position];
if (!account.mValid) {
Toast.makeText(activity, R.string.login_select_corrupted, Toast.LENGTH_LONG).show();
return;
}
activity.startActivity(new Intent(activity.getApplicationContext(), ScreenshotsActivity.class)
.putExtra(ScreenshotsActivity.EXTRASTATE_ACCOUNT, account));
}
}