Skip to main content

How I upgraded the Lenovo 4 10 Plus to Android Pie/9 and passed SafetyNet

Before you do anything listed below Please Please Please understand that if done incorrectly you will break your tablet and make it unusable. It is also important to note that not all devices with this name is the same, I have only tested this on the X704L but it would probably work the same on X704F as well, do not try this on any other tablets without first verifying with the creators that it works on your tablet.

I am writing this guide mainly as a reference for my future self so it will be on a level where you already have to know the basics of these things. If you don’t understand the steps in my guide, please head over to the XDA thread instead and have a look at their instructions for installing the OS.

I have made backups of all the files I mention in this guide as I know this type of thing tends to disappear after a few years. If any of the files / sites I link to has disappeared let me know and I will share these files. I will only share my copy of the files once the official ones are gone as I want the creators/maintainers to get the credit they deserve. By going the official route you also make sure you always get the latest versions.

The following are the steps I followed when I did it earlier this week, please note that newer versions might require different steps.

I started by installing Minimal ADB and Fastboot on my computer, this was to allow me to send commands to the tablet easier.

Next I enabled developer options on the tablet and enabled OEM unlock and USB debugging, I connected the tablet to the computer and ran the following command

adb reboot bootloader

This put the tablet in the bootloader mode where you only see a Lenovo logo. Once I saw the logo I ran another command. Keep in mind that this command will factory reset the device.

fastboot oem unlock-go

As the device is now factory reset I had to enable USB debugging again and after that it was time to start downloading the stuff I was going to install.

First off was TWRP. One thing to keep in mind here is that the TWRP states that it is for X704F and not X704L. The version I used worked fine on the L but make sure to verify that newer versions do this as well before flashing. The version I used was twrp-3.3.1-0-X704F.img.

Next it was time to download the ROM, when I write this there is only one Pie ROM available for the tablet and that is an Unofficial version of Lineage OS 16 maintained by yener90. I used the version that was released 20190609

Since Lineage comes without any Google software I also downloaded the Micro GApps pack from The Open GApps Project. Make sure to check Arm64, Android 9 .0 and Micro before hitting download.

The last thing I needed to download for now was Magisk. I downloaded the latest stable version which at the time I write this is 19.3. When I was at it I also downloaded the Magisk Manager APK as that would be required later.

Once everything was downloaded I put a copy of everything both in the root of the internal storage and at the root of an external SD card. Then I ran the command

adb reboot bootloader

Once again, remember that this will only show you the Lenovo logo, when I saw it I ran the command

fastboot flash recovery twrp-3.3.1-0-X704F.img

Once flashed I used the volume buttons to navigate the menu at the top of the screen, wen it said Recovery Mode I used the power button to select it. This booted TWRP where I selected that I want to write to system.

The first thing I did now was make a backup of everything to an external SD card so I always have a way back if I want to.

Now it was time to clean out the old Android, hit wipe but don´t use the slide, instead hit format data and type yes. Once done, hit the back button and go to advanced wipe. Check Dalvik/ART Cache, System and Cache then swipe to wipe them. Go back to the main menu and reboot into recovery. If it asks if I want to install a TWRP app I always say no.

Once back in TWRP I began by flashing the ROM, then GAPPS and lastly Magisk, then I rebooted into system. Once again say no if it asks for installing a TWRP app.

Now I went through the setup of the tablet and once done I installed the Magisk Manager apk that I downloaded earlier.

Insie Magisk manager I headed to the settings and made sure Magisk Hide was enabled and also enabled that Magisk manager itself should be hidden (this is done by regenerating a package with a random name, cool!)

I headed to Google Play and installed the app “Termux”, in my case it was version 0.72.

Then I went back to magisk manager and installed the module “Busybox for Android NDK version 1.30.1. When it was installed I rebooted the device.

Now I headed over to XDA again and downloaded “MagiskHide Props Config” version 4.0.3. Then I went back to Magisk manager and installed this as a new module and rebooted the device.

When the tablet was back up I opened up Termux and typed su and hit enter, gave it root permissions and then typed props. I followed the menu that was started like this
Edit device fingerprint -> pick a certified fingerprint -> Lenovo -> Lenovo K6 Note (7.0) -> yes for reboot.

When the device was back up I ran the SafetyNet check inside Magisk Manager and saw that everything was green but when I tried to search for Netflix on Google Play it still didn’t show up. To fix this I headed in to the tablets settings, then apps, show system apps. Then clear all data for Google Play Services and Google Play. Now I rebooted the device one final time and then it was done.

The tablet is now running Android Pie and passes SafetyNet. One last thing to keep in mind is that SafetyNet is always updated so this will probably break in the future and then Magisk will probably update to fix it again etc etc. If always passing SafetyNet is really important to you I recommend looking for a new tablet with official updates.

Share

Stickers!

Everyone loves stickers, right?

At least I do, that’s why I had some Booksonic stickers made for myself last week and since I know there are some people out there that love Booksonic as much as I do I bought a few extra.

They are vinyl stickers and the size is roughly 3.5 x 3.5 cm.

If you are interested in getting some stickers let me know below or on [email protected] Since this is something I am doing for fun and not profit I’m setting the price to pay what you want + shipping. Shipping cost is $4.

Share
Booksonic app giveaway

The Booksonic app stopped working for almost ten hours today due to bug

First of all, I want to say that I am very sorry to all of you who have been unable to use the Booksonic app today.

Second I want to get in to a bit of what actually happened as well as give a promise that I will make sure it can never happen again.

Ok, so the reason that you haven’t been able to connect to your server today is due to two things. Today at 08:05 Swedish time booksonic.org went down. This was due to a break in the fibre cable leading to the server center that is hosting it.

The second and more important thing is why this caused you not to be able to connect to your own servers. 

First of all I want to make one thing very clear, Booksonic is a selfhosted server and as such this should not happen if my servers go down, that is very important to me.

None of your data between the server and app is ever routed through booksonic.org and will never be so. That said, there are two times that Booksonic connects to my servers. One is when you send me a log file, the second is when the app checks if it has an internet connection and that’s where the problem was.

The app determines if you have an internet connection or not by checking if it can reach booksonic.org. if it can’t, it is supposed to give you a message about it and then move on. The reason this is checking my servers instead of your own booksonic server is so that it can let you know if the problem is that your booksonic server is down or that your internet is down.

What this means is that when booksonic.org went down today all that should have happened is that you should have seen a message in your app letting you know that you don’t have an internet connection but since you actually did you should have been able to use the app just fine anyway, this however  is not what happened. It turns out there is a bug in the code that checks the internet connection. 

While I haven’t been able to verify this yet as I don’t have access to a computer at the moment my guess is that the reason it messes up is because you actually got a connection response (booksonic.org is behind cloudflare) just not the one it was expecting.

This bug is now my highest priority and I will make sure that a fix for it is found and pushed to GitHub and the Booksonic beta channel (sign up on the Google play page if you are interested) before the end of the week. If for some reason I am unable to get a fix for it working before then I will temporary disable this internet checking feature until I am able to find a fix because the fact that your apps stop working when my servers go offline is simply unacceptable to me.

Update 28/4:

After running some tests I have to admit that my first guess about what was messing up the connection was wrong, it was not the internet check in the app that was buggy, it was the version check on the server.

I have released a new version of the server where this is fixed and since I was releasing a new version of the server any way I also fixed the bug where the covers would not stretch to fit.
The new version of the server is called 1.1 and can be downloaded at booksonic.org

Share

Deleting domains from your pihole history database

For a while I have had an error in my home automation system that caused my hub to do hundreds of request to popeen.com every night. Today I finally sat down and fixed it and once it was fixed I also wanted to purge all the lines from the database so it doesn’t screw up my statistics anymore. Doing so was fairly simple but took me a few minutes to figure out so I decided to write it down here. That way I can come back here whenever I need to do it again and hopefully help someone else out at the same time.

First you SSH into the server running pihole, I am assuming you know how to do that already and if not there are plenty of guides for it if you google it so I won’t cover it here.

The first thing we need to do is shutdown pihole so we are free to modify the database, to shut down pihole run the command

sudo service pihole-FTL stop

Then we need to access the database, we do so by running the command

sudo sqlite3 /etc/pihole/pihole-FTL.db

ok, now it’s time to delete the domain, we do this by running this command, replace popeen.com with the domain you want to purge.

delete from queries where domain = "popeen.com";

when you have purged all the domains you want we exit the database by hitting CTRL + C

and lastly we start pihole up again by running

sudo service pihole-FTL start
Share

Building Powershell GUIs that won’t freeze when you use them

A few days ago I wrote about how important I think it is that you build a GUI for your scripts if they are to be used by anoyone else.

If you have ever built a GUI using Powershell however, you know there is a problem with it that I didn’t mention, that is, whenever your script is actually doing anything the GUI will freeze and windows will tell you it isn’t responding. This is not good as most users will then try to close it and try again. We don’t want that.

The reason this happens is because you are running your form (GUI) and logic in the same thread, something you should never do, problem is, Powershells support for multithreading is limited at best.

In the last post I also talked about my module EasyGUI and mentioned that there are features I wouldnt go in to in that post, one of those features is an easy way to use threads.

There are two ways to use threads in EasyGUI, I go through both of them below as well as a tip on how I prefer to use them.

Method 1.

Passing in a scriptblock to the thread, here I am creating it on the fly but you could also store the scriptblock in a variable and pass that to the function instead

New-Thread {
    0..60|Foreach-Object{
        $SYNC.myLabel.Text = $_
    }
}

Method 2.

You could also write the code for the thread in a separate script file and then pass that to the New-Thread function like this

New-Thread "D:\Program\Powershell\myThread.ps1"

One thing to be aware of is that the threads will start running emediatly when you create them. Often you might not want that. What I usually do is create the threads inside a scriptblock that I store in a variable, then when I need the tread to run I run that scriptblock. That would look something like this.

$myThread = {
    New-Thread {
        0...60|Foreach-Object{
            $SYNC.myLabel.Text = $_
        }
    }
}

#Now it's time to run the thread, simply type the & sign and then the variable containing the scriptblock
&$myThread

$SYNC ? Where did that come from?

Noticed that did you?

This is a variable that’s automatically created when you initialize the EasyGUI module. It’s a hashtable that’s synced between all threads so you can communicate between them. In the examples you see that I am using $SYNC.myLabel. This is created in the GUI like this.

$SYNC.myLabel = New-Label @{
    Location = "15, 15"
}

or like this

$myLabel = New-Label @{
    Location = "15, 15"
}
$SYNC.myLabel = $myLabel

If you want to see a complete example of a GUI script with threading implemented there is an example availiable in the Easy GUI repository.

Share

Booksonic Bridge Preview

As part of communicating more what happens with the Booksonic project I thought it might be a good idea to show what the Bridge will look like.
Important to know is that most parts of the bridge currently doesn’t have an interface but as they are created I’ll add them to this post.

If you have any suggestions or ideas for improvements to the design let me know in a comment here, at reddit.com/r/booksonic or at [email protected]

Share

Writing Powershell GUIs the easy way

One of the most important tools for any IT professional or service desk technician that works in a Windows environment is without a doubt Powershell. Not only is it extremely powerful but it is also very fun to work with if you ask me.

One of the great features of Powershell that I feel doesn’t get enough love from the Powershell community is the ability to write scripts with graphical user interfaces. Yeah, yeah, I know, you want to be able to do a quick change in the script and then rerun it inside ISE and anyone that doesn’t know how to use a console shouldn’t be in IT anyway, right? Wrong!

It is my firm belief that a clear and easy to use interface is just as important as the logic itself when you write a script that is going to be used by someone else. For most people, that means the interface needs to be graphical. I base this belief on having worked in an IT department at a large company for several years as well as maintained the Booksonic project since the start in late 2015. If you want to change my mind, feel free to try and do so in the comments below.

Now with that out of the way I will stop trying to convince you about writing user interfaces for your scripts, the fact that you are reading this post probably means that you are already doing it or thinking about doing it. Instead I am going to focus on how to do it in a way so the code is easy to read and maintain even once you start writing more complex UIs.

When I first started writing powershell I noticed that most examples of people writing powershell UIs get really messy real fast.

A typical example you may find online looks something like this

Add-Type -AssemblyName System.Windows.Forms
Add-Type -Name Window -Namespace Console -MemberDefinition '
        [DllImport("Kernel32.dll")]
        public static extern IntPtr GetConsoleWindow();     
        [DllImport("user32.dll")]
        public static extern bool ShowWindow(IntPtr hWnd, Int32 nCmdShow);

[Console.Window]::ShowWindow([Console.Window]::GetConsoleWindow(), 0)       '

$font = New-Object System.Drawing.Font("Times New Roman",24,[System.Drawing.FontStyle]::Bold)

$label = New-Object System.Windows.Forms.Label
$label.Cursor = [System.Windows.Forms.Cursors]::Hand
$label.Text = "Click me to open popeen.com" 
$label.BackColor = "Transparent"
$label.ForeColor = "Blue" 
$label.AutoSize = $true
$label.Location.X = 15
$label.Location.Y = 15
$label.Add_Click = { Start-Process -FilePath iexplore  -ArgumentList "https://popeen.com" }

$form = New-Object system.Windows.Forms.Form
$form.Width = 600
$form.Height = 200
$form.Text = "Example form"
$form.Font = $font
$form.Controls.Add($label)
$form.ShowDialog() 

Now functionally speaking there is nothing wrong with that script and in fact it may not look that bad either but remember, all we have done is created a window and added one label to it. Imagine how cluttered this would become once you started doing some more advanced UIs. A better way to write the above that I have actually never seen anyone use other than me and some of my colleages would be using -Properties like this.

Add-Type -AssemblyName System.Windows.Forms
Add-Type -Name Window -Namespace Console -MemberDefinition '
        [DllImport("Kernel32.dll")]
        public static extern IntPtr GetConsoleWindow();     
        [DllImport("user32.dll")]
        public static extern bool ShowWindow(IntPtr hWnd, Int32 nCmdShow);

[Console.Window]::ShowWindow([Console.Window]::GetConsoleWindow(), 0)

$label = New-Object System.Windows.Forms.Label -Properties @{
    Cursor = [System.Windows.Forms.Cursors]::Hand
    Text = "Click me to open popeen.com" 
    BackColor = "Transparent"
    ForeColor = "Blue"
    AutoSize = $true
    Location = "15, 15"
    Add_Click = { Start-Process -FilePath iexplore  -ArgumentList "https://popeen.com" }
}

$form = New-Object system.Windows.Forms.Form -Properties @{
    Size = "600, 200"
    Text = "Example form"
    Font = New-Object System.Drawing.Font("Times New Roman", 24, [System.Drawing.FontStyle]::Bold)
}
$form.Controls.Add($label)
$form.ShowDialog() 

While this takes up about the same space it looks much better right? This way a quick glance at the code gives you a much better understanding of what it is you are looking at.

If you choose to stop reading here and start writing your UIs in this way I beleive you will have a much easier time maintaining that script then you had before. However, I have taken it a step further in my scripts.

When I write a script I use a specific framework that makes the code even quicker to read and also includes some other nice features that I won’t go in to in this post but might make future posts about. One of the most important parts of this framework is a module I call EasyGUI and that you can download at https://gitlab.com/Popeen/EasyGUI

This module builds on the second example above and simplifies it even more. It also includes some other cool stuff that I also won’t go in to here but again, might make another post about. If we decided to use EasyGUI to write the example above it would look like this

Import-Module EasyGUI

Initialize-EasyGUI
Hide-Console

$form = New-Form @{
    Size = "600, 200"
    Text = "Example form"
    Font = New-Font -Font "Times New Roman" -Size 24 -Style $FONTSTYLE.Bold
}

$label = New-Label @{
    Cursor = $CURSOR.Hand
    Text = "Click me to open popeen.com" 
    BackColor = "Transparent"
    ForeColor = "Blue"
    AutoSize = $true
    Location = "15, 15"
    Add_Click = { Start-Process -FilePath iexplore  -ArgumentList "https://popeen.com" }
}

$form.Controls.Add($label)

Show-Form $form
Stop-Console 

I dont know about you but I find that to be much more readable then the first example we looked at, especially when you are working with a lot more then just a label.

It should be noted that not every forms object is in EasyGUI yet as I add them when I need them but adding them yourself should be very easy even for someone new to Powershell and if not just post a comment below and let me know what object you would like added.

I would love to hear your thoughts on this, is it something you would ever use or do you think I’m just talking rubbish when I say that UIs are this important or that a simple module like this can make it a lot more quick, fun and easy to code and maintain UIs.

Share

Booksonic FAQ

Last updated: July 30, 2019

Here I try to answer the most common questions I get regarding Booksonic. Depending on what the problem you are experiencing is the answers may not always apply to you. If the answer doesn’t help you or you have a problem that is not mentioned here do the following

  • Restart the app
  • Do the thing that fails
  • Go to the main screen of the app
  • Tap the dots at the top right
  • Tap “Send Log”
  • Enter a description of the problem and then send it to me, I will get back to you as soon as I can.

Another great resource for getting help with Booksonic is to go to the Booksonic Reddit and ask the question there. You can find it at https://reddit.com/r/booksonic


The app is just showing white and then crashes when I open it

This can sometimes happen if you dont have a profilepicture set on the server.
Go to the server in the browser and then Settings -> Personal then select a Profile/Personal image and click save.
There will be a fix for this in a later version of the app.


I can’t connect to the server outside of my network

Make sure that you have portforwarded the port you are using in your router. The default port is 4040. Also make sure that you are specifying the port when you try to go to the server. It should look something like this http(s)://example.com:4040


I can connect to the server in the browser but not in the app

Make sure that you enter http:// or https:// at the beginning of the adress and :4040 at the end. If you are using docker or tomcat, make sure to also include /booksonic at the end.


The app keeps crashing when I do X, please help

To be able to help you I need to see the log file. See the list at the top of this post for instructions on how to send me one.


The server sais “Folder not found” when I try to use a network location

This is due to how windows handles permissions. I have posted instructions on how to fix it at https://popeen.com/2016/05/27/using-a-network-shared-folder-in-booksonic/


Casting to Chromecast fails

This will happen if you use a self signed certificate as Chromecast does not support those. There is a workaround for it in the app that you can enable. Go to Settings -> Playback and enable Use device as a proxy, this should fix your problem.


What is the difference between cache and permanent cache?

Files that are cached by Booksonic will normally be automatically removed to make space for newer files once you have reached your cache limit. If you download them using permanent cache they will never be deleted automatically.


When I try to reset my password it says reCaptcha v1 is shut down, can I still reset it?

To reset your password do the following

  • Log on to the machine hosting the server
  • Stop the server, verify that you can’t reach it in the browser
  • use notepad to open c:\booksonic\db\booksonic.script, make sure that you set notepad to Any file or you won’t see it.
  • Press CTRL + F and search for INSERT INTO USER VALUES
  • After your username you will see enc:lots of numbers
  • Replace all the numbers that are before the ‘ sign with 626f6f6b736f6e6963
  • Save the file and close notepad
  • Start the server

You can now sign in with the password booksonic, make sure the first thing you do is change your password.

If you are running it on a Linux machine the file is probably located at /var/booksonic/db/booksonic.script


I am getting the message <UNKNOWN SSID> when I try to enter SSID in server settings

There was a change in a recent version of Android that requires apps to have location permission before they can see the name of the SSID you are connected to. In the future Booksonic will ask for this permission but for now you have to give it manually from your phone’s settings menu.

The settings menu can look a bit different depending on your phone but it should be something like this, settings -> apps -> Booksonic -> permissions. Then enable the location permission. Go back one step and force close Booksonic.

Now reopen Booksonic and you should be able to get the SSID.


Do you plan to release an iOS version of Booksonic or would you consider it?

No I don’t plan on creating an iOS version and I will most likely never change my mind regarding this. However, I am working on a new server that will have an HTML5 player that should work just as good on iOS as on Android.

In the meantime you can use any iOS app that was created for Subsonic to connect to your Booksonic server. Or you can use webapps like Jamstash or Aurial. These will work just fine for playback but you won’t get any book descriptions or narrator info.


Is Booksonic open-source?

Yes! Booksonic is indeed open source. The server is a fork of the Subsonic server and the Android app is a fork of the DSub app.
You can find the source code for Booksonic at https://github.com/popeen


I have a great idea for a feature, how do I contact you about it?

You can send it to my email at [email protected], open an issue at https://github.com/popeen/popeens-dsub or post it on https://reddit.com/r/booksonic
While I might sometimes be a bit inactive in posting on GitHub or Reddit I always keep up to date with what is posted.

If you know how to code and want to implement the feature yourself, go for it. Once you are done, send me a pull request on GitHub and as long as the feature doesn’t break compatibility with regular Subsonic servers I will most likely accept it.

Share

Using a network shared folder in Booksonic

I recently got a  question regarding using a network shared folder in Booksonic so I thought it would be a great idea to show how you can do this.

  1. Press the windows button and R at the same time
  2. Type services.msc and hit enter
  3. Look for the service called Subsonic, rightclick it anc click on properties
  4. Go to Log On and make sure the checkbox for This account is checked then enter the login information for an account that has access to the shared folder.
  5. Hit ok and then rightclick the Subsonic service and restart it.

Now you should be able to use your network share within Booksonic without problems.

 

UPDATE:

Obs, keep in mind that you can’t use a mapped location, you need to use the full path, as an example mine is \\PopeensDataServer\D\Audiobooks or \\192.168.1.4\D\Audiobooks

Share

Booksonic server is out of BETA. I celebrate with an app giveaway

Last night I released the first full release of the Booksonic server. So whats new in this new Booksonic server? Well check out the changelog

* m4b files are now supported out of the box!
* The server is installed as Booksonic instead of as Subsonic
* Book descriptions and narrators are shown in the web GUI
* Music only features has been hidden in the web GUI, they are still there and will work fine if you use them in other apps.
* Design tweaks
* Bugfixes
* The API has been updated to show if the server is up to date.

But it’s not only the server that is getting an update, so is the Android app. A few minutes ago I uploaded a new version of it to Google Play and it should be live in a couple of hours is live. Here’s the changelog for that.

* The app will tell you if the server is outdated
* If app is in Swedish it will look at boktipset.se before checking Google Books if the server has no book description
* Added a classic theme to bring back the old Booksonic design
* Design tweaks to drawer (sidebar)
* Sleeptimer will reset the counter if you shake the phone
* Server and account info can optionally be included in import/export
* Bugfixes

To celebrate the first none beta version of Booksonic I have decided to have a giveaway where the 10 first people to comment on this post will get the app for free on Google Play. To get the app you need to enter a valid email when you comment so I have somewhere to contact you, this email will not be published as long as you only enter it in the email field.

As usual if you have any questions/suggestions/bugreports regarding the new versions of Booksonic you are more then welcome to submit them to the issue trackers at GitHub. Here for the server and here for the app, or as a comment on this blog.

UPDATE:

No codes left but you can still get the app for only $3 at Google Play

Share