/*
standard MessageDigest algorithms:
MD5
SHA-1
SHA-256
*/
private String getCertificateFingerprint(Context mContext, String algorithm, String packageName) {
PackageManager pm = mContext.getPackageManager();
int flags = PackageManager.GET_SIGNATURES;
PackageInfo packageInfo = null;
try {
packageInfo = pm.getPackageInfo(packageName, flags);
} catch (PackageManager.NameNotFoundException e) {
e.printStackTrace();
}
if (packageInfo == null)
return null;
Signature[] signatures = packageInfo.signatures;
//此处我直接默认只有一个签名
byte[] cert = signatures[0].toByteArray();
InputStream input = new ByteArrayInputStream(cert);
CertificateFactory cf = null;
try {
cf = CertificateFactory.getInstance("X509");
} catch (CertificateException e) {
e.printStackTrace();
}
if (cf == null)
return null;
X509Certificate c = null;
try {
c = (X509Certificate) cf.generateCertificate(input);
} catch (CertificateException e) {
e.printStackTrace();
}
if (c==null)
return null;
String hexString = null;
try {
MessageDigest md = MessageDigest.getInstance(algorithm);
byte[] publicKey = md.digest(c.getEncoded());
hexString = byte2HexFormatted(publicKey);
} catch (NoSuchAlgorithmException e1) {
e1.printStackTrace();
} catch (CertificateEncodingException e) {
e.printStackTrace();
}
return hexString;
}
public static String byte2HexFormatted(byte[] arr) {
StringBuilder str = new StringBuilder(arr.length * 2);
for (int i = 0; i < arr.length; i++) {
String h = Integer.toHexString(arr[i]);
int l = h.length();
if (l == 1) h = "0" + h;
if (l > 2) h = h.substring(l - 2, l);
str.append(h.toUpperCase());
if (i < (arr.length - 1)) str.append(':');
}
return str.toString();
}
- 10月 01 週二 201911:24
Certificate
- 7月 19 週五 201910:45
Android View.getDrawingCache() is deprecated in Android API 28
interface onScreenShotFinishedListener
{
void onScreenShotFinished(@Nullable Bitmap pBitmap);
}
void screenShot(@NonNull Window window,@NonNull View pView, @NonNull onScreenShotFinishedListener pListener)
{
Rect tRect = calcViewRect(pView);
if (Build.VERSION.SDK_INT > Build.VERSION_CODES.O)
{
Bitmap tBitmap = Bitmap.createBitmap(tRect.width(), tRect.height(), Bitmap.Config.ARGB_8888, true);
try
{
PixelCopy.request(window, tRect, tBitmap, new PixelCopy.OnPixelCopyFinishedListener()
{
@Override
public void onPixelCopyFinished(int copyResult)
{
if (PixelCopy.SUCCESS == copyResult)
{
pListener.onScreenShotFinished(tBitmap);
}
else
{
pListener.onScreenShotFinished(null);
}
}
}, new Handler(Looper.getMainLooper()));
}
catch (Exception e)
{
e.printStackTrace();
pListener.onScreenShotFinished(null);
}
}
else
{
pView.setDrawingCacheEnabled(true);
try
{
Bitmap tBitmap = Bitmap.createBitmap(pView.getDrawingCache());
pListener.onScreenShotFinished(tBitmap);
}
catch (Exception e)
{
e.printStackTrace();
pListener.onScreenShotFinished(null);
}
finally
{
pView.setDrawingCacheEnabled(false);
}
}
}
private Rect calcViewRect(View pTargetView)
{
int[] location = new int[2];
pTargetView.getLocationOnScreen(location);
Rect tRect = new Rect(location[0],
location[1],
location[0] + pTargetView.getWidth(),
location[1] + pTargetView.getHeight());
return tRect;
}
- 7月 17 週三 201909:54
Android 個資遮蔽setTransformationMethod
TextView.setTransformationMethod(new PersonalCapitalTransformationMethod(5, 12, '*'));
class PersonalCapitalTransformationMethod extends PasswordTransformationMethod
{
private int m_Begin;
private int m_End;
private char m_Replacement;
public PersonalCapitalTransformationMethod(int pBegin, int pEnd, char pReplacement)
{
super();
m_Begin = pBegin;
m_End = pEnd;
m_Replacement = pReplacement;
}
@Override
public CharSequence getTransformation(CharSequence pSource, View pView)
{
return new PersonalCapitalCharSequence(pSource);
}
private class PersonalCapitalCharSequence implements CharSequence
{
private CharSequence m_Source;
public PersonalCapitalCharSequence(CharSequence pSource)
{
m_Source = pSource;
}
- 7月 11 週四 201910:13
Android 傅立葉級數Reconnect Interval
public class ReconnectInterval
{
private AtomicInteger m_AtomicCount = new AtomicInteger(0);
private int m_Max = 12;
private double A = Math.sqrt(5) / 5;
private double B = (1 + Math.sqrt(5)) / 2;
private double C = (1 - Math.sqrt(5)) / 2;
long getInterval()
{
int nValue = m_AtomicCount.incrementAndGet();
if (nValue / m_Max > 0)
{
nValue = m_Max;
}
long lFibonacci = fibonacci(nValue);
return lFibonacci * 1000;
}
void reset()
{
m_AtomicCount.set(0);
}
long getRetryCount()
{
return m_AtomicCount.get();
}
- 7月 11 週四 201909:59
Android Gesture計算角度
double dbAngle = Math.abs(
180 * Math.atan2((e1.getY() - e2.getY()), (e2.getX() - e1.getX())) / Math.PI);
if (dbAngle > 45 && dbAngle < 135){
//TODO SOME THINGS
}
else
{
//TODO SOME THINGS
}
- 7月 10 週三 201916:50
StackTraceElement
StringBuilder tStringBuilder = new StringBuilder();
StackTraceElement[] tStackTraceElement = new Throwable().getStackTrace();
int nStacksLen = tStackTraceElement.length;
if (nStacksLen > 0)
{
tStringBuilder.append("class: ").append(tStackTraceElement[1].getClassName())
.append("; method: ").append(tStackTraceElement[1].getMethodName())
.append("; number: ").append(tStackTraceElement[1].getLineNumber());
}
- 7月 02 週二 201915:15
Android OKHttp 進階設定 MaxRequests ConnectionPool ThreadPool
//執行緒池
Dispatcher dispatcher = new Dispatcher(
new ThreadPoolExecutor(0, Integer.MAX_VALUE, 60, TimeUnit.SECONDS,
new SynchronousQueue<Runnable>(),
Util.threadFactory("OkHttp Dispatcher", false)));
//最大的請求數量 def 64
dispatcher.setMaxRequests(64);
//主機同一個時間,最大的請求數量 def 5
dispatcher.setMaxRequestsPerHost(5);
//連線池
ConnectionPool connectionPool = new ConnectionPool(5, 5, TimeUnit.MINUTES);
OkHttpClient client = builder
.dispatcher(dispatcher)
.connectionPool(connectionPool)
.connectTimeout(5, TimeUnit.SECONDS)
.writeTimeout(5, TimeUnit.SECONDS)
.readTimeout(5, TimeUnit.SECONDS)
.followRedirects(true)
.retryOnConnectionFailure(false)
.build();
- 7月 02 週二 201915:14
Android Migrate to Androidx 之後 layout_behavior
layout_behavior="com.google.android.material.bottomsheet.BottomSheetBehavior"
layout_behavior="com.google.android.material.appbar.AppBarLayout$ScrollingViewBehavior"
- 7月 01 週一 201913:56
Android RecycleView Scroll Control
RecyclerView 提供相當多種控制Scroll的方法
1.scrollBy(int x, int y)
2.scrollTo(int x, int y)
3.scrollToPosition(int position)
4.smoothScrollBy(int dx, int dy)
5.smoothScrollBy(int dx, int dy, Interpolator interpolator)
6.smoothScrollToPosition(int position)
其中ScrollToPosition與smoothScrollToPosition,
都只能讓指定的Position顯示在畫面上而具體位置在哪則無法控制。
若使用LinearLayoutManager的
scrollToPositionWithOffset(int position, int offset)
這個方法則解決了上面的問題其中若將offset設定為0則此position將置頂,
若為100則positionru將會停在距離上方100Pixel的位置。
- 7月 01 週一 201909:53
Android解決AppBarLayout無法滑動問題
AppBarLayout無法滑動時可透過設定DragCallback解決此問題
CoordinatorLayout.LayoutParams tParams = (CoordinatorLayout.LayoutParams) m_AppBarLayout.getLayoutParams();
AppBarLayout.Behavior tBehavior = new AppBarLayout.Behavior();
tBehavior.setDragCallback(new AppBarLayout.Behavior.DragCallback()
{
@Override
public boolean canDrag(@NonNull AppBarLayout appBarLayout)
{
return true;
}
});
tParams.setBehavior(tBehavior);
