package de.robv.android.xposed.installer;
import android.app.Activity;
import android.app.ListFragment;
import android.content.Context;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.os.Bundle;
import android.text.method.LinkMovementMethod;
import android.util.DisplayMetrics;
import android.util.TypedValue;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.TextView;
import android.widget.Toast;
import java.io.File;
import java.text.DateFormat;
import java.util.Date;
import de.robv.android.xposed.installer.repo.Module;
import de.robv.android.xposed.installer.repo.ModuleVersion;
import de.robv.android.xposed.installer.repo.ReleaseType;
import de.robv.android.xposed.installer.repo.RepoParser;
import de.robv.android.xposed.installer.util.DownloadsUtil;
import de.robv.android.xposed.installer.util.HashUtil;
import de.robv.android.xposed.installer.util.ModuleUtil.InstalledModule;
import de.robv.android.xposed.installer.util.RepoLoader;
import de.robv.android.xposed.installer.util.ThemeUtil;
import de.robv.android.xposed.installer.util.chrome.LinkTransformationMethod;
import de.robv.android.xposed.installer.widget.DownloadView;
import static de.robv.android.xposed.installer.XposedApp.WRITE_EXTERNAL_PERMISSION;
public class DownloadDetailsVersionsFragment extends ListFragment {
private static VersionsAdapter sAdapter;
private DownloadDetailsActivity mActivity;
private Module module;
@Override
public void onAttach(Activity activity) {
super.onAttach(activity);
mActivity = (DownloadDetailsActivity) activity;
}
@Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
module = mActivity.getModule();
if (module == null)
return;
if (module.versions.isEmpty()) {
setEmptyText(getString(R.string.download_no_versions));
setListShown(true);
} else {
RepoLoader repoLoader = RepoLoader.getInstance();
if (!repoLoader.isVersionShown(module.versions.get(0))) {
TextView txtHeader = new TextView(getActivity());
txtHeader.setText(R.string.download_test_version_not_shown);
txtHeader.setTextColor(getResources().getColor(R.color.warning));
txtHeader.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
mActivity.gotoPage(DownloadDetailsActivity.DOWNLOAD_SETTINGS);
}
});
getListView().addHeaderView(txtHeader);
}
sAdapter = new VersionsAdapter(mActivity, mActivity.getInstalledModule());
for (ModuleVersion version : module.versions) {
if (repoLoader.isVersionShown(version))
sAdapter.add(version);
}
setListAdapter(sAdapter);
}
DisplayMetrics metrics = getResources().getDisplayMetrics();
int sixDp = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 6, metrics);
int eightDp = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 8, metrics);
getListView().setDivider(null);
getListView().setDividerHeight(sixDp);
getListView().setPadding(eightDp, eightDp, eightDp, eightDp);
getListView().setClipToPadding(false);
}
@Override
public void onDestroyView() {
super.onDestroyView();
setListAdapter(null);
}
@Override
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
if (requestCode == WRITE_EXTERNAL_PERMISSION) {
if (grantResults.length == 1 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
DownloadsUtil.add(getActivity(), module.name,
DownloadView.mClickedUrl,
new DownloadsUtil.DownloadFinishedCallback() {
@Override
public void onDownloadFinished(Context context, DownloadsUtil.DownloadInfo info) {
Toast.makeText(context, context.getString(R.string.module_saved, info.localFilename), Toast.LENGTH_SHORT).show();
}
}, DownloadsUtil.MIME_TYPES.APK, true, true);
} else {
Toast.makeText(getActivity(), R.string.permissionNotGranted, Toast.LENGTH_LONG).show();
}
}
}
static class ViewHolder {
TextView txtStatus;
TextView txtVersion;
TextView txtRelType;
TextView txtUploadDate;
DownloadView downloadView;
TextView txtChangesTitle;
TextView txtChanges;
}
public static class DownloadModuleCallback implements DownloadsUtil.DownloadFinishedCallback {
private final ModuleVersion moduleVersion;
public DownloadModuleCallback(ModuleVersion moduleVersion) {
this.moduleVersion = moduleVersion;
}
@Override
public void onDownloadFinished(Context context,
DownloadsUtil.DownloadInfo info) {
File localFile = new File(info.localFilename);
if (!localFile.isFile())
return;
if (moduleVersion.md5sum != null && !moduleVersion.md5sum.isEmpty()) {
try {
String actualMd5Sum = HashUtil.md5(localFile);
if (!moduleVersion.md5sum.equals(actualMd5Sum)) {
Toast.makeText(context, context.getString(R.string.download_md5sum_incorrect, actualMd5Sum, moduleVersion.md5sum), Toast.LENGTH_LONG).show();
DownloadsUtil.removeById(context, info.id);
return;
}
} catch (Exception e) {
Toast.makeText(context, context.getString(R.string.download_could_not_read_file, e.getMessage()), Toast.LENGTH_LONG).show();
DownloadsUtil.removeById(context, info.id);
return;
}
}
PackageManager pm = context.getPackageManager();
PackageInfo packageInfo = pm.getPackageArchiveInfo(info.localFilename, 0);
if (packageInfo == null) {
Toast.makeText(context, R.string.download_no_valid_apk, Toast.LENGTH_LONG).show();
DownloadsUtil.removeById(context, info.id);
return;
}
if (!packageInfo.packageName
.equals(moduleVersion.module.packageName)) {
Toast.makeText(context, context.getString(R.string.download_incorrect_package_name, packageInfo.packageName, moduleVersion.module.packageName), Toast.LENGTH_LONG).show();
DownloadsUtil.removeById(context, info.id);
return;
}
XposedApp.installApk(context, info);
}
}
private class VersionsAdapter extends ArrayAdapter<ModuleVersion> {
private final DateFormat mDateFormatter = DateFormat
.getDateInstance(DateFormat.SHORT);
private final int mColorRelTypeStable;
private final int mColorRelTypeOthers;
private final int mColorInstalled;
private final int mColorUpdateAvailable;
private final String mTextInstalled;
private final String mTextUpdateAvailable;
private final int mInstalledVersionCode;
public VersionsAdapter(Context context, InstalledModule installed) {
super(context, R.layout.list_item_version);
mColorRelTypeStable = ThemeUtil.getThemeColor(context, android.R.attr.textColorTertiary);
mColorRelTypeOthers = getResources().getColor(R.color.warning);
mColorInstalled = ThemeUtil.getThemeColor(context, R.attr.download_status_installed);
mColorUpdateAvailable = getResources().getColor(R.color.download_status_update_available);
mTextInstalled = getString(R.string.download_section_installed) + ":";
mTextUpdateAvailable = getString(R.string.download_section_update_available) + ":";
mInstalledVersionCode = (installed != null) ? installed.versionCode : -1;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
View view = convertView;
if (view == null) {
LayoutInflater inflater = (LayoutInflater) getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
view = inflater.inflate(R.layout.list_item_version, null, true);
ViewHolder viewHolder = new ViewHolder();
viewHolder.txtStatus = (TextView) view.findViewById(R.id.txtStatus);
viewHolder.txtVersion = (TextView) view.findViewById(R.id.txtVersion);
viewHolder.txtRelType = (TextView) view.findViewById(R.id.txtRelType);
viewHolder.txtUploadDate = (TextView) view.findViewById(R.id.txtUploadDate);
viewHolder.downloadView = (DownloadView) view.findViewById(R.id.downloadView);
viewHolder.txtChangesTitle = (TextView) view.findViewById(R.id.txtChangesTitle);
viewHolder.txtChanges = (TextView) view.findViewById(R.id.txtChanges);
viewHolder.downloadView.fragment = DownloadDetailsVersionsFragment.this;
view.setTag(viewHolder);
}
ViewHolder holder = (ViewHolder) view.getTag();
ModuleVersion item = getItem(position);
holder.txtVersion.setText(item.name);
holder.txtRelType.setText(item.relType.getTitleId());
holder.txtRelType.setTextColor(item.relType == ReleaseType.STABLE
? mColorRelTypeStable : mColorRelTypeOthers);
if (item.uploaded > 0) {
holder.txtUploadDate.setText(
mDateFormatter.format(new Date(item.uploaded)));
holder.txtUploadDate.setVisibility(View.VISIBLE);
} else {
holder.txtUploadDate.setVisibility(View.GONE);
}
if (item.code <= 0 || mInstalledVersionCode <= 0
|| item.code < mInstalledVersionCode) {
holder.txtStatus.setVisibility(View.GONE);
} else if (item.code == mInstalledVersionCode) {
holder.txtStatus.setText(mTextInstalled);
holder.txtStatus.setTextColor(mColorInstalled);
holder.txtStatus.setVisibility(View.VISIBLE);
} else { // item.code > mInstalledVersionCode
holder.txtStatus.setText(mTextUpdateAvailable);
holder.txtStatus.setTextColor(mColorUpdateAvailable);
holder.txtStatus.setVisibility(View.VISIBLE);
}
holder.downloadView.setUrl(item.downloadLink);
holder.downloadView.setTitle(mActivity.getModule().name);
holder.downloadView.setDownloadFinishedCallback(new DownloadModuleCallback(item));
if (item.changelog != null && !item.changelog.isEmpty()) {
holder.txtChangesTitle.setVisibility(View.VISIBLE);
holder.txtChanges.setVisibility(View.VISIBLE);
if (item.changelogIsHtml) {
holder.txtChanges.setText(RepoParser.parseSimpleHtml(getActivity(), item.changelog, holder.txtChanges));
holder.txtChanges.setTransformationMethod(new LinkTransformationMethod(getActivity()));
holder.txtChanges.setMovementMethod(LinkMovementMethod.getInstance());
} else {
holder.txtChanges.setText(item.changelog);
holder.txtChanges.setMovementMethod(null);
}
} else {
holder.txtChangesTitle.setVisibility(View.GONE);
holder.txtChanges.setVisibility(View.GONE);
}
return view;
}
}
}