[Xiaomi Redmi Note 3 Guides, News, & Discussion] S0bes:
So, it's a known issue that custom kernel breaks read mode cause xiaomi didn't cover up that part in released source code.

But, all the kernels (almost all) supports kcal. That's technology that used for example in kernel adiutor app allowing you to change your display color. More explained here - https://xdaforums.com/android/software-hacking/dev-kcal-advanced-color-control-t3032080.

And that's the technology I used to bring back read mode in my xposed module here - https://xdaforums.com/redmi-note-3/themes/app-bring-read-mode-custom-kernels-t3648558

So, now I share the guide with you how to bring read mode on any MIUI 8/9 device with custom kernel that supports kcal.

You need to know how to decompile/recompile jar files.

framework.jar/miui/hareware/display/DisplayFeatureManager.smali

find

# instance fields

add bellow following lines

.field public blue:[Ljava/lang/String;

.field public count:I

.field level:I

.field line:Ljava/lang/String;

.field old_blue:Ljava/lang/String;

.field path:Ljava/lang/String;

.field rgb_old:[Ljava/lang/String;

.field toogle_state:Z

find

.method private constructor <init>()V
.locals 2

and change it to

.method private constructor <init>()V
.locals 4

.prologue
const/4 v3, 0x0

Two strings were added and locals 2 now locals 4.

Inside

.method private constructor <init>()V

find

return-void

and paste above

.line 19
const-string v0, " "

iput-object v0, p0, Lmiui/hareware/display/DisplayFeatureManager;->old_blue:Ljava/lang/String;

.line 21
const-string v0, "/sys/devices/platform/kcal_ctrl.0/kcal"

iput-object v0, p0, Lmiui/hareware/display/DisplayFeatureManager;->path:Ljava/lang/String;

.line 23
const/4 v0, 0x0

iput-object v0, p0, Lmiui/hareware/display/DisplayFeatureManager;->rgb_old:[Ljava/lang/String;

.line 24
iput v3, p0, Lmiui/hareware/display/DisplayFeatureManager;->level:I

.line 25
const/16 v0, 0x8

new-array v0, v0, [Ljava/lang/String;

const-string v1, "220"

aput-object v1, v0, v3

const/4 v1, 0x1

const-string v2, "205"

aput-object v2, v0, v1

const/4 v1, 0x2

const-string v2, "190"

aput-object v2, v0, v1

const/4 v1, 0x3

const-string v2, "175"

aput-object v2, v0, v1

const/4 v1, 0x4

const-string v2, "160"

aput-object v2, v0, v1

const/4 v1, 0x5

const-string v2, "145"

aput-object v2, v0, v1

const/4 v1, 0x6

const-string v2, "130"

aput-object v2, v0, v1

const/4 v1, 0x7

const-string v2, "125"

aput-object v2, v0, v1

iput-object v0, p0, Lmiui/hareware/display/DisplayFeatureManager;->blue:[Ljava/lang/String;

.line 27
iput v3, p0, Lmiui/hareware/display/DisplayFeatureManager;->count:I

now find

.method public setEyeCare(I)V

inside it find

return-void

and paste above it

invoke-virtual {p0, p1}, Lmiui/hareware/display/DisplayFeatureManager;->s0bes(I)V

now at the end of the smali file add following lines

.method public RMcontrol(ZLjava/lang/String;)V
.locals 9
.param p1, "z" # Z
.param p2, "b" # Ljava/lang/String;
.annotation system Ldalvik/annotation/Throws;
value = {
Ljava/io/FileNotFoundException;,
Ljava/io/IOException;
}
.end annotation

.prologue
const/4 v6, 0x1

.line 54
const/4 v5, 0x0

.line 55
:try_start_0
new-instance v1, Ljava/io/FileInputStream;

iget-object v4, p0, Lmiui/hareware/display/DisplayFeatureManager;->path:Ljava/lang/String;

invoke-direct {v1, v4}, Ljava/io/FileInputStream;-><init>(Ljava/lang/String;)V
:try_end_0
.catchall {:try_start_0 .. :try_end_0} :catchall_3

.line 56
.local v1, "fis":Ljava/io/InputStream;
:try_start_1
new-instance v2, Ljava/io/InputStreamReader;

const-string v4, "UTF-8"

invoke-static {v4}, Ljava/nio/charset/Charset;->forName(Ljava/lang/String;)Ljava/nio/charset/Charset;

move-result-object v4

invoke-direct {v2, v1, v4}, Ljava/io/InputStreamReader;-><init>(Ljava/io/InputStream;Ljava/nio/charset/Charset;)V
:try_end_1
.catchall {:try_start_1 .. :try_end_1} :catchall_2

.line 57
.local v2, "isr":Ljava/io/InputStreamReader;
:try_start_2
new-instance v0, Ljava/io/BufferedReader;

invoke-direct {v0, v2}, Ljava/io/BufferedReader;-><init>(Ljava/io/Reader;)V
:try_end_2
.catchall {:try_start_2 .. :try_end_2} :catchall_4

.line 60
.local v0, "br":Ljava/io/BufferedReader;
if-eqz p1, :cond_b

.line 61
:try_start_3
iget v4, p0, Lmiui/hareware/display/DisplayFeatureManager;->count:I

if-ge v4, v6, :cond_0

.line 62
iget v4, p0, Lmiui/hareware/display/DisplayFeatureManager;->count:I

add-int/lit8 v4, v4, 0x1

iput v4, p0, Lmiui/hareware/display/DisplayFeatureManager;->count:I

.line 63
:goto_0
invoke-virtual {v0}, Ljava/io/BufferedReader;->readLine()Ljava/lang/String;

move-result-object v4

iput-object v4, p0, Lmiui/hareware/display/DisplayFeatureManager;->line:Ljava/lang/String;

if-nez v4, :cond_5

.line 66
:cond_0
invoke-virtual {v0}, Ljava/io/BufferedReader;->close()V

.line 67
new-instance v4, Ljava/lang/StringBuilder;

iget-object v6, p0, Lmiui/hareware/display/DisplayFeatureManager;->rgb_old:[Ljava/lang/String;

const/4 v7, 0x0

aget-object v6, v6, v7

invoke-static {v6}, Ljava/lang/String;->valueOf(Ljava/lang/Object;)Ljava/lang/String;

move-result-object v6

invoke-direct {v4, v6}, Ljava/lang/StringBuilder;-><init>(Ljava/lang/String;)V

const-string v6, " "

invoke-virtual {v4, v6}, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder;

move-result-object v4

iget-object v6, p0, Lmiui/hareware/display/DisplayFeatureManager;->rgb_old:[Ljava/lang/String;

const/4 v7, 0x1

aget-object v6, v6, v7

invoke-virtual {v4, v6}, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder;

move-result-object v4

const-string v6, " "

invoke-virtual {v4, v6}, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder;

move-result-object v4

invoke-virtual {v4, p2}, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder;

move-result-object v4

invoke-virtual {v4}, Ljava/lang/StringBuilder;->toString()Ljava/lang/String;

move-result-object v3

.line 68
.local v3, "rgb":Ljava/lang/String;
iget-object v4, p0, Lmiui/hareware/display/DisplayFeatureManager;->path:Ljava/lang/String;

invoke-static {v4, v3}, Landroid/miui/Shell;->write(Ljava/lang/String;Ljava/lang/String;)Z
:try_end_3
.catchall {:try_start_3 .. :try_end_3} :catchall_0

.line 77
.end local v3 # "rgb":Ljava/lang/String;
:cond_1
:goto_1
if-eqz v0, :cond_2

:try_start_4
invoke-virtual {v0}, Ljava/io/BufferedReader;->close()V
:try_end_4
.catchall {:try_start_4 .. :try_end_4} :catchall_4

:cond_2
if-eqz v2, :cond_3

:try_start_5
invoke-virtual {v2}, Ljava/io/InputStreamReader;->close()V
:try_end_5
.catchall {:try_start_5 .. :try_end_5} :catchall_2

:cond_3
if-eqz v1, :cond_4

:try_start_6
invoke-virtual {v1}, Ljava/io/InputStream;->close()V
:try_end_6
.catchall {:try_start_6 .. :try_end_6} :catchall_3

.line 79
:cond_4
return-void

.line 64
:cond_5
:try_start_7
iget-object v4, p0, Lmiui/hareware/display/DisplayFeatureManager;->line:Ljava/lang/String;

const-string v6, " "

invoke-virtual {v4, v6}, Ljava/lang/String;->split(Ljava/lang/String;)[Ljava/lang/String;

move-result-object v4

iput-object v4, p0, Lmiui/hareware/display/DisplayFeatureManager;->rgb_old:[Ljava/lang/String;
:try_end_7
.catchall {:try_start_7 .. :try_end_7} :catchall_0

goto :goto_0

.line 77
:catchall_0
move-exception v4

if-eqz v0, :cond_6

:try_start_8
invoke-virtual {v0}, Ljava/io/BufferedReader;->close()V

:cond_6
throw v4
:try_end_8
.catchall {:try_start_8 .. :try_end_8} :catchall_1

:catchall_1
move-exception v5

move-object v8, v5

move-object v5, v4

move-object v4, v8

.end local v0 # "br":Ljava/io/BufferedReader;
:goto_2
if-nez v5, :cond_c

move-object v5, v4

:cond_7
:goto_3
if-eqz v2, :cond_8

:try_start_9
invoke-virtual {v2}, Ljava/io/InputStreamReader;->close()V

:cond_8
throw v5
:try_end_9
.catchall {:try_start_9 .. :try_end_9} :catchall_2

.end local v2 # "isr":Ljava/io/InputStreamReader;
:catchall_2
move-exception v4

if-nez v5, :cond_d

move-object v5, v4

:cond_9
:goto_4
if-eqz v1, :cond_a

:try_start_a
invoke-virtual {v1}, Ljava/io/InputStream;->close()V

:cond_a
throw v5
:try_end_a
.catchall {:try_start_a .. :try_end_a} :catchall_3

.end local v1 # "fis":Ljava/io/InputStream;
:catchall_3
move-exception v4

if-nez v5, :cond_e

:goto_5
throw v4

.line 71
.restart local v0 # "br":Ljava/io/BufferedReader;
.restart local v1 # "fis":Ljava/io/InputStream;
.restart local v2 # "isr":Ljava/io/InputStreamReader;
:cond_b
:try_start_b
iget-object v4, p0, Lmiui/hareware/display/DisplayFeatureManager;->rgb_old:[Ljava/lang/String;

if-eqz v4, :cond_1

.line 72
new-instance v4, Ljava/lang/StringBuilder;

iget-object v6, p0, Lmiui/hareware/display/DisplayFeatureManager;->rgb_old:[Ljava/lang/String;

const/4 v7, 0x0

aget-object v6, v6, v7

invoke-static {v6}, Ljava/lang/String;->valueOf(Ljava/lang/Object;)Ljava/lang/String;

move-result-object v6

invoke-direct {v4, v6}, Ljava/lang/StringBuilder;-><init>(Ljava/lang/String;)V

const-string v6, " "

invoke-virtual {v4, v6}, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder;

move-result-object v4

iget-object v6, p0, Lmiui/hareware/display/DisplayFeatureManager;->rgb_old:[Ljava/lang/String;

const/4 v7, 0x1

aget-object v6, v6, v7

invoke-virtual {v4, v6}, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder;

move-result-object v4

const-string v6, " "

invoke-virtual {v4, v6}, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder;

move-result-object v4

iget-object v6, p0, Lmiui/hareware/display/DisplayFeatureManager;->rgb_old:[Ljava/lang/String;

const/4 v7, 0x2

aget-object v6, v6, v7

invoke-virtual {v4, v6}, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder;

move-result-object v4

invoke-virtual {v4}, Ljava/lang/StringBuilder;->toString()Ljava/lang/String;

move-result-object v3

.line 73
.restart local v3 # "rgb":Ljava/lang/String;
iget-object v4, p0, Lmiui/hareware/display/DisplayFeatureManager;->path:Ljava/lang/String;

invoke-static {v4, v3}, Landroid/miui/Shell;->write(Ljava/lang/String;Ljava/lang/String;)Z
:try_end_b
.catchall {:try_start_b .. :try_end_b} :catchall_0

goto :goto_1

.line 77
.end local v0 # "br":Ljava/io/BufferedReader;
.end local v3 # "rgb":Ljava/lang/String;
:cond_c
if-eq v5, v4, :cond_7

:try_start_c
invoke-virtual {v5, v4}, Ljava/lang/Throwable;->addSuppressed(Ljava/lang/Throwable;)V
:try_end_c
.catchall {:try_start_c .. :try_end_c} :catchall_2

goto :goto_3

.end local v2 # "isr":Ljava/io/InputStreamReader;
:cond_d
if-eq v5, v4, :cond_9

:try_start_d
invoke-virtual {v5, v4}, Ljava/lang/Throwable;->addSuppressed(Ljava/lang/Throwable;)V
:try_end_d
.catchall {:try_start_d .. :try_end_d} :catchall_3

goto :goto_4

.end local v1 # "fis":Ljava/io/InputStream;
:cond_e
if-eq v5, v4, :cond_f

invoke-virtual {v5, v4}, Ljava/lang/Throwable;->addSuppressed(Ljava/lang/Throwable;)V

:cond_f
move-object v4, v5

goto :goto_5

.restart local v1 # "fis":Ljava/io/InputStream;
.restart local v2 # "isr":Ljava/io/InputStreamReader;
:catchall_4
move-exception v4

goto :goto_2
.end method

.method public s0bes(I)V
.locals 3
.param p1, "param" # I
.annotation system Ldalvik/annotation/Throws;
value = {
Ljava/lang/Throwable;
}
.end annotation

.prologue
const/4 v2, 0x0

.line 31
if-eqz p1, :cond_0

.line 32
iput p1, p0, Lmiui/hareware/display/DisplayFeatureManager;->level:I

.line 33
const/4 v0, 0x1

iget-object v1, p0, Lmiui/hareware/display/DisplayFeatureManager;->blue:[Ljava/lang/String;

iget v2, p0, Lmiui/hareware/display/DisplayFeatureManager;->level:I

add-int/lit8 v2, v2, -0x1

aget-object v1, v1, v2

invoke-virtual {p0, v0, v1}, Lmiui/hareware/display/DisplayFeatureManager;->RMcontrol(ZLjava/lang/String;)V

.line 38
:goto_0
return-void

.line 35
:cond_0
iput v2, p0, Lmiui/hareware/display/DisplayFeatureManager;->level:I

.line 36
iget-object v0, p0, Lmiui/hareware/display/DisplayFeatureManager;->blue:[Ljava/lang/String;

iget v1, p0, Lmiui/hareware/display/DisplayFeatureManager;->level:I

aget-object v0, v0, v1

invoke-virtual {p0, v2, v0}, Lmiui/hareware/display/DisplayFeatureManager;->RMcontrol(ZLjava/lang/String;)V

goto :goto_0
.end method

I have already tested that approach here - https://xdaforums.com/showpost.php?p=73728907&postcount=734 and as people reported it works.

[MENTION=4188806]Orochixxx[/MENTION], [MENTION=5863451]JamFlux[/MENTION] , you can use the guide to fix the issue in your MIUI9 ports.

UPDATE 03.12.2017

If the hack doesn't work anymore

it's easy to fix

The instruction is the same except the path. Now it's in services.jar/com/android/server/display/DisplayFeatureManager.smali

And after you paste new code you should replace (ctrl+H)

Lmiui/hareware/display/DisplayFeatureManager

to

Lcom/android/server/display/DisplayFeatureManager