1 /* 2 * Copyright (C) 2017 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.settings.intelligence.search.sitemap; 18 19 import android.content.Context; 20 import android.database.Cursor; 21 import android.database.sqlite.SQLiteDatabase; 22 import androidx.annotation.WorkerThread; 23 import android.text.TextUtils; 24 import android.util.Log; 25 26 import com.android.settings.intelligence.search.indexing.IndexDatabaseHelper; 27 import com.android.settings.intelligence.search.indexing.IndexDatabaseHelper.SiteMapColumns; 28 29 import java.util.ArrayList; 30 import java.util.List; 31 32 public class SiteMapManager { 33 34 private static final String TAG = "SiteMapManager"; 35 private static final boolean DEBUG_TIMING = false; 36 37 public static final String[] SITE_MAP_COLUMNS = { 38 SiteMapColumns.PARENT_CLASS, 39 SiteMapColumns.PARENT_TITLE, 40 SiteMapColumns.CHILD_CLASS, 41 SiteMapColumns.CHILD_TITLE 42 }; 43 44 private final List<SiteMapPair> mPairs = new ArrayList<>(); 45 46 private boolean mInitialized; 47 48 /** 49 * Given a fragment class name and its screen title, build a breadcrumb from Settings root to 50 * this screen. 51 * <p/> 52 * Not all screens have a full breadcrumb path leading up to root, it's because either some 53 * page in the breadcrumb path is not indexed, or it's only reachable via search. 54 */ 55 @WorkerThread buildBreadCrumb(Context context, String clazz, String screenTitle)56 public synchronized List<String> buildBreadCrumb(Context context, String clazz, 57 String screenTitle) { 58 init(context); 59 final long startTime = System.currentTimeMillis(); 60 final List<String> breadcrumbs = new ArrayList<>(); 61 if (!mInitialized) { 62 Log.w(TAG, "SiteMap is not initialized yet, skipping"); 63 return breadcrumbs; 64 } 65 breadcrumbs.add(screenTitle); 66 String currentClass = clazz; 67 String currentTitle = screenTitle; 68 // Look up current page's parent, if found add it to breadcrumb string list, and repeat. 69 while (true) { 70 final SiteMapPair pair = lookUpParent(currentClass, currentTitle); 71 if (pair == null) { 72 if (DEBUG_TIMING) { 73 Log.d(TAG, "BreadCrumb timing: " + (System.currentTimeMillis() - startTime)); 74 } 75 return breadcrumbs; 76 } 77 breadcrumbs.add(0, pair.getParentTitle()); 78 currentClass = pair.getParentClass(); 79 currentTitle = pair.getParentTitle(); 80 } 81 } 82 83 /** 84 * Initialize a list of {@link SiteMapPair}s. Each pair knows about a single parent-child 85 * page relationship. 86 */ 87 @WorkerThread init(Context context)88 private synchronized void init(Context context) { 89 if (mInitialized) { 90 // Make sure only init once. 91 return; 92 } 93 final long startTime = System.currentTimeMillis(); 94 // First load site map from static index table. 95 final Context appContext = context.getApplicationContext(); 96 final SQLiteDatabase db = IndexDatabaseHelper.getInstance(appContext).getReadableDatabase(); 97 Cursor sitemap = db.query(IndexDatabaseHelper.Tables.TABLE_SITE_MAP, SITE_MAP_COLUMNS, null, 98 null, null, null, null); 99 while (sitemap.moveToNext()) { 100 final SiteMapPair pair = new SiteMapPair( 101 sitemap.getString(sitemap.getColumnIndex(SiteMapColumns.PARENT_CLASS)), 102 sitemap.getString(sitemap.getColumnIndex(SiteMapColumns.PARENT_TITLE)), 103 sitemap.getString(sitemap.getColumnIndex(SiteMapColumns.CHILD_CLASS)), 104 sitemap.getString(sitemap.getColumnIndex(SiteMapColumns.CHILD_TITLE))); 105 mPairs.add(pair); 106 } 107 sitemap.close(); 108 // Done. 109 mInitialized = true; 110 if (DEBUG_TIMING) { 111 Log.d(TAG, "Init timing: " + (System.currentTimeMillis() - startTime)); 112 } 113 } 114 115 @WorkerThread lookUpParent(String clazz, String title)116 private SiteMapPair lookUpParent(String clazz, String title) { 117 for (SiteMapPair pair : mPairs) { 118 if (TextUtils.equals(pair.getChildClass(), clazz) 119 && TextUtils.equals(title, pair.getChildTitle())) { 120 return pair; 121 } 122 } 123 return null; 124 } 125 126 }