diff --git a/app_pojavlauncher/src/main/java/com/kdt/mcgui/mcAccountSpinner.java b/app_pojavlauncher/src/main/java/com/kdt/mcgui/mcAccountSpinner.java index 0cf849263..9280aa2ae 100644 --- a/app_pojavlauncher/src/main/java/com/kdt/mcgui/mcAccountSpinner.java +++ b/app_pojavlauncher/src/main/java/com/kdt/mcgui/mcAccountSpinner.java @@ -8,19 +8,24 @@ import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Paint; import android.graphics.drawable.BitmapDrawable; +import android.graphics.drawable.Drawable; import android.net.Uri; import android.util.AttributeSet; import android.util.Log; +import android.view.LayoutInflater; import android.view.MotionEvent; import android.view.View; +import android.view.ViewGroup; import android.widget.AdapterView; import android.widget.ArrayAdapter; +import android.widget.BaseAdapter; import android.widget.Toast; import androidx.annotation.Keep; import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.appcompat.widget.AppCompatSpinner; +import androidx.core.content.res.ResourcesCompat; import net.kdt.pojavlaunch.PojavProfile; @@ -39,6 +44,7 @@ import net.kdt.pojavlaunch.value.MinecraftAccount; import java.io.File; import java.io.IOException; import java.util.ArrayList; +import java.util.HashMap; import java.util.List; import fr.spse.extended_view.ExtendedTextView; @@ -251,7 +257,7 @@ public class mcAccountSpinner extends AppCompatSpinner implements AdapterView.On } String[] accountArray = mAccountList.toArray(new String[0]); - ArrayAdapter accountAdapter = new ArrayAdapter<>(getContext(), R.layout.item_minecraft_account, accountArray); + AccountAdapter accountAdapter = new AccountAdapter(getContext(), R.layout.item_minecraft_account, accountArray); accountAdapter.setDropDownViewResource(R.layout.item_minecraft_account); setAdapter(accountAdapter); @@ -306,6 +312,12 @@ public class mcAccountSpinner extends AppCompatSpinner implements AdapterView.On } mSelectecAccount = selectedAccount; + setImageFromSelectedAccount(); + } + + @Deprecated() + /* Legacy behavior, update the head image manually for the selected account */ + private void setImageFromSelectedAccount(){ BitmapDrawable oldBitmapDrawable = mHeadDrawable; if(mSelectecAccount != null){ @@ -314,21 +326,54 @@ public class mcAccountSpinner extends AppCompatSpinner implements AdapterView.On Bitmap bitmap = mSelectecAccount.getSkinFace(); if(bitmap != null) { mHeadDrawable = new BitmapDrawable(getResources(), bitmap); - mHeadDrawable.setBounds(0, 0, bitmap.getWidth(), bitmap.getHeight()); - view.setCompoundDrawables(mHeadDrawable, null, null, null); - view.postProcessDrawables(); }else{ view.setCompoundDrawables(null, null, null, null); - view.postProcessDrawables(); } + view.postProcessDrawables(); } } if(oldBitmapDrawable != null){ oldBitmapDrawable.getBitmap().recycle(); } + } + + private static class AccountAdapter extends ArrayAdapter { + + private final HashMap mImageCache = new HashMap<>(); + public AccountAdapter(@NonNull Context context, int resource, @NonNull String[] objects) { + super(context, resource, objects); + } + + @Override + public View getDropDownView(int position, @Nullable View convertView, @NonNull ViewGroup parent) { + return getView(position, convertView, parent); + } + + @NonNull + @Override + public View getView(int position, View convertView, @NonNull ViewGroup parent) { + if(convertView == null){ + convertView = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_minecraft_account, parent, false); + } + ExtendedTextView textview = (ExtendedTextView) convertView; + textview.setText(super.getItem(position)); + + // Handle the "Add account section" + if(position == 0) textview.setCompoundDrawables(ResourcesCompat.getDrawable(parent.getResources(), R.drawable.ic_add, null), null, null, null); + else { + String username = super.getItem(position); + Drawable accountHead = mImageCache.get(username); + if (accountHead == null){ + accountHead = new BitmapDrawable(parent.getResources(), MinecraftAccount.getSkinFace(username)); + mImageCache.put(username, accountHead); + } + textview.setCompoundDrawables(accountHead, null, null, null); + } + return convertView; + } } } diff --git a/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/value/MinecraftAccount.java b/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/value/MinecraftAccount.java index ae133e44f..68c871c95 100644 --- a/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/value/MinecraftAccount.java +++ b/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/value/MinecraftAccount.java @@ -5,6 +5,8 @@ import android.graphics.BitmapFactory; import android.util.Log; import net.kdt.pojavlaunch.*; +import net.kdt.pojavlaunch.utils.FileUtils; + import java.io.*; import com.google.gson.*; import android.graphics.Bitmap; @@ -25,14 +27,14 @@ public class MinecraftAccount { public boolean isMicrosoft = false; public String msaRefreshToken = "0"; public String xuid; - public String skinFaceBase64; public long expiresAt; + public String skinFaceBase64; + private Bitmap mFaceCache; void updateSkinFace(String uuid) { try { - File skinFile = File.createTempFile("skin", ".png", new File(Tools.DIR_DATA, "cache")); + File skinFile = getSkinFaceFile(username); Tools.downloadFile("https://mc-heads.net/head/" + uuid + "/100", skinFile.getAbsolutePath()); - skinFaceBase64 = Base64.encodeToString(IOUtils.toByteArray(new FileInputStream(skinFile)), Base64.DEFAULT); Log.i("SkinLoader", "Update skin face success"); } catch (IOException e) { @@ -85,9 +87,6 @@ public class MinecraftAccount { if (acc.msaRefreshToken == null) { acc.msaRefreshToken = "0"; } - if (acc.skinFaceBase64 == null) { - // acc.updateSkinFace("MHF_Steve"); - } return acc; } catch(IOException | JsonSyntaxException e) { Log.e(MinecraftAccount.class.getName(), "Caught an exception while loading the profile",e); @@ -96,11 +95,29 @@ public class MinecraftAccount { } public Bitmap getSkinFace(){ - if(skinFaceBase64 == null){ - return null; + if(isLocal()) return null; + + File skinFaceFile = getSkinFaceFile(username); + if (!skinFaceFile.exists()) { + // Legacy version, storing the head inside the json as base 64 + if(skinFaceBase64 == null) return null; + byte[] faceIconBytes = Base64.decode(skinFaceBase64, Base64.DEFAULT); + return BitmapFactory.decodeByteArray(faceIconBytes, 0, faceIconBytes.length); + } else { + if(mFaceCache == null) { + mFaceCache = BitmapFactory.decodeFile(skinFaceFile.getAbsolutePath()); + } } - byte[] faceIconBytes = Base64.decode(skinFaceBase64, Base64.DEFAULT); - return BitmapFactory.decodeByteArray(faceIconBytes, 0, faceIconBytes.length); + + return mFaceCache; + } + + public static Bitmap getSkinFace(String username) { + return BitmapFactory.decodeFile(getSkinFaceFile(username).getAbsolutePath()); + } + + private static File getSkinFaceFile(String username) { + return new File(Tools.DIR_CACHE, username + ".png"); } private static boolean accountExists(String username){