A reliable/fast way to know an APK file's api level

I googled quite a while and found the following way is the best:

If you have Android Studio installed, using the "Build > Analyze APK" menu command is indeed a convenient way to quickly determine the supported API level of an APK file. Here are the steps:

Open Android Studio.

Go to "Build" in the top menu.

Choose "Analyse APK..."

Navigate to and select the APK file you want to analyze.

Android Studio will display information about the APK, including the minimum and target API levels.

Surely if you don't have Android Studio installed, then this way cannot help.

Moq Tips 2 - check if a log message with a specific prefix/suffix and call a method with an object having a specific field value

  1. To check if a log message with a specific prefix is logged, you can use Moq's Verify method along with an appropriate assertion.
_logger.Verify(logger => logger.logInformation(
    It.Is<string>(s => s.StartsWith("specific prefix"))), Times.Once);
  1. To verify that a method is called with an object containing a specific property value, you can use Moq's It.Is<T> matcher along with a lambda expression. Here's an example:

    _mockObject.Verify(x => x.MyMethod(It.Is<MyObject>(
     obj => obj.PropertyValue == expectedPropertyValue)), Times.Once);
    
  2. Correctly returns null: Sometimes we need to set up a Moq mock to return null but cannot directly do it as Moq doesn't allow. Please check the following way that you should use:

_bookStoreAccountRepository.Setup(
    b => b.GetBookStoreAccountByUserName(It.IsAny<string>()))
    .Returns((BookStoreAccount)null);

The key is to use (BookStoreAccount)null to explicitly cast null to the expected return type.

我的新“玩具” - 电子墨水屏阅读器 BOYUE LikeBook S61

身为软件开发者,我工作时盯着屏幕,工作之余除了刷社交媒体就是看电子书,还是大大小小的屏幕。往往不等到休息时间,眼睛就干涩得不行。我不禁怀念起我那台多年前就不知道丢到哪里的老Kindle。还是要整一台e-ink 设备专门读书,而且一定得是安卓系统,这样我就能在墨水屏上用我最爱的 KOReader阅读器读书了。

预算不多,而且主要是看书,我的期望值并不高:屏幕不必大,CPU也不求多块,但存书的空间最好能大一点。

AliExpress 上一通搜索,这台BOYUE 阅读器吸引住我的眼球。

BOYUE LikeBook S61 6 inch 4核1.6G CPU 1G RAM 16G Storage NZ$ 102.97 运费 $4.25 再加上 15% 的GST,到手价才 $122.42。

这定然是老机器清仓甩卖。因为描述里写系统是Android 4.4,相当老了。但乐观的我想,应该总能找到第三方ROM刷机吧,于是乎就下单了。这次物流蛮给力,只等了十几天,我3月1日就收到货了。系统不是 4.4, 而是更老的 4.2.2。网上一通搜索,并没有找到合适的ROM刷机。于是乎拿到机器这几天,我只能因陋就简,在网上找能满足我需要的尚支持 Android 4.2.2 版本的软件。这个过程并不顺利,我甚至一度考虑别折腾了,要不干脆退货算了。然而在最初的挫折之后,后面却是越来越顺利。

经过一番调教之后,这台机器用起来已经相当顺手,甚至可以说是舒适了!

中间反复尝试的艰辛略去不提,今天这篇主要是分享一下我的成果, 如果能帮到也买了这台全新的老机器的网友,那我就再开心不过了。

  • 主阅读程序 koreader-v2023-06-1.apk
  • Launcher Simple.ink.launcher.apk
  • SSH server, SimpleSSHD-27.apk
  • Browser, com.UCMobile.intl_11.4.apk
  • File Manager es-file-explorer-4-2.apk
  • Mastodon client tusky.apk

抽时间我会将这些apk打个包扔我一台破VPS上供大家下载,毕竟找这些安装包花了我不少时间。

English Learning Memo 1

My boss sent a message in our office channel, which said she was WFH today, as "she have a bloke coming round to fix the garage door".

BLOKE is a new word to me. so I learned this word today.

Other learnings

  • "得不偿失" in English can be translated as "not worth the loss" or "the gains do not justify the losses."
  • "蒜苔" in English is "garlic scape" or simply "garlic shoots."
  • "In and out promotion" 广告术语中指的是一种快速进行的促销活动,通常是短期的、迅速产生效果的宣传推广。这可能包括限时折扣、特价促销等手段,旨在迅速吸引顾客。

Moq tips 1 - learn how to write unit tests from ChatGPT

When should I use mockObject.Reset() and when should I use mockObject.Invocations.Clear()?

In the context of using a mocking framework like Moq in C# for unit testing, the choice between mockObject.Reset() and mockObject.Invocations.Clear() depends on what you want to achieve.

  1. mockObject.Reset():

    • This is specific to the Moq library.
    • It resets the mock object, removing any setups or custom behavior you might have defined for that mock.
    • It does not clear recorded invocations; you can still access them after calling Reset().

    Example:

    var mock = new Mock<MyClass>();
    mock.Setup(x => x.MyMethod()).Returns("Original");
       
    // ... code using the mock ...
       
    // Reset the mock, removing setups
    mock.Reset();
       
    // Now, if you call the method, it won't use the previous setup
    var result = mock.Object.MyMethod();
    
  2. mockObject.Invocations.Clear():

    • This clears the recorded invocations on the mock object.
    • It doesn't affect setups or custom behavior. It just removes the history of invocations.
    • This can be useful when you want to verify interactions or check the number of invocations without interference from previous test runs.

    Example:

   var mock = new Mock<MyClass>();
   mock.Setup(x => x.MyMethod()).Returns("Original");
   
   // ... code using the mock ...
   
   // Clear recorded invocations
   mock.Invocations.Clear();
   
   // Now, if you verify invocations, it won't consider previous calls
   mock.Verify(x => x.MyMethod(), Times.Never());

In summary:

  • Use mockObject.Reset() when you want to clear setups and start fresh with the mock.
  • Use mockObject.Invocations.Clear() when you want to clear the history of invocations, but keep the existing setups and behaviors.

If I set up a method with the same parameters multiple times, the last setup will take effect, right?

In most mocking frameworks, including Moq for C#, the answer is YES. Each new setup for the same method and parameters overrides any previous setups.

Here's an example using Moq:


// Setting up the method with the same parameters but different returns
mock.Setup(x => x.MyMethod()).Returns("FirstSetup");
mock.Setup(x => x.MyMethod()).Returns("SecondSetup");

// Now, if you call the method, it will return "SecondSetup"
var result = mock.Object.MyMethod();